script/dom/
node.rs

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