mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
script: Implement CSSStyleSheet constructor (#36521)
https://drafts.csswg.org/cssom/#dom-cssstylesheet-cssstylesheet Testing: covered by WPT This is part of #36162 Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
372fd04b23
commit
10f6f50c61
11 changed files with 127 additions and 38 deletions
|
@ -125,6 +125,11 @@ impl CSSRuleList {
|
|||
let loader = owner
|
||||
.as_ref()
|
||||
.map(|element| StylesheetLoader::for_element(element));
|
||||
let allow_import_rules = if self.parent_stylesheet.is_constructed() {
|
||||
AllowImportRules::No
|
||||
} else {
|
||||
AllowImportRules::Yes
|
||||
};
|
||||
let new_rule = css_rules
|
||||
.insert_rule(
|
||||
&parent_stylesheet.shared_lock,
|
||||
|
@ -134,7 +139,7 @@ impl CSSRuleList {
|
|||
containing_rule_types,
|
||||
parse_relative_rule_type,
|
||||
loader.as_ref().map(|l| l as &dyn StyleStylesheetLoader),
|
||||
AllowImportRules::Yes,
|
||||
allow_import_rules,
|
||||
)
|
||||
.map_err(Convert::convert)?;
|
||||
|
||||
|
|
|
@ -5,14 +5,24 @@
|
|||
use std::cell::Cell;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use servo_arc::Arc;
|
||||
use style::media_queries::MediaList as StyleMediaList;
|
||||
use style::shared_lock::SharedRwLock;
|
||||
use style::stylesheets::{CssRuleTypes, Stylesheet as StyleStyleSheet};
|
||||
use style::stylesheets::{
|
||||
AllowImportRules, CssRuleTypes, Origin, Stylesheet as StyleStyleSheet, UrlExtraData,
|
||||
};
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::CSSStyleSheetBinding::CSSStyleSheetMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::CSSStyleSheetBinding::{
|
||||
CSSStyleSheetInit, CSSStyleSheetMethods,
|
||||
};
|
||||
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::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::reflector::{
|
||||
DomGlobal, reflect_dom_object, reflect_dom_object_with_proto,
|
||||
};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::cssrulelist::{CSSRuleList, RulesSource};
|
||||
|
@ -32,44 +42,82 @@ pub(crate) struct CSSStyleSheet {
|
|||
#[no_trace]
|
||||
style_stylesheet: Arc<StyleStyleSheet>,
|
||||
origin_clean: Cell<bool>,
|
||||
is_constructed: bool,
|
||||
}
|
||||
|
||||
impl CSSStyleSheet {
|
||||
fn new_inherited(
|
||||
owner: &Element,
|
||||
owner: Option<&Element>,
|
||||
type_: DOMString,
|
||||
href: Option<DOMString>,
|
||||
title: Option<DOMString>,
|
||||
stylesheet: Arc<StyleStyleSheet>,
|
||||
is_constructed: bool,
|
||||
) -> CSSStyleSheet {
|
||||
CSSStyleSheet {
|
||||
stylesheet: StyleSheet::new_inherited(type_, href, title),
|
||||
owner: MutNullableDom::new(Some(owner)),
|
||||
owner: MutNullableDom::new(owner),
|
||||
rulelist: MutNullableDom::new(None),
|
||||
style_stylesheet: stylesheet,
|
||||
origin_clean: Cell::new(true),
|
||||
is_constructed,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
window: &Window,
|
||||
owner: &Element,
|
||||
owner: Option<&Element>,
|
||||
type_: DOMString,
|
||||
href: Option<DOMString>,
|
||||
title: Option<DOMString>,
|
||||
stylesheet: Arc<StyleStyleSheet>,
|
||||
is_constructed: bool,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<CSSStyleSheet> {
|
||||
reflect_dom_object(
|
||||
Box::new(CSSStyleSheet::new_inherited(
|
||||
owner, type_, href, title, stylesheet,
|
||||
owner,
|
||||
type_,
|
||||
href,
|
||||
title,
|
||||
stylesheet,
|
||||
is_constructed,
|
||||
)),
|
||||
window,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn new_with_proto(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
owner: Option<&Element>,
|
||||
type_: DOMString,
|
||||
href: Option<DOMString>,
|
||||
title: Option<DOMString>,
|
||||
stylesheet: Arc<StyleStyleSheet>,
|
||||
is_constructed: bool,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<CSSStyleSheet> {
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(CSSStyleSheet::new_inherited(
|
||||
owner,
|
||||
type_,
|
||||
href,
|
||||
title,
|
||||
stylesheet,
|
||||
is_constructed,
|
||||
)),
|
||||
window,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn rulelist(&self, can_gc: CanGc) -> DomRoot<CSSRuleList> {
|
||||
self.rulelist.or_init(|| {
|
||||
let rules = self.style_stylesheet.contents.rules.clone();
|
||||
|
@ -123,9 +171,58 @@ impl CSSStyleSheet {
|
|||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#concept-css-style-sheet-constructed-flag>
|
||||
#[inline]
|
||||
pub(crate) fn is_constructed(&self) -> bool {
|
||||
self.is_constructed
|
||||
}
|
||||
}
|
||||
|
||||
impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
|
||||
/// <https://drafts.csswg.org/cssom/#dom-cssstylesheet-cssstylesheet>
|
||||
fn Constructor(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
options: &CSSStyleSheetInit,
|
||||
) -> DomRoot<Self> {
|
||||
let doc = window.Document();
|
||||
let shared_lock = doc.style_shared_lock().clone();
|
||||
let media = Arc::new(shared_lock.wrap(match &options.media {
|
||||
Some(media) => match media {
|
||||
MediaListOrString::MediaList(media_list) => media_list.clone_media_list(),
|
||||
MediaListOrString::String(str) => MediaList::parse_media_list(str, window),
|
||||
},
|
||||
None => StyleMediaList::empty(),
|
||||
}));
|
||||
let stylesheet = Arc::new(StyleStyleSheet::from_str(
|
||||
"",
|
||||
UrlExtraData(window.get_url().get_arc()),
|
||||
Origin::Author,
|
||||
media,
|
||||
shared_lock,
|
||||
None,
|
||||
window.css_error_reporter(),
|
||||
doc.quirks_mode(),
|
||||
AllowImportRules::No,
|
||||
));
|
||||
if options.disabled {
|
||||
stylesheet.set_disabled(true);
|
||||
}
|
||||
Self::new_with_proto(
|
||||
window,
|
||||
proto,
|
||||
None, // owner
|
||||
"text/css".into(),
|
||||
None, // href
|
||||
None, // title
|
||||
stylesheet,
|
||||
true, // is_constructed
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#dom-cssstylesheet-cssrules>
|
||||
fn GetCssRules(&self, can_gc: CanGc) -> Fallible<DomRoot<CSSRuleList>> {
|
||||
if !self.origin_clean.get() {
|
||||
|
|
|
@ -182,11 +182,12 @@ impl HTMLLinkElement {
|
|||
self.cssom_stylesheet.or_init(|| {
|
||||
CSSStyleSheet::new(
|
||||
&self.owner_window(),
|
||||
self.upcast::<Element>(),
|
||||
Some(self.upcast::<Element>()),
|
||||
"text/css".into(),
|
||||
None, // todo handle location
|
||||
None, // todo handle title
|
||||
sheet,
|
||||
false, // is_constructed
|
||||
can_gc,
|
||||
)
|
||||
})
|
||||
|
|
|
@ -151,11 +151,12 @@ impl HTMLStyleElement {
|
|||
self.cssom_stylesheet.or_init(|| {
|
||||
CSSStyleSheet::new(
|
||||
&self.owner_window(),
|
||||
self.upcast::<Element>(),
|
||||
Some(self.upcast::<Element>()),
|
||||
"text/css".into(),
|
||||
None, // todo handle location
|
||||
None, // todo handle title
|
||||
sheet,
|
||||
false, // is_constructed
|
||||
CanGc::note(),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -106,6 +106,11 @@ impl MediaList {
|
|||
);
|
||||
MediaQuery::parse(&context, &mut parser)
|
||||
}
|
||||
|
||||
pub(crate) fn clone_media_list(&self) -> StyleMediaList {
|
||||
let guard = self.shared_lock().read();
|
||||
self.media_queries.read_with(&guard).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl MediaListMethods<crate::DomTypeHolder> for MediaList {
|
||||
|
|
|
@ -5,12 +5,20 @@
|
|||
// https://drafts.csswg.org/cssom/#the-cssstylesheet-interface
|
||||
[Exposed=Window]
|
||||
interface CSSStyleSheet : StyleSheet {
|
||||
constructor(optional CSSStyleSheetInit options = {});
|
||||
|
||||
// readonly attribute CSSRule? ownerRule;
|
||||
[Throws, SameObject] readonly attribute CSSRuleList cssRules;
|
||||
[Throws] unsigned long insertRule(DOMString rule, optional unsigned long index = 0);
|
||||
[Throws] undefined deleteRule(unsigned long index);
|
||||
};
|
||||
|
||||
dictionary CSSStyleSheetInit {
|
||||
// DOMString baseURL = null;
|
||||
(MediaList or DOMString) media;
|
||||
boolean disabled = false;
|
||||
};
|
||||
|
||||
// https://drafts.csswg.org/cssom/#legacy-css-style-sheet-members
|
||||
partial interface CSSStyleSheet {
|
||||
[Throws, SameObject] readonly attribute CSSRuleList rules;
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
[Attempting to insert a CSSNestedDeclaration rule into top-level @media rule]
|
||||
expected: FAIL
|
||||
|
||||
[Attempting to insert a CSSNestedDeclaration rule into a stylesheet]
|
||||
expected: FAIL
|
||||
|
||||
[Attempting to insert a CSSNestedDeclaration rule, empty block]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -2,12 +2,8 @@
|
|||
[@import rules are not parsed in CSSStyleSheet.replaceSync]
|
||||
expected: FAIL
|
||||
|
||||
[Inserting an @import rule through insertRule on a constructed stylesheet throws an exception]
|
||||
expected: FAIL
|
||||
|
||||
[@import rules are not parsed in CSSStyleSheet.replace]
|
||||
expected: FAIL
|
||||
|
||||
[@import rules should not trigger any loads.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
[new CSSStyleSheet produces empty CSSStyleSheet]
|
||||
expected: FAIL
|
||||
|
||||
[title can be set in the CSSStyleSheet constructor]
|
||||
expected: FAIL
|
||||
|
||||
[CSSStyleSheet.replace produces Promise<CSSStyleSheet>]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -56,9 +53,6 @@
|
|||
[Adopted sheets are ordered after non-adopted sheets in the document]
|
||||
expected: FAIL
|
||||
|
||||
[Inserting an @import rule through insertRule on a constructed stylesheet throws an exception]
|
||||
expected: FAIL
|
||||
|
||||
[CSSStyleSheet.replaceSync should not trigger any loads from @import rules]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -74,21 +68,12 @@
|
|||
[CSSStyleSheet.replace does not reject on failed imports]
|
||||
expected: FAIL
|
||||
|
||||
[Cloning a shadow host will not clone shadow root, and also adoptedStyleSheets]
|
||||
expected: FAIL
|
||||
|
||||
[Importing a shadow host will not copy shadow root, and also adoptedStyleSheets]
|
||||
expected: FAIL
|
||||
|
||||
[Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document]
|
||||
expected: FAIL
|
||||
|
||||
[Adopting a shadow host's ancestor will empty adoptedStyleSheets if adopting to a different document]
|
||||
expected: FAIL
|
||||
|
||||
[Forcing a style update after adding an adopted stylesheet on a disconnected shadow root should not crash.]
|
||||
expected: FAIL
|
||||
|
||||
[Modifying an adopted stylesheet on a disconnected shadow root should not crash.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[CSSStyleSheet-modify-after-removal.html]
|
||||
[Modify constructed sheet from removed iframe]
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[insertRule-across-context.html]
|
||||
[The constructor of inserted rule object must be from iframe for new CSSStyleSheet()]
|
||||
expected: FAIL
|
Loading…
Add table
Add a link
Reference in a new issue