Bug 1313293 - Implement CSSStyleSheet.insertRule and deleteRule. r?heycam draft
authorXidorn Quan <me@upsuper.org>
Thu, 24 Nov 2016 18:15:05 +1100
changeset 444558 c1285a5cede9c6e0c423d9102ee62c23fe79eb5f
parent 444557 9caa43695a4b92adec88192132bd171093c6ca06
child 538308 ea85d8c5b7b202967713a8964a06ee87985a30bf
push id37280
push userxquan@mozilla.com
push dateMon, 28 Nov 2016 07:16:11 +0000
reviewersheycam
bugs1313293
milestone53.0a1
Bug 1313293 - Implement CSSStyleSheet.insertRule and deleteRule. r?heycam MozReview-Commit-ID: DLHWrNqVH0D
layout/style/ServoBindingList.h
layout/style/ServoCSSRuleList.cpp
layout/style/ServoCSSRuleList.h
layout/style/ServoStyleSheet.cpp
servo/components/style/binding_tools/regen.py
servo/components/style/gecko/conversions.rs
servo/ports/geckolib/glue.rs
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -48,16 +48,21 @@ SERVO_BINDING_FUNC(Servo_StyleSet_Insert
                    RawServoStyleSheetBorrowed reference)
 
 // 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)
+SERVO_BINDING_FUNC(Servo_CssRules_InsertRule, nsresult,
+                   ServoCssRulesBorrowed rules, const nsACString* rule,
+                   uint32_t index, bool nested, uint16_t* rule_type)
+SERVO_BINDING_FUNC(Servo_CssRules_DeleteRule, nsresult,
+                   ServoCssRulesBorrowed rules, uint32_t index)
 
 // CSS Rules
 SERVO_BINDING_FUNC(Servo_StyleRule_Debug, void,
                    RawServoStyleRuleBorrowed rule, nsACString* result)
 SERVO_BINDING_FUNC(Servo_StyleRule_GetStyle, RawServoDeclarationBlockStrong,
                    RawServoStyleRuleBorrowed rule)
 SERVO_BINDING_FUNC(Servo_StyleRule_SetStyle, void,
                    RawServoStyleRuleBorrowed rule,
--- a/layout/style/ServoCSSRuleList.cpp
+++ b/layout/style/ServoCSSRuleList.cpp
@@ -19,24 +19,19 @@ ServoCSSRuleList::ServoCSSRuleList(Servo
   , 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.
 }
 
-nsIDOMCSSRule*
-ServoCSSRuleList::IndexedGetter(uint32_t aIndex, bool& aFound)
+css::Rule*
+ServoCSSRuleList::GetRule(uint32_t aIndex)
 {
-  if (aIndex >= mRules.Length()) {
-    aFound = false;
-    return nullptr;
-  }
-  aFound = true;
   uintptr_t rule = mRules[aIndex];
   if (rule <= kMaxRuleType) {
     RefPtr<css::Rule> ruleObj = nullptr;
     switch (rule) {
       case nsIDOMCSSRule::STYLE_RULE: {
         ruleObj = new ServoStyleRule(
           Servo_CssRules_GetStyleRuleAt(mRawRules, aIndex).Consume());
         break;
@@ -49,17 +44,31 @@ ServoCSSRuleList::IndexedGetter(uint32_t
       default:
         NS_ERROR("stylo: not implemented yet");
         return nullptr;
     }
     ruleObj->SetStyleSheet(mStyleSheet);
     rule = CastToUint(ruleObj.forget().take());
     mRules[aIndex] = rule;
   }
-  return CastToPtr(rule)->GetDOMRule();
+  return CastToPtr(rule);
+}
+
+nsIDOMCSSRule*
+ServoCSSRuleList::IndexedGetter(uint32_t aIndex, bool& aFound)
+{
+  if (aIndex >= mRules.Length()) {
+    aFound = false;
+    return nullptr;
+  }
+  aFound = true;
+  if (css::Rule* rule = GetRule(aIndex)) {
+    return rule->GetDOMRule();
+  }
+  return nullptr;
 }
 
 template<typename Func>
 void
 ServoCSSRuleList::EnumerateInstantiatedRules(Func aCallback)
 {
   for (uintptr_t rule : mRules) {
     if (rule > kMaxRuleType) {
@@ -72,14 +81,40 @@ void
 ServoCSSRuleList::DropReference()
 {
   mStyleSheet = nullptr;
   EnumerateInstantiatedRules([](css::Rule* rule) {
     rule->SetStyleSheet(nullptr);
   });
 }
 
+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;
+  uint16_t type;
+  nsresult rv = Servo_CssRules_InsertRule(mRawRules, &rule,
+                                          aIndex, nested, &type);
+  if (!NS_FAILED(rv)) {
+    mRules.InsertElementAt(type);
+  }
+  return rv;
+}
+
+nsresult
+ServoCSSRuleList::DeleteRule(uint32_t aIndex)
+{
+  nsresult rv = Servo_CssRules_DeleteRule(mRawRules, aIndex);
+  if (!NS_FAILED(rv)) {
+    mRules.RemoveElementAt(aIndex);
+  }
+  return rv;
+}
+
 ServoCSSRuleList::~ServoCSSRuleList()
 {
   EnumerateInstantiatedRules([](css::Rule* rule) { rule->Release(); });
 }
 
 } // namespace mozilla
--- a/layout/style/ServoCSSRuleList.h
+++ b/layout/style/ServoCSSRuleList.h
@@ -27,16 +27,20 @@ public:
 
   ServoStyleSheet* GetParentObject() final { return mStyleSheet; }
 
   nsIDOMCSSRule* IndexedGetter(uint32_t aIndex, bool& aFound) final;
   uint32_t Length() final { return mRules.Length(); }
 
   void DropReference();
 
+  css::Rule* GetRule(uint32_t aIndex);
+  nsresult InsertRule(const nsAString& aRule, uint32_t aIndex);
+  nsresult DeleteRule(uint32_t aIndex);
+
 private:
   virtual ~ServoCSSRuleList();
 
   // XXX Is it possible to have an address lower than or equal to 255?
   //     Is it possible to have more than 255 CSS rule types?
   static const uintptr_t kMaxRuleType = UINT8_MAX;
 
   static uintptr_t CastToUint(css::Rule* aPtr) {
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ServoStyleSheet.h"
 #include "mozilla/StyleBackendType.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoCSSRuleList.h"
 #include "mozilla/dom/CSSRuleList.h"
 
+#include "mozAutoDocUpdate.h"
+
 namespace mozilla {
 
 ServoStyleSheet::ServoStyleSheet(css::SheetParsingMode aParsingMode,
                                  CORSMode aCORSMode,
                                  net::ReferrerPolicy aReferrerPolicy,
                                  const dom::SRIMetadata& aIntegrity)
   : StyleSheet(StyleBackendType::Servo, aParsingMode)
   , mSheetInfo(aCORSMode, aReferrerPolicy, aIntegrity)
@@ -134,19 +136,48 @@ ServoStyleSheet::GetCssRulesInternal(Err
   }
   return mRuleList;
 }
 
 uint32_t
 ServoStyleSheet::InsertRuleInternal(const nsAString& aRule,
                                     uint32_t aIndex, ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return 0;
+  // Ensure mRuleList is constructed.
+  GetCssRulesInternal(aRv);
+
+  mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
+  aRv = mRuleList->InsertRule(aRule, aIndex);
+  if (aRv.Failed()) {
+    return 0;
+  }
+  if (mDocument) {
+    // XXX When we support @import rules, we should not notify here,
+    // but rather when the sheet the rule is importing is loaded.
+    // XXX We may not want to get the rule when stylesheet change event
+    // is not enabled.
+    mDocument->StyleRuleAdded(this, mRuleList->GetRule(aIndex));
+  }
+  return aIndex;
 }
 
 void
 ServoStyleSheet::DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  // Ensure mRuleList is constructed.
+  GetCssRulesInternal(aRv);
+  if (aIndex > mRuleList->Length()) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return;
+  }
+
+  mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
+  // Hold a strong ref to the rule so it doesn't die when we remove it
+  // from the list. XXX We may not want to hold it if stylesheet change
+  // event is not enabled.
+  RefPtr<css::Rule> rule = mRuleList->GetRule(aIndex);
+  aRv = mRuleList->DeleteRule(aIndex);
+  if (!aRv.Failed() && mDocument) {
+    mDocument->StyleRuleRemoved(this, rule);
+  }
 }
 
 } // namespace mozilla
--- a/servo/components/style/binding_tools/regen.py
+++ b/servo/components/style/binding_tools/regen.py
@@ -283,16 +283,17 @@ COMPILATION_TARGETS = {
             "nsFont",
             "nsIAtom",
             "nsIDocument",
             "nsINode",
             "nsIPrincipal",
             "nsIURI",
             "nsMainThreadPtrHolder",
             "nsRestyleHint",
+            "nsresult",
             "nsString",
             "nsStyleBackground",
             "nsStyleBorder",
             "nsStyleColor",
             "nsStyleColumn",
             "nsStyleContent",
             "nsStyleContext",
             "nsStyleCoord",
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -8,22 +8,23 @@
 
 #![allow(unsafe_code)]
 
 use app_units::Au;
 use gecko::values::{convert_rgba_to_nscolor, StyleCoordHelpers};
 use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue, Gecko_SetUrlImageValue};
 use gecko_bindings::bindings::{RawServoStyleSheet, RawServoDeclarationBlock, RawServoStyleRule};
 use gecko_bindings::bindings::{ServoComputedValues, ServoCssRules};
+use gecko_bindings::structs::nsresult;
 use gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImage};
 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI};
 use parking_lot::RwLock;
 use properties::{ComputedValues, PropertyDeclarationBlock};
-use stylesheets::{CssRules, Stylesheet, StyleRule};
+use stylesheets::{CssRules, RulesMutateError, Stylesheet, StyleRule};
 use values::computed::{CalcLengthOrPercentage, Gradient, Image, LengthOrPercentage, LengthOrPercentageOrAuto};
 
 unsafe impl HasFFI for Stylesheet {
     type FFIType = RawServoStyleSheet;
 }
 unsafe impl HasArcFFI for Stylesheet {}
 unsafe impl HasFFI for ComputedValues {
     type FFIType = ServoComputedValues;
@@ -492,8 +493,19 @@ pub mod basic_shape {
                 Margin => GeometryBox::ShapeBox(ShapeBox::Margin),
                 Fill => GeometryBox::Fill,
                 Stroke => GeometryBox::Stroke,
                 View => GeometryBox::View,
             }
         }
     }
 }
+
+impl From<RulesMutateError> for nsresult {
+    fn from(other: RulesMutateError) -> Self {
+        match other {
+            RulesMutateError::Syntax => nsresult::NS_ERROR_DOM_SYNTAX_ERR,
+            RulesMutateError::IndexSize => nsresult::NS_ERROR_DOM_INDEX_SIZE_ERR,
+            RulesMutateError::HierarchyRequest => nsresult::NS_ERROR_DOM_HIERARCHY_REQUEST_ERR,
+            RulesMutateError::InvalidState => nsresult::NS_ERROR_DOM_INVALID_STATE_ERR,
+        }
+    }
+}
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -32,16 +32,17 @@ use style::gecko_bindings::bindings::{Se
 use style::gecko_bindings::bindings::{ThreadSafePrincipalHolder, ThreadSafeURIHolder};
 use style::gecko_bindings::bindings::{nsACString, nsAString};
 use style::gecko_bindings::bindings::Gecko_Utf8SliceToString;
 use style::gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
 use style::gecko_bindings::bindings::nsTArrayBorrowed_uintptr_t;
 use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom};
 use style::gecko_bindings::structs::ServoElementSnapshot;
 use style::gecko_bindings::structs::nsRestyleHint;
+use style::gecko_bindings::structs::nsresult;
 use style::gecko_bindings::structs::nsString;
 use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasBoxFFI};
 use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong};
 use style::gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
 use style::parallel;
 use style::parser::{ParserContext, ParserContextExtraData};
 use style::properties::{CascadeFlags, ComputedValues, Importance, PropertyDeclaration};
 use style::properties::{PropertyDeclarationParseResult, PropertyDeclarationBlock};
@@ -300,16 +301,41 @@ pub extern "C" fn Servo_CssRules_GetStyl
         CssRule::Style(ref rule) => rule.clone().into_strong(),
         _ => {
             unreachable!("GetStyleRuleAt should only be called on a style rule");
         }
     }
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_CssRules_InsertRule(rules: ServoCssRulesBorrowed, rule: *const nsACString,
+                                            index: u32, nested: bool, rule_type: *mut u16) -> nsresult {
+    let rules = RwLock::<CssRules>::as_arc(&rules);
+    let rule = unsafe { rule.as_ref().unwrap().as_str_unchecked() };
+    // FIXME Needs real URL
+    let base_url = &*DUMMY_BASE_URL;
+    match rules.write().insert_rule(rule, &base_url, index as usize, nested) {
+        Ok(new_rule) => {
+            *unsafe { rule_type.as_mut().unwrap() } = new_rule.rule_type() as u16;
+            nsresult::NS_OK
+        }
+        Err(err) => err.into()
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_CssRules_DeleteRule(rules: ServoCssRulesBorrowed, index: u32) -> nsresult {
+    let rules = RwLock::<CssRules>::as_arc(&rules);
+    match rules.write().remove_rule(index as usize) {
+        Ok(_) => nsresult::NS_OK,
+        Err(err) => err.into()
+    }
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_CssRules_AddRef(rules: ServoCssRulesBorrowed) -> () {
     unsafe { RwLock::<CssRules>::addref(rules) };
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_CssRules_Release(rules: ServoCssRulesBorrowed) -> () {
     unsafe { RwLock::<CssRules>::release(rules) };
 }