script/dom/
node.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
6
7use std::borrow::Cow;
8use std::cell::{Cell, LazyCell, UnsafeCell};
9use std::default::Default;
10use std::f64::consts::PI;
11use std::slice::from_ref;
12use std::{cmp, fmt, iter};
13
14use app_units::Au;
15use base::id::{BrowsingContextId, PipelineId};
16use bitflags::bitflags;
17use devtools_traits::NodeInfo;
18use dom_struct::dom_struct;
19use embedder_traits::UntrustedNodeAddress;
20use euclid::default::Size2D;
21use euclid::{Point2D, Rect};
22use html5ever::serialize::HtmlSerializer;
23use html5ever::{Namespace, Prefix, QualName, ns, serialize as html_serialize};
24use js::jsapi::JSObject;
25use js::rust::HandleObject;
26use keyboard_types::Modifiers;
27use layout_api::wrapper_traits::SharedSelection;
28use layout_api::{
29    BoxAreaType, GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutElementType,
30    LayoutNodeType, PhysicalSides, QueryMsg, SVGElementData, StyleData, TrustedNodeAddress,
31};
32use libc::{self, c_void, uintptr_t};
33use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
34use net_traits::image_cache::Image;
35use pixels::ImageMetadata;
36use script_bindings::codegen::InheritTypes::DocumentFragmentTypeId;
37use script_traits::DocumentActivity;
38use selectors::bloom::BloomFilter;
39use selectors::matching::{
40    MatchingContext, MatchingForInvalidation, MatchingMode, NeedsSelectorFlags,
41    matches_selector_list,
42};
43use selectors::parser::SelectorList;
44use servo_arc::Arc as ServoArc;
45use servo_config::pref;
46use servo_url::ServoUrl;
47use smallvec::SmallVec;
48use style::attr::AttrValue;
49use style::context::QuirksMode;
50use style::dom::OpaqueNode;
51use style::properties::ComputedValues;
52use style::selector_parser::{PseudoElement, SelectorImpl, SelectorParser};
53use style::stylesheets::{Stylesheet, UrlExtraData};
54use style_traits::CSSPixel;
55use uuid::Uuid;
56use xml5ever::{local_name, serialize as xml_serialize};
57
58use super::types::CDATASection;
59use crate::conversions::Convert;
60use crate::document_loader::DocumentLoader;
61use crate::dom::attr::Attr;
62use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
63use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
64use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
65use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
66use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
67use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
68use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
69use crate::dom::bindings::codegen::Bindings::NodeBinding::{
70    GetRootNodeOptions, NodeConstants, NodeMethods,
71};
72use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
73use crate::dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
74use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
75use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
76    ShadowRootMode, SlotAssignmentMode,
77};
78use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
79use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
80use crate::dom::bindings::conversions::{self, DerivedFrom};
81use crate::dom::bindings::domname::namespace_from_domstring;
82use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
83use crate::dom::bindings::inheritance::{
84    Castable, CharacterDataTypeId, ElementTypeId, EventTargetTypeId, HTMLElementTypeId, NodeTypeId,
85    SVGElementTypeId, SVGGraphicsElementTypeId, TextTypeId,
86};
87use crate::dom::bindings::reflector::{DomObject, DomObjectWrap, reflect_dom_object_with_proto};
88use crate::dom::bindings::root::{Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout};
89use crate::dom::bindings::str::{DOMString, USVString};
90use crate::dom::characterdata::{CharacterData, LayoutCharacterDataHelpers};
91use crate::dom::css::cssstylesheet::CSSStyleSheet;
92use crate::dom::css::stylesheetlist::StyleSheetListOwner;
93use crate::dom::customelementregistry::{
94    CallbackReaction, CustomElementRegistry, try_upgrade_element,
95};
96use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
97use crate::dom::documentfragment::DocumentFragment;
98use crate::dom::documenttype::DocumentType;
99use crate::dom::element::{
100    AttributeMutationReason, CustomElementCreationMode, Element, ElementCreator, SelectorWrapper,
101};
102use crate::dom::event::{Event, EventBubbles, EventCancelable};
103use crate::dom::eventtarget::EventTarget;
104use crate::dom::globalscope::GlobalScope;
105use crate::dom::html::htmlcanvaselement::{HTMLCanvasElement, LayoutHTMLCanvasElementHelpers};
106use crate::dom::html::htmlcollection::HTMLCollection;
107use crate::dom::html::htmlelement::HTMLElement;
108use crate::dom::html::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
109use crate::dom::html::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
110use crate::dom::html::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
111use crate::dom::html::htmllinkelement::HTMLLinkElement;
112use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
113use crate::dom::html::htmlstyleelement::HTMLStyleElement;
114use crate::dom::html::htmltextareaelement::{
115    HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers,
116};
117use crate::dom::html::htmlvideoelement::{HTMLVideoElement, LayoutHTMLVideoElementHelpers};
118use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
119use crate::dom::nodelist::NodeList;
120use crate::dom::pointerevent::{PointerEvent, PointerId};
121use crate::dom::processinginstruction::ProcessingInstruction;
122use crate::dom::range::WeakRangeVec;
123use crate::dom::raredata::NodeRareData;
124use crate::dom::servoparser::html::HtmlSerialize;
125use crate::dom::servoparser::{ServoParser, serialize_html_fragment};
126use crate::dom::shadowroot::{IsUserAgentWidget, LayoutShadowRootHelpers, ShadowRoot};
127use crate::dom::svg::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement};
128use crate::dom::text::Text;
129use crate::dom::types::KeyboardEvent;
130use crate::dom::virtualmethods::{VirtualMethods, vtable_for};
131use crate::dom::window::Window;
132use crate::script_runtime::CanGc;
133use crate::script_thread::ScriptThread;
134
135//
136// The basic Node structure
137//
138
139/// An HTML node.
140#[dom_struct]
141pub struct Node {
142    /// The JavaScript reflector for this node.
143    eventtarget: EventTarget,
144
145    /// The parent of this node.
146    parent_node: MutNullableDom<Node>,
147
148    /// The first child of this node.
149    first_child: MutNullableDom<Node>,
150
151    /// The last child of this node.
152    last_child: MutNullableDom<Node>,
153
154    /// The next sibling of this node.
155    next_sibling: MutNullableDom<Node>,
156
157    /// The previous sibling of this node.
158    prev_sibling: MutNullableDom<Node>,
159
160    /// The document that this node belongs to.
161    owner_doc: MutNullableDom<Document>,
162
163    /// Rare node data.
164    rare_data: DomRefCell<Option<Box<NodeRareData>>>,
165
166    /// The live count of children of this node.
167    children_count: Cell<u32>,
168
169    /// A bitfield of flags for node items.
170    flags: Cell<NodeFlags>,
171
172    /// The maximum version of any inclusive descendant of this node.
173    inclusive_descendants_version: Cell<u64>,
174
175    /// Style data for this node. This is accessed and mutated by style
176    /// passes and is used to lay out this node and populate layout data.
177    #[no_trace]
178    style_data: DomRefCell<Option<Box<StyleData>>>,
179
180    /// Layout data for this node. This is populated during layout and can
181    /// be used for incremental relayout and script queries.
182    #[no_trace]
183    layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
184}
185
186impl fmt::Debug for Node {
187    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
188        if matches!(self.type_id(), NodeTypeId::Element(_)) {
189            let el = self.downcast::<Element>().unwrap();
190            el.fmt(f)
191        } else {
192            write!(f, "[Node({:?})]", self.type_id())
193        }
194    }
195}
196
197/// Flags for node items
198#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
199pub(crate) struct NodeFlags(u16);
200
201bitflags! {
202    impl NodeFlags: u16 {
203        /// Specifies whether this node is in a document.
204        ///
205        /// <https://dom.spec.whatwg.org/#in-a-document-tree>
206        const IS_IN_A_DOCUMENT_TREE = 1 << 0;
207
208        /// Specifies whether this node needs style recalc on next reflow.
209        const HAS_DIRTY_DESCENDANTS = 1 << 1;
210
211        /// Specifies whether or not there is an authentic click in progress on
212        /// this element.
213        const CLICK_IN_PROGRESS = 1 << 2;
214
215        /// Specifies whether this node is focusable and whether it is supposed
216        /// to be reachable with using sequential focus navigation."]
217        const SEQUENTIALLY_FOCUSABLE = 1 << 3;
218
219        // There are two free bits here.
220
221        /// Specifies whether the parser has set an associated form owner for
222        /// this element. Only applicable for form-associatable elements.
223        const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
224
225        /// Whether this element has a snapshot stored due to a style or
226        /// attribute change.
227        ///
228        /// See the `style::restyle_hints` module.
229        const HAS_SNAPSHOT = 1 << 7;
230
231        /// Whether this element has already handled the stored snapshot.
232        const HANDLED_SNAPSHOT = 1 << 8;
233
234        /// Whether this node participates in a shadow tree.
235        const IS_IN_SHADOW_TREE = 1 << 9;
236
237        /// Specifies whether this node's shadow-including root is a document.
238        ///
239        /// <https://dom.spec.whatwg.org/#connected>
240        const IS_CONNECTED = 1 << 10;
241
242        /// Whether this node has a weird parser insertion mode. i.e whether setting innerHTML
243        /// needs extra work or not
244        const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
245
246        /// Whether this node resides in UA shadow DOM. Element within UA Shadow DOM
247        /// will have a different style computation behavior
248        const IS_IN_UA_WIDGET = 1 << 12;
249
250        /// Whether this node has a pseudo-element style which uses `attr()` in the `content` attribute.
251        const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
252    }
253}
254
255/// suppress observers flag
256/// <https://dom.spec.whatwg.org/#concept-node-insert>
257/// <https://dom.spec.whatwg.org/#concept-node-remove>
258#[derive(Clone, Copy, MallocSizeOf)]
259enum SuppressObserver {
260    Suppressed,
261    Unsuppressed,
262}
263
264impl Node {
265    /// Adds a new child to the end of this node's list of children.
266    ///
267    /// Fails unless `new_child` is disconnected from the tree.
268    fn add_child(&self, new_child: &Node, before: Option<&Node>, can_gc: CanGc) {
269        assert!(new_child.parent_node.get().is_none());
270        assert!(new_child.prev_sibling.get().is_none());
271        assert!(new_child.next_sibling.get().is_none());
272        match before {
273            Some(before) => {
274                assert!(before.parent_node.get().as_deref() == Some(self));
275                let prev_sibling = before.GetPreviousSibling();
276                match prev_sibling {
277                    None => {
278                        assert!(self.first_child.get().as_deref() == Some(before));
279                        self.first_child.set(Some(new_child));
280                    },
281                    Some(ref prev_sibling) => {
282                        prev_sibling.next_sibling.set(Some(new_child));
283                        new_child.prev_sibling.set(Some(prev_sibling));
284                    },
285                }
286                before.prev_sibling.set(Some(new_child));
287                new_child.next_sibling.set(Some(before));
288            },
289            None => {
290                let last_child = self.GetLastChild();
291                match last_child {
292                    None => self.first_child.set(Some(new_child)),
293                    Some(ref last_child) => {
294                        assert!(last_child.next_sibling.get().is_none());
295                        last_child.next_sibling.set(Some(new_child));
296                        new_child.prev_sibling.set(Some(last_child));
297                    },
298                }
299
300                self.last_child.set(Some(new_child));
301            },
302        }
303
304        new_child.parent_node.set(Some(self));
305        self.children_count.set(self.children_count.get() + 1);
306
307        let parent_is_in_a_document_tree = self.is_in_a_document_tree();
308        let parent_in_shadow_tree = self.is_in_a_shadow_tree();
309        let parent_is_connected = self.is_connected();
310        let parent_is_in_ua_widget = self.is_in_ua_widget();
311
312        let context = BindContext::new(self, IsShadowTree::No);
313
314        for node in new_child.traverse_preorder(ShadowIncluding::No) {
315            if parent_in_shadow_tree {
316                if let Some(shadow_root) = self.containing_shadow_root() {
317                    node.set_containing_shadow_root(Some(&*shadow_root));
318                }
319                debug_assert!(node.containing_shadow_root().is_some());
320            }
321            node.set_flag(
322                NodeFlags::IS_IN_A_DOCUMENT_TREE,
323                parent_is_in_a_document_tree,
324            );
325            node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
326            node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
327            node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
328
329            // Out-of-document elements never have the descendants flag set.
330            debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
331            vtable_for(&node).bind_to_tree(&context, can_gc);
332        }
333    }
334
335    /// Implements the "unsafely set HTML" algorithm as specified in:
336    /// <https://html.spec.whatwg.org/multipage/#concept-unsafely-set-html>
337    pub(crate) fn unsafely_set_html(
338        target: &Node,
339        context_element: &Element,
340        html: DOMString,
341        can_gc: CanGc,
342    ) {
343        // Step 1. Let newChildren be the result of the HTML fragment parsing algorithm.
344        let new_children = ServoParser::parse_html_fragment(context_element, html, true, can_gc);
345
346        // Step 2. Let fragment be a new DocumentFragment whose node document is contextElement's node document.
347
348        let context_document = context_element.owner_document();
349        let fragment = DocumentFragment::new(&context_document, can_gc);
350
351        // Step 3. For each node in newChildren, append node to fragment.
352        for child in new_children {
353            fragment
354                .upcast::<Node>()
355                .AppendChild(&child, can_gc)
356                .unwrap();
357        }
358
359        // Step 4. Replace all with fragment within target.
360        Node::replace_all(Some(fragment.upcast()), target, can_gc);
361    }
362
363    /// Clear this [`Node`]'s layout data and also clear the layout data of all children.
364    /// Note that clears layout data from all non-flat tree descendants and flat tree
365    /// descendants.
366    pub(crate) fn remove_layout_boxes_from_subtree(&self) {
367        for node in self.traverse_preorder(ShadowIncluding::Yes) {
368            node.layout_data.borrow_mut().take();
369        }
370    }
371
372    pub(crate) fn clean_up_style_and_layout_data(&self) {
373        self.owner_doc().cancel_animations_for_node(self);
374        self.style_data.borrow_mut().take();
375        self.layout_data.borrow_mut().take();
376    }
377
378    /// Clean up flags and runs steps 11-14 of remove a node.
379    /// <https://dom.spec.whatwg.org/#concept-node-remove>
380    pub(crate) fn complete_remove_subtree(root: &Node, context: &UnbindContext, can_gc: CanGc) {
381        // Flags that reset when a node is disconnected
382        const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
383            .union(NodeFlags::IS_CONNECTED)
384            .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
385            .union(NodeFlags::HAS_SNAPSHOT)
386            .union(NodeFlags::HANDLED_SNAPSHOT);
387
388        for node in root.traverse_preorder(ShadowIncluding::No) {
389            node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
390
391            // If the element has a shadow root attached to it then we traverse that as well,
392            // but without touching the IS_IN_SHADOW_TREE flags of the children
393            if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
394                for node in shadow_root
395                    .upcast::<Node>()
396                    .traverse_preorder(ShadowIncluding::Yes)
397                {
398                    node.set_flag(RESET_FLAGS, false);
399                }
400            }
401        }
402
403        // Step 12.
404        let is_parent_connected = context.parent.is_connected();
405        let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
406
407        // Since both the initial traversal in light dom and the inner traversal
408        // in shadow DOM share the same code, we define a closure to prevent omissions.
409        let cleanup_node = |node: &Node| {
410            node.clean_up_style_and_layout_data();
411
412            // Step 11 & 14.1. Run the removing steps.
413            // This needs to be in its own loop, because unbind_from_tree may
414            // rely on the state of IS_IN_DOC of the context node's descendants,
415            // e.g. when removing a <form>.
416            vtable_for(node).unbind_from_tree(context, can_gc);
417
418            // Step 12 & 14.2. Enqueue disconnected custom element reactions.
419            if is_parent_connected {
420                if let Some(element) = node.as_custom_element() {
421                    custom_element_reaction_stack.enqueue_callback_reaction(
422                        &element,
423                        CallbackReaction::Disconnected,
424                        None,
425                    );
426                }
427            }
428        };
429
430        for node in root.traverse_preorder(ShadowIncluding::No) {
431            cleanup_node(&node);
432
433            // Make sure that we don't accidentally initialize the rare data for this node
434            // by setting it to None
435            if node.containing_shadow_root().is_some() {
436                // Reset the containing shadowRoot after we unbind the node, since some elements
437                // require the containing shadowRoot for cleanup logic (e.g. <style>).
438                node.set_containing_shadow_root(None);
439            }
440
441            // If the element has a shadow root attached to it then we traverse that as well,
442            // but without resetting the contained shadow root
443            if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
444                for node in shadow_root
445                    .upcast::<Node>()
446                    .traverse_preorder(ShadowIncluding::Yes)
447                {
448                    cleanup_node(&node);
449                }
450            }
451        }
452    }
453
454    /// Removes the given child from this node's list of children.
455    ///
456    /// Fails unless `child` is a child of this node.
457    fn remove_child(&self, child: &Node, cached_index: Option<u32>, can_gc: CanGc) {
458        assert!(child.parent_node.get().as_deref() == Some(self));
459        self.note_dirty_descendants();
460
461        let prev_sibling = child.GetPreviousSibling();
462        match prev_sibling {
463            None => {
464                self.first_child.set(child.next_sibling.get().as_deref());
465            },
466            Some(ref prev_sibling) => {
467                prev_sibling
468                    .next_sibling
469                    .set(child.next_sibling.get().as_deref());
470            },
471        }
472        let next_sibling = child.GetNextSibling();
473        match next_sibling {
474            None => {
475                self.last_child.set(child.prev_sibling.get().as_deref());
476            },
477            Some(ref next_sibling) => {
478                next_sibling
479                    .prev_sibling
480                    .set(child.prev_sibling.get().as_deref());
481            },
482        }
483
484        let context = UnbindContext::new(
485            self,
486            prev_sibling.as_deref(),
487            next_sibling.as_deref(),
488            cached_index,
489        );
490
491        child.prev_sibling.set(None);
492        child.next_sibling.set(None);
493        child.parent_node.set(None);
494        self.children_count.set(self.children_count.get() - 1);
495
496        Self::complete_remove_subtree(child, &context, can_gc);
497    }
498
499    pub(crate) fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
500        UntrustedNodeAddress(self.reflector().get_jsobject().get() as *const c_void)
501    }
502
503    pub(crate) fn to_opaque(&self) -> OpaqueNode {
504        OpaqueNode(self.reflector().get_jsobject().get() as usize)
505    }
506
507    pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
508        self.downcast::<Element>().and_then(|element| {
509            if element.is_custom() {
510                assert!(element.get_custom_element_definition().is_some());
511                Some(DomRoot::from_ref(element))
512            } else {
513                None
514            }
515        })
516    }
517
518    /// <https://html.spec.whatwg.org/multipage/#fire-a-synthetic-pointer-event>
519    pub(crate) fn fire_synthetic_pointer_event_not_trusted(&self, name: DOMString, can_gc: CanGc) {
520        // Spec says the choice of which global to create the pointer event
521        // on is not well-defined,
522        // and refers to heycam/webidl#135
523        let window = self.owner_window();
524
525        // <https://w3c.github.io/pointerevents/#the-click-auxclick-and-contextmenu-events>
526        let pointer_event = PointerEvent::new(
527            &window, // ambiguous in spec
528            name,
529            EventBubbles::Bubbles,              // Step 3: bubbles
530            EventCancelable::Cancelable,        // Step 3: cancelable
531            Some(&window),                      // Step 7: view
532            0,                                  // detail uninitialized
533            Point2D::zero(),                    // coordinates uninitialized
534            Point2D::zero(),                    // coordinates uninitialized
535            Point2D::zero(),                    // coordinates uninitialized
536            Modifiers::empty(),                 // empty modifiers
537            0,                                  // button, left mouse button
538            0,                                  // buttons
539            None,                               // related_target
540            None,                               // point_in_target
541            PointerId::NonPointerDevice as i32, // pointer_id
542            1,                                  // width
543            1,                                  // height
544            0.5,                                // pressure
545            0.0,                                // tangential_pressure
546            0,                                  // tilt_x
547            0,                                  // tilt_y
548            0,                                  // twist
549            PI / 2.0,                           // altitude_angle
550            0.0,                                // azimuth_angle
551            DOMString::from(""),                // pointer_type
552            false,                              // is_primary
553            vec![],                             // coalesced_events
554            vec![],                             // predicted_events
555            can_gc,
556        );
557
558        // Step 4. Set event's composed flag.
559        pointer_event.upcast::<Event>().set_composed(true);
560
561        // Step 5. If the not trusted flag is set, initialize event's isTrusted attribute to false.
562        pointer_event.upcast::<Event>().set_trusted(false);
563
564        // Step 6,8. TODO keyboard modifiers
565
566        pointer_event
567            .upcast::<Event>()
568            .dispatch(self.upcast::<EventTarget>(), false, can_gc);
569    }
570
571    pub(crate) fn parent_directionality(&self) -> String {
572        let mut current = self.GetParentNode();
573
574        loop {
575            match current {
576                Some(node) => {
577                    if let Some(directionality) = node
578                        .downcast::<HTMLElement>()
579                        .and_then(|html_element| html_element.directionality())
580                    {
581                        return directionality;
582                    } else {
583                        current = node.GetParentNode();
584                    }
585                },
586                None => return "ltr".to_owned(),
587            }
588        }
589    }
590}
591
592pub(crate) struct QuerySelectorIterator {
593    selectors: SelectorList<SelectorImpl>,
594    iterator: TreeIterator,
595}
596
597impl QuerySelectorIterator {
598    fn new(iter: TreeIterator, selectors: SelectorList<SelectorImpl>) -> QuerySelectorIterator {
599        QuerySelectorIterator {
600            selectors,
601            iterator: iter,
602        }
603    }
604}
605
606impl Iterator for QuerySelectorIterator {
607    type Item = DomRoot<Node>;
608
609    fn next(&mut self) -> Option<DomRoot<Node>> {
610        let selectors = &self.selectors;
611
612        let (quirks_mode, filter) = match self.iterator.by_ref().peek() {
613            Some(node) => (node.owner_doc().quirks_mode(), BloomFilter::default()),
614            None => return None,
615        };
616
617        self.iterator.by_ref().find_map(|node| {
618            if let Some(element) = DomRoot::downcast(node) {
619                let mut nth_index_cache = Default::default();
620                let mut ctx = MatchingContext::new(
621                    MatchingMode::Normal,
622                    Some(&filter),
623                    &mut nth_index_cache,
624                    quirks_mode,
625                    NeedsSelectorFlags::No,
626                    MatchingForInvalidation::No,
627                );
628                if matches_selector_list(selectors, &SelectorWrapper::Borrowed(&element), &mut ctx)
629                {
630                    return Some(DomRoot::upcast(element));
631                }
632            }
633            None
634        })
635    }
636}
637
638impl Node {
639    fn rare_data(&self) -> Ref<'_, Option<Box<NodeRareData>>> {
640        self.rare_data.borrow()
641    }
642
643    fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
644        let mut rare_data = self.rare_data.borrow_mut();
645        if rare_data.is_none() {
646            *rare_data = Some(Default::default());
647        }
648        RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
649    }
650
651    /// Returns true if this node is before `other` in the same connected DOM
652    /// tree.
653    pub(crate) fn is_before(&self, other: &Node) -> bool {
654        let cmp = other.CompareDocumentPosition(self);
655        if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
656            return false;
657        }
658
659        cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
660    }
661
662    /// Return all registered mutation observers for this node. Lazily initialize the
663    /// raredata if it does not exist.
664    pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
665        RefMut::map(self.ensure_rare_data(), |rare_data| {
666            &mut rare_data.mutation_observers
667        })
668    }
669
670    pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
671        let rare_data: Ref<'_, _> = self.rare_data.borrow();
672
673        if rare_data.is_none() {
674            return None;
675        }
676        Some(Ref::map(rare_data, |rare_data| {
677            &rare_data.as_ref().unwrap().mutation_observers
678        }))
679    }
680
681    /// Add a new mutation observer for a given node.
682    #[cfg_attr(crown, expect(crown::unrooted_must_root))]
683    pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
684        self.ensure_rare_data().mutation_observers.push(observer);
685    }
686
687    /// Removes the mutation observer for a given node.
688    pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
689        self.ensure_rare_data()
690            .mutation_observers
691            .retain(|reg_obs| &*reg_obs.observer != observer)
692    }
693
694    /// Dumps the subtree rooted at this node, for debugging.
695    pub(crate) fn dump(&self) {
696        self.dump_indent(0);
697    }
698
699    /// Dumps the node tree, for debugging, with indentation.
700    pub(crate) fn dump_indent(&self, indent: u32) {
701        let mut s = String::new();
702        for _ in 0..indent {
703            s.push_str("    ");
704        }
705
706        s.push_str(&self.debug_str());
707        debug!("{:?}", s);
708
709        // FIXME: this should have a pure version?
710        for kid in self.children() {
711            kid.dump_indent(indent + 1)
712        }
713    }
714
715    /// Returns a string that describes this node.
716    pub(crate) fn debug_str(&self) -> String {
717        format!("{:?}", self.type_id())
718    }
719
720    /// <https://dom.spec.whatwg.org/#in-a-document-tree>
721    pub(crate) fn is_in_a_document_tree(&self) -> bool {
722        self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
723    }
724
725    /// Return true iff node's root is a shadow-root.
726    pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
727        self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
728    }
729
730    pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
731        self.flags
732            .get()
733            .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
734    }
735
736    pub(crate) fn set_weird_parser_insertion_mode(&self) {
737        self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
738    }
739
740    /// <https://dom.spec.whatwg.org/#connected>
741    pub(crate) fn is_connected(&self) -> bool {
742        self.flags.get().contains(NodeFlags::IS_CONNECTED)
743    }
744
745    pub(crate) fn set_in_ua_widget(&self, in_ua_widget: bool) {
746        self.set_flag(NodeFlags::IS_IN_UA_WIDGET, in_ua_widget)
747    }
748
749    pub(crate) fn is_in_ua_widget(&self) -> bool {
750        self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
751    }
752
753    /// Returns the type ID of this node.
754    pub(crate) fn type_id(&self) -> NodeTypeId {
755        match *self.eventtarget.type_id() {
756            EventTargetTypeId::Node(type_id) => type_id,
757            _ => unreachable!(),
758        }
759    }
760
761    /// <https://dom.spec.whatwg.org/#concept-node-length>
762    pub(crate) fn len(&self) -> u32 {
763        match self.type_id() {
764            NodeTypeId::DocumentType => 0,
765            NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
766            _ => self.children_count(),
767        }
768    }
769
770    pub(crate) fn is_empty(&self) -> bool {
771        // A node is considered empty if its length is 0.
772        self.len() == 0
773    }
774
775    /// <https://dom.spec.whatwg.org/#concept-tree-index>
776    pub(crate) fn index(&self) -> u32 {
777        self.preceding_siblings().count() as u32
778    }
779
780    /// Returns true if this node has a parent.
781    pub(crate) fn has_parent(&self) -> bool {
782        self.parent_node.get().is_some()
783    }
784
785    pub(crate) fn children_count(&self) -> u32 {
786        self.children_count.get()
787    }
788
789    pub(crate) fn ranges(&self) -> RefMut<'_, WeakRangeVec> {
790        RefMut::map(self.ensure_rare_data(), |rare_data| &mut rare_data.ranges)
791    }
792
793    pub(crate) fn ranges_is_empty(&self) -> bool {
794        self.rare_data()
795            .as_ref()
796            .is_none_or(|data| data.ranges.is_empty())
797    }
798
799    #[inline]
800    pub(crate) fn is_doctype(&self) -> bool {
801        self.type_id() == NodeTypeId::DocumentType
802    }
803
804    pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
805        self.flags.get().contains(flag)
806    }
807
808    pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
809        let mut flags = self.flags.get();
810
811        if value {
812            flags.insert(flag);
813        } else {
814            flags.remove(flag);
815        }
816
817        self.flags.set(flags);
818    }
819
820    // FIXME(emilio): This and the function below should move to Element.
821    pub(crate) fn note_dirty_descendants(&self) {
822        self.owner_doc().note_node_with_dirty_descendants(self);
823    }
824
825    pub(crate) fn has_dirty_descendants(&self) -> bool {
826        self.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)
827    }
828
829    pub(crate) fn rev_version(&self) {
830        // The new version counter is 1 plus the max of the node's current version counter,
831        // its descendants version, and the document's version. Normally, this will just be
832        // the document's version, but we do have to deal with the case where the node has moved
833        // document, so may have a higher version count than its owning document.
834        let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
835        let version = cmp::max(
836            self.inclusive_descendants_version(),
837            doc.inclusive_descendants_version(),
838        ) + 1;
839
840        // This `while` loop is equivalent to iterating over the non-shadow-inclusive ancestors
841        // without creating intermediate rooted DOM objects.
842        let mut node = &MutNullableDom::new(Some(self));
843        while let Some(p) = node.if_is_some(|p| {
844            p.inclusive_descendants_version.set(version);
845            &p.parent_node
846        }) {
847            node = p
848        }
849        doc.inclusive_descendants_version.set(version);
850    }
851
852    pub(crate) fn dirty(&self, damage: NodeDamage) {
853        self.rev_version();
854        if !self.is_connected() {
855            return;
856        }
857
858        match self.type_id() {
859            NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
860                // For content changes in text nodes, we should accurately use
861                // [`NodeDamage::ContentOrHeritage`] to mark the parent node, thereby
862                // reducing the scope of incremental box tree construction.
863                self.parent_node
864                    .get()
865                    .unwrap()
866                    .dirty(NodeDamage::ContentOrHeritage)
867            },
868            NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(damage),
869            NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
870                .downcast::<ShadowRoot>()
871                .unwrap()
872                .Host()
873                .upcast::<Element>()
874                .restyle(damage),
875            _ => {},
876        };
877    }
878
879    /// The maximum version number of this node's descendants, including itself
880    pub(crate) fn inclusive_descendants_version(&self) -> u64 {
881        self.inclusive_descendants_version.get()
882    }
883
884    /// Iterates over this node and all its descendants, in preorder.
885    pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
886        TreeIterator::new(self, shadow_including)
887    }
888
889    pub(crate) fn inclusively_following_siblings(
890        &self,
891    ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
892        SimpleNodeIterator {
893            current: Some(DomRoot::from_ref(self)),
894            next_node: |n| n.GetNextSibling(),
895        }
896    }
897
898    pub(crate) fn inclusively_preceding_siblings(
899        &self,
900    ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
901        SimpleNodeIterator {
902            current: Some(DomRoot::from_ref(self)),
903            next_node: |n| n.GetPreviousSibling(),
904        }
905    }
906
907    pub(crate) fn common_ancestor(
908        &self,
909        other: &Node,
910        shadow_including: ShadowIncluding,
911    ) -> Option<DomRoot<Node>> {
912        self.inclusive_ancestors(shadow_including).find(|ancestor| {
913            other
914                .inclusive_ancestors(shadow_including)
915                .any(|node| node == *ancestor)
916        })
917    }
918
919    pub(crate) fn common_ancestor_in_flat_tree(&self, other: &Node) -> Option<DomRoot<Node>> {
920        self.inclusive_ancestors_in_flat_tree().find(|ancestor| {
921            other
922                .inclusive_ancestors_in_flat_tree()
923                .any(|node| node == *ancestor)
924        })
925    }
926
927    pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
928        self == child || self.is_ancestor_of(child)
929    }
930
931    pub(crate) fn is_ancestor_of(&self, child: &Node) -> bool {
932        let mut current = &MutNullableDom::new(Some(child));
933        let mut done = false;
934
935        while let Some(node) = current.if_is_some(|node| {
936            done = node == self;
937            &node.parent_node
938        }) {
939            if done {
940                break;
941            }
942            current = node
943        }
944        done
945    }
946
947    pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
948        node.inclusive_ancestors(ShadowIncluding::Yes)
949            .any(|ancestor| &*ancestor == self)
950    }
951
952    pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
953        SimpleNodeIterator {
954            current: self.GetNextSibling(),
955            next_node: |n| n.GetNextSibling(),
956        }
957    }
958
959    pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
960        SimpleNodeIterator {
961            current: self.GetPreviousSibling(),
962            next_node: |n| n.GetPreviousSibling(),
963        }
964    }
965
966    pub(crate) fn following_nodes(&self, root: &Node) -> FollowingNodeIterator {
967        FollowingNodeIterator {
968            current: Some(DomRoot::from_ref(self)),
969            root: DomRoot::from_ref(root),
970        }
971    }
972
973    pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
974        PrecedingNodeIterator {
975            current: Some(DomRoot::from_ref(self)),
976            root: DomRoot::from_ref(root),
977        }
978    }
979
980    /// Return an iterator that moves from `self` down the tree, choosing the last child
981    /// at each step of the way.
982    pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
983        SimpleNodeIterator {
984            current: self.GetLastChild(),
985            next_node: |n| n.GetLastChild(),
986        }
987    }
988
989    pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
990        child
991            .parent_node
992            .get()
993            .is_some_and(|parent| &*parent == self)
994    }
995
996    pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
997        TrustedNodeAddress(self as *const Node as *const libc::c_void)
998    }
999
1000    pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1001        self.owner_window().padding_query_without_reflow(self)
1002    }
1003
1004    pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1005        self.owner_window()
1006            .box_area_query(self, BoxAreaType::Content, false)
1007    }
1008
1009    pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1010        self.owner_window()
1011            .box_area_query(self, BoxAreaType::Border, false)
1012    }
1013
1014    pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1015        self.owner_window()
1016            .box_area_query(self, BoxAreaType::Padding, false)
1017    }
1018
1019    pub(crate) fn border_boxes(&self) -> Vec<Rect<Au, CSSPixel>> {
1020        self.owner_window()
1021            .box_areas_query(self, BoxAreaType::Border)
1022    }
1023
1024    pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1025        self.owner_window().client_rect_query(self)
1026    }
1027
1028    /// <https://drafts.csswg.org/cssom-view/#dom-element-scrollwidth>
1029    /// <https://drafts.csswg.org/cssom-view/#dom-element-scrollheight>
1030    pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1031        // "1. Let document be the element’s node document.""
1032        let document = self.owner_doc();
1033
1034        // "2. If document is not the active document, return zero and terminate these steps.""
1035        if !document.is_active() {
1036            return Rect::zero();
1037        }
1038
1039        // "3. Let viewport width/height be the width of the viewport excluding the width/height of the
1040        // scroll bar, if any, or zero if there is no viewport."
1041        let window = document.window();
1042        let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1043
1044        let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1045        let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1046        let is_body_element = self
1047            .downcast::<HTMLElement>()
1048            .is_some_and(|e| e.is_body_element());
1049
1050        // "4. If the element is the root element and document is not in quirks mode
1051        // return max(viewport scrolling area width/height, viewport width/height)."
1052        // "5. If the element is the body element, document is in quirks mode and the
1053        // element is not potentially scrollable, return max(viewport scrolling area
1054        // width, viewport width)."
1055        if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1056            let viewport_scrolling_area = window.scrolling_area_query(None);
1057            return Rect::new(
1058                viewport_scrolling_area.origin,
1059                viewport_scrolling_area.size.max(viewport),
1060            );
1061        }
1062
1063        // "6. If the element does not have any associated box return zero and terminate
1064        // these steps."
1065        // "7. Return the width of the element’s scrolling area."
1066        window.scrolling_area_query(Some(self))
1067    }
1068
1069    /// <https://dom.spec.whatwg.org/#dom-childnode-before>
1070    pub(crate) fn before(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
1071        // Step 1.
1072        let parent = &self.parent_node;
1073
1074        // Step 2.
1075        let parent = match parent.get() {
1076            None => return Ok(()),
1077            Some(parent) => parent,
1078        };
1079
1080        // Step 3.
1081        let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1082
1083        // Step 4.
1084        let node = self
1085            .owner_doc()
1086            .node_from_nodes_and_strings(nodes, can_gc)?;
1087
1088        // Step 5.
1089        let viable_previous_sibling = match viable_previous_sibling {
1090            Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1091            None => parent.first_child.get(),
1092        };
1093
1094        // Step 6.
1095        Node::pre_insert(&node, &parent, viable_previous_sibling.as_deref(), can_gc)?;
1096
1097        Ok(())
1098    }
1099
1100    /// <https://dom.spec.whatwg.org/#dom-childnode-after>
1101    pub(crate) fn after(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
1102        // Step 1.
1103        let parent = &self.parent_node;
1104
1105        // Step 2.
1106        let parent = match parent.get() {
1107            None => return Ok(()),
1108            Some(parent) => parent,
1109        };
1110
1111        // Step 3.
1112        let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1113
1114        // Step 4.
1115        let node = self
1116            .owner_doc()
1117            .node_from_nodes_and_strings(nodes, can_gc)?;
1118
1119        // Step 5.
1120        Node::pre_insert(&node, &parent, viable_next_sibling.as_deref(), can_gc)?;
1121
1122        Ok(())
1123    }
1124
1125    /// <https://dom.spec.whatwg.org/#dom-childnode-replacewith>
1126    pub(crate) fn replace_with(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
1127        // Step 1. Let parent be this’s parent.
1128        let Some(parent) = self.GetParentNode() else {
1129            // Step 2. If parent is null, then return.
1130            return Ok(());
1131        };
1132
1133        // Step 3. Let viableNextSibling be this’s first following sibling not in nodes; otherwise null.
1134        let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1135
1136        // Step 4. Let node be the result of converting nodes into a node, given nodes and this’s node document.
1137        let node = self
1138            .owner_doc()
1139            .node_from_nodes_and_strings(nodes, can_gc)?;
1140
1141        if self.parent_node == Some(&*parent) {
1142            // Step 5. If this’s parent is parent, replace this with node within parent.
1143            parent.ReplaceChild(&node, self, can_gc)?;
1144        } else {
1145            // Step 6. Otherwise, pre-insert node into parent before viableNextSibling.
1146            Node::pre_insert(&node, &parent, viable_next_sibling.as_deref(), can_gc)?;
1147        }
1148        Ok(())
1149    }
1150
1151    /// <https://dom.spec.whatwg.org/#dom-parentnode-prepend>
1152    pub(crate) fn prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
1153        // Step 1.
1154        let doc = self.owner_doc();
1155        let node = doc.node_from_nodes_and_strings(nodes, can_gc)?;
1156        // Step 2.
1157        let first_child = self.first_child.get();
1158        Node::pre_insert(&node, self, first_child.as_deref(), can_gc).map(|_| ())
1159    }
1160
1161    /// <https://dom.spec.whatwg.org/#dom-parentnode-append>
1162    pub(crate) fn append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
1163        // Step 1.
1164        let doc = self.owner_doc();
1165        let node = doc.node_from_nodes_and_strings(nodes, can_gc)?;
1166        // Step 2.
1167        self.AppendChild(&node, can_gc).map(|_| ())
1168    }
1169
1170    /// <https://dom.spec.whatwg.org/#dom-parentnode-replacechildren>
1171    pub(crate) fn replace_children(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
1172        // Step 1. Let node be the result of converting nodes into a node given nodes and this’s
1173        // node document.
1174        let doc = self.owner_doc();
1175        let node = doc.node_from_nodes_and_strings(nodes, can_gc)?;
1176
1177        // Step 2. Ensure pre-insert validity of node into this before null.
1178        Node::ensure_pre_insertion_validity(&node, self, None)?;
1179
1180        // Step 3. Replace all with node within this.
1181        Node::replace_all(Some(&node), self, can_gc);
1182        Ok(())
1183    }
1184
1185    /// <https://dom.spec.whatwg.org/#dom-parentnode-queryselector>
1186    pub(crate) fn query_selector(
1187        &self,
1188        selectors: DOMString,
1189    ) -> Fallible<Option<DomRoot<Element>>> {
1190        // Step 1.
1191        let doc = self.owner_doc();
1192        match SelectorParser::parse_author_origin_no_namespace(
1193            &selectors.str(),
1194            &UrlExtraData(doc.url().get_arc()),
1195        ) {
1196            // Step 2.
1197            Err(_) => Err(Error::Syntax(None)),
1198            // Step 3.
1199            Ok(selectors) => {
1200                let mut nth_index_cache = Default::default();
1201                let filter = BloomFilter::default();
1202                let mut ctx = MatchingContext::new(
1203                    MatchingMode::Normal,
1204                    Some(&filter),
1205                    &mut nth_index_cache,
1206                    doc.quirks_mode(),
1207                    NeedsSelectorFlags::No,
1208                    MatchingForInvalidation::No,
1209                );
1210                let mut descendants = self.traverse_preorder(ShadowIncluding::No);
1211                // Skip the root of the tree.
1212                assert!(&*descendants.next().unwrap() == self);
1213                Ok(descendants.filter_map(DomRoot::downcast).find(|element| {
1214                    matches_selector_list(&selectors, &SelectorWrapper::Borrowed(element), &mut ctx)
1215                }))
1216            },
1217        }
1218    }
1219
1220    /// <https://dom.spec.whatwg.org/#scope-match-a-selectors-string>
1221    /// Get an iterator over all nodes which match a set of selectors
1222    /// Be careful not to do anything which may manipulate the DOM tree
1223    /// whilst iterating, otherwise the iterator may be invalidated.
1224    pub(crate) fn query_selector_iter(
1225        &self,
1226        selectors: DOMString,
1227    ) -> Fallible<QuerySelectorIterator> {
1228        // Step 1.
1229        let url = self.owner_doc().url();
1230        match SelectorParser::parse_author_origin_no_namespace(
1231            &selectors.str(),
1232            &UrlExtraData(url.get_arc()),
1233        ) {
1234            // Step 2.
1235            Err(_) => Err(Error::Syntax(None)),
1236            // Step 3.
1237            Ok(selectors) => {
1238                let mut descendants = self.traverse_preorder(ShadowIncluding::No);
1239                // Skip the root of the tree.
1240                assert!(&*descendants.next().unwrap() == self);
1241                Ok(QuerySelectorIterator::new(descendants, selectors))
1242            },
1243        }
1244    }
1245
1246    /// <https://dom.spec.whatwg.org/#dom-parentnode-queryselectorall>
1247    pub(crate) fn query_selector_all(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
1248        let window = self.owner_window();
1249        let iter = self.query_selector_iter(selectors)?;
1250        Ok(NodeList::new_simple_list(&window, iter, CanGc::note()))
1251    }
1252
1253    pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1254        SimpleNodeIterator {
1255            current: self.GetParentNode(),
1256            next_node: |n| n.GetParentNode(),
1257        }
1258    }
1259
1260    /// <https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor>
1261    pub(crate) fn inclusive_ancestors(
1262        &self,
1263        shadow_including: ShadowIncluding,
1264    ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1265        SimpleNodeIterator {
1266            current: Some(DomRoot::from_ref(self)),
1267            next_node: move |n| {
1268                if shadow_including == ShadowIncluding::Yes {
1269                    if let Some(shadow_root) = n.downcast::<ShadowRoot>() {
1270                        return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1271                    }
1272                }
1273                n.GetParentNode()
1274            },
1275        }
1276    }
1277
1278    pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1279        self.owner_doc.get().unwrap()
1280    }
1281
1282    pub(crate) fn set_owner_doc(&self, document: &Document) {
1283        self.owner_doc.set(Some(document));
1284    }
1285
1286    pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1287        self.rare_data()
1288            .as_ref()?
1289            .containing_shadow_root
1290            .as_ref()
1291            .map(|sr| DomRoot::from_ref(&**sr))
1292    }
1293
1294    pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1295        self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1296    }
1297
1298    pub(crate) fn is_in_html_doc(&self) -> bool {
1299        self.owner_doc().is_html_document()
1300    }
1301
1302    pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1303        self.is_connected() && self.owner_doc().browsing_context().is_some()
1304    }
1305
1306    pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1307        SimpleNodeIterator {
1308            current: self.GetFirstChild(),
1309            next_node: |n| n.GetNextSibling(),
1310        }
1311    }
1312
1313    pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1314        SimpleNodeIterator {
1315            current: self.GetLastChild(),
1316            next_node: |n| n.GetPreviousSibling(),
1317        }
1318    }
1319
1320    pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1321        self.children()
1322            .filter_map(DomRoot::downcast as fn(_) -> _)
1323            .peekable()
1324    }
1325
1326    pub(crate) fn remove_self(&self, can_gc: CanGc) {
1327        if let Some(ref parent) = self.GetParentNode() {
1328            Node::remove(self, parent, SuppressObserver::Unsuppressed, can_gc);
1329        }
1330    }
1331
1332    pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1333        let mut rare_data = self.ensure_rare_data();
1334
1335        if rare_data.unique_id.is_none() {
1336            let node_id = UniqueId::new();
1337            ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string());
1338            rare_data.unique_id = Some(node_id);
1339        }
1340        rare_data
1341            .unique_id
1342            .as_ref()
1343            .unwrap()
1344            .borrow()
1345            .simple()
1346            .to_string()
1347    }
1348
1349    pub(crate) fn summarize(&self, can_gc: CanGc) -> NodeInfo {
1350        let USVString(base_uri) = self.BaseURI();
1351        let node_type = self.NodeType();
1352        let pipeline = self.owner_window().pipeline_id();
1353
1354        let maybe_shadow_root = self.downcast::<ShadowRoot>();
1355        let shadow_root_mode = maybe_shadow_root
1356            .map(ShadowRoot::Mode)
1357            .map(ShadowRootMode::convert);
1358        let host = maybe_shadow_root
1359            .map(ShadowRoot::Host)
1360            .map(|host| host.upcast::<Node>().unique_id(pipeline));
1361        let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1362            let Some(root) = potential_host.shadow_root() else {
1363                return false;
1364            };
1365            !root.is_user_agent_widget() || pref!(inspector_show_servo_internal_shadow_roots)
1366        });
1367
1368        let num_children = if is_shadow_host {
1369            // Shadow roots count as children
1370            self.ChildNodes(can_gc).Length() as usize + 1
1371        } else {
1372            self.ChildNodes(can_gc).Length() as usize
1373        };
1374
1375        let window = self.owner_window();
1376        let display = self
1377            .downcast::<Element>()
1378            .map(|elem| window.GetComputedStyle(elem, None))
1379            .map(|style| style.Display().into());
1380
1381        NodeInfo {
1382            unique_id: self.unique_id(pipeline),
1383            host,
1384            base_uri,
1385            parent: self
1386                .GetParentNode()
1387                .map_or("".to_owned(), |node| node.unique_id(pipeline)),
1388            node_type,
1389            is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1390            node_name: String::from(self.NodeName()),
1391            node_value: self.GetNodeValue().map(|v| v.into()),
1392            num_children,
1393            attrs: self.downcast().map(Element::summarize).unwrap_or(vec![]),
1394            is_shadow_host,
1395            shadow_root_mode,
1396            display,
1397            // It is not entirely clear when this should be set to false.
1398            // Firefox considers nodes with "display: contents" to be displayed.
1399            // The doctype node is displayed despite being `display: none`.
1400            is_displayed: !self.is_display_none() || self.is::<DocumentType>(),
1401            doctype_name: self
1402                .downcast::<DocumentType>()
1403                .map(DocumentType::name)
1404                .cloned()
1405                .map(String::from),
1406            doctype_public_identifier: self
1407                .downcast::<DocumentType>()
1408                .map(DocumentType::public_id)
1409                .cloned()
1410                .map(String::from),
1411            doctype_system_identifier: self
1412                .downcast::<DocumentType>()
1413                .map(DocumentType::system_id)
1414                .cloned()
1415                .map(String::from),
1416        }
1417    }
1418
1419    /// Used by `HTMLTableSectionElement::InsertRow` and `HTMLTableRowElement::InsertCell`
1420    pub(crate) fn insert_cell_or_row<F, G, I>(
1421        &self,
1422        index: i32,
1423        get_items: F,
1424        new_child: G,
1425        can_gc: CanGc,
1426    ) -> Fallible<DomRoot<HTMLElement>>
1427    where
1428        F: Fn() -> DomRoot<HTMLCollection>,
1429        G: Fn() -> DomRoot<I>,
1430        I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1431    {
1432        if index < -1 {
1433            return Err(Error::IndexSize(None));
1434        }
1435
1436        let tr = new_child();
1437
1438        {
1439            let tr_node = tr.upcast::<Node>();
1440            if index == -1 {
1441                self.InsertBefore(tr_node, None, can_gc)?;
1442            } else {
1443                let items = get_items();
1444                let node = match items
1445                    .elements_iter()
1446                    .map(DomRoot::upcast::<Node>)
1447                    .map(Some)
1448                    .chain(iter::once(None))
1449                    .nth(index as usize)
1450                {
1451                    None => return Err(Error::IndexSize(None)),
1452                    Some(node) => node,
1453                };
1454                self.InsertBefore(tr_node, node.as_deref(), can_gc)?;
1455            }
1456        }
1457
1458        Ok(DomRoot::upcast::<HTMLElement>(tr))
1459    }
1460
1461    /// Used by `HTMLTableSectionElement::DeleteRow` and `HTMLTableRowElement::DeleteCell`
1462    pub(crate) fn delete_cell_or_row<F, G>(
1463        &self,
1464        index: i32,
1465        get_items: F,
1466        is_delete_type: G,
1467        can_gc: CanGc,
1468    ) -> ErrorResult
1469    where
1470        F: Fn() -> DomRoot<HTMLCollection>,
1471        G: Fn(&Element) -> bool,
1472    {
1473        let element = match index {
1474            index if index < -1 => return Err(Error::IndexSize(None)),
1475            -1 => {
1476                let last_child = self.upcast::<Node>().GetLastChild();
1477                match last_child.and_then(|node| {
1478                    node.inclusively_preceding_siblings()
1479                        .filter_map(DomRoot::downcast::<Element>)
1480                        .find(|elem| is_delete_type(elem))
1481                }) {
1482                    Some(element) => element,
1483                    None => return Ok(()),
1484                }
1485            },
1486            index => match get_items().Item(index as u32) {
1487                Some(element) => element,
1488                None => return Err(Error::IndexSize(None)),
1489            },
1490        };
1491
1492        element.upcast::<Node>().remove_self(can_gc);
1493        Ok(())
1494    }
1495
1496    pub(crate) fn get_stylesheet(&self) -> Option<ServoArc<Stylesheet>> {
1497        if let Some(node) = self.downcast::<HTMLStyleElement>() {
1498            node.get_stylesheet()
1499        } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1500            node.get_stylesheet()
1501        } else {
1502            None
1503        }
1504    }
1505
1506    pub(crate) fn get_cssom_stylesheet(&self) -> Option<DomRoot<CSSStyleSheet>> {
1507        if let Some(node) = self.downcast::<HTMLStyleElement>() {
1508            node.get_cssom_stylesheet()
1509        } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1510            node.get_cssom_stylesheet(CanGc::note())
1511        } else {
1512            None
1513        }
1514    }
1515
1516    pub(crate) fn is_styled(&self) -> bool {
1517        self.style_data.borrow().is_some()
1518    }
1519
1520    pub(crate) fn is_display_none(&self) -> bool {
1521        self.style_data.borrow().as_ref().is_none_or(|data| {
1522            data.element_data
1523                .borrow()
1524                .styles
1525                .primary()
1526                .get_box()
1527                .display
1528                .is_none()
1529        })
1530    }
1531
1532    pub(crate) fn style(&self) -> Option<ServoArc<ComputedValues>> {
1533        self.owner_window().layout_reflow(QueryMsg::StyleQuery);
1534        self.style_data
1535            .borrow()
1536            .as_ref()
1537            .map(|data| data.element_data.borrow().styles.primary().clone())
1538    }
1539
1540    /// <https://html.spec.whatwg.org/multipage/#language>
1541    pub(crate) fn get_lang(&self) -> Option<String> {
1542        self.inclusive_ancestors(ShadowIncluding::Yes)
1543            .find_map(|node| {
1544                node.downcast::<Element>().and_then(|el| {
1545                    el.get_attribute(&ns!(xml), &local_name!("lang"))
1546                        .or_else(|| el.get_attribute(&ns!(), &local_name!("lang")))
1547                        .map(|attr| String::from(attr.Value()))
1548                })
1549                // TODO: Check meta tags for a pragma-set default language
1550                // TODO: Check HTTP Content-Language header
1551            })
1552    }
1553
1554    /// <https://dom.spec.whatwg.org/#assign-slotables-for-a-tree>
1555    pub(crate) fn assign_slottables_for_a_tree(&self) {
1556        // NOTE: This method traverses all descendants of the node and is potentially very
1557        // expensive. If the node is neither a shadowroot nor a slot then assigning slottables
1558        // for it won't have any effect, so we take a fast path out.
1559        let is_shadow_root_with_slots = self
1560            .downcast::<ShadowRoot>()
1561            .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
1562        if !is_shadow_root_with_slots && !self.is::<HTMLSlotElement>() {
1563            return;
1564        }
1565
1566        // > To assign slottables for a tree, given a node root, run assign slottables for each slot
1567        // > slot in root’s inclusive descendants, in tree order.
1568        for node in self.traverse_preorder(ShadowIncluding::No) {
1569            if let Some(slot) = node.downcast::<HTMLSlotElement>() {
1570                slot.assign_slottables();
1571            }
1572        }
1573    }
1574
1575    pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
1576        let assigned_slot = self
1577            .rare_data
1578            .borrow()
1579            .as_ref()?
1580            .slottable_data
1581            .assigned_slot
1582            .as_ref()?
1583            .as_rooted();
1584        Some(assigned_slot)
1585    }
1586
1587    pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
1588        self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
1589    }
1590
1591    pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
1592        let manually_assigned_slot = self
1593            .rare_data
1594            .borrow()
1595            .as_ref()?
1596            .slottable_data
1597            .manual_slot_assignment
1598            .as_ref()?
1599            .as_rooted();
1600        Some(manually_assigned_slot)
1601    }
1602
1603    pub(crate) fn set_manual_slot_assignment(
1604        &self,
1605        manually_assigned_slot: Option<&HTMLSlotElement>,
1606    ) {
1607        self.ensure_rare_data()
1608            .slottable_data
1609            .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
1610    }
1611
1612    /// Gets the parent of this node from the perspective of layout and style.
1613    ///
1614    /// The returned node is the node's assigned slot, if any, or the
1615    /// shadow host if it's a shadow root. Otherwise, it is the node's
1616    /// parent.
1617    pub(crate) fn parent_in_flat_tree(&self) -> Option<DomRoot<Node>> {
1618        if let Some(assigned_slot) = self.assigned_slot() {
1619            return Some(DomRoot::upcast(assigned_slot));
1620        }
1621
1622        let parent_or_none = self.GetParentNode();
1623        if let Some(parent) = parent_or_none.as_deref() {
1624            if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
1625                return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1626            }
1627        }
1628
1629        parent_or_none
1630    }
1631
1632    pub(crate) fn inclusive_ancestors_in_flat_tree(
1633        &self,
1634    ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1635        SimpleNodeIterator {
1636            current: Some(DomRoot::from_ref(self)),
1637            next_node: move |n| n.parent_in_flat_tree(),
1638        }
1639    }
1640
1641    /// We are marking this as an implemented pseudo element.
1642    pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
1643        // Implemented pseudo element should exist only in the UA shadow DOM.
1644        debug_assert!(self.is_in_ua_widget());
1645        self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
1646    }
1647
1648    pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
1649        self.rare_data
1650            .borrow()
1651            .as_ref()
1652            .and_then(|rare_data| rare_data.implemented_pseudo_element)
1653    }
1654}
1655
1656/// Iterate through `nodes` until we find a `Node` that is not in `not_in`
1657fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
1658where
1659    I: Iterator<Item = DomRoot<Node>>,
1660{
1661    nodes.find(|node| {
1662        not_in.iter().all(|n| match *n {
1663            NodeOrString::Node(ref n) => n != node,
1664            _ => true,
1665        })
1666    })
1667}
1668
1669/// If the given untrusted node address represents a valid DOM node in the given runtime,
1670/// returns it.
1671#[expect(unsafe_code)]
1672pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
1673    let node = unsafe { Node::from_untrusted_node_address(candidate) };
1674    DomRoot::from_ref(node)
1675}
1676
1677#[expect(unsafe_code)]
1678pub(crate) trait LayoutNodeHelpers<'dom> {
1679    fn type_id_for_layout(self) -> NodeTypeId;
1680
1681    fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>>;
1682    fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>>;
1683    fn first_child_ref(self) -> Option<LayoutDom<'dom, Node>>;
1684    fn last_child_ref(self) -> Option<LayoutDom<'dom, Node>>;
1685    fn prev_sibling_ref(self) -> Option<LayoutDom<'dom, Node>>;
1686    fn next_sibling_ref(self) -> Option<LayoutDom<'dom, Node>>;
1687
1688    fn owner_doc_for_layout(self) -> LayoutDom<'dom, Document>;
1689    fn containing_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>>;
1690    fn assigned_slot_for_layout(self) -> Option<LayoutDom<'dom, HTMLSlotElement>>;
1691
1692    fn is_element_for_layout(&self) -> bool;
1693    fn is_text_node_for_layout(&self) -> bool;
1694    unsafe fn get_flag(self, flag: NodeFlags) -> bool;
1695    unsafe fn set_flag(self, flag: NodeFlags, value: bool);
1696
1697    fn style_data(self) -> Option<&'dom StyleData>;
1698    fn layout_data(self) -> Option<&'dom GenericLayoutData>;
1699
1700    /// Initialize the style data of this node.
1701    ///
1702    /// # Safety
1703    ///
1704    /// This method is unsafe because it modifies the given node during
1705    /// layout. Callers should ensure that no other layout thread is
1706    /// attempting to read or modify the opaque layout data of this node.
1707    unsafe fn initialize_style_data(self);
1708
1709    /// Initialize the opaque layout data of this node.
1710    ///
1711    /// # Safety
1712    ///
1713    /// This method is unsafe because it modifies the given node during
1714    /// layout. Callers should ensure that no other layout thread is
1715    /// attempting to read or modify the opaque layout data of this node.
1716    unsafe fn initialize_layout_data(self, data: Box<GenericLayoutData>);
1717
1718    /// Clear the style and opaque layout data of this node.
1719    ///
1720    /// # Safety
1721    ///
1722    /// This method is unsafe because it modifies the given node during
1723    /// layout. Callers should ensure that no other layout thread is
1724    /// attempting to read or modify the opaque layout data of this node.
1725    unsafe fn clear_style_and_layout_data(self);
1726
1727    /// Whether this element serve as a container of editable text for a text input
1728    /// that is implemented as an UA widget.
1729    fn is_single_line_text_inner_editor(&self) -> bool;
1730
1731    /// Whether this element serve as a container of any text inside a text input
1732    /// that is implemented as an UA widget.
1733    fn is_text_container_of_single_line_input(&self) -> bool;
1734    fn text_content(self) -> Cow<'dom, str>;
1735    fn selection(self) -> Option<SharedSelection>;
1736    fn image_url(self) -> Option<ServoUrl>;
1737    fn image_density(self) -> Option<f64>;
1738    fn image_data(self) -> Option<(Option<Image>, Option<ImageMetadata>)>;
1739    fn showing_broken_image_icon(self) -> bool;
1740    fn canvas_data(self) -> Option<HTMLCanvasData>;
1741    fn media_data(self) -> Option<HTMLMediaData>;
1742    fn svg_data(self) -> Option<SVGElementData<'dom>>;
1743    fn iframe_browsing_context_id(self) -> Option<BrowsingContextId>;
1744    fn iframe_pipeline_id(self) -> Option<PipelineId>;
1745    fn opaque(self) -> OpaqueNode;
1746    fn implemented_pseudo_element(&self) -> Option<PseudoElement>;
1747    fn is_in_ua_widget(&self) -> bool;
1748}
1749
1750impl<'dom> LayoutDom<'dom, Node> {
1751    #[inline]
1752    #[expect(unsafe_code)]
1753    pub(crate) fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
1754        unsafe { self.unsafe_get().parent_node.get_inner_as_layout() }
1755    }
1756}
1757
1758impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
1759    #[inline]
1760    fn type_id_for_layout(self) -> NodeTypeId {
1761        self.unsafe_get().type_id()
1762    }
1763
1764    #[inline]
1765    fn is_element_for_layout(&self) -> bool {
1766        (*self).is::<Element>()
1767    }
1768
1769    fn is_text_node_for_layout(&self) -> bool {
1770        self.type_id_for_layout() ==
1771            NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text))
1772    }
1773
1774    #[inline]
1775    #[expect(unsafe_code)]
1776    fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
1777        unsafe { self.unsafe_get().parent_node.get_inner_as_layout() }
1778    }
1779
1780    #[inline]
1781    fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
1782        let parent = self.parent_node_ref();
1783        if let Some(parent) = parent {
1784            if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
1785                return Some(shadow_root.get_host_for_layout().upcast());
1786            }
1787        }
1788        parent
1789    }
1790
1791    #[inline]
1792    #[expect(unsafe_code)]
1793    fn first_child_ref(self) -> Option<LayoutDom<'dom, Node>> {
1794        unsafe { self.unsafe_get().first_child.get_inner_as_layout() }
1795    }
1796
1797    #[inline]
1798    #[expect(unsafe_code)]
1799    fn last_child_ref(self) -> Option<LayoutDom<'dom, Node>> {
1800        unsafe { self.unsafe_get().last_child.get_inner_as_layout() }
1801    }
1802
1803    #[inline]
1804    #[expect(unsafe_code)]
1805    fn prev_sibling_ref(self) -> Option<LayoutDom<'dom, Node>> {
1806        unsafe { self.unsafe_get().prev_sibling.get_inner_as_layout() }
1807    }
1808
1809    #[inline]
1810    #[expect(unsafe_code)]
1811    fn next_sibling_ref(self) -> Option<LayoutDom<'dom, Node>> {
1812        unsafe { self.unsafe_get().next_sibling.get_inner_as_layout() }
1813    }
1814
1815    #[inline]
1816    #[expect(unsafe_code)]
1817    fn owner_doc_for_layout(self) -> LayoutDom<'dom, Document> {
1818        unsafe { self.unsafe_get().owner_doc.get_inner_as_layout().unwrap() }
1819    }
1820
1821    #[inline]
1822    #[expect(unsafe_code)]
1823    fn containing_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
1824        unsafe {
1825            self.unsafe_get()
1826                .rare_data
1827                .borrow_for_layout()
1828                .as_ref()?
1829                .containing_shadow_root
1830                .as_ref()
1831                .map(|sr| sr.to_layout())
1832        }
1833    }
1834
1835    #[inline]
1836    #[expect(unsafe_code)]
1837    fn assigned_slot_for_layout(self) -> Option<LayoutDom<'dom, HTMLSlotElement>> {
1838        unsafe {
1839            self.unsafe_get()
1840                .rare_data
1841                .borrow_for_layout()
1842                .as_ref()?
1843                .slottable_data
1844                .assigned_slot
1845                .as_ref()
1846                .map(|assigned_slot| assigned_slot.to_layout())
1847        }
1848    }
1849
1850    // FIXME(nox): get_flag/set_flag (especially the latter) are not safe because
1851    // they mutate stuff while values of this type can be used from multiple
1852    // threads at once, this should be revisited.
1853
1854    #[inline]
1855    #[expect(unsafe_code)]
1856    unsafe fn get_flag(self, flag: NodeFlags) -> bool {
1857        (self.unsafe_get()).flags.get().contains(flag)
1858    }
1859
1860    #[inline]
1861    #[expect(unsafe_code)]
1862    unsafe fn set_flag(self, flag: NodeFlags, value: bool) {
1863        let this = self.unsafe_get();
1864        let mut flags = (this).flags.get();
1865
1866        if value {
1867            flags.insert(flag);
1868        } else {
1869            flags.remove(flag);
1870        }
1871
1872        (this).flags.set(flags);
1873    }
1874
1875    // FIXME(nox): How we handle style and layout data needs to be completely
1876    // revisited so we can do that more cleanly and safely in layout 2020.
1877    #[inline]
1878    #[expect(unsafe_code)]
1879    fn style_data(self) -> Option<&'dom StyleData> {
1880        unsafe { self.unsafe_get().style_data.borrow_for_layout().as_deref() }
1881    }
1882
1883    #[inline]
1884    #[expect(unsafe_code)]
1885    fn layout_data(self) -> Option<&'dom GenericLayoutData> {
1886        unsafe { self.unsafe_get().layout_data.borrow_for_layout().as_deref() }
1887    }
1888
1889    #[inline]
1890    #[expect(unsafe_code)]
1891    unsafe fn initialize_style_data(self) {
1892        let data = unsafe { self.unsafe_get().style_data.borrow_mut_for_layout() };
1893        debug_assert!(data.is_none());
1894        *data = Some(Box::default());
1895    }
1896
1897    #[inline]
1898    #[expect(unsafe_code)]
1899    unsafe fn initialize_layout_data(self, new_data: Box<GenericLayoutData>) {
1900        let data = unsafe { self.unsafe_get().layout_data.borrow_mut_for_layout() };
1901        debug_assert!(data.is_none());
1902        *data = Some(new_data);
1903    }
1904
1905    #[inline]
1906    #[expect(unsafe_code)]
1907    unsafe fn clear_style_and_layout_data(self) {
1908        unsafe {
1909            self.unsafe_get().style_data.borrow_mut_for_layout().take();
1910            self.unsafe_get().layout_data.borrow_mut_for_layout().take();
1911        }
1912    }
1913
1914    fn is_single_line_text_inner_editor(&self) -> bool {
1915        matches!(
1916            self.unsafe_get().implemented_pseudo_element(),
1917            Some(PseudoElement::ServoTextControlInnerEditor)
1918        )
1919    }
1920
1921    fn is_text_container_of_single_line_input(&self) -> bool {
1922        let is_single_line_text_inner_placeholder = matches!(
1923            self.unsafe_get().implemented_pseudo_element(),
1924            Some(PseudoElement::Placeholder)
1925        );
1926        // Currently `::placeholder` is only implemented for single line text input element.
1927        debug_assert!(
1928            !is_single_line_text_inner_placeholder ||
1929                self.containing_shadow_root_for_layout()
1930                    .map(|root| root.get_host_for_layout())
1931                    .map(|host| host.downcast::<HTMLInputElement>())
1932                    .is_some()
1933        );
1934
1935        self.is_single_line_text_inner_editor() || is_single_line_text_inner_placeholder
1936    }
1937
1938    fn text_content(self) -> Cow<'dom, str> {
1939        self.downcast::<Text>()
1940            .expect("Called LayoutDom::text_content on non-Text node!")
1941            .upcast()
1942            .data_for_layout()
1943            .into()
1944    }
1945
1946    /// Get the selection for the given node. This only works for text nodes that are in
1947    /// the shadow DOM of user agent widgets for form controls, specifically for `<input>`
1948    /// and `<textarea>`.
1949    ///
1950    /// As we want to expose the selection on the inner text node of the widget's shadow
1951    /// DOM, we must find the shadow root and then access the containing element itself.
1952    fn selection(self) -> Option<SharedSelection> {
1953        if let Some(input) = self.downcast::<HTMLInputElement>() {
1954            return input.selection_for_layout();
1955        }
1956        if let Some(textarea) = self.downcast::<HTMLTextAreaElement>() {
1957            return Some(textarea.selection_for_layout());
1958        }
1959
1960        let shadow_root = self
1961            .containing_shadow_root_for_layout()?
1962            .get_host_for_layout();
1963        if let Some(input) = shadow_root.downcast::<HTMLInputElement>() {
1964            return input.selection_for_layout();
1965        }
1966        shadow_root
1967            .downcast::<HTMLTextAreaElement>()
1968            .map(|textarea| textarea.selection_for_layout())
1969    }
1970
1971    fn image_url(self) -> Option<ServoUrl> {
1972        self.downcast::<HTMLImageElement>()
1973            .expect("not an image!")
1974            .image_url()
1975    }
1976
1977    fn image_data(self) -> Option<(Option<Image>, Option<ImageMetadata>)> {
1978        self.downcast::<HTMLImageElement>().map(|e| e.image_data())
1979    }
1980
1981    fn image_density(self) -> Option<f64> {
1982        self.downcast::<HTMLImageElement>()
1983            .expect("not an image!")
1984            .image_density()
1985    }
1986
1987    fn showing_broken_image_icon(self) -> bool {
1988        self.downcast::<HTMLImageElement>()
1989            .map(|image_element| image_element.showing_broken_image_icon())
1990            .unwrap_or_default()
1991    }
1992
1993    fn canvas_data(self) -> Option<HTMLCanvasData> {
1994        self.downcast::<HTMLCanvasElement>()
1995            .map(|canvas| canvas.data())
1996    }
1997
1998    fn media_data(self) -> Option<HTMLMediaData> {
1999        self.downcast::<HTMLVideoElement>()
2000            .map(|media| media.data())
2001    }
2002
2003    fn svg_data(self) -> Option<SVGElementData<'dom>> {
2004        self.downcast::<SVGSVGElement>().map(|svg| svg.data())
2005    }
2006
2007    fn iframe_browsing_context_id(self) -> Option<BrowsingContextId> {
2008        self.downcast::<HTMLIFrameElement>()
2009            .and_then(|iframe_element| iframe_element.browsing_context_id())
2010    }
2011
2012    fn iframe_pipeline_id(self) -> Option<PipelineId> {
2013        self.downcast::<HTMLIFrameElement>()
2014            .and_then(|iframe_element| iframe_element.pipeline_id())
2015    }
2016
2017    #[expect(unsafe_code)]
2018    fn opaque(self) -> OpaqueNode {
2019        unsafe { OpaqueNode(self.get_jsobject() as usize) }
2020    }
2021
2022    fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2023        self.unsafe_get().implemented_pseudo_element()
2024    }
2025
2026    fn is_in_ua_widget(&self) -> bool {
2027        self.unsafe_get().is_in_ua_widget()
2028    }
2029}
2030
2031//
2032// Iteration and traversal
2033//
2034
2035pub(crate) struct FollowingNodeIterator {
2036    current: Option<DomRoot<Node>>,
2037    root: DomRoot<Node>,
2038}
2039
2040impl FollowingNodeIterator {
2041    /// Skips iterating the children of the current node
2042    pub(crate) fn next_skipping_children(&mut self) -> Option<DomRoot<Node>> {
2043        let current = self.current.take()?;
2044        self.next_skipping_children_impl(current)
2045    }
2046
2047    fn next_skipping_children_impl(&mut self, current: DomRoot<Node>) -> Option<DomRoot<Node>> {
2048        if self.root == current {
2049            self.current = None;
2050            return None;
2051        }
2052
2053        if let Some(next_sibling) = current.GetNextSibling() {
2054            self.current = Some(next_sibling);
2055            return current.GetNextSibling();
2056        }
2057
2058        for ancestor in current.inclusive_ancestors(ShadowIncluding::No) {
2059            if self.root == ancestor {
2060                break;
2061            }
2062            if let Some(next_sibling) = ancestor.GetNextSibling() {
2063                self.current = Some(next_sibling);
2064                return ancestor.GetNextSibling();
2065            }
2066        }
2067        self.current = None;
2068        None
2069    }
2070}
2071
2072impl Iterator for FollowingNodeIterator {
2073    type Item = DomRoot<Node>;
2074
2075    /// <https://dom.spec.whatwg.org/#concept-tree-following>
2076    fn next(&mut self) -> Option<DomRoot<Node>> {
2077        let current = self.current.take()?;
2078
2079        if let Some(first_child) = current.GetFirstChild() {
2080            self.current = Some(first_child);
2081            return current.GetFirstChild();
2082        }
2083
2084        self.next_skipping_children_impl(current)
2085    }
2086}
2087
2088pub(crate) struct PrecedingNodeIterator {
2089    current: Option<DomRoot<Node>>,
2090    root: DomRoot<Node>,
2091}
2092
2093impl Iterator for PrecedingNodeIterator {
2094    type Item = DomRoot<Node>;
2095
2096    /// <https://dom.spec.whatwg.org/#concept-tree-preceding>
2097    fn next(&mut self) -> Option<DomRoot<Node>> {
2098        let current = self.current.take()?;
2099
2100        self.current = if self.root == current {
2101            None
2102        } else if let Some(previous_sibling) = current.GetPreviousSibling() {
2103            if self.root == previous_sibling {
2104                None
2105            } else if let Some(last_child) = previous_sibling.descending_last_children().last() {
2106                Some(last_child)
2107            } else {
2108                Some(previous_sibling)
2109            }
2110        } else {
2111            current.GetParentNode()
2112        };
2113        self.current.clone()
2114    }
2115}
2116
2117struct SimpleNodeIterator<I>
2118where
2119    I: Fn(&Node) -> Option<DomRoot<Node>>,
2120{
2121    current: Option<DomRoot<Node>>,
2122    next_node: I,
2123}
2124
2125impl<I> Iterator for SimpleNodeIterator<I>
2126where
2127    I: Fn(&Node) -> Option<DomRoot<Node>>,
2128{
2129    type Item = DomRoot<Node>;
2130
2131    fn next(&mut self) -> Option<Self::Item> {
2132        let current = self.current.take();
2133        self.current = current.as_ref().and_then(|c| (self.next_node)(c));
2134        current
2135    }
2136}
2137
2138/// Whether a tree traversal should pass shadow tree boundaries.
2139#[derive(Clone, Copy, PartialEq)]
2140pub(crate) enum ShadowIncluding {
2141    No,
2142    Yes,
2143}
2144
2145pub(crate) struct TreeIterator {
2146    current: Option<DomRoot<Node>>,
2147    depth: usize,
2148    shadow_including: bool,
2149}
2150
2151impl TreeIterator {
2152    fn new(root: &Node, shadow_including: ShadowIncluding) -> TreeIterator {
2153        TreeIterator {
2154            current: Some(DomRoot::from_ref(root)),
2155            depth: 0,
2156            shadow_including: shadow_including == ShadowIncluding::Yes,
2157        }
2158    }
2159
2160    pub(crate) fn next_skipping_children(&mut self) -> Option<DomRoot<Node>> {
2161        let current = self.current.take()?;
2162
2163        self.next_skipping_children_impl(current)
2164    }
2165
2166    fn next_skipping_children_impl(&mut self, current: DomRoot<Node>) -> Option<DomRoot<Node>> {
2167        let iter = current.inclusive_ancestors(if self.shadow_including {
2168            ShadowIncluding::Yes
2169        } else {
2170            ShadowIncluding::No
2171        });
2172
2173        for ancestor in iter {
2174            if self.depth == 0 {
2175                break;
2176            }
2177            if let Some(next_sibling) = ancestor.GetNextSibling() {
2178                self.current = Some(next_sibling);
2179                return Some(current);
2180            }
2181            if let Some(shadow_root) = ancestor.downcast::<ShadowRoot>() {
2182                // Shadow roots don't have sibling, so after we're done traversing
2183                // one we jump to the first child of the host
2184                if let Some(child) = shadow_root.Host().upcast::<Node>().GetFirstChild() {
2185                    self.current = Some(child);
2186                    return Some(current);
2187                }
2188            }
2189            self.depth -= 1;
2190        }
2191        debug_assert_eq!(self.depth, 0);
2192        self.current = None;
2193        Some(current)
2194    }
2195
2196    pub(crate) fn peek(&self) -> Option<&DomRoot<Node>> {
2197        self.current.as_ref()
2198    }
2199}
2200
2201impl Iterator for TreeIterator {
2202    type Item = DomRoot<Node>;
2203
2204    /// <https://dom.spec.whatwg.org/#concept-tree-order>
2205    /// <https://dom.spec.whatwg.org/#concept-shadow-including-tree-order>
2206    fn next(&mut self) -> Option<DomRoot<Node>> {
2207        let current = self.current.take()?;
2208
2209        // Handle a potential shadow root on the element
2210        if let Some(element) = current.downcast::<Element>() {
2211            if let Some(shadow_root) = element.shadow_root() {
2212                if self.shadow_including {
2213                    self.current = Some(DomRoot::from_ref(shadow_root.upcast::<Node>()));
2214                    self.depth += 1;
2215                    return Some(current);
2216                }
2217            }
2218        }
2219
2220        if let Some(first_child) = current.GetFirstChild() {
2221            self.current = Some(first_child);
2222            self.depth += 1;
2223            return Some(current);
2224        };
2225
2226        self.next_skipping_children_impl(current)
2227    }
2228}
2229
2230/// Specifies whether children must be recursively cloned or not.
2231#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2232pub(crate) enum CloneChildrenFlag {
2233    CloneChildren,
2234    DoNotCloneChildren,
2235}
2236
2237impl From<bool> for CloneChildrenFlag {
2238    fn from(boolean: bool) -> Self {
2239        if boolean {
2240            CloneChildrenFlag::CloneChildren
2241        } else {
2242            CloneChildrenFlag::DoNotCloneChildren
2243        }
2244    }
2245}
2246
2247fn as_uintptr<T>(t: &T) -> uintptr_t {
2248    t as *const T as uintptr_t
2249}
2250
2251impl Node {
2252    pub(crate) fn reflect_node<N>(node: Box<N>, document: &Document, can_gc: CanGc) -> DomRoot<N>
2253    where
2254        N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2255    {
2256        Self::reflect_node_with_proto(node, document, None, can_gc)
2257    }
2258
2259    pub(crate) fn reflect_node_with_proto<N>(
2260        node: Box<N>,
2261        document: &Document,
2262        proto: Option<HandleObject>,
2263        can_gc: CanGc,
2264    ) -> DomRoot<N>
2265    where
2266        N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2267    {
2268        let window = document.window();
2269        reflect_dom_object_with_proto(node, window, proto, can_gc)
2270    }
2271
2272    pub(crate) fn new_inherited(doc: &Document) -> Node {
2273        Node::new_(NodeFlags::empty(), Some(doc))
2274    }
2275
2276    pub(crate) fn new_document_node() -> Node {
2277        Node::new_(
2278            NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2279            None,
2280        )
2281    }
2282
2283    fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2284        Node {
2285            eventtarget: EventTarget::new_inherited(),
2286
2287            parent_node: Default::default(),
2288            first_child: Default::default(),
2289            last_child: Default::default(),
2290            next_sibling: Default::default(),
2291            prev_sibling: Default::default(),
2292            owner_doc: MutNullableDom::new(doc),
2293            rare_data: Default::default(),
2294            children_count: Cell::new(0u32),
2295            flags: Cell::new(flags),
2296            inclusive_descendants_version: Cell::new(0),
2297            style_data: Default::default(),
2298            layout_data: Default::default(),
2299        }
2300    }
2301
2302    /// <https://dom.spec.whatwg.org/#concept-node-adopt>
2303    pub(crate) fn adopt(node: &Node, document: &Document, can_gc: CanGc) {
2304        document.add_script_and_layout_blocker();
2305
2306        // Step 1. Let oldDocument be node’s node document.
2307        let old_doc = node.owner_doc();
2308        old_doc.add_script_and_layout_blocker();
2309
2310        // Step 2. If node’s parent is non-null, then remove node.
2311        node.remove_self(can_gc);
2312
2313        // Step 3. If document is not oldDocument:
2314        if &*old_doc != document {
2315            // Step 3.1. For each inclusiveDescendant in node’s shadow-including inclusive descendants:
2316            for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2317                // Step 3.1.1 Set inclusiveDescendant’s node document to document.
2318                descendant.set_owner_doc(document);
2319
2320                // Step 3.1.2 If inclusiveDescendant is an element, then set the node document of each
2321                // attribute in inclusiveDescendant’s attribute list to document.
2322                if let Some(element) = descendant.downcast::<Element>() {
2323                    for attribute in element.attrs().iter() {
2324                        attribute.upcast::<Node>().set_owner_doc(document);
2325                    }
2326                }
2327            }
2328
2329            // Step 3.2 For each inclusiveDescendant in node’s shadow-including inclusive descendants
2330            // that is custom, enqueue a custom element callback reaction with inclusiveDescendant,
2331            // callback name "adoptedCallback", and « oldDocument, document ».
2332            let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2333            for descendant in node
2334                .traverse_preorder(ShadowIncluding::Yes)
2335                .filter_map(|d| d.as_custom_element())
2336            {
2337                custom_element_reaction_stack.enqueue_callback_reaction(
2338                    &descendant,
2339                    CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2340                    None,
2341                );
2342            }
2343
2344            // Step 3.3 For each inclusiveDescendant in node’s shadow-including inclusive descendants,
2345            // in shadow-including tree order, run the adopting steps with inclusiveDescendant and oldDocument.
2346            for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2347                vtable_for(&descendant).adopting_steps(&old_doc, can_gc);
2348            }
2349        }
2350
2351        old_doc.remove_script_and_layout_blocker();
2352        document.remove_script_and_layout_blocker();
2353    }
2354
2355    /// <https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity>
2356    pub(crate) fn ensure_pre_insertion_validity(
2357        node: &Node,
2358        parent: &Node,
2359        child: Option<&Node>,
2360    ) -> ErrorResult {
2361        // Step 1.
2362        match parent.type_id() {
2363            NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2364            },
2365            _ => return Err(Error::HierarchyRequest(None)),
2366        }
2367
2368        // Step 2.
2369        if node.is_inclusive_ancestor_of(parent) {
2370            return Err(Error::HierarchyRequest(None));
2371        }
2372
2373        // Step 3.
2374        if let Some(child) = child {
2375            if !parent.is_parent_of(child) {
2376                return Err(Error::NotFound(None));
2377            }
2378        }
2379
2380        // Step 4-5.
2381        match node.type_id() {
2382            NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2383                if parent.is::<Document>() {
2384                    return Err(Error::HierarchyRequest(None));
2385                }
2386            },
2387            NodeTypeId::DocumentType => {
2388                if !parent.is::<Document>() {
2389                    return Err(Error::HierarchyRequest(None));
2390                }
2391            },
2392            NodeTypeId::DocumentFragment(_) |
2393            NodeTypeId::Element(_) |
2394            NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2395            NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2396            NodeTypeId::Document(_) | NodeTypeId::Attr => {
2397                return Err(Error::HierarchyRequest(None));
2398            },
2399        }
2400
2401        // Step 6.
2402        if parent.is::<Document>() {
2403            match node.type_id() {
2404                // Step 6.1
2405                NodeTypeId::DocumentFragment(_) => {
2406                    // Step 6.1.1(b)
2407                    if node.children().any(|c| c.is::<Text>()) {
2408                        return Err(Error::HierarchyRequest(None));
2409                    }
2410                    match node.child_elements().count() {
2411                        0 => (),
2412                        // Step 6.1.2
2413                        1 => {
2414                            if parent.child_elements().next().is_some() {
2415                                return Err(Error::HierarchyRequest(None));
2416                            }
2417                            if let Some(child) = child {
2418                                if child
2419                                    .inclusively_following_siblings()
2420                                    .any(|child| child.is_doctype())
2421                                {
2422                                    return Err(Error::HierarchyRequest(None));
2423                                }
2424                            }
2425                        },
2426                        // Step 6.1.1(a)
2427                        _ => return Err(Error::HierarchyRequest(None)),
2428                    }
2429                },
2430                // Step 6.2
2431                NodeTypeId::Element(_) => {
2432                    if parent.child_elements().next().is_some() {
2433                        return Err(Error::HierarchyRequest(None));
2434                    }
2435                    if let Some(child) = child {
2436                        if child
2437                            .inclusively_following_siblings()
2438                            .any(|child| child.is_doctype())
2439                        {
2440                            return Err(Error::HierarchyRequest(None));
2441                        }
2442                    }
2443                },
2444                // Step 6.3
2445                NodeTypeId::DocumentType => {
2446                    if parent.children().any(|c| c.is_doctype()) {
2447                        return Err(Error::HierarchyRequest(None));
2448                    }
2449                    match child {
2450                        Some(child) => {
2451                            if parent
2452                                .children()
2453                                .take_while(|c| &**c != child)
2454                                .any(|c| c.is::<Element>())
2455                            {
2456                                return Err(Error::HierarchyRequest(None));
2457                            }
2458                        },
2459                        None => {
2460                            if parent.child_elements().next().is_some() {
2461                                return Err(Error::HierarchyRequest(None));
2462                            }
2463                        },
2464                    }
2465                },
2466                NodeTypeId::CharacterData(_) => (),
2467                // Because Document and Attr should already throw `HierarchyRequest`
2468                // error, both of them are unreachable here.
2469                NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
2470            }
2471        }
2472        Ok(())
2473    }
2474
2475    /// <https://dom.spec.whatwg.org/#concept-node-pre-insert>
2476    pub(crate) fn pre_insert(
2477        node: &Node,
2478        parent: &Node,
2479        child: Option<&Node>,
2480        can_gc: CanGc,
2481    ) -> Fallible<DomRoot<Node>> {
2482        // Step 1.
2483        Node::ensure_pre_insertion_validity(node, parent, child)?;
2484
2485        // Steps 2-3.
2486        let reference_child_root;
2487        let reference_child = match child {
2488            Some(child) if child == node => {
2489                reference_child_root = node.GetNextSibling();
2490                reference_child_root.as_deref()
2491            },
2492            _ => child,
2493        };
2494
2495        // Step 4.
2496        Node::insert(
2497            node,
2498            parent,
2499            reference_child,
2500            SuppressObserver::Unsuppressed,
2501            can_gc,
2502        );
2503
2504        // Step 5.
2505        Ok(DomRoot::from_ref(node))
2506    }
2507
2508    /// <https://dom.spec.whatwg.org/#concept-node-insert>
2509    fn insert(
2510        node: &Node,
2511        parent: &Node,
2512        child: Option<&Node>,
2513        suppress_observers: SuppressObserver,
2514        can_gc: CanGc,
2515    ) {
2516        debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
2517
2518        // Step 1. Let nodes be node’s children, if node is a DocumentFragment node; otherwise « node ».
2519        rooted_vec!(let mut new_nodes);
2520        let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2521            new_nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
2522            new_nodes.r()
2523        } else {
2524            from_ref(&node)
2525        };
2526
2527        // Step 2. Let count be nodes’s size.
2528        let count = new_nodes.len();
2529
2530        // Step 3. If count is 0, then return.
2531        if count == 0 {
2532            return;
2533        }
2534
2535        // Script and layout blockers must be added after any early return.
2536        // `node.owner_doc()` may change during the algorithm.
2537        let parent_document = parent.owner_doc();
2538        let from_document = node.owner_doc();
2539        from_document.add_script_and_layout_blocker();
2540        parent_document.add_script_and_layout_blocker();
2541
2542        // Step 4. If node is a DocumentFragment node:
2543        if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2544            // Step 4.1. Remove its children with the suppress observers flag set.
2545            for kid in new_nodes {
2546                Node::remove(kid, node, SuppressObserver::Suppressed, can_gc);
2547            }
2548            vtable_for(node)
2549                .children_changed(&ChildrenMutation::replace_all(new_nodes, &[]), can_gc);
2550
2551            // Step 4.2. Queue a tree mutation record for node with « », nodes, null, and null.
2552            let mutation = LazyCell::new(|| Mutation::ChildList {
2553                added: None,
2554                removed: Some(new_nodes),
2555                prev: None,
2556                next: None,
2557            });
2558            MutationObserver::queue_a_mutation_record(node, mutation);
2559        }
2560
2561        // Step 5. If child is non-null:
2562        //     1. For each live range whose start node is parent and start offset is
2563        //        greater than child’s index, increase its start offset by count.
2564        //     2. For each live range whose end node is parent and end offset is
2565        //        greater than child’s index, increase its end offset by count.
2566        if let Some(child) = child {
2567            if !parent.ranges_is_empty() {
2568                parent
2569                    .ranges()
2570                    .increase_above(parent, child.index(), count.try_into().unwrap());
2571            }
2572        }
2573
2574        // Step 6. Let previousSibling be child’s previous sibling or parent’s last child if child is null.
2575        let previous_sibling = match suppress_observers {
2576            SuppressObserver::Unsuppressed => match child {
2577                Some(child) => child.GetPreviousSibling(),
2578                None => parent.GetLastChild(),
2579            },
2580            SuppressObserver::Suppressed => None,
2581        };
2582
2583        let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2584
2585        // Step 10. Let staticNodeList be a list of nodes, initially « ».
2586        let mut static_node_list: SmallVec<[_; 4]> = Default::default();
2587
2588        let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
2589        let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
2590        let parent_as_slot = parent.downcast::<HTMLSlotElement>();
2591
2592        // Step 7. For each node in nodes, in tree order:
2593        for kid in new_nodes {
2594            // Step 7.1. Adopt node into parent’s node document.
2595            Node::adopt(kid, &parent.owner_document(), can_gc);
2596
2597            // Step 7.2. If child is null, then append node to parent’s children.
2598            // Step 7.3. Otherwise, insert node into parent’s children before child’s index.
2599            parent.add_child(kid, child, can_gc);
2600
2601            // Step 7.4 If parent is a shadow host whose shadow root’s slot assignment is "named"
2602            // and node is a slottable, then assign a slot for node.
2603            if let Some(ref shadow_root) = parent_shadow_root {
2604                if shadow_root.SlotAssignment() == SlotAssignmentMode::Named {
2605                    let cx = GlobalScope::get_cx();
2606                    if kid.is::<Element>() || kid.is::<Text>() {
2607                        rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(kid)));
2608                        slottable.assign_a_slot();
2609                    }
2610                }
2611            }
2612
2613            // Step 7.5 If parent’s root is a shadow root, and parent is a slot whose assigned nodes
2614            // is the empty list, then run signal a slot change for parent.
2615            if parent_in_shadow_tree {
2616                if let Some(slot_element) = parent_as_slot {
2617                    if !slot_element.has_assigned_nodes() {
2618                        slot_element.signal_a_slot_change();
2619                    }
2620                }
2621            }
2622
2623            // Step 7.6 Run assign slottables for a tree with node’s root.
2624            kid.GetRootNode(&GetRootNodeOptions::empty())
2625                .assign_slottables_for_a_tree();
2626
2627            // Step 7.7. For each shadow-including inclusive descendant inclusiveDescendant of node,
2628            // in shadow-including tree order:
2629            for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
2630                // Step 11.1 For each shadow-including inclusive descendant inclusiveDescendant of node,
2631                //           in shadow-including tree order, append inclusiveDescendant to staticNodeList.
2632                if descendant.is_connected() {
2633                    static_node_list.push(descendant.clone());
2634                }
2635
2636                // Step 7.7.1. Run the insertion steps with inclusiveDescendant.
2637                // This is done in `parent.add_child()`.
2638
2639                // Step 7.7.2, whatwg/dom#833
2640                // Enqueue connected reactions for custom elements or try upgrade.
2641                if let Some(descendant) = DomRoot::downcast::<Element>(descendant) {
2642                    if descendant.is_custom() {
2643                        if descendant.is_connected() {
2644                            custom_element_reaction_stack.enqueue_callback_reaction(
2645                                &descendant,
2646                                CallbackReaction::Connected,
2647                                None,
2648                            );
2649                        }
2650                    } else {
2651                        try_upgrade_element(&descendant);
2652                    }
2653                }
2654            }
2655        }
2656
2657        if let SuppressObserver::Unsuppressed = suppress_observers {
2658            // Step 9. Run the children changed steps for parent.
2659            // TODO(xiaochengh): If we follow the spec and move it out of the if block, some WPT fail. Investigate.
2660            vtable_for(parent).children_changed(
2661                &ChildrenMutation::insert(previous_sibling.as_deref(), new_nodes, child),
2662                can_gc,
2663            );
2664
2665            // Step 8. If suppress observers flag is unset, then queue a tree mutation record for parent
2666            // with nodes, « », previousSibling, and child.
2667            let mutation = LazyCell::new(|| Mutation::ChildList {
2668                added: Some(new_nodes),
2669                removed: None,
2670                prev: previous_sibling.as_deref(),
2671                next: child,
2672            });
2673            MutationObserver::queue_a_mutation_record(parent, mutation);
2674        }
2675
2676        // We use a delayed task for this step to work around an awkward interaction between
2677        // script/layout blockers, Node::replace_all, and the children_changed vtable method.
2678        // Any node with a post connection step that triggers layout (such as iframes) needs
2679        // to be marked as dirty before doing so. This is handled by Node's children_changed
2680        // callback, but when Node::insert is called as part of Node::replace_all then the
2681        // callback is suppressed until we return to Node::replace_all. To ensure the sequence:
2682        // 1) children_changed in Node::replace_all,
2683        // 2) post_connection_steps from Node::insert,
2684        // we use a delayed task that will run as soon as Node::insert removes its
2685        // script/layout blocker.
2686        parent_document.add_delayed_task(
2687            task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
2688                // Step 12. For each node of staticNodeList, if node is connected, then run the
2689                //          post-connection steps with node.
2690                for node in static_node_list {
2691                    vtable_for(&node).post_connection_steps(CanGc::from_cx(cx));
2692                }
2693            }),
2694        );
2695
2696        parent_document.remove_script_and_layout_blocker();
2697        from_document.remove_script_and_layout_blocker();
2698    }
2699
2700    /// <https://dom.spec.whatwg.org/#concept-node-replace-all>
2701    pub(crate) fn replace_all(node: Option<&Node>, parent: &Node, can_gc: CanGc) {
2702        parent.owner_doc().add_script_and_layout_blocker();
2703
2704        // Step 1. Let removedNodes be parent’s children.
2705        rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
2706
2707        // Step 2. Let addedNodes be the empty set.
2708        // Step 3. If node is a DocumentFragment node, then set addedNodes to node’s children.
2709        // Step 4. Otherwise, if node is non-null, set addedNodes to « node ».
2710        rooted_vec!(let mut added_nodes);
2711        let added_nodes = if let Some(node) = node.as_ref() {
2712            if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2713                added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
2714                added_nodes.r()
2715            } else {
2716                from_ref(node)
2717            }
2718        } else {
2719            &[] as &[&Node]
2720        };
2721
2722        // Step 5. Remove all parent’s children, in tree order, with suppressObservers set to true.
2723        for child in &*removed_nodes {
2724            Node::remove(child, parent, SuppressObserver::Suppressed, can_gc);
2725        }
2726
2727        // Step 6. If node is non-null, then insert node into parent before null with suppressObservers set to true.
2728        if let Some(node) = node {
2729            Node::insert(node, parent, None, SuppressObserver::Suppressed, can_gc);
2730        }
2731
2732        vtable_for(parent).children_changed(
2733            &ChildrenMutation::replace_all(removed_nodes.r(), added_nodes),
2734            can_gc,
2735        );
2736
2737        // Step 7. If either addedNodes or removedNodes is not empty, then queue a tree mutation record
2738        // for parent with addedNodes, removedNodes, null, and null.
2739        if !removed_nodes.is_empty() || !added_nodes.is_empty() {
2740            let mutation = LazyCell::new(|| Mutation::ChildList {
2741                added: Some(added_nodes),
2742                removed: Some(removed_nodes.r()),
2743                prev: None,
2744                next: None,
2745            });
2746            MutationObserver::queue_a_mutation_record(parent, mutation);
2747        }
2748        parent.owner_doc().remove_script_and_layout_blocker();
2749    }
2750
2751    /// <https://dom.spec.whatwg.org/multipage/#string-replace-all>
2752    pub(crate) fn string_replace_all(string: DOMString, parent: &Node, can_gc: CanGc) {
2753        if string.is_empty() {
2754            Node::replace_all(None, parent, can_gc);
2755        } else {
2756            let text = Text::new(string, &parent.owner_document(), can_gc);
2757            Node::replace_all(Some(text.upcast::<Node>()), parent, can_gc);
2758        };
2759    }
2760
2761    /// <https://dom.spec.whatwg.org/#concept-node-pre-remove>
2762    fn pre_remove(child: &Node, parent: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
2763        // Step 1.
2764        match child.GetParentNode() {
2765            Some(ref node) if &**node != parent => return Err(Error::NotFound(None)),
2766            None => return Err(Error::NotFound(None)),
2767            _ => (),
2768        }
2769
2770        // Step 2.
2771        Node::remove(child, parent, SuppressObserver::Unsuppressed, can_gc);
2772
2773        // Step 3.
2774        Ok(DomRoot::from_ref(child))
2775    }
2776
2777    /// <https://dom.spec.whatwg.org/#concept-node-remove>
2778    fn remove(node: &Node, parent: &Node, suppress_observers: SuppressObserver, can_gc: CanGc) {
2779        parent.owner_doc().add_script_and_layout_blocker();
2780
2781        // Step 1. Let parent be node’s parent.
2782        // Step 2. Assert: parent is non-null.
2783        // NOTE: We get parent as an argument instead
2784        assert!(
2785            node.GetParentNode()
2786                .is_some_and(|node_parent| &*node_parent == parent)
2787        );
2788
2789        // Step 3. Run the live range pre-remove steps.
2790        // https://dom.spec.whatwg.org/#live-range-pre-remove-steps
2791        let cached_index = {
2792            if parent.ranges_is_empty() {
2793                None
2794            } else {
2795                // Step 1. Let parent be node’s parent.
2796                // Step 2. Assert: parent is not null.
2797                // NOTE: We already have the parent.
2798
2799                // Step 3. Let index be node’s index.
2800                let index = node.index();
2801
2802                // Steps 4-5 are handled in Node::unbind_from_tree.
2803
2804                // Step 6. For each live range whose start node is parent and start offset is greater than index,
2805                // decrease its start offset by 1.
2806                // Step 7. For each live range whose end node is parent and end offset is greater than index,
2807                // decrease its end offset by 1.
2808                parent.ranges().decrease_above(parent, index, 1);
2809
2810                // Parent had ranges, we needed the index, let's keep track of
2811                // it to avoid computing it for other ranges when calling
2812                // unbind_from_tree recursively.
2813                Some(index)
2814            }
2815        };
2816
2817        // TODO: Step 4. Pre-removing steps for node iterators
2818
2819        // Step 5.
2820        let old_previous_sibling = node.GetPreviousSibling();
2821
2822        // Step 6.
2823        let old_next_sibling = node.GetNextSibling();
2824
2825        // Step 7. Remove node from its parent's children.
2826        // Step 11-14. Run removing steps and enqueue disconnected custom element reactions for the subtree.
2827        parent.remove_child(node, cached_index, can_gc);
2828
2829        // Step 8. If node is assigned, then run assign slottables for node’s assigned slot.
2830        if let Some(slot) = node.assigned_slot() {
2831            slot.assign_slottables();
2832        }
2833
2834        // Step 9. If parent’s root is a shadow root, and parent is a slot whose assigned nodes is the empty list,
2835        // then run signal a slot change for parent.
2836        if parent.is_in_a_shadow_tree() {
2837            if let Some(slot_element) = parent.downcast::<HTMLSlotElement>() {
2838                if !slot_element.has_assigned_nodes() {
2839                    slot_element.signal_a_slot_change();
2840                }
2841            }
2842        }
2843
2844        // Step 10. If node has an inclusive descendant that is a slot:
2845        let has_slot_descendant = node
2846            .traverse_preorder(ShadowIncluding::No)
2847            .any(|elem| elem.is::<HTMLSlotElement>());
2848        if has_slot_descendant {
2849            // Step 10.1 Run assign slottables for a tree with parent’s root.
2850            parent
2851                .GetRootNode(&GetRootNodeOptions::empty())
2852                .assign_slottables_for_a_tree();
2853
2854            // Step 10.2 Run assign slottables for a tree with node.
2855            node.assign_slottables_for_a_tree();
2856        }
2857
2858        // TODO: Step 15. transient registered observers
2859
2860        // Step 16.
2861        if let SuppressObserver::Unsuppressed = suppress_observers {
2862            vtable_for(parent).children_changed(
2863                &ChildrenMutation::replace(
2864                    old_previous_sibling.as_deref(),
2865                    &Some(node),
2866                    &[],
2867                    old_next_sibling.as_deref(),
2868                ),
2869                can_gc,
2870            );
2871
2872            let removed = [node];
2873            let mutation = LazyCell::new(|| Mutation::ChildList {
2874                added: None,
2875                removed: Some(&removed),
2876                prev: old_previous_sibling.as_deref(),
2877                next: old_next_sibling.as_deref(),
2878            });
2879            MutationObserver::queue_a_mutation_record(parent, mutation);
2880        }
2881        parent.owner_doc().remove_script_and_layout_blocker();
2882    }
2883
2884    /// Ensure that for styles, we clone the already-parsed property declaration block.
2885    /// This does two things:
2886    /// 1. it uses the same fast-path as CSSStyleDeclaration
2887    /// 2. it also avoids the CSP checks when cloning (it shouldn't run any when cloning
2888    ///    existing valid attributes)
2889    fn compute_attribute_value_with_style_fast_path(attr: &Dom<Attr>, elem: &Element) -> AttrValue {
2890        if *attr.local_name() == local_name!("style") {
2891            if let Some(ref pdb) = *elem.style_attribute().borrow() {
2892                let document = elem.owner_document();
2893                let shared_lock = document.style_shared_lock();
2894                let new_pdb = pdb.read_with(&shared_lock.read()).clone();
2895                return AttrValue::Declaration(
2896                    (**attr.value()).to_owned(),
2897                    ServoArc::new(shared_lock.wrap(new_pdb)),
2898                );
2899            }
2900        }
2901
2902        attr.value().clone()
2903    }
2904
2905    /// <https://dom.spec.whatwg.org/#concept-node-clone>
2906    pub(crate) fn clone(
2907        node: &Node,
2908        maybe_doc: Option<&Document>,
2909        clone_children: CloneChildrenFlag,
2910        registry: Option<DomRoot<CustomElementRegistry>>,
2911        can_gc: CanGc,
2912    ) -> DomRoot<Node> {
2913        // Step 1. If document is not given, let document be node’s node document.
2914        let document = match maybe_doc {
2915            Some(doc) => DomRoot::from_ref(doc),
2916            None => node.owner_doc(),
2917        };
2918
2919        // Step 2. / Step 3.
2920        // XXXabinader: clone() for each node as trait?
2921        let copy: DomRoot<Node> = match node.type_id() {
2922            NodeTypeId::DocumentType => {
2923                let doctype = node.downcast::<DocumentType>().unwrap();
2924                let doctype = DocumentType::new(
2925                    doctype.name().clone(),
2926                    Some(doctype.public_id().clone()),
2927                    Some(doctype.system_id().clone()),
2928                    &document,
2929                    can_gc,
2930                );
2931                DomRoot::upcast::<Node>(doctype)
2932            },
2933            NodeTypeId::Attr => {
2934                let attr = node.downcast::<Attr>().unwrap();
2935                let attr = Attr::new(
2936                    &document,
2937                    attr.local_name().clone(),
2938                    attr.value().clone(),
2939                    attr.name().clone(),
2940                    attr.namespace().clone(),
2941                    attr.prefix().cloned(),
2942                    None,
2943                    can_gc,
2944                );
2945                DomRoot::upcast::<Node>(attr)
2946            },
2947            NodeTypeId::DocumentFragment(_) => {
2948                let doc_fragment = DocumentFragment::new(&document, can_gc);
2949                DomRoot::upcast::<Node>(doc_fragment)
2950            },
2951            NodeTypeId::CharacterData(_) => {
2952                let cdata = node.downcast::<CharacterData>().unwrap();
2953                cdata.clone_with_data(cdata.Data(), &document, can_gc)
2954            },
2955            NodeTypeId::Document(_) => {
2956                // Step 1. Set copy’s encoding, content type, URL, origin, type, mode,
2957                // and allow declarative shadow roots, to those of node.
2958                let document = node.downcast::<Document>().unwrap();
2959                let is_html_doc = if document.is_html_document() {
2960                    IsHTMLDocument::HTMLDocument
2961                } else {
2962                    IsHTMLDocument::NonHTMLDocument
2963                };
2964                let window = document.window();
2965                let loader = DocumentLoader::new(&document.loader());
2966                let document = Document::new(
2967                    window,
2968                    HasBrowsingContext::No,
2969                    Some(document.url()),
2970                    None,
2971                    // https://github.com/whatwg/dom/issues/378
2972                    document.origin().clone(),
2973                    is_html_doc,
2974                    None,
2975                    None,
2976                    DocumentActivity::Inactive,
2977                    DocumentSource::NotFromParser,
2978                    loader,
2979                    None,
2980                    document.status_code(),
2981                    Default::default(),
2982                    false,
2983                    document.allow_declarative_shadow_roots(),
2984                    Some(document.insecure_requests_policy()),
2985                    document.has_trustworthy_ancestor_or_current_origin(),
2986                    document.custom_element_reaction_stack(),
2987                    document.creation_sandboxing_flag_set(),
2988                    can_gc,
2989                );
2990                // Step 2. If node’s custom element registry’s is scoped is true,
2991                // then set copy’s custom element registry to node’s custom element registry.
2992                // TODO
2993                DomRoot::upcast::<Node>(document)
2994            },
2995            // Step 2. If node is an element:
2996            NodeTypeId::Element(..) => {
2997                let element = node.downcast::<Element>().unwrap();
2998                // Step 2.1. Let registry be node’s custom element registry.
2999                // Step 2.2. If registry is null, then set registry to fallbackRegistry.
3000                let registry = element.custom_element_registry().or(registry);
3001                // Step 2.3. If registry is a global custom element registry, then
3002                // set registry to document’s effective global custom element registry.
3003                let registry =
3004                    if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3005                        Some(document.custom_element_registry())
3006                    } else {
3007                        registry
3008                    };
3009                // Step 2.4. Set copy to the result of creating an element,
3010                // given document, node’s local name, node’s namespace,
3011                // node’s namespace prefix, node’s is value, false, and registry.
3012                let name = QualName {
3013                    prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3014                    ns: element.namespace().clone(),
3015                    local: element.local_name().clone(),
3016                };
3017                let element = Element::create(
3018                    name,
3019                    element.get_is(),
3020                    &document,
3021                    ElementCreator::ScriptCreated,
3022                    CustomElementCreationMode::Asynchronous,
3023                    None,
3024                    can_gc,
3025                );
3026                // TODO: Move this into `Element::create`
3027                element.set_custom_element_registry(registry);
3028                DomRoot::upcast::<Node>(element)
3029            },
3030        };
3031
3032        // Step 4. Set copy’s node document and document to copy, if copy is a document,
3033        // and set copy’s node document to document otherwise.
3034        let document = match copy.downcast::<Document>() {
3035            Some(doc) => DomRoot::from_ref(doc),
3036            None => DomRoot::from_ref(&*document),
3037        };
3038        assert!(copy.owner_doc() == document);
3039
3040        // TODO: The spec tells us to do this in step 3.
3041        match node.type_id() {
3042            NodeTypeId::Document(_) => {
3043                let node_doc = node.downcast::<Document>().unwrap();
3044                let copy_doc = copy.downcast::<Document>().unwrap();
3045                copy_doc.set_encoding(node_doc.encoding());
3046                copy_doc.set_quirks_mode(node_doc.quirks_mode());
3047            },
3048            NodeTypeId::Element(..) => {
3049                let node_elem = node.downcast::<Element>().unwrap();
3050                let copy_elem = copy.downcast::<Element>().unwrap();
3051
3052                // Step 2.5. For each attribute of node’s attribute list:
3053                for attr in node_elem.attrs().iter() {
3054                    // Step 2.5.1. Let copyAttribute be the result of cloning a single node given attribute, document, and null.
3055                    let new_value =
3056                        Node::compute_attribute_value_with_style_fast_path(attr, node_elem);
3057                    // Step 2.5.2. Append copyAttribute to copy.
3058                    copy_elem.push_new_attribute(
3059                        attr.local_name().clone(),
3060                        new_value,
3061                        attr.name().clone(),
3062                        attr.namespace().clone(),
3063                        attr.prefix().cloned(),
3064                        AttributeMutationReason::ByCloning,
3065                        can_gc,
3066                    );
3067                }
3068            },
3069            _ => (),
3070        }
3071
3072        // Step 5: Run any cloning steps defined for node in other applicable specifications and pass copy,
3073        // node, document, and the clone children flag if set, as parameters.
3074        vtable_for(node).cloning_steps(&copy, maybe_doc, clone_children, can_gc);
3075
3076        // Step 6. If the clone children flag is set, then for each child child of node, in tree order: append the
3077        // result of cloning child with document and the clone children flag set, to copy.
3078        if clone_children == CloneChildrenFlag::CloneChildren {
3079            for child in node.children() {
3080                let child_copy = Node::clone(&child, Some(&document), clone_children, None, can_gc);
3081                let _inserted_node = Node::pre_insert(&child_copy, &copy, None, can_gc);
3082            }
3083        }
3084
3085        // Step 7. If node is a shadow host whose shadow root’s clonable is true:
3086        // NOTE: Only elements can be shadow hosts
3087        if matches!(node.type_id(), NodeTypeId::Element(_)) {
3088            let node_elem = node.downcast::<Element>().unwrap();
3089            let copy_elem = copy.downcast::<Element>().unwrap();
3090
3091            if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3092                // Step 7.1 Assert: copy is not a shadow host.
3093                assert!(!copy_elem.is_shadow_host());
3094
3095                // Step 7.2 Run attach a shadow root with copy, node’s shadow root’s mode, true,
3096                // node’s shadow root’s serializable, node’s shadow root’s delegates focus,
3097                // and node’s shadow root’s slot assignment.
3098                let copy_shadow_root =
3099                    copy_elem.attach_shadow(
3100                        IsUserAgentWidget::No,
3101                        shadow_root.Mode(),
3102                        shadow_root.Clonable(),
3103                        shadow_root.Serializable(),
3104                        shadow_root.DelegatesFocus(),
3105                        shadow_root.SlotAssignment(),
3106                        can_gc
3107                    )
3108                    .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3109
3110                // Step 7.3 Set copy’s shadow root’s declarative to node’s shadow root’s declarative.
3111                copy_shadow_root.set_declarative(shadow_root.is_declarative());
3112
3113                // Step 7.4 For each child child of node’s shadow root, in tree order: append the result of
3114                // cloning child with document and the clone children flag set, to copy’s shadow root.
3115                for child in shadow_root.upcast::<Node>().children() {
3116                    let child_copy = Node::clone(
3117                        &child,
3118                        Some(&document),
3119                        CloneChildrenFlag::CloneChildren,
3120                        None,
3121                        can_gc,
3122                    );
3123
3124                    // TODO: Should we handle the error case here and in step 6?
3125                    let _inserted_node = Node::pre_insert(
3126                        &child_copy,
3127                        copy_shadow_root.upcast::<Node>(),
3128                        None,
3129                        can_gc,
3130                    );
3131                }
3132            }
3133        }
3134
3135        // Step 8. Return copy.
3136        copy
3137    }
3138
3139    /// <https://html.spec.whatwg.org/multipage/#child-text-content>
3140    pub(crate) fn child_text_content(&self) -> DOMString {
3141        Node::collect_text_contents(self.children())
3142    }
3143
3144    /// <https://html.spec.whatwg.org/multipage/#descendant-text-content>
3145    pub(crate) fn descendant_text_content(&self) -> DOMString {
3146        Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3147    }
3148
3149    pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3150        iterator: T,
3151    ) -> DOMString {
3152        let mut content = String::new();
3153        for node in iterator {
3154            if let Some(text) = node.downcast::<Text>() {
3155                content.push_str(&text.upcast::<CharacterData>().data());
3156            }
3157        }
3158        DOMString::from(content)
3159    }
3160
3161    /// <https://dom.spec.whatwg.org/#string-replace-all>
3162    pub(crate) fn set_text_content_for_element(&self, value: Option<DOMString>, can_gc: CanGc) {
3163        // This should only be called for elements and document fragments when setting the
3164        // text content: https://dom.spec.whatwg.org/#set-text-content
3165        assert!(matches!(
3166            self.type_id(),
3167            NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3168        ));
3169        let value = value.unwrap_or_default();
3170        let node = if value.is_empty() {
3171            // Step 1. Let node be null.
3172            None
3173        } else {
3174            // Step 2. If string is not the empty string, then set node to
3175            // a new Text node whose data is string and node document is parent’s node document.
3176            Some(DomRoot::upcast(
3177                self.owner_doc().CreateTextNode(value, can_gc),
3178            ))
3179        };
3180
3181        // Step 3. Replace all with node within parent.
3182        Self::replace_all(node.as_deref(), self, can_gc);
3183    }
3184
3185    pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3186        match namespace {
3187            ns!() => None,
3188            // FIXME(ajeffrey): convert directly from Namespace to DOMString
3189            _ => Some(DOMString::from(&*namespace)),
3190        }
3191    }
3192
3193    /// <https://dom.spec.whatwg.org/#locate-a-namespace>
3194    pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3195        match node.type_id() {
3196            NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3197            NodeTypeId::Attr => node
3198                .downcast::<Attr>()
3199                .unwrap()
3200                .GetOwnerElement()
3201                .as_ref()
3202                .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3203            NodeTypeId::Document(_) => node
3204                .downcast::<Document>()
3205                .unwrap()
3206                .GetDocumentElement()
3207                .as_ref()
3208                .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3209            NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3210            _ => node
3211                .GetParentElement()
3212                .as_ref()
3213                .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3214        }
3215    }
3216
3217    /// If the given untrusted node address represents a valid DOM node in the given runtime,
3218    /// returns it.
3219    ///
3220    /// # Safety
3221    ///
3222    /// Callers should ensure they pass an UntrustedNodeAddress that points to a valid [`JSObject`]
3223    /// in memory that represents a [`Node`].
3224    #[expect(unsafe_code)]
3225    pub(crate) unsafe fn from_untrusted_node_address(
3226        candidate: UntrustedNodeAddress,
3227    ) -> &'static Self {
3228        // https://github.com/servo/servo/issues/6383
3229        let candidate = candidate.0 as usize;
3230        let object = candidate as *mut JSObject;
3231        if object.is_null() {
3232            panic!("Attempted to create a `Node` from an invalid pointer!")
3233        }
3234
3235        unsafe { &*(conversions::private_from_object(object) as *const Self) }
3236    }
3237
3238    pub(crate) fn html_serialize(
3239        &self,
3240        traversal_scope: html_serialize::TraversalScope,
3241        serialize_shadow_roots: bool,
3242        shadow_roots: Vec<DomRoot<ShadowRoot>>,
3243        can_gc: CanGc,
3244    ) -> DOMString {
3245        let mut writer = vec![];
3246        let mut serializer = HtmlSerializer::new(
3247            &mut writer,
3248            html_serialize::SerializeOpts {
3249                traversal_scope: traversal_scope.clone(),
3250                ..Default::default()
3251            },
3252        );
3253
3254        serialize_html_fragment(
3255            self,
3256            &mut serializer,
3257            traversal_scope,
3258            serialize_shadow_roots,
3259            shadow_roots,
3260            can_gc,
3261        )
3262        .expect("Serializing node failed");
3263
3264        // FIXME(ajeffrey): Directly convert UTF8 to DOMString
3265        DOMString::from(String::from_utf8(writer).unwrap())
3266    }
3267
3268    /// <https://w3c.github.io/DOM-Parsing/#dfn-xml-serialization>
3269    pub(crate) fn xml_serialize(
3270        &self,
3271        traversal_scope: xml_serialize::TraversalScope,
3272    ) -> Fallible<DOMString> {
3273        let mut writer = vec![];
3274        xml_serialize::serialize(
3275            &mut writer,
3276            &HtmlSerialize::new(self),
3277            xml_serialize::SerializeOpts { traversal_scope },
3278        )
3279        .map_err(|error| {
3280            error!("Cannot serialize node: {error}");
3281            Error::InvalidState(None)
3282        })?;
3283
3284        // FIXME(ajeffrey): Directly convert UTF8 to DOMString
3285        let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3286            error!("Cannot serialize node: {error}");
3287            Error::InvalidState(None)
3288        })?);
3289
3290        Ok(string)
3291    }
3292
3293    /// <https://html.spec.whatwg.org/multipage/#fragment-serializing-algorithm-steps>
3294    pub(crate) fn fragment_serialization_algorithm(
3295        &self,
3296        require_well_formed: bool,
3297        can_gc: CanGc,
3298    ) -> Fallible<DOMString> {
3299        // Step 1. Let context document be node's node document.
3300        let context_document = self.owner_document();
3301
3302        // Step 2. If context document is an HTML document, return the result of HTML fragment serialization algorithm
3303        // with node, false, and « ».
3304        if context_document.is_html_document() {
3305            return Ok(self.html_serialize(
3306                html_serialize::TraversalScope::ChildrenOnly(None),
3307                false,
3308                vec![],
3309                can_gc,
3310            ));
3311        }
3312
3313        // Step 3. Return the XML serialization of node given require well-formed.
3314        // TODO: xml5ever doesn't seem to want require_well_formed
3315        let _ = require_well_formed;
3316        self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3317    }
3318
3319    /// Return true if this node establishes a "scrolling box" for the purposes of `scrollIntoView`.
3320    pub(crate) fn establishes_scrolling_box(&self) -> bool {
3321        // For now, `Document` represents the viewport.
3322        //
3323        // TODO: Is this the right thing to do? Maybe `Document` should be ignored and viewport
3324        // should be represented by the root of the DOM flat tree.
3325        if self.is::<Document>() {
3326            return true;
3327        }
3328        let Some(element) = self.downcast::<Element>() else {
3329            // Shadow roots and other nodes are not scrolling boxes.
3330            return false;
3331        };
3332        // TODO: This should ask layout whether or not the element establishes a scrolling
3333        // box. This heuristic is wrong.
3334        element.style().is_some_and(|style| {
3335            let overflow_x = style.get_box().clone_overflow_x();
3336            let overflow_y = style.get_box().clone_overflow_y();
3337            overflow_x.is_scrollable() || overflow_y.is_scrollable()
3338        })
3339    }
3340}
3341
3342impl NodeMethods<crate::DomTypeHolder> for Node {
3343    /// <https://dom.spec.whatwg.org/#dom-node-nodetype>
3344    fn NodeType(&self) -> u16 {
3345        match self.type_id() {
3346            NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3347            NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3348                NodeConstants::TEXT_NODE
3349            },
3350            NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3351                NodeConstants::CDATA_SECTION_NODE
3352            },
3353            NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3354                NodeConstants::PROCESSING_INSTRUCTION_NODE
3355            },
3356            NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3357            NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3358            NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3359            NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3360            NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3361        }
3362    }
3363
3364    /// <https://dom.spec.whatwg.org/#dom-node-nodename>
3365    fn NodeName(&self) -> DOMString {
3366        match self.type_id() {
3367            NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3368            NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3369            NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3370                DOMString::from("#text")
3371            },
3372            NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3373                DOMString::from("#cdata-section")
3374            },
3375            NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3376                self.downcast::<ProcessingInstruction>().unwrap().Target()
3377            },
3378            NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => DOMString::from("#comment"),
3379            NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3380            NodeTypeId::DocumentFragment(_) => DOMString::from("#document-fragment"),
3381            NodeTypeId::Document(_) => DOMString::from("#document"),
3382        }
3383    }
3384
3385    /// <https://dom.spec.whatwg.org/#dom-node-baseuri>
3386    fn BaseURI(&self) -> USVString {
3387        USVString(String::from(self.owner_doc().base_url().as_str()))
3388    }
3389
3390    /// <https://dom.spec.whatwg.org/#dom-node-isconnected>
3391    fn IsConnected(&self) -> bool {
3392        self.is_connected()
3393    }
3394
3395    /// <https://dom.spec.whatwg.org/#dom-node-ownerdocument>
3396    fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3397        match self.type_id() {
3398            NodeTypeId::Document(_) => None,
3399            _ => Some(self.owner_doc()),
3400        }
3401    }
3402
3403    /// <https://dom.spec.whatwg.org/#dom-node-getrootnode>
3404    fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3405        if !options.composed {
3406            if let Some(shadow_root) = self.containing_shadow_root() {
3407                return DomRoot::upcast(shadow_root);
3408            }
3409        }
3410
3411        if self.is_connected() {
3412            DomRoot::from_ref(self.owner_doc().upcast::<Node>())
3413        } else {
3414            self.inclusive_ancestors(ShadowIncluding::Yes)
3415                .last()
3416                .unwrap()
3417        }
3418    }
3419
3420    /// <https://dom.spec.whatwg.org/#dom-node-parentnode>
3421    fn GetParentNode(&self) -> Option<DomRoot<Node>> {
3422        self.parent_node.get()
3423    }
3424
3425    /// <https://dom.spec.whatwg.org/#dom-node-parentelement>
3426    fn GetParentElement(&self) -> Option<DomRoot<Element>> {
3427        self.GetParentNode().and_then(DomRoot::downcast)
3428    }
3429
3430    /// <https://dom.spec.whatwg.org/#dom-node-haschildnodes>
3431    fn HasChildNodes(&self) -> bool {
3432        self.first_child.get().is_some()
3433    }
3434
3435    /// <https://dom.spec.whatwg.org/#dom-node-childnodes>
3436    fn ChildNodes(&self, can_gc: CanGc) -> DomRoot<NodeList> {
3437        if let Some(list) = self.ensure_rare_data().child_list.get() {
3438            return list;
3439        }
3440
3441        let doc = self.owner_doc();
3442        let window = doc.window();
3443        let list = NodeList::new_child_list(window, self, can_gc);
3444        self.ensure_rare_data().child_list.set(Some(&list));
3445        list
3446    }
3447
3448    /// <https://dom.spec.whatwg.org/#dom-node-firstchild>
3449    fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
3450        self.first_child.get()
3451    }
3452
3453    /// <https://dom.spec.whatwg.org/#dom-node-lastchild>
3454    fn GetLastChild(&self) -> Option<DomRoot<Node>> {
3455        self.last_child.get()
3456    }
3457
3458    /// <https://dom.spec.whatwg.org/#dom-node-previoussibling>
3459    fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
3460        self.prev_sibling.get()
3461    }
3462
3463    /// <https://dom.spec.whatwg.org/#dom-node-nextsibling>
3464    fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
3465        self.next_sibling.get()
3466    }
3467
3468    /// <https://dom.spec.whatwg.org/#dom-node-nodevalue>
3469    fn GetNodeValue(&self) -> Option<DOMString> {
3470        match self.type_id() {
3471            NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3472            NodeTypeId::CharacterData(_) => {
3473                self.downcast::<CharacterData>().map(CharacterData::Data)
3474            },
3475            _ => None,
3476        }
3477    }
3478
3479    /// <https://dom.spec.whatwg.org/#dom-node-nodevalue>
3480    fn SetNodeValue(&self, val: Option<DOMString>, can_gc: CanGc) -> Fallible<()> {
3481        match self.type_id() {
3482            NodeTypeId::Attr => {
3483                let attr = self.downcast::<Attr>().unwrap();
3484                attr.SetValue(val.unwrap_or_default(), can_gc)?;
3485            },
3486            NodeTypeId::CharacterData(_) => {
3487                let character_data = self.downcast::<CharacterData>().unwrap();
3488                character_data.SetData(val.unwrap_or_default());
3489            },
3490            _ => {},
3491        };
3492        Ok(())
3493    }
3494
3495    /// <https://dom.spec.whatwg.org/#dom-node-textcontent>
3496    fn GetTextContent(&self) -> Option<DOMString> {
3497        match self.type_id() {
3498            NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3499                let content =
3500                    Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
3501                Some(content)
3502            },
3503            NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3504            NodeTypeId::CharacterData(..) => {
3505                let characterdata = self.downcast::<CharacterData>().unwrap();
3506                Some(characterdata.Data())
3507            },
3508            NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
3509        }
3510    }
3511
3512    /// <https://dom.spec.whatwg.org/#set-text-content>
3513    fn SetTextContent(&self, value: Option<DOMString>, can_gc: CanGc) -> Fallible<()> {
3514        match self.type_id() {
3515            NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3516                self.set_text_content_for_element(value, can_gc);
3517            },
3518            NodeTypeId::Attr => {
3519                let attr = self.downcast::<Attr>().unwrap();
3520                attr.SetValue(value.unwrap_or_default(), can_gc)?;
3521            },
3522            NodeTypeId::CharacterData(..) => {
3523                let characterdata = self.downcast::<CharacterData>().unwrap();
3524                characterdata.SetData(value.unwrap_or_default());
3525            },
3526            NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
3527        };
3528        Ok(())
3529    }
3530
3531    /// <https://dom.spec.whatwg.org/#dom-node-insertbefore>
3532    fn InsertBefore(
3533        &self,
3534        node: &Node,
3535        child: Option<&Node>,
3536        can_gc: CanGc,
3537    ) -> Fallible<DomRoot<Node>> {
3538        Node::pre_insert(node, self, child, can_gc)
3539    }
3540
3541    /// <https://dom.spec.whatwg.org/#dom-node-appendchild>
3542    fn AppendChild(&self, node: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
3543        Node::pre_insert(node, self, None, can_gc)
3544    }
3545
3546    /// <https://dom.spec.whatwg.org/#concept-node-replace>
3547    fn ReplaceChild(&self, node: &Node, child: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
3548        // Step 1. If parent is not a Document, DocumentFragment, or Element node,
3549        // then throw a "HierarchyRequestError" DOMException.
3550        match self.type_id() {
3551            NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3552            },
3553            _ => return Err(Error::HierarchyRequest(None)),
3554        }
3555
3556        // Step 2. If node is a host-including inclusive ancestor of parent,
3557        // then throw a "HierarchyRequestError" DOMException.
3558        if node.is_inclusive_ancestor_of(self) {
3559            return Err(Error::HierarchyRequest(None));
3560        }
3561
3562        // Step 3. If child’s parent is not parent, then throw a "NotFoundError" DOMException.
3563        if !self.is_parent_of(child) {
3564            return Err(Error::NotFound(None));
3565        }
3566
3567        // Step 4. If node is not a DocumentFragment, DocumentType, Element, or CharacterData node,
3568        // then throw a "HierarchyRequestError" DOMException.
3569        // Step 5. If either node is a Text node and parent is a document,
3570        // or node is a doctype and parent is not a document, then throw a "HierarchyRequestError" DOMException.
3571        match node.type_id() {
3572            NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
3573                return Err(Error::HierarchyRequest(None));
3574            },
3575            NodeTypeId::DocumentType if !self.is::<Document>() => {
3576                return Err(Error::HierarchyRequest(None));
3577            },
3578            NodeTypeId::Document(_) | NodeTypeId::Attr => {
3579                return Err(Error::HierarchyRequest(None));
3580            },
3581            _ => (),
3582        }
3583
3584        // Step 6. If parent is a document, and any of the statements below, switched on the interface node implements,
3585        // are true, then throw a "HierarchyRequestError" DOMException.
3586        if self.is::<Document>() {
3587            match node.type_id() {
3588                // Step 6.1
3589                NodeTypeId::DocumentFragment(_) => {
3590                    // Step 6.1.1(b)
3591                    if node.children().any(|c| c.is::<Text>()) {
3592                        return Err(Error::HierarchyRequest(None));
3593                    }
3594                    match node.child_elements().count() {
3595                        0 => (),
3596                        // Step 6.1.2
3597                        1 => {
3598                            if self.child_elements().any(|c| c.upcast::<Node>() != child) {
3599                                return Err(Error::HierarchyRequest(None));
3600                            }
3601                            if child.following_siblings().any(|child| child.is_doctype()) {
3602                                return Err(Error::HierarchyRequest(None));
3603                            }
3604                        },
3605                        // Step 6.1.1(a)
3606                        _ => return Err(Error::HierarchyRequest(None)),
3607                    }
3608                },
3609                // Step 6.2
3610                NodeTypeId::Element(..) => {
3611                    if self.child_elements().any(|c| c.upcast::<Node>() != child) {
3612                        return Err(Error::HierarchyRequest(None));
3613                    }
3614                    if child.following_siblings().any(|child| child.is_doctype()) {
3615                        return Err(Error::HierarchyRequest(None));
3616                    }
3617                },
3618                // Step 6.3
3619                NodeTypeId::DocumentType => {
3620                    if self.children().any(|c| c.is_doctype() && &*c != child) {
3621                        return Err(Error::HierarchyRequest(None));
3622                    }
3623                    if self
3624                        .children()
3625                        .take_while(|c| &**c != child)
3626                        .any(|c| c.is::<Element>())
3627                    {
3628                        return Err(Error::HierarchyRequest(None));
3629                    }
3630                },
3631                NodeTypeId::CharacterData(..) => (),
3632                // Because Document and Attr should already throw `HierarchyRequest`
3633                // error, both of them are unreachable here.
3634                NodeTypeId::Document(_) => unreachable!(),
3635                NodeTypeId::Attr => unreachable!(),
3636            }
3637        }
3638
3639        // Step 7. Let referenceChild be child’s next sibling.
3640        // Step 8. If referenceChild is node, then set referenceChild to node’s next sibling.
3641        let child_next_sibling = child.GetNextSibling();
3642        let node_next_sibling = node.GetNextSibling();
3643        let reference_child = if child_next_sibling.as_deref() == Some(node) {
3644            node_next_sibling.as_deref()
3645        } else {
3646            child_next_sibling.as_deref()
3647        };
3648
3649        // Step 9. Let previousSibling be child’s previous sibling.
3650        let previous_sibling = child.GetPreviousSibling();
3651
3652        // NOTE: All existing browsers assume that adoption is performed here, which does not follow the DOM spec.
3653        // However, if we follow the spec and delay adoption to inside `Node::insert()`, then the mutation records will
3654        // be different, and we will fail WPT dom/nodes/MutationObserver-childList.html.
3655        let document = self.owner_document();
3656        Node::adopt(node, &document, can_gc);
3657
3658        // Step 10. Let removedNodes be the empty set.
3659        // Step 11. If child’s parent is non-null:
3660        //     1. Set removedNodes to « child ».
3661        //     2. Remove child with the suppress observers flag set.
3662        let removed_child = if node != child {
3663            // Step 11.
3664            Node::remove(child, self, SuppressObserver::Suppressed, can_gc);
3665            Some(child)
3666        } else {
3667            None
3668        };
3669
3670        // Step 12. Let nodes be node’s children if node is a DocumentFragment node; otherwise « node ».
3671        rooted_vec!(let mut nodes);
3672        let nodes = if node.type_id() ==
3673            NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
3674            node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
3675        {
3676            nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
3677            nodes.r()
3678        } else {
3679            from_ref(&node)
3680        };
3681
3682        // Step 13. Insert node into parent before referenceChild with the suppress observers flag set.
3683        Node::insert(
3684            node,
3685            self,
3686            reference_child,
3687            SuppressObserver::Suppressed,
3688            can_gc,
3689        );
3690
3691        vtable_for(self).children_changed(
3692            &ChildrenMutation::replace(
3693                previous_sibling.as_deref(),
3694                &removed_child,
3695                nodes,
3696                reference_child,
3697            ),
3698            can_gc,
3699        );
3700
3701        // Step 14. Queue a tree mutation record for parent with nodes, removedNodes,
3702        // previousSibling, and referenceChild.
3703        let removed = removed_child.map(|r| [r]);
3704        let mutation = LazyCell::new(|| Mutation::ChildList {
3705            added: Some(nodes),
3706            removed: removed.as_ref().map(|r| &r[..]),
3707            prev: previous_sibling.as_deref(),
3708            next: reference_child,
3709        });
3710
3711        MutationObserver::queue_a_mutation_record(self, mutation);
3712
3713        // Step 15. Return child.
3714        Ok(DomRoot::from_ref(child))
3715    }
3716
3717    /// <https://dom.spec.whatwg.org/#dom-node-removechild>
3718    fn RemoveChild(&self, node: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
3719        Node::pre_remove(node, self, can_gc)
3720    }
3721
3722    /// <https://dom.spec.whatwg.org/#dom-node-normalize>
3723    fn Normalize(&self, can_gc: CanGc) {
3724        let mut children = self.children().enumerate().peekable();
3725        while let Some((_, node)) = children.next() {
3726            if let Some(text) = node.downcast::<Text>() {
3727                if text.is::<CDATASection>() {
3728                    continue;
3729                }
3730                let cdata = text.upcast::<CharacterData>();
3731                let mut length = cdata.Length();
3732                if length == 0 {
3733                    Node::remove(&node, self, SuppressObserver::Unsuppressed, can_gc);
3734                    continue;
3735                }
3736                while children.peek().is_some_and(|(_, sibling)| {
3737                    sibling.is::<Text>() && !sibling.is::<CDATASection>()
3738                }) {
3739                    let (index, sibling) = children.next().unwrap();
3740                    sibling
3741                        .ranges()
3742                        .drain_to_preceding_text_sibling(&sibling, &node, length);
3743                    self.ranges()
3744                        .move_to_text_child_at(self, index as u32, &node, length);
3745                    let sibling_cdata = sibling.downcast::<CharacterData>().unwrap();
3746                    length += sibling_cdata.Length();
3747                    cdata.append_data(&sibling_cdata.data());
3748                    Node::remove(&sibling, self, SuppressObserver::Unsuppressed, can_gc);
3749                }
3750            } else {
3751                node.Normalize(can_gc);
3752            }
3753        }
3754    }
3755
3756    /// <https://dom.spec.whatwg.org/#dom-node-clonenode>
3757    fn CloneNode(&self, subtree: bool, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
3758        // Step 1. If this is a shadow root, then throw a "NotSupportedError" DOMException.
3759        if self.is::<ShadowRoot>() {
3760            return Err(Error::NotSupported(None));
3761        }
3762
3763        // Step 2. Return the result of cloning a node given this with subtree set to subtree.
3764        let result = Node::clone(
3765            self,
3766            None,
3767            if subtree {
3768                CloneChildrenFlag::CloneChildren
3769            } else {
3770                CloneChildrenFlag::DoNotCloneChildren
3771            },
3772            None,
3773            can_gc,
3774        );
3775        Ok(result)
3776    }
3777
3778    /// <https://dom.spec.whatwg.org/#dom-node-isequalnode>
3779    fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
3780        fn is_equal_doctype(node: &Node, other: &Node) -> bool {
3781            let doctype = node.downcast::<DocumentType>().unwrap();
3782            let other_doctype = other.downcast::<DocumentType>().unwrap();
3783            (*doctype.name() == *other_doctype.name()) &&
3784                (*doctype.public_id() == *other_doctype.public_id()) &&
3785                (*doctype.system_id() == *other_doctype.system_id())
3786        }
3787        fn is_equal_element(node: &Node, other: &Node) -> bool {
3788            let element = node.downcast::<Element>().unwrap();
3789            let other_element = other.downcast::<Element>().unwrap();
3790            (*element.namespace() == *other_element.namespace()) &&
3791                (*element.prefix() == *other_element.prefix()) &&
3792                (*element.local_name() == *other_element.local_name()) &&
3793                (element.attrs().len() == other_element.attrs().len())
3794        }
3795        fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
3796            let pi = node.downcast::<ProcessingInstruction>().unwrap();
3797            let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
3798            (*pi.target() == *other_pi.target()) &&
3799                (*pi.upcast::<CharacterData>().data() ==
3800                    *other_pi.upcast::<CharacterData>().data())
3801        }
3802        fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
3803            let characterdata = node.downcast::<CharacterData>().unwrap();
3804            let other_characterdata = other.downcast::<CharacterData>().unwrap();
3805            *characterdata.data() == *other_characterdata.data()
3806        }
3807        fn is_equal_attr(node: &Node, other: &Node) -> bool {
3808            let attr = node.downcast::<Attr>().unwrap();
3809            let other_attr = other.downcast::<Attr>().unwrap();
3810            (*attr.namespace() == *other_attr.namespace()) &&
3811                (attr.local_name() == other_attr.local_name()) &&
3812                (**attr.value() == **other_attr.value())
3813        }
3814        fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
3815            let element = node.downcast::<Element>().unwrap();
3816            let other_element = other.downcast::<Element>().unwrap();
3817            assert!(element.attrs().len() == other_element.attrs().len());
3818            element.attrs().iter().all(|attr| {
3819                other_element.attrs().iter().any(|other_attr| {
3820                    (*attr.namespace() == *other_attr.namespace()) &&
3821                        (attr.local_name() == other_attr.local_name()) &&
3822                        (**attr.value() == **other_attr.value())
3823                })
3824            })
3825        }
3826
3827        fn is_equal_node(this: &Node, node: &Node) -> bool {
3828            // Step 2.
3829            if this.NodeType() != node.NodeType() {
3830                return false;
3831            }
3832
3833            match node.type_id() {
3834                // Step 3.
3835                NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
3836                NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
3837                NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
3838                    if !is_equal_processinginstruction(this, node) =>
3839                {
3840                    return false;
3841                },
3842                NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
3843                NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
3844                    if !is_equal_characterdata(this, node) =>
3845                {
3846                    return false;
3847                },
3848                // Step 4.
3849                NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
3850                NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
3851
3852                _ => (),
3853            }
3854
3855            // Step 5.
3856            if this.children_count() != node.children_count() {
3857                return false;
3858            }
3859
3860            // Step 6.
3861            this.children()
3862                .zip(node.children())
3863                .all(|(child, other_child)| is_equal_node(&child, &other_child))
3864        }
3865        match maybe_node {
3866            // Step 1.
3867            None => false,
3868            // Step 2-6.
3869            Some(node) => is_equal_node(self, node),
3870        }
3871    }
3872
3873    /// <https://dom.spec.whatwg.org/#dom-node-issamenode>
3874    fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
3875        match other_node {
3876            Some(node) => self == node,
3877            None => false,
3878        }
3879    }
3880
3881    /// <https://dom.spec.whatwg.org/#dom-node-comparedocumentposition>
3882    fn CompareDocumentPosition(&self, other: &Node) -> u16 {
3883        // step 1.
3884        if self == other {
3885            return 0;
3886        }
3887
3888        // step 2
3889        let mut node1 = Some(other);
3890        let mut node2 = Some(self);
3891
3892        // step 3
3893        let mut attr1: Option<&Attr> = None;
3894        let mut attr2: Option<&Attr> = None;
3895
3896        // step 4: spec says to operate on node1 here,
3897        // node1 is definitely Some(other) going into this step
3898        // The compiler doesn't know the lifetime of attr1.GetOwnerElement
3899        // is guaranteed by the lifetime of attr1, so we hold it explicitly
3900        let attr1owner;
3901        if let Some(a) = other.downcast::<Attr>() {
3902            attr1 = Some(a);
3903            attr1owner = a.GetOwnerElement();
3904            node1 = match attr1owner {
3905                Some(ref e) => Some(e.upcast()),
3906                None => None,
3907            }
3908        }
3909
3910        // step 5.1: spec says to operate on node2 here,
3911        // node2 is definitely just Some(self) going into this step
3912        let attr2owner;
3913        if let Some(a) = self.downcast::<Attr>() {
3914            attr2 = Some(a);
3915            attr2owner = a.GetOwnerElement();
3916            node2 = match attr2owner {
3917                Some(ref e) => Some(e.upcast()),
3918                None => None,
3919            }
3920        }
3921
3922        // Step 5.2
3923        // This substep seems lacking in test coverage.
3924        // We hit this when comparing two attributes that have the
3925        // same owner element.
3926        if let Some(node2) = node2 {
3927            if Some(node2) == node1 {
3928                if let (Some(a1), Some(a2)) = (attr1, attr2) {
3929                    let attrs = node2.downcast::<Element>().unwrap().attrs();
3930                    // go through the attrs in order to see if self
3931                    // or other is first; spec is clear that we
3932                    // want value-equality, not reference-equality
3933                    for attr in attrs.iter() {
3934                        if (*attr.namespace() == *a1.namespace()) &&
3935                            (attr.local_name() == a1.local_name()) &&
3936                            (**attr.value() == **a1.value())
3937                        {
3938                            return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
3939                                NodeConstants::DOCUMENT_POSITION_PRECEDING;
3940                        }
3941                        if (*attr.namespace() == *a2.namespace()) &&
3942                            (attr.local_name() == a2.local_name()) &&
3943                            (**attr.value() == **a2.value())
3944                        {
3945                            return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
3946                                NodeConstants::DOCUMENT_POSITION_FOLLOWING;
3947                        }
3948                    }
3949                    // both attrs have node2 as their owner element, so
3950                    // we can't have left the loop without seeing them
3951                    unreachable!();
3952                }
3953            }
3954        }
3955
3956        // Step 6
3957        match (node1, node2) {
3958            (None, _) => {
3959                // node1 is null
3960                NodeConstants::DOCUMENT_POSITION_FOLLOWING +
3961                    NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
3962                    NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
3963            },
3964            (_, None) => {
3965                // node2 is null
3966                NodeConstants::DOCUMENT_POSITION_PRECEDING +
3967                    NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
3968                    NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
3969            },
3970            (Some(node1), Some(node2)) => {
3971                // still step 6, testing if node1 and 2 share a root
3972                let mut self_and_ancestors = node2
3973                    .inclusive_ancestors(ShadowIncluding::No)
3974                    .collect::<SmallVec<[_; 20]>>();
3975                let mut other_and_ancestors = node1
3976                    .inclusive_ancestors(ShadowIncluding::No)
3977                    .collect::<SmallVec<[_; 20]>>();
3978
3979                if self_and_ancestors.last() != other_and_ancestors.last() {
3980                    let random = as_uintptr(self_and_ancestors.last().unwrap()) <
3981                        as_uintptr(other_and_ancestors.last().unwrap());
3982                    let random = if random {
3983                        NodeConstants::DOCUMENT_POSITION_FOLLOWING
3984                    } else {
3985                        NodeConstants::DOCUMENT_POSITION_PRECEDING
3986                    };
3987
3988                    // Disconnected.
3989                    return random +
3990                        NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
3991                        NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
3992                }
3993                // steps 7-10
3994                let mut parent = self_and_ancestors.pop().unwrap();
3995                other_and_ancestors.pop().unwrap();
3996
3997                let mut current_position =
3998                    cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
3999
4000                while current_position > 0 {
4001                    current_position -= 1;
4002                    let child_1 = self_and_ancestors.pop().unwrap();
4003                    let child_2 = other_and_ancestors.pop().unwrap();
4004
4005                    if child_1 != child_2 {
4006                        let is_before = parent.children().position(|c| c == child_1).unwrap() <
4007                            parent.children().position(|c| c == child_2).unwrap();
4008                        // If I am before, `other` is following, and the other way
4009                        // around.
4010                        return if is_before {
4011                            NodeConstants::DOCUMENT_POSITION_FOLLOWING
4012                        } else {
4013                            NodeConstants::DOCUMENT_POSITION_PRECEDING
4014                        };
4015                    }
4016
4017                    parent = child_1;
4018                }
4019
4020                // We hit the end of one of the parent chains, so one node needs to be
4021                // contained in the other.
4022                //
4023                // If we're the container, return that `other` is contained by us.
4024                if self_and_ancestors.len() < other_and_ancestors.len() {
4025                    NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4026                        NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
4027                } else {
4028                    NodeConstants::DOCUMENT_POSITION_PRECEDING +
4029                        NodeConstants::DOCUMENT_POSITION_CONTAINS
4030                }
4031            },
4032        }
4033    }
4034
4035    /// <https://dom.spec.whatwg.org/#dom-node-contains>
4036    fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4037        match maybe_other {
4038            None => false,
4039            Some(other) => self.is_inclusive_ancestor_of(other),
4040        }
4041    }
4042
4043    /// <https://dom.spec.whatwg.org/#dom-node-lookupprefix>
4044    fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4045        let namespace = namespace_from_domstring(namespace);
4046
4047        // Step 1.
4048        if namespace == ns!() {
4049            return None;
4050        }
4051
4052        // Step 2.
4053        match self.type_id() {
4054            NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4055            NodeTypeId::Document(_) => self
4056                .downcast::<Document>()
4057                .unwrap()
4058                .GetDocumentElement()
4059                .and_then(|element| element.lookup_prefix(namespace)),
4060            NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4061            NodeTypeId::Attr => self
4062                .downcast::<Attr>()
4063                .unwrap()
4064                .GetOwnerElement()
4065                .and_then(|element| element.lookup_prefix(namespace)),
4066            _ => self
4067                .GetParentElement()
4068                .and_then(|element| element.lookup_prefix(namespace)),
4069        }
4070    }
4071
4072    /// <https://dom.spec.whatwg.org/#dom-node-lookupnamespaceuri>
4073    fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4074        // Step 1. If prefix is the empty string, then set it to null.
4075        let prefix = prefix.filter(|prefix| !prefix.is_empty());
4076
4077        // Step 2. Return the result of running locate a namespace for this using prefix.
4078        Node::namespace_to_string(Node::locate_namespace(self, prefix))
4079    }
4080
4081    /// <https://dom.spec.whatwg.org/#dom-node-isdefaultnamespace>
4082    fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4083        // Step 1.
4084        let namespace = namespace_from_domstring(namespace);
4085        // Steps 2 and 3.
4086        Node::locate_namespace(self, None) == namespace
4087    }
4088}
4089
4090pub(crate) trait NodeTraits {
4091    /// Get the [`Document`] that owns this node. Note that this may differ from the
4092    /// [`Document`] that the node was created in if it was adopted by a different
4093    /// [`Document`] (the owner).
4094    fn owner_document(&self) -> DomRoot<Document>;
4095    /// Get the [`Window`] of the [`Document`] that owns this node. Note that this may
4096    /// differ from the [`Document`] that the node was created in if it was adopted by a
4097    /// different [`Document`] (the owner).
4098    fn owner_window(&self) -> DomRoot<Window>;
4099    /// Get the [`GlobalScope`] of the [`Document`] that owns this node. Note that this may
4100    /// differ from the [`GlobalScope`] that the node was created in if it was adopted by a
4101    /// different [`Document`] (the owner).
4102    fn owner_global(&self) -> DomRoot<GlobalScope>;
4103    /// If this [`Node`] is contained in a [`ShadowRoot`] return it, otherwise `None`.
4104    fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4105    /// Get the stylesheet owner for this node: either the [`Document`] or the [`ShadowRoot`]
4106    /// of the node.
4107    fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4108}
4109
4110impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4111    fn owner_document(&self) -> DomRoot<Document> {
4112        self.upcast().owner_doc()
4113    }
4114
4115    fn owner_window(&self) -> DomRoot<Window> {
4116        DomRoot::from_ref(self.owner_document().window())
4117    }
4118
4119    fn owner_global(&self) -> DomRoot<GlobalScope> {
4120        DomRoot::from_ref(self.owner_window().upcast())
4121    }
4122
4123    fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4124        Node::containing_shadow_root(self.upcast())
4125    }
4126
4127    #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4128    fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4129        self.containing_shadow_root()
4130            .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4131            .unwrap_or_else(|| {
4132                StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4133            })
4134    }
4135}
4136
4137impl VirtualMethods for Node {
4138    fn super_type(&self) -> Option<&dyn VirtualMethods> {
4139        Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4140    }
4141
4142    fn children_changed(&self, mutation: &ChildrenMutation, can_gc: CanGc) {
4143        if let Some(s) = self.super_type() {
4144            s.children_changed(mutation, can_gc);
4145        }
4146
4147        if let Some(data) = self.rare_data().as_ref() {
4148            if let Some(list) = data.child_list.get() {
4149                list.as_children_list().children_changed(mutation);
4150            }
4151        }
4152
4153        self.owner_doc().content_and_heritage_changed(self);
4154    }
4155
4156    // This handles the ranges mentioned in steps 2-3 when removing a node.
4157    /// <https://dom.spec.whatwg.org/#concept-node-remove>
4158    fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
4159        self.super_type().unwrap().unbind_from_tree(context, can_gc);
4160
4161        // Ranges should only drain to the parent from inclusive non-shadow
4162        // including descendants. If we're in a shadow tree at this point then the
4163        // unbind operation happened further up in the tree and we should not
4164        // drain any ranges.
4165        if !self.is_in_a_shadow_tree() && !self.ranges_is_empty() {
4166            self.ranges().drain_to_parent(context, self);
4167        }
4168    }
4169
4170    fn handle_event(&self, event: &Event, _: CanGc) {
4171        if let Some(event) = event.downcast::<KeyboardEvent>() {
4172            self.owner_document()
4173                .event_handler()
4174                .run_default_keyboard_event_handler(event);
4175        }
4176    }
4177}
4178
4179/// A summary of the changes that happened to a node.
4180#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4181pub(crate) enum NodeDamage {
4182    /// The node's `style` attribute changed.
4183    Style,
4184    /// The node's content or heritage changed, such as the addition or removal of
4185    /// children.
4186    ContentOrHeritage,
4187    /// Other parts of a node changed; attributes, text content, etc.
4188    Other,
4189}
4190
4191pub(crate) enum ChildrenMutation<'a> {
4192    Append {
4193        prev: &'a Node,
4194        added: &'a [&'a Node],
4195    },
4196    Insert {
4197        prev: &'a Node,
4198        added: &'a [&'a Node],
4199        next: &'a Node,
4200    },
4201    Prepend {
4202        added: &'a [&'a Node],
4203        next: &'a Node,
4204    },
4205    Replace {
4206        prev: Option<&'a Node>,
4207        removed: &'a Node,
4208        added: &'a [&'a Node],
4209        next: Option<&'a Node>,
4210    },
4211    ReplaceAll {
4212        removed: &'a [&'a Node],
4213        added: &'a [&'a Node],
4214    },
4215    /// Mutation for when a Text node's data is modified.
4216    /// This doesn't change the structure of the list, which is what the other
4217    /// variants' fields are stored for at the moment, so this can just have no
4218    /// fields.
4219    ChangeText,
4220}
4221
4222impl<'a> ChildrenMutation<'a> {
4223    fn insert(
4224        prev: Option<&'a Node>,
4225        added: &'a [&'a Node],
4226        next: Option<&'a Node>,
4227    ) -> ChildrenMutation<'a> {
4228        match (prev, next) {
4229            (None, None) => ChildrenMutation::ReplaceAll {
4230                removed: &[],
4231                added,
4232            },
4233            (Some(prev), None) => ChildrenMutation::Append { prev, added },
4234            (None, Some(next)) => ChildrenMutation::Prepend { added, next },
4235            (Some(prev), Some(next)) => ChildrenMutation::Insert { prev, added, next },
4236        }
4237    }
4238
4239    fn replace(
4240        prev: Option<&'a Node>,
4241        removed: &'a Option<&'a Node>,
4242        added: &'a [&'a Node],
4243        next: Option<&'a Node>,
4244    ) -> ChildrenMutation<'a> {
4245        if let Some(ref removed) = *removed {
4246            if let (None, None) = (prev, next) {
4247                ChildrenMutation::ReplaceAll {
4248                    removed: from_ref(removed),
4249                    added,
4250                }
4251            } else {
4252                ChildrenMutation::Replace {
4253                    prev,
4254                    removed,
4255                    added,
4256                    next,
4257                }
4258            }
4259        } else {
4260            ChildrenMutation::insert(prev, added, next)
4261        }
4262    }
4263
4264    fn replace_all(removed: &'a [&'a Node], added: &'a [&'a Node]) -> ChildrenMutation<'a> {
4265        ChildrenMutation::ReplaceAll { removed, added }
4266    }
4267
4268    /// Get the child that follows the added or removed children.
4269    /// Currently only used when this mutation might force us to
4270    /// restyle later children (see HAS_SLOW_SELECTOR_LATER_SIBLINGS and
4271    /// Element's implementation of VirtualMethods::children_changed).
4272    pub(crate) fn next_child(&self) -> Option<&Node> {
4273        match *self {
4274            ChildrenMutation::Append { .. } => None,
4275            ChildrenMutation::Insert { next, .. } => Some(next),
4276            ChildrenMutation::Prepend { next, .. } => Some(next),
4277            ChildrenMutation::Replace { next, .. } => next,
4278            ChildrenMutation::ReplaceAll { .. } => None,
4279            ChildrenMutation::ChangeText => None,
4280        }
4281    }
4282
4283    /// If nodes were added or removed at the start or end of a container, return any
4284    /// previously-existing child whose ":first-child" or ":last-child" status *may* have changed.
4285    ///
4286    /// NOTE: This does not check whether the inserted/removed nodes were elements, so in some
4287    /// cases it will return a false positive.  This doesn't matter for correctness, because at
4288    /// worst the returned element will be restyled unnecessarily.
4289    pub(crate) fn modified_edge_element(&self) -> Option<DomRoot<Node>> {
4290        match *self {
4291            // Add/remove at start of container: Return the first following element.
4292            ChildrenMutation::Prepend { next, .. } |
4293            ChildrenMutation::Replace {
4294                prev: None,
4295                next: Some(next),
4296                ..
4297            } => next
4298                .inclusively_following_siblings()
4299                .find(|node| node.is::<Element>()),
4300            // Add/remove at end of container: Return the last preceding element.
4301            ChildrenMutation::Append { prev, .. } |
4302            ChildrenMutation::Replace {
4303                prev: Some(prev),
4304                next: None,
4305                ..
4306            } => prev
4307                .inclusively_preceding_siblings()
4308                .find(|node| node.is::<Element>()),
4309            // Insert or replace in the middle:
4310            ChildrenMutation::Insert { prev, next, .. } |
4311            ChildrenMutation::Replace {
4312                prev: Some(prev),
4313                next: Some(next),
4314                ..
4315            } => {
4316                if prev
4317                    .inclusively_preceding_siblings()
4318                    .all(|node| !node.is::<Element>())
4319                {
4320                    // Before the first element: Return the first following element.
4321                    next.inclusively_following_siblings()
4322                        .find(|node| node.is::<Element>())
4323                } else if next
4324                    .inclusively_following_siblings()
4325                    .all(|node| !node.is::<Element>())
4326                {
4327                    // After the last element: Return the last preceding element.
4328                    prev.inclusively_preceding_siblings()
4329                        .find(|node| node.is::<Element>())
4330                } else {
4331                    None
4332                }
4333            },
4334
4335            ChildrenMutation::Replace {
4336                prev: None,
4337                next: None,
4338                ..
4339            } => unreachable!(),
4340            ChildrenMutation::ReplaceAll { .. } => None,
4341            ChildrenMutation::ChangeText => None,
4342        }
4343    }
4344}
4345
4346/// The context of the binding to tree of a node.
4347pub(crate) struct BindContext<'a> {
4348    /// The parent of the inclusive ancestor that was inserted.
4349    pub(crate) parent: &'a Node,
4350
4351    /// Whether the tree is connected.
4352    ///
4353    /// <https://dom.spec.whatwg.org/#connected>
4354    pub(crate) tree_connected: bool,
4355
4356    /// Whether the tree's root is a document.
4357    ///
4358    /// <https://dom.spec.whatwg.org/#in-a-document-tree>
4359    pub(crate) tree_is_in_a_document_tree: bool,
4360
4361    /// Whether the tree's root is a shadow root
4362    pub(crate) tree_is_in_a_shadow_tree: bool,
4363
4364    /// Whether the root of the subtree that is being bound to the parent is a shadow root.
4365    ///
4366    /// This implies that all elements whose "bind_to_tree" method are called were already
4367    /// in a shadow tree beforehand.
4368    pub(crate) is_shadow_tree: IsShadowTree,
4369}
4370
4371#[derive(Debug, Eq, PartialEq)]
4372pub(crate) enum IsShadowTree {
4373    Yes,
4374    No,
4375}
4376
4377impl<'a> BindContext<'a> {
4378    /// Create a new `BindContext` value.
4379    pub(crate) fn new(parent: &'a Node, is_shadow_tree: IsShadowTree) -> Self {
4380        BindContext {
4381            parent,
4382            tree_connected: parent.is_connected(),
4383            tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
4384            tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
4385            is_shadow_tree,
4386        }
4387    }
4388
4389    /// Return true iff the tree is inside either a document- or a shadow tree.
4390    pub(crate) fn is_in_tree(&self) -> bool {
4391        self.tree_is_in_a_document_tree || self.tree_is_in_a_shadow_tree
4392    }
4393}
4394
4395/// The context of the unbinding from a tree of a node when one of its
4396/// inclusive ancestors is removed.
4397pub(crate) struct UnbindContext<'a> {
4398    /// The index of the inclusive ancestor that was removed.
4399    index: Cell<Option<u32>>,
4400    /// The parent of the inclusive ancestor that was removed.
4401    pub(crate) parent: &'a Node,
4402    /// The previous sibling of the inclusive ancestor that was removed.
4403    prev_sibling: Option<&'a Node>,
4404    /// The next sibling of the inclusive ancestor that was removed.
4405    pub(crate) next_sibling: Option<&'a Node>,
4406
4407    /// Whether the tree is connected.
4408    ///
4409    /// <https://dom.spec.whatwg.org/#connected>
4410    pub(crate) tree_connected: bool,
4411
4412    /// Whether the tree's root is a document.
4413    ///
4414    /// <https://dom.spec.whatwg.org/#in-a-document-tree>
4415    pub(crate) tree_is_in_a_document_tree: bool,
4416
4417    /// Whether the tree's root is a shadow root
4418    pub(crate) tree_is_in_a_shadow_tree: bool,
4419}
4420
4421impl<'a> UnbindContext<'a> {
4422    /// Create a new `UnbindContext` value.
4423    pub(crate) fn new(
4424        parent: &'a Node,
4425        prev_sibling: Option<&'a Node>,
4426        next_sibling: Option<&'a Node>,
4427        cached_index: Option<u32>,
4428    ) -> Self {
4429        UnbindContext {
4430            index: Cell::new(cached_index),
4431            parent,
4432            prev_sibling,
4433            next_sibling,
4434            tree_connected: parent.is_connected(),
4435            tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
4436            tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
4437        }
4438    }
4439
4440    /// The index of the inclusive ancestor that was removed from the tree.
4441    pub(crate) fn index(&self) -> u32 {
4442        if let Some(index) = self.index.get() {
4443            return index;
4444        }
4445        let index = self.prev_sibling.map_or(0, |sibling| sibling.index() + 1);
4446        self.index.set(Some(index));
4447        index
4448    }
4449}
4450
4451/// A node's unique ID, for devtools.
4452pub(crate) struct UniqueId {
4453    cell: UnsafeCell<Option<Box<Uuid>>>,
4454}
4455
4456unsafe_no_jsmanaged_fields!(UniqueId);
4457
4458impl MallocSizeOf for UniqueId {
4459    #[expect(unsafe_code)]
4460    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
4461        if let Some(uuid) = unsafe { &*self.cell.get() } {
4462            unsafe { ops.malloc_size_of(&**uuid) }
4463        } else {
4464            0
4465        }
4466    }
4467}
4468
4469impl UniqueId {
4470    /// Create a new `UniqueId` value. The underlying `Uuid` is lazily created.
4471    fn new() -> UniqueId {
4472        UniqueId {
4473            cell: UnsafeCell::new(None),
4474        }
4475    }
4476
4477    /// The Uuid of that unique ID.
4478    #[expect(unsafe_code)]
4479    fn borrow(&self) -> &Uuid {
4480        unsafe {
4481            let ptr = self.cell.get();
4482            if (*ptr).is_none() {
4483                *ptr = Some(Box::new(Uuid::new_v4()));
4484            }
4485            (*ptr).as_ref().unwrap()
4486        }
4487    }
4488}
4489
4490pub(crate) struct NodeTypeIdWrapper(pub(crate) NodeTypeId);
4491
4492impl From<NodeTypeIdWrapper> for LayoutNodeType {
4493    #[inline(always)]
4494    fn from(node_type: NodeTypeIdWrapper) -> LayoutNodeType {
4495        match node_type.0 {
4496            NodeTypeId::Element(e) => LayoutNodeType::Element(ElementTypeIdWrapper(e).into()),
4497            NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => LayoutNodeType::Text,
4498            x => unreachable!("Layout should not traverse nodes of type {:?}", x),
4499        }
4500    }
4501}
4502
4503struct ElementTypeIdWrapper(ElementTypeId);
4504
4505impl From<ElementTypeIdWrapper> for LayoutElementType {
4506    #[inline(always)]
4507    fn from(element_type: ElementTypeIdWrapper) -> LayoutElementType {
4508        match element_type.0 {
4509            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement) => {
4510                LayoutElementType::HTMLBodyElement
4511            },
4512            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBRElement) => {
4513                LayoutElementType::HTMLBRElement
4514            },
4515            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement) => {
4516                LayoutElementType::HTMLCanvasElement
4517            },
4518            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHtmlElement) => {
4519                LayoutElementType::HTMLHtmlElement
4520            },
4521            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement) => {
4522                LayoutElementType::HTMLIFrameElement
4523            },
4524            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement) => {
4525                LayoutElementType::HTMLImageElement
4526            },
4527            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(_)) => {
4528                LayoutElementType::HTMLMediaElement
4529            },
4530            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement) => {
4531                LayoutElementType::HTMLInputElement
4532            },
4533            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement) => {
4534                LayoutElementType::HTMLOptGroupElement
4535            },
4536            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement) => {
4537                LayoutElementType::HTMLOptionElement
4538            },
4539            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement) => {
4540                LayoutElementType::HTMLObjectElement
4541            },
4542            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLParagraphElement) => {
4543                LayoutElementType::HTMLParagraphElement
4544            },
4545            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLPreElement) => {
4546                LayoutElementType::HTMLPreElement
4547            },
4548            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement) => {
4549                LayoutElementType::HTMLSelectElement
4550            },
4551            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableCellElement) => {
4552                LayoutElementType::HTMLTableCellElement
4553            },
4554            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement) => {
4555                LayoutElementType::HTMLTableColElement
4556            },
4557            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement) => {
4558                LayoutElementType::HTMLTableElement
4559            },
4560            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement) => {
4561                LayoutElementType::HTMLTableRowElement
4562            },
4563            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement) => {
4564                LayoutElementType::HTMLTableSectionElement
4565            },
4566            ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement) => {
4567                LayoutElementType::HTMLTextAreaElement
4568            },
4569            ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
4570                SVGGraphicsElementTypeId::SVGImageElement,
4571            )) => LayoutElementType::SVGImageElement,
4572            ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
4573                SVGGraphicsElementTypeId::SVGSVGElement,
4574            )) => LayoutElementType::SVGSVGElement,
4575            _ => LayoutElementType::Element,
4576        }
4577    }
4578}
4579
4580/// Helper trait to insert an element into vector whose elements
4581/// are maintained in tree order
4582pub(crate) trait VecPreOrderInsertionHelper<T> {
4583    fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
4584}
4585
4586impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
4587where
4588    T: DerivedFrom<Node> + DomObject,
4589{
4590    /// This algorithm relies on the following assumptions:
4591    /// * any elements inserted in this vector share the same tree root
4592    /// * any time an element is removed from the tree root, it is also removed from this array
4593    /// * any time an element is moved within the tree, it is removed from this array and re-inserted
4594    ///
4595    /// Under these assumptions, an element's tree-order position in this array can be determined by
4596    /// performing a [preorder traversal](https://dom.spec.whatwg.org/#concept-tree-order) of the tree root's children,
4597    /// and increasing the destination index in the array every time a node in the array is encountered during
4598    /// the traversal.
4599    fn insert_pre_order(&mut self, elem: &T, tree_root: &Node) {
4600        if self.is_empty() {
4601            self.push(Dom::from_ref(elem));
4602            return;
4603        }
4604
4605        let elem_node = elem.upcast::<Node>();
4606        let mut head: usize = 0;
4607        for node in tree_root.traverse_preorder(ShadowIncluding::No) {
4608            let head_node = DomRoot::upcast::<Node>(DomRoot::from_ref(&*self[head]));
4609            if head_node == node {
4610                head += 1;
4611            }
4612            if elem_node == &*node || head == self.len() {
4613                break;
4614            }
4615        }
4616        self.insert(head, Dom::from_ref(elem));
4617    }
4618}