Bug 1057129 patch 3 - Post restyles from CheckAnimationRule directly to pseudo-elements. r=birtles
authorL. David Baron <dbaron@dbaron.org>
Sun, 24 Aug 2014 21:48:22 -0700
changeset 201272 916f273f3ad1c438b8e48ff0cce848b01f2ed86d
parent 201271 2bf015380818ecdae9254922461ff99defd6d7b5
child 201273 55d62d21a98d140f93625c9e3a653b14264af129
push id48141
push userdbaron@mozilla.com
push dateMon, 25 Aug 2014 04:48:50 +0000
treeherdermozilla-inbound@916f273f3ad1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles
bugs1057129, 960465
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1057129 patch 3 - Post restyles from CheckAnimationRule directly to pseudo-elements. r=birtles This matches patch 2, and also fixes an incorrect use of eRestyle_Self on the parents of pseudo-elements in order to restyle those pseudo-elements, where it would not previously have been effective. This should all be temporary, since this code can go away with bug 960465, when animation phases are removed.
layout/base/RestyleManager.cpp
layout/style/nsStyleSet.cpp
layout/style/nsStyleSet.h
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -2103,18 +2103,23 @@ RestyleManager::ReparentStyleContext(nsI
     // continuation).
     newContext = prevContinuationContext;
   } else {
     nsIFrame* parentFrame = aFrame->GetParent();
     Element* element =
       ElementForStyleContext(parentFrame ? parentFrame->GetContent() : nullptr,
                              aFrame,
                              oldContext->GetPseudoType());
+    nsIContent* pseudoElementContent = aFrame->GetContent();
+    Element* pseudoElement =
+      (pseudoElementContent && pseudoElementContent->IsElement())
+        ? pseudoElementContent->AsElement() : nullptr;
     newContext = mPresContext->StyleSet()->
-                   ReparentStyleContext(oldContext, newParentContext, element);
+                   ReparentStyleContext(oldContext, newParentContext, element,
+                                        pseudoElement);
   }
 
   if (newContext) {
     if (newContext != oldContext) {
       // We probably don't want to initiate transitions from
       // ReparentStyleContext, since we call it during frame
       // construction rather than in response to dynamic changes.
       // Also see the comment at the start of
@@ -2182,17 +2187,17 @@ RestyleManager::ReparentStyleContext(nsI
       // do additional contexts
       int32_t contextIndex = 0;
       for (nsStyleContext* oldExtraContext;
            (oldExtraContext = aFrame->GetAdditionalStyleContext(contextIndex));
            ++contextIndex) {
         nsRefPtr<nsStyleContext> newExtraContext;
         newExtraContext = mPresContext->StyleSet()->
                             ReparentStyleContext(oldExtraContext,
-                                                 newContext, nullptr);
+                                                 newContext, nullptr, nullptr);
         if (newExtraContext) {
           if (newExtraContext != oldExtraContext) {
             // Make sure to call CalcStyleDifference so that the new
             // context ends up resolving all the structs the old context
             // resolved.
             DebugOnly<nsChangeHint> styleChange =
               oldExtraContext->CalcStyleDifference(newExtraContext,
                                                    nsChangeHint(0));
@@ -2524,18 +2529,23 @@ ElementRestyler::RestyleSelf(nsIFrame* a
     NS_ASSERTION(aSelf->GetContent(),
                  "non pseudo-element frame without content node");
     newContext = styleSet->ResolveStyleForNonElement(parentContext);
   }
   else if (!(aRestyleHint & (eRestyle_Self | eRestyle_Subtree))) {
     Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType);
     if (aRestyleHint == nsRestyleHint(0) &&
         !styleSet->IsInRuleTreeReconstruct()) {
+      nsIContent* pseudoElementContent = aSelf->GetContent();
+      Element* pseudoElement =
+        (pseudoElementContent && pseudoElementContent->IsElement())
+          ? pseudoElementContent->AsElement() : nullptr;
       newContext =
-        styleSet->ReparentStyleContext(oldContext, parentContext, element);
+        styleSet->ReparentStyleContext(oldContext, parentContext, element,
+                                       pseudoElement);
     } else {
       // Use ResolveStyleWithReplacement either for actual replacements
       // or, with no replacements, as a substitute for
       // ReparentStyleContext that rebuilds the path in the rule tree
       // rather than reusing the rule node, as we need to do during a
       // rule tree reconstruct.
       newContext =
         styleSet->ResolveStyleWithReplacement(element, parentContext, oldContext,
@@ -2651,18 +2661,23 @@ ElementRestyler::RestyleSelf(nsIFrame* a
         // ReparentStyleContext that rebuilds the path in the rule tree
         // rather than reusing the rule node, as we need to do during a
         // rule tree reconstruct.
         newExtraContext =
           styleSet->ResolveStyleWithReplacement(element, newContext,
                                                 oldExtraContext,
                                                 nsRestyleHint(0));
       } else {
+        nsIContent* pseudoElementContent = aSelf->GetContent();
+        Element* pseudoElement =
+          (pseudoElementContent && pseudoElementContent->IsElement())
+            ? pseudoElementContent->AsElement() : nullptr;
         newExtraContext =
-          styleSet->ReparentStyleContext(oldExtraContext, newContext, element);
+          styleSet->ReparentStyleContext(oldExtraContext, newContext, element,
+                                         pseudoElement);
       }
     } else if (extraPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
       newExtraContext = styleSet->ResolveAnonymousBoxStyle(extraPseudoTag,
                                                            newContext);
     } else {
       // Don't expect XUL tree stuff here, since it needs a comparator and
       // all.
       NS_ASSERTION(extraPseudoType <
@@ -2820,17 +2835,17 @@ ElementRestyler::RestyleUndisplayedChild
           styleSet->ResolveStyleWithReplacement(element,
                                                 mFrame->StyleContext(),
                                                 undisplayed->mStyle,
                                                 thisChildHint);
       } else {
         undisplayedContext =
           styleSet->ReparentStyleContext(undisplayed->mStyle,
                                          mFrame->StyleContext(),
-                                         element);
+                                         element, element);
       }
       const nsStyleDisplay* display = undisplayedContext->StyleDisplay();
       if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
         NS_ASSERTION(undisplayed->mContent,
                      "Must have undisplayed content");
         mChangeList->AppendChange(nullptr, undisplayed->mContent,
                                   NS_STYLE_HINT_FRAMECHANGE);
         // The node should be removed from the undisplayed map when
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -1971,17 +1971,17 @@ nsStyleSet::GCRuleTrees()
   }
 }
 
 /**
  * Return an equivalent to aRuleNode with both animation and transition
  * rules removed, and post a restyle if needed.
  */
 static inline nsRuleNode*
-SkipAnimationRules(nsRuleNode* aRuleNode, Element* aElement, bool isPseudo)
+SkipAnimationRules(nsRuleNode* aRuleNode, Element* aElementOrPseudoElement)
 {
   nsRuleNode* ruleNode = aRuleNode;
   // The transition rule must be at the top of the cascade.
   if (!ruleNode->IsRoot() &&
       ruleNode->GetLevel() == nsStyleSet::eTransitionSheet) {
     ruleNode = ruleNode->GetParent();
   }
   NS_ABORT_IF_FALSE(ruleNode->IsRoot() ||
@@ -1991,30 +1991,35 @@ SkipAnimationRules(nsRuleNode* aRuleNode
   // Use our existing ReplaceAnimationRule function to replace the
   // animation rule, if present.
   nsIStyleRule* animationRule = GetAnimationRule(ruleNode);
   if (animationRule) {
     ruleNode = ReplaceAnimationRule(ruleNode, animationRule, nullptr);
   }
 
   if (ruleNode != aRuleNode) {
-    NS_ASSERTION(aElement, "How can we have transition rules but no element?");
+    NS_ASSERTION(aElementOrPseudoElement,
+                 "How can we have transition rules but no element?");
     // Need to do an animation restyle, just like
     // nsTransitionManager::WalkTransitionRule and
     // nsAnimationManager::GetAnimationRule would.
-    nsRestyleHint hint = isPseudo ? eRestyle_Subtree : eRestyle_Self;
-    aRuleNode->PresContext()->PresShell()->RestyleForAnimation(aElement, hint);
+    aRuleNode->PresContext()->PresShell()->
+      RestyleForAnimation(aElementOrPseudoElement, eRestyle_Self);
   }
   return ruleNode;
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
                                  nsStyleContext* aNewParentContext,
-                                 Element* aElement)
+                                 Element* aElement,
+                                 // aElementOrPseudoElement is temporary
+                                 // until bug 960465 lands, and for
+                                 // SkipAnimationRules only
+                                 Element* aElementOrPseudoElement)
 {
   MOZ_ASSERT(aStyleContext, "aStyleContext must not be null");
 
   // This short-circuit is OK because we don't call TryStartingTransition
   // during style reresolution if the style context pointer hasn't changed.
   if (aStyleContext->GetParent() == aNewParentContext) {
     nsRefPtr<nsStyleContext> ret = aStyleContext;
     return ret.forget();
@@ -2028,36 +2033,32 @@ nsStyleSet::ReparentStyleContext(nsStyle
   // nsTransitionManager::WalkTransitionRule would.
   bool skipAnimationRules = PresContext()->IsProcessingRestyles() &&
     !PresContext()->IsProcessingAnimationStyleChange();
   if (skipAnimationRules) {
     // Make sure that we're not using transition rules or animation rules for
     // our new style context.  If we need them, an animation restyle will
     // provide.
     ruleNode =
-      SkipAnimationRules(ruleNode, aElement,
-                         pseudoType !=
-                           nsCSSPseudoElements::ePseudo_NotPseudoElement);
+      SkipAnimationRules(ruleNode, aElementOrPseudoElement);
   }
 
   nsRuleNode* visitedRuleNode = nullptr;
   nsStyleContext* visitedContext = aStyleContext->GetStyleIfVisited();
   // Reparenting a style context just changes where we inherit from,
   // not what rules we match or what our DOM looks like.  In
   // particular, it doesn't change whether this is a style context for
   // a link.
   if (visitedContext) {
      visitedRuleNode = visitedContext->RuleNode();
      // Again, skip transition rules as needed
      if (skipAnimationRules) {
       // FIXME do something here for animations?
        visitedRuleNode =
-         SkipAnimationRules(visitedRuleNode, aElement,
-                            pseudoType !=
-                              nsCSSPseudoElements::ePseudo_NotPseudoElement);
+         SkipAnimationRules(visitedRuleNode, aElementOrPseudoElement);
      }
   }
 
   uint32_t flags = eNoFlags;
   if (aStyleContext->IsLinkContext()) {
     flags |= eIsLink;
 
     // GetContext handles propagating RelevantLinkVisited state from the
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -217,20 +217,26 @@ class nsStyleSet
                                    nsStyleContext* aStyleContext);
 
   // Get a new style context that lives in a different parent
   // The new context will be the same as the old if the new parent is the
   // same as the old parent.
   // aElement should be non-null if this is a style context for an
   // element or pseudo-element; in the latter case it should be the
   // real element the pseudo-element is for.
+  // aElementOrPseudoElement should be the same, except for
+  // pseudo-elements it should be the pseudo-element.  It is temporary
+  // until bug 960465 lands.  It only really needs to be correct for
+  // things we run animations on (elements and ::before and ::after
+  // pseudo-elements).
   already_AddRefed<nsStyleContext>
   ReparentStyleContext(nsStyleContext* aStyleContext,
                        nsStyleContext* aNewParentContext,
-                       mozilla::dom::Element* aElement);
+                       mozilla::dom::Element* aElement,
+                       mozilla::dom::Element* aElementOrPseudoElement);
 
   // Test if style is dependent on a document state.
   bool HasDocumentStateDependentStyle(nsPresContext* aPresContext,
                                       nsIContent*    aContent,
                                       mozilla::EventStates aStateMask);
 
   // Test if style is dependent on content state
   nsRestyleHint HasStateDependentStyle(nsPresContext* aPresContext,