Bug 1382078 Part 3 - Support media changes for XBL stylesheets. draft
authorTing-Yu Lin <tlin@mozilla.com>
Wed, 30 Aug 2017 15:44:48 +0800
changeset 655595 bddb760a8d62497bae95e28945dec40e1e07aedb
parent 655582 8ba4b3db97265ca6d6f6b4b407cbd6160aeb8f66
child 728892 11a4605b967ddb84802b26469d911c73bfd9b673
push id76937
push userbmo:tlin@mozilla.com
push dateWed, 30 Aug 2017 08:06:13 +0000
bugs1382078
milestone57.0a1
Bug 1382078 Part 3 - Support media changes for XBL stylesheets. MozReview-Commit-ID: EJp8EMyanBT
dom/xbl/nsBindingManager.cpp
dom/xbl/nsBindingManager.h
dom/xbl/nsXBLPrototypeBinding.cpp
dom/xbl/nsXBLPrototypeBinding.h
dom/xbl/nsXBLPrototypeResources.cpp
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
layout/style/nsStyleSet.cpp
layout/style/test/mochitest.ini
--- a/dom/xbl/nsBindingManager.cpp
+++ b/dom/xbl/nsBindingManager.cpp
@@ -45,16 +45,17 @@
 
 #include "nsIScriptContext.h"
 #include "xpcpublic.h"
 #include "jswrapper.h"
 
 #include "nsThreadUtils.h"
 #include "mozilla/dom/NodeListBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/ServoStyleSet.h"
 #include "mozilla/Unused.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // Implement our nsISupports methods
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsBindingManager)
@@ -718,26 +719,52 @@ nsBindingManager::WalkAllRules(nsIStyleR
       aBinding->PrototypeBinding()->GetRuleProcessor();
     if (ruleProcessor) {
       (*(aFunc))(ruleProcessor, aData);
     }
   });
 }
 
 bool
-nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext)
+nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext,
+                                        bool aViewportChanged)
 {
   bool rulesChanged = false;
 
   EnumerateBoundContentBindings([=, &rulesChanged](nsXBLBinding* aBinding) {
-    nsIStyleRuleProcessor* ruleProcessor =
-      aBinding->PrototypeBinding()->GetRuleProcessor();
-    if (ruleProcessor) {
-      bool thisChanged = ruleProcessor->MediumFeaturesChanged(aPresContext);
-      rulesChanged = rulesChanged || thisChanged;
+    if (mDocument->IsStyledByServo()) {
+      nsXBLPrototypeBinding* protoBinding = aBinding->PrototypeBinding();
+      ServoStyleSet* styleSet = protoBinding->GetServoStyleSet();
+
+      if (styleSet) {
+        bool needToRecompute = false;
+        if (styleSet->IsPresContextChanged(aPresContext)) {
+          needToRecompute = true;
+        } else {
+          // PresContext is not changed. This means aPresContext is still
+          // alive since the last time it initialized this XBL styleset.
+          // It's safe to check whether medium features changed.
+          needToRecompute =
+            styleSet->MediumFeaturesChanged(aViewportChanged) != nsRestyleHint(0);
+        }
+
+        if (needToRecompute) {
+          // Recompute servo style set by using new PresContext.
+          protoBinding->ComputeServoStyleSet(aPresContext);
+        }
+
+        rulesChanged = rulesChanged || needToRecompute;
+      }
+    } else {
+      nsIStyleRuleProcessor* ruleProcessor =
+        aBinding->PrototypeBinding()->GetRuleProcessor();
+      if (ruleProcessor) {
+        bool thisChanged = ruleProcessor->MediumFeaturesChanged(aPresContext);
+        rulesChanged = rulesChanged || thisChanged;
+      }
     }
   });
 
   return rulesChanged;
 }
 
 void
 nsBindingManager::AppendAllSheets(nsTArray<StyleSheet*>& aArray)
--- a/dom/xbl/nsBindingManager.h
+++ b/dom/xbl/nsBindingManager.h
@@ -125,22 +125,23 @@ public:
 
   // Style rule methods
   nsresult WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc,
                      ElementDependentRuleProcessorData* aData,
                      bool* aCutOffInheritance);
 
   void WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc,
                     ElementDependentRuleProcessorData* aData);
-  /**
-   * Do any processing that needs to happen as a result of a change in
-   * the characteristics of the medium, and return whether this rule
-   * processor's rules have changed (e.g., because of media queries).
-   */
-  bool MediumFeaturesChanged(nsPresContext* aPresContext);
+
+  // Do any processing that needs to happen as a result of a change in the
+  // characteristics of the medium, and return whether this rule processor's
+  // rules or the servo style set have changed (e.g., because of media
+  // queries).
+  bool MediumFeaturesChanged(nsPresContext* aPresContext,
+                             bool aViewportChanged);
 
   void AppendAllSheets(nsTArray<mozilla::StyleSheet*>& aArray);
 
   void Traverse(nsIContent *aContent,
                             nsCycleCollectionTraversalCallback &cb);
 
   NS_DECL_CYCLE_COLLECTION_CLASS(nsBindingManager)
 
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -564,16 +564,24 @@ nsXBLPrototypeBinding::GetRuleProcessor(
 {
   if (mResources) {
     return mResources->GetRuleProcessor();
   }
 
   return nullptr;
 }
 
+void
+nsXBLPrototypeBinding::ComputeServoStyleSet(nsPresContext* aPresContext)
+{
+  if (mResources) {
+    mResources->ComputeServoStyleSet(aPresContext);
+  }
+}
+
 ServoStyleSet*
 nsXBLPrototypeBinding::GetServoStyleSet() const
 {
   return mResources ? mResources->GetServoStyleSet() : nullptr;
 }
 
 void
 nsXBLPrototypeBinding::EnsureAttributeTable()
--- a/dom/xbl/nsXBLPrototypeBinding.h
+++ b/dom/xbl/nsXBLPrototypeBinding.h
@@ -126,16 +126,17 @@ public:
   void RemoveStyleSheet(mozilla::StyleSheet* aSheet);
   void InsertStyleSheetAt(size_t aIndex, mozilla::StyleSheet* aSheet);
   mozilla::StyleSheet* StyleSheetAt(size_t aIndex) const;
   size_t SheetCount() const;
   bool HasStyleSheets() const;
   void AppendStyleSheetsTo(nsTArray<mozilla::StyleSheet*>& aResult) const;
 
   nsIStyleRuleProcessor* GetRuleProcessor();
+  void ComputeServoStyleSet(nsPresContext* aPresContext);
   mozilla::ServoStyleSet* GetServoStyleSet() const;
 
   nsresult FlushSkinSheets();
 
   nsIAtom* GetBaseTag(int32_t* aNamespaceID);
   void SetBaseTag(int32_t aNamespaceID, nsIAtom* aTag);
 
   bool ImplementsInterface(REFNSIID aIID) const;
--- a/dom/xbl/nsXBLPrototypeResources.cpp
+++ b/dom/xbl/nsXBLPrototypeResources.cpp
@@ -162,17 +162,19 @@ nsXBLPrototypeResources::GatherRuleProce
                                           SheetType::Doc,
                                           nullptr,
                                           mRuleProcessor);
 }
 
 void
 nsXBLPrototypeResources::ComputeServoStyleSet(nsPresContext* aPresContext)
 {
-  mServoStyleSet.reset(new ServoStyleSet());
+  if (!mServoStyleSet) {
+    mServoStyleSet.reset(new ServoStyleSet());
+  }
   mServoStyleSet->Init(aPresContext, nullptr);
   for (StyleSheet* sheet : mStyleSheetList) {
     MOZ_ASSERT(sheet->IsServo(),
                "This should only be called with Servo-flavored style backend!");
     // The XBL style sheets aren't document level sheets, but we need to
     // decide a particular SheetType to add them to style set. This type
     // doesn't affect the place where we pull those rules from
     // stylist::push_applicable_declarations_as_xbl_only_stylist().
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -103,16 +103,18 @@ ServoStyleSet::~ServoStyleSet()
     }
   }
 }
 
 void
 ServoStyleSet::Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager)
 {
   mPresContext = aPresContext;
+  mLastPresContext = aPresContext;
+
   mRawSet.reset(Servo_StyleSet_Init(aPresContext));
   mBindingManager = aBindingManager;
 
   mPresContext->DeviceContext()->InitFontCache();
 
   // Now that we have an mRawSet, go ahead and notify about whatever stylesheets
   // we have so far.
   for (auto& sheetArray : mSheets) {
@@ -170,16 +172,26 @@ ServoStyleSet::MediumFeaturesChanged(boo
   const OriginFlags rulesChanged = static_cast<OriginFlags>(
     Servo_StyleSet_MediumFeaturesChanged(mRawSet.get(), &viewportUnitsUsed));
 
   if (rulesChanged != OriginFlags(0)) {
     MarkOriginsDirty(rulesChanged);
     return eRestyle_Subtree;
   }
 
+  if (mBindingManager && mPresContext) {
+    // We are main style set. Call binding manager to check medium features
+    // change for content bindings.
+    bool bindingStylesChanged =
+      mBindingManager->MediumFeaturesChanged(mPresContext, aViewportChanged);
+    if (bindingStylesChanged) {
+      return eRestyle_Subtree;
+    }
+  }
+
   if (viewportUnitsUsed && aViewportChanged) {
     return eRestyle_ForceDescendants;
   }
 
   return nsRestyleHint(0);
 }
 
 size_t
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -424,16 +424,20 @@ public:
   // Returns the style rule map.
   ServoStyleRuleMap* StyleRuleMap();
 
   // Clear mPresContext. This is needed after XBL ServoStyleSet is created.
   void ClearPresContext() {
     mPresContext = nullptr;
   }
 
+  bool IsPresContextChanged(nsPresContext* aPresContext) const {
+    return aPresContext != mLastPresContext;
+  }
+
   /**
    * Returns true if a modification to an an attribute with the specified
    * local name might require us to restyle the element.
    *
    * This function allows us to skip taking a an attribute snapshot when
    * the modified attribute doesn't appear in an attribute selector in
    * a style sheet.
    */
@@ -550,17 +554,24 @@ private:
 
   void InsertSheetOfType(SheetType aType,
                          ServoStyleSheet* aSheet,
                          ServoStyleSheet* aBeforeSheet);
 
   void RemoveSheetOfType(SheetType aType,
                          ServoStyleSheet* aSheet);
 
-  nsPresContext* mPresContext;
+  // Nullptr if this is an XBL style set.
+  nsPresContext* MOZ_NON_OWNING_REF mPresContext = nullptr;
+
+  // Because XBL style set could be used by multiple PresContext, we need to
+  // store the last PresContext which initialize this style set for
+  // computing medium rule changes.
+  nsPresContext* MOZ_NON_OWNING_REF mLastPresContext = nullptr;
+
   UniquePtr<RawServoStyleSet> mRawSet;
   EnumeratedArray<SheetType, SheetType::Count,
                   nsTArray<RefPtr<ServoStyleSheet>>> mSheets;
   bool mAuthorStyleDisabled;
   StylistState mStylistState;
   uint64_t mUserFontSetUpdateGeneration;
   uint32_t mUserFontCacheUpdateGeneration;
 
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -2680,17 +2680,17 @@ nsStyleSet::MediumFeaturesChanged(bool a
   }
   for (nsIStyleRuleProcessor* processor : mScopedDocSheetRuleProcessors) {
     bool thisChanged = processor->MediumFeaturesChanged(presContext);
     stylesChanged = stylesChanged || thisChanged;
   }
 
   if (mBindingManager) {
     bool thisChanged =
-      mBindingManager->MediumFeaturesChanged(presContext);
+      mBindingManager->MediumFeaturesChanged(presContext, aViewportChanged);
     stylesChanged = stylesChanged || thisChanged;
   }
 
   if (stylesChanged) {
     return eRestyle_Subtree;
   }
   if (aViewportChanged && mUsesViewportUnits) {
     // Rebuild all style data without rerunning selector matching.
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -237,17 +237,16 @@ skip-if = !stylo
 [test_keyframes_rules.html]
 [test_keyframes_vendor_prefix.html]
 [test_load_events_on_stylesheets.html]
 [test_logical_properties.html]
 [test_media_queries.html]
 skip-if = android_version == '18' #debug-only failure; timed out #Android 4.3 aws only; bug 1030419
 [test_media_queries_dynamic.html]
 [test_media_queries_dynamic_xbl.html]
-fail-if = stylo # bug 1382078
 [test_media_query_list.html]
 [test_media_query_serialization.html]
 [test_moz_device_pixel_ratio.html]
 [test_namespace_rule.html]
 [test_of_type_selectors.xhtml]
 [test_page_parser.html]
 [test_parse_eof.html]
 [test_parse_ident.html]