mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Construct all our image loaders when we create frames so that we can allow arbitrary numbers of image loaders per frame (for multiple background images). (Bug 322475) r+sr=bzbarsky
This commit is contained in:
parent
c34734e572
commit
6e5f3d5edc
@ -41,6 +41,7 @@
|
||||
|
||||
#include "nsIDOMDataContainerEvent.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
|
||||
class nsDOMDataContainerEvent : public nsDOMEvent,
|
||||
public nsIDOMDataContainerEvent
|
||||
|
@ -1477,8 +1477,7 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
|
||||
// We have a background image
|
||||
|
||||
// Lookup the image
|
||||
imgIRequest *req = aPresContext->LoadImage(aColor.mBackgroundImage,
|
||||
aForFrame);
|
||||
imgIRequest *req = aColor.mBackgroundImage;
|
||||
|
||||
PRUint32 status = imgIRequest::STATUS_ERROR;
|
||||
if (req)
|
||||
@ -1916,7 +1915,7 @@ DrawBorderImage(nsPresContext* aPresContext,
|
||||
borderImageSplit[NS_SIDE_BOTTOM] = aBorderStyle.mBorderImageSplit.GetBottom();
|
||||
borderImageSplit[NS_SIDE_LEFT] = aBorderStyle.mBorderImageSplit.GetLeft();
|
||||
|
||||
imgIRequest *req = aPresContext->LoadBorderImage(aBorderStyle.GetBorderImage(), aForFrame);
|
||||
imgIRequest *req = aBorderStyle.GetBorderImage();
|
||||
|
||||
nsCOMPtr<imgIContainer> image;
|
||||
req->GetImage(getter_AddRefs(image));
|
||||
|
@ -1064,24 +1064,6 @@ CaptureChange(nsStyleContext* aOldContext, nsStyleContext* aNewContext,
|
||||
return aMinChange;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
ShouldStopImage(imgIRequest *aOldImage, imgIRequest *aNewImage)
|
||||
{
|
||||
if (!aOldImage)
|
||||
return PR_FALSE;
|
||||
|
||||
PRBool stopImages = !aNewImage;
|
||||
if (!stopImages) {
|
||||
nsCOMPtr<nsIURI> oldURI, newURI;
|
||||
aOldImage->GetURI(getter_AddRefs(oldURI));
|
||||
aNewImage->GetURI(getter_AddRefs(newURI));
|
||||
PRBool equal;
|
||||
stopImages =
|
||||
NS_FAILED(oldURI->Equals(newURI, &equal)) || !equal;
|
||||
}
|
||||
return stopImages;
|
||||
}
|
||||
|
||||
nsChangeHint
|
||||
nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
nsIFrame *aFrame,
|
||||
@ -1217,33 +1199,6 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
// if frame gets regenerated, let it keep old context
|
||||
aFrame->SetStyleContext(newContext);
|
||||
}
|
||||
// if old context had image and new context does not have the same image,
|
||||
// stop the image load for the frame
|
||||
if (ShouldStopImage(
|
||||
oldContext->GetStyleBackground()->mBackgroundImage,
|
||||
newContext->GetStyleBackground()->mBackgroundImage)) {
|
||||
// stop the image loading for the frame, the image has changed
|
||||
aPresContext->StopBackgroundImageFor(aFrame);
|
||||
}
|
||||
|
||||
imgIRequest *newBorderImage =
|
||||
newContext->GetStyleBorder()->GetBorderImage();
|
||||
if (ShouldStopImage(oldContext->GetStyleBorder()->GetBorderImage(),
|
||||
newBorderImage)) {
|
||||
// stop the image loading for the frame, the image has changed
|
||||
aPresContext->StopBorderImageFor(aFrame);
|
||||
}
|
||||
|
||||
// Since the CalcDifference call depended on the result of
|
||||
// GetActualBorder() and that result depends on whether the
|
||||
// image has loaded, start the image load now so that we'll get
|
||||
// notified when it completes loading and can do a restyle.
|
||||
// Otherwise, the image might finish loading from the network
|
||||
// before we start listening to its notifications, and then
|
||||
// we'll never know that it's finished loading.
|
||||
if (newBorderImage) {
|
||||
aPresContext->LoadBorderImage(newBorderImage, aFrame);
|
||||
}
|
||||
}
|
||||
oldContext->Release();
|
||||
}
|
||||
|
@ -63,36 +63,49 @@
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsImageLoader, imgIDecoderObserver, imgIContainerObserver)
|
||||
|
||||
nsImageLoader::nsImageLoader() :
|
||||
mFrame(nsnull), mPresContext(nsnull)
|
||||
nsImageLoader::nsImageLoader(nsIFrame *aFrame, PRBool aReflowOnLoad,
|
||||
nsImageLoader *aNextLoader)
|
||||
: mFrame(aFrame),
|
||||
mReflowOnLoad(aReflowOnLoad),
|
||||
mNextLoader(aNextLoader)
|
||||
{
|
||||
}
|
||||
|
||||
nsImageLoader::~nsImageLoader()
|
||||
{
|
||||
mFrame = nsnull;
|
||||
mPresContext = nsnull;
|
||||
|
||||
if (mRequest) {
|
||||
mRequest->Cancel(NS_ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsImageLoader::Init(nsIFrame *aFrame, nsPresContext *aPresContext,
|
||||
PRBool aReflowOnLoad)
|
||||
/* static */ already_AddRefed<nsImageLoader>
|
||||
nsImageLoader::Create(nsIFrame *aFrame, imgIRequest *aRequest,
|
||||
PRBool aReflowOnLoad, nsImageLoader *aNextLoader)
|
||||
{
|
||||
mFrame = aFrame;
|
||||
mPresContext = aPresContext;
|
||||
mReflowOnLoad = aReflowOnLoad;
|
||||
nsRefPtr<nsImageLoader> loader =
|
||||
new nsImageLoader(aFrame, aReflowOnLoad, aNextLoader);
|
||||
|
||||
loader->Load(aRequest);
|
||||
|
||||
return loader.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoader::Destroy()
|
||||
{
|
||||
// Destroy the chain with only one level of recursion.
|
||||
nsRefPtr<nsImageLoader> list = mNextLoader;
|
||||
mNextLoader = nsnull;
|
||||
while (list) {
|
||||
nsRefPtr<nsImageLoader> todestroy = list;
|
||||
list = todestroy->mNextLoader;
|
||||
todestroy->mNextLoader = nsnull;
|
||||
todestroy->Destroy();
|
||||
}
|
||||
|
||||
mFrame = nsnull;
|
||||
mPresContext = nsnull;
|
||||
|
||||
if (mRequest) {
|
||||
mRequest->Cancel(NS_ERROR_FAILURE);
|
||||
@ -104,28 +117,14 @@ nsImageLoader::Destroy()
|
||||
nsresult
|
||||
nsImageLoader::Load(imgIRequest *aImage)
|
||||
{
|
||||
NS_ASSERTION(!mRequest, "can't reuse image loaders");
|
||||
|
||||
if (!mFrame)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!aImage)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (mRequest) {
|
||||
nsCOMPtr<nsIURI> oldURI;
|
||||
mRequest->GetURI(getter_AddRefs(oldURI));
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
aImage->GetURI(getter_AddRefs(newURI));
|
||||
PRBool eq = PR_FALSE;
|
||||
nsresult rv = newURI->Equals(oldURI, &eq);
|
||||
if (NS_SUCCEEDED(rv) && eq) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now cancel the old request so it won't hold a stale ref to us.
|
||||
mRequest->Cancel(NS_ERROR_FAILURE);
|
||||
mRequest = nsnull;
|
||||
}
|
||||
|
||||
// Make sure to clone into a temporary, then set mRequest, since
|
||||
// cloning may notify and we don't want to trigger paints from this
|
||||
// code.
|
||||
@ -147,7 +146,7 @@ NS_IMETHODIMP nsImageLoader::OnStartContainer(imgIRequest *aRequest,
|
||||
* one frame = 1
|
||||
* one loop = 2
|
||||
*/
|
||||
aImage->SetAnimationMode(mPresContext->ImageAnimationMode());
|
||||
aImage->SetAnimationMode(mFrame->PresContext()->ImageAnimationMode());
|
||||
// Ensure the animation (if any) is started.
|
||||
aImage->StartAnimation();
|
||||
}
|
||||
@ -211,7 +210,7 @@ void
|
||||
nsImageLoader::RedrawDirtyFrame(const nsRect* aDamageRect)
|
||||
{
|
||||
if (mReflowOnLoad) {
|
||||
nsIPresShell *shell = mPresContext->GetPresShell();
|
||||
nsIPresShell *shell = mFrame->PresContext()->GetPresShell();
|
||||
#ifdef DEBUG
|
||||
nsresult rv =
|
||||
#endif
|
||||
|
@ -37,23 +37,35 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/* class to notify frames of background image loads */
|
||||
/* class to notify frames of background and border image loads */
|
||||
|
||||
#include "nsStubImageDecoderObserver.h"
|
||||
|
||||
class nsPresContext;
|
||||
class nsIFrame;
|
||||
class nsIURI;
|
||||
|
||||
#include "imgIRequest.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
/**
|
||||
* Image loaders pass notifications for background and border image
|
||||
* loading and animation on to the frames.
|
||||
*
|
||||
* Each frame's image loaders form a linked list.
|
||||
*/
|
||||
class nsImageLoader : public nsStubImageDecoderObserver
|
||||
{
|
||||
public:
|
||||
nsImageLoader();
|
||||
private:
|
||||
nsImageLoader(nsIFrame *aFrame, PRBool aReflowOnLoad,
|
||||
nsImageLoader *aNextLoader);
|
||||
virtual ~nsImageLoader();
|
||||
|
||||
public:
|
||||
static already_AddRefed<nsImageLoader>
|
||||
Create(nsIFrame *aFrame, imgIRequest *aRequest,
|
||||
PRBool aReflowOnLoad, nsImageLoader *aNextLoader);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// imgIDecoderObserver (override nsStubImageDecoderObserver)
|
||||
@ -69,21 +81,18 @@ public:
|
||||
NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
|
||||
nsRect * dirtyRect);
|
||||
|
||||
void Init(nsIFrame *aFrame, nsPresContext *aPresContext,
|
||||
PRBool aReflowOnLoad);
|
||||
nsresult Load(imgIRequest *aImage);
|
||||
|
||||
void Destroy();
|
||||
|
||||
nsIFrame *GetFrame() { return mFrame; }
|
||||
imgIRequest *GetRequest() { return mRequest; }
|
||||
nsImageLoader *GetNextLoader() { return mNextLoader; }
|
||||
|
||||
private:
|
||||
nsresult Load(imgIRequest *aImage);
|
||||
void RedrawDirtyFrame(const nsRect* aDamageRect);
|
||||
|
||||
private:
|
||||
nsIFrame *mFrame;
|
||||
nsPresContext *mPresContext;
|
||||
nsCOMPtr<imgIRequest> mRequest;
|
||||
PRBool mReflowOnLoad;
|
||||
nsRefPtr<nsImageLoader> mNextLoader;
|
||||
};
|
||||
|
@ -150,7 +150,7 @@ IsVisualCharset(const nsCString& aCharset)
|
||||
|
||||
|
||||
static PLDHashOperator
|
||||
destroy_loads(const void * aKey, nsCOMPtr<nsImageLoader>& aData, void* closure)
|
||||
destroy_loads(const void * aKey, nsRefPtr<nsImageLoader>& aData, void* closure)
|
||||
{
|
||||
aData->Destroy();
|
||||
return PL_DHASH_NEXT;
|
||||
@ -299,7 +299,7 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPresContext)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPresContext)
|
||||
|
||||
static PLDHashOperator
|
||||
TraverseImageLoader(const void * aKey, nsCOMPtr<nsImageLoader>& aData,
|
||||
TraverseImageLoader(const void * aKey, nsRefPtr<nsImageLoader>& aData,
|
||||
void* aClosure)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
@ -816,9 +816,6 @@ nsPresContext::Init(nsIDeviceContext* aDeviceContext)
|
||||
if (!mImageLoaders.Init())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (!mBorderImageLoaders.Init())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Get the look and feel service here; default colors will be initialized
|
||||
// from calling GetUserPreferences() when we get a presshell.
|
||||
nsresult rv = CallGetService(kLookAndFeelCID, &mLookAndFeel);
|
||||
@ -1028,10 +1025,13 @@ static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, PRUint16 aMode)
|
||||
|
||||
// Enumeration call back for HashTable
|
||||
static PLDHashOperator
|
||||
set_animation_mode(const void * aKey, nsCOMPtr<nsImageLoader>& aData, void* closure)
|
||||
set_animation_mode(const void * aKey, nsRefPtr<nsImageLoader>& aData, void* closure)
|
||||
{
|
||||
imgIRequest* imgReq = aData->GetRequest();
|
||||
for (nsImageLoader *loader = aData; loader;
|
||||
loader = loader->GetNextLoader()) {
|
||||
imgIRequest* imgReq = loader->GetRequest();
|
||||
SetImgAnimModeOnImgReq(imgReq, (PRUint16)NS_PTR_TO_INT32(closure));
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
@ -1166,64 +1166,27 @@ nsPresContext::SetFullZoom(float aZoom)
|
||||
mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
|
||||
}
|
||||
|
||||
imgIRequest*
|
||||
nsPresContext::DoLoadImage(nsPresContext::ImageLoaderTable& aTable,
|
||||
imgIRequest* aImage,
|
||||
nsIFrame* aTargetFrame,
|
||||
PRBool aReflowOnLoad)
|
||||
void
|
||||
nsPresContext::SetImageLoaders(nsIFrame* aTargetFrame,
|
||||
nsImageLoader* aImageLoaders)
|
||||
{
|
||||
// look and see if we have a loader for the target frame.
|
||||
nsCOMPtr<nsImageLoader> loader;
|
||||
aTable.Get(aTargetFrame, getter_AddRefs(loader));
|
||||
nsRefPtr<nsImageLoader> oldLoaders;
|
||||
mImageLoaders.Get(aTargetFrame, getter_AddRefs(oldLoaders));
|
||||
|
||||
if (!loader) {
|
||||
loader = new nsImageLoader();
|
||||
if (!loader)
|
||||
return nsnull;
|
||||
|
||||
loader->Init(aTargetFrame, this, aReflowOnLoad);
|
||||
mImageLoaders.Put(aTargetFrame, loader);
|
||||
if (aImageLoaders) {
|
||||
mImageLoaders.Put(aTargetFrame, aImageLoaders);
|
||||
} else if (oldLoaders) {
|
||||
mImageLoaders.Remove(aTargetFrame);
|
||||
}
|
||||
|
||||
loader->Load(aImage);
|
||||
|
||||
imgIRequest *request = loader->GetRequest();
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
imgIRequest*
|
||||
nsPresContext::LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame)
|
||||
{
|
||||
return DoLoadImage(mImageLoaders, aImage, aTargetFrame, PR_FALSE);
|
||||
}
|
||||
|
||||
imgIRequest*
|
||||
nsPresContext::LoadBorderImage(imgIRequest* aImage, nsIFrame* aTargetFrame)
|
||||
{
|
||||
return DoLoadImage(mBorderImageLoaders, aImage, aTargetFrame,
|
||||
aTargetFrame->GetStyleBorder()->ImageBorderDiffers());
|
||||
if (oldLoaders)
|
||||
oldLoaders->Destroy();
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::StopImagesFor(nsIFrame* aTargetFrame)
|
||||
{
|
||||
StopBackgroundImageFor(aTargetFrame);
|
||||
StopBorderImageFor(aTargetFrame);
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::DoStopImageFor(nsPresContext::ImageLoaderTable& aTable,
|
||||
nsIFrame* aTargetFrame)
|
||||
{
|
||||
nsCOMPtr<nsImageLoader> loader;
|
||||
aTable.Get(aTargetFrame, getter_AddRefs(loader));
|
||||
|
||||
if (loader) {
|
||||
loader->Destroy();
|
||||
|
||||
aTable.Remove(aTargetFrame);
|
||||
}
|
||||
SetImageLoaders(aTargetFrame, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -60,7 +60,7 @@
|
||||
#include "nsPropertyTable.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsChangeHint.h"
|
||||
// This also pulls in gfxTypes.h, which we cannot include directly.
|
||||
@ -364,35 +364,12 @@ public:
|
||||
* aImage loads, where aImage is its background image. Only a single
|
||||
* image will be tracked per frame.
|
||||
*/
|
||||
NS_HIDDEN_(imgIRequest*) LoadImage(imgIRequest* aImage,
|
||||
nsIFrame* aTargetFrame);
|
||||
/**
|
||||
* Set up observers so that aTargetFrame will be invalidated or
|
||||
* reflowed (as appropriate) when aImage loads, where aImage is its
|
||||
* *border* image. Only a single image will be tracked per frame.
|
||||
*/
|
||||
NS_HIDDEN_(imgIRequest*) LoadBorderImage(imgIRequest* aImage,
|
||||
nsIFrame* aTargetFrame);
|
||||
NS_HIDDEN_(void) SetImageLoaders(nsIFrame* aTargetFrame,
|
||||
nsImageLoader* aImageLoaders);
|
||||
|
||||
private:
|
||||
typedef nsInterfaceHashtable<nsVoidPtrHashKey, nsImageLoader> ImageLoaderTable;
|
||||
|
||||
NS_HIDDEN_(imgIRequest*) DoLoadImage(ImageLoaderTable& aTable,
|
||||
imgIRequest* aImage,
|
||||
nsIFrame* aTargetFrame,
|
||||
PRBool aReflowOnLoad);
|
||||
|
||||
NS_HIDDEN_(void) DoStopImageFor(ImageLoaderTable& aTable,
|
||||
nsIFrame* aTargetFrame);
|
||||
public:
|
||||
|
||||
NS_HIDDEN_(void) StopBackgroundImageFor(nsIFrame* aTargetFrame)
|
||||
{ DoStopImageFor(mImageLoaders, aTargetFrame); }
|
||||
NS_HIDDEN_(void) StopBorderImageFor(nsIFrame* aTargetFrame)
|
||||
{ DoStopImageFor(mBorderImageLoaders, aTargetFrame); }
|
||||
/**
|
||||
* This method is called when a frame is being destroyed to
|
||||
* ensure that the image load gets disassociated from the prescontext
|
||||
* ensure that the image loads get disassociated from the prescontext
|
||||
*/
|
||||
NS_HIDDEN_(void) StopImagesFor(nsIFrame* aTargetFrame);
|
||||
|
||||
@ -787,8 +764,8 @@ protected:
|
||||
nsILinkHandler* mLinkHandler; // [WEAK]
|
||||
nsIAtom* mLangGroup; // [STRONG]
|
||||
|
||||
ImageLoaderTable mImageLoaders;
|
||||
ImageLoaderTable mBorderImageLoaders;
|
||||
nsRefPtrHashtable<nsVoidPtrHashKey, nsImageLoader> mImageLoaders;
|
||||
|
||||
nsWeakPtr mContainer;
|
||||
|
||||
float mTextZoom; // Text zoom, defaults to 1.0
|
||||
|
@ -119,6 +119,7 @@
|
||||
#include "nsBoxLayoutState.h"
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsImageLoader.h"
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
@ -552,6 +553,27 @@ nsFrame::GetOffsets(PRInt32 &aStart, PRInt32 &aEnd) const
|
||||
// Subclass hook for style post processing
|
||||
NS_IMETHODIMP nsFrame::DidSetStyleContext()
|
||||
{
|
||||
// Ensure that this frame gets invalidates (and, in the case of some
|
||||
// 'border-image's, reflows) when images that affect it load.
|
||||
nsRefPtr<nsImageLoader> loaderChain;
|
||||
|
||||
const nsStyleBackground *background = GetStyleBackground();
|
||||
imgIRequest *newBackgroundImage = background->mBackgroundImage;
|
||||
if (newBackgroundImage) {
|
||||
loaderChain = nsImageLoader::Create(this, newBackgroundImage,
|
||||
PR_FALSE, loaderChain);
|
||||
}
|
||||
|
||||
const nsStyleBorder *border = GetStyleBorder();
|
||||
imgIRequest *newBorderImage = border->GetBorderImage();
|
||||
if (newBorderImage) {
|
||||
loaderChain = nsImageLoader::Create(this, newBorderImage,
|
||||
border->ImageBorderDiffers(),
|
||||
loaderChain);
|
||||
}
|
||||
|
||||
PresContext()->SetImageLoaders(this, loaderChain);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -289,17 +289,6 @@ nsHTMLReflowState::Init(nsPresContext* aPresContext,
|
||||
|
||||
InitResizeFlags(aPresContext);
|
||||
|
||||
// We have to start loading the border image now, because the
|
||||
// border-image's width overrides only apply once the image is loaded.
|
||||
// Starting the load of the image means we'll get a reflow when the
|
||||
// image loads. (If we didn't do it now, and the image loaded between
|
||||
// reflow and paint, we'd never get the notification, and our size
|
||||
// would be wrong.)
|
||||
imgIRequest *borderImage = mStyleBorder->GetBorderImage();
|
||||
if (borderImage) {
|
||||
aPresContext->LoadBorderImage(borderImage, frame);
|
||||
}
|
||||
|
||||
NS_ASSERTION((mFrameType == NS_CSS_FRAME_TYPE_INLINE &&
|
||||
!frame->IsFrameOfType(nsIFrame::eReplaced)) ||
|
||||
frame->GetType() == nsGkAtoms::textFrame ||
|
||||
|
Loading…
Reference in New Issue
Block a user