script/dom/
node.rs

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