diff --git a/layout/reftests/bugs/950436-1-ref.html b/layout/reftests/bugs/950436-1-ref.html new file mode 100644 index 00000000000..42ff61d1d33 --- /dev/null +++ b/layout/reftests/bugs/950436-1-ref.html @@ -0,0 +1,5 @@ + + + diff --git a/layout/reftests/bugs/950436-1.html b/layout/reftests/bugs/950436-1.html new file mode 100644 index 00000000000..e2a4a4e7cfd --- /dev/null +++ b/layout/reftests/bugs/950436-1.html @@ -0,0 +1,7 @@ + + + diff --git a/layout/reftests/bugs/950436-1.png b/layout/reftests/bugs/950436-1.png new file mode 100644 index 00000000000..4718c00e62b Binary files /dev/null and b/layout/reftests/bugs/950436-1.png differ diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 082fc93d7db..dbe12dd5d9c 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1793,6 +1793,7 @@ fuzzy-if(OSX==10.6,2,30) skip-if(B2G&&browserIsRemote) == 933264-1.html 933264-1 == 953334-win32-clipping.html 953334-win32-clipping-ref.html == 956513-1.svg 956513-1-ref.svg == 944291-1.html 944291-1-ref.html +== 950436-1.html 950436-1-ref.html == 957770-1.svg 957770-1-ref.svg == 960277-1.html 960277-1-ref.html pref(layout.css.overflow-clip-box.enabled,true) fuzzy(50,10) == 966992-1.html 966992-1-ref.html diff --git a/layout/style/nsCSSDataBlock.cpp b/layout/style/nsCSSDataBlock.cpp index a4062879126..bc6f3ab60f9 100644 --- a/layout/style/nsCSSDataBlock.cpp +++ b/layout/style/nsCSSDataBlock.cpp @@ -48,19 +48,27 @@ ShouldIgnoreColors(nsRuleData *aRuleData) * Image sources are specified by |url()| or |-moz-image-rect()| function. */ static void -TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument) +TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument, + nsCSSValueTokenStream* aTokenStream) { MOZ_ASSERT(aDocument); if (aValue.GetUnit() == eCSSUnit_URL) { aValue.StartImageLoad(aDocument); + if (aTokenStream) { + aTokenStream->mImageValues.PutEntry(aValue.GetImageStructValue()); + } } else if (aValue.GetUnit() == eCSSUnit_Image) { // If we already have a request, see if this document needs to clone it. imgIRequest* request = aValue.GetImageValue(nullptr); if (request) { - aDocument->StyleImageLoader()->MaybeRegisterCSSImage(aValue.GetImageStructValue()); + mozilla::css::ImageValue* imageValue = aValue.GetImageStructValue(); + aDocument->StyleImageLoader()->MaybeRegisterCSSImage(imageValue); + if (aTokenStream) { + aTokenStream->mImageValues.PutEntry(imageValue); + } } } else if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) { @@ -68,25 +76,27 @@ TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument) NS_ABORT_IF_FALSE(arguments->Count() == 6, "unexpected num of arguments"); const nsCSSValue& image = arguments->Item(1); - TryToStartImageLoadOnValue(image, aDocument); + TryToStartImageLoadOnValue(image, aDocument, aTokenStream); } } static void TryToStartImageLoad(const nsCSSValue& aValue, nsIDocument* aDocument, - nsCSSProperty aProperty) + nsCSSProperty aProperty, + nsCSSValueTokenStream* aTokenStream) { if (aValue.GetUnit() == eCSSUnit_List) { for (const nsCSSValueList* l = aValue.GetListValue(); l; l = l->mNext) { - TryToStartImageLoad(l->mValue, aDocument, aProperty); + TryToStartImageLoad(l->mValue, aDocument, aProperty, aTokenStream); } } else if (nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_IMAGE_IS_IN_ARRAY_0)) { if (aValue.GetUnit() == eCSSUnit_Array) { - TryToStartImageLoadOnValue(aValue.GetArrayValue()->Item(0), aDocument); + TryToStartImageLoadOnValue(aValue.GetArrayValue()->Item(0), aDocument, + aTokenStream); } } else { - TryToStartImageLoadOnValue(aValue, aDocument); + TryToStartImageLoadOnValue(aValue, aDocument, aTokenStream); } } @@ -111,9 +121,28 @@ MapSinglePropertyInto(nsCSSProperty aProp, nsRuleData* aRuleData) { NS_ABORT_IF_FALSE(aValue->GetUnit() != eCSSUnit_Null, "oops"); + + // Although aTarget is the nsCSSValue we are going to write into, + // we also look at its value before writing into it. This is done + // when aTarget is a token stream value, which is the case when we + // have just re-parsed a property that had a variable reference (in + // nsCSSParser::ParsePropertyWithVariableReferences). TryToStartImageLoad + // then records any resulting ImageValue objects on the + // nsCSSValueTokenStream object we found on aTarget. See the comment + // above nsCSSValueTokenStream::mImageValues for why. + NS_ABORT_IF_FALSE(aTarget->GetUnit() == eCSSUnit_TokenStream || + aTarget->GetUnit() == eCSSUnit_Null, + "aTarget must only be a token stream (when re-parsing " + "properties with variable references) or null"); + + nsCSSValueTokenStream* tokenStream = + aTarget->GetUnit() == eCSSUnit_TokenStream ? + aTarget->GetTokenStreamValue() : + nullptr; + if (ShouldStartImageLoads(aRuleData, aProp)) { nsIDocument* doc = aRuleData->mPresContext->Document(); - TryToStartImageLoad(*aValue, doc, aProp); + TryToStartImageLoad(*aValue, doc, aProp, tokenStream); } *aTarget = *aValue; if (nsCSSProps::PropHasFlags(aProp, diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h index 6db57f3b976..fcb3b09c180 100644 --- a/layout/style/nsCSSValue.h +++ b/layout/style/nsCSSValue.h @@ -1355,6 +1355,18 @@ struct nsCSSValueTokenStream { uint32_t mLineNumber; uint32_t mLineOffset; + // This table is used to hold a reference on to any ImageValue that results + // from re-parsing this token stream at computed value time. When properties + // like background-image contain a normal url(), the Declaration's data block + // will hold a reference to the ImageValue. When a token stream is used, + // the Declaration only holds on to this nsCSSValueTokenStream object, and + // the ImageValue would only exist for the duration of + // nsRuleNode::WalkRuleTree, in the AutoCSSValueArray. So instead when + // we re-parse a token stream and get an ImageValue, we record it in this + // table so that the Declaration can be the object that keeps holding + // a reference to it. + nsTHashtable > mImageValues; + private: nsCSSValueTokenStream(const nsCSSValueTokenStream& aOther) MOZ_DELETE; nsCSSValueTokenStream& operator=(const nsCSSValueTokenStream& aOther) MOZ_DELETE; diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 32096ce8e1c..d79f67e9ada 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -2073,6 +2073,14 @@ nsRuleNode::ResolveVariableReferences(const nsStyleStructID aSID, &aContext->StyleVariables()->mVariables; nsCSSValueTokenStream* tokenStream = value->GetTokenStreamValue(); + // Note that ParsePropertyWithVariableReferences relies on the fact + // that the nsCSSValue in aRuleData for the property we are re-parsing + // is still the token stream value. When + // ParsePropertyWithVariableReferences calls + // nsCSSExpandedDataBlock::MapRuleInfoInto, that function will add + // the ImageValue that is created into the token stream object's + // mImageValues table; see the comment above mImageValues for why. + // XXX Should pass in sheet here (see bug 952338). parser.ParsePropertyWithVariableReferences( tokenStream->mPropertyID, tokenStream->mShorthandPropertyID,