mirror of
https://github.com/servo/servo.git
synced 2025-07-22 14:53:49 +01: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
|
let loader = owner
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|element| StylesheetLoader::for_element(element));
|
.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
|
let new_rule = css_rules
|
||||||
.insert_rule(
|
.insert_rule(
|
||||||
&parent_stylesheet.shared_lock,
|
&parent_stylesheet.shared_lock,
|
||||||
|
@ -134,7 +139,7 @@ impl CSSRuleList {
|
||||||
containing_rule_types,
|
containing_rule_types,
|
||||||
parse_relative_rule_type,
|
parse_relative_rule_type,
|
||||||
loader.as_ref().map(|l| l as &dyn StyleStylesheetLoader),
|
loader.as_ref().map(|l| l as &dyn StyleStylesheetLoader),
|
||||||
AllowImportRules::Yes,
|
allow_import_rules,
|
||||||
)
|
)
|
||||||
.map_err(Convert::convert)?;
|
.map_err(Convert::convert)?;
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,24 @@
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
use js::rust::HandleObject;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
|
use style::media_queries::MediaList as StyleMediaList;
|
||||||
use style::shared_lock::SharedRwLock;
|
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::GenericBindings::CSSRuleListBinding::CSSRuleList_Binding::CSSRuleListMethods;
|
||||||
|
use crate::dom::bindings::codegen::UnionTypes::MediaListOrString;
|
||||||
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
|
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::root::{DomRoot, MutNullableDom};
|
||||||
use crate::dom::bindings::str::DOMString;
|
use crate::dom::bindings::str::DOMString;
|
||||||
use crate::dom::cssrulelist::{CSSRuleList, RulesSource};
|
use crate::dom::cssrulelist::{CSSRuleList, RulesSource};
|
||||||
|
@ -32,44 +42,82 @@ pub(crate) struct CSSStyleSheet {
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
style_stylesheet: Arc<StyleStyleSheet>,
|
style_stylesheet: Arc<StyleStyleSheet>,
|
||||||
origin_clean: Cell<bool>,
|
origin_clean: Cell<bool>,
|
||||||
|
is_constructed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSSStyleSheet {
|
impl CSSStyleSheet {
|
||||||
fn new_inherited(
|
fn new_inherited(
|
||||||
owner: &Element,
|
owner: Option<&Element>,
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
href: Option<DOMString>,
|
href: Option<DOMString>,
|
||||||
title: Option<DOMString>,
|
title: Option<DOMString>,
|
||||||
stylesheet: Arc<StyleStyleSheet>,
|
stylesheet: Arc<StyleStyleSheet>,
|
||||||
|
is_constructed: bool,
|
||||||
) -> CSSStyleSheet {
|
) -> CSSStyleSheet {
|
||||||
CSSStyleSheet {
|
CSSStyleSheet {
|
||||||
stylesheet: StyleSheet::new_inherited(type_, href, title),
|
stylesheet: StyleSheet::new_inherited(type_, href, title),
|
||||||
owner: MutNullableDom::new(Some(owner)),
|
owner: MutNullableDom::new(owner),
|
||||||
rulelist: MutNullableDom::new(None),
|
rulelist: MutNullableDom::new(None),
|
||||||
style_stylesheet: stylesheet,
|
style_stylesheet: stylesheet,
|
||||||
origin_clean: Cell::new(true),
|
origin_clean: Cell::new(true),
|
||||||
|
is_constructed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
window: &Window,
|
window: &Window,
|
||||||
owner: &Element,
|
owner: Option<&Element>,
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
href: Option<DOMString>,
|
href: Option<DOMString>,
|
||||||
title: Option<DOMString>,
|
title: Option<DOMString>,
|
||||||
stylesheet: Arc<StyleStyleSheet>,
|
stylesheet: Arc<StyleStyleSheet>,
|
||||||
|
is_constructed: bool,
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> DomRoot<CSSStyleSheet> {
|
) -> DomRoot<CSSStyleSheet> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(CSSStyleSheet::new_inherited(
|
Box::new(CSSStyleSheet::new_inherited(
|
||||||
owner, type_, href, title, stylesheet,
|
owner,
|
||||||
|
type_,
|
||||||
|
href,
|
||||||
|
title,
|
||||||
|
stylesheet,
|
||||||
|
is_constructed,
|
||||||
)),
|
)),
|
||||||
window,
|
window,
|
||||||
can_gc,
|
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> {
|
fn rulelist(&self, can_gc: CanGc) -> DomRoot<CSSRuleList> {
|
||||||
self.rulelist.or_init(|| {
|
self.rulelist.or_init(|| {
|
||||||
let rules = self.style_stylesheet.contents.rules.clone();
|
let rules = self.style_stylesheet.contents.rules.clone();
|
||||||
|
@ -123,9 +171,58 @@ impl CSSStyleSheet {
|
||||||
can_gc,
|
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 {
|
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>
|
/// <https://drafts.csswg.org/cssom/#dom-cssstylesheet-cssrules>
|
||||||
fn GetCssRules(&self, can_gc: CanGc) -> Fallible<DomRoot<CSSRuleList>> {
|
fn GetCssRules(&self, can_gc: CanGc) -> Fallible<DomRoot<CSSRuleList>> {
|
||||||
if !self.origin_clean.get() {
|
if !self.origin_clean.get() {
|
||||||
|
|
|
@ -182,11 +182,12 @@ impl HTMLLinkElement {
|
||||||
self.cssom_stylesheet.or_init(|| {
|
self.cssom_stylesheet.or_init(|| {
|
||||||
CSSStyleSheet::new(
|
CSSStyleSheet::new(
|
||||||
&self.owner_window(),
|
&self.owner_window(),
|
||||||
self.upcast::<Element>(),
|
Some(self.upcast::<Element>()),
|
||||||
"text/css".into(),
|
"text/css".into(),
|
||||||
None, // todo handle location
|
None, // todo handle location
|
||||||
None, // todo handle title
|
None, // todo handle title
|
||||||
sheet,
|
sheet,
|
||||||
|
false, // is_constructed
|
||||||
can_gc,
|
can_gc,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -151,11 +151,12 @@ impl HTMLStyleElement {
|
||||||
self.cssom_stylesheet.or_init(|| {
|
self.cssom_stylesheet.or_init(|| {
|
||||||
CSSStyleSheet::new(
|
CSSStyleSheet::new(
|
||||||
&self.owner_window(),
|
&self.owner_window(),
|
||||||
self.upcast::<Element>(),
|
Some(self.upcast::<Element>()),
|
||||||
"text/css".into(),
|
"text/css".into(),
|
||||||
None, // todo handle location
|
None, // todo handle location
|
||||||
None, // todo handle title
|
None, // todo handle title
|
||||||
sheet,
|
sheet,
|
||||||
|
false, // is_constructed
|
||||||
CanGc::note(),
|
CanGc::note(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -106,6 +106,11 @@ impl MediaList {
|
||||||
);
|
);
|
||||||
MediaQuery::parse(&context, &mut parser)
|
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 {
|
impl MediaListMethods<crate::DomTypeHolder> for MediaList {
|
||||||
|
|
|
@ -5,12 +5,20 @@
|
||||||
// https://drafts.csswg.org/cssom/#the-cssstylesheet-interface
|
// https://drafts.csswg.org/cssom/#the-cssstylesheet-interface
|
||||||
[Exposed=Window]
|
[Exposed=Window]
|
||||||
interface CSSStyleSheet : StyleSheet {
|
interface CSSStyleSheet : StyleSheet {
|
||||||
|
constructor(optional CSSStyleSheetInit options = {});
|
||||||
|
|
||||||
// readonly attribute CSSRule? ownerRule;
|
// readonly attribute CSSRule? ownerRule;
|
||||||
[Throws, SameObject] readonly attribute CSSRuleList cssRules;
|
[Throws, SameObject] readonly attribute CSSRuleList cssRules;
|
||||||
[Throws] unsigned long insertRule(DOMString rule, optional unsigned long index = 0);
|
[Throws] unsigned long insertRule(DOMString rule, optional unsigned long index = 0);
|
||||||
[Throws] undefined deleteRule(unsigned long index);
|
[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
|
// https://drafts.csswg.org/cssom/#legacy-css-style-sheet-members
|
||||||
partial interface CSSStyleSheet {
|
partial interface CSSStyleSheet {
|
||||||
[Throws, SameObject] readonly attribute CSSRuleList rules;
|
[Throws, SameObject] readonly attribute CSSRuleList rules;
|
||||||
|
|
|
@ -26,9 +26,6 @@
|
||||||
[Attempting to insert a CSSNestedDeclaration rule into top-level @media rule]
|
[Attempting to insert a CSSNestedDeclaration rule into top-level @media rule]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Attempting to insert a CSSNestedDeclaration rule into a stylesheet]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Attempting to insert a CSSNestedDeclaration rule, empty block]
|
[Attempting to insert a CSSNestedDeclaration rule, empty block]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,8 @@
|
||||||
[@import rules are not parsed in CSSStyleSheet.replaceSync]
|
[@import rules are not parsed in CSSStyleSheet.replaceSync]
|
||||||
expected: FAIL
|
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]
|
[@import rules are not parsed in CSSStyleSheet.replace]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[@import rules should not trigger any loads.]
|
[@import rules should not trigger any loads.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
[new CSSStyleSheet produces empty CSSStyleSheet]
|
[new CSSStyleSheet produces empty CSSStyleSheet]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[title can be set in the CSSStyleSheet constructor]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CSSStyleSheet.replace produces Promise<CSSStyleSheet>]
|
[CSSStyleSheet.replace produces Promise<CSSStyleSheet>]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -56,9 +53,6 @@
|
||||||
[Adopted sheets are ordered after non-adopted sheets in the document]
|
[Adopted sheets are ordered after non-adopted sheets in the document]
|
||||||
expected: FAIL
|
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]
|
[CSSStyleSheet.replaceSync should not trigger any loads from @import rules]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -74,21 +68,12 @@
|
||||||
[CSSStyleSheet.replace does not reject on failed imports]
|
[CSSStyleSheet.replace does not reject on failed imports]
|
||||||
expected: FAIL
|
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]
|
[Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Adopting a shadow host's ancestor will empty adoptedStyleSheets if adopting to a different document]
|
[Adopting a shadow host's ancestor will empty adoptedStyleSheets if adopting to a different document]
|
||||||
expected: FAIL
|
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.]
|
[Modifying an adopted stylesheet on a disconnected shadow root should not crash.]
|
||||||
expected: FAIL
|
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