Bug 1307357 part 6 - Implement CSSStyleRule.style. r?heycam draft
authorXidorn Quan <me@upsuper.org>
Mon, 07 Nov 2016 17:19:38 +1100
changeset 441111 8ba19b8ec4ad81c7a58821335cc31953640dced2
parent 441110 6ed9999655f03ae101eb4524c4c2ff14960b93f1
child 441112 59ccfb1e50dd74f3fbda6ebd0c87da4c0ece6409
push id36360
push userxquan@mozilla.com
push dateFri, 18 Nov 2016 12:08:30 +0000
reviewersheycam
bugs1307357
milestone53.0a1
Bug 1307357 part 6 - Implement CSSStyleRule.style. r?heycam MozReview-Commit-ID: 8Qvzc74wveE
layout/style/ServoBindingList.h
layout/style/ServoDeclarationBlock.h
layout/style/ServoStyleRule.cpp
layout/style/ServoStyleRule.h
servo/components/style/gecko_bindings/bindings.rs
servo/ports/geckolib/glue.rs
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -54,16 +54,21 @@ SERVO_BINDING_FUNC(Servo_StyleSet_Insert
 // CSSRuleList
 SERVO_BINDING_FUNC(Servo_CssRules_ListTypes, void,
                    ServoCssRulesBorrowed rules,
                    nsTArrayBorrowed_uintptr_t result)
 SERVO_BINDING_FUNC(Servo_CssRules_GetStyleRuleAt, RawServoStyleRuleStrong,
                    ServoCssRulesBorrowed rules, uint32_t index)
 
 // CSS Rules
+SERVO_BINDING_FUNC(Servo_StyleRule_GetStyle, RawServoDeclarationBlockStrong,
+                   RawServoStyleRuleBorrowed rule)
+SERVO_BINDING_FUNC(Servo_StyleRule_SetStyle, void,
+                   RawServoStyleRuleBorrowed rule,
+                   RawServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_StyleRule_GetCssText, void,
                    RawServoStyleRuleBorrowed rule, nsAString* result)
 SERVO_BINDING_FUNC(Servo_StyleRule_GetSelectorText, void,
                    RawServoStyleRuleBorrowed rule, nsAString* result)
 
 // Animations API
 SERVO_BINDING_FUNC(Servo_ParseProperty,
                    RawServoDeclarationBlockStrong,
--- a/layout/style/ServoDeclarationBlock.h
+++ b/layout/style/ServoDeclarationBlock.h
@@ -9,16 +9,20 @@
 #include "mozilla/ServoBindings.h"
 #include "mozilla/DeclarationBlock.h"
 
 namespace mozilla {
 
 class ServoDeclarationBlock final : public DeclarationBlock
 {
 public:
+  explicit ServoDeclarationBlock(
+    already_AddRefed<RawServoDeclarationBlock> aRaw)
+    : DeclarationBlock(StyleBackendType::Servo), mRaw(aRaw) {}
+
   ServoDeclarationBlock()
     : ServoDeclarationBlock(Servo_DeclarationBlock_CreateEmpty().Consume()) {}
 
   ServoDeclarationBlock(const ServoDeclarationBlock& aCopy)
     : DeclarationBlock(aCopy)
     , mRaw(Servo_DeclarationBlock_Clone(aCopy.mRaw).Consume()) {}
 
   NS_INLINE_DECL_REFCOUNTING(ServoDeclarationBlock)
@@ -51,21 +55,16 @@ public:
   void GetAuthoredPropertyValue(const nsAString& aProperty,
                                 nsAString& aValue) const {
     GetPropertyValue(aProperty, aValue);
   }
   bool GetPropertyIsImportant(const nsAString& aProperty) const;
   void RemoveProperty(const nsAString& aProperty);
   void RemovePropertyByID(nsCSSPropertyID aPropID);
 
-protected:
-  explicit ServoDeclarationBlock(
-    already_AddRefed<RawServoDeclarationBlock> aRaw)
-    : DeclarationBlock(StyleBackendType::Servo), mRaw(aRaw) {}
-
 private:
   ~ServoDeclarationBlock() {}
 
   RefPtr<RawServoDeclarationBlock> mRaw;
 };
 
 } // namespace mozilla
 
--- a/layout/style/ServoStyleRule.cpp
+++ b/layout/style/ServoStyleRule.cpp
@@ -4,33 +4,145 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* representation of CSSStyleRule for stylo */
 
 #include "mozilla/ServoStyleRule.h"
 
 #include "mozilla/ServoBindings.h"
+#include "mozilla/ServoDeclarationBlock.h"
 
 #include "nsDOMClassInfoID.h"
+#include "mozAutoDocUpdate.h"
 
 namespace mozilla {
 
+// -- ServoStyleRuleDeclaration ---------------------------------------
+
+ServoStyleRuleDeclaration::ServoStyleRuleDeclaration(
+  already_AddRefed<RawServoDeclarationBlock> aDecls)
+  : mDecls(new ServoDeclarationBlock(Move(aDecls)))
+{
+}
+
+ServoStyleRuleDeclaration::~ServoStyleRuleDeclaration()
+{
+}
+
+// QueryInterface implementation for ServoStyleRuleDeclaration
+NS_INTERFACE_MAP_BEGIN(ServoStyleRuleDeclaration)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  // We forward the cycle collection interfaces to Rule(), which is
+  // never null (in fact, we're part of that object!)
+  if (aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ||
+      aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant))) {
+    return Rule()->QueryInterface(aIID, aInstancePtr);
+  }
+  else
+NS_IMPL_QUERY_TAIL_INHERITING(nsDOMCSSDeclaration)
+
+NS_IMPL_ADDREF_USING_AGGREGATOR(ServoStyleRuleDeclaration, Rule())
+NS_IMPL_RELEASE_USING_AGGREGATOR(ServoStyleRuleDeclaration, Rule())
+
+/* nsDOMCSSDeclaration implementation */
+
+NS_IMETHODIMP
+ServoStyleRuleDeclaration::GetParentRule(nsIDOMCSSRule** aParent)
+{
+  *aParent = do_AddRef(Rule()).take();
+  return NS_OK;
+}
+
+nsINode*
+ServoStyleRuleDeclaration::GetParentObject()
+{
+  return Rule()->GetDocument();
+}
+
+DeclarationBlock*
+ServoStyleRuleDeclaration::GetCSSDeclaration(Operation aOperation)
+{
+  return mDecls;
+}
+
+nsresult
+ServoStyleRuleDeclaration::SetCSSDeclaration(DeclarationBlock* aDecl)
+{
+  ServoStyleRule* rule = Rule();
+  if (RefPtr<ServoStyleSheet> sheet = rule->GetStyleSheet()->AsServo()) {
+    nsCOMPtr<nsIDocument> owningDoc = sheet->GetOwningDocument();
+    mozAutoDocUpdate updateBatch(owningDoc, UPDATE_STYLE, true);
+    if (aDecl != mDecls) {
+      RefPtr<ServoDeclarationBlock> decls = aDecl->AsServo();
+      Servo_StyleRule_SetStyle(rule->Raw(), decls->Raw());
+      mDecls = decls.forget();
+    }
+    if (owningDoc) {
+      owningDoc->StyleRuleChanged(sheet, rule);
+    }
+  }
+  return NS_OK;
+}
+
+nsIDocument*
+ServoStyleRuleDeclaration::DocToUpdate()
+{
+  return nullptr;
+}
+
+void
+ServoStyleRuleDeclaration::GetCSSParsingEnvironment(
+  CSSParsingEnvironment& aCSSParseEnv)
+{
+  GetCSSParsingEnvironmentForRule(Rule(), aCSSParseEnv);
+}
+
 // -- ServoStyleRule --------------------------------------------------
 
+ServoStyleRule::ServoStyleRule(already_AddRefed<RawServoStyleRule> aRawRule)
+  : css::Rule(0, 0)
+  , mRawRule(aRawRule)
+  , mDecls(Servo_StyleRule_GetStyle(mRawRule).Consume())
+{
+}
+
 // QueryInterface implementation for ServoStyleRule
-NS_INTERFACE_MAP_BEGIN(ServoStyleRule)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServoStyleRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, css::Rule)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleRule)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_ADDREF(ServoStyleRule)
-NS_IMPL_RELEASE(ServoStyleRule)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(ServoStyleRule)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(ServoStyleRule)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(ServoStyleRule)
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ServoStyleRule)
+  // Trace the wrapper for our declaration.  This just expands out
+  // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
+  // directly because the wrapper is on the declaration, not on us.
+  tmp->mDecls.TraceWrapper(aCallbacks, aClosure);
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ServoStyleRule)
+  // Unlink the wrapper for our declaraton.  This just expands out
+  // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use
+  // directly because the wrapper is on the declaration, not on us.
+  tmp->mDecls.ReleaseWrapper(static_cast<nsISupports*>(p));
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ServoStyleRule)
+  // Just NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS here: that will call
+  // into our Trace hook, where we do the right thing with declarations
+  // already.
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 already_AddRefed<css::Rule>
 ServoStyleRule::Clone() const
 {
   // Rule::Clone is only used when CSSStyleSheetInner is cloned in
   // preparation of being mutated. However, ServoStyleSheet never clones
   // anything, so this method should never be called.
   MOZ_ASSERT_UNREACHABLE("Shouldn't be cloning ServoStyleRule");
@@ -109,13 +221,13 @@ ServoStyleRule::SetSelectorText(const ns
   //     so it's probably okay to leave it unimplemented currently?
   //     See bug 37468 and mozilla::css::StyleRule::SetSelectorText.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ServoStyleRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
 {
-  *aStyle = nullptr;
-  return NS_ERROR_NOT_IMPLEMENTED;
+  *aStyle = do_AddRef(&mDecls).take();
+  return NS_OK;
 }
 
 } // namespace mozilla
--- a/layout/style/ServoStyleRule.h
+++ b/layout/style/ServoStyleRule.h
@@ -8,43 +8,85 @@
 
 #ifndef mozilla_ServoStyleRule_h
 #define mozilla_ServoStyleRule_h
 
 #include "mozilla/css/Rule.h"
 #include "mozilla/ServoBindingTypes.h"
 
 #include "nsIDOMCSSStyleRule.h"
+#include "nsDOMCSSDeclaration.h"
 
 namespace mozilla {
 
+class ServoDeclarationBlock;
+
+class ServoStyleRuleDeclaration final : public nsDOMCSSDeclaration
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  NS_IMETHOD GetParentRule(nsIDOMCSSRule** aParent) final;
+  nsINode* GetParentObject() final;
+
+protected:
+  DeclarationBlock* GetCSSDeclaration(Operation aOperation) final;
+  nsresult SetCSSDeclaration(DeclarationBlock* aDecl) final;
+  nsIDocument* DocToUpdate() final;
+  void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) final;
+
+private:
+  // For accessing the constructor.
+  friend class ServoStyleRule;
+
+  explicit ServoStyleRuleDeclaration(
+    already_AddRefed<RawServoDeclarationBlock> aDecls);
+  ~ServoStyleRuleDeclaration();
+
+  inline ServoStyleRule* Rule();
+
+  RefPtr<ServoDeclarationBlock> mDecls;
+};
+
 class ServoStyleRule final : public css::Rule
                            , public nsIDOMCSSStyleRule
 {
 public:
-  explicit ServoStyleRule(already_AddRefed<RawServoStyleRule> aRawRule)
-    : css::Rule(0, 0)
-    , mRawRule(aRawRule)
-  {}
+  explicit ServoStyleRule(already_AddRefed<RawServoStyleRule> aRawRule);
 
-  NS_DECL_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(ServoStyleRule,
+                                                         css::Rule)
   NS_DECL_NSIDOMCSSRULE
   NS_DECL_NSIDOMCSSSTYLERULE
 
+  RawServoStyleRule* Raw() const { return mRawRule; }
+
   // Methods of mozilla::css::Rule
   int32_t GetType() const final { return css::Rule::STYLE_RULE; }
   already_AddRefed<Rule> Clone() const final;
   nsIDOMCSSRule* GetDOMRule() final { return this; }
   nsIDOMCSSRule* GetExistingDOMRule() final { return this; }
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const final;
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const final;
 #endif
 
 private:
   ~ServoStyleRule() {}
 
+  // For computing the offset of mDecls.
+  friend class ServoStyleRuleDeclaration;
+
   RefPtr<RawServoStyleRule> mRawRule;
+  ServoStyleRuleDeclaration mDecls;
 };
 
+ServoStyleRule*
+ServoStyleRuleDeclaration::Rule()
+{
+  return reinterpret_cast<ServoStyleRule*>(reinterpret_cast<uint8_t*>(this) -
+                                           offsetof(ServoStyleRule, mDecls));
+}
+
 } // namespace mozilla
 
 #endif // mozilla_ServoStyleRule_h
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -990,16 +990,25 @@ extern "C" {
                                                  reference:
                                                      RawServoStyleSheetBorrowed);
 }
 extern "C" {
     pub fn Servo_CssRules_ListRuleTypes(rules: ServoCssRulesBorrowed,
                                         result: nsTArrayBorrowed_uintptr_t);
 }
 extern "C" {
+    pub fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed)
+     -> RawServoDeclarationBlockStrong;
+}
+extern "C" {
+    pub fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed,
+                                    declarations:
+                                        RawServoDeclarationBlockBorrowed);
+}
+extern "C" {
     pub fn Servo_StyleRule_GetCssText(rule: RawServoStyleRuleBorrowed,
                                       result: *mut nsAString_internal);
 }
 extern "C" {
     pub fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed,
                                            result: *mut nsAString_internal);
 }
 extern "C" {
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -315,16 +315,30 @@ pub extern "C" fn Servo_StyleRule_AddRef
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleRule_Release(rule: RawServoStyleRuleBorrowed) -> () {
     unsafe { RwLock::<StyleRule>::release(rule) };
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed) -> RawServoDeclarationBlockStrong {
+    let rule = RwLock::<StyleRule>::as_arc(&rule);
+    rule.read().block.clone().into_strong()
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed,
+                                           declarations: RawServoDeclarationBlockBorrowed) -> () {
+    let rule = RwLock::<StyleRule>::as_arc(&rule);
+    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    rule.write().block = declarations.clone();
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_StyleRule_GetCssText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) -> () {
     let rule = RwLock::<StyleRule>::as_arc(&rule);
     rule.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap();
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) -> () {
     let rule = RwLock::<StyleRule>::as_arc(&rule);