Bug 977991 patch 3 - Add ability for RuleNodeWithReplacement to replace the style attribute rule and its important rule. r=birtles

This allows posting a restyle that says that only the rule(s) from the
StyleAttrSheet cascade level will be replaced, which avoids running
selector matching.

Part 4 will ensure that we only invoke this code for element styles (and
not pseudo-element or anonymous box styles).  Despite that, I prefer
having the runtime check here as well given that it's a very simple way
to ensure we don't do something silly that might have security
implications.
This commit is contained in:
L. David Baron 2014-09-13 06:17:36 -07:00
parent b4d8a65955
commit 5e262a47d8
2 changed files with 48 additions and 2 deletions

View File

@ -313,6 +313,15 @@ enum nsRestyleHint {
// superset of the work.)
eRestyle_SVGAttrAnimations = (1<<5),
// Replace the style data coming from inline style without updating
// any other style data. If a new style context results, update style
// contexts on the descendants. (Irrelevant if eRestyle_Self or
// eRestyle_Subtree is also set, since those imply a superset of the
// work.) Supported only for element style contexts and not for
// pseudo-elements or anonymous boxes, on which it converts to
// eRestyle_Self.
eRestyle_StyleAttribute = (1<<6),
// Continue the restyling process to the current frame's children even
// if this frame's restyling resulted in no style changes.
eRestyle_Force = (1<<8),

View File

@ -1339,12 +1339,12 @@ static const CascadeLevel gCascadeLevels[] = {
{ nsStyleSet::eSVGAttrAnimationSheet, false, false, eRestyle_SVGAttrAnimations },
{ nsStyleSet::eDocSheet, false, false, nsRestyleHint(0) },
{ nsStyleSet::eScopedDocSheet, false, false, nsRestyleHint(0) },
{ nsStyleSet::eStyleAttrSheet, false, false, nsRestyleHint(0) },
{ nsStyleSet::eStyleAttrSheet, false, true, eRestyle_StyleAttribute },
{ nsStyleSet::eOverrideSheet, false, false, nsRestyleHint(0) },
{ nsStyleSet::eAnimationSheet, false, false, eRestyle_CSSAnimations },
{ nsStyleSet::eScopedDocSheet, true, false, nsRestyleHint(0) },
{ nsStyleSet::eDocSheet, true, false, nsRestyleHint(0) },
{ nsStyleSet::eStyleAttrSheet, true, false, nsRestyleHint(0) },
{ nsStyleSet::eStyleAttrSheet, true, false, eRestyle_StyleAttribute },
{ nsStyleSet::eOverrideSheet, true, false, nsRestyleHint(0) },
{ nsStyleSet::eUserSheet, true, false, nsRestyleHint(0) },
{ nsStyleSet::eAgentSheet, true, false, nsRestyleHint(0) },
@ -1360,6 +1360,7 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement,
NS_ABORT_IF_FALSE(!(aReplacements & ~(eRestyle_CSSTransitions |
eRestyle_CSSAnimations |
eRestyle_SVGAttrAnimations |
eRestyle_StyleAttribute |
eRestyle_Force |
eRestyle_ForceDescendants)),
// FIXME: Once bug 979133 lands we'll have a better
@ -1387,6 +1388,12 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement,
nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
auto rulesIndex = rules.Length();
// We need to transfer this information between the non-!important and
// !important phases for the style attribute level.
nsRuleNode* lastScopedRN = nullptr;
nsRuleNode* lastStyleAttrRN = nullptr;
bool haveImportantStyleAttrRules = false;
for (const CascadeLevel *level = gCascadeLevels,
*levelEnd = ArrayEnd(gCascadeLevels);
level != levelEnd; ++level) {
@ -1446,7 +1453,37 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement,
}
break;
}
case eRestyle_StyleAttribute: {
if (!level->mIsImportant) {
// First time through, we handle the non-!important rule.
MOZ_ASSERT(aPseudoType ==
nsCSSPseudoElements::ePseudo_NotPseudoElement,
"this code doesn't know how to replace "
"pseudo-element rules");
nsHTMLCSSStyleSheet* ruleProcessor =
static_cast<nsHTMLCSSStyleSheet*>(
mRuleProcessors[eStyleAttrSheet].get());
if (ruleProcessor &&
// check condition we asserted above (belt & braces security)
aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
lastScopedRN = ruleWalker.CurrentNode();
ruleProcessor->ElementRulesMatching(PresContext(),
aElement,
&ruleWalker);
lastStyleAttrRN = ruleWalker.CurrentNode();
haveImportantStyleAttrRules =
!ruleWalker.GetCheckForImportantRules();
}
} else {
// Second time through, we handle the !important rule(s).
if (haveImportantStyleAttrRules) {
AddImportantRules(lastStyleAttrRN, lastScopedRN, &ruleWalker);
}
}
break;
}
default:
MOZ_ASSERT(false, "unexpected result from gCascadeLevels lookup");
break;
}
}