mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
script: Implement DocumentOrShadowDOM.adoptedStylesheet
with FrozenArray
(#38163)
Spec: https://drafts.csswg.org/cssom/#dom-documentorshadowroot-adoptedstylesheets Implement `DocumentOrShadowDOM.adoptedStylesheet`. Due to `ObservableArray` being a massive issue on its own, it will be as it was a `FrozenArray` at first. This approach is similar to how Gecko implement adopted stylesheet. See https://phabricator.services.mozilla.com/D144547#change-IXyOzxxFn8sU. All of the changes will be gated behind a preference `dom_adoptedstylesheet_enabled`. Adopted stylesheet is implemented by adding the setter and getter of it. While the getter works like a normal attribute getter, the setter need to consider the inner working of document and shadow root StylesheetSet, specifically the ordering and the invalidations. Particularly for setter, we will clear all of the adopted stylesheet within the StylesheetSet and readd them. Possible optimization exist, but the focus should be directed to implementing `ObservableArray`. More context about the implementations https://hackmd.io/vtJAn4UyS_O0Idvk5dCO_w. Testing: Existing WPT Coverage Fixes: https://github.com/servo/servo/issues/37561 --------- Signed-off-by: Jo Steven Novaryo <jo.steven.novaryo@huawei.com>
This commit is contained in:
parent
d2e5137201
commit
f523445fc3
24 changed files with 434 additions and 139 deletions
|
@ -69,6 +69,7 @@ pub struct Preferences {
|
|||
/// List of comma-separated backends to be used by wgpu.
|
||||
pub dom_webgpu_wgpu_backend: String,
|
||||
pub dom_abort_controller_enabled: bool,
|
||||
pub dom_adoptedstylesheet_enabled: bool,
|
||||
pub dom_async_clipboard_enabled: bool,
|
||||
pub dom_bluetooth_enabled: bool,
|
||||
pub dom_bluetooth_testing_enabled: bool,
|
||||
|
@ -247,6 +248,7 @@ impl Preferences {
|
|||
devtools_server_enabled: false,
|
||||
devtools_server_port: 0,
|
||||
dom_abort_controller_enabled: false,
|
||||
dom_adoptedstylesheet_enabled: false,
|
||||
dom_allow_scripts_to_close_windows: false,
|
||||
dom_async_clipboard_enabled: false,
|
||||
dom_bluetooth_enabled: false,
|
||||
|
|
|
@ -120,7 +120,7 @@ impl CSSRuleList {
|
|||
let parent_stylesheet = self.parent_stylesheet.style_stylesheet();
|
||||
let owner = self
|
||||
.parent_stylesheet
|
||||
.get_owner()
|
||||
.owner_node()
|
||||
.and_then(DomRoot::downcast::<HTMLElement>);
|
||||
let loader = owner
|
||||
.as_ref()
|
||||
|
|
|
@ -127,9 +127,7 @@ impl CSSStyleOwner {
|
|||
if changed {
|
||||
// If this is changed, see also
|
||||
// CSSStyleRule::SetSelectorText, which does the same thing.
|
||||
if let Some(owner) = rule.parent_stylesheet().get_owner() {
|
||||
owner.stylesheet_list_owner().invalidate_stylesheets();
|
||||
}
|
||||
rule.parent_stylesheet().notify_invalidations();
|
||||
}
|
||||
result
|
||||
},
|
||||
|
|
|
@ -21,7 +21,6 @@ use crate::dom::cssgroupingrule::CSSGroupingRule;
|
|||
use crate::dom::cssrule::SpecificCSSRule;
|
||||
use crate::dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
|
||||
use crate::dom::cssstylesheet::CSSStyleSheet;
|
||||
use crate::dom::node::NodeTraits;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
|
@ -136,9 +135,9 @@ impl CSSStyleRuleMethods<crate::DomTypeHolder> for CSSStyleRule {
|
|||
let mut guard = self.cssgroupingrule.shared_lock().write();
|
||||
let stylerule = self.stylerule.write_with(&mut guard);
|
||||
mem::swap(&mut stylerule.selectors, &mut s);
|
||||
if let Some(owner) = self.cssgroupingrule.parent_stylesheet().get_owner() {
|
||||
owner.stylesheet_list_owner().invalidate_stylesheets();
|
||||
}
|
||||
self.cssgroupingrule
|
||||
.parent_stylesheet()
|
||||
.notify_invalidations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::cell::Cell;
|
|||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use script_bindings::root::Dom;
|
||||
use servo_arc::Arc;
|
||||
use style::media_queries::MediaList as StyleMediaList;
|
||||
use style::shared_lock::SharedRwLock;
|
||||
|
@ -13,6 +14,7 @@ use style::stylesheets::{
|
|||
AllowImportRules, CssRuleTypes, Origin, Stylesheet as StyleStyleSheet, UrlExtraData,
|
||||
};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::CSSStyleSheetBinding::{
|
||||
CSSStyleSheetInit, CSSStyleSheetMethods,
|
||||
};
|
||||
|
@ -26,23 +28,41 @@ use crate::dom::bindings::reflector::{
|
|||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::bindings::str::{DOMString, USVString};
|
||||
use crate::dom::cssrulelist::{CSSRuleList, RulesSource};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::medialist::MediaList;
|
||||
use crate::dom::node::NodeTraits;
|
||||
use crate::dom::stylesheet::StyleSheet;
|
||||
use crate::dom::stylesheetlist::StyleSheetListOwner;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct CSSStyleSheet {
|
||||
stylesheet: StyleSheet,
|
||||
owner: MutNullableDom<Element>,
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#concept-css-style-sheet-owner-node>
|
||||
owner_node: MutNullableDom<Element>,
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#ref-for-concept-css-style-sheet-css-rules>
|
||||
rulelist: MutNullableDom<CSSRuleList>,
|
||||
|
||||
/// The inner Stylo's [Stylesheet].
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
#[no_trace]
|
||||
style_stylesheet: Arc<StyleStyleSheet>,
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#concept-css-style-sheet-origin-clean-flag>
|
||||
origin_clean: Cell<bool>,
|
||||
is_constructed: bool,
|
||||
|
||||
/// In which [Document] that this stylesheet was constructed.
|
||||
///
|
||||
/// <https://drafts.csswg.org/cssom/#concept-css-style-sheet-constructor-document>
|
||||
constructor_document: Option<Dom<Document>>,
|
||||
|
||||
/// Documents or shadow DOMs thats adopt this stylesheet, they will be notified whenever
|
||||
/// the stylesheet is modified.
|
||||
adopters: DomRefCell<Vec<StyleSheetListOwner>>,
|
||||
}
|
||||
|
||||
impl CSSStyleSheet {
|
||||
|
@ -52,15 +72,16 @@ impl CSSStyleSheet {
|
|||
href: Option<DOMString>,
|
||||
title: Option<DOMString>,
|
||||
stylesheet: Arc<StyleStyleSheet>,
|
||||
is_constructed: bool,
|
||||
constructor_document: Option<&Document>,
|
||||
) -> CSSStyleSheet {
|
||||
CSSStyleSheet {
|
||||
stylesheet: StyleSheet::new_inherited(type_, href, title),
|
||||
owner: MutNullableDom::new(owner),
|
||||
owner_node: MutNullableDom::new(owner),
|
||||
rulelist: MutNullableDom::new(None),
|
||||
style_stylesheet: stylesheet,
|
||||
origin_clean: Cell::new(true),
|
||||
is_constructed,
|
||||
constructor_document: constructor_document.map(Dom::from_ref),
|
||||
adopters: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,7 +94,7 @@ impl CSSStyleSheet {
|
|||
href: Option<DOMString>,
|
||||
title: Option<DOMString>,
|
||||
stylesheet: Arc<StyleStyleSheet>,
|
||||
is_constructed: bool,
|
||||
constructor_document: Option<&Document>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<CSSStyleSheet> {
|
||||
reflect_dom_object(
|
||||
|
@ -83,7 +104,7 @@ impl CSSStyleSheet {
|
|||
href,
|
||||
title,
|
||||
stylesheet,
|
||||
is_constructed,
|
||||
constructor_document,
|
||||
)),
|
||||
window,
|
||||
can_gc,
|
||||
|
@ -100,7 +121,7 @@ impl CSSStyleSheet {
|
|||
href: Option<DOMString>,
|
||||
title: Option<DOMString>,
|
||||
stylesheet: Arc<StyleStyleSheet>,
|
||||
is_constructed: bool,
|
||||
constructor_document: Option<&Document>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<CSSStyleSheet> {
|
||||
reflect_dom_object_with_proto(
|
||||
|
@ -110,7 +131,7 @@ impl CSSStyleSheet {
|
|||
href,
|
||||
title,
|
||||
stylesheet,
|
||||
is_constructed,
|
||||
constructor_document,
|
||||
)),
|
||||
window,
|
||||
proto,
|
||||
|
@ -134,21 +155,18 @@ impl CSSStyleSheet {
|
|||
self.style_stylesheet.disabled()
|
||||
}
|
||||
|
||||
pub(crate) fn get_owner(&self) -> Option<DomRoot<Element>> {
|
||||
self.owner.get()
|
||||
pub(crate) fn owner_node(&self) -> Option<DomRoot<Element>> {
|
||||
self.owner_node.get()
|
||||
}
|
||||
|
||||
pub(crate) fn set_disabled(&self, disabled: bool) {
|
||||
if self.style_stylesheet.set_disabled(disabled) && self.get_owner().is_some() {
|
||||
self.get_owner()
|
||||
.unwrap()
|
||||
.stylesheet_list_owner()
|
||||
.invalidate_stylesheets();
|
||||
if self.style_stylesheet.set_disabled(disabled) {
|
||||
self.notify_invalidations();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_owner(&self, value: Option<&Element>) {
|
||||
self.owner.set(value);
|
||||
pub(crate) fn set_owner_node(&self, value: Option<&Element>) {
|
||||
self.owner_node.set(value);
|
||||
}
|
||||
|
||||
pub(crate) fn shared_lock(&self) -> &SharedRwLock {
|
||||
|
@ -159,6 +177,10 @@ impl CSSStyleSheet {
|
|||
&self.style_stylesheet
|
||||
}
|
||||
|
||||
pub(crate) fn style_stylesheet_arc(&self) -> &Arc<StyleStyleSheet> {
|
||||
&self.style_stylesheet
|
||||
}
|
||||
|
||||
pub(crate) fn set_origin_clean(&self, origin_clean: bool) {
|
||||
self.origin_clean.set(origin_clean);
|
||||
}
|
||||
|
@ -175,7 +197,39 @@ impl CSSStyleSheet {
|
|||
/// <https://drafts.csswg.org/cssom/#concept-css-style-sheet-constructed-flag>
|
||||
#[inline]
|
||||
pub(crate) fn is_constructed(&self) -> bool {
|
||||
self.is_constructed
|
||||
self.constructor_document.is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn constructor_document_matches(&self, other_doc: &Document) -> bool {
|
||||
match &self.constructor_document {
|
||||
Some(doc) => *doc == other_doc,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a [StyleSheetListOwner] as an adopter to be notified whenever this stylesheet is
|
||||
/// modified.
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
pub(crate) fn add_adopter(&self, owner: StyleSheetListOwner) {
|
||||
debug_assert!(self.is_constructed());
|
||||
self.adopters.borrow_mut().push(owner);
|
||||
}
|
||||
|
||||
pub(crate) fn remove_adopter(&self, owner: &StyleSheetListOwner) {
|
||||
let adopters = &mut *self.adopters.borrow_mut();
|
||||
if let Some(index) = adopters.iter().position(|o| o == owner) {
|
||||
adopters.swap_remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
/// Invalidate all stylesheet set this stylesheet is a part on.
|
||||
pub(crate) fn notify_invalidations(&self) {
|
||||
if let Some(owner) = self.owner_node() {
|
||||
owner.stylesheet_list_owner().invalidate_stylesheets();
|
||||
}
|
||||
for adopter in self.adopters.borrow().iter() {
|
||||
adopter.invalidate_stylesheets();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,7 +272,7 @@ impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
|
|||
None, // href
|
||||
None, // title
|
||||
stylesheet,
|
||||
true, // is_constructed
|
||||
Some(&window.Document()), // constructor_document
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
@ -294,7 +348,7 @@ impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
|
|||
/// <https://drafts.csswg.org/cssom/#synchronously-replace-the-rules-of-a-cssstylesheet>
|
||||
fn ReplaceSync(&self, text: USVString) -> Result<(), Error> {
|
||||
// Step 1. If the constructed flag is not set throw a NotAllowedError
|
||||
if !self.is_constructed {
|
||||
if !self.is_constructed() {
|
||||
return Err(Error::NotAllowed);
|
||||
}
|
||||
|
||||
|
@ -316,6 +370,9 @@ impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
|
|||
// at the next getter access.
|
||||
self.rulelist.set(None);
|
||||
|
||||
// Notify invalidation to update the styles immediately.
|
||||
self.notify_invalidations();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ use fnv::FnvHashMap;
|
|||
use html5ever::{LocalName, Namespace, QualName, local_name, ns};
|
||||
use hyper_serde::Serde;
|
||||
use ipc_channel::ipc;
|
||||
use js::rust::{HandleObject, HandleValue};
|
||||
use js::rust::{HandleObject, HandleValue, MutableHandleValue};
|
||||
use keyboard_types::{Code, Key, KeyState, Modifiers};
|
||||
use layout_api::{
|
||||
PendingRestyle, ReflowGoal, RestyleReason, TrustedNodeAddress, node_id_from_scroll_id,
|
||||
|
@ -58,6 +58,7 @@ use profile_traits::ipc as profile_ipc;
|
|||
use profile_traits::time::TimerMetadataFrameType;
|
||||
use regex::bytes::Regex;
|
||||
use script_bindings::interfaces::DocumentHelpers;
|
||||
use script_bindings::script_runtime::JSContext;
|
||||
use script_traits::{ConstellationInputEvent, DocumentActivity, ProgressiveWebMetricType};
|
||||
use servo_arc::Arc;
|
||||
use servo_config::pref;
|
||||
|
@ -114,6 +115,7 @@ use crate::dom::bindings::domname::{
|
|||
self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
|
||||
};
|
||||
use crate::dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible};
|
||||
use crate::dom::bindings::frozenarray::CachedFrozenArray;
|
||||
use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||
|
@ -564,6 +566,12 @@ pub(crate) struct Document {
|
|||
active_keyboard_modifiers: Cell<Modifiers>,
|
||||
/// The node that is currently highlighted by the devtools
|
||||
highlighted_dom_node: MutNullableDom<Node>,
|
||||
/// The constructed stylesheet that is adopted by this [Document].
|
||||
/// <https://drafts.csswg.org/cssom/#dom-documentorshadowroot-adoptedstylesheets>
|
||||
adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
|
||||
/// Cached frozen array of [`Self::adopted_stylesheets`]
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
adopted_stylesheets_frozen_types: CachedFrozenArray,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
|
@ -4253,6 +4261,8 @@ impl Document {
|
|||
intersection_observers: Default::default(),
|
||||
active_keyboard_modifiers: Cell::new(Modifiers::empty()),
|
||||
highlighted_dom_node: Default::default(),
|
||||
adopted_stylesheets: Default::default(),
|
||||
adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4898,26 +4908,30 @@ impl Document {
|
|||
.and_then(|s| s.owner.get_cssom_object())
|
||||
}
|
||||
|
||||
/// Add a stylesheet owned by `owner` to the list of document sheets, in the
|
||||
/// correct tree position.
|
||||
/// Add a stylesheet owned by `owner_node` to the list of document sheets, in the
|
||||
/// correct tree position. Additionally, ensure that the owned stylesheet is inserted
|
||||
/// before any constructed stylesheet.
|
||||
///
|
||||
/// <https://drafts.csswg.org/cssom/#documentorshadowroot-final-css-style-sheets>
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
|
||||
pub(crate) fn add_stylesheet(&self, owner: StylesheetSource, sheet: Arc<Stylesheet>) {
|
||||
pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
|
||||
let stylesheets = &mut *self.stylesheets.borrow_mut();
|
||||
|
||||
// TODO(stevennovayo): support constructed stylesheet for adopted stylesheet and its ordering
|
||||
let insertion_point = match &owner {
|
||||
StylesheetSource::Element(owner_elem) => stylesheets
|
||||
.iter()
|
||||
.map(|(sheet, _origin)| sheet)
|
||||
.find(|sheet_in_doc| match sheet_in_doc.owner {
|
||||
StylesheetSource::Element(ref other_elem) => {
|
||||
owner_elem.upcast::<Node>().is_before(other_elem.upcast())
|
||||
// FIXME(stevennovaryo): This is almost identical with the one in ShadowRoot::add_stylesheet.
|
||||
let insertion_point = stylesheets
|
||||
.iter()
|
||||
.map(|(sheet, _origin)| sheet)
|
||||
.find(|sheet_in_doc| {
|
||||
match &sheet_in_doc.owner {
|
||||
StylesheetSource::Element(other_node) => {
|
||||
owner_node.upcast::<Node>().is_before(other_node.upcast())
|
||||
},
|
||||
StylesheetSource::Constructed(_) => unreachable!(),
|
||||
})
|
||||
.cloned(),
|
||||
StylesheetSource::Constructed(_) => unreachable!(),
|
||||
};
|
||||
// Non-constructed stylesheet should be ordered before the
|
||||
// constructed ones.
|
||||
StylesheetSource::Constructed(_) => true,
|
||||
}
|
||||
})
|
||||
.cloned();
|
||||
|
||||
if self.has_browsing_context() {
|
||||
self.window.layout_mut().add_stylesheet(
|
||||
|
@ -4927,7 +4941,40 @@ impl Document {
|
|||
}
|
||||
|
||||
DocumentOrShadowRoot::add_stylesheet(
|
||||
owner,
|
||||
StylesheetSource::Element(Dom::from_ref(owner_node)),
|
||||
StylesheetSetRef::Document(stylesheets),
|
||||
sheet,
|
||||
insertion_point,
|
||||
self.style_shared_lock(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Append a constructed stylesheet to the back of document stylesheet set. Because
|
||||
/// it would be the last element, we therefore would not mess with the ordering.
|
||||
///
|
||||
/// <https://drafts.csswg.org/cssom/#documentorshadowroot-final-css-style-sheets>
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
|
||||
debug_assert!(cssom_stylesheet.is_constructed());
|
||||
|
||||
let stylesheets = &mut *self.stylesheets.borrow_mut();
|
||||
let sheet = cssom_stylesheet.style_stylesheet_arc().clone();
|
||||
|
||||
let insertion_point = stylesheets
|
||||
.iter()
|
||||
.last()
|
||||
.map(|(sheet, _origin)| sheet)
|
||||
.cloned();
|
||||
|
||||
if self.has_browsing_context() {
|
||||
self.window.layout_mut().add_stylesheet(
|
||||
sheet.clone(),
|
||||
insertion_point.as_ref().map(|s| s.sheet.clone()),
|
||||
);
|
||||
}
|
||||
|
||||
DocumentOrShadowRoot::add_stylesheet(
|
||||
StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
|
||||
StylesheetSetRef::Document(stylesheets),
|
||||
sheet,
|
||||
insertion_point,
|
||||
|
@ -6719,6 +6766,40 @@ impl DocumentMethods<crate::DomTypeHolder> for Document {
|
|||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#dom-documentorshadowroot-adoptedstylesheets>
|
||||
fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
|
||||
self.adopted_stylesheets_frozen_types.get_or_init(
|
||||
|| {
|
||||
self.adopted_stylesheets
|
||||
.borrow()
|
||||
.clone()
|
||||
.iter()
|
||||
.map(|sheet| sheet.as_rooted())
|
||||
.collect()
|
||||
},
|
||||
context,
|
||||
retval,
|
||||
can_gc,
|
||||
);
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#dom-documentorshadowroot-adoptedstylesheets>
|
||||
fn SetAdoptedStyleSheets(&self, context: JSContext, val: HandleValue) -> ErrorResult {
|
||||
let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
|
||||
context,
|
||||
self.adopted_stylesheets.borrow_mut().as_mut(),
|
||||
val,
|
||||
&StyleSheetListOwner::Document(Dom::from_ref(self)),
|
||||
);
|
||||
|
||||
// If update is successful, clear the FrozenArray cache.
|
||||
if result.is_ok() {
|
||||
self.adopted_stylesheets_frozen_types.clear()
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn update_with_current_instant(marker: &Cell<Option<CrossProcessInstant>>) {
|
||||
|
|
|
@ -2,12 +2,17 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
|
||||
use embedder_traits::UntrustedNodeAddress;
|
||||
use euclid::default::Point2D;
|
||||
use js::rust::HandleValue;
|
||||
use layout_api::{NodesFromPointQueryType, QueryMsg};
|
||||
use script_bindings::error::{Error, ErrorResult};
|
||||
use script_bindings::script_runtime::JSContext;
|
||||
use servo_arc::Arc;
|
||||
use servo_config::pref;
|
||||
use style::invalidation::media_queries::{MediaListKey, ToMediaListKey};
|
||||
use style::media_queries::MediaList;
|
||||
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard};
|
||||
|
@ -19,6 +24,7 @@ use super::bindings::trace::HashMapTracedValues;
|
|||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::NodeBinding::Node_Binding::NodeMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootMethods;
|
||||
use crate::dom::bindings::conversions::{ConversionResult, SafeFromJSValConvertible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
|
@ -26,6 +32,7 @@ use crate::dom::element::Element;
|
|||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::node::{self, Node, VecPreOrderInsertionHelper};
|
||||
use crate::dom::shadowroot::ShadowRoot;
|
||||
use crate::dom::stylesheetlist::StyleSheetListOwner;
|
||||
use crate::dom::types::CSSStyleSheet;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
@ -37,8 +44,6 @@ use crate::stylesheet_set::StylesheetSetRef;
|
|||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
pub(crate) enum StylesheetSource {
|
||||
Element(Dom<Element>),
|
||||
// TODO(stevennovaryo): This type of enum would not be used until we implement adopted stylesheet
|
||||
#[allow(dead_code)]
|
||||
Constructed(Dom<CSSStyleSheet>),
|
||||
}
|
||||
|
||||
|
@ -56,6 +61,10 @@ impl StylesheetSource {
|
|||
StylesheetSource::Constructed(ss) => ss.is_constructed(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_constructed(&self) -> bool {
|
||||
matches!(self, StylesheetSource::Constructed(_))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
||||
|
@ -285,6 +294,10 @@ impl DocumentOrShadowRoot {
|
|||
) {
|
||||
debug_assert!(owner.is_a_valid_owner(), "Wat");
|
||||
|
||||
if owner.is_constructed() && !pref!(dom_adoptedstylesheet_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let sheet = ServoStylesheetInDocument { sheet, owner };
|
||||
|
||||
let guard = style_shared_lock.read();
|
||||
|
@ -345,4 +358,111 @@ impl DocumentOrShadowRoot {
|
|||
let elements = id_map.entry(id.clone()).or_default();
|
||||
elements.insert_pre_order(element, &root);
|
||||
}
|
||||
|
||||
/// Inner part of adopted stylesheet. We are setting it by, assuming it is a FrozenArray
|
||||
/// instead of an ObservableArray. Thus, it would have a completely different workflow
|
||||
/// compared to the spec. The workflow here is actually following Gecko's implementation
|
||||
/// of AdoptedStylesheet before the implementation of ObservableArray.
|
||||
///
|
||||
/// The main purpose from this function is to set the `&mut adopted_stylesheet` to match
|
||||
/// `incoming_stylesheet` and update the corresponding Styleset in a Document or a ShadowRoot.
|
||||
/// In case of duplicates, the setter will respect the last duplicates.
|
||||
///
|
||||
/// <https://drafts.csswg.org/cssom/#dom-documentorshadowroot-adoptedstylesheets>
|
||||
// TODO: Handle duplicated adoptedstylesheet correctly, Stylo is preventing duplicates inside a
|
||||
// Stylesheet Set. But this is not ideal. https://bugzilla.mozilla.org/show_bug.cgi?id=1978755
|
||||
fn set_adopted_stylesheet(
|
||||
adopted_stylesheets: &mut Vec<Dom<CSSStyleSheet>>,
|
||||
incoming_stylesheets: &[Dom<CSSStyleSheet>],
|
||||
owner: &StyleSheetListOwner,
|
||||
) -> ErrorResult {
|
||||
if !pref!(dom_adoptedstylesheet_enabled) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let owner_doc = match owner {
|
||||
StyleSheetListOwner::Document(doc) => doc,
|
||||
StyleSheetListOwner::ShadowRoot(root) => root.owner_doc(),
|
||||
};
|
||||
|
||||
for sheet in incoming_stylesheets.iter() {
|
||||
// > If value’s constructed flag is not set, or its constructor document is not equal
|
||||
// > to this DocumentOrShadowRoot’s node document, throw a "NotAllowedError" DOMException.
|
||||
if !sheet.constructor_document_matches(owner_doc) {
|
||||
return Err(Error::NotAllowed);
|
||||
}
|
||||
}
|
||||
|
||||
// The set to check for the duplicates when removing the old stylesheets.
|
||||
let mut stylesheet_remove_set = HashSet::with_capacity(adopted_stylesheets.len());
|
||||
|
||||
// Remove the old stylesheets from the StyleSet. This workflow is limited by utilities
|
||||
// Stylo StyleSet given to us.
|
||||
// TODO(stevennovaryo): we could optimize this by maintaining the longest common prefix
|
||||
// but we should consider the implementation of ObservableArray as well.
|
||||
for sheet_to_remove in adopted_stylesheets.iter() {
|
||||
// Check for duplicates, only proceed with the removal if the stylesheet is not removed yet.
|
||||
if stylesheet_remove_set.insert(sheet_to_remove) {
|
||||
owner.remove_stylesheet(
|
||||
StylesheetSource::Constructed(sheet_to_remove.clone()),
|
||||
sheet_to_remove.style_stylesheet_arc(),
|
||||
);
|
||||
sheet_to_remove.remove_adopter(owner);
|
||||
}
|
||||
}
|
||||
|
||||
// The set to check for the duplicates when adding a new stylesheet.
|
||||
let mut stylesheet_add_set = HashSet::with_capacity(incoming_stylesheets.len());
|
||||
|
||||
// Readd all stylesheet to the StyleSet. This workflow is limited by the utilities
|
||||
// Stylo StyleSet given to us.
|
||||
for sheet in incoming_stylesheets.iter() {
|
||||
// Check for duplicates.
|
||||
if !stylesheet_add_set.insert(sheet) {
|
||||
// The idea is that this case is rare, so we pay the price of removing the
|
||||
// old sheet from the styles and append it later rather than the other way
|
||||
// around.
|
||||
owner.remove_stylesheet(
|
||||
StylesheetSource::Constructed(sheet.clone()),
|
||||
sheet.style_stylesheet_arc(),
|
||||
);
|
||||
} else {
|
||||
sheet.add_adopter(owner.clone());
|
||||
}
|
||||
|
||||
owner.append_constructed_stylesheet(sheet);
|
||||
}
|
||||
|
||||
*adopted_stylesheets = incoming_stylesheets.to_vec();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set adoptedStylesheet given a js value by converting and passing the converted
|
||||
/// values to the inner [DocumentOrShadowRoot::set_adopted_stylesheet].
|
||||
pub(crate) fn set_adopted_stylesheet_from_jsval(
|
||||
context: JSContext,
|
||||
adopted_stylesheets: &mut Vec<Dom<CSSStyleSheet>>,
|
||||
incoming_value: HandleValue,
|
||||
owner: &StyleSheetListOwner,
|
||||
) -> ErrorResult {
|
||||
let maybe_stylesheets =
|
||||
Vec::<DomRoot<CSSStyleSheet>>::safe_from_jsval(context, incoming_value, ());
|
||||
|
||||
match maybe_stylesheets {
|
||||
Ok(ConversionResult::Success(stylesheets)) => {
|
||||
rooted_vec!(let stylesheets <- stylesheets.to_owned().iter().map(|s| s.as_traced()));
|
||||
|
||||
DocumentOrShadowRoot::set_adopted_stylesheet(
|
||||
adopted_stylesheets,
|
||||
&stylesheets,
|
||||
owner,
|
||||
)
|
||||
},
|
||||
Ok(ConversionResult::Failure(msg)) => Err(Error::Type(msg.to_string())),
|
||||
Err(_) => Err(Error::Type(
|
||||
"The provided value is not a sequence of 'CSSStylesheet'.".to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,8 +185,7 @@ impl HTMLLinkElement {
|
|||
}
|
||||
*self.stylesheet.borrow_mut() = Some(s.clone());
|
||||
self.clean_stylesheet_ownership();
|
||||
stylesheets_owner
|
||||
.add_stylesheet(StylesheetSource::Element(Dom::from_ref(self.upcast())), s);
|
||||
stylesheets_owner.add_owned_stylesheet(self.upcast(), s);
|
||||
}
|
||||
|
||||
pub(crate) fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
|
||||
|
@ -203,7 +202,7 @@ impl HTMLLinkElement {
|
|||
None, // todo handle location
|
||||
None, // todo handle title
|
||||
sheet,
|
||||
false, // is_constructed
|
||||
None, // constructor_document
|
||||
can_gc,
|
||||
)
|
||||
})
|
||||
|
@ -222,7 +221,7 @@ impl HTMLLinkElement {
|
|||
|
||||
fn clean_stylesheet_ownership(&self) {
|
||||
if let Some(cssom_stylesheet) = self.cssom_stylesheet.get() {
|
||||
cssom_stylesheet.set_owner(None);
|
||||
cssom_stylesheet.set_owner_node(None);
|
||||
}
|
||||
self.cssom_stylesheet.set(None);
|
||||
}
|
||||
|
|
|
@ -160,8 +160,7 @@ impl HTMLStyleElement {
|
|||
}
|
||||
*self.stylesheet.borrow_mut() = Some(s.clone());
|
||||
self.clean_stylesheet_ownership();
|
||||
stylesheets_owner
|
||||
.add_stylesheet(StylesheetSource::Element(Dom::from_ref(self.upcast())), s);
|
||||
stylesheets_owner.add_owned_stylesheet(self.upcast(), s);
|
||||
}
|
||||
|
||||
pub(crate) fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
|
||||
|
@ -178,7 +177,7 @@ impl HTMLStyleElement {
|
|||
None, // todo handle location
|
||||
None, // todo handle title
|
||||
sheet,
|
||||
false, // is_constructed
|
||||
None, // constructor_document
|
||||
CanGc::note(),
|
||||
)
|
||||
})
|
||||
|
@ -187,7 +186,7 @@ impl HTMLStyleElement {
|
|||
|
||||
fn clean_stylesheet_ownership(&self) {
|
||||
if let Some(cssom_stylesheet) = self.cssom_stylesheet.get() {
|
||||
cssom_stylesheet.set_owner(None);
|
||||
cssom_stylesheet.set_owner_node(None);
|
||||
}
|
||||
self.cssom_stylesheet.set(None);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@ use std::collections::hash_map::Entry;
|
|||
|
||||
use dom_struct::dom_struct;
|
||||
use html5ever::serialize::TraversalScope;
|
||||
use js::rust::{HandleValue, MutableHandleValue};
|
||||
use script_bindings::error::ErrorResult;
|
||||
use script_bindings::script_runtime::JSContext;
|
||||
use servo_arc::Arc;
|
||||
use style::author_styles::AuthorStyles;
|
||||
use style::dom::TElement;
|
||||
|
@ -24,6 +27,7 @@ use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Bindi
|
|||
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
|
||||
ShadowRootMode, SlotAssignmentMode,
|
||||
};
|
||||
use crate::dom::bindings::frozenarray::CachedFrozenArray;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object;
|
||||
|
@ -92,6 +96,14 @@ pub(crate) struct ShadowRoot {
|
|||
|
||||
/// <https://dom.spec.whatwg.org/#shadowroot-delegates-focus>
|
||||
delegates_focus: Cell<bool>,
|
||||
|
||||
/// The constructed stylesheet that is adopted by this [ShadowRoot].
|
||||
/// <https://drafts.csswg.org/cssom/#dom-documentorshadowroot-adoptedstylesheets>
|
||||
adopted_stylesheets: DomRefCell<Vec<Dom<CSSStyleSheet>>>,
|
||||
|
||||
/// Cached frozen array of [`Self::adopted_stylesheets`]
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
adopted_stylesheets_frozen_types: CachedFrozenArray,
|
||||
}
|
||||
|
||||
impl ShadowRoot {
|
||||
|
@ -129,6 +141,8 @@ impl ShadowRoot {
|
|||
declarative: Cell::new(false),
|
||||
serializable: Cell::new(false),
|
||||
delegates_focus: Cell::new(false),
|
||||
adopted_stylesheets: Default::default(),
|
||||
adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,6 +177,10 @@ impl ShadowRoot {
|
|||
self.host.set(None);
|
||||
}
|
||||
|
||||
pub(crate) fn owner_doc(&self) -> &Document {
|
||||
&self.document
|
||||
}
|
||||
|
||||
pub(crate) fn get_focused_element(&self) -> Option<DomRoot<Element>> {
|
||||
//XXX get retargeted focused element
|
||||
None
|
||||
|
@ -180,28 +198,51 @@ impl ShadowRoot {
|
|||
.and_then(|s| s.owner.get_cssom_object())
|
||||
}
|
||||
|
||||
/// Add a stylesheet owned by `owner` to the list of shadow root sheets, in the
|
||||
/// correct tree position.
|
||||
/// Add a stylesheet owned by `owner_node` to the list of shadow root sheets, in the
|
||||
/// correct tree position. Additionally, ensure that owned stylesheet is inserted before
|
||||
/// any constructed stylesheet.
|
||||
///
|
||||
/// <https://drafts.csswg.org/cssom/#documentorshadowroot-final-css-style-sheets>
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
|
||||
pub(crate) fn add_stylesheet(&self, owner: StylesheetSource, sheet: Arc<Stylesheet>) {
|
||||
pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
|
||||
let stylesheets = &mut self.author_styles.borrow_mut().stylesheets;
|
||||
|
||||
// TODO(stevennovayo): support constructed stylesheet for adopted stylesheet and its ordering
|
||||
let insertion_point = match &owner {
|
||||
StylesheetSource::Element(owner_elem) => stylesheets
|
||||
.iter()
|
||||
.find(|sheet_in_shadow| match sheet_in_shadow.owner {
|
||||
StylesheetSource::Element(ref other_elem) => {
|
||||
owner_elem.upcast::<Node>().is_before(other_elem.upcast())
|
||||
// FIXME(stevennovaryo): This is almost identical with the one in Document::add_stylesheet.
|
||||
let insertion_point = stylesheets
|
||||
.iter()
|
||||
.find(|sheet_in_shadow| {
|
||||
match &sheet_in_shadow.owner {
|
||||
StylesheetSource::Element(other_node) => {
|
||||
owner_node.upcast::<Node>().is_before(other_node.upcast())
|
||||
},
|
||||
StylesheetSource::Constructed(_) => unreachable!(),
|
||||
})
|
||||
.cloned(),
|
||||
StylesheetSource::Constructed(_) => unreachable!(),
|
||||
};
|
||||
// Non-constructed stylesheet should be ordered before the
|
||||
// constructed ones.
|
||||
StylesheetSource::Constructed(_) => true,
|
||||
}
|
||||
})
|
||||
.cloned();
|
||||
|
||||
DocumentOrShadowRoot::add_stylesheet(
|
||||
owner,
|
||||
StylesheetSource::Element(Dom::from_ref(owner_node)),
|
||||
StylesheetSetRef::Author(stylesheets),
|
||||
sheet,
|
||||
insertion_point,
|
||||
self.document.style_shared_lock(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Append a constructed stylesheet to the back of shadow root stylesheet set.
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
|
||||
debug_assert!(cssom_stylesheet.is_constructed());
|
||||
|
||||
let stylesheets = &mut self.author_styles.borrow_mut().stylesheets;
|
||||
let sheet = cssom_stylesheet.style_stylesheet_arc().clone();
|
||||
|
||||
let insertion_point = stylesheets.iter().last().cloned();
|
||||
|
||||
DocumentOrShadowRoot::add_stylesheet(
|
||||
StylesheetSource::Constructed(Dom::from_ref(cssom_stylesheet)),
|
||||
StylesheetSetRef::Author(stylesheets),
|
||||
sheet,
|
||||
insertion_point,
|
||||
|
@ -473,6 +514,40 @@ impl ShadowRootMethods<crate::DomTypeHolder> for ShadowRoot {
|
|||
|
||||
// https://dom.spec.whatwg.org/#dom-shadowroot-onslotchange
|
||||
event_handler!(onslotchange, GetOnslotchange, SetOnslotchange);
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#dom-documentorshadowroot-adoptedstylesheets>
|
||||
fn AdoptedStyleSheets(&self, context: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
|
||||
self.adopted_stylesheets_frozen_types.get_or_init(
|
||||
|| {
|
||||
self.adopted_stylesheets
|
||||
.borrow()
|
||||
.clone()
|
||||
.iter()
|
||||
.map(|sheet| sheet.as_rooted())
|
||||
.collect()
|
||||
},
|
||||
context,
|
||||
retval,
|
||||
can_gc,
|
||||
);
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#dom-documentorshadowroot-adoptedstylesheets>
|
||||
fn SetAdoptedStyleSheets(&self, context: JSContext, val: HandleValue) -> ErrorResult {
|
||||
let result = DocumentOrShadowRoot::set_adopted_stylesheet_from_jsval(
|
||||
context,
|
||||
self.adopted_stylesheets.borrow_mut().as_mut(),
|
||||
val,
|
||||
&StyleSheetListOwner::ShadowRoot(Dom::from_ref(self)),
|
||||
);
|
||||
|
||||
// If update is successful, clear the FrozenArray cache.
|
||||
if result.is_ok() {
|
||||
self.adopted_stylesheets_frozen_types.clear();
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualMethods for ShadowRoot {
|
||||
|
@ -485,6 +560,8 @@ impl VirtualMethods for ShadowRoot {
|
|||
s.bind_to_tree(context, can_gc);
|
||||
}
|
||||
|
||||
// TODO(stevennovaryo): Handle adoptedStylesheet to deal with different
|
||||
// constructor document.
|
||||
if context.tree_connected {
|
||||
let document = self.owner_document();
|
||||
document.register_shadow_root(self);
|
||||
|
|
|
@ -51,7 +51,8 @@ impl StyleSheetMethods<crate::DomTypeHolder> for StyleSheet {
|
|||
|
||||
// https://drafts.csswg.org/cssom/#dom-stylesheet-ownernode
|
||||
fn GetOwnerNode(&self) -> Option<DomRoot<Element>> {
|
||||
self.downcast::<CSSStyleSheet>().and_then(|s| s.get_owner())
|
||||
self.downcast::<CSSStyleSheet>()
|
||||
.and_then(|s| s.owner_node())
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom/#dom-stylesheet-media
|
||||
|
|
|
@ -12,13 +12,14 @@ use crate::dom::bindings::root::{Dom, DomRoot};
|
|||
use crate::dom::cssstylesheet::CSSStyleSheet;
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::documentorshadowroot::StylesheetSource;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::shadowroot::ShadowRoot;
|
||||
use crate::dom::stylesheet::StyleSheet;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
|
||||
pub(crate) enum StyleSheetListOwner {
|
||||
Document(Dom<Document>),
|
||||
ShadowRoot(Dom<ShadowRoot>),
|
||||
|
@ -39,12 +40,23 @@ impl StyleSheetListOwner {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
|
||||
pub(crate) fn add_stylesheet(&self, owner: StylesheetSource, sheet: Arc<Stylesheet>) {
|
||||
pub(crate) fn add_owned_stylesheet(&self, owner_node: &Element, sheet: Arc<Stylesheet>) {
|
||||
match *self {
|
||||
StyleSheetListOwner::Document(ref doc) => doc.add_stylesheet(owner, sheet),
|
||||
StyleSheetListOwner::Document(ref doc) => doc.add_owned_stylesheet(owner_node, sheet),
|
||||
StyleSheetListOwner::ShadowRoot(ref shadow_root) => {
|
||||
shadow_root.add_stylesheet(owner, sheet)
|
||||
shadow_root.add_owned_stylesheet(owner_node, sheet)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
pub(crate) fn append_constructed_stylesheet(&self, cssom_stylesheet: &CSSStyleSheet) {
|
||||
match *self {
|
||||
StyleSheetListOwner::Document(ref doc) => {
|
||||
doc.append_constructed_stylesheet(cssom_stylesheet)
|
||||
},
|
||||
StyleSheetListOwner::ShadowRoot(ref shadow_root) => {
|
||||
shadow_root.append_constructed_stylesheet(cssom_stylesheet)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ DOMInterfaces = {
|
|||
|
||||
'Document': {
|
||||
'additionalTraits': ["crate::interfaces::DocumentHelpers"],
|
||||
'canGc': ['Close', 'CreateElement', 'CreateElementNS', 'ImportNode', 'SetTitle', 'Write', 'Writeln', 'CreateEvent', 'CreateRange', 'Open', 'Open_', 'CreateComment', 'CreateAttribute', 'CreateAttributeNS', 'CreateDocumentFragment', 'CreateTextNode', 'CreateCDATASection', 'CreateProcessingInstruction', 'Prepend', 'Append', 'ReplaceChildren', 'SetBgColor', 'SetFgColor', 'Fonts', 'ElementFromPoint', 'ElementsFromPoint', 'GetScrollingElement', 'ExitFullscreen', 'CreateExpression', 'CreateNSResolver', 'Evaluate', 'StyleSheets', 'Implementation', 'GetElementsByTagName', 'GetElementsByTagNameNS', 'GetElementsByClassName', 'AdoptNode', 'CreateNodeIterator', 'SetBody', 'GetElementsByName', 'Images', 'Embeds', 'Plugins', 'Links', 'Forms', 'Scripts', 'Anchors', 'Applets', 'Children', 'GetSelection', 'NamedGetter'],
|
||||
'canGc': ['Close', 'CreateElement', 'CreateElementNS', 'ImportNode', 'SetTitle', 'Write', 'Writeln', 'CreateEvent', 'CreateRange', 'Open', 'Open_', 'CreateComment', 'CreateAttribute', 'CreateAttributeNS', 'CreateDocumentFragment', 'CreateTextNode', 'CreateCDATASection', 'CreateProcessingInstruction', 'Prepend', 'Append', 'ReplaceChildren', 'SetBgColor', 'SetFgColor', 'Fonts', 'ElementFromPoint', 'ElementsFromPoint', 'GetScrollingElement', 'ExitFullscreen', 'CreateExpression', 'CreateNSResolver', 'Evaluate', 'StyleSheets', 'Implementation', 'GetElementsByTagName', 'GetElementsByTagNameNS', 'GetElementsByClassName', 'AdoptNode', 'CreateNodeIterator', 'SetBody', 'GetElementsByName', 'Images', 'Embeds', 'Plugins', 'Links', 'Forms', 'Scripts', 'Anchors', 'Applets', 'Children', 'GetSelection', 'NamedGetter', 'AdoptedStyleSheets'],
|
||||
},
|
||||
|
||||
'DissimilarOriginWindow': {
|
||||
|
@ -586,7 +586,7 @@ DOMInterfaces = {
|
|||
},
|
||||
|
||||
'ShadowRoot': {
|
||||
'canGc': ['SetHTMLUnsafe', 'ElementFromPoint', 'ElementsFromPoint', 'SetInnerHTML', 'GetHTML', 'InnerHTML'],
|
||||
'canGc': ['SetHTMLUnsafe', 'ElementFromPoint', 'ElementsFromPoint', 'SetInnerHTML', 'GetHTML', 'InnerHTML', 'AdoptedStyleSheets'],
|
||||
},
|
||||
|
||||
'StaticRange': {
|
||||
|
|
|
@ -15,3 +15,9 @@ interface mixin DocumentOrShadowRoot {
|
|||
readonly attribute Element? activeElement;
|
||||
readonly attribute StyleSheetList styleSheets;
|
||||
};
|
||||
|
||||
partial interface mixin DocumentOrShadowRoot {
|
||||
// TODO(37902): Use ObservableArray Array when available
|
||||
[Pref="dom_adoptedstylesheet_enabled", SetterThrows]
|
||||
attribute /* ObservableArray<CSSStyleSheet> */ any adoptedStyleSheets;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue