Bug 1373018 - Part 5: stylo: Move child/sibling pointers to GeckoStyleContext; r?bholley draft
authorManish Goregaokar <manishearth@gmail.com>
Sat, 10 Jun 2017 22:27:45 -0700
changeset 595120 a207c9c3455e4a933466f17df594999ada9d599a
parent 595119 809494245d30364800584b0da904db2ca8e95228
child 595121 df1d11ad343e98862c6c8758559a9c95e1bb3b66
push id64258
push userbmo:manishearth@gmail.com
push dateFri, 16 Jun 2017 03:04:15 +0000
reviewersbholley
bugs1373018
milestone56.0a1
Bug 1373018 - Part 5: stylo: Move child/sibling pointers to GeckoStyleContext; r?bholley MozReview-Commit-ID: Gay6RwpkNcu
layout/base/GeckoRestyleManager.cpp
layout/style/GeckoStyleContext.cpp
layout/style/GeckoStyleContext.h
layout/style/moz.build
layout/style/nsStyleContext.cpp
layout/style/nsStyleContext.h
layout/style/nsStyleContextInlines.h
layout/style/nsStyleSet.cpp
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -8,26 +8,28 @@
  * changes need to happen, scheduling them, and doing them.
  */
 
 #include "mozilla/GeckoRestyleManager.h"
 
 #include <algorithm> // For std::max
 #include "gfxContext.h"
 #include "mozilla/EffectSet.h"
+#include "mozilla/GeckoStyleContext.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/ViewportFrame.h"
 #include "mozilla/css/StyleRule.h" // For nsCSSSelector
 #include "nsLayoutUtils.h"
 #include "AnimationCommon.h" // For GetLayerAnimationInfo
 #include "FrameLayerBuilder.h"
 #include "GeckoProfiler.h"
 #include "nsAutoPtr.h"
 #include "nsStyleChangeList.h"
 #include "nsRuleProcessorData.h"
+#include "nsStyleContextInlines.h"
 #include "nsStyleSet.h"
 #include "nsStyleUtil.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsSVGEffects.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSRendering.h"
 #include "nsAnimationManager.h"
 #include "nsTransitionManager.h"
@@ -3438,17 +3440,17 @@ ElementRestyler::SendAccessibilityNotifi
 
 static void
 ClearCachedInheritedStyleDataOnDescendants(
     nsTArray<ElementRestyler::ContextToClear>& aContextsToClear)
 {
   for (size_t i = 0; i < aContextsToClear.Length(); i++) {
     auto& entry = aContextsToClear[i];
     if (!entry.mStyleContext->HasSingleReference()) {
-      entry.mStyleContext->ClearCachedInheritedStyleDataOnDescendants(
+      entry.mStyleContext->AsGecko()->ClearCachedInheritedStyleDataOnDescendants(
           entry.mStructs);
     }
     entry.mStyleContext = nullptr;
   }
 }
 
 void
 GeckoRestyleManager::ComputeAndProcessStyleChange(
--- a/layout/style/GeckoStyleContext.cpp
+++ b/layout/style/GeckoStyleContext.cpp
@@ -4,26 +4,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/GeckoStyleContext.h"
 
 #include "nsStyleConsts.h"
 #include "nsStyleStruct.h"
 #include "nsPresContext.h"
 #include "nsRuleNode.h"
+#include "nsStyleContextInlines.h"
 
 using namespace mozilla;
 
 GeckoStyleContext::GeckoStyleContext(nsStyleContext* aParent,
                                      nsIAtom* aPseudoTag,
                                      CSSPseudoElementType aPseudoType,
                                      already_AddRefed<nsRuleNode> aRuleNode,
                                      bool aSkipParentDisplayBasedStyleFixup)
   : nsStyleContext(aParent, OwningStyleContextSource(Move(aRuleNode)),
                    aPseudoTag, aPseudoType)
+  , mChild(nullptr)
+  , mEmptyChild(nullptr)
 {
   mBits |= NS_STYLE_CONTEXT_IS_GECKO;
 
   if (aParent) {
 #ifdef DEBUG
     nsRuleNode *r1 = mParent->RuleNode(), *r2 = mSource.AsGeckoRuleNode();
     while (r1->GetParent())
       r1 = r1->GetParent();
@@ -31,22 +34,205 @@ GeckoStyleContext::GeckoStyleContext(nsS
       r2 = r2->GetParent();
     NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent");
 #endif
   } else {
     PresContext()->PresShell()->StyleSet()->RootStyleContextAdded();
   }
 
   mSource.AsGeckoRuleNode()->SetUsedDirectly(); // before ApplyStyleFixups()!
+  // FinishConstruction() calls AddChild which needs these
+  // to be initialized!
+  mNextSibling = this;
+  mPrevSibling = this;
+
   FinishConstruction();
   ApplyStyleFixups(aSkipParentDisplayBasedStyleFixup);
 }
 
 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
 // (which comes from the presShell) to perform the allocation.
 void*
 GeckoStyleContext::operator new(size_t sz, nsPresContext* aPresContext)
 {
   MOZ_ASSERT(sz == sizeof(GeckoStyleContext));
   // Check the recycle list first.
   return aPresContext->PresShell()->
     AllocateByObjectID(eArenaObjectID_GeckoStyleContext, sz);
 }
+
+
+void
+GeckoStyleContext::AddChild(GeckoStyleContext* aChild)
+{
+  NS_ASSERTION(aChild->mPrevSibling == aChild &&
+               aChild->mNextSibling == aChild,
+               "child already in a child list");
+
+  GeckoStyleContext **listPtr = aChild->mSource.MatchesNoRules() ? &mEmptyChild : &mChild;
+  // Explicitly dereference listPtr so that compiler doesn't have to know that mNextSibling
+  // etc. don't alias with what ever listPtr points at.
+  GeckoStyleContext *list = *listPtr;
+
+  // Insert at the beginning of the list.  See also FindChildWithRules.
+  if (list) {
+    // Link into existing elements, if there are any.
+    aChild->mNextSibling = list;
+    aChild->mPrevSibling = list->mPrevSibling;
+    list->mPrevSibling->mNextSibling = aChild;
+    list->mPrevSibling = aChild;
+  }
+  (*listPtr) = aChild;
+}
+
+void
+GeckoStyleContext::RemoveChild(GeckoStyleContext* aChild)
+{
+  NS_PRECONDITION(nullptr != aChild && this == aChild->mParent, "bad argument");
+
+  GeckoStyleContext **list = aChild->mSource.MatchesNoRules() ? &mEmptyChild : &mChild;
+
+  if (aChild->mPrevSibling != aChild) { // has siblings
+    if ((*list) == aChild) {
+      (*list) = (*list)->mNextSibling;
+    }
+  }
+  else {
+    NS_ASSERTION((*list) == aChild, "bad sibling pointers");
+    (*list) = nullptr;
+  }
+
+  aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
+  aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
+  aChild->mNextSibling = aChild;
+  aChild->mPrevSibling = aChild;
+}
+
+#ifdef DEBUG
+void
+GeckoStyleContext::ListDescendants(FILE* out, int32_t aIndent)
+{
+  if (nullptr != mChild) {
+    GeckoStyleContext* child = mChild;
+    do {
+      child->List(out, aIndent + 1, true);
+      child = child->mNextSibling;
+    } while (mChild != child);
+  }
+  if (nullptr != mEmptyChild) {
+    GeckoStyleContext* child = mEmptyChild;
+    do {
+      child->List(out, aIndent + 1, true);
+      child = child->mNextSibling;
+    } while (mEmptyChild != child);
+  }
+}
+#endif
+
+void
+GeckoStyleContext::ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
+{
+  if (mChild) {
+    GeckoStyleContext* child = mChild;
+    do {
+      child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
+      child = child->mNextSibling;
+    } while (mChild != child);
+  }
+  if (mEmptyChild) {
+    GeckoStyleContext* child = mEmptyChild;
+    do {
+      child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
+      child = child->mNextSibling;
+    } while (mEmptyChild != child);
+  }
+}
+
+void
+GeckoStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
+{
+  NS_ASSERTION(mFrameRefCnt == 0, "frame still referencing style context");
+  for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
+       i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
+       i = nsStyleStructID(i + 1)) {
+    uint32_t bit = nsCachedStyleData::GetBitForSID(i);
+    if (aStructs & bit) {
+      if (!(mBits & bit) && mCachedInheritedData.mStyleStructs[i]) {
+        aStructs &= ~bit;
+      } else {
+        mCachedInheritedData.mStyleStructs[i] = nullptr;
+      }
+    }
+  }
+
+  if (mCachedResetData) {
+    for (nsStyleStructID i = nsStyleStructID_Reset_Start;
+         i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
+         i = nsStyleStructID(i + 1)) {
+      uint32_t bit = nsCachedStyleData::GetBitForSID(i);
+      if (aStructs & bit) {
+        if (!(mBits & bit) && mCachedResetData->mStyleStructs[i]) {
+          aStructs &= ~bit;
+        } else {
+          mCachedResetData->mStyleStructs[i] = nullptr;
+        }
+      }
+    }
+  }
+
+  if (aStructs == 0) {
+    return;
+  }
+
+  ClearCachedInheritedStyleDataOnDescendants(aStructs);
+}
+
+
+already_AddRefed<GeckoStyleContext>
+GeckoStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag,
+                                   NonOwningStyleContextSource aSource,
+                                   NonOwningStyleContextSource aSourceIfVisited,
+                                   bool aRelevantLinkVisited)
+{
+  uint32_t threshold = 10; // The # of siblings we're willing to examine
+                           // before just giving this whole thing up.
+
+  RefPtr<GeckoStyleContext> result;
+  GeckoStyleContext *list = aSource.MatchesNoRules() ? mEmptyChild : mChild;
+
+  if (list) {
+    GeckoStyleContext *child = list;
+    do {
+      if (child->mSource.AsRaw() == aSource &&
+          child->mPseudoTag == aPseudoTag &&
+          !child->IsStyleIfVisited() &&
+          child->RelevantLinkVisited() == aRelevantLinkVisited) {
+        bool match = false;
+        if (!aSourceIfVisited.IsNull()) {
+          match = child->GetStyleIfVisited() &&
+                  child->GetStyleIfVisited()->AsGecko()->mSource.AsRaw() == aSourceIfVisited;
+        } else {
+          match = !child->GetStyleIfVisited();
+        }
+        if (match && !(child->mBits & NS_STYLE_INELIGIBLE_FOR_SHARING)) {
+          result = child;
+          break;
+        }
+      }
+      child = child->mNextSibling;
+      threshold--;
+      if (threshold == 0)
+        break;
+    } while (child != list);
+  }
+
+  if (result) {
+    if (result != list) {
+      // Move result to the front of the list.
+      RemoveChild(result);
+      AddChild(result);
+    }
+    result->mBits |= NS_STYLE_IS_SHARED;
+  }
+
+  return result.forget();
+}
+
--- a/layout/style/GeckoStyleContext.h
+++ b/layout/style/GeckoStyleContext.h
@@ -19,13 +19,54 @@ public:
                     already_AddRefed<nsRuleNode> aRuleNode,
                     bool aSkipParentDisplayBasedStyleFixup);
 
   void* operator new(size_t sz, nsPresContext* aPresContext);
 
   nsPresContext* PresContext() const {
     return mSource.AsGeckoRuleNode()->PresContext();
   }
+
+  void AddChild(GeckoStyleContext* aChild);
+  void RemoveChild(GeckoStyleContext* aChild);
+  /**
+   * On each descendant of this style context, clears out any cached inherited
+   * structs indicated in aStructs.
+   */
+  void ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
+  // Find, if it already exists *and is easily findable* (i.e., near the
+  // start of the child list), a style context whose:
+  //  * GetPseudo() matches aPseudoTag
+  //  * mSource matches aSource
+  //  * !!GetStyleIfVisited() == !!aSourceIfVisited, and, if they're
+  //    non-null, GetStyleIfVisited()->mSource == aSourceIfVisited
+  //  * RelevantLinkVisited() == aRelevantLinkVisited
+  already_AddRefed<GeckoStyleContext>
+  FindChildWithRules(const nsIAtom* aPseudoTag,
+                     mozilla::NonOwningStyleContextSource aSource,
+                     mozilla::NonOwningStyleContextSource aSourceIfVisited,
+                     bool aRelevantLinkVisited);
+
+#ifdef DEBUG
+  void ListDescendants(FILE* out, int32_t aIndent);
+#endif
+
+private:
+  // Helper for ClearCachedInheritedStyleDataOnDescendants.
+  void DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
+
+
+public:
+  // Children are kept in two circularly-linked lists.  The list anchor
+  // is not part of the list (null for empty), and we point to the first
+  // child.
+  // mEmptyChild for children whose rule node is the root rule node, and
+  // mChild for other children.  The order of children is not
+  // meaningful.
+  GeckoStyleContext* mChild;
+  GeckoStyleContext* mEmptyChild;
+  GeckoStyleContext* mPrevSibling;
+  GeckoStyleContext* mNextSibling;
 };
 
 }
 
 #endif // mozilla_GeckoStyleContext_h
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -64,16 +64,17 @@ EXPORTS += [
     'nsMediaList.h',
     'nsRuleData.h',
     'nsRuleNode.h',
     'nsRuleProcessorData.h',
     'nsRuleWalker.h',
     'nsStyleAutoArray.h',
     'nsStyleConsts.h',
     'nsStyleContext.h',
+    'nsStyleContextInlines.h',
     'nsStyleCoord.h',
     'nsStyleSet.h',
     'nsStyleStruct.h',
     'nsStyleStructFwd.h',
     'nsStyleStructInlines.h',
     'nsStyleTransformMatrix.h',
     'nsStyleUtil.h',
 ]
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -1,18 +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/. */
 
 /* the interface (to internal code) for retrieving computed style data */
 
 #include "nsStyleContext.h"
-#include "nsStyleContextInlines.h"
-
 #include "CSSVariableImageTable.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Maybe.h"
 
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSPseudoElements.h"
 #include "nsFontMetrics.h"
 #include "nsStyleConsts.h"
@@ -32,16 +30,17 @@
 #include "nsPrintfCString.h"
 #include "RubyUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ArenaObjectID.h"
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSetHandleInlines.h"
 #include "mozilla/GeckoStyleContext.h"
 #include "mozilla/ServoStyleContext.h"
+#include "nsStyleContextInlines.h"
 
 #include "mozilla/ReflowInput.h"
 #include "nsLayoutUtils.h"
 #include "nsCoord.h"
 
 // Ensure the binding function declarations in nsStyleContext.h matches
 // those in ServoBindings.h.
 #include "mozilla/ServoBindings.h"
@@ -82,18 +81,16 @@ const uint32_t nsStyleContext::sDependen
 static bool sExpensiveStyleStructAssertionsEnabled;
 #endif
 
 nsStyleContext::nsStyleContext(nsStyleContext* aParent,
                                OwningStyleContextSource&& aSource,
                                nsIAtom* aPseudoTag,
                                CSSPseudoElementType aPseudoType)
   : mParent(aParent)
-  , mChild(nullptr)
-  , mEmptyChild(nullptr)
   , mPseudoTag(aPseudoTag)
   , mSource(Move(aSource))
   , mCachedResetData(nullptr)
   , mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT)
   , mRefCnt(0)
 #ifdef DEBUG
   , mFrameRefCnt(0)
   , mComputingStruct(nsStyleStructID_None)
@@ -112,33 +109,34 @@ nsStyleContext::FinishConstruction()
   MOZ_ASSERT(!mSource.IsNull());
 
 #ifdef DEBUG
   static_assert(MOZ_ARRAY_LENGTH(nsStyleContext::sDependencyTable)
                   == nsStyleStructID_Length,
                 "Number of items in dependency table doesn't match IDs");
 #endif
 
-  mNextSibling = this;
-  mPrevSibling = this;
   if (mParent) {
     mParent->AddChild(this);
   }
 
   SetStyleBits();
 
   #define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
   static_assert(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
                 "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
   #undef eStyleStruct_LastItem
 }
 
 nsStyleContext::~nsStyleContext()
 {
-  NS_ASSERTION((nullptr == mChild) && (nullptr == mEmptyChild), "destructing context with children");
+  if (const GeckoStyleContext* gecko = GetAsGecko()) {
+    NS_ASSERTION((nullptr == gecko->mChild) && (nullptr == gecko->mEmptyChild),
+                 "destructing context with children");
+  }
   MOZ_ASSERT(!mSource.IsServoComputedValues() || !mCachedResetData);
 
 #ifdef DEBUG
   if (mSource.IsServoComputedValues()) {
     MOZ_ASSERT(!mCachedResetData,
                "Servo shouldn't cache reset structs in nsStyleContext");
     for (const auto* data : mCachedInheritedData.mStyleStructs) {
       MOZ_ASSERT(!data,
@@ -250,76 +248,49 @@ nsStyleContext::AssertStructsNotUsedElse
 #include "nsStyleStructList.h"
 
 #undef STYLE_STRUCT_INHERITED
 #undef STYLE_STRUCT_RESET
       }
     }
   }
 
-  if (mChild) {
-    const nsStyleContext* child = mChild;
-    do {
-      child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
-      child = child->mNextSibling;
-    } while (child != mChild);
-  }
+  if (const GeckoStyleContext* gecko = GetAsGecko()) {
+    if (gecko->mChild) {
+      const GeckoStyleContext* child = gecko->mChild;
+      do {
+        child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
+        child = child->mNextSibling;
+      } while (child != gecko->mChild);
+    }
 
-  if (mEmptyChild) {
-    const nsStyleContext* child = mEmptyChild;
-    do {
-      child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
-      child = child->mNextSibling;
-    } while (child != mEmptyChild);
+    if (gecko->mEmptyChild) {
+      const GeckoStyleContext* child = gecko->mEmptyChild;
+      do {
+        child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
+        child = child->mNextSibling;
+      } while (child != gecko->mEmptyChild);
+    }
   }
 }
 #endif
 
+
 void nsStyleContext::AddChild(nsStyleContext* aChild)
 {
-  NS_ASSERTION(aChild->mPrevSibling == aChild &&
-               aChild->mNextSibling == aChild,
-               "child already in a child list");
-
-  nsStyleContext **listPtr = aChild->mSource.MatchesNoRules() ? &mEmptyChild : &mChild;
-  // Explicitly dereference listPtr so that compiler doesn't have to know that mNextSibling
-  // etc. don't alias with what ever listPtr points at.
-  nsStyleContext *list = *listPtr;
-
-  // Insert at the beginning of the list.  See also FindChildWithRules.
-  if (list) {
-    // Link into existing elements, if there are any.
-    aChild->mNextSibling = list;
-    aChild->mPrevSibling = list->mPrevSibling;
-    list->mPrevSibling->mNextSibling = aChild;
-    list->mPrevSibling = aChild;
+  if (GeckoStyleContext* gecko = GetAsGecko()) {
+    gecko->AddChild(aChild->AsGecko());
   }
-  (*listPtr) = aChild;
 }
 
 void nsStyleContext::RemoveChild(nsStyleContext* aChild)
 {
-  NS_PRECONDITION(nullptr != aChild && this == aChild->mParent, "bad argument");
-
-  nsStyleContext **list = aChild->mSource.MatchesNoRules() ? &mEmptyChild : &mChild;
-
-  if (aChild->mPrevSibling != aChild) { // has siblings
-    if ((*list) == aChild) {
-      (*list) = (*list)->mNextSibling;
-    }
+  if (GeckoStyleContext* gecko = GetAsGecko()) {
+    gecko->RemoveChild(aChild->AsGecko());
   }
-  else {
-    NS_ASSERTION((*list) == aChild, "bad sibling pointers");
-    (*list) = nullptr;
-  }
-
-  aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
-  aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
-  aChild->mNextSibling = aChild;
-  aChild->mPrevSibling = aChild;
 }
 
 void
 nsStyleContext::MoveTo(nsStyleContext* aNewParent)
 {
   MOZ_ASSERT(aNewParent != mParent);
 
   // This function shouldn't be getting called if the parents have different
@@ -358,66 +329,16 @@ nsStyleContext::MoveTo(nsStyleContext* a
 
   if (mStyleIfVisited) {
     mStyleIfVisited->mParent->RemoveChild(mStyleIfVisited);
     mStyleIfVisited->mParent = aNewParent;
     mStyleIfVisited->mParent->AddChild(mStyleIfVisited);
   }
 }
 
-already_AddRefed<nsStyleContext>
-nsStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag,
-                                   NonOwningStyleContextSource aSource,
-                                   NonOwningStyleContextSource aSourceIfVisited,
-                                   bool aRelevantLinkVisited)
-{
-  uint32_t threshold = 10; // The # of siblings we're willing to examine
-                           // before just giving this whole thing up.
-
-  RefPtr<nsStyleContext> result;
-  nsStyleContext *list = aSource.MatchesNoRules() ? mEmptyChild : mChild;
-
-  if (list) {
-    nsStyleContext *child = list;
-    do {
-      if (child->mSource.AsRaw() == aSource &&
-          child->mPseudoTag == aPseudoTag &&
-          !child->IsStyleIfVisited() &&
-          child->RelevantLinkVisited() == aRelevantLinkVisited) {
-        bool match = false;
-        if (!aSourceIfVisited.IsNull()) {
-          match = child->GetStyleIfVisited() &&
-                  child->GetStyleIfVisited()->mSource.AsRaw() == aSourceIfVisited;
-        } else {
-          match = !child->GetStyleIfVisited();
-        }
-        if (match && !(child->mBits & NS_STYLE_INELIGIBLE_FOR_SHARING)) {
-          result = child;
-          break;
-        }
-      }
-      child = child->mNextSibling;
-      threshold--;
-      if (threshold == 0)
-        break;
-    } while (child != list);
-  }
-
-  if (result) {
-    if (result != list) {
-      // Move result to the front of the list.
-      RemoveChild(result);
-      AddChild(result);
-    }
-    result->mBits |= NS_STYLE_IS_SHARED;
-  }
-
-  return result.forget();
-}
-
 const void* nsStyleContext::StyleData(nsStyleStructID aSID)
 {
   const void* cachedData = GetCachedStyleData(aSID);
   if (cachedData)
     return cachedData; // We have computed data stored on this node in the context tree.
   // Our style source will take care of it for us.
   const void* newData;
   if (mSource.IsGeckoRuleNode()) {
@@ -471,17 +392,22 @@ nsStyleContext::GetUniqueStyleData(const
              "Can't COW-mutate servo values from Gecko!");
 
   // If we already own the struct and no kids could depend on it, then
   // just return it.  (We leak in this case if there are kids -- and this
   // function really shouldn't be called for style contexts that could
   // have kids depending on the data.  ClearStyleData would be OK, but
   // this test for no mChild or mEmptyChild doesn't catch that case.)
   const void *current = StyleData(aSID);
-  if (!mChild && !mEmptyChild &&
+  GeckoStyleContext *child = nullptr, *emptyChild = nullptr;
+  if (const GeckoStyleContext* gecko = GetAsGecko()) {
+    child = gecko->mChild;
+    emptyChild = gecko->mEmptyChild;
+  }
+  if (!child && !emptyChild &&
       !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
       GetCachedStyleData(aSID))
     return const_cast<void*>(current);
 
   void* result;
   nsPresContext *presContext = PresContext();
   switch (aSID) {
 
@@ -510,18 +436,20 @@ nsStyleContext::GetUniqueStyleData(const
   return result;
 }
 
 // This is an evil function, but less evil than GetUniqueStyleData. It
 // creates an empty style struct for this nsStyleContext.
 void*
 nsStyleContext::CreateEmptyStyleData(const nsStyleStructID& aSID)
 {
-  MOZ_ASSERT(!mChild && !mEmptyChild &&
-             !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
+  if (const GeckoStyleContext* gecko = GetAsGecko()) {
+    MOZ_ASSERT(!gecko->mChild && !gecko->mEmptyChild, "This style should not have been computed");
+  }
+  MOZ_ASSERT(!(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
              !GetCachedStyleData(aSID),
              "This style should not have been computed");
 
   void* result;
   nsPresContext* presContext = PresContext();
   switch (aSID) {
 #define UNIQUE_CASE(c_) \
     case eStyleStruct_##c_: \
@@ -1300,29 +1228,18 @@ void nsStyleContext::List(FILE* out, int
     }
     fprintf_stderr(out, "%s}\n", str.get());
   }
   else {
     fprintf_stderr(out, "%s{}\n", str.get());
   }
 
   if (aListDescendants) {
-    if (nullptr != mChild) {
-      nsStyleContext* child = mChild;
-      do {
-        child->List(out, aIndent + 1, aListDescendants);
-        child = child->mNextSibling;
-      } while (mChild != child);
-    }
-    if (nullptr != mEmptyChild) {
-      nsStyleContext* child = mEmptyChild;
-      do {
-        child->List(out, aIndent + 1, aListDescendants);
-        child = child->mNextSibling;
-      } while (mEmptyChild != child);
+    if (GeckoStyleContext* gecko = GetAsGecko()) {
+      gecko->ListDescendants(out, aIndent);
     }
   }
 }
 #endif
 
 // Overridden to prevent the global delete from being called, since the memory
 // came out of an nsIArena instead of the global delete operator's heap.
 void
@@ -1531,93 +1448,37 @@ nsStyleContext::SwapStyleData(nsStyleCon
       }
     } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
       std::swap(thisData, otherData);
     }
   }
 }
 
 void
-nsStyleContext::ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
-{
-  if (mChild) {
-    nsStyleContext* child = mChild;
-    do {
-      child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
-      child = child->mNextSibling;
-    } while (mChild != child);
-  }
-  if (mEmptyChild) {
-    nsStyleContext* child = mEmptyChild;
-    do {
-      child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
-      child = child->mNextSibling;
-    } while (mEmptyChild != child);
-  }
-}
-
-void
-nsStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
-{
-  NS_ASSERTION(mFrameRefCnt == 0, "frame still referencing style context");
-  for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
-       i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
-       i = nsStyleStructID(i + 1)) {
-    uint32_t bit = nsCachedStyleData::GetBitForSID(i);
-    if (aStructs & bit) {
-      if (!(mBits & bit) && mCachedInheritedData.mStyleStructs[i]) {
-        aStructs &= ~bit;
-      } else {
-        mCachedInheritedData.mStyleStructs[i] = nullptr;
-      }
-    }
-  }
-
-  if (mCachedResetData) {
-    for (nsStyleStructID i = nsStyleStructID_Reset_Start;
-         i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
-         i = nsStyleStructID(i + 1)) {
-      uint32_t bit = nsCachedStyleData::GetBitForSID(i);
-      if (aStructs & bit) {
-        if (!(mBits & bit) && mCachedResetData->mStyleStructs[i]) {
-          aStructs &= ~bit;
-        } else {
-          mCachedResetData->mStyleStructs[i] = nullptr;
-        }
-      }
-    }
-  }
-
-  if (aStructs == 0) {
-    return;
-  }
-
-  ClearCachedInheritedStyleDataOnDescendants(aStructs);
-}
-
-void
 nsStyleContext::SetIneligibleForSharing()
 {
   if (mBits & NS_STYLE_INELIGIBLE_FOR_SHARING) {
     return;
   }
   mBits |= NS_STYLE_INELIGIBLE_FOR_SHARING;
-  if (mChild) {
-    nsStyleContext* child = mChild;
-    do {
-      child->SetIneligibleForSharing();
-      child = child->mNextSibling;
-    } while (mChild != child);
-  }
-  if (mEmptyChild) {
-    nsStyleContext* child = mEmptyChild;
-    do {
-      child->SetIneligibleForSharing();
-      child = child->mNextSibling;
-    } while (mEmptyChild != child);
+  if (const GeckoStyleContext* gecko = GetAsGecko()) {
+    if (gecko->mChild) {
+      GeckoStyleContext* child = gecko->mChild;
+      do {
+        child->SetIneligibleForSharing();
+        child = child->mNextSibling;
+      } while (gecko->mChild != child);
+    }
+    if (gecko->mEmptyChild) {
+      GeckoStyleContext* child = gecko->mEmptyChild;
+      do {
+        child->SetIneligibleForSharing();
+        child = child->mNextSibling;
+      } while (gecko->mEmptyChild != child);
+    }
   }
 }
 
 #ifdef RESTYLE_LOGGING
 nsCString
 nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
 {
   nsCString structs;
@@ -1687,29 +1548,31 @@ nsStyleContext::LogStyleContextTree(bool
   }
 
   LOG_RESTYLE("%p(%d) %s%s%s%s",
               this, mRefCnt,
               structs.get(), pseudo.get(), flags.get(), parent.get());
 
   LOG_RESTYLE_INDENT();
 
-  if (nullptr != mChild) {
-    nsStyleContext* child = mChild;
-    do {
-      child->LogStyleContextTree(false, aStructs);
-      child = child->mNextSibling;
-    } while (mChild != child);
-  }
-  if (nullptr != mEmptyChild) {
-    nsStyleContext* child = mEmptyChild;
-    do {
-      child->LogStyleContextTree(false, aStructs);
-      child = child->mNextSibling;
-    } while (mEmptyChild != child);
+  if (const GeckoStyleContext* gecko = GetAsGecko()) {
+    if (nullptr != gecko->mChild) {
+      GeckoStyleContext* child = gecko->mChild;
+      do {
+        child->LogStyleContextTree(false, aStructs);
+        child = child->mNextSibling;
+      } while (gecko->mChild != child);
+    }
+    if (nullptr != gecko->mEmptyChild) {
+      GeckoStyleContext* child = gecko->mEmptyChild;
+      do {
+        child->LogStyleContextTree(false, aStructs);
+        child = child->mNextSibling;
+      } while (gecko->mEmptyChild != child);
+    }
   }
 }
 #endif
 
 #ifdef DEBUG
 /* static */ void
 nsStyleContext::Initialize()
 {
@@ -1719,8 +1582,9 @@ nsStyleContext::Initialize()
 }
 #endif
 
 nsPresContext*
 nsStyleContext::PresContext() const
 {
     MOZ_STYLO_FORWARD(PresContext, ())
 }
+
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -149,29 +149,16 @@ public:
   bool IsAnonBox() const {
     return
       GetPseudoType() == mozilla::CSSPseudoElementType::InheritingAnonBox ||
       GetPseudoType() == mozilla::CSSPseudoElementType::NonInheritingAnonBox;
   }
   bool IsPseudoElement() const { return mPseudoTag && !IsAnonBox(); }
 
 
-  // Find, if it already exists *and is easily findable* (i.e., near the
-  // start of the child list), a style context whose:
-  //  * GetPseudo() matches aPseudoTag
-  //  * mSource matches aSource
-  //  * !!GetStyleIfVisited() == !!aSourceIfVisited, and, if they're
-  //    non-null, GetStyleIfVisited()->mSource == aSourceIfVisited
-  //  * RelevantLinkVisited() == aRelevantLinkVisited
-  already_AddRefed<nsStyleContext>
-  FindChildWithRules(const nsIAtom* aPseudoTag,
-                     mozilla::NonOwningStyleContextSource aSource,
-                     mozilla::NonOwningStyleContextSource aSourceIfVisited,
-                     bool aRelevantLinkVisited);
-
   // Does this style context or any of its ancestors have text
   // decoration lines?
   // Differs from nsStyleTextReset::HasTextDecorationLines, which tests
   // only the data for a single context.
   bool HasTextDecorationLines() const
     { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); }
 
   // Whether any line break inside should be suppressed? If this returns
@@ -455,21 +442,16 @@ public:
    * inheriting from the old ancestor.  This is not normally a problem, as
    * this style context will usually be destroyed by being released at the
    * end of ElementRestyler::Restyle; but for style contexts held on to outside
    * of the frame, we need to clear out the cached pointer so that if we need
    * it again we'll re-fetch it from the new ancestor.
    */
   void SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs);
 
-  /**
-   * On each descendant of this style context, clears out any cached inherited
-   * structs indicated in aStructs.
-   */
-  void ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
 
   /**
    * Sets the NS_STYLE_INELIGIBLE_FOR_SHARING bit on this style context
    * and its descendants.  If it finds a descendant that has the bit
    * already set, assumes that it can skip that subtree.
    */
   void SetIneligibleForSharing();
 
@@ -504,29 +486,30 @@ public:
     } else {
       cachedData = mCachedInheritedData.mStyleStructs[aSID];
     }
     return cachedData;
   }
 
   mozilla::NonOwningStyleContextSource StyleSource() const { return mSource.AsRaw(); }
 
-protected:
+public: // temporary
   // Private destructor, to discourage deletion outside of Release():
   ~nsStyleContext();
 
   // Delegated Helper constructor.
   nsStyleContext(nsStyleContext* aParent,
                  mozilla::OwningStyleContextSource&& aSource,
                  nsIAtom* aPseudoTag,
                  mozilla::CSSPseudoElementType aPseudoType);
 
   // Helper post-contruct hook.
   void FinishConstruction();
 
+  // Only does stuff in Gecko mode
   void AddChild(nsStyleContext* aChild);
   void RemoveChild(nsStyleContext* aChild);
 
   void* GetUniqueStyleData(const nsStyleStructID& aSID);
   void* CreateEmptyStyleData(const nsStyleStructID& aSID);
 
   void SetStyleBits();
 
@@ -676,46 +659,32 @@ protected:
         AddStyleBit(NS_STYLE_INHERIT_BIT(name_));                       \
       }                                                                 \
       return data;                                                      \
     }
   #include "nsStyleStructList.h"
   #undef STYLE_STRUCT_RESET
   #undef STYLE_STRUCT_INHERITED
 
-  // Helper for ClearCachedInheritedStyleDataOnDescendants.
-  void DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
-
 #ifdef DEBUG
   void AssertStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext,
                                      int32_t aLevels) const;
 #endif
 
 #ifdef RESTYLE_LOGGING
   void LogStyleContextTree(bool aFirst, uint32_t aStructs);
 
   // This only gets called under call trees where we've already checked
   // that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
   // It exists here just to satisfy LOG_RESTYLE's expectations.
   bool ShouldLogRestyle() { return true; }
 #endif
 
   RefPtr<nsStyleContext> mParent;
 
-  // Children are kept in two circularly-linked lists.  The list anchor
-  // is not part of the list (null for empty), and we point to the first
-  // child.
-  // mEmptyChild for children whose rule node is the root rule node, and
-  // mChild for other children.  The order of children is not
-  // meaningful.
-  nsStyleContext* mChild;
-  nsStyleContext* mEmptyChild;
-  nsStyleContext* mPrevSibling;
-  nsStyleContext* mNextSibling;
-
   // Style to be used instead for the R, G, and B components of color,
   // background-color, and border-*-color if the nearest ancestor link
   // element is visited (see RelevantLinkVisited()).
   RefPtr<nsStyleContext> mStyleIfVisited;
 
   // If this style context is for a pseudo-element or anonymous box,
   // the relevant atom.
   nsCOMPtr<nsIAtom> mPseudoTag;
--- a/layout/style/nsStyleContextInlines.h
+++ b/layout/style/nsStyleContextInlines.h
@@ -6,21 +6,21 @@
 
 /*
  * Inlined methods for nsStyleContext. Will just redirect to
  * GeckoStyleContext methods when compiled without stylo, but will do
  * virtual dispatch (by checking which kind of container it is)
  * in stylo mode.
  */
 
-#ifndef mozilla_nsStyleContextInlines_h
-#define mozilla_nsStyleContextInlines_h
+#ifndef nsStyleContextInlines_h
+#define nsStyleContextInlines_h
 
 #include "nsStyleContext.h"
 #include "mozilla/ServoStyleContext.h"
 #include "mozilla/GeckoStyleContext.h"
 #include "mozilla/ServoUtils.h"
 
 using namespace mozilla;
 
 MOZ_DEFINE_STYLO_METHODS(nsStyleContext, GeckoStyleContext, ServoStyleContext);
 
-#endif // mozilla_nsStyleContextInlines_h
+#endif // nsStyleContextInlines_h
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -38,16 +38,17 @@
 #include "nsHTMLCSSStyleSheet.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsCSSRules.h"
 #include "nsPrintfCString.h"
 #include "nsIFrame.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/RestyleManagerInlines.h"
 #include "nsQueryObject.h"
+#include "nsStyleContextInlines.h"
 
 #include <inttypes.h>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS(nsEmptyStyleRule, nsIStyleRule)
 
@@ -921,17 +922,17 @@ nsStyleSet::GetContext(nsStyleContext* a
   }
 
   bool relevantLinkVisited = (aFlags & eIsLink) ?
     (aFlags & eIsVisitedLink) :
     (aParentContext && aParentContext->RelevantLinkVisited());
 
   RefPtr<nsStyleContext> result;
   if (aParentContext)
-    result = aParentContext->FindChildWithRules(aPseudoTag, aRuleNode,
+    result = aParentContext->AsGecko()->FindChildWithRules(aPseudoTag, aRuleNode,
                                                 aVisitedRuleNode,
                                                 relevantLinkVisited);
 
   if (!result) {
     // |aVisitedRuleNode| may have a ref-count of zero since we are yet
     // to create the style context that will hold an owning reference to it.
     // As a result, we need to make sure it stays alive until that point
     // in case something in the first call to NS_NewStyleContext triggers a