--- 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;