aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorSimon Wülker <simon.wuelker@arcor.de>2025-02-05 14:16:36 +0100
committerGitHub <noreply@github.com>2025-02-05 13:16:36 +0000
commit09bfaf51b0eddce9daf343fdfe48cbdbc024f300 (patch)
treebb537532274e44edad0b98f05764ad460384850e /components
parent2bd96633d487fd991ee7e8f03156e5124e06c768 (diff)
downloadservo-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.rs54
-rw-r--r--components/script/devtools.rs35
-rw-r--r--components/script/dom/node.rs29
-rw-r--r--components/script/dom/shadowroot.rs10
-rw-r--r--components/shared/devtools/lib.rs19
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"),
+ }
+ }
+}