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
This commit is contained in:
bzbarsky%mit.edu 2004-03-09 03:57:51 +00:00
parent 401ebf9a1a
commit 134fed8856
39 changed files with 633 additions and 240 deletions

View File

@ -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;
};

View File

@ -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<nsIDOMWindow> 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<nsILoadGroup> 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)
{

View File

@ -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<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
NS_WARN_IF_FALSE(loadGroup, "Could not get loadgroup; onload may fire too early");
nsIURI *documentURI = doc->GetDocumentURI();
nsCOMPtr<imgIRequest> & 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<nsIDOMWindow> 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()
{

View File

@ -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

View File

@ -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()) {

View File

@ -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<nsIURI> 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;

View File

@ -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<nsIDocument> doc;
nsresult rv = shell->GetDocument(getter_AddRefs(doc));
if (NS_SUCCEEDED(rv) && doc) {
nsCOMPtr<nsIURI> 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<nsIURI> 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;
}
}
}

View File

@ -48,6 +48,7 @@ REQUIRES = xpcom \
view \
intl \
pref \
imglib2 \
$(NULL)
CPPSRCS = \

View File

@ -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?

View File

@ -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;

View File

@ -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;

View File

@ -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<imgIRequest> 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;
};

View File

@ -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<nsIURI> uri;
if (color->mBackgroundImage) {
color->mBackgroundImage->GetURI(getter_AddRefs(uri));
}
val->SetURI(uri);
}
}

View File

@ -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<nsIURI> mBackgroundImage; // [reset]
nsCOMPtr<imgIRequest> mBackgroundImage; // [reset]
PRBool IsTransparent() const
{

View File

@ -37,6 +37,7 @@ REQUIRES = xpcom \
dom \
necko \
unicharutil \
imglib2 \
$(NULL)
CPPSRCS = \

View File

@ -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<nsIURI> 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) ||

View File

@ -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<nsIURI> 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();

View File

@ -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<nsIDocument> doc;
nsresult rv = shell->GetDocument(getter_AddRefs(doc));
if (NS_FAILED(rv)) return rv;
// Get the document's loadgroup
nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
if (mRequest) {
nsCOMPtr<nsIURI> oldURI;
mRequest->GetURI(getter_AddRefs(oldURI));
nsCOMPtr<nsIURI> 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<imgILoader> 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;

View File

@ -41,7 +41,7 @@ public:
NS_DECL_IMGICONTAINEROBSERVER
void Init(nsIFrame *aFrame, nsIPresContext *aPresContext);
nsresult Load(nsIURI *aURI);
nsresult Load(imgIRequest *aImage);
void Destroy();

View File

@ -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<nsIDOMElement> element(do_QueryInterface(content));
if (content && element) {
nsCOMPtr<nsIDocument> 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<nsIDOMWindow> 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());

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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<nsIDocument> doc;
nsresult rv = shell->GetDocument(getter_AddRefs(doc));
if (NS_FAILED(rv)) return rv;
// Get the document's loadgroup
nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
if (mRequest) {
nsCOMPtr<nsIURI> oldURI;
mRequest->GetURI(getter_AddRefs(oldURI));
nsCOMPtr<nsIURI> 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<imgILoader> 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;

View File

@ -41,7 +41,7 @@ public:
NS_DECL_IMGICONTAINEROBSERVER
void Init(nsIFrame *aFrame, nsIPresContext *aPresContext);
nsresult Load(nsIURI *aURI);
nsresult Load(imgIRequest *aImage);
void Destroy();

View File

@ -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<nsIDOMElement> element(do_QueryInterface(content));
if (content && element) {
nsCOMPtr<nsIDocument> 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<nsIDOMWindow> 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());

View File

@ -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);

View File

@ -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<nsIURI> 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();

View File

@ -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?

View File

@ -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;

View File

@ -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;

View File

@ -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<imgIRequest> 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;
};

View File

@ -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<nsIURI> uri;
if (color->mBackgroundImage) {
color->mBackgroundImage->GetURI(getter_AddRefs(uri));
}
val->SetURI(uri);
}
}

View File

@ -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()) {

View File

@ -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<nsIURI> 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;

View File

@ -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<nsIURI> 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) ||

View File

@ -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<nsIURI> mBackgroundImage; // [reset]
nsCOMPtr<imgIRequest> mBackgroundImage; // [reset]
PRBool IsTransparent() const
{

View File

@ -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);
};

View File

@ -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 **/