Bug 1315601 part 10 - Make ServoCSSRuleList support being nested. r=heycam draft
authorXidorn Quan <me@upsuper.org>
Thu, 09 Mar 2017 20:53:34 +1100
changeset 497346 a51c88fd19cf85376a52b4c61b3bd84df6356dab
parent 497345 04cb9ea11e01a4f57497b4edf148adbd4fc1311b
child 497347 a1ecece1115d08e3c377d8eb1bcd8f7e34957dc2
push id48869
push userxquan@mozilla.com
push dateMon, 13 Mar 2017 06:50:23 +0000
reviewersheycam
bugs1315601
milestone55.0a1
Bug 1315601 part 10 - Make ServoCSSRuleList support being nested. r=heycam MozReview-Commit-ID: 8IUGxkMZPMj
layout/style/ServoCSSRuleList.cpp
layout/style/ServoCSSRuleList.h
layout/style/ServoStyleSheet.cpp
--- a/layout/style/ServoCSSRuleList.cpp
+++ b/layout/style/ServoCSSRuleList.cpp
@@ -8,20 +8,18 @@
 
 #include "mozilla/ServoCSSRuleList.h"
 
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoStyleRule.h"
 
 namespace mozilla {
 
-ServoCSSRuleList::ServoCSSRuleList(ServoStyleSheet* aStyleSheet,
-                                   already_AddRefed<ServoCssRules> aRawRules)
-  : mStyleSheet(aStyleSheet)
-  , mRawRules(aRawRules)
+ServoCSSRuleList::ServoCSSRuleList(already_AddRefed<ServoCssRules> aRawRules)
+  : mRawRules(aRawRules)
 {
   Servo_CssRules_ListTypes(mRawRules, &mRules);
   // XXX We may want to eagerly create object for import rule, so that
   //     we don't lose the reference to child stylesheet when our own
   //     stylesheet goes away.
 }
 
 // QueryInterface implementation for ServoCSSRuleList
@@ -29,35 +27,46 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
 NS_INTERFACE_MAP_END_INHERITING(dom::CSSRuleList)
 
 NS_IMPL_ADDREF_INHERITED(ServoCSSRuleList, dom::CSSRuleList)
 NS_IMPL_RELEASE_INHERITED(ServoCSSRuleList, dom::CSSRuleList)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(ServoCSSRuleList)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ServoCSSRuleList)
-  for (uintptr_t& rule : tmp->mRules) {
-    if (rule > kMaxRuleType) {
-      CastToPtr(rule)->Release();
-      // Safest to set it to zero, in case someone else pokes at it
-      // during their own unlinking process.
-      rule = 0;
-    }
-  }
+  tmp->DropAllRules();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(dom::CSSRuleList)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ServoCSSRuleList,
                                                   dom::CSSRuleList)
   tmp->EnumerateInstantiatedRules([&](css::Rule* aRule) {
     if (!aRule->IsCCLeaf()) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
       cb.NoteXPCOMChild(aRule);
     }
   });
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
+void
+ServoCSSRuleList::SetParentRule(css::GroupRule* aParentRule)
+{
+  mParentRule = aParentRule;
+  EnumerateInstantiatedRules([aParentRule](css::Rule* rule) {
+    rule->SetParentRule(aParentRule);
+  });
+}
+
+void
+ServoCSSRuleList::SetStyleSheet(StyleSheet* aStyleSheet)
+{
+  mStyleSheet = aStyleSheet ? aStyleSheet->AsServo() : nullptr;
+  EnumerateInstantiatedRules([aStyleSheet](css::Rule* rule) {
+    rule->SetStyleSheet(aStyleSheet);
+  });
+}
+
 css::Rule*
 ServoCSSRuleList::GetRule(uint32_t aIndex)
 {
   uintptr_t rule = mRules[aIndex];
   if (rule <= kMaxRuleType) {
     RefPtr<css::Rule> ruleObj = nullptr;
     switch (rule) {
       case nsIDOMCSSRule::STYLE_RULE: {
@@ -70,16 +79,17 @@ ServoCSSRuleList::GetRule(uint32_t aInde
       case nsIDOMCSSRule::KEYFRAMES_RULE:
       case nsIDOMCSSRule::NAMESPACE_RULE:
         // XXX create corresponding rules
       default:
         NS_WARNING("stylo: not implemented yet");
         return nullptr;
     }
     ruleObj->SetStyleSheet(mStyleSheet);
+    ruleObj->SetParentRule(mParentRule);
     rule = CastToUint(ruleObj.forget().take());
     mRules[aIndex] = rule;
   }
   return CastToPtr(rule);
 }
 
 css::Rule*
 ServoCSSRuleList::IndexedGetter(uint32_t aIndex, bool& aFound)
@@ -98,53 +108,67 @@ ServoCSSRuleList::EnumerateInstantiatedR
 {
   for (uintptr_t rule : mRules) {
     if (rule > kMaxRuleType) {
       aCallback(CastToPtr(rule));
     }
   }
 }
 
+static void
+DropRule(already_AddRefed<css::Rule> aRule)
+{
+  RefPtr<css::Rule> rule = aRule;
+  rule->SetStyleSheet(nullptr);
+  rule->SetParentRule(nullptr);
+}
+
+void
+ServoCSSRuleList::DropAllRules()
+{
+  EnumerateInstantiatedRules([](css::Rule* rule) {
+    DropRule(already_AddRefed<css::Rule>(rule));
+  });
+  mRules.Clear();
+}
+
 void
 ServoCSSRuleList::DropReference()
 {
   mStyleSheet = nullptr;
-  EnumerateInstantiatedRules([](css::Rule* rule) {
-    rule->SetStyleSheet(nullptr);
-  });
+  mParentRule = nullptr;
+  DropAllRules();
 }
 
 nsresult
 ServoCSSRuleList::InsertRule(const nsAString& aRule, uint32_t aIndex)
 {
   NS_ConvertUTF16toUTF8 rule(aRule);
-  // XXX This needs to actually reflect whether it is nested when we
-  // support using CSSRuleList in CSSGroupingRules.
-  bool nested = false;
+  bool nested = !!mParentRule;
   uint16_t type;
   nsresult rv = Servo_CssRules_InsertRule(mRawRules, mStyleSheet->RawSheet(),
                                           &rule, aIndex, nested, &type);
   if (!NS_FAILED(rv)) {
     mRules.InsertElementAt(aIndex, type);
   }
   return rv;
 }
 
 nsresult
 ServoCSSRuleList::DeleteRule(uint32_t aIndex)
 {
   nsresult rv = Servo_CssRules_DeleteRule(mRawRules, aIndex);
   if (!NS_FAILED(rv)) {
     uintptr_t rule = mRules[aIndex];
     if (rule > kMaxRuleType) {
-      CastToPtr(rule)->Release();
+      DropRule(already_AddRefed<css::Rule>(CastToPtr(rule)));
     }
     mRules.RemoveElementAt(aIndex);
   }
   return rv;
 }
 
 ServoCSSRuleList::~ServoCSSRuleList()
 {
-  EnumerateInstantiatedRules([](css::Rule* rule) { rule->Release(); });
+  DropAllRules();
 }
 
 } // namespace mozilla
--- a/layout/style/ServoCSSRuleList.h
+++ b/layout/style/ServoCSSRuleList.h
@@ -11,24 +11,26 @@
 
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/dom/CSSRuleList.h"
 
 namespace mozilla {
 
 class ServoStyleSheet;
 namespace css {
+class GroupRule;
 class Rule;
 } // namespace css
 
 class ServoCSSRuleList final : public dom::CSSRuleList
 {
 public:
-  ServoCSSRuleList(ServoStyleSheet* aStyleSheet,
-                   already_AddRefed<ServoCssRules> aRawRules);
+  explicit ServoCSSRuleList(already_AddRefed<ServoCssRules> aRawRules);
+  void SetParentRule(css::GroupRule* aParentRule);
+  void SetStyleSheet(StyleSheet* aSheet);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServoCSSRuleList, dom::CSSRuleList)
 
   ServoStyleSheet* GetParentObject() final { return mStyleSheet; }
 
   css::Rule* IndexedGetter(uint32_t aIndex, bool& aFound) final;
   uint32_t Length() final { return mRules.Length(); }
@@ -52,18 +54,22 @@ private:
   static css::Rule* CastToPtr(uintptr_t aInt) {
     MOZ_ASSERT(aInt > kMaxRuleType);
     return reinterpret_cast<css::Rule*>(aInt);
   }
 
   template<typename Func>
   void EnumerateInstantiatedRules(Func aCallback);
 
+  void DropAllRules();
+
   // mStyleSheet may be nullptr when it drops the reference to us.
-  ServoStyleSheet* mStyleSheet;
+  ServoStyleSheet* mStyleSheet = nullptr;
+  // mParentRule is nullptr if it isn't a nested rule list.
+  css::GroupRule* mParentRule = nullptr;
   RefPtr<ServoCssRules> mRawRules;
   // Array stores either a number indicating rule type, or a pointer to
   // css::Rule. If the value is less than kMaxRuleType, the given rule
   // instance has not been constructed, and the value means the type
   // of the rule. Otherwise, it is a pointer.
   nsTArray<uintptr_t> mRules;
 };
 
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -146,17 +146,18 @@ ServoStyleSheet::Clone(StyleSheet* aClon
 }
 
 CSSRuleList*
 ServoStyleSheet::GetCssRulesInternal(ErrorResult& aRv)
 {
   if (!mRuleList) {
     RefPtr<ServoCssRules> rawRules =
       Servo_StyleSheet_GetRules(Inner()->mSheet).Consume();
-    mRuleList = new ServoCSSRuleList(this, rawRules.forget());
+    mRuleList = new ServoCSSRuleList(rawRules.forget());
+    mRuleList->SetStyleSheet(this);
   }
   return mRuleList;
 }
 
 uint32_t
 ServoStyleSheet::InsertRuleInternal(const nsAString& aRule,
                                     uint32_t aIndex, ErrorResult& aRv)
 {