mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Inform the devtools about shadow roots on a node (#35294)
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
parent
2bd96633d4
commit
09bfaf51b0
5 changed files with 108 additions and 35 deletions
|
@ -11,7 +11,7 @@ use std::net::TcpStream;
|
||||||
|
|
||||||
use base::id::PipelineId;
|
use base::id::PipelineId;
|
||||||
use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement, ModifyAttribute};
|
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 ipc_channel::ipc::{self, IpcSender};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{self, Map, Value};
|
use serde_json::{self, Map, Value};
|
||||||
|
@ -44,6 +44,10 @@ struct AttrMsg {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct NodeActorMsg {
|
pub struct NodeActorMsg {
|
||||||
pub actor: String,
|
pub actor: String,
|
||||||
|
|
||||||
|
/// The ID of the shadow host of this node, if it is
|
||||||
|
/// a shadow root
|
||||||
|
host: Option<String>,
|
||||||
#[serde(rename = "baseURI")]
|
#[serde(rename = "baseURI")]
|
||||||
base_uri: String,
|
base_uri: String,
|
||||||
causes_overflow: bool,
|
causes_overflow: bool,
|
||||||
|
@ -62,6 +66,7 @@ pub struct NodeActorMsg {
|
||||||
is_marker_pseudo_element: bool,
|
is_marker_pseudo_element: bool,
|
||||||
is_native_anonymous: bool,
|
is_native_anonymous: bool,
|
||||||
is_scrollable: bool,
|
is_scrollable: bool,
|
||||||
|
is_shadow_host: bool,
|
||||||
is_shadow_root: bool,
|
is_shadow_root: bool,
|
||||||
is_top_level_document: bool,
|
is_top_level_document: bool,
|
||||||
node_name: String,
|
node_name: String,
|
||||||
|
@ -70,7 +75,7 @@ pub struct NodeActorMsg {
|
||||||
pub num_children: usize,
|
pub num_children: usize,
|
||||||
#[serde(skip_serializing_if = "String::is_empty")]
|
#[serde(skip_serializing_if = "String::is_empty")]
|
||||||
parent: String,
|
parent: String,
|
||||||
shadow_root_mode: Option<()>,
|
shadow_root_mode: Option<String>,
|
||||||
traits: HashMap<String, ()>,
|
traits: HashMap<String, ()>,
|
||||||
attrs: Vec<AttrMsg>,
|
attrs: Vec<AttrMsg>,
|
||||||
}
|
}
|
||||||
|
@ -175,9 +180,10 @@ impl NodeInfoToProtocol for NodeInfo {
|
||||||
pipeline: PipelineId,
|
pipeline: PipelineId,
|
||||||
walker: String,
|
walker: String,
|
||||||
) -> NodeActorMsg {
|
) -> NodeActorMsg {
|
||||||
let actor = if !actors.script_actor_registered(self.unique_id.clone()) {
|
let get_or_register_node_actor = |id: &str| {
|
||||||
|
if !actors.script_actor_registered(id.to_string()) {
|
||||||
let name = actors.new_name("node");
|
let name = actors.new_name("node");
|
||||||
actors.register_script_actor(self.unique_id, name.clone());
|
actors.register_script_actor(id.to_string(), name.clone());
|
||||||
|
|
||||||
let node_actor = NodeActor {
|
let node_actor = NodeActor {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
|
@ -189,9 +195,16 @@ impl NodeInfoToProtocol for NodeInfo {
|
||||||
actors.register_later(Box::new(node_actor));
|
actors.register_later(Box::new(node_actor));
|
||||||
name
|
name
|
||||||
} else {
|
} else {
|
||||||
actors.script_to_actor(self.unique_id)
|
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());
|
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,
|
// 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 {
|
NodeActorMsg {
|
||||||
actor,
|
actor,
|
||||||
|
host,
|
||||||
base_uri: self.base_uri,
|
base_uri: self.base_uri,
|
||||||
causes_overflow: false,
|
causes_overflow: false,
|
||||||
container_type: None,
|
container_type: None,
|
||||||
|
@ -241,14 +255,18 @@ impl NodeInfoToProtocol for NodeInfo {
|
||||||
is_marker_pseudo_element: false,
|
is_marker_pseudo_element: false,
|
||||||
is_native_anonymous: false,
|
is_native_anonymous: false,
|
||||||
is_scrollable: 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,
|
is_top_level_document: self.is_top_level_document,
|
||||||
node_name: self.node_name,
|
node_name: self.node_name,
|
||||||
node_type: self.node_type,
|
node_type: self.node_type,
|
||||||
node_value: self.node_value,
|
node_value: self.node_value,
|
||||||
num_children: self.num_children,
|
num_children: self.num_children,
|
||||||
parent: actors.script_to_actor(self.parent.clone()),
|
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(),
|
traits: HashMap::new(),
|
||||||
attrs: self
|
attrs: self
|
||||||
.attrs
|
.attrs
|
||||||
|
|
|
@ -162,10 +162,11 @@ pub(crate) fn handle_get_children(
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let children: Vec<_> = parent
|
let mut children = vec![];
|
||||||
.children()
|
if let Some(shadow_root) = parent.downcast::<Element>().and_then(Element::shadow_root) {
|
||||||
.enumerate()
|
children.push(shadow_root.upcast::<Node>().summarize());
|
||||||
.filter_map(|(i, child)| {
|
}
|
||||||
|
let children_iter = parent.children().enumerate().filter_map(|(i, child)| {
|
||||||
// Filter whitespace only text nodes that are not inline level
|
// 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
|
// 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 prev_inline = i > 0 && inline[i - 1];
|
||||||
|
@ -177,8 +178,8 @@ pub(crate) fn handle_get_children(
|
||||||
}
|
}
|
||||||
|
|
||||||
(prev_inline && next_inline).then_some(info)
|
(prev_inline && next_inline).then_some(info)
|
||||||
})
|
});
|
||||||
.collect();
|
children.extend(children_iter);
|
||||||
|
|
||||||
reply.send(Some(children)).unwrap();
|
reply.send(Some(children)).unwrap();
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,6 +46,7 @@ use uuid::Uuid;
|
||||||
use xml5ever::serialize as xml_serialize;
|
use xml5ever::serialize as xml_serialize;
|
||||||
|
|
||||||
use super::globalscope::GlobalScope;
|
use super::globalscope::GlobalScope;
|
||||||
|
use crate::conversions::Convert;
|
||||||
use crate::document_loader::DocumentLoader;
|
use crate::document_loader::DocumentLoader;
|
||||||
use crate::dom::attr::Attr;
|
use crate::dom::attr::Attr;
|
||||||
use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
|
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::NodeListBinding::NodeListMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
|
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::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::Bindings::WindowBinding::WindowMethods;
|
||||||
use crate::dom::bindings::codegen::InheritTypes::DocumentFragmentTypeId;
|
use crate::dom::bindings::codegen::InheritTypes::DocumentFragmentTypeId;
|
||||||
use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
|
use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
|
||||||
|
@ -1180,8 +1183,28 @@ impl Node {
|
||||||
pub(crate) fn summarize(&self) -> NodeInfo {
|
pub(crate) fn summarize(&self) -> NodeInfo {
|
||||||
let USVString(base_uri) = self.BaseURI();
|
let USVString(base_uri) = self.BaseURI();
|
||||||
let node_type = self.NodeType();
|
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 {
|
NodeInfo {
|
||||||
unique_id: self.unique_id(),
|
unique_id: self.unique_id(),
|
||||||
|
host,
|
||||||
base_uri,
|
base_uri,
|
||||||
parent: self
|
parent: self
|
||||||
.GetParentNode()
|
.GetParentNode()
|
||||||
|
@ -1190,8 +1213,10 @@ impl Node {
|
||||||
is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
|
is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
|
||||||
node_name: String::from(self.NodeName()),
|
node_name: String::from(self.NodeName()),
|
||||||
node_value: self.GetNodeValue().map(|v| v.into()),
|
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![]),
|
attrs: self.downcast().map(Element::summarize).unwrap_or(vec![]),
|
||||||
|
is_shadow_host,
|
||||||
|
shadow_root_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ use style::shared_lock::SharedRwLockReadGuard;
|
||||||
use style::stylesheets::Stylesheet;
|
use style::stylesheets::Stylesheet;
|
||||||
use style::stylist::{CascadeData, Stylist};
|
use style::stylist::{CascadeData, Stylist};
|
||||||
|
|
||||||
|
use crate::conversions::Convert;
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
|
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#![crate_type = "rlib"]
|
#![crate_type = "rlib"]
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
@ -125,6 +126,7 @@ pub struct AttrInfo {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct NodeInfo {
|
pub struct NodeInfo {
|
||||||
pub unique_id: String,
|
pub unique_id: String,
|
||||||
|
pub host: Option<String>,
|
||||||
#[serde(rename = "baseURI")]
|
#[serde(rename = "baseURI")]
|
||||||
pub base_uri: String,
|
pub base_uri: String,
|
||||||
pub parent: String,
|
pub parent: String,
|
||||||
|
@ -134,6 +136,8 @@ pub struct NodeInfo {
|
||||||
pub num_children: usize,
|
pub num_children: usize,
|
||||||
pub attrs: Vec<AttrInfo>,
|
pub attrs: Vec<AttrInfo>,
|
||||||
pub is_top_level_document: bool,
|
pub is_top_level_document: bool,
|
||||||
|
pub shadow_root_mode: Option<ShadowRootMode>,
|
||||||
|
pub is_shadow_host: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StartedTimelineMarker {
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue