mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Add shadow tree flags to Bind/UnbindContext (#34863)
* Rename IS_IN_DOC flag to IS_IN_A_DOCUMENT_TREE Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Add BindContext::is_in_a_shadow_tree Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Add UnbindContext::tree_is_in_shadow_tree Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * ./mach fmt Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Update test expectations Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * fix build after rebasing 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
82bc7cb5bb
commit
b6a5eaa3db
11 changed files with 77 additions and 43 deletions
|
@ -303,7 +303,10 @@ impl DocumentOrShadowRoot {
|
|||
root: DomRoot<Node>,
|
||||
) {
|
||||
debug!("Adding named element {:p}: {:p} id={}", self, element, id);
|
||||
assert!(element.upcast::<Node>().is_connected_to_tree());
|
||||
assert!(
|
||||
element.upcast::<Node>().is_in_a_document_tree() ||
|
||||
element.upcast::<Node>().is_in_a_shadow_tree()
|
||||
);
|
||||
assert!(!id.is_empty());
|
||||
let mut id_map = id_map.borrow_mut();
|
||||
let elements = id_map.entry(id.clone()).or_default();
|
||||
|
|
|
@ -544,7 +544,8 @@ impl Element {
|
|||
|
||||
let bind_context = BindContext {
|
||||
tree_connected: self.upcast::<Node>().is_connected(),
|
||||
tree_in_doc: self.upcast::<Node>().is_in_doc(),
|
||||
tree_is_in_a_document_tree: self.upcast::<Node>().is_in_a_document_tree(),
|
||||
tree_is_in_a_shadow_tree: true,
|
||||
};
|
||||
shadow_root.bind_to_tree(&bind_context);
|
||||
|
||||
|
@ -1355,7 +1356,7 @@ impl Element {
|
|||
}
|
||||
|
||||
pub fn root_element(&self) -> DomRoot<Element> {
|
||||
if self.node.is_in_doc() {
|
||||
if self.node.is_in_a_document_tree() {
|
||||
self.upcast::<Node>()
|
||||
.owner_doc()
|
||||
.GetDocumentElement()
|
||||
|
@ -3512,7 +3513,7 @@ impl VirtualMethods for Element {
|
|||
});
|
||||
|
||||
let containing_shadow_root = self.containing_shadow_root();
|
||||
if node.is_connected_to_tree() {
|
||||
if node.is_in_a_document_tree() || node.is_in_a_shadow_tree() {
|
||||
let value = attr.value().as_atom().clone();
|
||||
match mutation {
|
||||
AttributeMutation::Set(old_value) => {
|
||||
|
@ -3619,7 +3620,7 @@ impl VirtualMethods for Element {
|
|||
shadow_root.bind_to_tree(context);
|
||||
}
|
||||
|
||||
if !context.tree_connected {
|
||||
if !context.is_in_tree() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3652,7 +3653,7 @@ impl VirtualMethods for Element {
|
|||
f.unbind_form_control_from_tree();
|
||||
}
|
||||
|
||||
if !context.tree_connected {
|
||||
if !context.tree_is_in_a_document_tree && !context.tree_is_in_a_shadow_tree {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3668,7 +3669,7 @@ impl VirtualMethods for Element {
|
|||
if let Some(ref shadow_root) = self.containing_shadow_root() {
|
||||
// Only unregister the element id if the node was disconnected from it's shadow root
|
||||
// (as opposed to the whole shadow tree being disconnected as a whole)
|
||||
if !self.upcast::<Node>().is_in_shadow_tree() {
|
||||
if !self.upcast::<Node>().is_in_a_shadow_tree() {
|
||||
shadow_root.unregister_element_id(self, value.clone());
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -126,11 +126,11 @@ impl VirtualMethods for HTMLBaseElement {
|
|||
|
||||
fn bind_to_tree(&self, context: &BindContext) {
|
||||
self.super_type().unwrap().bind_to_tree(context);
|
||||
self.bind_unbind(context.tree_in_doc);
|
||||
self.bind_unbind(context.tree_is_in_a_document_tree);
|
||||
}
|
||||
|
||||
fn unbind_from_tree(&self, context: &UnbindContext) {
|
||||
self.super_type().unwrap().unbind_from_tree(context);
|
||||
self.bind_unbind(context.tree_in_doc);
|
||||
self.bind_unbind(context.tree_is_in_a_document_tree);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ impl VirtualMethods for HTMLBodyElement {
|
|||
s.bind_to_tree(context);
|
||||
}
|
||||
|
||||
if !context.tree_in_doc {
|
||||
if !context.tree_is_in_a_document_tree {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -949,7 +949,7 @@ impl HTMLScriptElement {
|
|||
|
||||
match script.type_ {
|
||||
ScriptType::Classic => {
|
||||
if self.upcast::<Node>().is_in_shadow_tree() {
|
||||
if self.upcast::<Node>().is_in_a_shadow_tree() {
|
||||
document.set_current_script(None)
|
||||
} else {
|
||||
document.set_current_script(Some(self))
|
||||
|
|
|
@ -194,7 +194,7 @@ impl VirtualMethods for HTMLStyleElement {
|
|||
// "The element is not on the stack of open elements of an HTML parser or XML parser,
|
||||
// and one of its child nodes is modified by a script."
|
||||
// TODO: Handle Text child contents being mutated.
|
||||
if self.upcast::<Node>().is_in_doc() && !self.in_stack_of_open_elements.get() {
|
||||
if self.upcast::<Node>().is_in_a_document_tree() && !self.in_stack_of_open_elements.get() {
|
||||
self.parse_own_css();
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ impl VirtualMethods for HTMLStyleElement {
|
|||
// Handles the case when:
|
||||
// "The element is popped off the stack of open elements of an HTML parser or XML parser."
|
||||
self.in_stack_of_open_elements.set(false);
|
||||
if self.upcast::<Node>().is_in_doc() {
|
||||
if self.upcast::<Node>().is_in_a_document_tree() {
|
||||
self.parse_own_css();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ impl HTMLTitleElement {
|
|||
|
||||
fn notify_title_changed(&self) {
|
||||
let node = self.upcast::<Node>();
|
||||
if node.is_in_doc() {
|
||||
if node.is_in_a_document_tree() {
|
||||
node.owner_doc().title_changed();
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ impl VirtualMethods for HTMLTitleElement {
|
|||
s.bind_to_tree(context);
|
||||
}
|
||||
let node = self.upcast::<Node>();
|
||||
if context.tree_in_doc {
|
||||
if context.tree_is_in_a_document_tree {
|
||||
node.owner_doc().title_changed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,7 +193,9 @@ pub struct NodeFlags(u16);
|
|||
bitflags! {
|
||||
impl NodeFlags: u16 {
|
||||
/// Specifies whether this node is in a document.
|
||||
const IS_IN_DOC = 1 << 0;
|
||||
///
|
||||
/// <https://dom.spec.whatwg.org/#in-a-document-tree>
|
||||
const IS_IN_A_DOCUMENT_TREE = 1 << 0;
|
||||
|
||||
/// Specifies whether this node needs style recalc on next reflow.
|
||||
const HAS_DIRTY_DESCENDANTS = 1 << 1;
|
||||
|
@ -225,6 +227,8 @@ bitflags! {
|
|||
const IS_IN_SHADOW_TREE = 1 << 9;
|
||||
|
||||
/// Specifies whether this node's shadow-including root is a document.
|
||||
///
|
||||
/// <https://dom.spec.whatwg.org/#connected>
|
||||
const IS_CONNECTED = 1 << 10;
|
||||
|
||||
/// Whether this node has a weird parser insertion mode. i.e whether setting innerHTML
|
||||
|
@ -285,8 +289,8 @@ impl Node {
|
|||
new_child.parent_node.set(Some(self));
|
||||
self.children_count.set(self.children_count.get() + 1);
|
||||
|
||||
let parent_in_doc = self.is_in_doc();
|
||||
let parent_in_shadow_tree = self.is_in_shadow_tree();
|
||||
let parent_is_in_a_document_tree = self.is_in_a_document_tree();
|
||||
let parent_in_shadow_tree = self.is_in_a_shadow_tree();
|
||||
let parent_is_connected = self.is_connected();
|
||||
|
||||
for node in new_child.traverse_preorder(ShadowIncluding::No) {
|
||||
|
@ -296,14 +300,19 @@ impl Node {
|
|||
}
|
||||
debug_assert!(node.containing_shadow_root().is_some());
|
||||
}
|
||||
node.set_flag(NodeFlags::IS_IN_DOC, parent_in_doc);
|
||||
node.set_flag(
|
||||
NodeFlags::IS_IN_A_DOCUMENT_TREE,
|
||||
parent_is_in_a_document_tree,
|
||||
);
|
||||
node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
|
||||
node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
|
||||
|
||||
// Out-of-document elements never have the descendants flag set.
|
||||
debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
|
||||
vtable_for(&node).bind_to_tree(&BindContext {
|
||||
tree_connected: parent_is_connected,
|
||||
tree_in_doc: parent_in_doc,
|
||||
tree_is_in_a_document_tree: parent_is_in_a_document_tree,
|
||||
tree_is_in_a_shadow_tree: parent_in_shadow_tree,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -317,7 +326,7 @@ impl Node {
|
|||
/// Clean up flags and unbind from tree.
|
||||
pub fn complete_remove_subtree(root: &Node, context: &UnbindContext) {
|
||||
// Flags that reset when a node is disconnected
|
||||
const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_DOC
|
||||
const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
|
||||
.union(NodeFlags::IS_CONNECTED)
|
||||
.union(NodeFlags::HAS_DIRTY_DESCENDANTS)
|
||||
.union(NodeFlags::HAS_SNAPSHOT)
|
||||
|
@ -597,11 +606,12 @@ impl Node {
|
|||
format!("{:?}", self.type_id())
|
||||
}
|
||||
|
||||
pub fn is_in_doc(&self) -> bool {
|
||||
self.flags.get().contains(NodeFlags::IS_IN_DOC)
|
||||
/// <https://dom.spec.whatwg.org/#in-a-document-tree>
|
||||
pub fn is_in_a_document_tree(&self) -> bool {
|
||||
self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
|
||||
}
|
||||
|
||||
pub fn is_in_shadow_tree(&self) -> bool {
|
||||
pub fn is_in_a_shadow_tree(&self) -> bool {
|
||||
self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
|
||||
}
|
||||
|
||||
|
@ -615,15 +625,11 @@ impl Node {
|
|||
self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
|
||||
}
|
||||
|
||||
/// <https://dom.spec.whatwg.org/#connected>
|
||||
pub fn is_connected(&self) -> bool {
|
||||
self.flags.get().contains(NodeFlags::IS_CONNECTED)
|
||||
}
|
||||
|
||||
/// Return true iff the node's root is a Document or a ShadowRoot
|
||||
pub fn is_connected_to_tree(&self) -> bool {
|
||||
self.is_connected() || self.is_in_shadow_tree()
|
||||
}
|
||||
|
||||
/// Returns the type ID of this node.
|
||||
pub fn type_id(&self) -> NodeTypeId {
|
||||
match *self.eventtarget.type_id() {
|
||||
|
@ -1842,7 +1848,10 @@ impl Node {
|
|||
|
||||
#[allow(crown::unrooted_must_root)]
|
||||
pub fn new_document_node() -> Node {
|
||||
Node::new_(NodeFlags::IS_IN_DOC | NodeFlags::IS_CONNECTED, None)
|
||||
Node::new_(
|
||||
NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(crown::unrooted_must_root)]
|
||||
|
@ -2679,7 +2688,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
|
|||
};
|
||||
}
|
||||
|
||||
if self.is_in_doc() {
|
||||
if self.is_in_a_document_tree() {
|
||||
DomRoot::from_ref(self.owner_doc().upcast::<Node>())
|
||||
} else {
|
||||
self.inclusive_ancestors(ShadowIncluding::No)
|
||||
|
@ -3558,9 +3567,24 @@ impl<'a> ChildrenMutation<'a> {
|
|||
/// The context of the binding to tree of a node.
|
||||
pub struct BindContext {
|
||||
/// Whether the tree is connected.
|
||||
///
|
||||
/// <https://dom.spec.whatwg.org/#connected>
|
||||
pub tree_connected: bool,
|
||||
/// Whether the tree is in the document.
|
||||
pub tree_in_doc: bool,
|
||||
|
||||
/// Whether the tree's root is a document.
|
||||
///
|
||||
/// <https://dom.spec.whatwg.org/#in-a-document-tree>
|
||||
pub tree_is_in_a_document_tree: bool,
|
||||
|
||||
/// Whether the tree's root is a shadow root
|
||||
pub tree_is_in_a_shadow_tree: bool,
|
||||
}
|
||||
|
||||
impl BindContext {
|
||||
/// Return true iff the tree is inside either a document- or a shadow tree.
|
||||
pub fn is_in_tree(&self) -> bool {
|
||||
self.tree_is_in_a_document_tree || self.tree_is_in_a_shadow_tree
|
||||
}
|
||||
}
|
||||
|
||||
/// The context of the unbinding from a tree of a node when one of its
|
||||
|
@ -3574,12 +3598,19 @@ pub struct UnbindContext<'a> {
|
|||
prev_sibling: Option<&'a Node>,
|
||||
/// The next sibling of the inclusive ancestor that was removed.
|
||||
pub next_sibling: Option<&'a Node>,
|
||||
|
||||
/// Whether the tree is connected.
|
||||
///
|
||||
/// A tree is connected iff it's root is a Document or a ShadowRoot.
|
||||
/// <https://dom.spec.whatwg.org/#connected>
|
||||
pub tree_connected: bool,
|
||||
/// Whether the tree is in doc.
|
||||
pub tree_in_doc: bool,
|
||||
|
||||
/// Whether the tree's root is a document.
|
||||
///
|
||||
/// <https://dom.spec.whatwg.org/#in-a-document-tree>
|
||||
pub tree_is_in_a_document_tree: bool,
|
||||
|
||||
/// Whether the tree's root is a shadow root
|
||||
pub tree_is_in_a_shadow_tree: bool,
|
||||
}
|
||||
|
||||
impl<'a> UnbindContext<'a> {
|
||||
|
@ -3595,8 +3626,9 @@ impl<'a> UnbindContext<'a> {
|
|||
parent,
|
||||
prev_sibling,
|
||||
next_sibling,
|
||||
tree_connected: parent.is_connected_to_tree(),
|
||||
tree_in_doc: parent.is_in_doc(),
|
||||
tree_connected: parent.is_connected(),
|
||||
tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
|
||||
tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -319,6 +319,7 @@ impl VirtualMethods for ShadowRoot {
|
|||
}
|
||||
|
||||
let shadow_root = self.upcast::<Node>();
|
||||
|
||||
shadow_root.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected);
|
||||
for node in shadow_root.children() {
|
||||
node.set_flag(NodeFlags::IS_CONNECTED, context.tree_connected);
|
||||
|
|
|
@ -168,7 +168,7 @@ impl<'dom> style::dom::TNode for ServoLayoutNode<'dom> {
|
|||
}
|
||||
|
||||
fn is_in_document(&self) -> bool {
|
||||
unsafe { self.node.get_flag(NodeFlags::IS_IN_DOC) }
|
||||
unsafe { self.node.get_flag(NodeFlags::IS_IN_A_DOCUMENT_TREE) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
[form-control-form-attribute.html]
|
||||
[Shadow form control's form attribute should work also in shadow DOM.]
|
||||
expected: FAIL
|
||||
|
||||
[Form element as form control's ancestor should work also in shadow DOM.]
|
||||
expected: FAIL
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue