Bug 1294299 part 11 - Implement getting and removing property. r?heycam,SimonSapin draft
authorXidorn Quan <me@upsuper.org>
Mon, 24 Oct 2016 17:47:58 +1100
changeset 429044 c9673d5bfc8469a52b8cc833bf3d9265c45a2a03
parent 429043 381e3d61ff2af9c1514495b5e4b0465b94d4721b
child 429045 a4b1a41a4fab66a5b561769c090bdef359815e94
push id33478
push userxquan@mozilla.com
push dateTue, 25 Oct 2016 03:59:31 +0000
reviewersheycam, SimonSapin
bugs1294299
milestone52.0a1
Bug 1294299 part 11 - Implement getting and removing property. r?heycam,SimonSapin MozReview-Commit-ID: 4xvfXR8mkfN
layout/style/DeclarationBlock.h
layout/style/DeclarationBlockInlines.h
layout/style/ServoBindingList.h
layout/style/ServoDeclarationBlock.cpp
layout/style/ServoDeclarationBlock.h
layout/style/nsDOMCSSDeclaration.cpp
servo/components/style/gecko_bindings/bindings.rs
servo/ports/geckolib/glue.rs
--- a/layout/style/DeclarationBlock.h
+++ b/layout/style/DeclarationBlock.h
@@ -10,16 +10,18 @@
  */
 
 #ifndef mozilla_DeclarationBlock_h
 #define mozilla_DeclarationBlock_h
 
 #include "mozilla/ServoUtils.h"
 #include "mozilla/StyleBackendType.h"
 
+#include "nsCSSPropertyID.h"
+
 class nsHTMLCSSStyleSheet;
 
 namespace mozilla {
 
 class ServoDeclarationBlock;
 
 namespace css {
 class Declaration;
@@ -99,16 +101,26 @@ public:
     return c.mHTMLCSSStyleSheet;
   }
 
   inline void ToString(nsAString& aString) const;
 
   inline uint32_t Count() const;
   inline bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const;
 
+  inline void GetPropertyValue(const nsAString& aProperty,
+                               nsAString& aValue) const;
+  inline void GetPropertyValueById(nsCSSPropertyID aPropID,
+                                   nsAString& aValue) const;
+  inline void GetAuthoredPropertyValue(const nsAString& aProperty,
+                                       nsAString& aValue) const;
+  inline bool GetPropertyIsImportant(const nsAString& aProperty) const;
+  inline void RemoveProperty(const nsAString& aProperty);
+  inline void RemovePropertyById(nsCSSPropertyID aProperty);
+
 private:
   union {
     // We only ever have one of these since we have an
     // nsHTMLCSSStyleSheet only for style attributes, and style
     // attributes never have an owning rule.
 
     // It's an nsHTMLCSSStyleSheet if the low bit is set.
 
--- a/layout/style/DeclarationBlockInlines.h
+++ b/layout/style/DeclarationBlockInlines.h
@@ -65,11 +65,50 @@ DeclarationBlock::Count() const
 }
 
 bool
 DeclarationBlock::GetNthProperty(uint32_t aIndex, nsAString& aReturn) const
 {
   MOZ_STYLO_FORWARD(GetNthProperty, (aIndex, aReturn))
 }
 
+void
+DeclarationBlock::GetPropertyValue(const nsAString& aProperty,
+                                   nsAString& aValue) const
+{
+  MOZ_STYLO_FORWARD(GetPropertyValue, (aProperty, aValue))
+}
+
+void
+DeclarationBlock::GetPropertyValueById(nsCSSPropertyID aPropID,
+                                       nsAString& aValue) const
+{
+  MOZ_STYLO_FORWARD(GetPropertyValueById, (aPropID, aValue))
+}
+
+void
+DeclarationBlock::GetAuthoredPropertyValue(const nsAString& aProperty,
+                                           nsAString& aValue) const
+{
+  MOZ_STYLO_FORWARD(GetAuthoredPropertyValue, (aProperty, aValue))
+}
+
+bool
+DeclarationBlock::GetPropertyIsImportant(const nsAString& aProperty) const
+{
+  MOZ_STYLO_FORWARD(GetPropertyIsImportant, (aProperty))
+}
+
+void
+DeclarationBlock::RemoveProperty(const nsAString& aProperty)
+{
+  MOZ_STYLO_FORWARD(RemoveProperty, (aProperty))
+}
+
+void
+DeclarationBlock::RemovePropertyById(nsCSSPropertyID aProperty)
+{
+  MOZ_STYLO_FORWARD(RemovePropertyById, (aProperty))
+}
+
 } // namespace mozilla
 
 #endif // mozilla_DeclarationBlockInlines_h
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -79,16 +79,25 @@ SERVO_BINDING_FUNC(Servo_DeclarationBloc
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_SerializeOneValue, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsString* buffer)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_Count, uint32_t,
                    RawServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetNthProperty, bool,
                    RawServoDeclarationBlockBorrowed declarations,
                    uint32_t index, nsAString* result)
+SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetPropertyValue, void,
+                   RawServoDeclarationBlockBorrowed declarations,
+                   nsIAtom* property, bool is_custom, nsAString* value)
+SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetPropertyIsImportant, bool,
+                   RawServoDeclarationBlockBorrowed declarations,
+                   nsIAtom* property, bool is_custom)
+SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemoveProperty, void,
+                   RawServoDeclarationBlockBorrowed declarations,
+                   nsIAtom* property, bool is_custom)
 
 // CSS supports()
 SERVO_BINDING_FUNC(Servo_CSSSupports, bool,
                    const nsACString* name, const nsACString* value)
 
 // Computed style data
 SERVO_BINDING_FUNC(Servo_ComputedValues_Get, ServoComputedValuesStrong,
                    RawGeckoNodeBorrowed node)
--- a/layout/style/ServoDeclarationBlock.cpp
+++ b/layout/style/ServoDeclarationBlock.cpp
@@ -2,21 +2,109 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "mozilla/ServoDeclarationBlock.h"
 
 #include "mozilla/ServoBindings.h"
 
+#include "nsCSSProps.h"
+
 namespace mozilla {
 
 /* static */ already_AddRefed<ServoDeclarationBlock>
 ServoDeclarationBlock::FromCssText(const nsAString& aCssText)
 {
   NS_ConvertUTF16toUTF8 value(aCssText);
   RefPtr<RawServoDeclarationBlock>
     raw = Servo_ParseStyleAttribute(&value).Consume();
   RefPtr<ServoDeclarationBlock> decl = new ServoDeclarationBlock(raw.forget());
   return decl.forget();
 }
 
+/**
+ * An RAII class holding an atom for the given property.
+ */
+class MOZ_STACK_CLASS PropertyAtomHolder
+{
+public:
+  explicit PropertyAtomHolder(const nsAString& aProperty)
+  {
+    nsCSSPropertyID propID =
+      nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eForAllContent);
+    if (propID == eCSSPropertyExtra_variable) {
+      mIsCustomProperty = true;
+      mAtom = NS_Atomize(
+        Substring(aProperty, CSS_CUSTOM_NAME_PREFIX_LENGTH)).take();
+    } else {
+      mIsCustomProperty = false;
+      if (propID != eCSSProperty_UNKNOWN) {
+        mAtom = nsCSSProps::AtomForProperty(propID);
+      } else {
+        mAtom = nullptr;
+      }
+    }
+  }
+
+  ~PropertyAtomHolder()
+  {
+    if (mIsCustomProperty) {
+      NS_RELEASE(mAtom);
+    }
+  }
+
+  explicit operator bool() const { return !!mAtom; }
+  nsIAtom* Atom() const { return mAtom; }
+  bool IsCustomProperty() const { return mIsCustomProperty; }
+
+private:
+  nsIAtom* mAtom;
+  bool mIsCustomProperty;
+};
+
+void
+ServoDeclarationBlock::GetPropertyValue(const nsAString& aProperty,
+                                        nsAString& aValue) const
+{
+  if (PropertyAtomHolder holder{aProperty}) {
+    Servo_DeclarationBlock_GetPropertyValue(
+      mRaw, holder.Atom(), holder.IsCustomProperty(), &aValue);
+  }
+}
+
+void
+ServoDeclarationBlock::GetPropertyValueById(nsCSSPropertyID aPropID,
+                                            nsAString& aValue) const
+{
+  nsIAtom* atom = nsCSSProps::AtomForProperty(aPropID);
+  Servo_DeclarationBlock_GetPropertyValue(mRaw, atom, false, &aValue);
+}
+
+bool
+ServoDeclarationBlock::GetPropertyIsImportant(const nsAString& aProperty) const
+{
+  if (PropertyAtomHolder holder{aProperty}) {
+    return Servo_DeclarationBlock_GetPropertyIsImportant(
+      mRaw, holder.Atom(), holder.IsCustomProperty());
+  }
+  return false;
+}
+
+void
+ServoDeclarationBlock::RemoveProperty(const nsAString& aProperty)
+{
+  AssertMutable();
+  if (PropertyAtomHolder holder{aProperty}) {
+    Servo_DeclarationBlock_RemoveProperty(mRaw, holder.Atom(),
+                                          holder.IsCustomProperty());
+  }
+}
+
+void
+ServoDeclarationBlock::RemovePropertyById(nsCSSPropertyID aPropID)
+{
+  AssertMutable();
+  nsIAtom* atom = nsCSSProps::AtomForProperty(aPropID);
+  Servo_DeclarationBlock_RemoveProperty(mRaw, atom, false);
+}
+
 } // namespace mozilla
--- a/layout/style/ServoDeclarationBlock.h
+++ b/layout/style/ServoDeclarationBlock.h
@@ -40,16 +40,26 @@ public:
   uint32_t Count() const {
     return Servo_DeclarationBlock_Count(mRaw);
   }
   bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const {
     aReturn.Truncate();
     return Servo_DeclarationBlock_GetNthProperty(mRaw, aIndex, &aReturn);
   }
 
+  void GetPropertyValue(const nsAString& aProperty, nsAString& aValue) const;
+  void GetPropertyValueById(nsCSSPropertyID aPropID, nsAString& aValue) const;
+  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() {}
 
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -44,17 +44,17 @@ NS_INTERFACE_MAP_END
 NS_IMETHODIMP
 nsDOMCSSDeclaration::GetPropertyValue(const nsCSSPropertyID aPropID,
                                       nsAString& aValue)
 {
   NS_PRECONDITION(aPropID != eCSSProperty_UNKNOWN,
                   "Should never pass eCSSProperty_UNKNOWN around");
 
   aValue.Truncate();
-  if (css::Declaration* decl = GetCSSDeclaration(eOperation_Read)->AsGecko()) {
+  if (DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read)) {
     decl->GetPropertyValueById(aPropID, aValue);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMCSSDeclaration::SetPropertyValue(const nsCSSPropertyID aPropID,
                                       const nsAString& aValue)
@@ -178,37 +178,37 @@ nsDOMCSSDeclaration::IndexedGetter(uint3
   aFound = decl && decl->GetNthProperty(aIndex, aPropName);
 }
 
 NS_IMETHODIMP
 nsDOMCSSDeclaration::GetPropertyValue(const nsAString& aPropertyName,
                                       nsAString& aReturn)
 {
   aReturn.Truncate();
-  if (css::Declaration* decl = GetCSSDeclaration(eOperation_Read)->AsGecko()) {
+  if (DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read)) {
     decl->GetPropertyValue(aPropertyName, aReturn);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMCSSDeclaration::GetAuthoredPropertyValue(const nsAString& aPropertyName,
                                               nsAString& aReturn)
 {
-  if (css::Declaration* decl = GetCSSDeclaration(eOperation_Read)->AsGecko()) {
+  if (DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read)) {
     decl->GetAuthoredPropertyValue(aPropertyName, aReturn);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMCSSDeclaration::GetPropertyPriority(const nsAString& aPropertyName,
                                          nsAString& aReturn)
 {
-  css::Declaration* decl = GetCSSDeclaration(eOperation_Read)->AsGecko();
+  DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read);
 
   aReturn.Truncate();
   if (decl && decl->GetPropertyIsImportant(aPropertyName)) {
     aReturn.AssignLiteral("important");
   }
 
   return NS_OK;
 }
@@ -363,17 +363,17 @@ nsDOMCSSDeclaration::RemovePropertyInter
   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   // Attribute setting code, which leads in turn to BeginUpdate.  We
   // need to start the update now so that the old rule doesn't get used
   // between when we mutate the declaration and when we set the new
   // rule (see stack in bug 209575).
   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
 
   RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
-  decl->AsGecko()->RemovePropertyById(aPropID);
+  decl->RemovePropertyById(aPropID);
   return SetCSSDeclaration(decl);
 }
 
 nsresult
 nsDOMCSSDeclaration::RemovePropertyInternal(const nsAString& aPropertyName)
 {
   DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_RemoveProperty);
   if (!olddecl) {
@@ -383,11 +383,11 @@ nsDOMCSSDeclaration::RemovePropertyInter
   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   // Attribute setting code, which leads in turn to BeginUpdate.  We
   // need to start the update now so that the old rule doesn't get used
   // between when we mutate the declaration and when we set the new
   // rule (see stack in bug 209575).
   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
 
   RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
-  decl->AsGecko()->RemoveProperty(aPropertyName);
+  decl->RemoveProperty(aPropertyName);
   return SetCSSDeclaration(decl);
 }
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -924,16 +924,38 @@ extern "C" {
     pub fn Servo_DeclarationBlock_GetNthProperty(declarations:
                                                      RawServoDeclarationBlockBorrowed,
                                                  index: u32,
                                                  result:
                                                      *mut nsAString_internal)
      -> bool;
 }
 extern "C" {
+    pub fn Servo_DeclarationBlock_GetPropertyValue(declarations:
+                                                       RawServoDeclarationBlockBorrowed,
+                                                   property: *mut nsIAtom,
+                                                   is_custom: bool,
+                                                   value:
+                                                       *mut nsAString_internal);
+}
+extern "C" {
+    pub fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations:
+                                                             RawServoDeclarationBlockBorrowed,
+                                                         property:
+                                                             *mut nsIAtom,
+                                                         is_custom: bool)
+     -> bool;
+}
+extern "C" {
+    pub fn Servo_DeclarationBlock_RemoveProperty(declarations:
+                                                     RawServoDeclarationBlockBorrowed,
+                                                 property: *mut nsIAtom,
+                                                 is_custom: bool);
+}
+extern "C" {
     pub fn Servo_CSSSupports(name: *const nsACString_internal,
                              value: *const nsACString_internal) -> bool;
 }
 extern "C" {
     pub fn Servo_ComputedValues_Get(node: RawGeckoNodeBorrowed)
      -> ServoComputedValuesStrong;
 }
 extern "C" {
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -486,16 +486,55 @@ pub extern "C" fn Servo_DeclarationBlock
     if let Some(&(ref decl, _)) = declarations.read().declarations.get(index as usize) {
         let name = decl.name().to_string();
         unsafe { result.as_mut().unwrap() }.write_str(&name).is_ok()
     } else {
         false
     }
 }
 
+// FIXME Methods of PropertyDeclarationBlock should take atoms directly.
+// This function is just a temporary workaround before that finishes.
+fn get_property_name_from_atom(atom: *mut nsIAtom, is_custom: bool) -> String {
+    let atom = Atom::from(atom);
+    if !is_custom {
+        atom.to_string()
+    } else {
+        let mut result = String::with_capacity(atom.len() as usize + 2);
+        result.push_str("--");
+        write!(result, "{}", atom).unwrap();
+        result
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_DeclarationBlock_GetPropertyValue(declarations: RawServoDeclarationBlockBorrowed,
+                                                          property: *mut nsIAtom, is_custom: bool,
+                                                          value: *mut nsAString) {
+    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let property = get_property_name_from_atom(property, is_custom);
+    declarations.read().property_value_to_css(&property, unsafe { value.as_mut().unwrap() }).unwrap();
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations: RawServoDeclarationBlockBorrowed,
+                                                                property: *mut nsIAtom, is_custom: bool) -> bool {
+    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let property = get_property_name_from_atom(property, is_custom);
+    declarations.read().property_priority(&property).important()
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_DeclarationBlock_RemoveProperty(declarations: RawServoDeclarationBlockBorrowed,
+                                                        property: *mut nsIAtom, is_custom: bool) {
+    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    let property = get_property_name_from_atom(property, is_custom);
+    declarations.write().remove_property(&property);
+}
+
 #[no_mangle]
 pub extern "C" fn Servo_CSSSupports(property: *const nsACString, value: *const nsACString) -> bool {
     let property = unsafe { property.as_ref().unwrap().as_str_unchecked() };
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
 
     let base_url = &*DUMMY_BASE_URL;
     let extra_data = ParserContextExtraData::default();