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