diff options
author | Simon Wülker <simon.wuelker@arcor.de> | 2024-11-21 01:22:42 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-21 00:22:42 +0000 |
commit | 527e2d426d1101b281e5b30b870859d44425465a (patch) | |
tree | 6dcfea507e3e7127b383fcbd0c62538529d6ba0a | |
parent | c5cf2621b672ff481ad1494dc280f578e146c4e0 (diff) | |
download | servo-527e2d426d1101b281e5b30b870859d44425465a.tar.gz servo-527e2d426d1101b281e5b30b870859d44425465a.zip |
Implement `element.shadowRoot` attribute (#34306)
* Implement Element.shadowRoot attribute
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Remove comments about shadowdom not being exposed for web content
This is obviously not the case anymore.
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Update WPT expectations
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
15 files changed, 209 insertions, 65 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 251f088c6ed..1c6d22c979a 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -73,11 +73,13 @@ use crate::dom::attr::{Attr, AttrHelpersForLayout}; use crate::dom::bindings::cell::{ref_filter_map, DomRefCell, Ref, RefMut}; use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; -use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; +use crate::dom::bindings::codegen::Bindings::ElementBinding::{ElementMethods, ShadowRootInit}; use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function; use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; -use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods; +use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{ + ShadowRootMethods, ShadowRootMode, +}; use crate::dom::bindings::codegen::Bindings::WindowBinding::{ ScrollBehavior, ScrollToOptions, WindowMethods, }; @@ -507,9 +509,11 @@ impl Element { } /// <https://dom.spec.whatwg.org/#dom-element-attachshadow> - /// XXX This is not exposed to web content yet. It is meant to be used - /// for UA widgets only. - pub fn attach_shadow(&self, is_ua_widget: IsUserAgentWidget) -> Fallible<DomRoot<ShadowRoot>> { + pub fn attach_shadow( + &self, + is_ua_widget: IsUserAgentWidget, + mode: ShadowRootMode, + ) -> Fallible<DomRoot<ShadowRoot>> { // Step 1. if self.namespace != ns!(html) { return Err(Error::NotSupported); @@ -546,7 +550,7 @@ impl Element { } // Steps 4, 5 and 6. - let shadow_root = ShadowRoot::new(self, &self.node.owner_doc()); + let shadow_root = ShadowRoot::new(self, &self.node.owner_doc(), mode); self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root)); shadow_root .upcast::<Node>() @@ -3050,11 +3054,29 @@ impl ElementMethods for Element { doc.enter_fullscreen(self, can_gc) } - // XXX Hidden under dom.shadowdom.enabled pref. Only exposed to be able - // to test partial Shadow DOM support for UA widgets. // https://dom.spec.whatwg.org/#dom-element-attachshadow - fn AttachShadow(&self) -> Fallible<DomRoot<ShadowRoot>> { - self.attach_shadow(IsUserAgentWidget::No) + fn AttachShadow(&self, init: &ShadowRootInit) -> Fallible<DomRoot<ShadowRoot>> { + // Step 1. Run attach a shadow root with this, init["mode"], init["clonable"], init["serializable"], + // init["delegatesFocus"], and init["slotAssignment"]. + let shadow_root = self.attach_shadow(IsUserAgentWidget::No, init.mode)?; + + // Step 2. Return this’s shadow root. + Ok(shadow_root) + } + + /// <https://dom.spec.whatwg.org/#dom-element-shadowroot> + fn GetShadowRoot(&self) -> Option<DomRoot<ShadowRoot>> { + // Step 1. Let shadow be this’s shadow root. + let shadow_or_none = self.shadow_root(); + + // Step 2. If shadow is null or its mode is "closed", then return null. + let shadow = shadow_or_none?; + if shadow.Mode() == ShadowRootMode::Closed { + return None; + } + + // Step 3. Return shadow. + Some(shadow) } fn GetRole(&self) -> Option<DOMString> { diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index e76b57e9b8b..e7aa9c274e4 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -54,6 +54,7 @@ use crate::dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorConsta use crate::dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethods; use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods; use crate::dom::bindings::codegen::Bindings::NodeBinding::Node_Binding::NodeMethods; +use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootMode; use crate::dom::bindings::codegen::Bindings::TextTrackBinding::{TextTrackKind, TextTrackMode}; use crate::dom::bindings::codegen::Bindings::URLBinding::URLMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods; @@ -1908,7 +1909,9 @@ impl HTMLMediaElement { // if we are already showing the controls. return; } - let shadow_root = element.attach_shadow(IsUserAgentWidget::Yes).unwrap(); + let shadow_root = element + .attach_shadow(IsUserAgentWidget::Yes, ShadowRootMode::Closed) + .unwrap(); let document = document_from_node(self); let script = HTMLScriptElement::new( local_name!("script"), diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 1db7f44ff63..22967bb5ad2 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -36,7 +36,7 @@ pub enum IsUserAgentWidget { Yes, } -// https://dom.spec.whatwg.org/#interface-shadowroot +/// <https://dom.spec.whatwg.org/#interface-shadowroot> #[dom_struct] pub struct ShadowRoot { document_fragment: DocumentFragment, @@ -48,11 +48,14 @@ pub struct ShadowRoot { author_styles: DomRefCell<AuthorStyles<StyleSheetInDocument>>, stylesheet_list: MutNullableDom<StyleSheetList>, window: Dom<Window>, + + /// <https://dom.spec.whatwg.org/#dom-shadowroot-mode> + mode: ShadowRootMode, } impl ShadowRoot { #[allow(crown::unrooted_must_root)] - fn new_inherited(host: &Element, document: &Document) -> ShadowRoot { + fn new_inherited(host: &Element, document: &Document, mode: ShadowRootMode) -> ShadowRoot { let document_fragment = DocumentFragment::new_inherited(document); let node = document_fragment.upcast::<Node>(); node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); @@ -60,6 +63,7 @@ impl ShadowRoot { NodeFlags::IS_CONNECTED, host.upcast::<Node>().is_connected(), ); + ShadowRoot { document_fragment, document_or_shadow_root: DocumentOrShadowRoot::new(document.window()), @@ -68,12 +72,13 @@ impl ShadowRoot { author_styles: DomRefCell::new(AuthorStyles::new()), stylesheet_list: MutNullableDom::new(None), window: Dom::from_ref(document.window()), + mode, } } - pub fn new(host: &Element, document: &Document) -> DomRoot<ShadowRoot> { + pub fn new(host: &Element, document: &Document, mode: ShadowRootMode) -> DomRoot<ShadowRoot> { reflect_dom_object( - Box::new(ShadowRoot::new_inherited(host, document)), + Box::new(ShadowRoot::new_inherited(host, document, mode)), document.window(), ) } @@ -226,7 +231,7 @@ impl ShadowRootMethods for ShadowRoot { /// <https://dom.spec.whatwg.org/#dom-shadowroot-mode> fn Mode(&self) -> ShadowRootMode { - ShadowRootMode::Closed + self.mode } /// <https://dom.spec.whatwg.org/#dom-shadowroot-host> diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl index 1a06f1394ca..4525e4ae9c8 100644 --- a/components/script/dom/webidls/Element.webidl +++ b/components/script/dom/webidls/Element.webidl @@ -83,7 +83,16 @@ interface Element : Node { [CEReactions, Throws] undefined insertAdjacentHTML(DOMString position, DOMString html); - [Throws, Pref="dom.shadowdom.enabled"] ShadowRoot attachShadow(); + [Throws, Pref="dom.shadowdom.enabled"] ShadowRoot attachShadow(ShadowRootInit init); + readonly attribute ShadowRoot? shadowRoot; +}; + +dictionary ShadowRootInit { + required ShadowRootMode mode; + // boolean delegatesFocus = false; + // SlotAssignmentMode slotAssignment = "named"; + // boolean clonable = false; + // boolean serializable = false; }; // http://dev.w3.org/csswg/cssom-view/#extensions-to-the-element-interface diff --git a/components/script/dom/webidls/ShadowRoot.webidl b/components/script/dom/webidls/ShadowRoot.webidl index b39991df4b6..c8f3e754016 100644 --- a/components/script/dom/webidls/ShadowRoot.webidl +++ b/components/script/dom/webidls/ShadowRoot.webidl @@ -13,5 +13,6 @@ interface ShadowRoot : DocumentFragment { }; enum ShadowRootMode { "open", "closed"}; +// enum SlotAssignmentMode { "manual", "named" }; ShadowRoot includes DocumentOrShadowRoot; diff --git a/tests/wpt/meta/css/css-transforms/transform-origin-in-shadow.html.ini b/tests/wpt/meta/css/css-transforms/transform-origin-in-shadow.html.ini index d83ca2cd726..5d5b580cf10 100644 --- a/tests/wpt/meta/css/css-transforms/transform-origin-in-shadow.html.ini +++ b/tests/wpt/meta/css/css-transforms/transform-origin-in-shadow.html.ini @@ -1,2 +1,3 @@ [transform-origin-in-shadow.html] - expected: ERROR + ['transform-origin' on <svg> being direct descendant of shadow root] + expected: FAIL diff --git a/tests/wpt/meta/dom/idlharness.window.js.ini b/tests/wpt/meta/dom/idlharness.window.js.ini index 40c94b08fcf..7bca20fc440 100644 --- a/tests/wpt/meta/dom/idlharness.window.js.ini +++ b/tests/wpt/meta/dom/idlharness.window.js.ini @@ -64,9 +64,6 @@ [XPathResult interface: constant STRING_TYPE on interface prototype object] expected: FAIL - [Element interface: attribute shadowRoot] - expected: FAIL - [XPathResult interface: document.evaluate("//*", document.body) must inherit property "ORDERED_NODE_ITERATOR_TYPE" with the proper type] expected: FAIL @@ -91,9 +88,6 @@ [EventTarget interface: new AbortController().signal must inherit property "removeEventListener(DOMString, EventListener?, optional (EventListenerOptions or boolean))" with the proper type] expected: FAIL - [Element interface: operation attachShadow(ShadowRootInit)] - expected: FAIL - [Document interface: xmlDoc must inherit property "createNSResolver(Node)" with the proper type] expected: FAIL @@ -124,9 +118,6 @@ [XPathResult interface: constant UNORDERED_NODE_SNAPSHOT_TYPE on interface prototype object] expected: FAIL - [Element interface: calling attachShadow(ShadowRootInit) on element with too few arguments must throw TypeError] - expected: FAIL - [XPathResult interface: constant ORDERED_NODE_SNAPSHOT_TYPE on interface object] expected: FAIL @@ -511,9 +502,6 @@ [Element interface: operation append((Node or DOMString)...)] expected: FAIL - [Element interface: element must inherit property "shadowRoot" with the proper type] - expected: FAIL - [XPathEvaluator interface: existence and properties of interface prototype object] expected: FAIL diff --git a/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow-double-nested.html.ini b/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow-double-nested.html.ini index d1c4692eae2..5108f6d77ee 100644 --- a/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow-double-nested.html.ini +++ b/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow-double-nested.html.ini @@ -1,2 +1,2 @@ [dialog-focus-shadow-double-nested.html] - expected: ERROR + expected: CRASH diff --git a/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow.html.ini b/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow.html.ini index 12a0dcd821c..13de7ade329 100644 --- a/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow.html.ini +++ b/tests/wpt/meta/html/semantics/interactive-elements/the-dialog-element/dialog-focus-shadow.html.ini @@ -1,2 +1,150 @@ [dialog-focus-shadow.html] - expected: ERROR + [show: No autofocus, no delegatesFocus, no siblings] + expected: FAIL + + [showModal: No autofocus, no delegatesFocus, no siblings] + expected: FAIL + + [show: No autofocus, no delegatesFocus, sibling before] + expected: FAIL + + [showModal: No autofocus, no delegatesFocus, sibling before] + expected: FAIL + + [show: No autofocus, no delegatesFocus, sibling after] + expected: FAIL + + [showModal: No autofocus, no delegatesFocus, sibling after] + expected: FAIL + + [show: No autofocus, yes delegatesFocus, no siblings] + expected: FAIL + + [showModal: No autofocus, yes delegatesFocus, no siblings] + expected: FAIL + + [show: No autofocus, yes delegatesFocus, sibling before] + expected: FAIL + + [showModal: No autofocus, yes delegatesFocus, sibling before] + expected: FAIL + + [show: No autofocus, yes delegatesFocus, sibling after] + expected: FAIL + + [showModal: No autofocus, yes delegatesFocus, sibling after] + expected: FAIL + + [show: Autofocus before, no delegatesFocus] + expected: FAIL + + [showModal: Autofocus before, no delegatesFocus] + expected: FAIL + + [show: Autofocus before, yes delegatesFocus] + expected: FAIL + + [showModal: Autofocus before, yes delegatesFocus] + expected: FAIL + + [show: Autofocus after, no delegatesFocus] + expected: FAIL + + [showModal: Autofocus after, no delegatesFocus] + expected: FAIL + + [show: Autofocus after, yes delegatesFocus] + expected: FAIL + + [showModal: Autofocus after, yes delegatesFocus] + expected: FAIL + + [show: Autofocus on shadow host, yes delegatesFocus, no siblings] + expected: FAIL + + [showModal: Autofocus on shadow host, yes delegatesFocus, no siblings] + expected: FAIL + + [show: Autofocus on shadow host, yes delegatesFocus, sibling before] + expected: FAIL + + [showModal: Autofocus on shadow host, yes delegatesFocus, sibling before] + expected: FAIL + + [show: Autofocus on shadow host, yes delegatesFocus, sibling after] + expected: FAIL + + [showModal: Autofocus on shadow host, yes delegatesFocus, sibling after] + expected: FAIL + + [show: Autofocus on shadow host, no delegatesFocus, no siblings] + expected: FAIL + + [showModal: Autofocus on shadow host, no delegatesFocus, no siblings] + expected: FAIL + + [show: Autofocus on shadow host, no delegatesFocus, sibling before] + expected: FAIL + + [showModal: Autofocus on shadow host, no delegatesFocus, sibling before] + expected: FAIL + + [show: Autofocus on shadow host, no delegatesFocus, sibling after] + expected: FAIL + + [showModal: Autofocus on shadow host, no delegatesFocus, sibling after] + expected: FAIL + + [show: Autofocus inside shadow tree, yes delegatesFocus, no siblings] + expected: FAIL + + [showModal: Autofocus inside shadow tree, yes delegatesFocus, no siblings] + expected: FAIL + + [show: Autofocus inside shadow tree, yes delegatesFocus, sibling before] + expected: FAIL + + [showModal: Autofocus inside shadow tree, yes delegatesFocus, sibling before] + expected: FAIL + + [show: Autofocus inside shadow tree, yes delegatesFocus, sibling after] + expected: FAIL + + [showModal: Autofocus inside shadow tree, yes delegatesFocus, sibling after] + expected: FAIL + + [show: Autofocus inside shadow tree, no delegatesFocus, no siblings] + expected: FAIL + + [showModal: Autofocus inside shadow tree, no delegatesFocus, no siblings] + expected: FAIL + + [show: Autofocus inside shadow tree, no delegatesFocus, sibling before] + expected: FAIL + + [showModal: Autofocus inside shadow tree, no delegatesFocus, sibling before] + expected: FAIL + + [show: Autofocus inside shadow tree, no delegatesFocus, sibling after] + expected: FAIL + + [showModal: Autofocus inside shadow tree, no delegatesFocus, sibling after] + expected: FAIL + + [show: Two shadow trees, both delegatesFocus, first tree doesn't have autofocus element, second does] + expected: FAIL + + [showModal: Two shadow trees, both delegatesFocus, first tree doesn't have autofocus element, second does] + expected: FAIL + + [show: No autofocus, no delegatesFocus, slotted target] + expected: FAIL + + [showModal: No autofocus, no delegatesFocus, slotted target] + expected: FAIL + + [show: Shadowroot on child, no autofocus, no delegatesFocus] + expected: FAIL + + [showModal: Shadowroot on child, no autofocus, no delegatesFocus] + expected: FAIL diff --git a/tests/wpt/meta/shadow-dom/Element-interface-attachShadow.html.ini b/tests/wpt/meta/shadow-dom/Element-interface-attachShadow.html.ini index 9b613b98e41..fc87801c777 100644 --- a/tests/wpt/meta/shadow-dom/Element-interface-attachShadow.html.ini +++ b/tests/wpt/meta/shadow-dom/Element-interface-attachShadow.html.ini @@ -1,6 +1,3 @@ [Element-interface-attachShadow.html] - [Element.attachShadow must throw a TypeError if mode is not "open" or "closed"] - expected: FAIL - [Element.attachShadow must throw a NotSupportedError if the context object already hosts a shadow tree] expected: FAIL diff --git a/tests/wpt/meta/shadow-dom/Element-interface-shadowRoot-attribute.html.ini b/tests/wpt/meta/shadow-dom/Element-interface-shadowRoot-attribute.html.ini deleted file mode 100644 index 79d1f328900..00000000000 --- a/tests/wpt/meta/shadow-dom/Element-interface-shadowRoot-attribute.html.ini +++ /dev/null @@ -1,9 +0,0 @@ -[Element-interface-shadowRoot-attribute.html] - [shadowRoot must be defined on Element prototype] - expected: FAIL - - [shadowRoot attribute must return the open shadow root associated with the element] - expected: FAIL - - [shadowRoot attribute must return null if the shadow root attached to the element is closed] - expected: FAIL diff --git a/tests/wpt/meta/shadow-dom/Node-prototype-cloneNode.html.ini b/tests/wpt/meta/shadow-dom/Node-prototype-cloneNode.html.ini index 4455907c066..6baad59fe78 100644 --- a/tests/wpt/meta/shadow-dom/Node-prototype-cloneNode.html.ini +++ b/tests/wpt/meta/shadow-dom/Node-prototype-cloneNode.html.ini @@ -4,6 +4,3 @@ [cloneNode on a shadow root in closed mode must throw a NotSupportedError] expected: FAIL - - [cloneNode on an element with an open shadow root should not clone its shadow root] - expected: FAIL diff --git a/tests/wpt/meta/shadow-dom/declarative/declarative-shadow-dom-basic.html.ini b/tests/wpt/meta/shadow-dom/declarative/declarative-shadow-dom-basic.html.ini index 2553fab5ad9..751a14f9d24 100644 --- a/tests/wpt/meta/shadow-dom/declarative/declarative-shadow-dom-basic.html.ini +++ b/tests/wpt/meta/shadow-dom/declarative/declarative-shadow-dom-basic.html.ini @@ -56,8 +56,5 @@ [Declarative Shadow DOM: template containing declarative shadow root and UA shadow root] expected: FAIL - [Declarative Shadow DOM: declarative shadow roots are not supported by the template element] - expected: FAIL - [Declarative Shadow DOM: explicit test that exceptions are not thrown] expected: FAIL diff --git a/tests/wpt/meta/shadow-dom/focus/focus-selector-delegatesFocus.html.ini b/tests/wpt/meta/shadow-dom/focus/focus-selector-delegatesFocus.html.ini index 8aba9ff8234..6752cf2abf8 100644 --- a/tests/wpt/meta/shadow-dom/focus/focus-selector-delegatesFocus.html.ini +++ b/tests/wpt/meta/shadow-dom/focus/focus-selector-delegatesFocus.html.ini @@ -8,15 +8,9 @@ [:focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=true is focused] expected: FAIL - [:focus should be removed from hosts with delegatesFocus=true when none of the elements in a nested shadow tree with delegatesFocus=true is focused] - expected: FAIL - [:focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=false is focused] expected: FAIL - [:focus should be removed from hosts with delegatesFocus=true when none of the elements in a nested shadow tree with delegatesFocus=false is focused] - expected: FAIL - [:focus applies to host with delegatesFocus=false when the shadow root's descendant has focus] expected: FAIL @@ -26,11 +20,5 @@ [:focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=true is focused] expected: FAIL - [:focus should be removed from hosts with delegatesFocus=false when none of the elements in a nested shadow tree with delegatesFocus=true is focused] - expected: FAIL - [:focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=false is focused] expected: FAIL - - [:focus should be removed from hosts with delegatesFocus=false when none of the elements in a nested shadow tree with delegatesFocus=false is focused] - expected: FAIL diff --git a/tests/wpt/meta/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/attributes/test-006.html.ini b/tests/wpt/meta/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/attributes/test-006.html.ini deleted file mode 100644 index cffed0d3bbc..00000000000 --- a/tests/wpt/meta/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/attributes/test-006.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[test-006.html] - [A_10_02_01_06_T01] - expected: FAIL |