Bug 1348481 Part 2: Gecko-side track unique IDs for each stylesheet and send them to Servo. draft
authorBrad Werth <bwerth@mozilla.com>
Mon, 01 May 2017 16:46:41 -0700
changeset 571471 de49cdb244f63a10c8608bf293cf3a7419921484
parent 571470 13a3b97a2597fa5e72a640a09dc2fdc7728e6d42
child 571472 c3d54f057c6f9068b2696bae7224f15697610a27
push id56805
push userbwerth@mozilla.com
push dateTue, 02 May 2017 18:03:06 +0000
bugs1348481
milestone55.0a1
Bug 1348481 Part 2: Gecko-side track unique IDs for each stylesheet and send them to Servo. MozReview-Commit-ID: 7ZaQYhjdYmG
layout/style/ServoBindingList.h
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -45,24 +45,35 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_HasR
                    RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSheet_GetRules, ServoCssRulesStrong,
                    RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSetOwned, RawGeckoPresContextOwned pres_context)
 SERVO_BINDING_FUNC(Servo_StyleSet_RebuildData, void,
                    RawServoStyleSetBorrowed set)
 SERVO_BINDING_FUNC(Servo_StyleSet_Drop, void, RawServoStyleSetOwned set)
 SERVO_BINDING_FUNC(Servo_StyleSet_AppendStyleSheet, void,
-                   RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet, bool flush)
+                   RawServoStyleSetBorrowed set,
+                   RawServoStyleSheetBorrowed sheet,
+                   uint32_t unique_id,
+                   bool flush)
 SERVO_BINDING_FUNC(Servo_StyleSet_PrependStyleSheet, void,
-                   RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet, bool flush)
+                   RawServoStyleSetBorrowed set,
+                   RawServoStyleSheetBorrowed sheet,
+                   uint32_t unique_id,
+                   bool flush)
 SERVO_BINDING_FUNC(Servo_StyleSet_RemoveStyleSheet, void,
-                   RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet, bool flush)
+                   RawServoStyleSetBorrowed set,
+                   uint32_t unique_id,
+                   bool flush)
 SERVO_BINDING_FUNC(Servo_StyleSet_InsertStyleSheetBefore, void,
-                   RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet,
-                   RawServoStyleSheetBorrowed reference, bool flush)
+                   RawServoStyleSetBorrowed set,
+                   RawServoStyleSheetBorrowed sheet,
+                   uint32_t unique_id,
+                   uint32_t before_unique_id,
+                   bool flush)
 SERVO_BINDING_FUNC(Servo_StyleSet_FlushStyleSheets, void, RawServoStyleSetBorrowed set)
 SERVO_BINDING_FUNC(Servo_StyleSet_NoteStyleSheetsChanged, void,
                    RawServoStyleSetBorrowed set, bool author_style_disabled)
 SERVO_BINDING_FUNC(Servo_StyleSet_FillKeyframesForName, bool,
                    RawServoStyleSetBorrowed set,
                    const nsACString* property,
                    nsTimingFunctionBorrowed timing_function,
                    ServoComputedValuesBorrowed computed_values,
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -26,16 +26,17 @@
 #include "nsStyleSet.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 ServoStyleSet::ServoStyleSet()
   : mPresContext(nullptr)
   , mBatching(0)
+  , mUniqueIDCounter(0)
   , mAllowResolveStaleStyles(false)
   , mAuthorStyleDisabled(false)
 {
 }
 
 ServoStyleSet::~ServoStyleSet()
 {
 }
@@ -46,25 +47,32 @@ ServoStyleSet::Init(nsPresContext* aPres
   mPresContext = aPresContext;
   mRawSet.reset(Servo_StyleSet_Init(aPresContext));
 
   mPresContext->DeviceContext()->InitFontCache();
   gfxPlatformFontList::PlatformFontList()->InitLangService();
 
   // Now that we have an mRawSet, go ahead and notify about whatever stylesheets
   // we have so far.
-  for (auto& sheetArray : mSheets) {
-    for (auto& sheet : sheetArray) {
+  for (auto& entryArray : mEntries) {
+    for (auto& entry : entryArray) {
       // There's no guarantee this will create a list on the servo side whose
       // ordering matches the list that would have been created had all those
-      // sheets been appended/prepended/etc after we had mRawSet.  But hopefully
-      // that's OK (e.g. because servo doesn't care about the relative ordering
-      // of sheets from different cascade levels in the list?).
-      MOZ_ASSERT(sheet->RawSheet(), "We should only append non-null raw sheets.");
-      Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet->RawSheet(), false);
+      // sheets been appended/prepended/etc after we had mRawSet. That's okay
+      // because Servo only needs to maintain relative ordering within a sheet
+      // type, which this preserves.
+
+      // Set the uniqueIDs as we go.
+      entry.uniqueID = ++mUniqueIDCounter;
+
+      MOZ_ASSERT(entry.sheet->RawSheet(), "We should only append non-null raw sheets.");
+      Servo_StyleSet_AppendStyleSheet(mRawSet.get(),
+                                      entry.sheet->RawSheet(),
+                                      entry.uniqueID,
+                                      false);
     }
   }
 
   // No need to Servo_StyleSet_FlushStyleSheets because we just created the
   // mRawSet, so there was nothing to flush.
 }
 
 void
@@ -542,88 +550,103 @@ ServoStyleSet::ResolveNonInheritingAnony
 // manage the set of style sheets in the style set
 nsresult
 ServoStyleSet::AppendStyleSheet(SheetType aType,
                                 ServoStyleSheet* aSheet)
 {
   MOZ_ASSERT(aSheet);
   MOZ_ASSERT(aSheet->IsApplicable());
   MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
+  MOZ_ASSERT(aSheet->RawSheet(), "Raw sheet should be in place before insertion.");
 
-  MOZ_ASSERT(aSheet->RawSheet(), "Raw sheet should be in place before insertion.");
-  mSheets[aType].RemoveElement(aSheet);
-  mSheets[aType].AppendElement(aSheet);
+  // If we were already tracking aSheet, the newUniqueID will be the same
+  // as the oldUniqueID. In that case, Servo will remove aSheet from its
+  // original position as part of the call to Servo_StyleSet_AppendStyleSheet.
+  uint32_t oldUniqueID = RemoveSheetOfType(aType, aSheet);
+  uint32_t newUniqueID = AppendSheetOfType(aType, aSheet, oldUniqueID);
 
   if (mRawSet) {
     // Maintain a mirrored list of sheets on the servo side.
-    Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet->RawSheet(), !mBatching);
+    Servo_StyleSet_AppendStyleSheet(mRawSet.get(),
+                                    aSheet->RawSheet(),
+                                    newUniqueID,
+                                    !mBatching);
   }
 
   return NS_OK;
 }
 
 nsresult
 ServoStyleSet::PrependStyleSheet(SheetType aType,
                                  ServoStyleSheet* aSheet)
 {
   MOZ_ASSERT(aSheet);
   MOZ_ASSERT(aSheet->IsApplicable());
   MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
+  MOZ_ASSERT(aSheet->RawSheet(), "Raw sheet should be in place before insertion.");
 
-  MOZ_ASSERT(aSheet->RawSheet(), "Raw sheet should be in place before insertion.");
-  mSheets[aType].RemoveElement(aSheet);
-  mSheets[aType].InsertElementAt(0, aSheet);
+  // If we were already tracking aSheet, the newUniqueID will be the same
+  // as the oldUniqueID. In that case, Servo will remove aSheet from its
+  // original position as part of the call to Servo_StyleSet_PrependStyleSheet.
+  uint32_t oldUniqueID = RemoveSheetOfType(aType, aSheet);
+  uint32_t newUniqueID = PrependSheetOfType(aType, aSheet, oldUniqueID);
 
   if (mRawSet) {
     // Maintain a mirrored list of sheets on the servo side.
-    Servo_StyleSet_PrependStyleSheet(mRawSet.get(), aSheet->RawSheet(), !mBatching);
+    Servo_StyleSet_PrependStyleSheet(mRawSet.get(),
+                                     aSheet->RawSheet(),
+                                     newUniqueID,
+                                     !mBatching);
   }
 
   return NS_OK;
 }
 
 nsresult
 ServoStyleSet::RemoveStyleSheet(SheetType aType,
                                 ServoStyleSheet* aSheet)
 {
   MOZ_ASSERT(aSheet);
   MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
 
-  mSheets[aType].RemoveElement(aSheet);
-
-  if (mRawSet) {
+  uint32_t uniqueID = RemoveSheetOfType(aType, aSheet);
+  if (mRawSet && uniqueID) {
     // Maintain a mirrored list of sheets on the servo side.
-    Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), aSheet->RawSheet(), !mBatching);
+    Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), uniqueID, !mBatching);
   }
 
   return NS_OK;
 }
 
 nsresult
 ServoStyleSet::ReplaceSheets(SheetType aType,
                              const nsTArray<RefPtr<ServoStyleSheet>>& aNewSheets)
 {
   // Gecko uses a two-dimensional array keyed by sheet type, whereas Servo
   // stores a flattened list. This makes ReplaceSheets a pretty clunky thing
   // to express. If the need ever arises, we can easily make this more efficent,
   // probably by aligning the representations better between engines.
 
+  // Remove all the existing sheets first.
   if (mRawSet) {
-    for (ServoStyleSheet* sheet : mSheets[aType]) {
-      Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), sheet->RawSheet(), false);
+    for (const Entry& entry : mEntries[aType]) {
+      Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), entry.uniqueID, false);
     }
   }
-
-  mSheets[aType].Clear();
-  mSheets[aType].AppendElements(aNewSheets);
+  mEntries[aType].Clear();
 
-  if (mRawSet) {
-    for (ServoStyleSheet* sheet : mSheets[aType]) {
+  // Add in all the new sheets.
+  for (auto& sheet : aNewSheets) {
+    uint32_t uniqueID = AppendSheetOfType(aType, sheet);
+    if (mRawSet) {
       MOZ_ASSERT(sheet->RawSheet(), "Raw sheet should be in place before replacement.");
-      Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet->RawSheet(), false);
+      Servo_StyleSet_AppendStyleSheet(mRawSet.get(),
+                                      sheet->RawSheet(),
+                                      uniqueID,
+                                      false);
     }
   }
 
   if (!mBatching) {
     Servo_StyleSet_FlushStyleSheets(mRawSet.get());
   }
 
   return NS_OK;
@@ -632,49 +655,58 @@ ServoStyleSet::ReplaceSheets(SheetType a
 nsresult
 ServoStyleSet::InsertStyleSheetBefore(SheetType aType,
                                       ServoStyleSheet* aNewSheet,
                                       ServoStyleSheet* aReferenceSheet)
 {
   MOZ_ASSERT(aNewSheet);
   MOZ_ASSERT(aReferenceSheet);
   MOZ_ASSERT(aNewSheet->IsApplicable());
+  MOZ_ASSERT(aNewSheet->RawSheet(), "Raw sheet should be in place before insertion.");
+  MOZ_ASSERT(aReferenceSheet->RawSheet(), "Reference sheet should have a raw sheet.");
 
-  mSheets[aType].RemoveElement(aNewSheet);
-  size_t idx = mSheets[aType].IndexOf(aReferenceSheet);
-  if (idx == mSheets[aType].NoIndex) {
+  uint32_t beforeUniqueID = FindSheetOfType(aType, aReferenceSheet);
+  if (beforeUniqueID == 0) {
     return NS_ERROR_INVALID_ARG;
   }
-  MOZ_ASSERT(aReferenceSheet->RawSheet(), "Reference sheet should have a raw sheet.");
 
-  MOZ_ASSERT(aNewSheet->RawSheet(), "Raw sheet should be in place before insertion.");
-  mSheets[aType].InsertElementAt(idx, aNewSheet);
+  // If we were already tracking aNewSheet, the newUniqueID will be the same
+  // as the oldUniqueID. In that case, Servo will remove aNewSheet from its
+  // original position as part of the call to Servo_StyleSet_InsertStyleSheetBefore.
+  uint32_t oldUniqueID = RemoveSheetOfType(aType, aNewSheet);
+  uint32_t newUniqueID = InsertSheetOfType(aType,
+                                           aNewSheet,
+                                           beforeUniqueID,
+                                           oldUniqueID);
 
   if (mRawSet) {
     // Maintain a mirrored list of sheets on the servo side.
-    Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aNewSheet->RawSheet(),
-                                          aReferenceSheet->RawSheet(), !mBatching);
+    Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(),
+                                          aNewSheet->RawSheet(),
+                                          newUniqueID,
+                                          beforeUniqueID,
+                                          !mBatching);
   }
 
   return NS_OK;
 }
 
 int32_t
 ServoStyleSet::SheetCount(SheetType aType) const
 {
   MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
-  return mSheets[aType].Length();
+  return mEntries[aType].Length();
 }
 
 ServoStyleSheet*
 ServoStyleSet::StyleSheetAt(SheetType aType,
                             int32_t aIndex) const
 {
   MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
-  return mSheets[aType][aIndex];
+  return mEntries[aType][aIndex].sheet;
 }
 
 nsresult
 ServoStyleSet::RemoveDocStyleSheet(ServoStyleSheet* aSheet)
 {
   return RemoveStyleSheet(SheetType::Doc, aSheet);
 }
 
@@ -682,33 +714,49 @@ nsresult
 ServoStyleSet::AddDocStyleSheet(ServoStyleSheet* aSheet,
                                 nsIDocument* aDocument)
 {
   MOZ_ASSERT(aSheet->IsApplicable());
   MOZ_ASSERT(aSheet->RawSheet(), "Raw sheet should be in place by this point.");
 
   RefPtr<StyleSheet> strong(aSheet);
 
-  nsTArray<RefPtr<ServoStyleSheet>>& sheetsArray = mSheets[SheetType::Doc];
-
-  sheetsArray.RemoveElement(aSheet);
+  uint32_t oldUniqueID = RemoveSheetOfType(SheetType::Doc, aSheet);
 
   size_t index =
-    aDocument->FindDocStyleSheetInsertionPoint(sheetsArray, aSheet);
-  sheetsArray.InsertElementAt(index, aSheet);
+    aDocument->FindDocStyleSheetInsertionPoint(mEntries[SheetType::Doc], aSheet);
+
+  if (index < mEntries[SheetType::Doc].Length()) {
+    // This case is insert before.
+    uint32_t beforeUniqueID = mEntries[SheetType::Doc][index].uniqueID;
+    uint32_t newUniqueID = InsertSheetOfType(SheetType::Doc,
+                                             aSheet,
+                                             beforeUniqueID,
+                                             oldUniqueID);
 
-  if (mRawSet) {
-    // Maintain a mirrored list of sheets on the servo side.
-    ServoStyleSheet* followingSheet = sheetsArray.SafeElementAt(index + 1);
-    if (followingSheet) {
-      MOZ_ASSERT(followingSheet->RawSheet(), "Every mSheets element should have a raw sheet");
-      Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aSheet->RawSheet(),
-                                            followingSheet->RawSheet(), !mBatching);
-    } else {
-      Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet->RawSheet(), !mBatching);
+    if (mRawSet) {
+      // Maintain a mirrored list of sheets on the servo side.
+      Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(),
+                                            aSheet->RawSheet(),
+                                            newUniqueID,
+                                            beforeUniqueID,
+                                            !mBatching);
+    }
+  } else {
+    // This case is append.
+    uint32_t newUniqueID = AppendSheetOfType(SheetType::Doc,
+                                             aSheet,
+                                             oldUniqueID);
+
+    if (mRawSet) {
+      // Maintain a mirrored list of sheets on the servo side.
+      Servo_StyleSet_AppendStyleSheet(mRawSet.get(),
+                                      aSheet->RawSheet(),
+                                      newUniqueID,
+                                      !mBatching);
     }
   }
 
   return NS_OK;
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ProbePseudoElementStyle(Element* aOriginatingElement,
@@ -980,9 +1028,74 @@ ServoStyleSet::ResolveForDeclarations(
   ServoComputedValuesBorrowedOrNull aParentOrNull,
   RawServoDeclarationBlockBorrowed aDeclarations)
 {
   return Servo_StyleSet_ResolveForDeclarations(mRawSet.get(),
                                                aParentOrNull,
                                                aDeclarations).Consume();
 }
 
+uint32_t
+ServoStyleSet::FindSheetOfType(SheetType aType,
+                               ServoStyleSheet* aSheet)
+{
+  for (const auto& entry : mEntries[aType]) {
+    if (entry.sheet == aSheet) {
+      return entry.uniqueID;
+    }
+  }
+  return 0;
+}
+
+uint32_t
+ServoStyleSet::PrependSheetOfType(SheetType aType,
+                                  ServoStyleSheet* aSheet,
+                                  uint32_t aReuseUniqueID)
+{
+  Entry* entry = mEntries[aType].InsertElementAt(0);
+  entry->uniqueID = aReuseUniqueID ? aReuseUniqueID : ++mUniqueIDCounter;
+  entry->sheet = aSheet;
+  return entry->uniqueID;
+}
+
+uint32_t
+ServoStyleSet::AppendSheetOfType(SheetType aType,
+                                 ServoStyleSheet* aSheet,
+                                 uint32_t aReuseUniqueID)
+{
+  Entry* entry = mEntries[aType].AppendElement();
+  entry->uniqueID = aReuseUniqueID ? aReuseUniqueID : ++mUniqueIDCounter;
+  entry->sheet = aSheet;
+  return entry->uniqueID;
+}
+
+uint32_t
+ServoStyleSet::InsertSheetOfType(SheetType aType,
+                                 ServoStyleSheet* aSheet,
+                                 uint32_t aBeforeUniqueID,
+                                 uint32_t aReuseUniqueID)
+{
+  for (uint32_t i = 0; i < mEntries[aType].Length(); ++i) {
+    if (mEntries[aType][i].uniqueID == aBeforeUniqueID) {
+      Entry* entry = mEntries[aType].InsertElementAt(i);
+      entry->uniqueID = aReuseUniqueID ? aReuseUniqueID : ++mUniqueIDCounter;
+      entry->sheet = aSheet;
+      return entry->uniqueID;
+    }
+  }
+  return 0;
+}
+
+uint32_t
+ServoStyleSet::RemoveSheetOfType(SheetType aType,
+                                 ServoStyleSheet* aSheet)
+{
+  for (uint32_t i = 0; i < mEntries[aType].Length(); ++i) {
+    if (mEntries[aType][i].sheet == aSheet) {
+      uint32_t uniqueID = mEntries[aType][i].uniqueID;
+      mEntries[aType].RemoveElementAt(i);
+      return uniqueID;
+    }
+  }
+  return 0;
+}
+
 bool ServoStyleSet::sInServoTraversal = false;
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -347,21 +347,50 @@ private:
    */
   void PreTraverse(dom::Element* aRoot = nullptr);
   // Subset of the pre-traverse steps that involve syncing up data
   void PreTraverseSync();
 
   already_AddRefed<ServoComputedValues> ResolveStyleLazily(dom::Element* aElement,
                                                            nsIAtom* aPseudoTag);
 
+  uint32_t FindSheetOfType(SheetType aType,
+                           ServoStyleSheet* aSheet);
+
+  uint32_t PrependSheetOfType(SheetType aType,
+                              ServoStyleSheet* aSheet,
+                              uint32_t aReuseUniqueID = 0);
+
+  uint32_t AppendSheetOfType(SheetType aType,
+                             ServoStyleSheet* aSheet,
+                             uint32_t aReuseUniqueID = 0);
+
+  uint32_t InsertSheetOfType(SheetType aType,
+                             ServoStyleSheet* aSheet,
+                             uint32_t aBeforeUniqueID,
+                             uint32_t aReuseUniqueID = 0);
+
+  uint32_t RemoveSheetOfType(SheetType aType,
+                             ServoStyleSheet* aSheet);
+
+  struct Entry {
+    uint32_t uniqueID;
+    RefPtr<ServoStyleSheet> sheet;
+
+    // Provide a cast operator to simplify calling
+    // nsIDocument::FindDocStyleSheetInsertionPoint.
+    operator ServoStyleSheet*() const { return sheet; }
+  };
+
   nsPresContext* mPresContext;
   UniquePtr<RawServoStyleSet> mRawSet;
   EnumeratedArray<SheetType, SheetType::Count,
-                  nsTArray<RefPtr<ServoStyleSheet>>> mSheets;
+                  nsTArray<Entry>> mEntries;
   int32_t mBatching;
+  uint32_t mUniqueIDCounter;
   bool mAllowResolveStaleStyles;
   bool mAuthorStyleDisabled;
 
   // Stores pointers to our cached style contexts for non-inheriting anonymous
   // boxes.
   EnumeratedArray<nsCSSAnonBoxes::NonInheriting,
                   nsCSSAnonBoxes::NonInheriting::_Count,
                   RefPtr<nsStyleContext>> mNonInheritingStyleContexts;