Bug 1313293 - Implement CSSStyleSheet.insertRule and deleteRule. r?heycam
MozReview-Commit-ID: DLHWrNqVH0D
--- 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) };
}