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