mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
script: Implement CSSStyleSheet.replace
(#38244)
Implement `CSSStyleSheet.replace` [#dom-cssstylesheet-replace](https://drafts.csswg.org/cssom/#dom-cssstylesheet-replace) with disallow modification flag [#concept-css-style-sheet-disallow-modification-flag](https://drafts.csswg.org/cssom/#concept-css-style-sheet-disallow-modification-flag). Basically it would behave like `replaceSync`, but we are running it asynchronously. Testing: Existing WPT coverage. Part of: https://github.com/servo/servo/issues/36162 --------- Signed-off-by: Jo Steven Novaryo <jo.steven.novaryo@huawei.com>
This commit is contained in:
parent
928934d4b0
commit
1d896699a4
5 changed files with 92 additions and 19 deletions
|
@ -3,9 +3,11 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use script_bindings::realms::InRealm;
|
||||
use script_bindings::root::Dom;
|
||||
use servo_arc::Arc;
|
||||
use style::media_queries::MediaList as StyleMediaList;
|
||||
|
@ -22,6 +24,7 @@ use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
|||
use crate::dom::bindings::codegen::GenericBindings::CSSRuleListBinding::CSSRuleList_Binding::CSSRuleListMethods;
|
||||
use crate::dom::bindings::codegen::UnionTypes::MediaListOrString;
|
||||
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::{
|
||||
DomGlobal, reflect_dom_object, reflect_dom_object_with_proto,
|
||||
};
|
||||
|
@ -34,8 +37,10 @@ use crate::dom::medialist::MediaList;
|
|||
use crate::dom::node::NodeTraits;
|
||||
use crate::dom::stylesheet::StyleSheet;
|
||||
use crate::dom::stylesheetlist::StyleSheetListOwner;
|
||||
use crate::dom::types::Promise;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
use crate::test::TrustedPromise;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct CSSStyleSheet {
|
||||
|
@ -60,6 +65,9 @@ pub(crate) struct CSSStyleSheet {
|
|||
/// <https://drafts.csswg.org/cssom/#concept-css-style-sheet-constructor-document>
|
||||
constructor_document: Option<Dom<Document>>,
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#concept-css-style-sheet-disallow-modification-flag>
|
||||
disallow_modification: Cell<bool>,
|
||||
|
||||
/// Documents or shadow DOMs thats adopt this stylesheet, they will be notified whenever
|
||||
/// the stylesheet is modified.
|
||||
adopters: DomRefCell<Vec<StyleSheetListOwner>>,
|
||||
|
@ -82,6 +90,7 @@ impl CSSStyleSheet {
|
|||
origin_clean: Cell::new(true),
|
||||
constructor_document: constructor_document.map(Dom::from_ref),
|
||||
adopters: Default::default(),
|
||||
disallow_modification: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,6 +240,11 @@ impl CSSStyleSheet {
|
|||
adopter.invalidate_stylesheets();
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#concept-css-style-sheet-disallow-modification-flag>
|
||||
pub(crate) fn disallow_modification(&self) -> bool {
|
||||
self.disallow_modification.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
|
||||
|
@ -287,18 +301,31 @@ impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
|
|||
|
||||
/// <https://drafts.csswg.org/cssom/#dom-cssstylesheet-insertrule>
|
||||
fn InsertRule(&self, rule: DOMString, index: u32, can_gc: CanGc) -> Fallible<u32> {
|
||||
// Step 1. If the origin-clean flag is unset, throw a SecurityError exception.
|
||||
if !self.origin_clean.get() {
|
||||
return Err(Error::Security);
|
||||
}
|
||||
|
||||
// Step 2. If the disallow modification flag is set, throw a NotAllowedError DOMException.
|
||||
if self.disallow_modification() {
|
||||
return Err(Error::NotAllowed);
|
||||
}
|
||||
|
||||
self.rulelist(can_gc)
|
||||
.insert_rule(&rule, index, CssRuleTypes::default(), None, can_gc)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#dom-cssstylesheet-deleterule>
|
||||
fn DeleteRule(&self, index: u32, can_gc: CanGc) -> ErrorResult {
|
||||
// Step 1. If the origin-clean flag is unset, throw a SecurityError exception.
|
||||
if !self.origin_clean.get() {
|
||||
return Err(Error::Security);
|
||||
}
|
||||
|
||||
// Step 2. If the disallow modification flag is set, throw a NotAllowedError DOMException.
|
||||
if self.disallow_modification() {
|
||||
return Err(Error::NotAllowed);
|
||||
}
|
||||
self.rulelist(can_gc).remove_rule(index)
|
||||
}
|
||||
|
||||
|
@ -345,10 +372,68 @@ impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
|
|||
Ok(-1)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#synchronously-replace-the-rules-of-a-cssstylesheet>
|
||||
/// <https://drafts.csswg.org/cssom/#dom-cssstylesheet-replace>
|
||||
fn Replace(&self, text: USVString, comp: InRealm, can_gc: CanGc) -> Fallible<Rc<Promise>> {
|
||||
// Step 1. Let promise be a promise.
|
||||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||||
|
||||
// Step 2. If the constructed flag is not set, or the disallow modification flag is set,
|
||||
// reject promise with a NotAllowedError DOMException and return promise.
|
||||
if !self.is_constructed() || self.disallow_modification() {
|
||||
return Err(Error::NotAllowed);
|
||||
}
|
||||
|
||||
// Step 3. Set the disallow modification flag.
|
||||
self.disallow_modification.set(true);
|
||||
|
||||
// Step 4. In parallel, do these steps:
|
||||
let trusted_sheet = Trusted::new(self);
|
||||
let trusted_promise = TrustedPromise::new(promise.clone());
|
||||
|
||||
self.global()
|
||||
.task_manager()
|
||||
.dom_manipulation_task_source()
|
||||
.queue(task!(cssstylesheet_replace: move || {
|
||||
let sheet = trusted_sheet.root();
|
||||
|
||||
// Step 4.1. Let rules be the result of running parse a stylesheet’s contents from text.
|
||||
// Step 4.2. If rules contains one or more @import rules, remove those rules from rules.
|
||||
// We are disallowing import rules in parsing
|
||||
let global = sheet.global();
|
||||
let window = global.as_window();
|
||||
|
||||
StyleStyleSheet::update_from_str(
|
||||
&sheet.style_stylesheet,
|
||||
&text,
|
||||
UrlExtraData(window.get_url().get_arc()),
|
||||
None,
|
||||
window.css_error_reporter(),
|
||||
AllowImportRules::No,
|
||||
);
|
||||
|
||||
// Step 4.3. Set sheet’s CSS rules to rules.
|
||||
// We reset our rule list, which will be initialized properly
|
||||
// at the next getter access.
|
||||
sheet.rulelist.set(None);
|
||||
|
||||
// Notify invalidation to update the styles immediately.
|
||||
sheet.notify_invalidations();
|
||||
|
||||
// Step 4.4. Unset sheet’s disallow modification flag.
|
||||
sheet.disallow_modification.set(false);
|
||||
|
||||
// Step 4.5. Resolve promise with sheet.
|
||||
trusted_promise.root().resolve_native(&sheet, CanGc::note());
|
||||
}));
|
||||
|
||||
Ok(promise)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#dom-cssstylesheet-replacesync>
|
||||
fn ReplaceSync(&self, text: USVString) -> Result<(), Error> {
|
||||
// Step 1. If the constructed flag is not set throw a NotAllowedError
|
||||
if !self.is_constructed() {
|
||||
// Step 1. If the constructed flag is not set, or the disallow modification flag is set,
|
||||
// throw a NotAllowedError DOMException.
|
||||
if !self.is_constructed() || self.disallow_modification() {
|
||||
return Err(Error::NotAllowed);
|
||||
}
|
||||
|
||||
|
|
|
@ -137,7 +137,8 @@ DOMInterfaces = {
|
|||
},
|
||||
|
||||
'CSSStyleSheet': {
|
||||
'canGc': ['AddRule', 'DeleteRule', 'GetCssRules', 'GetRules', 'InsertRule', 'RemoveRule'],
|
||||
'inRealms': ['Replace'],
|
||||
'canGc': ['AddRule', 'DeleteRule', 'GetCssRules', 'GetRules', 'InsertRule', 'RemoveRule', 'Replace'],
|
||||
},
|
||||
|
||||
'Crypto': {
|
||||
|
|
|
@ -11,6 +11,8 @@ interface CSSStyleSheet : StyleSheet {
|
|||
[Throws, SameObject] readonly attribute CSSRuleList cssRules;
|
||||
[Throws] unsigned long insertRule(DOMString rule, optional unsigned long index = 0);
|
||||
[Throws] undefined deleteRule(unsigned long index);
|
||||
|
||||
[Throws] Promise<CSSStyleSheet> replace(USVString text);
|
||||
[Throws] undefined replaceSync(USVString text);
|
||||
};
|
||||
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
[CSSStyleSheet.replace produces Promise<CSSStyleSheet>]
|
||||
expected: FAIL
|
||||
|
||||
[Constructed style sheets can be applied on document]
|
||||
expected: FAIL
|
||||
|
||||
[Constructed style sheets can be applied on shadow root]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -44,9 +41,6 @@
|
|||
[CSSStyleSheet.replace ignores @import rule but still loads other rules]
|
||||
expected: FAIL
|
||||
|
||||
[CSSStyleSheet.replace does not reject on failed imports]
|
||||
expected: FAIL
|
||||
|
||||
[Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document]
|
||||
expected: FAIL
|
||||
|
||||
|
|
9
tests/wpt/meta/css/cssom/idlharness.html.ini
vendored
9
tests/wpt/meta/css/cssom/idlharness.html.ini
vendored
|
@ -386,15 +386,6 @@
|
|||
[MathMLElement interface: attribute style]
|
||||
expected: FAIL
|
||||
|
||||
[CSSStyleSheet interface: operation replace(USVString)]
|
||||
expected: FAIL
|
||||
|
||||
[CSSStyleSheet interface: sheet must inherit property "replace(USVString)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[CSSStyleSheet interface: calling replace(USVString) on sheet with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[CSSImportRule interface: attribute supportsText]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue