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