diff options
author | Simon Wülker <simon.wuelker@arcor.de> | 2025-02-05 14:16:36 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-05 13:16:36 +0000 |
commit | 09bfaf51b0eddce9daf343fdfe48cbdbc024f300 (patch) | |
tree | bb537532274e44edad0b98f05764ad460384850e /components | |
parent | 2bd96633d487fd991ee7e8f03156e5124e06c768 (diff) | |
download | servo-09bfaf51b0eddce9daf343fdfe48cbdbc024f300.tar.gz servo-09bfaf51b0eddce9daf343fdfe48cbdbc024f300.zip |
Inform the devtools about shadow roots on a node (#35294)
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Diffstat (limited to 'components')
-rw-r--r-- | components/devtools/actors/inspector/node.rs | 54 | ||||
-rw-r--r-- | components/script/devtools.rs | 35 | ||||
-rw-r--r-- | components/script/dom/node.rs | 29 | ||||
-rw-r--r-- | components/script/dom/shadowroot.rs | 10 | ||||
-rw-r--r-- | components/shared/devtools/lib.rs | 19 |
5 files changed, 110 insertions, 37 deletions
diff --git a/components/devtools/actors/inspector/node.rs b/components/devtools/actors/inspector/node.rs index a203f43b839..6d054a62528 100644 --- a/components/devtools/actors/inspector/node.rs +++ b/components/devtools/actors/inspector/node.rs @@ -11,7 +11,7 @@ use std::net::TcpStream; use base::id::PipelineId; use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement, ModifyAttribute}; -use devtools_traits::{DevtoolScriptControlMsg, NodeInfo}; +use devtools_traits::{DevtoolScriptControlMsg, NodeInfo, ShadowRootMode}; use ipc_channel::ipc::{self, IpcSender}; use serde::Serialize; use serde_json::{self, Map, Value}; @@ -44,6 +44,10 @@ struct AttrMsg { #[serde(rename_all = "camelCase")] pub struct NodeActorMsg { pub actor: String, + + /// The ID of the shadow host of this node, if it is + /// a shadow root + host: Option<String>, #[serde(rename = "baseURI")] base_uri: String, causes_overflow: bool, @@ -62,6 +66,7 @@ pub struct NodeActorMsg { is_marker_pseudo_element: bool, is_native_anonymous: bool, is_scrollable: bool, + is_shadow_host: bool, is_shadow_root: bool, is_top_level_document: bool, node_name: String, @@ -70,7 +75,7 @@ pub struct NodeActorMsg { pub num_children: usize, #[serde(skip_serializing_if = "String::is_empty")] parent: String, - shadow_root_mode: Option<()>, + shadow_root_mode: Option<String>, traits: HashMap<String, ()>, attrs: Vec<AttrMsg>, } @@ -175,23 +180,31 @@ impl NodeInfoToProtocol for NodeInfo { pipeline: PipelineId, walker: String, ) -> NodeActorMsg { - let actor = if !actors.script_actor_registered(self.unique_id.clone()) { - let name = actors.new_name("node"); - actors.register_script_actor(self.unique_id, name.clone()); + let get_or_register_node_actor = |id: &str| { + if !actors.script_actor_registered(id.to_string()) { + let name = actors.new_name("node"); + actors.register_script_actor(id.to_string(), name.clone()); - let node_actor = NodeActor { - name: name.clone(), - script_chan: script_chan.clone(), - pipeline, - walker: walker.clone(), - style_rules: RefCell::new(HashMap::new()), - }; - actors.register_later(Box::new(node_actor)); - name - } else { - actors.script_to_actor(self.unique_id) + let node_actor = NodeActor { + name: name.clone(), + script_chan: script_chan.clone(), + pipeline, + walker: walker.clone(), + style_rules: RefCell::new(HashMap::new()), + }; + actors.register_later(Box::new(node_actor)); + name + } else { + actors.script_to_actor(id.to_string()) + } }; + let actor = get_or_register_node_actor(&self.unique_id); + let host = self + .host + .as_ref() + .map(|host_id| get_or_register_node_actor(host_id)); + let name = actors.actor_to_script(actor.clone()); // If a node only has a single text node as a child whith a small enough text, @@ -226,6 +239,7 @@ impl NodeInfoToProtocol for NodeInfo { NodeActorMsg { actor, + host, base_uri: self.base_uri, causes_overflow: false, container_type: None, @@ -241,14 +255,18 @@ impl NodeInfoToProtocol for NodeInfo { is_marker_pseudo_element: false, is_native_anonymous: false, is_scrollable: false, - is_shadow_root: false, + is_shadow_host: self.is_shadow_host, + is_shadow_root: self.shadow_root_mode.is_some(), is_top_level_document: self.is_top_level_document, node_name: self.node_name, node_type: self.node_type, node_value: self.node_value, num_children: self.num_children, parent: actors.script_to_actor(self.parent.clone()), - shadow_root_mode: None, + shadow_root_mode: self + .shadow_root_mode + .as_ref() + .map(ShadowRootMode::to_string), traits: HashMap::new(), attrs: self .attrs diff --git a/components/script/devtools.rs b/components/script/devtools.rs index fdf9c991bd2..7718486c14d 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -162,23 +162,24 @@ pub(crate) fn handle_get_children( }) .collect(); - let children: Vec<_> = parent - .children() - .enumerate() - .filter_map(|(i, child)| { - // Filter whitespace only text nodes that are not inline level - // https://firefox-source-docs.mozilla.org/devtools-user/page_inspector/how_to/examine_and_edit_html/index.html#whitespace-only-text-nodes - let prev_inline = i > 0 && inline[i - 1]; - let next_inline = i < inline.len() - 1 && inline[i + 1]; - - let info = child.summarize(); - if !is_whitespace(&info) { - return Some(info); - } - - (prev_inline && next_inline).then_some(info) - }) - .collect(); + let mut children = vec![]; + if let Some(shadow_root) = parent.downcast::<Element>().and_then(Element::shadow_root) { + children.push(shadow_root.upcast::<Node>().summarize()); + } + let children_iter = parent.children().enumerate().filter_map(|(i, child)| { + // Filter whitespace only text nodes that are not inline level + // https://firefox-source-docs.mozilla.org/devtools-user/page_inspector/how_to/examine_and_edit_html/index.html#whitespace-only-text-nodes + let prev_inline = i > 0 && inline[i - 1]; + let next_inline = i < inline.len() - 1 && inline[i + 1]; + + let info = child.summarize(); + if !is_whitespace(&info) { + return Some(info); + } + + (prev_inline && next_inline).then_some(info) + }); + children.extend(children_iter); reply.send(Some(children)).unwrap(); }, diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 280cd23b548..77be215cccb 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -46,6 +46,7 @@ use uuid::Uuid; use xml5ever::serialize as xml_serialize; use super::globalscope::GlobalScope; +use crate::conversions::Convert; use crate::document_loader::DocumentLoader; use crate::dom::attr::Attr; use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut}; @@ -60,7 +61,9 @@ use crate::dom::bindings::codegen::Bindings::NodeBinding::{ use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use crate::dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods; -use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::SlotAssignmentMode; +use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{ + ShadowRootMode, SlotAssignmentMode, +}; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::InheritTypes::DocumentFragmentTypeId; use crate::dom::bindings::codegen::UnionTypes::NodeOrString; @@ -1180,8 +1183,28 @@ impl Node { pub(crate) fn summarize(&self) -> NodeInfo { let USVString(base_uri) = self.BaseURI(); let node_type = self.NodeType(); + + let maybe_shadow_root = self.downcast::<ShadowRoot>(); + let shadow_root_mode = maybe_shadow_root + .map(ShadowRoot::Mode) + .map(ShadowRootMode::convert); + let host = maybe_shadow_root + .map(ShadowRoot::Host) + .map(|host| host.upcast::<Node>().unique_id()); + let is_shadow_host = self + .downcast::<Element>() + .is_some_and(Element::is_shadow_host); + + let num_children = if is_shadow_host { + // Shadow roots count as children + self.ChildNodes().Length() as usize + 1 + } else { + self.ChildNodes().Length() as usize + }; + NodeInfo { unique_id: self.unique_id(), + host, base_uri, parent: self .GetParentNode() @@ -1190,8 +1213,10 @@ impl Node { is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE, node_name: String::from(self.NodeName()), node_value: self.GetNodeValue().map(|v| v.into()), - num_children: self.ChildNodes().Length() as usize, + num_children, attrs: self.downcast().map(Element::summarize).unwrap_or(vec![]), + is_shadow_host, + shadow_root_mode, } } diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 872a3a461d5..1dddfa6a4f4 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -11,6 +11,7 @@ use style::shared_lock::SharedRwLockReadGuard; use style::stylesheets::Stylesheet; use style::stylist::{CascadeData, Stylist}; +use crate::conversions::Convert; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{ @@ -421,3 +422,12 @@ impl<'dom> LayoutShadowRootHelpers<'dom> for LayoutDom<'dom, ShadowRoot> { } } } + +impl Convert<devtools_traits::ShadowRootMode> for ShadowRootMode { + fn convert(self) -> devtools_traits::ShadowRootMode { + match self { + ShadowRootMode::Open => devtools_traits::ShadowRootMode::Open, + ShadowRootMode::Closed => devtools_traits::ShadowRootMode::Closed, + } + } +} diff --git a/components/shared/devtools/lib.rs b/components/shared/devtools/lib.rs index 6bfc275dc44..fa7981aa63f 100644 --- a/components/shared/devtools/lib.rs +++ b/components/shared/devtools/lib.rs @@ -10,6 +10,7 @@ #![crate_type = "rlib"] #![deny(unsafe_code)] +use core::fmt; use std::collections::HashMap; use std::net::TcpStream; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -125,6 +126,7 @@ pub struct AttrInfo { #[serde(rename_all = "camelCase")] pub struct NodeInfo { pub unique_id: String, + pub host: Option<String>, #[serde(rename = "baseURI")] pub base_uri: String, pub parent: String, @@ -134,6 +136,8 @@ pub struct NodeInfo { pub num_children: usize, pub attrs: Vec<AttrInfo>, pub is_top_level_document: bool, + pub shadow_root_mode: Option<ShadowRootMode>, + pub is_shadow_host: bool, } pub struct StartedTimelineMarker { @@ -519,3 +523,18 @@ impl ConsoleMessageBuilder { } } } + +#[derive(Debug, Deserialize, Serialize)] +pub enum ShadowRootMode { + Open, + Closed, +} + +impl fmt::Display for ShadowRootMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Open => write!(f, "open"), + Self::Closed => write!(f, "close"), + } + } +} |