diff --git a/layout/style/nsCSSDataBlock.cpp b/layout/style/nsCSSDataBlock.cpp index e6045451d8..09ac37550e 100644 --- a/layout/style/nsCSSDataBlock.cpp +++ b/layout/style/nsCSSDataBlock.cpp @@ -174,7 +174,8 @@ MapSinglePropertyInto(nsCSSPropertyID aTargetProp, // then records any resulting ImageValue objects in the // CSSVariableImageTable, to give them the appropriate lifetime. MOZ_ASSERT(aTargetValue->GetUnit() == eCSSUnit_TokenStream || - aTargetValue->GetUnit() == eCSSUnit_Null, + aTargetValue->GetUnit() == eCSSUnit_Null || + aTargetValue->GetUnit() == eCSSUnit_Revert, "aTargetValue must only be a token stream (when re-parsing " "properties with variable references) or null"); @@ -316,19 +317,26 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const EnsurePhysicalProperty(iProp, aRuleData); } nsCSSValue* target = aRuleData->ValueFor(iProp); - if (target->GetUnit() == eCSSUnit_Null) { - const nsCSSValue *val = ValueAtIndex(i); - // In order for variable resolution to have the right information - // about the stylesheet level of a value, that level needs to be - // stored on the token stream. We can't do that at creation time - // because the CSS parser (which creates the object) has no idea - // about the stylesheet level, so we do it here instead, where - // the rule walking will have just updated aRuleData. - if (val->GetUnit() == eCSSUnit_TokenStream) { - val->GetTokenStreamValue()->mLevel = aRuleData->mLevel; + if (target->GetUnit() == eCSSUnit_Revert) { + if (aRuleData->mLevel >= target->GetCascadeOriginValue()) { + continue; } - MapSinglePropertyInto(iProp, val, target, aRuleData); + } else if (target->GetUnit() != eCSSUnit_Null) { + continue; } + const nsCSSValue* val = ValueAtIndex(i); + // In order for variable resolution to have the right information + // about the stylesheet level of a value, that level needs to be + // stored on the token stream. We can't do that at creation time + // because the CSS parser (which creates the object) has no idea + // about the stylesheet level, so we do it here instead, where + // the rule walking will have just updated aRuleData. + if (val->GetUnit() == eCSSUnit_TokenStream) { + val->GetTokenStreamValue()->mLevel = aRuleData->mLevel; + } else if (val->GetUnit() == eCSSUnit_Revert) { + aRuleData->mConditions.SetUncacheable(); + } + MapSinglePropertyInto(iProp, val, target, aRuleData); } } } diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 668debb5cb..33c8ad5fa4 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -2248,7 +2248,8 @@ AreAllMathMLPropertiesUndefined(const nsRuleData* aRuleData) inline nsRuleNode::RuleDetail nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID, - const nsRuleData* aRuleData) + const nsRuleData* aRuleData, + bool& ignoreRuleCache) { // Build a count of the: uint32_t total = 0, // total number of props in the struct @@ -2323,6 +2324,8 @@ nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID, result = (*cb)(aRuleData, result); } + ignoreRuleCache = revert > 0; + return result; } @@ -2491,6 +2494,7 @@ nsRuleNode::WalkRuleTree(const nsStyleStructID aSID, // will be the root. (XXX misnamed) RuleDetail detail = eRuleNone; uint32_t bit = nsCachedStyleData::GetBitForSID(aSID); + bool ignoreRuleCache = false; while (ruleNode) { // See if this rule node has cached the fact that the remaining @@ -2517,9 +2521,16 @@ nsRuleNode::WalkRuleTree(const nsStyleStructID aSID, // we'll miss it. startStruct = ruleNode->mStyleData.GetStyleData(aSID); if (startStruct) { - break; // We found a rule with fully specified data. We don't - } // need to go up the tree any further, since the remainder - // of this branch has already been computed. + // XXX: Ignore cached data if the previous rule node has revert values. + if (ignoreRuleCache) { + startStruct = nullptr; + } else { + // We found a rule with fully specified data. We don't + // need to go up the tree any further, since the remainder + // of this branch has already been computed. + break; + } + } // Ask the rule to fill in the properties that it specifies. nsIStyleRule *rule = ruleNode->mRule; @@ -2532,15 +2543,15 @@ nsRuleNode::WalkRuleTree(const nsStyleStructID aSID, // Now we check to see how many properties have been specified by // the rules we've examined so far. RuleDetail oldDetail = detail; - detail = CheckSpecifiedProperties(aSID, &ruleData); + detail = CheckSpecifiedProperties(aSID, &ruleData, ignoreRuleCache); - if (oldDetail == eRuleNone && detail != eRuleNone) { + if (oldDetail == eRuleNone && (detail != eRuleNone || ignoreRuleCache)) { highestNode = ruleNode; } - if (detail == eRuleFullReset || - detail == eRuleFullMixed || - detail == eRuleFullInherited) { + if (!ignoreRuleCache && (detail == eRuleFullReset || + detail == eRuleFullMixed || + detail == eRuleFullInherited)) { break; // We don't need to examine any more rules. All properties } // have been fully specified. @@ -2576,7 +2587,7 @@ nsRuleNode::WalkRuleTree(const nsStyleStructID aSID, } if (recomputeDetail) { - detail = CheckSpecifiedProperties(aSID, &ruleData); + detail = CheckSpecifiedProperties(aSID, &ruleData, ignoreRuleCache); } NS_ASSERTION(!startStruct || (detail != eRuleFullReset && @@ -10804,7 +10815,8 @@ nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext, for (uint32_t i = 0; i < nValues; ++i) { if (values[i]->GetUnit() != eCSSUnit_Null && values[i]->GetUnit() != eCSSUnit_Dummy && // see above - values[i]->GetUnit() != eCSSUnit_DummyInherit) { + values[i]->GetUnit() != eCSSUnit_DummyInherit && + values[i]->GetUnit() != eCSSUnit_Revert) { // If author colors are not allowed, only claim to have // author-specified rules if we're looking at a non-color // property or if we're looking at the background color and it's diff --git a/layout/style/nsRuleNode.h b/layout/style/nsRuleNode.h index 49fa8a027b..7ca3a165f9 100644 --- a/layout/style/nsRuleNode.h +++ b/layout/style/nsRuleNode.h @@ -787,7 +787,8 @@ protected: nsStyleFont* aFont); inline RuleDetail CheckSpecifiedProperties(const nsStyleStructID aSID, - const nsRuleData* aRuleData); + const nsRuleData* aRuleData, + bool& ignoreRuleCache); private: nsRuleNode(nsPresContext* aPresContext, nsRuleNode* aParent,