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:
L. David Baron 2009-02-18 17:13:24 -08:00
Родитель 8353f3b1b1
Коммит 6a55a4774c
8 изменённых файлов: 205 добавлений и 193 удалений

Просмотреть файл

@ -41,6 +41,7 @@
#include "nsIDOMDataContainerEvent.h" #include "nsIDOMDataContainerEvent.h"
#include "nsDOMEvent.h" #include "nsDOMEvent.h"
#include "nsInterfaceHashtable.h"
class nsDOMDataContainerEvent : public nsDOMEvent, class nsDOMDataContainerEvent : public nsDOMEvent,
public nsIDOMDataContainerEvent public nsIDOMDataContainerEvent

Просмотреть файл

@ -1518,9 +1518,12 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
return; return;
} }
// Lookup the image // Ensure we get invalidated for loads of the image. We need to do
imgIRequest *req = aPresContext->LoadImage(aColor.mBackgroundImage, // this here because this might be the only code that knows about the
aForFrame); // association of the style data with the frame.
aPresContext->SetupBackgroundImageLoaders(aForFrame, &aColor);
imgIRequest *req = aColor.mBackgroundImage;
PRUint32 status = imgIRequest::STATUS_ERROR; PRUint32 status = imgIRequest::STATUS_ERROR;
if (req) if (req)
@ -1725,9 +1728,16 @@ DrawBorderImage(nsPresContext* aPresContext,
if (aDirtyRect.IsEmpty()) if (aDirtyRect.IsEmpty())
return; return;
// Clone the image loader and set up animation notifications. // Ensure we get invalidated for loads and animations of the image.
imgIRequest *req = // We need to do this here because this might be the only code that
aPresContext->LoadBorderImage(aBorderStyle.GetBorderImage(), aForFrame); // knows about the association of the style data with the frame.
// XXX We shouldn't really... since if anybody is passing in a
// different style, they'll potentially have the wrong size for the
// border too.
aPresContext->SetupBorderImageLoaders(aForFrame, &aBorderStyle);
imgIRequest *req = aBorderStyle.GetBorderImage();
#ifdef DEBUG #ifdef DEBUG
{ {
PRUint32 status = imgIRequest::STATUS_ERROR; PRUint32 status = imgIRequest::STATUS_ERROR;

Просмотреть файл

@ -91,7 +91,6 @@
#include "nsLayoutUtils.h" #include "nsLayoutUtils.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "imgIRequest.h" #include "imgIRequest.h"
#include "nsStyleStructInlines.h"
#include "nsFrameManager.h" #include "nsFrameManager.h"
#ifdef ACCESSIBILITY #ifdef ACCESSIBILITY
@ -1085,24 +1084,6 @@ CaptureChange(nsStyleContext* aOldContext, nsStyleContext* aNewContext,
return aMinChange; 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;
}
/** /**
* Recompute style for aFrame and accumulate changes into aChangeList * Recompute style for aFrame and accumulate changes into aChangeList
* given that aMinChange is already accumulated for an ancestor. * given that aMinChange is already accumulated for an ancestor.
@ -1264,33 +1245,6 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
// if frame gets regenerated, let it keep old context // if frame gets regenerated, let it keep old context
aFrame->SetStyleContext(newContext); 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(); oldContext->Release();
} }

Просмотреть файл

@ -63,36 +63,49 @@
NS_IMPL_ISUPPORTS2(nsImageLoader, imgIDecoderObserver, imgIContainerObserver) NS_IMPL_ISUPPORTS2(nsImageLoader, imgIDecoderObserver, imgIContainerObserver)
nsImageLoader::nsImageLoader() : nsImageLoader::nsImageLoader(nsIFrame *aFrame, PRBool aReflowOnLoad,
mFrame(nsnull), mPresContext(nsnull) nsImageLoader *aNextLoader)
: mFrame(aFrame),
mReflowOnLoad(aReflowOnLoad),
mNextLoader(aNextLoader)
{ {
} }
nsImageLoader::~nsImageLoader() nsImageLoader::~nsImageLoader()
{ {
mFrame = nsnull; mFrame = nsnull;
mPresContext = nsnull;
if (mRequest) { if (mRequest) {
mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE); mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
} }
} }
/* static */ already_AddRefed<nsImageLoader>
void nsImageLoader::Create(nsIFrame *aFrame, imgIRequest *aRequest,
nsImageLoader::Init(nsIFrame *aFrame, nsPresContext *aPresContext, PRBool aReflowOnLoad, nsImageLoader *aNextLoader)
PRBool aReflowOnLoad)
{ {
mFrame = aFrame; nsRefPtr<nsImageLoader> loader =
mPresContext = aPresContext; new nsImageLoader(aFrame, aReflowOnLoad, aNextLoader);
mReflowOnLoad = aReflowOnLoad;
loader->Load(aRequest);
return loader.forget();
} }
void void
nsImageLoader::Destroy() 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; mFrame = nsnull;
mPresContext = nsnull;
if (mRequest) { if (mRequest) {
mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE); mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
@ -104,28 +117,14 @@ nsImageLoader::Destroy()
nsresult nsresult
nsImageLoader::Load(imgIRequest *aImage) nsImageLoader::Load(imgIRequest *aImage)
{ {
NS_ASSERTION(!mRequest, "can't reuse image loaders");
if (!mFrame) if (!mFrame)
return NS_ERROR_NOT_INITIALIZED; return NS_ERROR_NOT_INITIALIZED;
if (!aImage) if (!aImage)
return NS_ERROR_FAILURE; 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->CancelAndForgetObserver(NS_ERROR_FAILURE);
mRequest = nsnull;
}
// Make sure to clone into a temporary, then set mRequest, since // Make sure to clone into a temporary, then set mRequest, since
// cloning may notify and we don't want to trigger paints from this // cloning may notify and we don't want to trigger paints from this
// code. // code.
@ -147,7 +146,7 @@ NS_IMETHODIMP nsImageLoader::OnStartContainer(imgIRequest *aRequest,
* one frame = 1 * one frame = 1
* one loop = 2 * one loop = 2
*/ */
aImage->SetAnimationMode(mPresContext->ImageAnimationMode()); aImage->SetAnimationMode(mFrame->PresContext()->ImageAnimationMode());
// Ensure the animation (if any) is started. // Ensure the animation (if any) is started.
aImage->StartAnimation(); aImage->StartAnimation();
} }
@ -206,7 +205,7 @@ void
nsImageLoader::RedrawDirtyFrame(const nsRect* aDamageRect) nsImageLoader::RedrawDirtyFrame(const nsRect* aDamageRect)
{ {
if (mReflowOnLoad) { if (mReflowOnLoad) {
nsIPresShell *shell = mPresContext->GetPresShell(); nsIPresShell *shell = mFrame->PresContext()->GetPresShell();
#ifdef DEBUG #ifdef DEBUG
nsresult rv = nsresult rv =
#endif #endif

Просмотреть файл

@ -37,23 +37,35 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
/* class to notify frames of background image loads */ /* class to notify frames of background and border image loads */
#include "nsStubImageDecoderObserver.h" #include "nsStubImageDecoderObserver.h"
class nsPresContext;
class nsIFrame; class nsIFrame;
class nsIURI; class nsIURI;
#include "imgIRequest.h" #include "imgIRequest.h"
#include "nsCOMPtr.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 class nsImageLoader : public nsStubImageDecoderObserver
{ {
public: private:
nsImageLoader(); nsImageLoader(nsIFrame *aFrame, PRBool aReflowOnLoad,
nsImageLoader *aNextLoader);
virtual ~nsImageLoader(); virtual ~nsImageLoader();
public:
static already_AddRefed<nsImageLoader>
Create(nsIFrame *aFrame, imgIRequest *aRequest,
PRBool aReflowOnLoad, nsImageLoader *aNextLoader);
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
// imgIDecoderObserver (override nsStubImageDecoderObserver) // imgIDecoderObserver (override nsStubImageDecoderObserver)
@ -69,21 +81,17 @@ public:
NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe, NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
nsIntRect *dirtyRect); nsIntRect *dirtyRect);
void Init(nsIFrame *aFrame, nsPresContext *aPresContext,
PRBool aReflowOnLoad);
nsresult Load(imgIRequest *aImage);
void Destroy(); void Destroy();
nsIFrame *GetFrame() { return mFrame; }
imgIRequest *GetRequest() { return mRequest; } imgIRequest *GetRequest() { return mRequest; }
nsImageLoader *GetNextLoader() { return mNextLoader; }
private: private:
nsresult Load(imgIRequest *aImage);
void RedrawDirtyFrame(const nsRect* aDamageRect); void RedrawDirtyFrame(const nsRect* aDamageRect);
private:
nsIFrame *mFrame; nsIFrame *mFrame;
nsPresContext *mPresContext;
nsCOMPtr<imgIRequest> mRequest; nsCOMPtr<imgIRequest> mRequest;
PRBool mReflowOnLoad; PRBool mReflowOnLoad;
nsRefPtr<nsImageLoader> mNextLoader;
}; };

Просмотреть файл

@ -89,6 +89,7 @@
#include "nsCSSRules.h" #include "nsCSSRules.h"
#include "nsFontFaceLoader.h" #include "nsFontFaceLoader.h"
#include "nsIEventListenerManager.h" #include "nsIEventListenerManager.h"
#include "nsStyleStructInlines.h"
#ifdef MOZ_SMIL #ifdef MOZ_SMIL
#include "nsSMILAnimationController.h" #include "nsSMILAnimationController.h"
@ -159,7 +160,7 @@ IsVisualCharset(const nsCString& aCharset)
static PLDHashOperator static PLDHashOperator
destroy_loads(const void * aKey, nsCOMPtr<nsImageLoader>& aData, void* closure) destroy_loads(const void * aKey, nsRefPtr<nsImageLoader>& aData, void* closure)
{ {
aData->Destroy(); aData->Destroy();
return PL_DHASH_NEXT; return PL_DHASH_NEXT;
@ -246,8 +247,8 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
nsPresContext::~nsPresContext() nsPresContext::~nsPresContext()
{ {
mImageLoaders.Enumerate(destroy_loads, nsnull); for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
mBorderImageLoaders.Enumerate(destroy_loads, nsnull); mImageLoaders[i].Enumerate(destroy_loads, nsnull);
NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer"); NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
SetShell(nsnull); SetShell(nsnull);
@ -313,7 +314,7 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPresContext)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPresContext) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPresContext)
static PLDHashOperator static PLDHashOperator
TraverseImageLoader(const void * aKey, nsCOMPtr<nsImageLoader>& aData, TraverseImageLoader(const void * aKey, nsRefPtr<nsImageLoader>& aData,
void* aClosure) void* aClosure)
{ {
nsCycleCollectionTraversalCallback *cb = nsCycleCollectionTraversalCallback *cb =
@ -331,8 +332,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLookAndFeel); // a service // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLookAndFeel); // a service
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLangGroup); // an atom // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLangGroup); // an atom
tmp->mImageLoaders.Enumerate(TraverseImageLoader, &cb); for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
tmp->mBorderImageLoaders.Enumerate(TraverseImageLoader, &cb); tmp->mImageLoaders[i].Enumerate(TraverseImageLoader, &cb);
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTheme); // a service // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTheme); // a service
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLangService); // a service // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLangService); // a service
@ -354,10 +355,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
// NS_RELEASE(tmp->mLookAndFeel); // a service // NS_RELEASE(tmp->mLookAndFeel); // a service
// NS_RELEASE(tmp->mLangGroup); // an atom // NS_RELEASE(tmp->mLangGroup); // an atom
tmp->mImageLoaders.Enumerate(destroy_loads, nsnull); for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i) {
tmp->mImageLoaders.Clear(); tmp->mImageLoaders[i].Enumerate(destroy_loads, nsnull);
tmp->mBorderImageLoaders.Enumerate(destroy_loads, nsnull); tmp->mImageLoaders[i].Clear();
tmp->mBorderImageLoaders.Clear(); }
// NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTheme); // a service // NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTheme); // a service
// NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLangService); // a service // NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLangService); // a service
@ -837,11 +838,9 @@ nsPresContext::Init(nsIDeviceContext* aDeviceContext)
mDeviceContext->FlushFontCache(); mDeviceContext->FlushFontCache();
mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel(); mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
if (!mImageLoaders.Init()) for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
return NS_ERROR_OUT_OF_MEMORY; if (!mImageLoaders[i].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 // Get the look and feel service here; default colors will be initialized
// from calling GetUserPreferences() when we get a presshell. // from calling GetUserPreferences() when we get a presshell.
@ -1058,10 +1057,13 @@ static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, PRUint16 aMode)
// Enumeration call back for HashTable // Enumeration call back for HashTable
static PLDHashOperator 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;
SetImgAnimModeOnImgReq(imgReq, (PRUint16)NS_PTR_TO_INT32(closure)); loader = loader->GetNextLoader()) {
imgIRequest* imgReq = loader->GetRequest();
SetImgAnimModeOnImgReq(imgReq, (PRUint16)NS_PTR_TO_INT32(closure));
}
return PL_DHASH_NEXT; return PL_DHASH_NEXT;
} }
@ -1122,8 +1124,8 @@ nsPresContext::SetImageAnimationModeInternal(PRUint16 aMode)
return; return;
// Set the mode on the image loaders. // Set the mode on the image loaders.
mImageLoaders.Enumerate(set_animation_mode, NS_INT32_TO_PTR(aMode)); for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
mBorderImageLoaders.Enumerate(set_animation_mode, NS_INT32_TO_PTR(aMode)); mImageLoaders[i].Enumerate(set_animation_mode, NS_INT32_TO_PTR(aMode));
// Now walk the content tree and set the animation mode // Now walk the content tree and set the animation mode
// on all the images. // on all the images.
@ -1228,66 +1230,51 @@ nsPresContext::SetFullZoom(float aZoom)
mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel(); mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
} }
imgIRequest* void
nsPresContext::DoLoadImage(nsPresContext::ImageLoaderTable& aTable, nsPresContext::SetImageLoaders(nsIFrame* aTargetFrame,
imgIRequest* aImage, ImageLoadType aType,
nsIFrame* aTargetFrame, nsImageLoader* aImageLoaders)
PRBool aReflowOnLoad)
{ {
// look and see if we have a loader for the target frame. nsRefPtr<nsImageLoader> oldLoaders;
nsCOMPtr<nsImageLoader> loader; mImageLoaders[aType].Get(aTargetFrame, getter_AddRefs(oldLoaders));
aTable.Get(aTargetFrame, getter_AddRefs(loader));
if (!loader) { if (aImageLoaders) {
loader = new nsImageLoader(); mImageLoaders[aType].Put(aTargetFrame, aImageLoaders);
if (!loader) } else if (oldLoaders) {
return nsnull; mImageLoaders[aType].Remove(aTargetFrame);
loader->Init(aTargetFrame, this, aReflowOnLoad);
aTable.Put(aTargetFrame, loader);
} }
loader->Load(aImage); if (oldLoaders)
oldLoaders->Destroy();
imgIRequest *request = loader->GetRequest();
return request;
} }
imgIRequest* void
nsPresContext::LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame) nsPresContext::SetupBackgroundImageLoaders(nsIFrame* aFrame,
const nsStyleBackground* aStyleBackground)
{ {
return DoLoadImage(mImageLoaders, aImage, aTargetFrame, PR_FALSE); nsRefPtr<nsImageLoader> loader =
nsImageLoader::Create(aFrame, aStyleBackground->mBackgroundImage,
PR_FALSE, nsnull);
SetImageLoaders(aFrame, BACKGROUND_IMAGE, loader);
} }
imgIRequest* void
nsPresContext::LoadBorderImage(imgIRequest* aImage, nsIFrame* aTargetFrame) nsPresContext::SetupBorderImageLoaders(nsIFrame* aFrame,
const nsStyleBorder* aStyleBorder)
{ {
return DoLoadImage(mBorderImageLoaders, aImage, aTargetFrame, nsRefPtr<nsImageLoader> loader =
aTargetFrame->GetStyleBorder()->ImageBorderDiffers()); nsImageLoader::Create(aFrame, aStyleBorder->GetBorderImage(),
aStyleBorder->ImageBorderDiffers(), nsnull);
SetImageLoaders(aFrame, BORDER_IMAGE, loader);
} }
void void
nsPresContext::StopImagesFor(nsIFrame* aTargetFrame) nsPresContext::StopImagesFor(nsIFrame* aTargetFrame)
{ {
StopBackgroundImageFor(aTargetFrame); for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
StopBorderImageFor(aTargetFrame); SetImageLoaders(aTargetFrame, ImageLoadType(i), nsnull);
} }
void
nsPresContext::DoStopImageFor(nsPresContext::ImageLoaderTable& aTable,
nsIFrame* aTargetFrame)
{
nsCOMPtr<nsImageLoader> loader;
aTable.Get(aTargetFrame, getter_AddRefs(loader));
if (loader) {
loader->Destroy();
aTable.Remove(aTargetFrame);
}
}
void void
nsPresContext::SetContainer(nsISupports* aHandler) nsPresContext::SetContainer(nsISupports* aHandler)
{ {

Просмотреть файл

@ -60,7 +60,7 @@
#include "nsPropertyTable.h" #include "nsPropertyTable.h"
#include "nsGkAtoms.h" #include "nsGkAtoms.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsInterfaceHashtable.h" #include "nsRefPtrHashtable.h"
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
#include "nsChangeHint.h" #include "nsChangeHint.h"
// This also pulls in gfxTypes.h, which we cannot include directly. // This also pulls in gfxTypes.h, which we cannot include directly.
@ -93,6 +93,7 @@ class nsILookAndFeel;
class nsICSSPseudoComparator; class nsICSSPseudoComparator;
class nsIAtom; class nsIAtom;
struct nsStyleBackground; struct nsStyleBackground;
struct nsStyleBorder;
class nsIRunnable; class nsIRunnable;
class gfxUserFontSet; class gfxUserFontSet;
class nsUserFontSet; class nsUserFontSet;
@ -378,41 +379,46 @@ public:
PRBool GetFocusRingOnAnything() const { return mFocusRingOnAnything; } PRBool GetFocusRingOnAnything() const { return mFocusRingOnAnything; }
PRUint8 GetFocusRingStyle() const { return mFocusRingStyle; } PRUint8 GetFocusRingStyle() const { return mFocusRingStyle; }
/**
* The types of image load types that the pres context needs image
* loaders to track invalidation for.
*/
enum ImageLoadType {
BACKGROUND_IMAGE,
BORDER_IMAGE,
IMAGE_LOAD_TYPE_COUNT
};
/** /**
* Set up observers so that aTargetFrame will be invalidated when * Set the list of image loaders that track invalidation for a
* aImage loads, where aImage is its background image. Only a single * specific frame and type of image. This list will replace any
* image will be tracked per frame. * previous list for that frame and image type (and null will remove
* any previous list).
*/ */
NS_HIDDEN_(imgIRequest*) LoadImage(imgIRequest* aImage, NS_HIDDEN_(void) SetImageLoaders(nsIFrame* aTargetFrame,
nsIFrame* aTargetFrame); ImageLoadType aType,
nsImageLoader* aImageLoaders);
/** /**
* Set up observers so that aTargetFrame will be invalidated or * Make an appropriate SetImageLoaders call (including potentially
* reflowed (as appropriate) when aImage loads, where aImage is its * with null aImageLoaders) given that aFrame draws its background
* *border* image. Only a single image will be tracked per frame. * based on aStyleBackground.
*/ */
NS_HIDDEN_(imgIRequest*) LoadBorderImage(imgIRequest* aImage, NS_HIDDEN_(void) SetupBackgroundImageLoaders(nsIFrame* aFrame,
nsIFrame* aTargetFrame); const nsStyleBackground*
aStyleBackground);
private: /**
typedef nsInterfaceHashtable<nsVoidPtrHashKey, nsImageLoader> ImageLoaderTable; * Make an appropriate SetImageLoaders call (including potentially
* with null aImageLoaders) given that aFrame draws its border
* based on aStyleBorder.
*/
NS_HIDDEN_(void) SetupBorderImageLoaders(nsIFrame* aFrame,
const nsStyleBorder* aStyleBorder);
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 * 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); NS_HIDDEN_(void) StopImagesFor(nsIFrame* aTargetFrame);
@ -847,8 +853,9 @@ protected:
nsILinkHandler* mLinkHandler; // [WEAK] nsILinkHandler* mLinkHandler; // [WEAK]
nsIAtom* mLangGroup; // [STRONG] nsIAtom* mLangGroup; // [STRONG]
ImageLoaderTable mImageLoaders; nsRefPtrHashtable<nsVoidPtrHashKey, nsImageLoader>
ImageLoaderTable mBorderImageLoaders; mImageLoaders[IMAGE_LOAD_TYPE_COUNT];
nsWeakPtr mContainer; nsWeakPtr mContainer;
float mTextZoom; // Text zoom, defaults to 1.0 float mTextZoom; // Text zoom, defaults to 1.0

Просмотреть файл

@ -518,19 +518,65 @@ nsFrame::GetOffsets(PRInt32 &aStart, PRInt32 &aEnd) const
return NS_OK; return NS_OK;
} }
static PRBool
EqualImages(imgIRequest *aOldImage, imgIRequest *aNewImage)
{
if (aOldImage == aNewImage)
return PR_TRUE;
if (!aOldImage || !aNewImage)
return PR_FALSE;
nsCOMPtr<nsIURI> oldURI, newURI;
aOldImage->GetURI(getter_AddRefs(oldURI));
aNewImage->GetURI(getter_AddRefs(newURI));
PRBool equal;
return NS_SUCCEEDED(oldURI->Equals(newURI, &equal)) && equal;
}
// Subclass hook for style post processing // Subclass hook for style post processing
/* virtual */ void /* virtual */ void
nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
{ {
// We have to start loading the border image before or during reflow, if (aOldStyleContext) {
// because the border-image's width overrides only apply once the // If the old context had a background image image and new context
// image is loaded. Starting the load of the image means we'll get a // does not have the same image, clear the image load notifier
// reflow when the image loads. (Otherwise, if the image loads // (which keeps the image loading, if it still is) for the frame.
// between reflow and paint, we never get the notification and our // We want to do this conservatively because some frames paint their
// size ends up wrong.) // backgrounds from some other frame's style data, and we don't want
imgIRequest *borderImage = GetStyleBorder()->GetBorderImage(); // to clear those notifiers unless we have to. (They'll be reset
if (borderImage) { // when we paint, although we could miss a notification in that
PresContext()->LoadBorderImage(borderImage, this); // interval.)
imgIRequest *oldBackgroundImage =
aOldStyleContext->GetStyleBackground()->mBackgroundImage;
if (oldBackgroundImage &&
!EqualImages(oldBackgroundImage,
GetStyleBackground()->mBackgroundImage)) {
// stop the image loading for the frame, the image has changed
PresContext()->SetImageLoaders(this,
nsPresContext::BACKGROUND_IMAGE, nsnull);
}
}
imgIRequest *oldBorderImage = aOldStyleContext
? aOldStyleContext->GetStyleBorder()->GetBorderImage()
: nsnull;
// For border-images, we can't be as conservative (we need to set the
// new loaders if there has been any change) 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. Likewise, we want to
// do this for freshly-created frames to prevent a similar race if the
// image loads between reflow (which can depend on whether the image
// is loaded) and paint. We also don't really care about any callers
// who try to paint borders with a different style context, because
// they won't have the correct size for the border either.
if (!EqualImages(oldBorderImage, GetStyleBorder()->GetBorderImage())) {
// stop and restart the image loading/notification
PresContext()->SetupBorderImageLoaders(this, GetStyleBorder());
} }
} }