Bug 1362991: Compute at most one text style context per element. r?heycam draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Mon, 08 May 2017 14:49:57 +0200
changeset 574741 4b1a9298d74fdf818ed2f15b2d425def4a063935
parent 574737 1b617c262610be87773748491f487933d70c904f
child 627697 a0402019696833309f973875b20fc3a59e242ccc
push id57815
push userbmo:emilio+bugs@crisal.io
push dateTue, 09 May 2017 10:44:33 +0000
reviewersheycam
bugs1362991
milestone55.0a1
Bug 1362991: Compute at most one text style context per element. r?heycam MozReview-Commit-ID: IDTRk47CsRS
layout/base/ServoRestyleManager.cpp
layout/base/ServoRestyleManager.h
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -135,30 +135,48 @@ ServoRestyleManager::ClearRestyleStateFr
   aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
 }
 
 /**
  * This struct takes care of encapsulating some common state that text nodes may
  * need to track during the post-traversal.
  *
  * This is currently used to properly compute change hints when the parent
- * element of this node is a display: contents node.
+ * element of this node is a display: contents node, and also to avoid computing
+ * the style for text children more than once per element.
  */
 struct ServoRestyleManager::TextPostTraversalState
 {
+  nsStyleContext& mParentContext;
+  ServoStyleSet& mStyleSet;
+  RefPtr<nsStyleContext> mStyle;
   bool mShouldPostHints;
   bool mShouldComputeHints;
   nsChangeHint mComputedHint;
 
-  explicit TextPostTraversalState(bool aDisplayContentsParentStyleChanged)
-    : mShouldPostHints(aDisplayContentsParentStyleChanged)
+  TextPostTraversalState(nsStyleContext& aParentContext,
+                         ServoStyleSet& aStyleSet,
+                         bool aDisplayContentsParentStyleChanged)
+    : mParentContext(aParentContext)
+    , mStyleSet(aStyleSet)
+    , mStyle(nullptr)
+    , mShouldPostHints(aDisplayContentsParentStyleChanged)
     , mShouldComputeHints(aDisplayContentsParentStyleChanged)
     , mComputedHint(nsChangeHint_Empty)
   {}
 
+  nsStyleContext& ComputeStyle(nsIContent* aTextNode)
+  {
+    if (!mStyle) {
+      mStyle = mStyleSet.ResolveStyleForText(aTextNode, &mParentContext);
+    }
+    MOZ_ASSERT(mStyle);
+    return *mStyle;
+  }
+
   void ComputeHintIfNeeded(nsIContent* aContent,
                            nsIFrame* aTextFrame,
                            nsStyleContext& aNewContext,
                            nsStyleChangeList& aChangeList)
   {
     MOZ_ASSERT(aTextFrame);
     MOZ_ASSERT(aNewContext.GetPseudo() == nsCSSAnonBoxes::mozText);
 
@@ -169,18 +187,16 @@ struct ServoRestyleManager::TextPostTrav
     nsStyleContext* oldContext = aTextFrame->StyleContext();
     MOZ_ASSERT(oldContext->GetPseudo() == nsCSSAnonBoxes::mozText);
 
     // We rely on the fact that all the text children for the same element share
     // style to avoid recomputing style differences for all of them.
     //
     // TODO(emilio): The above may not be true for ::first-{line,letter}, but
     // we'll cross that bridge when we support those in stylo.
-    //
-    // TODO(emilio): We could also use the same style context itself, can't we?
     if (mShouldComputeHints) {
       mShouldComputeHints = false;
       uint32_t equalStructs, samePointerStructs;
       mComputedHint =
         oldContext->CalcStyleDifference(&aNewContext,
                                         &equalStructs,
                                         &samePointerStructs);
     }
@@ -310,59 +326,55 @@ ServoRestyleManager::ProcessPostTraversa
   const bool traverseElementChildren =
     aElement->HasDirtyDescendantsForServo() || descendantsNeedFrames;
   const bool traverseTextChildren = recreateContext || descendantsNeedFrames;
   if (traverseElementChildren || traverseTextChildren) {
     nsStyleContext* upToDateContext =
       recreateContext ? newContext : oldStyleContext;
 
     StyleChildrenIterator it(aElement);
-    TextPostTraversalState textState(displayContentsNode && recreateContext);
+    TextPostTraversalState textState(
+        *upToDateContext, *aStyleSet, displayContentsNode && recreateContext);
     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
       if (traverseElementChildren && n->IsElement()) {
         ProcessPostTraversal(n->AsElement(), upToDateContext,
                              aStyleSet, aChangeList);
       } else if (traverseTextChildren && n->IsNodeOfType(nsINode::eTEXT)) {
-        ProcessPostTraversalForText(
-            n, upToDateContext, aStyleSet, aChangeList, textState);
+        ProcessPostTraversalForText(n, aChangeList, textState);
       }
     }
   }
 
   aElement->UnsetHasDirtyDescendantsForServo();
   aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
 }
 
 void
 ServoRestyleManager::ProcessPostTraversalForText(
     nsIContent* aTextNode,
-    nsStyleContext* aParentContext,
-    ServoStyleSet* aStyleSet,
     nsStyleChangeList& aChangeList,
     TextPostTraversalState& aPostTraversalState)
 {
   // Handle lazy frame construction.
   if (aTextNode->HasFlag(NODE_NEEDS_FRAME)) {
     aChangeList.AppendChange(nullptr, aTextNode, nsChangeHint_ReconstructFrame);
     return;
   }
 
   // Handle restyle.
   nsIFrame* primaryFrame = aTextNode->GetPrimaryFrame();
   if (primaryFrame) {
     RefPtr<nsStyleContext> oldStyleContext = primaryFrame->StyleContext();
-    RefPtr<nsStyleContext> newContext =
-      aStyleSet->ResolveStyleForText(aTextNode, aParentContext);
-
+    nsStyleContext& newContext = aPostTraversalState.ComputeStyle(aTextNode);
     aPostTraversalState.ComputeHintIfNeeded(
-        aTextNode, primaryFrame, *newContext, aChangeList);
+        aTextNode, primaryFrame, newContext, aChangeList);
 
     for (nsIFrame* f = primaryFrame; f;
          f = GetNextContinuationWithSameStyle(f, oldStyleContext)) {
-      f->SetStyleContext(newContext);
+      f->SetStyleContext(&newContext);
     }
   }
 }
 
 void
 ServoRestyleManager::ClearSnapshots()
 {
   for (auto iter = mSnapshots.Iter(); !iter.Done(); iter.Next()) {
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -118,18 +118,16 @@ private:
    */
   void ProcessPostTraversal(Element* aElement,
                             nsStyleContext* aParentContext,
                             ServoStyleSet* aStyleSet,
                             nsStyleChangeList& aChangeList);
 
   struct TextPostTraversalState;
   void ProcessPostTraversalForText(nsIContent* aTextNode,
-                                   nsStyleContext* aParentContext,
-                                   ServoStyleSet* aStyleSet,
                                    nsStyleChangeList& aChangeList,
                                    TextPostTraversalState& aState);
 
   inline ServoStyleSet* StyleSet() const
   {
     MOZ_ASSERT(PresContext()->StyleSet()->IsServo(),
                "ServoRestyleManager should only be used with a Servo-flavored "
                "style backend");