Bug 996796 patch 7 - Add new restyle types that replace only the data from CSS transitions or animations. r=heycam
authorL. David Baron <dbaron@dbaron.org>
Sat, 02 Aug 2014 19:37:43 -0700
changeset 197479 a8a810bc1b360482b6acf3c202c0c113f31543a4
parent 197478 8da0b361d546fb9a84774d0e0e2f633df6d4a427
child 197480 d9db9020d57ace77058e987ad5e8bef422da6b50
push id47142
push userdbaron@mozilla.com
push dateSun, 03 Aug 2014 02:38:23 +0000
treeherdermozilla-inbound@1636ae2d7b53 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs996796
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 996796 patch 7 - Add new restyle types that replace only the data from CSS transitions or animations. r=heycam This is the start of a refactoring of the existing code in CommonAnimationManager, nsTransitionManager, and nsAnimationManager, which will be removed in later patches (after patches in between cause this code to be used instead of the current code). But it also handles interesting cases more correctly, such as cases where style context parents are unusual. FIXME: It would be nice to add tests for these cases, but they're mostly pretty obscure (e.g., a transition of 'transform' that's affected by inheriting 'transform' from ::first-line), so I'm not treating it as a priority right now.
layout/base/RestyleManager.cpp
layout/base/nsChangeHint.h
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -2450,29 +2450,38 @@ ElementRestyler::RestyleSelf(nsIFrame* a
     // continuation.
     newContext = prevContinuationContext;
   }
   else if (pseudoTag == nsCSSAnonBoxes::mozNonElement) {
     NS_ASSERTION(aSelf->GetContent(),
                  "non pseudo-element frame without content node");
     newContext = styleSet->ResolveStyleForNonElement(parentContext);
   }
-  else if (!aRestyleHint && !prevContinuation) {
+  else if (!(aRestyleHint & (eRestyle_Self | eRestyle_Subtree)) &&
+           !prevContinuation) {
     // Unfortunately, if prevContinuation is non-null then we may have
     // already stolen the restyle tracker entry for this element while
     // processing prevContinuation.  So we don't know whether aRestyleHint
     // should really be 0 here or whether it should be eRestyle_Self.  Be
     // pessimistic and force an actual reresolve in that situation.  The good
     // news is that in the common case when prevContinuation is non-null we
     // just used prevContinuationContext anyway and aren't reaching this code
     // to start with.
-    newContext =
-      styleSet->ReparentStyleContext(oldContext, parentContext,
-                                     ElementForStyleContext(mParentContent,
-                                                            aSelf, pseudoType));
+
+    Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType);
+    if (aRestyleHint == nsRestyleHint(0)) {
+      newContext =
+        styleSet->ReparentStyleContext(oldContext, parentContext, element);
+    } else {
+      MOZ_ASSERT(!(~aRestyleHint & (eRestyle_CSSTransitions |
+                                    eRestyle_CSSAnimations)),
+                 "unexpected restyle bits");
+      newContext =
+        styleSet->ResolveStyleWithReplacement(element, parentContext, oldContext);
+    }
   } else if (pseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
     newContext = styleSet->ResolveAnonymousBoxStyle(pseudoTag,
                                                     parentContext);
   }
   else {
     Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType);
     if (pseudoTag) {
       if (pseudoTag == nsCSSPseudoElements::before ||
@@ -2696,21 +2705,29 @@ ElementRestyler::RestyleUndisplayedChild
       RestyleTracker::RestyleData undisplayedRestyleData;
       if (mRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(),
                                          &undisplayedRestyleData)) {
         thisChildHint =
           nsRestyleHint(thisChildHint | undisplayedRestyleData.mRestyleHint);
       }
       nsRefPtr<nsStyleContext> undisplayedContext;
       nsStyleSet* styleSet = mPresContext->StyleSet();
-      if (thisChildHint) {
+      if (thisChildHint & (eRestyle_Self | eRestyle_Subtree)) {
         undisplayedContext =
           styleSet->ResolveStyleFor(undisplayed->mContent->AsElement(),
                                     mFrame->StyleContext(),
                                     mTreeMatchContext);
+      } else if (thisChildHint) {
+        MOZ_ASSERT(!(~thisChildHint & (eRestyle_CSSTransitions |
+                                       eRestyle_CSSAnimations)),
+                   "unexpected restyle bits");
+        undisplayedContext =
+          styleSet->ResolveStyleWithReplacement(undisplayed->mContent->AsElement(),
+                                                mFrame->StyleContext(),
+                                                undisplayed->mStyle);
       } else {
         undisplayedContext =
           styleSet->ReparentStyleContext(undisplayed->mStyle,
                                          mFrame->StyleContext(),
                                          undisplayed->mContent->AsElement());
       }
       const nsStyleDisplay* display = undisplayedContext->StyleDisplay();
       if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -247,15 +247,38 @@ inline nsChangeHint NS_HintsNotHandledFo
   nsChangeHint(NS_STYLE_HINT_REFLOW | nsChangeHint_ReconstructFrame)
 
 /**
  * |nsRestyleHint| is a bitfield for the result of
  * |HasStateDependentStyle| and |HasAttributeDependentStyle|.  When no
  * restyling is necessary, use |nsRestyleHint(0)|.
  */
 enum nsRestyleHint {
-  eRestyle_Self = 0x1,
-  eRestyle_Subtree = 0x2, /* self and descendants */
-  eRestyle_LaterSiblings = 0x4 /* implies "and descendants" */
+  // Rerun selector matching on the element.  If a new style context
+  // results, update the style contexts of descendants.  (Irrelevant if
+  // eRestyle_Subtree is also set, since that implies a superset of the
+  // work.)
+  eRestyle_Self = (1<<0),
+
+  // Rerun selector matching on the element and all of its descendants.
+  eRestyle_Subtree = (1<<1),
+
+  // Rerun selector matching on all later siblings of the element and
+  // all of their descendants.
+  eRestyle_LaterSiblings = (1<<2),
+
+  // Replace the style data coming from CSS transitions 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.)
+  eRestyle_CSSTransitions = (1<<3),
+
+  // Replace the style data coming from CSS animations 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.)
+  eRestyle_CSSAnimations = (1<<4),
 };
 
 
 #endif /* nsChangeHint_h___ */