Bug 898329 patch 7: Split ElementRestyler::Restyle into multiple functions. r=heycam
authorL. David Baron <dbaron@dbaron.org>
Tue, 30 Jul 2013 17:36:11 -0700
changeset 152952 95ec9086d91a3d7b73986b5b84b193323c3ce30d
parent 152951 ac0d803f21120beea7d6d29fc3536d16fa963a3e
child 152953 37cf2915f42a66c0d89a9030edf1a588e03eb396
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs898329
milestone25.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 898329 patch 7: Split ElementRestyler::Restyle into multiple functions. r=heycam
layout/base/RestyleManager.cpp
layout/base/RestyleManager.h
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -2043,16 +2043,42 @@ ElementRestyler::Restyle(nsRestyleHint a
   // |content| and |pseudoContent| mean, and their relationship to
   // |mFrame->GetContent()|, make more sense.  However, we can't,
   // because of frame trees like the one in
   // https://bugzilla.mozilla.org/show_bug.cgi?id=472353#c14 .  Once we
   // fix bug 242277 we should be able to make this make more sense.
   NS_ASSERTION(mFrame->GetContent() || !mParentContent ||
                !mParentContent->GetParent(),
                "frame must have content (unless at the top of the tree)");
+
+  if (mContent && mContent->IsElement()) {
+    mContent->OwnerDoc()->FlushPendingLinkUpdates();
+    RestyleTracker::RestyleData restyleData;
+    if (mRestyleTracker.GetRestyleData(mContent->AsElement(), &restyleData)) {
+      if (NS_UpdateHint(mHintsHandled, restyleData.mChangeHint)) {
+        mChangeList->AppendChange(mFrame, mContent, restyleData.mChangeHint);
+      }
+      aRestyleHint = nsRestyleHint(aRestyleHint | restyleData.mRestyleHint);
+    }
+  }
+
+  nsRestyleHint childRestyleHint = aRestyleHint;
+
+  if (childRestyleHint == eRestyle_Self) {
+    childRestyleHint = nsRestyleHint(0);
+  }
+
+  RestyleSelf(aRestyleHint);
+
+  RestyleChildren(childRestyleHint);
+}
+
+void
+ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint)
+{
   // XXXldb get new context from prev-in-flow if possible, to avoid
   // duplication.  (Or should we just let |GetContext| handle that?)
   // Getting the hint would be nice too, but that's harder.
 
   // XXXbryner we may be able to avoid some of the refcounting goop here.
   // We do need a reference to oldContext for the lifetime of this function, and it's possible
   // that the frame has the last reference to it, so AddRef it here.
 
@@ -2063,33 +2089,16 @@ ElementRestyler::Restyle(nsRestyleHint a
 #ifdef ACCESSIBILITY
     mWasFrameVisible = nsIPresShell::IsAccessibilityActive() ?
       oldContext->StyleVisibility()->IsVisible() : false;
 #endif
 
     nsIAtom* const pseudoTag = oldContext->GetPseudo();
     const nsCSSPseudoElements::Type pseudoType = oldContext->GetPseudoType();
 
-    if (mContent && mContent->IsElement()) {
-      mContent->OwnerDoc()->FlushPendingLinkUpdates();
-      RestyleTracker::RestyleData restyleData;
-      if (mRestyleTracker.GetRestyleData(mContent->AsElement(), &restyleData)) {
-        if (NS_UpdateHint(mHintsHandled, restyleData.mChangeHint)) {
-          mChangeList->AppendChange(mFrame, mContent, restyleData.mChangeHint);
-        }
-        aRestyleHint = nsRestyleHint(aRestyleHint | restyleData.mRestyleHint);
-      }
-    }
-
-    nsRestyleHint childRestyleHint = aRestyleHint;
-
-    if (childRestyleHint == eRestyle_Self) {
-      childRestyleHint = nsRestyleHint(0);
-    }
-
     nsStyleContext* parentContext;
     // Get the frame providing the parent style context.  If it is a
     // child, then resolve the provider first.
     nsIFrame* providerFrame = mFrame->GetParentStyleContextFrame();
     bool isChild = providerFrame && providerFrame->GetParent() == mFrame;
     if (!isChild) {
       if (providerFrame)
         parentContext = providerFrame->StyleContext();
@@ -2329,19 +2338,63 @@ ElementRestyler::Restyle(nsRestyleHint a
             }
           }
         }
       }
       else {
         break;
       }
     }
+}
 
-    // now look for undisplayed child content and pseudos
+void
+ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint)
+{
+    RestyleUndisplayedChildren(aChildRestyleHint);
+
+    // Check whether we might need to create a new ::before frame.
+    // There's no need to do this if we're planning to reframe already
+    // or if we're not forcing restyles on kids.
+    // It's also important to check mHintsHandled since we use
+    // mFrame->StyleContext(), which is out of date if mHintsHandled has a
+    // ReconstructFrame hint.  Using an out of date style context could
+    // trigger assertions about mismatched rule trees.
+    if (!(mHintsHandled & nsChangeHint_ReconstructFrame) &&
+        aChildRestyleHint) {
+      RestyleBeforePseudo();
+    }
 
+    // Check whether we might need to create a new ::after frame.
+    // See comments above regarding :before.
+    if (!(mHintsHandled & nsChangeHint_ReconstructFrame) &&
+        aChildRestyleHint) {
+      RestyleAfterPseudo();
+    }
+
+    // There is no need to waste time crawling into a frame's children
+    // on a frame change.  The act of reconstructing frames will force
+    // new style contexts to be resolved on all of this frame's
+    // descendants anyway, so we want to avoid wasting time processing
+    // style contexts that we're just going to throw away anyway. - dwh
+    // It's also important to check mHintsHandled since reresolving the
+    // kids would use mFrame->StyleContext(), which is out of date if
+    // mHintsHandled has a ReconstructFrame hint; doing this could trigger
+    // assertions about mismatched rule trees.
+    if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
+      InitializeAccessibilityNotifications();
+
+      RestyleContentChildren(aChildRestyleHint);
+
+      SendAccessibilityNotifications();
+    }
+}
+
+void
+ElementRestyler::RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint)
+{
     // When the root element is display:none, we still construct *some*
     // frames that have the root element as their mContent, down to the
     // DocElementContainingBlock.
     bool checkUndisplayed;
     nsIContent* undisplayedParent;
     nsCSSFrameConstructor* frameConstructor = mPresContext->FrameConstructor();
     if (mFrame->StyleContext()->GetPseudo()) {
       checkUndisplayed = mFrame == frameConstructor->
@@ -2378,24 +2431,25 @@ ElementRestyler::Restyle(nsRestyleHint a
         // not have a frame and would not otherwise be pushed as an ancestor.
         nsIContent* parent = undisplayed->mContent->GetParent();
         bool pushInsertionPoint = parent && parent->IsActiveChildrenElement();
         TreeMatchContext::AutoAncestorPusher
           insertionPointPusher(pushInsertionPoint,
                                mTreeMatchContext,
                                parent && parent->IsElement() ? parent->AsElement() : nullptr);
 
-        nsRestyleHint thisChildHint = childRestyleHint;
+        nsRestyleHint thisChildHint = aChildRestyleHint;
         RestyleTracker::RestyleData undisplayedRestyleData;
         if (mRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(),
                                            &undisplayedRestyleData)) {
           thisChildHint =
             nsRestyleHint(thisChildHint | undisplayedRestyleData.mRestyleHint);
         }
         nsRefPtr<nsStyleContext> undisplayedContext;
+        nsStyleSet* styleSet = mPresContext->StyleSet();
         if (thisChildHint) {
           undisplayedContext =
             styleSet->ResolveStyleFor(undisplayed->mContent->AsElement(),
                                       mFrame->StyleContext(),
                                       mTreeMatchContext);
         } else {
           undisplayedContext =
             styleSet->ReparentStyleContext(undisplayed->mStyle,
@@ -2413,26 +2467,21 @@ ElementRestyler::Restyle(nsRestyleHint a
             // we reframe it.
           } else {
             // update the undisplayed node with the new context
             undisplayed->mStyle = undisplayedContext;
           }
         }
       }
     }
+}
 
-    // Check whether we might need to create a new ::before frame.
-    // There's no need to do this if we're planning to reframe already
-    // or if we're not forcing restyles on kids.
-    // It's also important to check mHintsHandled since we use
-    // mFrame->StyleContext(), which is out of date if mHintsHandled has a
-    // ReconstructFrame hint.  Using an out of date style context could
-    // trigger assertions about mismatched rule trees.
-    if (!(mHintsHandled & nsChangeHint_ReconstructFrame) &&
-        childRestyleHint) {
+void
+ElementRestyler::RestyleBeforePseudo()
+{
       // Make sure not to do this for pseudo-frames or frames that
       // can't have generated content.
       if (!mFrame->StyleContext()->GetPseudo() &&
           ((mFrame->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT) ||
            // Our content insertion frame might have gotten flagged
            (mFrame->GetContentInsertionFrame()->GetStateBits() &
             NS_FRAME_MAY_HAVE_GENERATED_CONTENT))) {
         // Check for a new :before pseudo and an existing :before
@@ -2448,22 +2497,21 @@ ElementRestyler::Restyle(nsRestyleHint a
                                             mPresContext)) {
             // Have to create the new :before frame
             NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame);
             mChangeList->AppendChange(mFrame, mContent,
                                       nsChangeHint_ReconstructFrame);
           }
         }
       }
-    }
+}
 
-    // Check whether we might need to create a new ::after frame.
-    // See comments above regarding :before.
-    if (!(mHintsHandled & nsChangeHint_ReconstructFrame) &&
-        childRestyleHint) {
+void
+ElementRestyler::RestyleAfterPseudo()
+{
       // Make sure not to do this for pseudo-frames or frames that
       // can't have generated content.
       if (!mFrame->StyleContext()->GetPseudo() &&
           ((mFrame->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT) ||
            // Our content insertion frame might have gotten flagged
            (mFrame->GetContentInsertionFrame()->GetStateBits() &
             NS_FRAME_MAY_HAVE_GENERATED_CONTENT))) {
         // Check for new :after content, but only if the frame is the
@@ -2480,29 +2528,21 @@ ElementRestyler::Restyle(nsRestyleHint a
               !nsLayoutUtils::GetAfterFrame(mFrame)) {
             // have to create the new :after frame
             NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame);
             mChangeList->AppendChange(mFrame, mContent,
                                       nsChangeHint_ReconstructFrame);
           }
         }
       }
-    }
+}
 
-    // There is no need to waste time crawling into a frame's children
-    // on a frame change.  The act of reconstructing frames will force
-    // new style contexts to be resolved on all of this frame's
-    // descendants anyway, so we want to avoid wasting time processing
-    // style contexts that we're just going to throw away anyway. - dwh
-    // It's also important to check mHintsHandled since reresolving the
-    // kids would use mFrame->StyleContext(), which is out of date if
-    // mHintsHandled has a ReconstructFrame hint; doing this could trigger
-    // assertions about mismatched rule trees.
-    if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
-
+void
+ElementRestyler::InitializeAccessibilityNotifications()
+{
 #ifdef ACCESSIBILITY
       // Notify a11y for primary frame only if it's a root frame of visibility
       // changes or its parent frame was hidden while it stays visible and
       // it is not inside a {ib} split or is the first frame of {ib} split.
       if (nsIPresShell::IsAccessibilityActive() &&
           !mFrame->GetPrevContinuation() &&
           !nsLayoutUtils::FrameIsNonFirstInIBSplit(mFrame)) {
         if (mDesiredA11yNotifications == eSendAllNotifications) {
@@ -2528,18 +2568,21 @@ ElementRestyler::Restyle(nsRestyleHint a
                    mFrame->StyleVisibility()->IsVisible()) {
           // Notify a11y that element stayed visible while its parent was
           // hidden.
           mVisibleKidsOfHiddenElement.AppendElement(mFrame->GetContent());
           mKidsDesiredA11yNotifications = eSkipNotifications;
         }
       }
 #endif
+}
 
-      // now do children
+void
+ElementRestyler::RestyleContentChildren(nsRestyleHint aChildRestyleHint)
+{
       nsIFrame::ChildListIterator lists(mFrame);
       for (TreeMatchContext::AutoAncestorPusher
              pushAncestor(!lists.IsDone(),
                           mTreeMatchContext,
                           mContent && mContent->IsElement()
                             ? mContent->AsElement() : nullptr);
            !lists.IsDone(); lists.Next()) {
         nsFrameList::Enumerator childFrames(lists.CurrentList());
@@ -2578,35 +2621,39 @@ ElementRestyler::Restyle(nsRestyleHint a
               // descendant of a frame we already have a reflow hint for,
               // reflow coalescing should keep us from doing the work twice.
 
               // |nsFrame::GetParentStyleContextFrame| checks being out
               // of flow so that this works correctly.
               do {
                 ElementRestyler oofRestyler(*this, outOfFlowFrame,
                                             FOR_OUT_OF_FLOW_CHILD);
-                oofRestyler.Restyle(childRestyleHint);
+                oofRestyler.Restyle(aChildRestyleHint);
               } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
 
               // reresolve placeholder's context under the same parent
               // as the out-of-flow frame
               ElementRestyler phRestyler(*this, child, 0);
-              phRestyler.Restyle(childRestyleHint);
+              phRestyler.Restyle(aChildRestyleHint);
             }
             else {  // regular child frame
               if (child != mResolvedChild) {
                 ElementRestyler childRestyler(*this, child, 0);
-                childRestyler.Restyle(childRestyleHint);
+                childRestyler.Restyle(aChildRestyleHint);
               }
             }
           }
         }
       }
       // XXX need to do overflow frames???
+}
 
+void
+ElementRestyler::SendAccessibilityNotifications()
+{
 #ifdef ACCESSIBILITY
       // Send notifications about visibility changes.
       if (mOurA11yNotification == eNotifyShown) {
         nsAccessibilityService* accService = nsIPresShell::AccService();
         if (accService) {
           nsIPresShell* presShell = mFrame->PresContext()->GetPresShell();
           nsIContent* content = mFrame->GetContent();
 
@@ -2628,17 +2675,16 @@ ElementRestyler::Restyle(nsRestyleHint a
             accService->ContentRangeInserted(presShell, childContent->GetParent(),
                                              childContent,
                                              childContent->GetNextSibling());
           }
           mVisibleKidsOfHiddenElement.Clear();
         }
       }
 #endif
-    }
 }
 
 void
 RestyleManager::ComputeStyleChangeFor(nsIFrame*          aFrame,
                                       nsStyleChangeList* aChangeList,
                                       nsChangeHint       aMinChange,
                                       RestyleTracker&    aRestyleTracker,
                                       bool               aRestyleDescendants)
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -314,20 +314,45 @@ public:
    * have been handled by ancestors, and by the end of Restyle it
    * represents the hints that have been handled for this frame.  This
    * method is intended to be called after Restyle, to find out what
    * hints have been handled for this frame.
    */
   nsChangeHint HintsHandledForFrame() { return mHintsHandled; }
 
 private:
+  /**
+   * First half of Restyle().
+   */
+  void RestyleSelf(nsRestyleHint aRestyleHint);
+
+  /**
+   * Restyle the children of this frame (and, in turn, their children).
+   *
+   * Second half of Restyle().
+   */
+  void RestyleChildren(nsRestyleHint aChildRestyleHint);
+
+  /**
+   * Helper for RestyleSelf().
+   */
   void CaptureChange(nsStyleContext* aOldContext,
                      nsStyleContext* aNewContext,
                      nsChangeHint aChangeToAssume);
 
+  /**
+   * Helpers for RestyleChildren().
+   */
+  void RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint);
+  void RestyleBeforePseudo();
+  void RestyleAfterPseudo();
+  void RestyleContentChildren(nsRestyleHint aChildRestyleHint);
+  void InitializeAccessibilityNotifications();
+  void SendAccessibilityNotifications();
+
   enum DesiredA11yNotifications {
     eSkipNotifications,
     eSendAllNotifications,
     eNotifyIfShown
   };
 
   enum A11yNotificationType {
     eDontNotify,