From 134fed88562081c017ec3f34f4137d456a158ed1 Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Tue, 9 Mar 2004 03:57:51 +0000 Subject: [PATCH] Load background images from style instead of from painting. This makes us start loading the background images when we resolve style on an object that needs them instead of when we scroll down and see it for the first time. Bug 57607, r=pavlov, sr=dbaron --- content/base/public/nsContentUtils.h | 32 ++++++ content/base/src/nsContentUtils.cpp | 79 ++++++++++++++ content/base/src/nsImageLoadingContent.cpp | 51 +-------- content/base/src/nsImageLoadingContent.h | 8 -- content/base/src/nsRuleNode.cpp | 7 +- content/base/src/nsStyleContext.cpp | 13 +++ .../html/content/src/nsGenericHTMLElement.cpp | 27 ++--- content/html/style/src/Makefile.in | 1 + content/html/style/src/nsCSSDataBlock.cpp | 4 + content/html/style/src/nsCSSDeclaration.cpp | 3 +- content/html/style/src/nsCSSValue.cpp | 103 ++++++++++++++++-- content/html/style/src/nsCSSValue.h | 51 ++++++++- content/html/style/src/nsComputedDOMStyle.cpp | 7 +- content/shared/public/nsStyleStruct.h | 5 +- content/shared/src/Makefile.in | 1 + content/shared/src/nsStyleStruct.cpp | 24 +++- layout/base/nsFrameManager.cpp | 23 ++-- layout/base/nsImageLoader.cpp | 46 +++----- layout/base/nsImageLoader.h | 2 +- layout/base/nsPresContext.cpp | 28 +---- layout/base/nsPresContext.h | 2 +- layout/base/public/nsIPresContext.h | 2 +- layout/base/public/nsPresContext.h | 2 +- layout/base/src/nsImageLoader.cpp | 46 +++----- layout/base/src/nsImageLoader.h | 2 +- layout/base/src/nsPresContext.cpp | 28 +---- layout/base/src/nsPresContext.h | 2 +- layout/html/base/src/nsFrameManager.cpp | 23 ++-- layout/style/nsCSSDataBlock.cpp | 4 + layout/style/nsCSSDeclaration.cpp | 3 +- layout/style/nsCSSValue.cpp | 103 ++++++++++++++++-- layout/style/nsCSSValue.h | 51 ++++++++- layout/style/nsComputedDOMStyle.cpp | 7 +- layout/style/nsRuleNode.cpp | 7 +- layout/style/nsStyleContext.cpp | 13 +++ layout/style/nsStyleStruct.cpp | 24 +++- layout/style/nsStyleStruct.h | 5 +- modules/libpr0n/public/imgIRequest.idl | 8 ++ modules/libpr0n/src/imgRequestProxy.cpp | 26 +++++ 39 files changed, 633 insertions(+), 240 deletions(-) diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 8f3ed352606c..a5f9f6f3ddec 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -59,6 +59,9 @@ class nsIThreadJSContextStack; class nsIParserService; class nsIIOService; class nsIURI; +class imgIDecoderObserver; +class imgIRequest; +class imgILoader; class nsContentUtils { @@ -290,6 +293,33 @@ public: nsIDocument** aDocument, nsIPrincipal** aPrincipal); + /** + * Method to do security and content policy checks on the image URI + * + * @param aURI uri of the image to be loaded + * @param aContext the context the image is loaded in (eg an element) + * @param aLoadingDocument the document we belong to + * @throws NS_ERROR_IMAGE_BLOCKED if the load is blocked. This is + * subject to change. See nsIContentPolicy. + */ + static nsresult CanLoadImage(nsIURI* aURI, + nsISupports* aContext, + nsIDocument* aLoadingDocument); + /** + * Method to start an image load. This does not do any security checks. + * + * @param aURI uri of the image to be loaded + * @param aLoadingDocument the document we belong to + * @param aObserver the observer for the image load + * @param aLoadFlags the load flags to use. See nsIRequest + * @return the imgIRequest for the image load + */ + static nsresult LoadImage(nsIURI* aURI, + nsIDocument* aLoadingDocument, + imgIDecoderObserver* aObserver, + PRInt32 aLoadFlags, + imgIRequest** aRequest); + private: static nsresult doReparentContentWrapper(nsIContent *aChild, nsIDocument *aNewDocument, @@ -312,6 +342,8 @@ private: static nsIIOService *sIOService; + static imgILoader* sImgLoader; + static PRBool sInitialized; }; diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index f8b959b03852..2ded2fc1d78d 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -78,6 +78,11 @@ #include "nsIFormControl.h" #include "nsHTMLAtoms.h" #include "nsLayoutAtoms.h" +#include "imgIDecoderObserver.h" +#include "imgIRequest.h" +#include "imgILoader.h" +#include "nsILoadGroup.h" +#include "nsContentPolicyUtils.h" static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1"; static NS_DEFINE_IID(kParserServiceCID, NS_PARSERSERVICE_CID); @@ -89,6 +94,7 @@ nsIThreadJSContextStack *nsContentUtils::sThreadJSContextStack = nsnull; nsIParserService *nsContentUtils::sParserService = nsnull; nsINameSpaceManager *nsContentUtils::sNameSpaceManager = nsnull; nsIIOService *nsContentUtils::sIOService = nsnull; +imgILoader *nsContentUtils::sImgLoader = nsnull; PRBool nsContentUtils::sInitialized = PR_FALSE; @@ -132,6 +138,13 @@ nsContentUtils::Init() sIOService = nsnull; } + // Ignore failure and just don't load images + rv = CallGetService("@mozilla.org/image/loader;1", &sImgLoader); + if (NS_FAILED(rv)) { + // no image loading for us. Oh, well. + sImgLoader = nsnull; + } + sInitialized = PR_TRUE; return NS_OK; @@ -402,6 +415,7 @@ nsContentUtils::Shutdown() NS_IF_RELEASE(sNameSpaceManager); NS_IF_RELEASE(sParserService); NS_IF_RELEASE(sIOService); + NS_IF_RELEASE(sImgLoader); } // static @@ -1655,6 +1669,71 @@ nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI, NS_ERROR_DOM_NAMESPACE_ERR : NS_OK; } +// static +nsresult +nsContentUtils::CanLoadImage(nsIURI* aURI, nsISupports* aContext, + nsIDocument* aLoadingDocument) +{ + NS_PRECONDITION(aURI, "Must have a URI"); + NS_PRECONDITION(aLoadingDocument, "Must have a document"); + + // XXXbz Do security manager check here! + + // Check with content policy + nsIScriptGlobalObject* globalScript = aLoadingDocument->GetScriptGlobalObject(); + + if (!globalScript) { + // just let it load. Documents loaded as data should take care to + // prevent image loading themselves. + return NS_OK; + } + + nsCOMPtr domWin(do_QueryInterface(globalScript)); + + PRBool shouldLoad = PR_TRUE; + nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::IMAGE, aURI, + aContext, + domWin, &shouldLoad); + if (NS_SUCCEEDED(rv) && !shouldLoad) { + return NS_ERROR_IMAGE_BLOCKED; + } + + return NS_OK; +} + +nsresult +nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument, + imgIDecoderObserver* aObserver, + PRInt32 aLoadFlags, imgIRequest** aRequest) +{ + NS_PRECONDITION(aURI, "Must have a URI"); + NS_PRECONDITION(aLoadingDocument, "Must have a document"); + NS_PRECONDITION(aRequest, "Null out param"); + + if (!sImgLoader) { + // nothing we can do here + return NS_OK; + } + + nsCOMPtr loadGroup = aLoadingDocument->GetDocumentLoadGroup(); + NS_WARN_IF_FALSE(loadGroup, "Could not get loadgroup; onload may fire too early"); + + nsIURI *documentURI = aLoadingDocument->GetDocumentURI(); + + // XXXbz using "documentURI" for the initialDocumentURI is not quite + // right, but the best we can do here... + return sImgLoader->LoadImage(aURI, /* uri to load */ + documentURI, /* initialDocumentURI */ + documentURI, /* referrer */ + loadGroup, /* loadgroup */ + aObserver, /* imgIDecoderObserver */ + aLoadingDocument, /* uniquification key */ + aLoadFlags, /* load flags */ + nsnull, /* cache key */ + nsnull, /* existing request*/ + aRequest); +} + void nsCxPusher::Push(nsISupports *aCurrentTarget) { diff --git a/content/base/src/nsImageLoadingContent.cpp b/content/base/src/nsImageLoadingContent.cpp index 78f533d05004..43ae67489d78 100644 --- a/content/base/src/nsImageLoadingContent.cpp +++ b/content/base/src/nsImageLoadingContent.cpp @@ -66,6 +66,8 @@ #include "nsLayoutAtoms.h" #include "nsIFrame.h" +#include "nsContentUtils.h" + // Statics imgILoader* nsImageLoadingContent::sImgLoader = nsnull; nsIIOService* nsImageLoadingContent::sIOService = nsnull; @@ -407,7 +409,7 @@ nsImageLoadingContent::ImageURIChanged(const nsACString& aNewURI) // not to show the broken image icon. If the load is blocked by the // content policy or security manager, we will want to cancel with // the error code from those. - nsresult cancelResult = CanLoadImage(imageURI, doc); + nsresult cancelResult = nsContentUtils::CanLoadImage(imageURI, this, doc); if (NS_SUCCEEDED(cancelResult)) { cancelResult = NS_ERROR_IMAGE_SRC_CHANGED; } @@ -421,11 +423,6 @@ nsImageLoadingContent::ImageURIChanged(const nsACString& aNewURI) return NS_OK; } - nsCOMPtr loadGroup = doc->GetDocumentLoadGroup(); - NS_WARN_IF_FALSE(loadGroup, "Could not get loadgroup; onload may fire too early"); - - nsIURI *documentURI = doc->GetDocumentURI(); - nsCOMPtr & req = mCurrentRequest ? mPendingRequest : mCurrentRequest; // It may be that one of our frames has replaced itself with alt text... This @@ -436,18 +433,8 @@ nsImageLoadingContent::ImageURIChanged(const nsACString& aNewURI) // that have changed to alt text on us yet. PRBool mayNeedReframe = mHaveHadObserver && !mCurrentRequest; - // XXXbz using "documentURI" for the initialDocumentURI is not quite - // right, but the best we can do here... - rv = sImgLoader->LoadImage(imageURI, /* uri to load */ - documentURI, /* initialDocumentURI */ - documentURI, /* referrer */ - loadGroup, /* loadgroup */ - this, /* imgIDecoderObserver */ - doc, /* uniquification key */ - nsIRequest::LOAD_NORMAL, /* load flags */ - nsnull, /* cache key */ - nsnull, /* existing request*/ - getter_AddRefs(req)); + rv = nsContentUtils::LoadImage(imageURI, doc, this, nsIRequest::LOAD_NORMAL, + getter_AddRefs(req)); NS_ENSURE_SUCCESS(rv, rv); @@ -517,34 +504,6 @@ nsImageLoadingContent::CancelImageRequests(nsresult aReason) } } -nsresult -nsImageLoadingContent::CanLoadImage(nsIURI* aURI, nsIDocument* aDocument) -{ - NS_PRECONDITION(aURI, "Null URI"); - NS_PRECONDITION(aDocument, "Null document!"); - - // Check with the content-policy things to make sure this load is permitted. - - nsIScriptGlobalObject *globalScript = aDocument->GetScriptGlobalObject(); - if (!globalScript) { - // just let it load. Documents loaded as data should take care to - // prevent image loading themselves. - return NS_OK; - } - - nsCOMPtr domWin(do_QueryInterface(globalScript)); - - PRBool shouldLoad = PR_TRUE; - nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::IMAGE, aURI, this, - domWin, &shouldLoad); - if (NS_SUCCEEDED(rv) && !shouldLoad) { - return NS_ERROR_IMAGE_BLOCKED; - } - - return NS_OK; -} - - nsIDocument* nsImageLoadingContent::GetOurDocument() { diff --git a/content/base/src/nsImageLoadingContent.h b/content/base/src/nsImageLoadingContent.h index d84611283d21..8e4b23a6d10a 100644 --- a/content/base/src/nsImageLoadingContent.h +++ b/content/base/src/nsImageLoadingContent.h @@ -119,14 +119,6 @@ private: */ void CancelImageRequests(nsresult aReason); - /** - * Method to do security and content policy checks on the image URI - * - * @param aURI uri of the image to be loaded - * @param aDocument the document we belong to - */ - nsresult CanLoadImage(nsIURI* aURI, nsIDocument* aDocument); - /** * helper to get the document for this content (from the nodeinfo * and such). Not named GetDocument to prevent ambiguous method diff --git a/content/base/src/nsRuleNode.cpp b/content/base/src/nsRuleNode.cpp index 4b8879310138..f75a85916dce 100644 --- a/content/base/src/nsRuleNode.cpp +++ b/content/base/src/nsRuleNode.cpp @@ -55,6 +55,7 @@ #include "nsStyleContext.h" #include "nsStyleSet.h" #include "nsSize.h" +#include "imgIRequest.h" /* * For storage of an |nsRuleNode|'s children in a linked list. @@ -2942,9 +2943,9 @@ nsRuleNode::ComputeBackgroundData(nsStyleStruct* aStartStruct, bg->mBackgroundFlags |= NS_STYLE_BG_COLOR_TRANSPARENT; } - // background-image: url, none, inherit - if (eCSSUnit_URL == colorData.mBackImage.GetUnit()) { - bg->mBackgroundImage = colorData.mBackImage.GetURLValue(); + // background-image: url (stored as image), none, inherit + if (eCSSUnit_Image == colorData.mBackImage.GetUnit()) { + bg->mBackgroundImage = colorData.mBackImage.GetImageValue(); bg->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE; } else if (eCSSUnit_None == colorData.mBackImage.GetUnit()) { diff --git a/content/base/src/nsStyleContext.cpp b/content/base/src/nsStyleContext.cpp index 92fabb7d5436..d053eb8cec12 100644 --- a/content/base/src/nsStyleContext.cpp +++ b/content/base/src/nsStyleContext.cpp @@ -54,6 +54,7 @@ #include "nsRuleNode.h" #include "nsUnitConversion.h" #include "nsStyleContext.h" +#include "imgIRequest.h" #ifdef DEBUG // #define NOISY_DEBUG @@ -532,6 +533,18 @@ public: } } + URICString(imgIRequest* aImageRequest) { + nsCOMPtr uri; + if (aImageRequest) { + aImageRequest->GetURI(getter_AddRefs(uri)); + } + if (uri) { + uri->GetSpec(*this); + } else { + Assign("[none]"); + } + } + URICString& operator=(const URICString& aOther) { Assign(aOther); return *this; diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index db6d2c43f5c1..b1af8d99557a 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -2965,23 +2965,18 @@ nsGenericHTMLElement::MapBackgroundAttributesInto(const nsMappedAttributes* aAtt // as well as elements with _baseHref set. We need to be able // to get to the element somehow, or store the base URI in the // attributes. - nsIPresShell *shell = aData->mPresContext->GetPresShell(); - if (shell) { - nsCOMPtr doc; - nsresult rv = shell->GetDocument(getter_AddRefs(doc)); - if (NS_SUCCEEDED(rv) && doc) { - nsCOMPtr uri; - rv = nsContentUtils::NewURIWithDocumentCharset( - getter_AddRefs(uri), spec, doc, doc->GetBaseURI()); - if (NS_SUCCEEDED(rv)) { - nsCSSValue::URL *url = new nsCSSValue::URL(uri, spec.get()); - if (url) { - if (url->mString) - aData->mColorData->mBackImage.SetURLValue(url); - else - delete url; - } + nsIDocument* doc = aData->mPresContext->GetDocument(); + nsCOMPtr uri; + nsresult rv = nsContentUtils::NewURIWithDocumentCharset( + getter_AddRefs(uri), spec, doc, doc->GetBaseURI()); + if (NS_SUCCEEDED(rv)) { + nsCSSValue::Image *img = new nsCSSValue::Image(uri, spec.get(), doc); + if (img) { + if (img->mString) { + aData->mColorData->mBackImage.SetImageValue(img); } + else + delete img; } } } diff --git a/content/html/style/src/Makefile.in b/content/html/style/src/Makefile.in index a8f6ba3dcb4f..77e981e1e333 100644 --- a/content/html/style/src/Makefile.in +++ b/content/html/style/src/Makefile.in @@ -48,6 +48,7 @@ REQUIRES = xpcom \ view \ intl \ pref \ + imglib2 \ $(NULL) CPPSRCS = \ diff --git a/content/html/style/src/nsCSSDataBlock.cpp b/content/html/style/src/nsCSSDataBlock.cpp index af8caabf124d..f1edbe6cfcdc 100644 --- a/content/html/style/src/nsCSSDataBlock.cpp +++ b/content/html/style/src/nsCSSDataBlock.cpp @@ -185,6 +185,10 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const if (target->GetUnit() == eCSSUnit_Null) { const nsCSSValue *val = ValueAtCursor(cursor); NS_ASSERTION(val->GetUnit() != eCSSUnit_Null, "oops"); + if (iProp == eCSSProperty_background_image && + val->GetUnit() == eCSSUnit_URL) { + val->StartImageLoad(aRuleData->mPresContext->GetDocument()); + } *target = *val; if (iProp == eCSSProperty_font_family) { // XXX Are there other things like this? diff --git a/content/html/style/src/nsCSSDeclaration.cpp b/content/html/style/src/nsCSSDeclaration.cpp index 643c86b5040f..cad6a5b9a265 100644 --- a/content/html/style/src/nsCSSDeclaration.cpp +++ b/content/html/style/src/nsCSSDeclaration.cpp @@ -415,7 +415,7 @@ PRBool nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty, const n aResult.Append(PRUnichar(')')); } - else if (eCSSUnit_URL == unit) { + else if (eCSSUnit_URL == unit || eCSSUnit_Image == unit) { aResult.Append(NS_LITERAL_STRING("url(") + nsDependentString(aValue.GetOriginalURLValue()) + NS_LITERAL_STRING(")")); @@ -441,6 +441,7 @@ PRBool nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty, const n case eCSSUnit_String: break; case eCSSUnit_URL: break; + case eCSSUnit_Image: break; case eCSSUnit_Attr: case eCSSUnit_Counter: case eCSSUnit_Counters: aResult.Append(PRUnichar(')')); break; diff --git a/content/html/style/src/nsCSSValue.cpp b/content/html/style/src/nsCSSValue.cpp index 83ad0fd9831a..30a7ab16da6e 100644 --- a/content/html/style/src/nsCSSValue.cpp +++ b/content/html/style/src/nsCSSValue.cpp @@ -39,6 +39,12 @@ #include "nsString.h" #include "nsCSSProps.h" #include "nsReadableUtils.h" +#include "imgIRequest.h" +#include "nsIDocument.h" +#include "nsContentUtils.h" + +// Paint forcing +#include "prenv.h" //#include "nsStyleConsts.h" @@ -97,6 +103,13 @@ nsCSSValue::nsCSSValue(nsCSSValue::URL* aValue) mValue.mURL->AddRef(); } +nsCSSValue::nsCSSValue(nsCSSValue::Image* aValue) + : mUnit(eCSSUnit_Image) +{ + mValue.mImage = aValue; + mValue.mImage->AddRef(); +} + nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) : mUnit(aCopy.mUnit) { @@ -118,6 +131,10 @@ nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) mValue.mURL = aCopy.mValue.mURL; mValue.mURL->AddRef(); } + else if (eCSSUnit_Image == mUnit){ + mValue.mImage = aCopy.mValue.mImage; + mValue.mImage->AddRef(); + } else { mValue.mFloat = aCopy.mValue.mFloat; } @@ -147,6 +164,10 @@ nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy) mValue.mURL = aCopy.mValue.mURL; mValue.mURL->AddRef(); } + else if (eCSSUnit_Image == mUnit){ + mValue.mImage = aCopy.mValue.mImage; + mValue.mImage->AddRef(); + } else { mValue.mFloat = aCopy.mValue.mFloat; } @@ -175,6 +196,9 @@ PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const else if (eCSSUnit_URL == mUnit) { return *mValue.mURL == *aOther.mValue.mURL; } + else if (eCSSUnit_Image == mUnit) { + return *mValue.mImage == *aOther.mValue.mImage; + } else { return mValue.mFloat == aOther.mValue.mFloat; } @@ -182,6 +206,12 @@ PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const return PR_FALSE; } +imgIRequest* nsCSSValue::GetImageValue() const +{ + NS_ASSERTION(mUnit == eCSSUnit_Image, "not an Image value"); + return mValue.mImage->mRequest; +} + nscoord nsCSSValue::GetLengthTwips() const { NS_ASSERTION(IsFixedLengthUnit(), "not a fixed length unit"); @@ -275,6 +305,14 @@ void nsCSSValue::SetURLValue(nsCSSValue::URL* aValue) mValue.mURL->AddRef(); } +void nsCSSValue::SetImageValue(nsCSSValue::Image* aValue) +{ + Reset(); + mUnit = eCSSUnit_Image; + mValue.mImage = aValue; + mValue.mImage->AddRef(); +} + void nsCSSValue::SetAutoValue() { Reset(); @@ -305,6 +343,52 @@ void nsCSSValue::SetNormalValue() mUnit = eCSSUnit_Normal; } +void nsCSSValue::StartImageLoad(nsIDocument* aDocument) const +{ + NS_PRECONDITION(eCSSUnit_URL == mUnit, "Not a URL value!"); + nsCSSValue::Image* image = + new nsCSSValue::Image(mValue.mURL->mURI, + mValue.mURL->mString, + aDocument); + if (image) { + if (image->mString) { + nsCSSValue* writable = NS_CONST_CAST(nsCSSValue*, this); + writable->SetImageValue(image); + } else { + delete image; + } + } +} + +nsCSSValue::Image::Image(nsIURI* aURI, const PRUnichar* aString, + nsIDocument* aDocument) + : URL(aURI, aString) +{ + MOZ_COUNT_CTOR(nsCSSValue::Image); + + // Check for failed mString allocation first + if (!mString) + return; + + // If Paint Forcing is enabled, then force all background image loads to + // complete before firing onload for the document + static PRInt32 loadFlag = PR_GetEnv("MOZ_FORCE_PAINT_AFTER_ONLOAD") + ? (PRInt32)nsIRequest::LOAD_NORMAL + : (PRInt32)nsIRequest::LOAD_BACKGROUND; + + if (mURI && + NS_SUCCEEDED(nsContentUtils::CanLoadImage(mURI, nsnull, aDocument))) { + nsContentUtils::LoadImage(mURI, aDocument, nsnull, + loadFlag, + getter_AddRefs(mRequest)); + } +} + +nsCSSValue::Image::~Image() +{ + MOZ_COUNT_DTOR(nsCSSValue::Image); +} + #ifdef DEBUG void nsCSSValue::AppendToString(nsAString& aBuffer, @@ -319,14 +403,15 @@ void nsCSSValue::AppendToString(nsAString& aBuffer, aBuffer.Append(NS_LITERAL_STRING(": ")); } + switch (mUnit) { + case eCSSUnit_Image: + case eCSSUnit_URL: aBuffer.Append(NS_LITERAL_STRING("url(")); break; + case eCSSUnit_Attr: aBuffer.Append(NS_LITERAL_STRING("attr(")); break; + case eCSSUnit_Counter: aBuffer.Append(NS_LITERAL_STRING("counter(")); break; + case eCSSUnit_Counters: aBuffer.Append(NS_LITERAL_STRING("counters(")); break; + default: break; + } if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Counters)) { - switch (mUnit) { - case eCSSUnit_URL: aBuffer.Append(NS_LITERAL_STRING("url(")); break; - case eCSSUnit_Attr: aBuffer.Append(NS_LITERAL_STRING("attr(")); break; - case eCSSUnit_Counter: aBuffer.Append(NS_LITERAL_STRING("counter(")); break; - case eCSSUnit_Counters: aBuffer.Append(NS_LITERAL_STRING("counters(")); break; - default: break; - } if (nsnull != mValue.mString) { aBuffer.Append(PRUnichar('"')); aBuffer.Append(mValue.mString); @@ -379,6 +464,9 @@ void nsCSSValue::AppendToString(nsAString& aBuffer, else if (eCSSUnit_URL == mUnit) { aBuffer.Append(mValue.mURL->mString); } + else if (eCSSUnit_Image == mUnit) { + aBuffer.Append(mValue.mImage->mString); + } else if (eCSSUnit_Percent == mUnit) { nsAutoString floatString; floatString.AppendFloat(mValue.mFloat * 100.0f); @@ -399,6 +487,7 @@ void nsCSSValue::AppendToString(nsAString& aBuffer, case eCSSUnit_Normal: aBuffer.Append(NS_LITERAL_STRING("normal")); break; case eCSSUnit_String: break; case eCSSUnit_URL: + case eCSSUnit_Image: case eCSSUnit_Attr: case eCSSUnit_Counter: case eCSSUnit_Counters: aBuffer.Append(NS_LITERAL_STRING(")")); break; diff --git a/content/html/style/src/nsCSSValue.h b/content/html/style/src/nsCSSValue.h index 5f8d6bd007c9..08c0b5785373 100644 --- a/content/html/style/src/nsCSSValue.h +++ b/content/html/style/src/nsCSSValue.h @@ -46,6 +46,10 @@ #include "nsUnitConversion.h" #include "nsIURI.h" #include "nsCOMPtr.h" +#include "nsAutoPtr.h" + +class imgIRequest; +class nsIDocument; enum nsCSSUnit { eCSSUnit_Null = 0, // (n/a) null unit, value is not specified @@ -59,6 +63,7 @@ enum nsCSSUnit { eCSSUnit_Counter = 12, // (PRUnichar*) a counter(string,[string]) value eCSSUnit_Counters = 13, // (PRUnichar*) a counters(string,string[,string]) value eCSSUnit_URL = 14, // (nsCSSValue::URL*) value + eCSSUnit_Image = 15, // (nsCSSValue::Image*) value eCSSUnit_Integer = 50, // (int) simple value eCSSUnit_Enumerated = 51, // (int) value has enumerated meaning eCSSUnit_Color = 80, // (color) an RGBA value @@ -118,6 +123,9 @@ public: struct URL; friend struct URL; + struct Image; + friend struct Image; + // for valueless units only (null, auto, inherit, none, normal) nsCSSValue(nsCSSUnit aUnit = eCSSUnit_Null) : mUnit(aUnit) @@ -134,6 +142,7 @@ public: nsCSSValue(const nsAString& aValue, nsCSSUnit aUnit); nsCSSValue(nscolor aValue); nsCSSValue(URL* aValue); + nsCSSValue(Image* aValue); nsCSSValue(const nsCSSValue& aCopy); ~nsCSSValue(); @@ -204,16 +213,25 @@ public: nsIURI* GetURLValue() const { - NS_ASSERTION(mUnit == eCSSUnit_URL, "not a URL value"); - return mValue.mURL->mURI; + NS_ASSERTION(mUnit == eCSSUnit_URL || mUnit == eCSSUnit_Image, + "not a URL value"); + return mUnit == eCSSUnit_URL ? + mValue.mURL->mURI : mValue.mImage->mURI; } const PRUnichar* GetOriginalURLValue() const { - NS_ASSERTION(mUnit == eCSSUnit_URL, "not a URL value"); - return mValue.mURL->mString; + NS_ASSERTION(mUnit == eCSSUnit_URL || mUnit == eCSSUnit_Image, + "not a URL value"); + return mUnit == eCSSUnit_URL ? + mValue.mURL->mString : mValue.mImage->mString; } + // Not making this inline because that would force us to include + // imgIRequest.h, which leads to REQUIRES hell, since this header is included + // all over. + imgIRequest* GetImageValue() const; + nscoord GetLengthTwips() const; void Reset() // sets to null @@ -223,6 +241,8 @@ public: nsCRT::free(mValue.mString); } else if (eCSSUnit_URL == mUnit) { mValue.mURL->Release(); + } else if (eCSSUnit_Image == mUnit) { + mValue.mImage->Release(); } mUnit = eCSSUnit_Null; mValue.mInt = 0; @@ -234,11 +254,13 @@ public: void SetStringValue(const nsAString& aValue, nsCSSUnit aUnit); void SetColorValue(nscolor aValue); void SetURLValue(nsCSSValue::URL* aURI); + void SetImageValue(nsCSSValue::Image* aImage); void SetAutoValue(); void SetInheritValue(); void SetInitialValue(); void SetNoneValue(); void SetNormalValue(); + void StartImageLoad(nsIDocument* aDocument) const; // Not really const, but pretending #ifdef DEBUG void AppendToString(nsAString& aBuffer, nsCSSProperty aPropID = eCSSProperty_UNKNOWN) const; @@ -282,10 +304,28 @@ public: void AddRef() { ++mRefCnt; } void Release() { if (--mRefCnt == 0) delete this; } - private: + protected: nsrefcnt mRefCnt; }; + MOZ_DECL_CTOR_COUNTER(nsCSSValue::Image) + + struct nsCSSValue::Image : public nsCSSValue::URL { + // Not making the constructor and destructor inline because that would + // force us to include imgIRequest.h, which leads to REQUIRES hell, since + // this header is included all over. + Image(nsIURI* aURI, const PRUnichar* aString, nsIDocument* aDocument); + ~Image(); + + // Inherit operator== from nsCSSValue::URL + + nsCOMPtr mRequest; // null == image load blocked or somehow failed + + // Override AddRef/Release so we delete ourselves via the right pointer. + void AddRef() { ++mRefCnt; } + void Release() { if (--mRefCnt == 0) delete this; } + }; + protected: nsCSSUnit mUnit; union { @@ -294,6 +334,7 @@ protected: PRUnichar* mString; nscolor mColor; URL* mURL; + Image* mImage; } mValue; }; diff --git a/content/html/style/src/nsComputedDOMStyle.cpp b/content/html/style/src/nsComputedDOMStyle.cpp index 0e1fbddccdd6..9f01f3a8fede 100644 --- a/content/html/style/src/nsComputedDOMStyle.cpp +++ b/content/html/style/src/nsComputedDOMStyle.cpp @@ -60,6 +60,7 @@ #include "nsCSSPseudoElements.h" #include "nsStyleSet.h" +#include "imgIRequest.h" #if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon) #define DEBUG_ComputedDOMStyle @@ -723,7 +724,11 @@ nsComputedDOMStyle::GetBackgroundImage(nsIFrame *aFrame, if (color->mBackgroundFlags & NS_STYLE_BG_IMAGE_NONE) { val->SetIdent(nsLayoutAtoms::none); } else { - val->SetURI(color->mBackgroundImage); + nsCOMPtr uri; + if (color->mBackgroundImage) { + color->mBackgroundImage->GetURI(getter_AddRefs(uri)); + } + val->SetURI(uri); } } diff --git a/content/shared/public/nsStyleStruct.h b/content/shared/public/nsStyleStruct.h index e84aa2073550..71a20560a420 100644 --- a/content/shared/public/nsStyleStruct.h +++ b/content/shared/public/nsStyleStruct.h @@ -54,6 +54,7 @@ #include "nsIURI.h" class nsIFrame; +class imgIRequest; enum nsStyleStructID { @@ -147,7 +148,7 @@ struct nsStyleColor : public nsStyleStruct { struct nsStyleBackground : public nsStyleStruct { nsStyleBackground(nsIPresContext* aPresContext); nsStyleBackground(const nsStyleBackground& aOther); - ~nsStyleBackground() {}; + ~nsStyleBackground(); NS_DEFINE_STATIC_STYLESTRUCTID_ACCESSOR(eStyleStruct_Background) @@ -183,7 +184,7 @@ struct nsStyleBackground : public nsStyleStruct { mBackgroundYPosition; // [reset] nscolor mBackgroundColor; // [reset] - nsCOMPtr mBackgroundImage; // [reset] + nsCOMPtr mBackgroundImage; // [reset] PRBool IsTransparent() const { diff --git a/content/shared/src/Makefile.in b/content/shared/src/Makefile.in index a9f6ff43a72a..6ea1c3790372 100644 --- a/content/shared/src/Makefile.in +++ b/content/shared/src/Makefile.in @@ -37,6 +37,7 @@ REQUIRES = xpcom \ dom \ necko \ unicharutil \ + imglib2 \ $(NULL) CPPSRCS = \ diff --git a/content/shared/src/nsStyleStruct.cpp b/content/shared/src/nsStyleStruct.cpp index 726d3166ec85..d4d217a5c21d 100644 --- a/content/shared/src/nsStyleStruct.cpp +++ b/content/shared/src/nsStyleStruct.cpp @@ -55,6 +55,8 @@ #include "nsBidiUtils.h" +#include "imgIRequest.h" + inline PRBool IsFixedUnit(nsStyleUnit aUnit, PRBool aEnumOK) { return PRBool((aUnit == eStyleUnit_Null) || @@ -162,6 +164,22 @@ static PRBool EqualURIs(nsIURI *aURI1, nsIURI *aURI2) eq); } +static PRBool EqualImages(imgIRequest *aImage1, imgIRequest* aImage2) +{ + if (aImage1 == aImage2) { + return PR_TRUE; + } + + if (!aImage1 || !aImage2) { + return PR_FALSE; + } + + nsCOMPtr uri1, uri2; + aImage1->GetURI(getter_AddRefs(uri1)); + aImage2->GetURI(getter_AddRefs(uri2)); + return EqualURIs(uri1, uri2); +} + // -------------------- // nsStyleFont // @@ -1019,6 +1037,10 @@ nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource) { } +nsStyleBackground::~nsStyleBackground() +{ +} + nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) const { if (mBackgroundAttachment != aOther.mBackgroundAttachment @@ -1036,7 +1058,7 @@ nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) (mBackgroundClip == aOther.mBackgroundClip) && (mBackgroundInlinePolicy == aOther.mBackgroundInlinePolicy) && (mBackgroundOrigin == aOther.mBackgroundOrigin) && - EqualURIs(mBackgroundImage, aOther.mBackgroundImage) && + EqualImages(mBackgroundImage, aOther.mBackgroundImage) && ((!(mBackgroundFlags & NS_STYLE_BG_X_POSITION_PERCENT) || (mBackgroundXPosition.mFloat == aOther.mBackgroundXPosition.mFloat)) && (!(mBackgroundFlags & NS_STYLE_BG_X_POSITION_LENGTH) || diff --git a/layout/base/nsFrameManager.cpp b/layout/base/nsFrameManager.cpp index 8bc009d97f76..510b127693d4 100644 --- a/layout/base/nsFrameManager.cpp +++ b/layout/base/nsFrameManager.cpp @@ -74,6 +74,7 @@ #include "nsLayoutErrors.h" #include "nsLayoutUtils.h" #include "nsAutoPtr.h" +#include "imgIRequest.h" #include "nsFrameManager.h" @@ -1420,14 +1421,20 @@ nsFrameManager::ReResolveStyleContext(nsIPresContext *aPresContext, const nsStyleBackground* oldColor = oldContext->GetStyleBackground(); const nsStyleBackground* newColor = newContext->GetStyleBackground(); - PRBool equal; - if (oldColor->mBackgroundImage && - (!newColor->mBackgroundImage || - NS_FAILED(oldColor->mBackgroundImage->Equals( - newColor->mBackgroundImage, &equal)) || - !equal)) { - // stop the image loading for the frame, the image has changed - aPresContext->StopImagesFor(aFrame); + if (oldColor->mBackgroundImage) { + PRBool stopImages = !newColor->mBackgroundImage; + if (!stopImages) { + nsCOMPtr oldURI, newURI; + oldColor->mBackgroundImage->GetURI(getter_AddRefs(oldURI)); + newColor->mBackgroundImage->GetURI(getter_AddRefs(newURI)); + PRBool equal; + stopImages = + NS_FAILED(oldURI->Equals(newURI, &equal)) || !equal; + } + if (stopImages) { + // stop the image loading for the frame, the image has changed + aPresContext->StopImagesFor(aFrame); + } } } oldContext->Release(); diff --git a/layout/base/nsImageLoader.cpp b/layout/base/nsImageLoader.cpp index eba9249d6a58..827bc6a0ab3a 100644 --- a/layout/base/nsImageLoader.cpp +++ b/layout/base/nsImageLoader.cpp @@ -83,51 +83,31 @@ nsImageLoader::Destroy() } nsresult -nsImageLoader::Load(nsIURI *aURI) +nsImageLoader::Load(imgIRequest *aImage) { if (!mFrame) return NS_ERROR_NOT_INITIALIZED; - if (!aURI) + if (!aImage) return NS_ERROR_FAILURE; - nsIPresShell *shell = mPresContext->GetPresShell(); - if (!shell) return NS_ERROR_FAILURE; - - nsCOMPtr doc; - nsresult rv = shell->GetDocument(getter_AddRefs(doc)); - if (NS_FAILED(rv)) return rv; - - // Get the document's loadgroup - nsCOMPtr loadGroup = doc->GetDocumentLoadGroup(); - if (mRequest) { nsCOMPtr oldURI; mRequest->GetURI(getter_AddRefs(oldURI)); + nsCOMPtr newURI; + aImage->GetURI(getter_AddRefs(newURI)); PRBool eq = PR_FALSE; - aURI->Equals(oldURI, &eq); - if (eq) { + 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; } - nsCOMPtr il(do_GetService("@mozilla.org/image/loader;1", &rv)); - if (NS_FAILED(rv)) return rv; - - // If Paint Forcing is enabled, then force all background image loads - // to complete before firing onload for the document - static PRInt32 loadFlag - = PR_GetEnv("MOZ_FORCE_PAINT_AFTER_ONLOAD") - ? (PRInt32)nsIRequest::LOAD_NORMAL - : (PRInt32)nsIRequest::LOAD_BACKGROUND; - - // XXX: initialDocumentURI is NULL! - return il->LoadImage(aURI, nsnull, doc->GetDocumentURI(), loadGroup, - this, doc, loadFlag, nsnull, nsnull, - getter_AddRefs(mRequest)); + return aImage->Clone(this, getter_AddRefs(mRequest)); } @@ -188,6 +168,11 @@ NS_IMETHODIMP nsImageLoader::OnStopFrame(imgIRequest *aRequest, } #endif + if (!mRequest) { + // We're in the middle of a paint anyway + return NS_OK; + } + // Draw the background image RedrawDirtyFrame(nsnull); return NS_OK; @@ -213,6 +198,11 @@ NS_IMETHODIMP nsImageLoader::FrameChanged(imgIContainer *aContainer, if (!mFrame) return NS_ERROR_FAILURE; + if (!mRequest) { + // We're in the middle of a paint anyway + return NS_OK; + } + nsRect r(*dirtyRect); float p2t; diff --git a/layout/base/nsImageLoader.h b/layout/base/nsImageLoader.h index c61dc3bfd971..6531de282bfa 100644 --- a/layout/base/nsImageLoader.h +++ b/layout/base/nsImageLoader.h @@ -41,7 +41,7 @@ public: NS_DECL_IMGICONTAINEROBSERVER void Init(nsIFrame *aFrame, nsIPresContext *aPresContext); - nsresult Load(nsIURI *aURI); + nsresult Load(imgIRequest *aImage); void Destroy(); diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 62cc40276b2f..e81eb9a9c857 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -945,7 +945,7 @@ nsPresContext::GetScaledPixelsToTwips(float* aResult) const } nsresult -nsPresContext::LoadImage(nsIURI* aURL, +nsPresContext::LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame,//may be null (precached image) imgIRequest **aRequest) { @@ -955,30 +955,6 @@ nsPresContext::LoadImage(nsIURI* aURL, nsImageLoader *loader = NS_REINTERPRET_CAST(nsImageLoader*, mImageLoaders.Get(&key)); // addrefs if (!loader) { - nsIContent* content = aTargetFrame->GetContent(); - - // Check with the content-policy things to make sure this load is permitted. - nsresult rv; - nsCOMPtr element(do_QueryInterface(content)); - - if (content && element) { - nsCOMPtr document = content->GetDocument(); - - // If there is no document, skip the policy check - // XXXldb This really means the document is being destroyed, so - // perhaps we're better off skipping the load entirely. - if (document) { - nsCOMPtr domWin(do_QueryInterface(document->GetScriptGlobalObject())); - if (domWin) { - PRBool shouldLoad = PR_TRUE; - rv = NS_CheckContentLoadPolicy(nsIContentPolicy::IMAGE, - aURL, element, domWin, &shouldLoad); - if (NS_SUCCEEDED(rv) && !shouldLoad) - return NS_ERROR_FAILURE; - } - } - } - loader = new nsImageLoader(); if (!loader) return NS_ERROR_OUT_OF_MEMORY; @@ -989,7 +965,7 @@ nsPresContext::LoadImage(nsIURI* aURL, mImageLoaders.Put(&key, loader); } - loader->Load(aURL); + loader->Load(aImage); NS_IF_ADDREF(*aRequest = loader->GetRequest()); diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 9a66cb568cc4..3f601d736271 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -260,7 +260,7 @@ public: * method will be invoked (via the ViewManager) so that the * appropriate damage repair is done. */ - virtual nsresult LoadImage(nsIURI* aURL, + virtual nsresult LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame, imgIRequest **aRequest) = 0; diff --git a/layout/base/public/nsIPresContext.h b/layout/base/public/nsIPresContext.h index 9a66cb568cc4..3f601d736271 100644 --- a/layout/base/public/nsIPresContext.h +++ b/layout/base/public/nsIPresContext.h @@ -260,7 +260,7 @@ public: * method will be invoked (via the ViewManager) so that the * appropriate damage repair is done. */ - virtual nsresult LoadImage(nsIURI* aURL, + virtual nsresult LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame, imgIRequest **aRequest) = 0; diff --git a/layout/base/public/nsPresContext.h b/layout/base/public/nsPresContext.h index 9a66cb568cc4..3f601d736271 100644 --- a/layout/base/public/nsPresContext.h +++ b/layout/base/public/nsPresContext.h @@ -260,7 +260,7 @@ public: * method will be invoked (via the ViewManager) so that the * appropriate damage repair is done. */ - virtual nsresult LoadImage(nsIURI* aURL, + virtual nsresult LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame, imgIRequest **aRequest) = 0; diff --git a/layout/base/src/nsImageLoader.cpp b/layout/base/src/nsImageLoader.cpp index eba9249d6a58..827bc6a0ab3a 100644 --- a/layout/base/src/nsImageLoader.cpp +++ b/layout/base/src/nsImageLoader.cpp @@ -83,51 +83,31 @@ nsImageLoader::Destroy() } nsresult -nsImageLoader::Load(nsIURI *aURI) +nsImageLoader::Load(imgIRequest *aImage) { if (!mFrame) return NS_ERROR_NOT_INITIALIZED; - if (!aURI) + if (!aImage) return NS_ERROR_FAILURE; - nsIPresShell *shell = mPresContext->GetPresShell(); - if (!shell) return NS_ERROR_FAILURE; - - nsCOMPtr doc; - nsresult rv = shell->GetDocument(getter_AddRefs(doc)); - if (NS_FAILED(rv)) return rv; - - // Get the document's loadgroup - nsCOMPtr loadGroup = doc->GetDocumentLoadGroup(); - if (mRequest) { nsCOMPtr oldURI; mRequest->GetURI(getter_AddRefs(oldURI)); + nsCOMPtr newURI; + aImage->GetURI(getter_AddRefs(newURI)); PRBool eq = PR_FALSE; - aURI->Equals(oldURI, &eq); - if (eq) { + 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; } - nsCOMPtr il(do_GetService("@mozilla.org/image/loader;1", &rv)); - if (NS_FAILED(rv)) return rv; - - // If Paint Forcing is enabled, then force all background image loads - // to complete before firing onload for the document - static PRInt32 loadFlag - = PR_GetEnv("MOZ_FORCE_PAINT_AFTER_ONLOAD") - ? (PRInt32)nsIRequest::LOAD_NORMAL - : (PRInt32)nsIRequest::LOAD_BACKGROUND; - - // XXX: initialDocumentURI is NULL! - return il->LoadImage(aURI, nsnull, doc->GetDocumentURI(), loadGroup, - this, doc, loadFlag, nsnull, nsnull, - getter_AddRefs(mRequest)); + return aImage->Clone(this, getter_AddRefs(mRequest)); } @@ -188,6 +168,11 @@ NS_IMETHODIMP nsImageLoader::OnStopFrame(imgIRequest *aRequest, } #endif + if (!mRequest) { + // We're in the middle of a paint anyway + return NS_OK; + } + // Draw the background image RedrawDirtyFrame(nsnull); return NS_OK; @@ -213,6 +198,11 @@ NS_IMETHODIMP nsImageLoader::FrameChanged(imgIContainer *aContainer, if (!mFrame) return NS_ERROR_FAILURE; + if (!mRequest) { + // We're in the middle of a paint anyway + return NS_OK; + } + nsRect r(*dirtyRect); float p2t; diff --git a/layout/base/src/nsImageLoader.h b/layout/base/src/nsImageLoader.h index c61dc3bfd971..6531de282bfa 100644 --- a/layout/base/src/nsImageLoader.h +++ b/layout/base/src/nsImageLoader.h @@ -41,7 +41,7 @@ public: NS_DECL_IMGICONTAINEROBSERVER void Init(nsIFrame *aFrame, nsIPresContext *aPresContext); - nsresult Load(nsIURI *aURI); + nsresult Load(imgIRequest *aImage); void Destroy(); diff --git a/layout/base/src/nsPresContext.cpp b/layout/base/src/nsPresContext.cpp index 62cc40276b2f..e81eb9a9c857 100644 --- a/layout/base/src/nsPresContext.cpp +++ b/layout/base/src/nsPresContext.cpp @@ -945,7 +945,7 @@ nsPresContext::GetScaledPixelsToTwips(float* aResult) const } nsresult -nsPresContext::LoadImage(nsIURI* aURL, +nsPresContext::LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame,//may be null (precached image) imgIRequest **aRequest) { @@ -955,30 +955,6 @@ nsPresContext::LoadImage(nsIURI* aURL, nsImageLoader *loader = NS_REINTERPRET_CAST(nsImageLoader*, mImageLoaders.Get(&key)); // addrefs if (!loader) { - nsIContent* content = aTargetFrame->GetContent(); - - // Check with the content-policy things to make sure this load is permitted. - nsresult rv; - nsCOMPtr element(do_QueryInterface(content)); - - if (content && element) { - nsCOMPtr document = content->GetDocument(); - - // If there is no document, skip the policy check - // XXXldb This really means the document is being destroyed, so - // perhaps we're better off skipping the load entirely. - if (document) { - nsCOMPtr domWin(do_QueryInterface(document->GetScriptGlobalObject())); - if (domWin) { - PRBool shouldLoad = PR_TRUE; - rv = NS_CheckContentLoadPolicy(nsIContentPolicy::IMAGE, - aURL, element, domWin, &shouldLoad); - if (NS_SUCCEEDED(rv) && !shouldLoad) - return NS_ERROR_FAILURE; - } - } - } - loader = new nsImageLoader(); if (!loader) return NS_ERROR_OUT_OF_MEMORY; @@ -989,7 +965,7 @@ nsPresContext::LoadImage(nsIURI* aURL, mImageLoaders.Put(&key, loader); } - loader->Load(aURL); + loader->Load(aImage); NS_IF_ADDREF(*aRequest = loader->GetRequest()); diff --git a/layout/base/src/nsPresContext.h b/layout/base/src/nsPresContext.h index c637746a58dc..18f35791a692 100644 --- a/layout/base/src/nsPresContext.h +++ b/layout/base/src/nsPresContext.h @@ -79,7 +79,7 @@ public: virtual const nsFont* GetDefaultFont(PRUint8 aFontID) const; NS_IMETHOD GetCachedIntPref(PRUint32 aPrefType, PRInt32& aValue); - virtual nsresult LoadImage(nsIURI* aURL, + virtual nsresult LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame, imgIRequest **aRequest); diff --git a/layout/html/base/src/nsFrameManager.cpp b/layout/html/base/src/nsFrameManager.cpp index 8bc009d97f76..510b127693d4 100644 --- a/layout/html/base/src/nsFrameManager.cpp +++ b/layout/html/base/src/nsFrameManager.cpp @@ -74,6 +74,7 @@ #include "nsLayoutErrors.h" #include "nsLayoutUtils.h" #include "nsAutoPtr.h" +#include "imgIRequest.h" #include "nsFrameManager.h" @@ -1420,14 +1421,20 @@ nsFrameManager::ReResolveStyleContext(nsIPresContext *aPresContext, const nsStyleBackground* oldColor = oldContext->GetStyleBackground(); const nsStyleBackground* newColor = newContext->GetStyleBackground(); - PRBool equal; - if (oldColor->mBackgroundImage && - (!newColor->mBackgroundImage || - NS_FAILED(oldColor->mBackgroundImage->Equals( - newColor->mBackgroundImage, &equal)) || - !equal)) { - // stop the image loading for the frame, the image has changed - aPresContext->StopImagesFor(aFrame); + if (oldColor->mBackgroundImage) { + PRBool stopImages = !newColor->mBackgroundImage; + if (!stopImages) { + nsCOMPtr oldURI, newURI; + oldColor->mBackgroundImage->GetURI(getter_AddRefs(oldURI)); + newColor->mBackgroundImage->GetURI(getter_AddRefs(newURI)); + PRBool equal; + stopImages = + NS_FAILED(oldURI->Equals(newURI, &equal)) || !equal; + } + if (stopImages) { + // stop the image loading for the frame, the image has changed + aPresContext->StopImagesFor(aFrame); + } } } oldContext->Release(); diff --git a/layout/style/nsCSSDataBlock.cpp b/layout/style/nsCSSDataBlock.cpp index af8caabf124d..f1edbe6cfcdc 100644 --- a/layout/style/nsCSSDataBlock.cpp +++ b/layout/style/nsCSSDataBlock.cpp @@ -185,6 +185,10 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const if (target->GetUnit() == eCSSUnit_Null) { const nsCSSValue *val = ValueAtCursor(cursor); NS_ASSERTION(val->GetUnit() != eCSSUnit_Null, "oops"); + if (iProp == eCSSProperty_background_image && + val->GetUnit() == eCSSUnit_URL) { + val->StartImageLoad(aRuleData->mPresContext->GetDocument()); + } *target = *val; if (iProp == eCSSProperty_font_family) { // XXX Are there other things like this? diff --git a/layout/style/nsCSSDeclaration.cpp b/layout/style/nsCSSDeclaration.cpp index 643c86b5040f..cad6a5b9a265 100644 --- a/layout/style/nsCSSDeclaration.cpp +++ b/layout/style/nsCSSDeclaration.cpp @@ -415,7 +415,7 @@ PRBool nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty, const n aResult.Append(PRUnichar(')')); } - else if (eCSSUnit_URL == unit) { + else if (eCSSUnit_URL == unit || eCSSUnit_Image == unit) { aResult.Append(NS_LITERAL_STRING("url(") + nsDependentString(aValue.GetOriginalURLValue()) + NS_LITERAL_STRING(")")); @@ -441,6 +441,7 @@ PRBool nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty, const n case eCSSUnit_String: break; case eCSSUnit_URL: break; + case eCSSUnit_Image: break; case eCSSUnit_Attr: case eCSSUnit_Counter: case eCSSUnit_Counters: aResult.Append(PRUnichar(')')); break; diff --git a/layout/style/nsCSSValue.cpp b/layout/style/nsCSSValue.cpp index 83ad0fd9831a..30a7ab16da6e 100644 --- a/layout/style/nsCSSValue.cpp +++ b/layout/style/nsCSSValue.cpp @@ -39,6 +39,12 @@ #include "nsString.h" #include "nsCSSProps.h" #include "nsReadableUtils.h" +#include "imgIRequest.h" +#include "nsIDocument.h" +#include "nsContentUtils.h" + +// Paint forcing +#include "prenv.h" //#include "nsStyleConsts.h" @@ -97,6 +103,13 @@ nsCSSValue::nsCSSValue(nsCSSValue::URL* aValue) mValue.mURL->AddRef(); } +nsCSSValue::nsCSSValue(nsCSSValue::Image* aValue) + : mUnit(eCSSUnit_Image) +{ + mValue.mImage = aValue; + mValue.mImage->AddRef(); +} + nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) : mUnit(aCopy.mUnit) { @@ -118,6 +131,10 @@ nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) mValue.mURL = aCopy.mValue.mURL; mValue.mURL->AddRef(); } + else if (eCSSUnit_Image == mUnit){ + mValue.mImage = aCopy.mValue.mImage; + mValue.mImage->AddRef(); + } else { mValue.mFloat = aCopy.mValue.mFloat; } @@ -147,6 +164,10 @@ nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy) mValue.mURL = aCopy.mValue.mURL; mValue.mURL->AddRef(); } + else if (eCSSUnit_Image == mUnit){ + mValue.mImage = aCopy.mValue.mImage; + mValue.mImage->AddRef(); + } else { mValue.mFloat = aCopy.mValue.mFloat; } @@ -175,6 +196,9 @@ PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const else if (eCSSUnit_URL == mUnit) { return *mValue.mURL == *aOther.mValue.mURL; } + else if (eCSSUnit_Image == mUnit) { + return *mValue.mImage == *aOther.mValue.mImage; + } else { return mValue.mFloat == aOther.mValue.mFloat; } @@ -182,6 +206,12 @@ PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const return PR_FALSE; } +imgIRequest* nsCSSValue::GetImageValue() const +{ + NS_ASSERTION(mUnit == eCSSUnit_Image, "not an Image value"); + return mValue.mImage->mRequest; +} + nscoord nsCSSValue::GetLengthTwips() const { NS_ASSERTION(IsFixedLengthUnit(), "not a fixed length unit"); @@ -275,6 +305,14 @@ void nsCSSValue::SetURLValue(nsCSSValue::URL* aValue) mValue.mURL->AddRef(); } +void nsCSSValue::SetImageValue(nsCSSValue::Image* aValue) +{ + Reset(); + mUnit = eCSSUnit_Image; + mValue.mImage = aValue; + mValue.mImage->AddRef(); +} + void nsCSSValue::SetAutoValue() { Reset(); @@ -305,6 +343,52 @@ void nsCSSValue::SetNormalValue() mUnit = eCSSUnit_Normal; } +void nsCSSValue::StartImageLoad(nsIDocument* aDocument) const +{ + NS_PRECONDITION(eCSSUnit_URL == mUnit, "Not a URL value!"); + nsCSSValue::Image* image = + new nsCSSValue::Image(mValue.mURL->mURI, + mValue.mURL->mString, + aDocument); + if (image) { + if (image->mString) { + nsCSSValue* writable = NS_CONST_CAST(nsCSSValue*, this); + writable->SetImageValue(image); + } else { + delete image; + } + } +} + +nsCSSValue::Image::Image(nsIURI* aURI, const PRUnichar* aString, + nsIDocument* aDocument) + : URL(aURI, aString) +{ + MOZ_COUNT_CTOR(nsCSSValue::Image); + + // Check for failed mString allocation first + if (!mString) + return; + + // If Paint Forcing is enabled, then force all background image loads to + // complete before firing onload for the document + static PRInt32 loadFlag = PR_GetEnv("MOZ_FORCE_PAINT_AFTER_ONLOAD") + ? (PRInt32)nsIRequest::LOAD_NORMAL + : (PRInt32)nsIRequest::LOAD_BACKGROUND; + + if (mURI && + NS_SUCCEEDED(nsContentUtils::CanLoadImage(mURI, nsnull, aDocument))) { + nsContentUtils::LoadImage(mURI, aDocument, nsnull, + loadFlag, + getter_AddRefs(mRequest)); + } +} + +nsCSSValue::Image::~Image() +{ + MOZ_COUNT_DTOR(nsCSSValue::Image); +} + #ifdef DEBUG void nsCSSValue::AppendToString(nsAString& aBuffer, @@ -319,14 +403,15 @@ void nsCSSValue::AppendToString(nsAString& aBuffer, aBuffer.Append(NS_LITERAL_STRING(": ")); } + switch (mUnit) { + case eCSSUnit_Image: + case eCSSUnit_URL: aBuffer.Append(NS_LITERAL_STRING("url(")); break; + case eCSSUnit_Attr: aBuffer.Append(NS_LITERAL_STRING("attr(")); break; + case eCSSUnit_Counter: aBuffer.Append(NS_LITERAL_STRING("counter(")); break; + case eCSSUnit_Counters: aBuffer.Append(NS_LITERAL_STRING("counters(")); break; + default: break; + } if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Counters)) { - switch (mUnit) { - case eCSSUnit_URL: aBuffer.Append(NS_LITERAL_STRING("url(")); break; - case eCSSUnit_Attr: aBuffer.Append(NS_LITERAL_STRING("attr(")); break; - case eCSSUnit_Counter: aBuffer.Append(NS_LITERAL_STRING("counter(")); break; - case eCSSUnit_Counters: aBuffer.Append(NS_LITERAL_STRING("counters(")); break; - default: break; - } if (nsnull != mValue.mString) { aBuffer.Append(PRUnichar('"')); aBuffer.Append(mValue.mString); @@ -379,6 +464,9 @@ void nsCSSValue::AppendToString(nsAString& aBuffer, else if (eCSSUnit_URL == mUnit) { aBuffer.Append(mValue.mURL->mString); } + else if (eCSSUnit_Image == mUnit) { + aBuffer.Append(mValue.mImage->mString); + } else if (eCSSUnit_Percent == mUnit) { nsAutoString floatString; floatString.AppendFloat(mValue.mFloat * 100.0f); @@ -399,6 +487,7 @@ void nsCSSValue::AppendToString(nsAString& aBuffer, case eCSSUnit_Normal: aBuffer.Append(NS_LITERAL_STRING("normal")); break; case eCSSUnit_String: break; case eCSSUnit_URL: + case eCSSUnit_Image: case eCSSUnit_Attr: case eCSSUnit_Counter: case eCSSUnit_Counters: aBuffer.Append(NS_LITERAL_STRING(")")); break; diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h index 5f8d6bd007c9..08c0b5785373 100644 --- a/layout/style/nsCSSValue.h +++ b/layout/style/nsCSSValue.h @@ -46,6 +46,10 @@ #include "nsUnitConversion.h" #include "nsIURI.h" #include "nsCOMPtr.h" +#include "nsAutoPtr.h" + +class imgIRequest; +class nsIDocument; enum nsCSSUnit { eCSSUnit_Null = 0, // (n/a) null unit, value is not specified @@ -59,6 +63,7 @@ enum nsCSSUnit { eCSSUnit_Counter = 12, // (PRUnichar*) a counter(string,[string]) value eCSSUnit_Counters = 13, // (PRUnichar*) a counters(string,string[,string]) value eCSSUnit_URL = 14, // (nsCSSValue::URL*) value + eCSSUnit_Image = 15, // (nsCSSValue::Image*) value eCSSUnit_Integer = 50, // (int) simple value eCSSUnit_Enumerated = 51, // (int) value has enumerated meaning eCSSUnit_Color = 80, // (color) an RGBA value @@ -118,6 +123,9 @@ public: struct URL; friend struct URL; + struct Image; + friend struct Image; + // for valueless units only (null, auto, inherit, none, normal) nsCSSValue(nsCSSUnit aUnit = eCSSUnit_Null) : mUnit(aUnit) @@ -134,6 +142,7 @@ public: nsCSSValue(const nsAString& aValue, nsCSSUnit aUnit); nsCSSValue(nscolor aValue); nsCSSValue(URL* aValue); + nsCSSValue(Image* aValue); nsCSSValue(const nsCSSValue& aCopy); ~nsCSSValue(); @@ -204,16 +213,25 @@ public: nsIURI* GetURLValue() const { - NS_ASSERTION(mUnit == eCSSUnit_URL, "not a URL value"); - return mValue.mURL->mURI; + NS_ASSERTION(mUnit == eCSSUnit_URL || mUnit == eCSSUnit_Image, + "not a URL value"); + return mUnit == eCSSUnit_URL ? + mValue.mURL->mURI : mValue.mImage->mURI; } const PRUnichar* GetOriginalURLValue() const { - NS_ASSERTION(mUnit == eCSSUnit_URL, "not a URL value"); - return mValue.mURL->mString; + NS_ASSERTION(mUnit == eCSSUnit_URL || mUnit == eCSSUnit_Image, + "not a URL value"); + return mUnit == eCSSUnit_URL ? + mValue.mURL->mString : mValue.mImage->mString; } + // Not making this inline because that would force us to include + // imgIRequest.h, which leads to REQUIRES hell, since this header is included + // all over. + imgIRequest* GetImageValue() const; + nscoord GetLengthTwips() const; void Reset() // sets to null @@ -223,6 +241,8 @@ public: nsCRT::free(mValue.mString); } else if (eCSSUnit_URL == mUnit) { mValue.mURL->Release(); + } else if (eCSSUnit_Image == mUnit) { + mValue.mImage->Release(); } mUnit = eCSSUnit_Null; mValue.mInt = 0; @@ -234,11 +254,13 @@ public: void SetStringValue(const nsAString& aValue, nsCSSUnit aUnit); void SetColorValue(nscolor aValue); void SetURLValue(nsCSSValue::URL* aURI); + void SetImageValue(nsCSSValue::Image* aImage); void SetAutoValue(); void SetInheritValue(); void SetInitialValue(); void SetNoneValue(); void SetNormalValue(); + void StartImageLoad(nsIDocument* aDocument) const; // Not really const, but pretending #ifdef DEBUG void AppendToString(nsAString& aBuffer, nsCSSProperty aPropID = eCSSProperty_UNKNOWN) const; @@ -282,10 +304,28 @@ public: void AddRef() { ++mRefCnt; } void Release() { if (--mRefCnt == 0) delete this; } - private: + protected: nsrefcnt mRefCnt; }; + MOZ_DECL_CTOR_COUNTER(nsCSSValue::Image) + + struct nsCSSValue::Image : public nsCSSValue::URL { + // Not making the constructor and destructor inline because that would + // force us to include imgIRequest.h, which leads to REQUIRES hell, since + // this header is included all over. + Image(nsIURI* aURI, const PRUnichar* aString, nsIDocument* aDocument); + ~Image(); + + // Inherit operator== from nsCSSValue::URL + + nsCOMPtr mRequest; // null == image load blocked or somehow failed + + // Override AddRef/Release so we delete ourselves via the right pointer. + void AddRef() { ++mRefCnt; } + void Release() { if (--mRefCnt == 0) delete this; } + }; + protected: nsCSSUnit mUnit; union { @@ -294,6 +334,7 @@ protected: PRUnichar* mString; nscolor mColor; URL* mURL; + Image* mImage; } mValue; }; diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 0e1fbddccdd6..9f01f3a8fede 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -60,6 +60,7 @@ #include "nsCSSPseudoElements.h" #include "nsStyleSet.h" +#include "imgIRequest.h" #if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon) #define DEBUG_ComputedDOMStyle @@ -723,7 +724,11 @@ nsComputedDOMStyle::GetBackgroundImage(nsIFrame *aFrame, if (color->mBackgroundFlags & NS_STYLE_BG_IMAGE_NONE) { val->SetIdent(nsLayoutAtoms::none); } else { - val->SetURI(color->mBackgroundImage); + nsCOMPtr uri; + if (color->mBackgroundImage) { + color->mBackgroundImage->GetURI(getter_AddRefs(uri)); + } + val->SetURI(uri); } } diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 4b8879310138..f75a85916dce 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -55,6 +55,7 @@ #include "nsStyleContext.h" #include "nsStyleSet.h" #include "nsSize.h" +#include "imgIRequest.h" /* * For storage of an |nsRuleNode|'s children in a linked list. @@ -2942,9 +2943,9 @@ nsRuleNode::ComputeBackgroundData(nsStyleStruct* aStartStruct, bg->mBackgroundFlags |= NS_STYLE_BG_COLOR_TRANSPARENT; } - // background-image: url, none, inherit - if (eCSSUnit_URL == colorData.mBackImage.GetUnit()) { - bg->mBackgroundImage = colorData.mBackImage.GetURLValue(); + // background-image: url (stored as image), none, inherit + if (eCSSUnit_Image == colorData.mBackImage.GetUnit()) { + bg->mBackgroundImage = colorData.mBackImage.GetImageValue(); bg->mBackgroundFlags &= ~NS_STYLE_BG_IMAGE_NONE; } else if (eCSSUnit_None == colorData.mBackImage.GetUnit()) { diff --git a/layout/style/nsStyleContext.cpp b/layout/style/nsStyleContext.cpp index 92fabb7d5436..d053eb8cec12 100644 --- a/layout/style/nsStyleContext.cpp +++ b/layout/style/nsStyleContext.cpp @@ -54,6 +54,7 @@ #include "nsRuleNode.h" #include "nsUnitConversion.h" #include "nsStyleContext.h" +#include "imgIRequest.h" #ifdef DEBUG // #define NOISY_DEBUG @@ -532,6 +533,18 @@ public: } } + URICString(imgIRequest* aImageRequest) { + nsCOMPtr uri; + if (aImageRequest) { + aImageRequest->GetURI(getter_AddRefs(uri)); + } + if (uri) { + uri->GetSpec(*this); + } else { + Assign("[none]"); + } + } + URICString& operator=(const URICString& aOther) { Assign(aOther); return *this; diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 726d3166ec85..d4d217a5c21d 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -55,6 +55,8 @@ #include "nsBidiUtils.h" +#include "imgIRequest.h" + inline PRBool IsFixedUnit(nsStyleUnit aUnit, PRBool aEnumOK) { return PRBool((aUnit == eStyleUnit_Null) || @@ -162,6 +164,22 @@ static PRBool EqualURIs(nsIURI *aURI1, nsIURI *aURI2) eq); } +static PRBool EqualImages(imgIRequest *aImage1, imgIRequest* aImage2) +{ + if (aImage1 == aImage2) { + return PR_TRUE; + } + + if (!aImage1 || !aImage2) { + return PR_FALSE; + } + + nsCOMPtr uri1, uri2; + aImage1->GetURI(getter_AddRefs(uri1)); + aImage2->GetURI(getter_AddRefs(uri2)); + return EqualURIs(uri1, uri2); +} + // -------------------- // nsStyleFont // @@ -1019,6 +1037,10 @@ nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource) { } +nsStyleBackground::~nsStyleBackground() +{ +} + nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) const { if (mBackgroundAttachment != aOther.mBackgroundAttachment @@ -1036,7 +1058,7 @@ nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) (mBackgroundClip == aOther.mBackgroundClip) && (mBackgroundInlinePolicy == aOther.mBackgroundInlinePolicy) && (mBackgroundOrigin == aOther.mBackgroundOrigin) && - EqualURIs(mBackgroundImage, aOther.mBackgroundImage) && + EqualImages(mBackgroundImage, aOther.mBackgroundImage) && ((!(mBackgroundFlags & NS_STYLE_BG_X_POSITION_PERCENT) || (mBackgroundXPosition.mFloat == aOther.mBackgroundXPosition.mFloat)) && (!(mBackgroundFlags & NS_STYLE_BG_X_POSITION_LENGTH) || diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index e84aa2073550..71a20560a420 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -54,6 +54,7 @@ #include "nsIURI.h" class nsIFrame; +class imgIRequest; enum nsStyleStructID { @@ -147,7 +148,7 @@ struct nsStyleColor : public nsStyleStruct { struct nsStyleBackground : public nsStyleStruct { nsStyleBackground(nsIPresContext* aPresContext); nsStyleBackground(const nsStyleBackground& aOther); - ~nsStyleBackground() {}; + ~nsStyleBackground(); NS_DEFINE_STATIC_STYLESTRUCTID_ACCESSOR(eStyleStruct_Background) @@ -183,7 +184,7 @@ struct nsStyleBackground : public nsStyleStruct { mBackgroundYPosition; // [reset] nscolor mBackgroundColor; // [reset] - nsCOMPtr mBackgroundImage; // [reset] + nsCOMPtr mBackgroundImage; // [reset] PRBool IsTransparent() const { diff --git a/modules/libpr0n/public/imgIRequest.idl b/modules/libpr0n/public/imgIRequest.idl index 647eadf7256b..e430d0f95985 100644 --- a/modules/libpr0n/public/imgIRequest.idl +++ b/modules/libpr0n/public/imgIRequest.idl @@ -69,5 +69,13 @@ interface imgIRequest : nsIRequest readonly attribute imgIDecoderObserver decoderObserver; readonly attribute string mimeType; + + /** + * Clone this request; the returned request will have aObserver as the + * observer. aObserver will be notified synchronously (before the clone() + * call returns) with all the notifications that have already been dispatched + * for this image load. + */ + imgIRequest clone(in imgIDecoderObserver aObserver); }; diff --git a/modules/libpr0n/src/imgRequestProxy.cpp b/modules/libpr0n/src/imgRequestProxy.cpp index 5bb89dbe551e..e8cf0ec9d77e 100644 --- a/modules/libpr0n/src/imgRequestProxy.cpp +++ b/modules/libpr0n/src/imgRequestProxy.cpp @@ -306,6 +306,32 @@ NS_IMETHODIMP imgRequestProxy::GetMimeType(char **aMimeType) return NS_OK; } +NS_IMETHODIMP imgRequestProxy::Clone(imgIDecoderObserver* aObserver, + imgIRequest** aClone) +{ + NS_PRECONDITION(aClone, "Null out param"); + *aClone = nsnull; + imgRequestProxy* clone = new imgRequestProxy(); + if (!clone) { + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ADDREF(clone); + + // It is important to call |SetLoadFlags()| before calling |Init()| because + // |Init()| adds the request to the loadgroup. + clone->SetLoadFlags(mLoadFlags); + nsresult rv = clone->Init(mOwner, mLoadGroup, aObserver); + if (NS_FAILED(rv)) { + NS_RELEASE(clone); + return rv; + } + + // Send the notifications to the clone's observer + mOwner->NotifyProxyListener(clone); + + *aClone = clone; + return NS_OK; +} /** imgIContainerObserver methods **/