diff --git a/content/smil/nsSMILCSSValueType.cpp b/content/smil/nsSMILCSSValueType.cpp index 228348d4ada6..85100e844eec 100644 --- a/content/smil/nsSMILCSSValueType.cpp +++ b/content/smil/nsSMILCSSValueType.cpp @@ -387,13 +387,10 @@ ValueFromStringHelper(nsCSSProperty aPropID, } nsDependentSubstring subString(aString, subStringBegin); if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, subString, - PR_TRUE, aStyleAnimValue)) { + PR_TRUE, aStyleAnimValue, + aIsContextSensitive)) { return PR_FALSE; } - if (aIsContextSensitive) { - // XXX - *aIsContextSensitive = PR_TRUE; - } if (isNegative) { InvertSign(aStyleAnimValue); } diff --git a/layout/style/nsRuleNode.h b/layout/style/nsRuleNode.h index f62a88af93e1..ca1a04d154b7 100644 --- a/layout/style/nsRuleNode.h +++ b/layout/style/nsRuleNode.h @@ -744,6 +744,10 @@ public: NS_ASSERTION(IsRoot(), "should only be called on root of rule tree"); return HaveChildren() || mStyleData.mInheritedData || mStyleData.mResetData; } + + PRBool NodeHasCachedData(const nsStyleStructID aSID) { + return !!mStyleData.GetStyleData(aSID); + } }; #endif diff --git a/layout/style/nsStyleAnimation.cpp b/layout/style/nsStyleAnimation.cpp index 549a2bd563c4..89081e29aab8 100644 --- a/layout/style/nsStyleAnimation.cpp +++ b/layout/style/nsStyleAnimation.cpp @@ -1926,48 +1926,13 @@ LookupStyleContext(dom::Element* aElement) return nsComputedDOMStyle::GetStyleContextForElement(aElement, nsnull, shell); } - -/** - * Helper function: StyleWithRuleAdded - * Creates a custom style context as a sibling of the given element's - * nsStyleContext with the given css::StyleRule added. - * - * @param aTargetElement The element whose style context we'll use as a - * sibling for our custom style context. - * @param aStyleRule The style rule to add to the style context. - * @return The generated custom nsStyleContext, or nsnull on failure. - */ -already_AddRefed -StyleWithRuleAdded(dom::Element* aTargetElement, - css::StyleRule* aStyleRule) -{ - NS_ABORT_IF_FALSE(aTargetElement, "null target element"); - NS_ABORT_IF_FALSE(aTargetElement->GetCurrentDoc(), - "element needs to be in a document " - "if we're going to look up its style context"); - NS_ABORT_IF_FALSE(aStyleRule, "null style rule"); - - // Look up style context for our target element - nsRefPtr styleContext = LookupStyleContext(aTargetElement); - if (!styleContext) { - return nsnull; - } - - aStyleRule->RuleMatched(); - - // Create a temporary nsStyleContext for the style rule - nsCOMArray ruleArray; - ruleArray.AppendObject(aStyleRule); - nsStyleSet* styleSet = styleContext->PresContext()->StyleSet(); - return styleSet->ResolveStyleByAddingRules(styleContext, ruleArray); -} - PRBool nsStyleAnimation::ComputeValue(nsCSSProperty aProperty, dom::Element* aTargetElement, const nsAString& aSpecifiedValue, PRBool aUseSVGMode, - Value& aComputedValue) + Value& aComputedValue, + PRBool* aIsContextSensitive) { NS_ABORT_IF_FALSE(aTargetElement, "null target element"); NS_ABORT_IF_FALSE(aTargetElement->GetCurrentDoc(), @@ -1984,18 +1949,66 @@ nsStyleAnimation::ComputeValue(nsCSSProperty aProperty, if (!styleRule) { return PR_FALSE; } - nsRefPtr tmpStyleContext = - StyleWithRuleAdded(aTargetElement, styleRule); - if (!tmpStyleContext) { - return PR_FALSE; - } - if (nsCSSProps::IsShorthand(aProperty) || - nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) { + if (nsCSSProps::IsShorthand(aProperty) || + nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) { // Just capture the specified value aComputedValue.SetUnparsedStringValue(nsString(aSpecifiedValue)); + if (aIsContextSensitive) { + // Since we're just returning the string as-is, aComputedValue isn't going + // to change depending on the context + *aIsContextSensitive = PR_FALSE; + } return PR_TRUE; } + + // Look up style context for our target element + nsRefPtr styleContext = LookupStyleContext(aTargetElement); + if (!styleContext) { + return PR_FALSE; + } + nsStyleSet* styleSet = styleContext->PresContext()->StyleSet(); + + nsRefPtr tmpStyleContext; + if (aIsContextSensitive) { + nsCOMArray ruleArray; + ruleArray.AppendObject(styleSet->InitialStyleRule()); + ruleArray.AppendObject(styleRule); + styleRule->RuleMatched(); + tmpStyleContext = + styleSet->ResolveStyleByAddingRules(styleContext, ruleArray); + if (!tmpStyleContext) { + return PR_FALSE; + } + + // Force walk of rule tree + nsStyleStructID sid = nsCSSProps::kSIDTable[aProperty]; + tmpStyleContext->GetStyleData(sid); + + // If the rule node will have cached style data if the value is not + // context-sensitive. So if there's nothing cached, it's not context + // sensitive. + *aIsContextSensitive = + !tmpStyleContext->GetRuleNode()->NodeHasCachedData(sid); + } + + // If we're not concerned whether the property is context sensitive then just + // add the rule to a new temporary style context alongside the target + // element's style context. + // Also, if we previously discovered that this property IS context-sensitive + // then we need to throw the temporary style context out since the property's + // value may have been biased by the 'initial' values supplied. + if (!aIsContextSensitive || *aIsContextSensitive) { + nsCOMArray ruleArray; + ruleArray.AppendObject(styleRule); + styleRule->RuleMatched(); + tmpStyleContext = + styleSet->ResolveStyleByAddingRules(styleContext, ruleArray); + if (!tmpStyleContext) { + return PR_FALSE; + } + } + // Extract computed value of our property from the temporary style rule return ExtractComputedValue(aProperty, tmpStyleContext, aComputedValue); } diff --git a/layout/style/nsStyleAnimation.h b/layout/style/nsStyleAnimation.h index e05f482b34ad..a09b254d2688 100644 --- a/layout/style/nsStyleAnimation.h +++ b/layout/style/nsStyleAnimation.h @@ -175,13 +175,22 @@ public: * @param aUseSVGMode A flag to indicate whether we should parse * |aSpecifiedValue| in SVG mode. * @param [out] aComputedValue The resulting computed value. + * @param [out] aIsContextSensitive + * Set to PR_TRUE if |aSpecifiedValue| may produce + * a different |aComputedValue| depending on other CSS + * properties on |aTargetElement| or its ancestors. + * PR_FALSE otherwise. + * Note that the operation of this method is + * significantly faster when |aIsContextSensitive| is + * nsnull. * @return PR_TRUE on success, PR_FALSE on failure. */ static PRBool ComputeValue(nsCSSProperty aProperty, - mozilla::dom::Element* aElement, + mozilla::dom::Element* aTargetElement, const nsAString& aSpecifiedValue, PRBool aUseSVGMode, - Value& aComputedValue); + Value& aComputedValue, + PRBool* aIsContextSensitive = nsnull); /** * Creates a specified value for the given computed value. diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index d5ae1bf202cd..23a9ce6391d7 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -57,6 +57,7 @@ #include "nsIContent.h" #include "nsIFrame.h" #include "nsContentUtils.h" +#include "nsRuleData.h" #include "nsRuleProcessorData.h" #include "nsTransitionManager.h" #include "nsAnimationManager.h" @@ -80,6 +81,50 @@ nsEmptyStyleRule::List(FILE* out, PRInt32 aIndent) const } #endif +NS_IMPL_ISUPPORTS1(nsInitialStyleRule, nsIStyleRule) + +/* virtual */ void +nsInitialStyleRule::MapRuleInfoInto(nsRuleData* aRuleData) +{ + // Iterate over the property groups + for (nsStyleStructID sid = nsStyleStructID(0); + sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) { + if (aRuleData->mSIDs & (1 << sid)) { + // Iterate over nsCSSValues within the property group + nsCSSValue * const value_start = + aRuleData->mValueStorage + aRuleData->mValueOffsets[sid]; + for (nsCSSValue *value = value_start, + *value_end = value + nsCSSProps::PropertyCountInStruct(sid); + value != value_end; ++value) { + // If MathML is disabled take care not to set MathML properties (or we + // will trigger assertions in nsRuleNode) + if (sid == eStyleStruct_Font && + !aRuleData->mPresContext->Document()->GetMathMLEnabled()) { + size_t index = value - value_start; + if (index == nsCSSProps::PropertyIndexInStruct( + eCSSProperty_script_level) || + index == nsCSSProps::PropertyIndexInStruct( + eCSSProperty_script_size_multiplier) || + index == nsCSSProps::PropertyIndexInStruct( + eCSSProperty_script_min_size)) { + continue; + } + } + if (value->GetUnit() == eCSSUnit_Null) { + value->SetInitialValue(); + } + } + } + } +} + +#ifdef DEBUG +/* virtual */ void +nsInitialStyleRule::List(FILE* out, PRInt32 aIndent) const +{ +} +#endif + static const nsStyleSet::sheetType gCSSSheetTypes[] = { nsStyleSet::eAgentSheet, nsStyleSet::eUserSheet, @@ -1565,3 +1610,12 @@ nsStyleSet::EnsureUniqueInnerOnCSSSheets() } return res; } + +nsIStyleRule* +nsStyleSet::InitialStyleRule() +{ + if (!mInitialStyleRule) { + mInitialStyleRule = new nsInitialStyleRule; + } + return mInitialStyleRule; +} diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h index 030565c70a32..8ca98645756c 100644 --- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -74,6 +74,15 @@ class nsEmptyStyleRule : public nsIStyleRule #endif }; +class nsInitialStyleRule : public nsIStyleRule +{ + NS_DECL_ISUPPORTS + virtual void MapRuleInfoInto(nsRuleData* aRuleData); +#ifdef DEBUG + virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const; +#endif +}; + // The style set object is created by the document viewer and ownership is // then handed off to the PresShell. Only the PresShell should delete a // style set. @@ -309,6 +318,8 @@ class nsStyleSet nsCSSStyleSheet::EnsureUniqueInnerResult EnsureUniqueInnerOnCSSSheets(); + nsIStyleRule* InitialStyleRule(); + private: // Not to be implemented nsStyleSet(const nsStyleSet& aCopy); @@ -400,6 +411,10 @@ class nsStyleSet // apply into different branches of the rule tree. nsRefPtr mFirstLineRule, mFirstLetterRule; + // Style rule which sets all properties to their initial values for + // determining when context-sensitive values are in use. + nsRefPtr mInitialStyleRule; + PRUint16 mBatching; // Old rule trees, which should only be non-empty between