mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Implement ShadowRoot.clonable
attribute (#34514)
* Implement ShadowRoot clonable attribute Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Update WPT expectations Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Update WPT expectations Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * ./mach test-tidy fixes Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * fix clippy warnings Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
parent
8ebb77ab76
commit
97e9841d47
8 changed files with 81 additions and 27 deletions
|
@ -507,8 +507,10 @@ impl Element {
|
||||||
/// <https://dom.spec.whatwg.org/#dom-element-attachshadow>
|
/// <https://dom.spec.whatwg.org/#dom-element-attachshadow>
|
||||||
pub fn attach_shadow(
|
pub fn attach_shadow(
|
||||||
&self,
|
&self,
|
||||||
|
// TODO: remove is_ua_widget argument
|
||||||
is_ua_widget: IsUserAgentWidget,
|
is_ua_widget: IsUserAgentWidget,
|
||||||
mode: ShadowRootMode,
|
mode: ShadowRootMode,
|
||||||
|
clonable: bool,
|
||||||
) -> Fallible<DomRoot<ShadowRoot>> {
|
) -> Fallible<DomRoot<ShadowRoot>> {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
if self.namespace != ns!(html) {
|
if self.namespace != ns!(html) {
|
||||||
|
@ -546,7 +548,7 @@ impl Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steps 4, 5 and 6.
|
// Steps 4, 5 and 6.
|
||||||
let shadow_root = ShadowRoot::new(self, &self.node.owner_doc(), mode);
|
let shadow_root = ShadowRoot::new(self, &self.node.owner_doc(), mode, clonable);
|
||||||
self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root));
|
self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root));
|
||||||
shadow_root
|
shadow_root
|
||||||
.upcast::<Node>()
|
.upcast::<Node>()
|
||||||
|
@ -3034,7 +3036,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
|
||||||
fn AttachShadow(&self, init: &ShadowRootInit) -> Fallible<DomRoot<ShadowRoot>> {
|
fn AttachShadow(&self, init: &ShadowRootInit) -> Fallible<DomRoot<ShadowRoot>> {
|
||||||
// Step 1. Run attach a shadow root with this, init["mode"], init["clonable"], init["serializable"],
|
// Step 1. Run attach a shadow root with this, init["mode"], init["clonable"], init["serializable"],
|
||||||
// init["delegatesFocus"], and init["slotAssignment"].
|
// init["delegatesFocus"], and init["slotAssignment"].
|
||||||
let shadow_root = self.attach_shadow(IsUserAgentWidget::No, init.mode)?;
|
let shadow_root = self.attach_shadow(IsUserAgentWidget::No, init.mode, init.clonable)?;
|
||||||
|
|
||||||
// Step 2. Return this’s shadow root.
|
// Step 2. Return this’s shadow root.
|
||||||
Ok(shadow_root)
|
Ok(shadow_root)
|
||||||
|
|
|
@ -1910,7 +1910,7 @@ impl HTMLMediaElement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let shadow_root = element
|
let shadow_root = element
|
||||||
.attach_shadow(IsUserAgentWidget::Yes, ShadowRootMode::Closed)
|
.attach_shadow(IsUserAgentWidget::Yes, ShadowRootMode::Closed, false)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let document = document_from_node(self);
|
let document = document_from_node(self);
|
||||||
let script = HTMLScriptElement::new(
|
let script = HTMLScriptElement::new(
|
||||||
|
|
|
@ -98,7 +98,7 @@ use crate::dom::nodelist::NodeList;
|
||||||
use crate::dom::processinginstruction::ProcessingInstruction;
|
use crate::dom::processinginstruction::ProcessingInstruction;
|
||||||
use crate::dom::range::WeakRangeVec;
|
use crate::dom::range::WeakRangeVec;
|
||||||
use crate::dom::raredata::NodeRareData;
|
use crate::dom::raredata::NodeRareData;
|
||||||
use crate::dom::shadowroot::{LayoutShadowRootHelpers, ShadowRoot};
|
use crate::dom::shadowroot::{IsUserAgentWidget, LayoutShadowRootHelpers, ShadowRoot};
|
||||||
use crate::dom::stylesheetlist::StyleSheetListOwner;
|
use crate::dom::stylesheetlist::StyleSheetListOwner;
|
||||||
use crate::dom::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement};
|
use crate::dom::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement};
|
||||||
use crate::dom::text::Text;
|
use crate::dom::text::Text;
|
||||||
|
@ -2247,13 +2247,13 @@ impl Node {
|
||||||
clone_children: CloneChildrenFlag,
|
clone_children: CloneChildrenFlag,
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> DomRoot<Node> {
|
) -> DomRoot<Node> {
|
||||||
// Step 1.
|
// Step 1. If document is not given, let document be node’s node document.
|
||||||
let document = match maybe_doc {
|
let document = match maybe_doc {
|
||||||
Some(doc) => DomRoot::from_ref(doc),
|
Some(doc) => DomRoot::from_ref(doc),
|
||||||
None => node.owner_doc(),
|
None => node.owner_doc(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 2.
|
// Step 2. / Step 3.
|
||||||
// XXXabinader: clone() for each node as trait?
|
// XXXabinader: clone() for each node as trait?
|
||||||
let copy: DomRoot<Node> = match node.type_id() {
|
let copy: DomRoot<Node> = match node.type_id() {
|
||||||
NodeTypeId::DocumentType => {
|
NodeTypeId::DocumentType => {
|
||||||
|
@ -2337,14 +2337,15 @@ impl Node {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 3.
|
// Step 4. Set copy’s node document and document to copy, if copy is a document,
|
||||||
|
// and set copy’s node document to document otherwise.
|
||||||
let document = match copy.downcast::<Document>() {
|
let document = match copy.downcast::<Document>() {
|
||||||
Some(doc) => DomRoot::from_ref(doc),
|
Some(doc) => DomRoot::from_ref(doc),
|
||||||
None => DomRoot::from_ref(&*document),
|
None => DomRoot::from_ref(&*document),
|
||||||
};
|
};
|
||||||
assert!(copy.owner_doc() == document);
|
assert!(copy.owner_doc() == document);
|
||||||
|
|
||||||
// Step 4 (some data already copied in step 2).
|
// TODO: The spec tells us to do this in step 3.
|
||||||
match node.type_id() {
|
match node.type_id() {
|
||||||
NodeTypeId::Document(_) => {
|
NodeTypeId::Document(_) => {
|
||||||
let node_doc = node.downcast::<Document>().unwrap();
|
let node_doc = node.downcast::<Document>().unwrap();
|
||||||
|
@ -2370,10 +2371,12 @@ impl Node {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5: cloning steps.
|
// Step 5: Run any cloning steps defined for node in other applicable specifications and pass copy,
|
||||||
|
// node, document, and the clone children flag if set, as parameters.
|
||||||
vtable_for(node).cloning_steps(©, maybe_doc, clone_children);
|
vtable_for(node).cloning_steps(©, maybe_doc, clone_children);
|
||||||
|
|
||||||
// Step 6.
|
// Step 6. If the clone children flag is set, then for each child child of node, in tree order: append the
|
||||||
|
// result of cloning child with document and the clone children flag set, to copy.
|
||||||
if clone_children == CloneChildrenFlag::CloneChildren {
|
if clone_children == CloneChildrenFlag::CloneChildren {
|
||||||
for child in node.children() {
|
for child in node.children() {
|
||||||
let child_copy = Node::clone(&child, Some(&document), clone_children, can_gc);
|
let child_copy = Node::clone(&child, Some(&document), clone_children, can_gc);
|
||||||
|
@ -2381,7 +2384,43 @@ impl Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 7.
|
// Step 7. If node is a shadow host whose shadow root’s clonable is true:
|
||||||
|
// NOTE: Only elements can be shadow hosts
|
||||||
|
if matches!(node.type_id(), NodeTypeId::Element(_)) {
|
||||||
|
let node_elem = node.downcast::<Element>().unwrap();
|
||||||
|
let copy_elem = copy.downcast::<Element>().unwrap();
|
||||||
|
|
||||||
|
if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
|
||||||
|
// Step 7.1 Assert: copy is not a shadow host.
|
||||||
|
assert!(!copy_elem.is_shadow_host());
|
||||||
|
|
||||||
|
// Step 7.2 Run attach a shadow root with copy, node’s shadow root’s mode, true,
|
||||||
|
// node’s shadow root’s serializable, node’s shadow root’s delegates focus,
|
||||||
|
// and node’s shadow root’s slot assignment.
|
||||||
|
let copy_shadow_root =
|
||||||
|
copy_elem.attach_shadow(IsUserAgentWidget::No, shadow_root.Mode(), true)
|
||||||
|
.expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
|
||||||
|
|
||||||
|
// TODO: Step 7.3 Set copy’s shadow root’s declarative to node’s shadow root’s declarative.
|
||||||
|
|
||||||
|
// Step 7.4 For each child child of node’s shadow root, in tree order: append the result of
|
||||||
|
// cloning child with document and the clone children flag set, to copy’s shadow root.
|
||||||
|
for child in shadow_root.upcast::<Node>().children() {
|
||||||
|
let child_copy = Node::clone(
|
||||||
|
&child,
|
||||||
|
Some(&document),
|
||||||
|
CloneChildrenFlag::CloneChildren,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: Should we handle the error case here and in step 6?
|
||||||
|
let _inserted_node =
|
||||||
|
Node::pre_insert(&child_copy, copy_shadow_root.upcast::<Node>(), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8. Return copy.
|
||||||
copy
|
copy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,11 +55,19 @@ pub struct ShadowRoot {
|
||||||
|
|
||||||
/// <https://dom.spec.whatwg.org/#dom-shadowroot-mode>
|
/// <https://dom.spec.whatwg.org/#dom-shadowroot-mode>
|
||||||
mode: ShadowRootMode,
|
mode: ShadowRootMode,
|
||||||
|
|
||||||
|
/// <https://dom.spec.whatwg.org/#dom-shadowroot-clonable>
|
||||||
|
clonable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShadowRoot {
|
impl ShadowRoot {
|
||||||
#[allow(crown::unrooted_must_root)]
|
#[allow(crown::unrooted_must_root)]
|
||||||
fn new_inherited(host: &Element, document: &Document, mode: ShadowRootMode) -> ShadowRoot {
|
fn new_inherited(
|
||||||
|
host: &Element,
|
||||||
|
document: &Document,
|
||||||
|
mode: ShadowRootMode,
|
||||||
|
clonable: bool,
|
||||||
|
) -> ShadowRoot {
|
||||||
let document_fragment = DocumentFragment::new_inherited(document);
|
let document_fragment = DocumentFragment::new_inherited(document);
|
||||||
let node = document_fragment.upcast::<Node>();
|
let node = document_fragment.upcast::<Node>();
|
||||||
node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, true);
|
node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, true);
|
||||||
|
@ -77,12 +85,18 @@ impl ShadowRoot {
|
||||||
stylesheet_list: MutNullableDom::new(None),
|
stylesheet_list: MutNullableDom::new(None),
|
||||||
window: Dom::from_ref(document.window()),
|
window: Dom::from_ref(document.window()),
|
||||||
mode,
|
mode,
|
||||||
|
clonable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(host: &Element, document: &Document, mode: ShadowRootMode) -> DomRoot<ShadowRoot> {
|
pub fn new(
|
||||||
|
host: &Element,
|
||||||
|
document: &Document,
|
||||||
|
mode: ShadowRootMode,
|
||||||
|
clonable: bool,
|
||||||
|
) -> DomRoot<ShadowRoot> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(ShadowRoot::new_inherited(host, document, mode)),
|
Box::new(ShadowRoot::new_inherited(host, document, mode, clonable)),
|
||||||
document.window(),
|
document.window(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -238,6 +252,11 @@ impl ShadowRootMethods<crate::DomTypeHolder> for ShadowRoot {
|
||||||
self.mode
|
self.mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://dom.spec.whatwg.org/#dom-shadowroot-clonable>
|
||||||
|
fn Clonable(&self) -> bool {
|
||||||
|
self.clonable
|
||||||
|
}
|
||||||
|
|
||||||
/// <https://dom.spec.whatwg.org/#dom-shadowroot-host>
|
/// <https://dom.spec.whatwg.org/#dom-shadowroot-host>
|
||||||
fn Host(&self) -> DomRoot<Element> {
|
fn Host(&self) -> DomRoot<Element> {
|
||||||
let host = self.host.get();
|
let host = self.host.get();
|
||||||
|
|
|
@ -91,7 +91,7 @@ dictionary ShadowRootInit {
|
||||||
required ShadowRootMode mode;
|
required ShadowRootMode mode;
|
||||||
// boolean delegatesFocus = false;
|
// boolean delegatesFocus = false;
|
||||||
// SlotAssignmentMode slotAssignment = "named";
|
// SlotAssignmentMode slotAssignment = "named";
|
||||||
// boolean clonable = false;
|
boolean clonable = false;
|
||||||
// boolean serializable = false;
|
// boolean serializable = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,15 @@
|
||||||
[Exposed=Window]
|
[Exposed=Window]
|
||||||
interface ShadowRoot : DocumentFragment {
|
interface ShadowRoot : DocumentFragment {
|
||||||
readonly attribute ShadowRootMode mode;
|
readonly attribute ShadowRootMode mode;
|
||||||
|
// readonly attribute boolean delegatesFocus;
|
||||||
|
// readonly attribute SlotAssignmentMode slotAssignment;
|
||||||
|
readonly attribute boolean clonable;
|
||||||
|
// readonly attribute boolean serializable;
|
||||||
readonly attribute Element host;
|
readonly attribute Element host;
|
||||||
|
// attribute EventHandler onslotchange;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum ShadowRootMode { "open", "closed"};
|
enum ShadowRootMode { "open", "closed"};
|
||||||
// enum SlotAssignmentMode { "manual", "named" };
|
// enum SlotAssignmentMode { "manual", "named" };
|
||||||
|
|
||||||
|
|
3
tests/wpt/meta/dom/idlharness.window.js.ini
vendored
3
tests/wpt/meta/dom/idlharness.window.js.ini
vendored
|
@ -694,9 +694,6 @@
|
||||||
[AbortSignal interface: calling any(sequence<AbortSignal>) on new AbortController().signal with too few arguments must throw TypeError]
|
[AbortSignal interface: calling any(sequence<AbortSignal>) on new AbortController().signal with too few arguments must throw TypeError]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[ShadowRoot interface: attribute clonable]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Document interface: operation prepend((Node or TrustedScript or DOMString)...)]
|
[Document interface: operation prepend((Node or TrustedScript or DOMString)...)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
[shadow-root-clonable.html]
|
[shadow-root-clonable.html]
|
||||||
[attachShadow with clonable: true]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attachShadow with clonable: false]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attachShadow with clonable: undefined]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[declarative shadow roots do *not* get clonable: true automatically]
|
[declarative shadow roots do *not* get clonable: true automatically]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue