Bug 1368290: Cache text styles in ServoStyleContext. r?bholley draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 25 Jul 2017 00:06:37 +0200
changeset 615159 9a68bffc81bf8c815394757d1ca1021748ffc44f
parent 615158 96052f161a9380fc995c4d8fcea303b6f8d9fbaf
child 639085 e994311f66bd9f09cae077d09f379be6ee5ed436
push id70248
push userbmo:emilio+bugs@crisal.io
push dateTue, 25 Jul 2017 14:15:39 +0000
reviewersbholley
bugs1368290
milestone56.0a1
Bug 1368290: Cache text styles in ServoStyleContext. r?bholley The rest of them is trivial with this infrastructure, will do tomorrow morning. Someone has to sleep for today. MozReview-Commit-ID: 44YEUs8zANw
layout/style/ServoStyleContext.cpp
layout/style/ServoStyleContext.h
layout/style/ServoStyleSet.cpp
layout/style/nsCSSAnonBoxes.h
layout/style/nsStyleContext.h
--- a/layout/style/ServoStyleContext.cpp
+++ b/layout/style/ServoStyleContext.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ServoStyleContext.h"
 
+#include "nsCSSAnonBoxes.h"
 #include "nsStyleConsts.h"
 #include "nsStyleStruct.h"
 #include "nsPresContext.h"
 #include "nsCSSRuleProcessor.h"
 #include "mozilla/dom/HTMLBodyElement.h"
 
 #include "mozilla/ServoBindings.h"
 
@@ -27,9 +28,26 @@ ServoStyleContext::ServoStyleContext(
 {
   AddStyleBit(Servo_ComputedValues_GetStyleBits(this));
   FinishConstruction();
 
   // No need to call ApplyStyleFixups here, since fixups are handled by Servo when
   // producing the ServoComputedData.
 }
 
+ServoStyleContext*
+ServoStyleContext::GetCachedInheritingAnonBoxStyle(nsIAtom* aAnonBox) const
+{
+  MOZ_ASSERT(nsCSSAnonBoxes::IsInheritingAnonBox(aAnonBox));
+  if (IsInheritingAnonBox()) {
+    return nullptr;
+  }
+
+  auto* current = mNextInheritingAnonBoxStyle.get();
+
+  while (current && current->GetPseudo() != aAnonBox) {
+    current = current->mNextInheritingAnonBoxStyle.get();
+  }
+
+  return current;
+}
+
 } // namespace mozilla
--- a/layout/style/ServoStyleContext.h
+++ b/layout/style/ServoStyleContext.h
@@ -30,22 +30,45 @@ public:
   void AddRef() { Servo_StyleContext_AddRef(this); }
   void Release() { Servo_StyleContext_Release(this); }
 
   ServoStyleContext* GetStyleIfVisited() const
   {
     return ComputedData()->visited_style.mPtr;
   }
 
+  ServoStyleContext* GetCachedInheritingAnonBoxStyle(nsIAtom* aAnonBox) const;
+
+  void SetCachedInheritedAnonBoxStyle(nsIAtom* aAnonBox,
+                                      ServoStyleContext& aStyle)
+  {
+    MOZ_ASSERT(!GetCachedInheritingAnonBoxStyle(aAnonBox));
+    MOZ_ASSERT(!aStyle.mNextInheritingAnonBoxStyle);
+
+    if (IsInheritingAnonBox()) {
+      return;
+    }
+
+    mNextInheritingAnonBoxStyle.swap(aStyle.mNextInheritingAnonBoxStyle);
+    mNextInheritingAnonBoxStyle = &aStyle;
+  }
+
   /**
    * Makes this context match |aOther| in terms of which style structs have
    * been resolved.
    */
   inline void ResolveSameStructsAs(const ServoStyleContext* aOther);
 
 private:
   nsPresContext* mPresContext;
   ServoComputedData mSource;
+
+  // A linked-list cache of inheriting anon boxes inheriting from this style _if
+  // the style isn't an inheriting anon-box_.
+  //
+  // Otherwise it represents the next entry in the cache of the parent style
+  // context.
+  RefPtr<ServoStyleContext> mNextInheritingAnonBoxStyle;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ServoStyleContext_h
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -351,26 +351,33 @@ ServoStyleSet::PrepareAndTraverseSubtree
 already_AddRefed<ServoStyleContext>
 ServoStyleSet::ResolveStyleForText(nsIContent* aTextNode,
                                    ServoStyleContext* aParentContext)
 {
   MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
   MOZ_ASSERT(aTextNode->GetParent());
   MOZ_ASSERT(aParentContext);
 
-  // Gecko expects text node style contexts to be like elements that match no
-  // rules: inherit the inherit structs, reset the reset structs. This is cheap
-  // enough to do on the main thread, which means that the parallel style system
-  // can avoid worrying about text nodes.
-  RefPtr<ServoStyleContext> computedValues =
-    Servo_ComputedValues_Inherit(mRawSet.get(),
-                                 nsCSSAnonBoxes::mozText,
-                                 aParentContext,
-                                 InheritTarget::Text).Consume();
-  return computedValues.forget();
+  RefPtr<ServoStyleContext> style =
+    aParentContext->GetCachedInheritingAnonBoxStyle(nsCSSAnonBoxes::mozText);
+
+  if (!style) {
+    // Gecko expects text node style contexts to be like elements that match no
+    // rules: inherit the inherit structs, reset the reset structs. This is
+    // cheap enough to do on the main thread, which means that the parallel
+    // style system can avoid worrying about text nodes.
+    style =
+      Servo_ComputedValues_Inherit(mRawSet.get(),
+                                   nsCSSAnonBoxes::mozText,
+                                   aParentContext,
+                                   InheritTarget::Text).Consume();
+    aParentContext->SetCachedInheritedAnonBoxStyle(nsCSSAnonBoxes::mozText, *style);
+  }
+
+  return style.forget();
 }
 
 already_AddRefed<ServoStyleContext>
 ServoStyleSet::ResolveStyleForFirstLetterContinuation(ServoStyleContext* aParentContext)
 {
   RefPtr<ServoStyleContext> computedValues =
     Servo_ComputedValues_Inherit(mRawSet.get(),
                                  nsCSSAnonBoxes::firstLetterContinuation,
--- a/layout/style/nsCSSAnonBoxes.h
+++ b/layout/style/nsCSSAnonBoxes.h
@@ -38,16 +38,29 @@ public:
 #define CSS_ANON_BOX(_name, _value) /* nothing */
 #define CSS_NON_INHERITING_ANON_BOX(_name, _value) _name,
 #include "nsCSSAnonBoxList.h"
 #undef CSS_NON_INHERITING_ANON_BOX
 #undef CSS_ANON_BOX
     _Count
   };
 
+#ifdef DEBUG
+  static bool IsInheritingAnonBox(nsIAtom* aPseudo)
+  {
+    return
+#define CSS_ANON_BOX(_name, _value) _name == aPseudo ||
+#define CSS_NON_INHERITING_ANON_BOX(_name, _value) /* nothing */
+#include "nsCSSAnonBoxList.h"
+#undef CSS_NON_INHERITING_ANON_BOX
+#undef CSS_ANON_BOX
+      false;
+  }
+#endif
+
   // Be careful using this: if we have a lot of non-inheriting anon box types it
   // might not be very fast.  We may want to think of ways to handle that
   // (e.g. by moving to an enum instead of an atom, like we did for
   // pseudo-elements, or by adding a new value of the pseudo-element enum for
   // non-inheriting anon boxes or something).
   static bool IsNonInheritingAnonBox(nsIAtom* aPseudo)
   {
     return
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -107,16 +107,20 @@ public:
   }
 
   nsIAtom* GetPseudo() const { return mPseudoTag; }
   mozilla::CSSPseudoElementType GetPseudoType() const {
     return static_cast<mozilla::CSSPseudoElementType>(
              mBits >> NS_STYLE_CONTEXT_TYPE_SHIFT);
   }
 
+  bool IsInheritingAnonBox() const {
+    return GetPseudoType() == mozilla::CSSPseudoElementType::InheritingAnonBox;
+  }
+
   bool IsAnonBox() const {
     return
       GetPseudoType() == mozilla::CSSPseudoElementType::InheritingAnonBox ||
       GetPseudoType() == mozilla::CSSPseudoElementType::NonInheritingAnonBox;
   }
   bool IsPseudoElement() const { return mPseudoTag && !IsAnonBox(); }