Bug 1436059: Fix inspector. r?xidorn draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 16 Feb 2018 11:34:12 +0100
changeset 756083 9dbb2e25d00a9224aec9955f0c00d5279cd5daeb
parent 756082 d59f1598981584168aaf580eef77d85b06c0f384
child 756084 bd8351268bf7145d183f6910157a5b9f86ded373
child 756086 d9b901c83f388c079721206152fd5a84db208d9d
push id99368
push userbmo:emilio@crisal.io
push dateFri, 16 Feb 2018 11:02:06 +0000
reviewersxidorn
bugs1436059
milestone60.0a1
Bug 1436059: Fix inspector. r?xidorn This removes a hack, but adds slightly more complex code in inspector-only code. I'm not excited about this code, but this fixes ServoStyleRuleMap for XBL. MozReview-Commit-ID: 6h0dCsiIWKU
layout/style/ServoBindingList.h
layout/style/ServoStyleSet.cpp
layout/style/StyleSheet.cpp
layout/style/StyleSheet.h
servo/ports/geckolib/glue.rs
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -178,16 +178,18 @@ SERVO_BINDING_FUNC(Servo_UACache_AddSize
 
 // AuthorStyles
 SERVO_BINDING_FUNC(Servo_AuthorStyles_Create, RawServoAuthorStyles*)
 // TODO(emilio): This will need to take an optional master style set to
 // implement invalidation for Shadow DOM.
 SERVO_BINDING_FUNC(Servo_AuthorStyles_AppendStyleSheet, void,
                    RawServoAuthorStylesBorrowedMut self,
                    const mozilla::ServoStyleSheet* gecko_sheet)
+SERVO_BINDING_FUNC(Servo_AuthorStyles_ForceDirty, void,
+                   RawServoAuthorStylesBorrowedMut self)
 // TODO(emilio): This will need to take an element to implement invalidation for
 // Shadow DOM.
 SERVO_BINDING_FUNC(Servo_AuthorStyles_Flush, void,
                    RawServoAuthorStylesBorrowedMut self,
                    RawServoStyleSetBorrowed document_styles)
 
 SERVO_BINDING_FUNC(Servo_StyleContext_AddRef, void, ServoStyleContextBorrowed ctx);
 SERVO_BINDING_FUNC(Servo_StyleContext_Release, void, ServoStyleContextBorrowed ctx);
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -1265,45 +1265,71 @@ ServoStyleSet::ComputeAnimationValue(
                                       aDeclarations,
                                       aContext,
                                       mRawSet.get()).Consume();
 }
 
 bool
 ServoStyleSet::EnsureUniqueInnerOnCSSSheets()
 {
-  AutoTArray<StyleSheet*, 32> queue;
+  using SheetOwner = Variant<ServoStyleSet*, nsXBLPrototypeBinding*>;
+
+  AutoTArray<Pair<StyleSheet*, SheetOwner>, 32> queue;
   for (auto& entryArray : mSheets) {
     for (auto& sheet : entryArray) {
-      queue.AppendElement(sheet);
+      StyleSheet* downcasted = sheet;
+      queue.AppendElement(MakePair(downcasted, SheetOwner { this }));
     }
   }
-  // This is a stub until more of the functionality of nsStyleSet is
-  // replicated for Servo here.
 
-  // Bug 1290276 will replicate the nsStyleSet work of checking
-  // a nsBindingManager
+  mDocument->BindingManager()->EnumerateBoundContentBindings(
+      [&](nsXBLBinding* aBinding) {
+        AutoTArray<StyleSheet*, 3> sheets;
+        aBinding->PrototypeBinding()->AppendStyleSheetsTo(sheets);
+        for (auto* sheet : sheets) {
+          queue.AppendElement(MakePair(sheet, SheetOwner { aBinding->PrototypeBinding() }));
+        }
+        return true;
+      });
 
+  bool anyXBLSheetChanged = false;
   while (!queue.IsEmpty()) {
     uint32_t idx = queue.Length() - 1;
-    StyleSheet* sheet = queue[idx];
+    auto* sheet = queue[idx].first();
+    SheetOwner owner = queue[idx].second();
     queue.RemoveElementAt(idx);
 
+    if (!sheet->HasUniqueInner() && owner.is<nsXBLPrototypeBinding*>()) {
+      if (auto* styles = owner.as<nsXBLPrototypeBinding*>()->GetServoStyles()) {
+        Servo_AuthorStyles_ForceDirty(styles);
+        mNeedsRestyleAfterEnsureUniqueInner = true;
+        anyXBLSheetChanged = true;
+      }
+    }
+
     // Only call EnsureUniqueInner for complete sheets. If we do call it on
     // incomplete sheets, we'll cause problems when the sheet is actually
     // loaded. We don't care about incomplete sheets here anyway, because this
     // method is only invoked by nsPresContext::EnsureSafeToHandOutCSSRules.
     // The CSSRule objects we are handing out won't contain any rules derived
     // from incomplete sheets (because they aren't yet applied in styling).
     if (sheet->IsComplete()) {
       sheet->EnsureUniqueInner();
     }
 
     // Enqueue all the sheet's children.
-    sheet->AppendAllChildSheets(queue);
+    AutoTArray<StyleSheet*, 3> children;
+    sheet->AppendAllChildSheets(children);
+    for (auto* sheet : children) {
+      queue.AppendElement(MakePair(sheet, owner));
+    }
+  }
+
+  if (anyXBLSheetChanged) {
+    SetStylistXBLStyleSheetsDirty();
   }
 
   if (mNeedsRestyleAfterEnsureUniqueInner) {
     // TODO(emilio): We could make this faster if needed tracking the specific
     // origins and all that, but the only caller of this doesn't seem to really
     // care about perf.
     MarkOriginsDirty(OriginFlags::All);
   }
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -396,33 +396,16 @@ StyleSheet::EnsureUniqueInner()
              "unexpected number of outers");
   mDirtyFlags |= FORCED_UNIQUE_INNER;
 
   if (HasUniqueInner()) {
     // already unique
     return;
   }
 
-  // If this stylesheet is for XBL with Servo, don't bother cloning
-  // it, as it may break ServoStyleRuleMap. XBL stylesheets are not
-  // supposed to change anyway.
-  //
-  // The mDocument check is used as a fast reject path because no
-  // XBL stylesheets would have associated document, but in normal
-  // cases, content stylesheets should usually have one.
-  //
-  // FIXME(emilio): Shadow DOM definitely modifies stylesheets! Right now all of
-  // them are unique anyway because we don't support <link>, but that needs to
-  // change.
-  if (!mDocument && IsServo() &&
-      mStyleSets.Length() == 1 &&
-      mStyleSets[0]->AsServo()->IsForXBL()) {
-    return;
-  }
-
   StyleSheetInfo* clone = mInner->CloneFor(this);
   MOZ_ASSERT(clone);
   mInner->RemoveSheet(this);
   mInner = clone;
 
   if (IsGecko()) {
 #ifdef MOZ_OLD_STYLE
     // Ensure we're using the new rules.
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -127,21 +127,30 @@ public:
   inline bool IsApplicable() const;
   inline bool HasRules() const;
 
   virtual already_AddRefed<StyleSheet> Clone(StyleSheet* aCloneParent,
                                              dom::CSSImportRule* aCloneOwnerRule,
                                              nsIDocument* aCloneDocument,
                                              nsINode* aCloneOwningNode) const = 0;
 
-  bool HasForcedUniqueInner() const { return mDirtyFlags &
-                                             FORCED_UNIQUE_INNER; }
-  bool HasModifiedRules() const { return mDirtyFlags &
-                                         MODIFIED_RULES; }
-  void ClearModifiedRules() { mDirtyFlags &= ~MODIFIED_RULES; }
+  bool HasForcedUniqueInner() const
+  {
+    return mDirtyFlags & FORCED_UNIQUE_INNER;
+  }
+
+  bool HasModifiedRules() const
+  {
+    return mDirtyFlags & MODIFIED_RULES;
+  }
+
+  void ClearModifiedRules()
+  {
+    mDirtyFlags &= ~MODIFIED_RULES;
+  }
 
   inline bool HasUniqueInner() const;
   void EnsureUniqueInner();
 
   // Append all of this sheet's child sheets to aArray.
   void AppendAllChildSheets(nsTArray<StyleSheet*>& aArray);
 
   // style sheet owner info
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1143,16 +1143,24 @@ pub unsafe extern "C" fn Servo_AuthorSty
 
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let sheet = GeckoStyleSheet::new(sheet);
     styles.stylesheets.append_stylesheet(None, sheet, &guard);
 }
 
 #[no_mangle]
+pub unsafe extern "C" fn Servo_AuthorStyles_ForceDirty(
+    styles: RawServoAuthorStylesBorrowedMut,
+) {
+    let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
+    styles.stylesheets.force_dirty();
+}
+
+#[no_mangle]
 pub unsafe extern "C" fn Servo_AuthorStyles_Flush(
     styles: RawServoAuthorStylesBorrowedMut,
     document_set: RawServoStyleSetBorrowed,
 ) {
     let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
     // Try to avoid the atomic borrow below if possible.
     if !styles.stylesheets.dirty() {
         return;