aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/node.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/node.rs')
-rw-r--r--components/script/dom/node.rs66
1 files changed, 49 insertions, 17 deletions
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 691b3a38f19..bf36242572f 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -48,7 +48,7 @@ use style::properties::ComputedValues;
use style::selector_parser::{SelectorImpl, SelectorParser};
use style::stylesheets::{Stylesheet, UrlExtraData};
use uuid::Uuid;
-use xml5ever::serialize as xml_serialize;
+use xml5ever::{local_name, serialize as xml_serialize};
use crate::conversions::Convert;
use crate::document_loader::DocumentLoader;
@@ -738,10 +738,9 @@ impl Node {
}
pub(crate) fn ranges_is_empty(&self) -> bool {
- match self.rare_data().as_ref() {
- Some(data) => data.ranges.is_empty(),
- None => false,
- }
+ self.rare_data()
+ .as_ref()
+ .is_none_or(|data| data.ranges.is_empty())
}
#[inline]
@@ -1247,13 +1246,13 @@ impl Node {
}
}
- pub(crate) fn unique_id(&self) -> String {
+ pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
let mut rare_data = self.ensure_rare_data();
if rare_data.unique_id.is_none() {
- let id = UniqueId::new();
- ScriptThread::save_node_id(id.borrow().simple().to_string());
- rare_data.unique_id = Some(id);
+ let node_id = UniqueId::new();
+ ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string());
+ rare_data.unique_id = Some(node_id);
}
rare_data
.unique_id
@@ -1267,6 +1266,7 @@ impl Node {
pub(crate) fn summarize(&self, can_gc: CanGc) -> NodeInfo {
let USVString(base_uri) = self.BaseURI();
let node_type = self.NodeType();
+ let pipeline = self.owner_document().window().pipeline_id();
let maybe_shadow_root = self.downcast::<ShadowRoot>();
let shadow_root_mode = maybe_shadow_root
@@ -1274,7 +1274,7 @@ impl Node {
.map(ShadowRootMode::convert);
let host = maybe_shadow_root
.map(ShadowRoot::Host)
- .map(|host| host.upcast::<Node>().unique_id());
+ .map(|host| host.upcast::<Node>().unique_id(pipeline));
let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
let Some(root) = potential_host.shadow_root() else {
return false;
@@ -1296,12 +1296,12 @@ impl Node {
.map(|style| style.Display().into());
NodeInfo {
- unique_id: self.unique_id(),
+ unique_id: self.unique_id(pipeline),
host,
base_uri,
parent: self
.GetParentNode()
- .map_or("".to_owned(), |node| node.unique_id()),
+ .map_or("".to_owned(), |node| node.unique_id(pipeline)),
node_type,
is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
node_name: String::from(self.NodeName()),
@@ -1455,6 +1455,21 @@ impl Node {
.map(|data| data.element_data.borrow().styles.primary().clone())
}
+ /// <https://html.spec.whatwg.org/multipage/#language>
+ pub(crate) fn get_lang(&self) -> Option<String> {
+ self.inclusive_ancestors(ShadowIncluding::Yes)
+ .filter_map(|node| {
+ node.downcast::<Element>().and_then(|el| {
+ el.get_attribute(&ns!(xml), &local_name!("lang"))
+ .or_else(|| el.get_attribute(&ns!(), &local_name!("lang")))
+ .map(|attr| String::from(attr.Value()))
+ })
+ // TODO: Check meta tags for a pragma-set default language
+ // TODO: Check HTTP Content-Language header
+ })
+ .next()
+ }
+
/// <https://dom.spec.whatwg.org/#assign-slotables-for-a-tree>
pub(crate) fn assign_slottables_for_a_tree(&self) {
// NOTE: This method traverses all descendants of the node and is potentially very
@@ -2603,7 +2618,9 @@ impl Node {
fn remove(node: &Node, parent: &Node, suppress_observers: SuppressObserver, can_gc: CanGc) {
parent.owner_doc().add_script_and_layout_blocker();
- // Step 2.
+ // Step 1. Let parent be node’s parent.
+ // Step 2. Assert: parent is non-null.
+ // NOTE: We get parent as an argument instead
assert!(
node.GetParentNode()
.is_some_and(|node_parent| &*node_parent == parent)
@@ -2615,11 +2632,21 @@ impl Node {
if parent.ranges_is_empty() {
None
} else {
- // Step 1.
+ // Step 1. Let parent be node’s parent.
+ // Step 2. Assert: parent is not null.
+ // NOTE: We already have the parent.
+
+ // Step 3. Let index be node’s index.
let index = node.index();
- // Steps 2-3 are handled in Node::unbind_from_tree.
- // Steps 4-5.
+
+ // Steps 4-5 are handled in Node::unbind_from_tree.
+
+ // Step 6. For each live range whose start node is parent and start offset is greater than index,
+ // decrease its start offset by 1.
+ // Step 7. For each live range whose end node is parent and end offset is greater than index,
+ // decrease its end offset by 1.
parent.ranges().decrease_above(parent, index, 1);
+
// Parent had ranges, we needed the index, let's keep track of
// it to avoid computing it for other ranges when calling
// unbind_from_tree recursively.
@@ -3863,7 +3890,12 @@ impl VirtualMethods for Node {
/// <https://dom.spec.whatwg.org/#concept-node-remove>
fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
self.super_type().unwrap().unbind_from_tree(context, can_gc);
- if !self.ranges_is_empty() {
+
+ // Ranges should only drain to the parent from inclusive non-shadow
+ // including descendants. If we're in a shadow tree at this point then the
+ // unbind operation happened further up in the tree and we should not
+ // drain any ranges.
+ if !self.is_in_a_shadow_tree() && !self.ranges_is_empty() {
self.ranges().drain_to_parent(context, self);
}
}