1use std::cell::{Cell, LazyCell, UnsafeCell};
8use std::cmp::Ordering;
9use std::default::Default;
10use std::f64::consts::PI;
11use std::ops::Deref;
12use std::rc::Rc;
13use std::slice::from_ref;
14use std::{cmp, fmt, iter};
15
16use app_units::Au;
17use bitflags::bitflags;
18use devtools_traits::NodeInfo;
19use dom_struct::dom_struct;
20use embedder_traits::{MouseButton, UntrustedNodeAddress};
21use euclid::default::Size2D;
22use euclid::{Point2D, Rect};
23use html5ever::serialize::HtmlSerializer;
24use html5ever::{Namespace, Prefix, QualName, ns, serialize as html_serialize};
25use js::context::{JSContext, NoGC};
26use js::jsapi::JSObject;
27use js::rust::HandleObject;
28use keyboard_types::Modifiers;
29use layout_api::{
30 AccessibilityDamage, AxesOverflow, BoxAreaType, CSSPixelRectVec, GenericLayoutData,
31 NodeRenderingType, PhysicalSides, TrustedNodeAddress, with_layout_state,
32};
33use libc::{self, uintptr_t};
34use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
35use script_bindings::cell::{DomRefCell, Ref, RefMut};
36use script_bindings::codegen::GenericBindings::ElementBinding::ElementMethods;
37use script_bindings::codegen::GenericBindings::EventBinding::EventMethods;
38use script_bindings::codegen::GenericBindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
39use script_bindings::codegen::GenericBindings::SelectionBinding::SelectionMethods;
40use script_bindings::codegen::InheritTypes::{DocumentFragmentTypeId, TextTypeId};
41use script_bindings::reflector::{
42 DomObject, DomObjectWrap, WeakReferenceableDomObjectWrap, reflect_dom_object_with_proto,
43 reflect_weak_referenceable_dom_object_with_proto,
44};
45use script_traits::{DocumentActivity, MouseButtons};
46use servo_base::id::PipelineId;
47use servo_base::text::Utf32CodeUnitsOrNodeOffset;
48use servo_config::pref;
49use smallvec::SmallVec;
50use style::Atom;
51use style::context::QuirksMode;
52use style::dom::OpaqueNode;
53use style::dom_apis::{QueryAll, QueryFirst};
54use style::selector_parser::PseudoElement;
55use style_traits::CSSPixel;
56use uuid::Uuid;
57use xml5ever::{local_name, serialize as xml_serialize};
58
59use crate::conversions::Convert;
60use crate::dom::attr::Attr;
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::HTMLCollectionBinding::HTMLCollectionMethods;
66use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
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::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
72use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
73 ShadowRootMode, SlotAssignmentMode,
74};
75use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
76use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
77use crate::dom::bindings::conversions::{self, DerivedFrom};
78use crate::dom::bindings::domname::namespace_from_domstring;
79use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
80use crate::dom::bindings::inheritance::{
81 Castable, CharacterDataTypeId, EventTargetTypeId, NodeTypeId,
82};
83use crate::dom::bindings::root::{
84 Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout, UnrootedDom,
85};
86use crate::dom::bindings::str::{DOMString, USVString};
87use crate::dom::characterdata::CharacterData;
88use crate::dom::context::{BindContext, IsShadowTree, MoveContext, UnbindContext};
89use crate::dom::css::cssstylesheet::CSSStyleSheet;
90use crate::dom::css::stylesheetlist::StyleSheetListOwner;
91use crate::dom::customelementregistry::{
92 CallbackReaction, CustomElementRegistry, try_upgrade_element,
93};
94use crate::dom::document::{Document, HasBrowsingContext, IsHTMLDocument};
95use crate::dom::documentfragment::DocumentFragment;
96use crate::dom::documenttype::DocumentType;
97use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
98use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
99use crate::dom::eventtarget::EventTarget;
100use crate::dom::globalscope::GlobalScope;
101use crate::dom::html::htmlcollection::HTMLCollection;
102use crate::dom::html::htmlelement::HTMLElement;
103use crate::dom::html::htmllinkelement::HTMLLinkElement;
104use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
105use crate::dom::html::htmlstyleelement::HTMLStyleElement;
106use crate::dom::inputevent::HitTestResult;
107use crate::dom::iterators::{
108 ShadowIncluding, UnrootedFollowingFlatTreeNodesTraversal, UnrootedFollowingNodeIterator,
109 UnrootedPrecedingNodeIterator,
110};
111use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
112use crate::dom::node::iterators::{
113 FollowingNodeIterator, PrecedingNodeIterator, SimpleNodeIterator, TreeIterator,
114 UnrootedSimpleNodeIterator, UnrootedTreeIterator,
115};
116use crate::dom::node::nodelist::NodeList;
117use crate::dom::node::virtualmethods::{VirtualMethods, vtable_for};
118use crate::dom::pointerevent::{PointerEvent, PointerId};
119use crate::dom::range::WeakRangeVec;
120use crate::dom::raredata::NodeRareData;
121use crate::dom::servoparser::html::HtmlSerialize;
122use crate::dom::servoparser::serialize_html_fragment;
123use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
124use crate::dom::text::Text;
125use crate::dom::types::{CDATASection, KeyboardEvent, MouseEvent, ProcessingInstruction};
126use crate::dom::window::Window;
127use crate::dom::{
128 ChildrenMutation, Range, live_range_insert_steps, live_range_normalization_steps,
129 live_range_pre_remove_steps, live_range_pre_remove_steps_for_parent,
130 live_range_pre_remove_steps_for_removed_subtree,
131};
132use crate::drag::document_selection_drag::DocumentSelectionDragHandler;
133use crate::drag::drag_gesture::{DragGesture, DragHandler};
134use crate::event_loop::document_loader::DocumentLoader;
135use crate::event_loop::script_thread::ScriptThread;
136use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode};
137
138#[dom_struct]
144pub struct Node {
145 eventtarget: EventTarget,
147
148 parent_node: MutNullableDom<Node>,
150
151 first_child: MutNullableDom<Node>,
153
154 last_child: MutNullableDom<Node>,
156
157 next_sibling: MutNullableDom<Node>,
159
160 prev_sibling: MutNullableDom<Node>,
162
163 owner_doc: MutNullableDom<Document>,
165
166 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
168
169 children_count: Cell<u32>,
171
172 flags: Cell<NodeFlags>,
174
175 inclusive_descendants_version: Cell<u64>,
177
178 #[no_trace]
181 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
182}
183
184impl fmt::Debug for Node {
185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186 if let Some(element) = self.downcast::<Element>() {
187 element.fmt(f)
188 } else if let Some(character_data) = self.downcast::<CharacterData>() {
189 write!(f, "[Text({})]", *character_data.data())
190 } else {
191 write!(f, "[Node({:?})]", self.type_id())
192 }
193 }
194}
195
196#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
198pub(crate) struct NodeFlags(u16);
199
200bitflags! {
201 impl NodeFlags: u16 {
202 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
206
207 const HAS_DIRTY_DESCENDANTS = 1 << 1;
209
210 const CLICK_IN_PROGRESS = 1 << 2;
213
214 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
219
220 const HAS_SNAPSHOT = 1 << 7;
225
226 const HANDLED_SNAPSHOT = 1 << 8;
228
229 const IS_IN_SHADOW_TREE = 1 << 9;
231
232 const IS_CONNECTED = 1 << 10;
236
237 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
240
241 const IS_IN_UA_WIDGET = 1 << 12;
244
245 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
247
248 const OVERLAPS_DOCUMENT_SELECTION = 1 << 14;
255 }
256}
257
258#[derive(Clone, Copy, MallocSizeOf)]
262pub(crate) enum SuppressObserver {
263 Suppressed,
264 Unsuppressed,
265}
266
267pub(crate) enum ForceSlottableNodeReconciliation {
268 Force,
269 Skip,
270}
271
272impl Node {
273 pub(super) fn parent_node(&self) -> &MutNullableDom<Node> {
275 &self.parent_node
276 }
277
278 pub(super) fn first_child(&self) -> &MutNullableDom<Node> {
279 &self.first_child
280 }
281
282 pub(super) fn last_child(&self) -> &MutNullableDom<Node> {
283 &self.last_child
284 }
285
286 pub(super) fn next_sibling(&self) -> &MutNullableDom<Node> {
287 &self.next_sibling
288 }
289
290 pub(super) fn prev_sibling(&self) -> &MutNullableDom<Node> {
291 &self.prev_sibling
292 }
293
294 pub(super) fn get_owner_doc(&self) -> &MutNullableDom<Document> {
295 &self.owner_doc
296 }
297
298 pub(super) fn get_rare_data(&self) -> &DomRefCell<Option<Box<NodeRareData>>> {
299 &self.rare_data
300 }
301
302 pub(super) fn flags(&self) -> &Cell<NodeFlags> {
303 &self.flags
304 }
305
306 pub(crate) fn layout_data(&self) -> &DomRefCell<Option<Box<GenericLayoutData>>> {
307 &self.layout_data
308 }
309
310 fn add_child(&self, cx: &mut JSContext, new_child: &Node, before: Option<&Node>) {
314 assert!(new_child.parent_node.get().is_none());
315 assert!(new_child.prev_sibling.get().is_none());
316 assert!(new_child.next_sibling.get().is_none());
317
318 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
319
320 match before {
321 Some(before) => {
322 assert!(before.parent_node.get().as_deref() == Some(self));
323 let prev_sibling = before.GetPreviousSibling();
324 match prev_sibling {
325 None => {
326 assert!(self.first_child.get().as_deref() == Some(before));
327 self.first_child.set(Some(new_child));
328 },
329 Some(ref prev_sibling) => {
330 prev_sibling.next_sibling.set(Some(new_child));
331 new_child.prev_sibling.set(Some(prev_sibling));
332 },
333 }
334 before.prev_sibling.set(Some(new_child));
335 new_child.next_sibling.set(Some(before));
336 },
337 None => {
338 let last_child = self.GetLastChild();
339 match last_child {
340 None => self.first_child.set(Some(new_child)),
341 Some(ref last_child) => {
342 assert!(last_child.next_sibling.get().is_none());
343 last_child.next_sibling.set(Some(new_child));
344 new_child.prev_sibling.set(Some(last_child));
345 },
346 }
347
348 self.last_child.set(Some(new_child));
349 },
350 }
351
352 new_child.parent_node.set(Some(self));
353 self.children_count.set(self.children_count.get() + 1);
354
355 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
356 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
357 let parent_is_connected = self.is_connected();
358 let parent_is_in_ua_widget = self.is_in_ua_widget();
359
360 let context = BindContext::new(self, IsShadowTree::No);
361
362 for node in new_child.traverse_preorder(ShadowIncluding::No) {
363 if parent_in_shadow_tree {
364 if let Some(shadow_root) = self.containing_shadow_root() {
365 node.set_containing_shadow_root(Some(&*shadow_root));
366 }
367 debug_assert!(node.containing_shadow_root().is_some());
368 }
369 node.set_flag(
370 NodeFlags::IS_IN_A_DOCUMENT_TREE,
371 parent_is_in_a_document_tree,
372 );
373 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
374 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
375 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
376
377 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
379 vtable_for(&node).bind_to_tree(cx, &context);
380 }
381 }
382
383 pub(crate) fn complete_remove_subtree(
386 cx: &mut JSContext,
387 root: &Node,
388 context: &UnbindContext,
389 ) {
390 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
392 .union(NodeFlags::IS_CONNECTED)
393 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
394 .union(NodeFlags::HAS_SNAPSHOT)
395 .union(NodeFlags::HANDLED_SNAPSHOT)
396 .union(NodeFlags::OVERLAPS_DOCUMENT_SELECTION);
397
398 for node in root.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No) {
399 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
400
401 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
404 for node in shadow_root
405 .upcast::<Node>()
406 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
407 {
408 node.set_flag(RESET_FLAGS, false);
409 }
410 }
411 }
412
413 let is_parent_connected = context.parent.is_connected();
415 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
416
417 let document = root.owner_doc();
420 let cleanup_node = |cx: &mut JSContext, node: &Node| {
421 document.cancel_animations_for_node(node);
422 document.clean_up_style_and_layout_data_for_node(node);
423
424 vtable_for(node).unbind_from_tree(cx, context);
429
430 if is_parent_connected && let Some(element) = node.as_custom_element() {
432 custom_element_reaction_stack.enqueue_callback_reaction(
433 cx,
434 &element,
435 CallbackReaction::Disconnected,
436 None,
437 );
438 }
439 };
440
441 for node in root.traverse_preorder(ShadowIncluding::No) {
442 cleanup_node(cx, &node);
443
444 if node.containing_shadow_root().is_some() {
447 node.set_containing_shadow_root(None);
450 }
451
452 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
455 for node in shadow_root
456 .upcast::<Node>()
457 .traverse_preorder(ShadowIncluding::Yes)
458 {
459 cleanup_node(cx, &node);
460 }
461 }
462 }
463
464 if root.owner_document().accessibility_active() {
467 root.owner_document()
468 .accessibility_data_mut()
469 .root_removed_node(cx.no_gc(), root);
470 }
471 }
472
473 pub(crate) fn complete_move_subtree(cx: &mut JSContext, root: &Node) {
474 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
476 .union(NodeFlags::IS_CONNECTED)
477 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
478 .union(NodeFlags::HAS_SNAPSHOT)
479 .union(NodeFlags::HANDLED_SNAPSHOT)
480 .union(NodeFlags::OVERLAPS_DOCUMENT_SELECTION);
481
482 let document = root.owner_document();
483 for node in root.traverse_preorder(ShadowIncluding::No) {
484 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
485 document.clean_up_style_and_layout_data_for_node(&node);
486
487 if let Some(element) = node.downcast::<Element>() {
490 element.unregister_current_id_and_name_attribute(cx);
491 }
492
493 if node.containing_shadow_root().is_some() {
496 node.set_containing_shadow_root(None);
499 }
500
501 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
505 for node in shadow_root
506 .upcast::<Node>()
507 .traverse_preorder(ShadowIncluding::Yes)
508 {
509 node.set_flag(RESET_FLAGS, false);
510 document.clean_up_style_and_layout_data_for_node(&node);
511 }
512 }
513 }
514 }
515
516 fn remove_child(&self, cx: &mut JSContext, child: &Node, cached_index: Option<u32>) {
520 assert!(child.parent_node.get().as_deref() == Some(self));
521
522 if let Some(element) = self.downcast::<Element>() {
523 element.note_dirty_descendants(cx.no_gc());
524 }
525 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
526
527 let prev_sibling = child.GetPreviousSibling();
528 match prev_sibling {
529 None => {
530 self.first_child.set(child.next_sibling.get().as_deref());
531 },
532 Some(ref prev_sibling) => {
533 prev_sibling
534 .next_sibling
535 .set(child.next_sibling.get().as_deref());
536 },
537 }
538 let next_sibling = child.GetNextSibling();
539 match next_sibling {
540 None => {
541 self.last_child.set(child.prev_sibling.get().as_deref());
542 },
543 Some(ref next_sibling) => {
544 next_sibling
545 .prev_sibling
546 .set(child.prev_sibling.get().as_deref());
547 },
548 }
549
550 let context = UnbindContext::new(
551 self,
552 prev_sibling.as_deref(),
553 next_sibling.as_deref(),
554 cached_index,
555 );
556
557 child.prev_sibling.set(None);
558 child.next_sibling.set(None);
559 child.parent_node.set(None);
560 self.children_count.set(self.children_count.get() - 1);
561
562 Self::complete_remove_subtree(cx, child, &context);
563 }
564
565 fn move_child(&self, cx: &mut JSContext, child: &Node) {
566 assert!(child.parent_node.get().as_deref() == Some(self));
567 self.dirty(cx.no_gc(), NodeDamage::ContentOrHeritage);
568 if let Some(element) = self.downcast::<Element>() {
569 element.note_dirty_descendants(cx.no_gc());
570 }
571
572 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
573
574 child.prev_sibling.set(None);
575 child.next_sibling.set(None);
576 child.parent_node.set(None);
577 self.children_count.set(self.children_count.get() - 1);
578 Self::complete_move_subtree(cx, child)
579 }
580
581 pub(crate) fn to_opaque(&self) -> OpaqueNode {
582 OpaqueNode(self.reflector().get_jsobject().get() as usize)
583 }
584
585 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
586 self.downcast::<Element>().and_then(|element| {
587 if element.is_custom() {
588 assert!(element.get_custom_element_definition().is_some());
589 Some(DomRoot::from_ref(element))
590 } else {
591 None
592 }
593 })
594 }
595
596 pub(crate) fn fire_synthetic_pointer_event_not_trusted(
598 &self,
599 cx: &mut JSContext,
600 event_type: Atom,
601 ) {
602 let window = self.owner_window();
606
607 let pointer_event = PointerEvent::new(
609 cx,
610 &window, event_type,
612 EventBubbles::Bubbles, EventCancelable::Cancelable, Some(&window), 0, Point2D::zero(), Point2D::zero(), Point2D::zero(), Modifiers::empty(), MouseButton::Primary, MouseButtons::empty(), None, None, PointerId::NonPointerDevice as i32, 1, 1, 0.5, 0.0, 0, 0, 0, PI / 2.0, 0.0, DOMString::from(""), false, vec![], vec![], );
639
640 pointer_event.upcast::<Event>().set_composed(true);
642
643 pointer_event.upcast::<Event>().set_trusted(false);
645
646 pointer_event
649 .upcast::<Event>()
650 .dispatch(cx, self.upcast::<EventTarget>(), false);
651 }
652
653 pub(crate) fn parent_directionality(&self) -> String {
654 let mut current = self.GetParentNode();
655
656 loop {
657 match current {
658 Some(node) => {
659 if let Some(directionality) = node
660 .downcast::<HTMLElement>()
661 .and_then(|html_element| html_element.directionality())
662 {
663 return directionality;
664 } else {
665 current = node.GetParentNode();
666 }
667 },
668 None => return "ltr".to_owned(),
669 }
670 }
671 }
672
673 pub(crate) fn is_being_rendered_or_delegates_rendering(
677 &self,
678 pseudo_element: Option<PseudoElement>,
679 ) -> bool {
680 matches!(
681 self.owner_window()
682 .layout()
683 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
684 NodeRenderingType::Rendered | NodeRenderingType::DelegatesRendering
685 )
686 }
687
688 pub(crate) fn is_being_rendered(&self, pseudo_element: Option<PseudoElement>) -> bool {
690 matches!(
691 self.owner_window()
692 .layout()
693 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
694 NodeRenderingType::Rendered
695 )
696 }
697
698 pub(crate) fn add_pending_accessibility_damage(&self, damage: AccessibilityDamage) {
699 if !self.owner_doc().accessibility_active() {
700 return;
701 }
702
703 self.owner_doc()
704 .accessibility_data_mut()
705 .add_pending_accessibility_damage_for_node(self, damage);
706 }
707}
708
709impl Node {
710 fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
711 let mut rare_data = self.rare_data.borrow_mut();
712 if rare_data.is_none() {
713 *rare_data = Some(Default::default());
714 }
715 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
716 }
717
718 pub(crate) fn is_before(&self, other: &Node) -> bool {
721 let cmp = other.CompareDocumentPosition(self);
722 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
723 return false;
724 }
725
726 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
727 }
728
729 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
732 RefMut::map(self.ensure_rare_data(), |rare_data| {
733 &mut rare_data.mutation_observers
734 })
735 }
736
737 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
738 let rare_data = self.rare_data.borrow();
739 if rare_data.is_none() {
740 return None;
741 }
742 Some(Ref::map(rare_data, |rare_data| {
743 &rare_data.as_ref().unwrap().mutation_observers
744 }))
745 }
746
747 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
749 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
750 self.ensure_rare_data().mutation_observers.push(observer);
751 }
752
753 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
755 let mut rare_data = self.rare_data.borrow_mut();
756 let Some(rare_data) = rare_data.as_mut() else {
757 return;
758 };
759 rare_data
760 .mutation_observers
761 .retain(|registered_observer| &*registered_observer.observer != observer)
762 }
763
764 pub(crate) fn debug_str(&self) -> String {
766 format!("{:?}", self.type_id())
767 }
768
769 pub(crate) fn is_in_a_document_tree(&self) -> bool {
771 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
772 }
773
774 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
776 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
777 }
778
779 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
780 self.flags
781 .get()
782 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
783 }
784
785 pub(crate) fn set_weird_parser_insertion_mode(&self) {
786 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
787 }
788
789 pub(crate) fn is_connected(&self) -> bool {
791 self.flags.get().contains(NodeFlags::IS_CONNECTED)
792 }
793
794 pub(crate) fn set_in_ua_widget(&self, in_ua_widget: bool) {
795 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, in_ua_widget)
796 }
797
798 pub(crate) fn is_in_ua_widget(&self) -> bool {
799 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
800 }
801
802 pub(crate) fn type_id(&self) -> NodeTypeId {
804 match *self.eventtarget.type_id() {
805 EventTargetTypeId::Node(type_id) => type_id,
806 _ => unreachable!(),
807 }
808 }
809
810 pub(crate) fn len(&self) -> u32 {
812 match self.type_id() {
813 NodeTypeId::DocumentType => 0,
814 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
815 _ => self.children_count(),
816 }
817 }
818
819 pub(crate) fn is_empty(&self) -> bool {
820 self.len() == 0
822 }
823
824 pub(crate) fn index(&self) -> u32 {
826 self.preceding_siblings().count() as u32
827 }
828
829 pub(crate) fn has_parent(&self) -> bool {
831 self.parent_node.get().is_some()
832 }
833
834 pub(crate) fn children_count(&self) -> u32 {
835 self.children_count.get()
836 }
837
838 pub(crate) fn ensure_weak_ranges(&self) -> RefMut<'_, WeakRangeVec> {
839 RefMut::map(self.ensure_rare_data(), |rare_data| {
840 &mut rare_data.weak_ranges
841 })
842 }
843
844 pub(crate) fn has_live_ranges(&self) -> bool {
846 self.rare_data
847 .borrow()
848 .as_ref()
849 .is_some_and(|data| !data.weak_ranges.is_empty())
850 }
851
852 pub(crate) fn live_ranges(&self) -> SmallVec<[DomRoot<Range>; 4]> {
854 let rare_data = self.rare_data.borrow();
855 let Some(rare_data) = &*rare_data else {
856 return Default::default();
857 };
858 rare_data.weak_ranges.live_ranges()
859 }
860
861 #[inline]
862 pub(crate) fn is_doctype(&self) -> bool {
863 self.type_id() == NodeTypeId::DocumentType
864 }
865
866 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
867 self.flags.get().contains(flag)
868 }
869
870 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
871 let mut flags = self.flags.get();
872
873 if value {
874 flags.insert(flag);
875 } else {
876 flags.remove(flag);
877 }
878
879 self.flags.set(flags);
880 }
881
882 pub(crate) fn rev_version(&self, no_gc: &NoGC) {
883 let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
888 let version = cmp::max(
889 self.inclusive_descendants_version(),
890 doc.inclusive_descendants_version(),
891 ) + 1;
892
893 for node in self.inclusive_ancestors_unrooted(no_gc, ShadowIncluding::No) {
894 node.inclusive_descendants_version.set(version);
895 }
896 doc.inclusive_descendants_version.set(version);
897 }
898
899 pub(crate) fn clear_layout_data(&self) {
900 self.layout_data.take();
901 }
902
903 pub(crate) fn dirty(&self, no_gc: &NoGC, damage: NodeDamage) {
904 self.rev_version(no_gc);
905 if !self.is_connected() {
906 return;
907 }
908
909 match self.type_id() {
910 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..)) => {
911 *self.layout_data.borrow_mut() = None;
914
915 self.parent_node
919 .get()
920 .unwrap()
921 .dirty(no_gc, NodeDamage::ContentOrHeritage);
922
923 if damage == NodeDamage::Other {
924 self.add_pending_accessibility_damage(AccessibilityDamage::Node);
925 }
926 },
927 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(no_gc, damage),
928 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
929 .downcast::<ShadowRoot>()
930 .unwrap()
931 .Host()
932 .upcast::<Element>()
933 .restyle(no_gc, damage),
934 _ => {},
935 };
936 }
937
938 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
940 self.inclusive_descendants_version.get()
941 }
942
943 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
945 TreeIterator::new(self, shadow_including)
946 }
947
948 pub(crate) fn traverse_preorder_non_rooting<'b>(
951 &self,
952 no_gc: &'b NoGC,
953 shadow_including: ShadowIncluding,
954 ) -> UnrootedTreeIterator<'b> {
955 UnrootedTreeIterator::new(self, shadow_including, no_gc)
956 }
957
958 pub(crate) fn inclusively_following_siblings(
959 &self,
960 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
961 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), |n| n.GetNextSibling())
962 }
963
964 pub(crate) fn inclusively_following_siblings_unrooted<'b>(
965 &self,
966 no_gc: &'b NoGC,
967 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
968 UnrootedSimpleNodeIterator::new(
969 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
970 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
971 no_gc,
972 )
973 }
974
975 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
976 &self,
977 no_gc: &'b NoGC,
978 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
979 UnrootedSimpleNodeIterator::new(
980 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
981 |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
982 no_gc,
983 )
984 }
985
986 pub(crate) fn common_ancestor(
987 &self,
988 other: &Node,
989 shadow_including: ShadowIncluding,
990 ) -> Option<DomRoot<Node>> {
991 self.inclusive_ancestors(shadow_including).find(|ancestor| {
992 other
993 .inclusive_ancestors(shadow_including)
994 .any(|node| node == *ancestor)
995 })
996 }
997
998 pub(crate) fn common_ancestor_in_flat_tree(
999 &self,
1000 no_gc: &NoGC,
1001 other: &Node,
1002 ) -> Option<DomRoot<Node>> {
1003 self.inclusive_ancestors_in_flat_tree_unrooted(no_gc)
1004 .find(|ancestor| {
1005 other
1006 .inclusive_ancestors_in_flat_tree_unrooted(no_gc)
1007 .any(|node| node == *ancestor)
1008 })
1009 .map(|node| node.as_rooted())
1010 }
1011
1012 pub(crate) fn following_flat_tree_nodes_unrooted<'no_gc>(
1013 &self,
1014 no_gc: &'no_gc NoGC,
1015 ) -> UnrootedFollowingFlatTreeNodesTraversal<'no_gc> {
1016 UnrootedFollowingFlatTreeNodesTraversal::new(self, no_gc)
1017 }
1018
1019 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
1021 self == child || self.is_ancestor_of(child)
1023 }
1024
1025 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
1027 let mut current = &possible_descendant.parent_node;
1029 let mut done = false;
1030
1031 while let Some(node) = current.if_is_some(|node| {
1032 done = node == self;
1033 &node.parent_node
1034 }) {
1035 if done {
1036 break;
1037 }
1038 current = node
1039 }
1040 done
1041 }
1042
1043 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
1045 self.is_inclusive_ancestor_of(child) ||
1048 child
1049 .GetRootNode(&GetRootNodeOptions::empty())
1050 .downcast::<DocumentFragment>()
1051 .and_then(|fragment| fragment.host())
1052 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1053 }
1054
1055 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1057 node.inclusive_ancestors(ShadowIncluding::Yes)
1058 .any(|ancestor| &*ancestor == self)
1059 }
1060
1061 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1062 SimpleNodeIterator::new(self.GetNextSibling(), |n| n.GetNextSibling())
1063 }
1064
1065 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1066 SimpleNodeIterator::new(self.GetPreviousSibling(), |n| n.GetPreviousSibling())
1067 }
1068
1069 pub(crate) fn following_nodes(
1070 &self,
1071 root: &Node,
1072 shadow_including: ShadowIncluding,
1073 ) -> FollowingNodeIterator {
1074 FollowingNodeIterator::new(
1075 Some(DomRoot::from_ref(self)),
1076 DomRoot::from_ref(root),
1077 shadow_including,
1078 )
1079 }
1080
1081 pub(crate) fn following_nodes_unrooted<'b>(
1082 &self,
1083 no_gc: &'b NoGC,
1084 root: &Node,
1085 shadow_including: ShadowIncluding,
1086 ) -> UnrootedFollowingNodeIterator<'b> {
1087 UnrootedFollowingNodeIterator::new(
1088 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1089 UnrootedDom::from_dom(Dom::from_ref(root), no_gc),
1090 shadow_including,
1091 no_gc,
1092 )
1093 }
1094
1095 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1096 PrecedingNodeIterator::new(Some(DomRoot::from_ref(self)), DomRoot::from_ref(root))
1097 }
1098
1099 pub(crate) fn preceding_nodes_unrooted<'b>(
1100 &self,
1101 no_gc: &'b NoGC,
1102 root: &Node,
1103 ) -> UnrootedPrecedingNodeIterator<'b> {
1104 UnrootedPrecedingNodeIterator::new(
1105 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1106 UnrootedDom::from_dom(Dom::from_ref(root), no_gc),
1107 no_gc,
1108 )
1109 }
1110
1111 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1114 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetLastChild())
1115 }
1116
1117 pub(crate) fn descending_last_children_unrooted<'b>(
1118 &self,
1119 no_gc: &'b NoGC,
1120 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> {
1121 UnrootedSimpleNodeIterator::new(
1122 self.get_last_child_unrooted(no_gc),
1123 |n, no_gc| n.get_last_child_unrooted(no_gc),
1124 no_gc,
1125 )
1126 }
1127
1128 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1129 child
1130 .parent_node
1131 .get()
1132 .is_some_and(|parent| &*parent == self)
1133 }
1134
1135 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1136 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1137 }
1138
1139 pub(crate) fn containing_block_node_without_reflow(&self) -> Option<DomRoot<Node>> {
1141 self.owner_window()
1142 .containing_block_node_query_without_reflow(self)
1143 }
1144
1145 pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1146 self.owner_window().padding_query_without_reflow(self)
1147 }
1148
1149 pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1150 self.owner_window()
1151 .box_area_query(self, BoxAreaType::Content, false)
1152 }
1153
1154 pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1155 self.owner_window()
1156 .box_area_query(self, BoxAreaType::Border, false)
1157 }
1158
1159 pub(crate) fn border_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1160 self.owner_window()
1161 .box_area_query_without_reflow(self, BoxAreaType::Border, false)
1162 }
1163
1164 pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1165 self.owner_window()
1166 .box_area_query(self, BoxAreaType::Padding, false)
1167 }
1168
1169 pub(crate) fn padding_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1170 self.owner_window()
1171 .box_area_query_without_reflow(self, BoxAreaType::Padding, false)
1172 }
1173
1174 pub(crate) fn border_boxes(&self) -> CSSPixelRectVec {
1175 self.owner_window()
1176 .box_areas_query(self, BoxAreaType::Border)
1177 }
1178
1179 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1180 self.owner_window().client_rect_query(self)
1181 }
1182
1183 pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1186 let document = self.owner_doc();
1188
1189 if !document.is_active() {
1191 return Rect::zero();
1192 }
1193
1194 let window = document.window();
1197 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1198
1199 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1200 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1201 let is_body_element = self
1202 .downcast::<HTMLElement>()
1203 .is_some_and(|e| e.is_body_element());
1204
1205 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1211 let viewport_scrolling_area = window.scrolling_area_query(None);
1212 return Rect::new(
1213 viewport_scrolling_area.origin,
1214 viewport_scrolling_area.size.max(viewport),
1215 );
1216 }
1217
1218 window.scrolling_area_query(Some(self))
1222 }
1223
1224 pub(crate) fn effective_overflow(&self) -> Option<AxesOverflow> {
1225 self.owner_window().query_effective_overflow(self)
1226 }
1227
1228 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1229 self.owner_window()
1230 .query_effective_overflow_without_reflow(self)
1231 }
1232
1233 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1235 let parent = &self.parent_node;
1237
1238 let parent = match parent.get() {
1240 None => return Ok(()),
1241 Some(parent) => parent,
1242 };
1243
1244 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1246
1247 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1249
1250 let viable_previous_sibling = match viable_previous_sibling {
1252 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1253 None => parent.first_child.get(),
1254 };
1255
1256 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1258
1259 Ok(())
1260 }
1261
1262 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1264 let parent = &self.parent_node;
1266
1267 let parent = match parent.get() {
1269 None => return Ok(()),
1270 Some(parent) => parent,
1271 };
1272
1273 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1275
1276 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1278
1279 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1281
1282 Ok(())
1283 }
1284
1285 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1287 let Some(parent) = self.GetParentNode() else {
1289 return Ok(());
1291 };
1292
1293 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1295
1296 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1298
1299 if self.parent_node == Some(&*parent) {
1300 parent.ReplaceChild(cx, &node, self)?;
1302 } else {
1303 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1305 }
1306 Ok(())
1307 }
1308
1309 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1311 let doc = self.owner_doc();
1313 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1314 let first_child = self.first_child.get();
1316 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1317 }
1318
1319 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1321 let doc = self.owner_doc();
1323 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1324 self.AppendChild(cx, &node).map(|_| ())
1326 }
1327
1328 pub(crate) fn replace_children(
1330 &self,
1331 cx: &mut JSContext,
1332 nodes: Vec<NodeOrString>,
1333 ) -> ErrorResult {
1334 let doc = self.owner_doc();
1337 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1338
1339 Node::ensure_pre_insertion_validity(cx.no_gc(), &node, self, None)?;
1341
1342 Node::replace_all(cx, Some(&node), self);
1344 Ok(())
1345 }
1346
1347 pub(crate) fn move_before(
1349 &self,
1350 cx: &mut JSContext,
1351 node: &Node,
1352 child: Option<&Node>,
1353 ) -> ErrorResult {
1354 let reference_child_root;
1357 let reference_child = match child {
1358 Some(child) if child == node => {
1359 reference_child_root = node.GetNextSibling();
1360 reference_child_root.as_deref()
1361 },
1362 _ => child,
1363 };
1364
1365 Node::move_fn(cx, node, self, reference_child)
1367 }
1368
1369 fn move_fn(
1371 cx: &mut JSContext,
1372 node: &Node,
1373 new_parent: &Node,
1374 child: Option<&Node>,
1375 ) -> ErrorResult {
1376 let mut options = GetRootNodeOptions::empty();
1381 options.composed = true;
1382 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1383 return Err(Error::HierarchyRequest(Some(
1384 "The `newParent` node's shadow root is not the same as the `node`'s shadow root"
1385 .into(),
1386 )));
1387 }
1388
1389 if node.is_inclusive_ancestor_of(new_parent) {
1392 return Err(Error::HierarchyRequest(Some(
1393 "`node` node cannot be the inclusive ancestor of the `newParent` node".into(),
1394 )));
1395 }
1396
1397 if let Some(child) = child &&
1400 !new_parent.is_parent_of(child)
1401 {
1402 return Err(Error::NotFound(Some(
1403 "`child` node's parent node is not `newParent`".into(),
1404 )));
1405 }
1406
1407 match node.type_id() {
1412 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1413 if new_parent.is::<Document>() {
1414 return Err(Error::HierarchyRequest(Some(
1415 "`node` cannot be a text node when `newParent` is a document".into(),
1416 )));
1417 }
1418 },
1419 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1420 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1421 NodeTypeId::Element(_) => (),
1422 NodeTypeId::DocumentFragment(_) |
1423 NodeTypeId::DocumentType |
1424 NodeTypeId::Document(_) |
1425 NodeTypeId::Attr => {
1426 return Err(Error::HierarchyRequest(Some(
1427 "To move `node` into a `newParent`, it must be an Element".into(),
1428 )));
1429 },
1430 }
1431
1432 if new_parent.is::<Document>() && node.is::<Element>() {
1436 if new_parent.child_elements().next().is_some() {
1438 return Err(Error::HierarchyRequest(Some(
1439 "`newParent` document cannot have an element child".into(),
1440 )));
1441 }
1442
1443 if child.is_some_and(|child| {
1446 child
1447 .inclusively_following_siblings_unrooted(cx.no_gc())
1448 .any(|child| child.is_doctype())
1449 }) {
1450 return Err(Error::HierarchyRequest(Some(
1451 "`child` node has a document node following it".into(),
1452 )));
1453 }
1454 }
1455
1456 let old_parent = node
1459 .parent_node
1460 .get()
1461 .expect("old_parent should always be initialized");
1462
1463 live_range_pre_remove_steps(node, &old_parent);
1465
1466 let old_previous_sibling = node.prev_sibling.get();
1471
1472 let old_next_sibling = node.next_sibling.get();
1474
1475 let prev_sibling = node.GetPreviousSibling();
1476 match prev_sibling {
1477 None => {
1478 old_parent
1479 .first_child
1480 .set(node.next_sibling.get().as_deref());
1481 },
1482 Some(ref prev_sibling) => {
1483 prev_sibling
1484 .next_sibling
1485 .set(node.next_sibling.get().as_deref());
1486 },
1487 }
1488 let next_sibling = node.GetNextSibling();
1489 match next_sibling {
1490 None => {
1491 old_parent
1492 .last_child
1493 .set(node.prev_sibling.get().as_deref());
1494 },
1495 Some(ref next_sibling) => {
1496 next_sibling
1497 .prev_sibling
1498 .set(node.prev_sibling.get().as_deref());
1499 },
1500 }
1501
1502 old_parent.move_child(cx, node);
1504
1505 if let Some(slot) = node.assigned_slot() {
1507 slot.assign_slottables(cx);
1508 }
1509
1510 if old_parent.is_in_a_shadow_tree() &&
1513 let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() &&
1514 !slot_element.has_assigned_nodes()
1515 {
1516 slot_element.signal_a_slot_change(cx);
1517 }
1518
1519 let has_slot_descendant = node
1521 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
1522 .any(|element| element.is::<HTMLSlotElement>());
1523 if has_slot_descendant {
1524 old_parent
1526 .GetRootNode(&GetRootNodeOptions::empty())
1527 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1528
1529 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1531 }
1532
1533 if let Some(child) = child {
1535 if let Some(selection) = new_parent.owner_document().selection() {
1537 selection.insert_steps(new_parent, child, 1);
1538 }
1539 live_range_insert_steps(new_parent, child, 1);
1540 }
1541
1542 let new_previous_sibling = child.map_or_else(
1545 || new_parent.last_child.get(),
1546 |child| child.prev_sibling.get(),
1547 );
1548
1549 new_parent.add_child(cx, node, child);
1552
1553 if let Some(shadow_root) = new_parent
1556 .downcast::<Element>()
1557 .and_then(Element::shadow_root) &&
1558 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1559 (node.is::<Element>() || node.is::<Text>())
1560 {
1561 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1562 slottable.assign_a_slot(cx);
1563 }
1564
1565 if new_parent.is_in_a_shadow_tree() &&
1568 let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() &&
1569 !slot_element.has_assigned_nodes()
1570 {
1571 slot_element.signal_a_slot_change(cx);
1572 }
1573
1574 node.GetRootNode(&GetRootNodeOptions::empty())
1576 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1577
1578 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1581 if descendant.deref() == node {
1585 vtable_for(&descendant).moving_steps(cx, &MoveContext::new(Some(&old_parent)));
1586 } else {
1587 vtable_for(&descendant).moving_steps(cx, &MoveContext::new(None));
1588 }
1589
1590 if let Some(descendant) = descendant.downcast::<Element>() &&
1592 descendant.is_custom() &&
1593 new_parent.is_connected()
1594 {
1595 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
1598 custom_element_reaction_stack.enqueue_callback_reaction(
1599 cx,
1600 descendant,
1601 CallbackReaction::ConnectedMove,
1602 None,
1603 );
1604 }
1605 }
1606
1607 let moved = [node];
1610 let mutation = LazyCell::new(|| Mutation::ChildList {
1611 added: None,
1612 removed: Some(&moved),
1613 prev: old_previous_sibling.as_deref(),
1614 next: old_next_sibling.as_deref(),
1615 });
1616 MutationObserver::queue_a_mutation_record(cx, &old_parent, mutation);
1617
1618 let mutation = LazyCell::new(|| Mutation::ChildList {
1621 added: Some(&moved),
1622 removed: None,
1623 prev: new_previous_sibling.as_deref(),
1624 next: child,
1625 });
1626 MutationObserver::queue_a_mutation_record(cx, new_parent, mutation);
1627
1628 Ok(())
1629 }
1630
1631 #[allow(unsafe_code)]
1633 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1634 pub(crate) fn query_selector(
1635 &self,
1636 no_gc: &NoGC,
1637 selectors: DOMString,
1638 ) -> Fallible<Option<DomRoot<Element>>> {
1639 let document_url = self.owner_document().url().get_arc();
1642
1643 self.owner_document()
1646 .id_map()
1647 .resolve_all(no_gc, self.owner_doc().upcast());
1648
1649 let traced_node = Dom::from_ref(self);
1651
1652 let first_matching_element = with_layout_state(|| {
1653 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1654 ServoDangerousStyleNode::from(layout_node)
1655 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1656 })?;
1657
1658 Ok(first_matching_element.map(ServoDangerousStyleElement::rooted))
1659 }
1660
1661 #[allow(unsafe_code)]
1663 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1664 pub(crate) fn query_selector_all(
1665 &self,
1666 cx: &mut JSContext,
1667 selectors: DOMString,
1668 ) -> Fallible<DomRoot<NodeList>> {
1669 let document_url = self.owner_document().url().get_arc();
1672
1673 self.owner_document()
1676 .id_map()
1677 .resolve_all(cx.no_gc(), self.owner_doc().upcast());
1678
1679 let traced_node = UnrootedDom::from_dom(Dom::from_ref(self), cx.no_gc());
1680 let matching_elements = with_layout_state(|| {
1681 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1682 ServoDangerousStyleNode::from(layout_node)
1683 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1684 })?;
1685 let iter = matching_elements
1686 .into_iter()
1687 .map(ServoDangerousStyleElement::rooted)
1688 .map(DomRoot::upcast::<Node>);
1689
1690 Ok(NodeList::new_simple_list(cx, &self.owner_window(), iter))
1693 }
1694
1695 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1696 SimpleNodeIterator::new(self.GetParentNode(), |n| n.GetParentNode())
1697 }
1698
1699 pub(crate) fn ancestors_unrooted<'a>(
1700 &self,
1701 no_gc: &'a NoGC,
1702 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1703 UnrootedSimpleNodeIterator::new(
1704 self.get_parent_node_unrooted(no_gc),
1705 |node, no_gc| node.get_parent_node_unrooted(no_gc),
1706 no_gc,
1707 )
1708 }
1709
1710 pub(crate) fn inclusive_ancestors(
1712 &self,
1713 shadow_including: ShadowIncluding,
1714 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1715 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |n| {
1716 if shadow_including == ShadowIncluding::Yes &&
1717 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1718 {
1719 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1720 }
1721 n.GetParentNode()
1722 })
1723 }
1724
1725 pub(crate) fn inclusive_ancestors_unrooted<'a>(
1726 &self,
1727 no_gc: &'a NoGC,
1728 shadow_including: ShadowIncluding,
1729 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1730 UnrootedSimpleNodeIterator::new(
1731 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1732 move |n, no_gc| {
1733 if shadow_including == ShadowIncluding::Yes &&
1734 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1735 {
1736 return Some(UnrootedDom::from_dom(
1737 Dom::from_ref(shadow_root.host_unrooted(no_gc).upcast::<Node>()),
1738 no_gc,
1739 ));
1740 }
1741 n.get_parent_node_unrooted(no_gc)
1742 },
1743 no_gc,
1744 )
1745 }
1746
1747 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1748 self.owner_doc.get().unwrap()
1749 }
1750
1751 pub(crate) fn owner_doc_unrooted<'a>(&self, no_gc: &'a NoGC) -> UnrootedDom<'a, Document> {
1752 self.owner_doc.get_unrooted(no_gc).unwrap()
1753 }
1754
1755 pub(crate) fn set_owner_doc(&self, document: &Document) {
1756 self.owner_doc.set(Some(document));
1757 }
1758
1759 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1760 self.rare_data
1761 .borrow()
1762 .as_ref()?
1763 .containing_shadow_root
1764 .as_ref()
1765 .map(|sr| DomRoot::from_ref(&**sr))
1766 }
1767
1768 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1769 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1770 }
1771
1772 pub(crate) fn is_in_html_doc(&self) -> bool {
1773 self.owner_doc().is_html_document()
1774 }
1775
1776 pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1777 self.is_connected() && self.owner_doc().browsing_context().is_some()
1778 }
1779
1780 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1781 SimpleNodeIterator::new(self.GetFirstChild(), |n| n.GetNextSibling())
1782 }
1783
1784 pub(crate) fn children_unrooted<'a>(
1785 &self,
1786 no_gc: &'a NoGC,
1787 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1788 UnrootedSimpleNodeIterator::new(
1789 self.get_first_child_unrooted(no_gc),
1790 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1791 no_gc,
1792 )
1793 }
1794
1795 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1796 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetPreviousSibling())
1797 }
1798
1799 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1801 self.children()
1802 .filter_map(DomRoot::downcast as fn(_) -> _)
1803 .peekable()
1804 }
1805
1806 pub(crate) fn child_elements_unrooted<'a>(
1807 &self,
1808 no_gc: &'a NoGC,
1809 ) -> impl Iterator<Item = UnrootedDom<'a, Element>> + use<'a> {
1810 self.children_unrooted(no_gc)
1811 .filter_map(UnrootedDom::downcast)
1812 .peekable()
1813 }
1814
1815 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1816 if let Some(ref parent) = self.GetParentNode() {
1817 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1818 }
1819 }
1820
1821 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1823 Ref::filter_map(self.rare_data.borrow(), |rare_data| {
1824 rare_data
1825 .as_ref()
1826 .and_then(|rare_data| rare_data.unique_id.as_ref())
1827 })
1828 .ok()
1829 .map(|unique_id| unique_id.borrow().simple().to_string())
1830 }
1831
1832 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1833 let mut rare_data = self.ensure_rare_data();
1834
1835 if rare_data.unique_id.is_none() {
1836 let node_id = UniqueId::new();
1837 ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string());
1838 rare_data.unique_id = Some(node_id);
1839 }
1840 rare_data
1841 .unique_id
1842 .as_ref()
1843 .unwrap()
1844 .borrow()
1845 .simple()
1846 .to_string()
1847 }
1848
1849 pub(crate) fn summarize(&self, cx: &mut JSContext) -> NodeInfo {
1850 let USVString(base_uri) = self.BaseURI();
1851 let node_type = self.NodeType();
1852 let pipeline = self.owner_window().pipeline_id();
1853
1854 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1855 let shadow_root_mode = maybe_shadow_root
1856 .map(ShadowRoot::Mode)
1857 .map(ShadowRootMode::convert);
1858 let host = maybe_shadow_root
1859 .map(ShadowRoot::Host)
1860 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1861 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1862 let Some(root) = potential_host.shadow_root() else {
1863 return false;
1864 };
1865 !root.is_user_agent_widget() || pref!(inspector_show_servo_internal_shadow_roots)
1866 });
1867
1868 let num_children = if is_shadow_host {
1869 self.ChildNodes(cx).Length() as usize + 1
1871 } else {
1872 self.ChildNodes(cx).Length() as usize
1873 };
1874
1875 let window = self.owner_window();
1876 let element = self.downcast::<Element>();
1877 let display = element
1878 .map(|elem| window.GetComputedStyle(cx, elem, None))
1879 .map(|style| style.Display().into());
1880
1881 let is_displayed =
1887 element.is_none_or(|element| !element.is_display_none()) || self.is::<DocumentType>();
1888 let attrs = element.map(Element::summarize).unwrap_or_default();
1889
1890 NodeInfo {
1891 unique_id: self.unique_id(pipeline),
1892 host,
1893 base_uri,
1894 parent: self
1895 .GetParentNode()
1896 .map_or("".to_owned(), |node| node.unique_id(pipeline)),
1897 node_type,
1898 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1899 node_name: String::from(self.NodeName()),
1900 node_value: self.GetNodeValue().map(|v| v.into()),
1901 num_children,
1902 attrs,
1903 is_shadow_host,
1904 shadow_root_mode,
1905 display,
1906 is_displayed,
1907 doctype_name: self
1908 .downcast::<DocumentType>()
1909 .map(DocumentType::name)
1910 .cloned()
1911 .map(String::from),
1912 doctype_public_identifier: self
1913 .downcast::<DocumentType>()
1914 .map(DocumentType::public_id)
1915 .cloned()
1916 .map(String::from),
1917 doctype_system_identifier: self
1918 .downcast::<DocumentType>()
1919 .map(DocumentType::system_id)
1920 .cloned()
1921 .map(String::from),
1922 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1923 }
1924 }
1925
1926 pub(crate) fn insert_cell_or_row<F, G, I>(
1928 &self,
1929 cx: &mut JSContext,
1930 index: i32,
1931 get_items: F,
1932 new_child: G,
1933 ) -> Fallible<DomRoot<HTMLElement>>
1934 where
1935 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1936 G: Fn(&mut JSContext) -> DomRoot<I>,
1937 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1938 {
1939 if index < -1 {
1940 return Err(Error::IndexSize(Some("Index is out of bounds".into())));
1941 }
1942
1943 let tr = new_child(cx);
1944
1945 {
1946 let tr_node = tr.upcast::<Node>();
1947 if index == -1 {
1948 self.InsertBefore(cx, tr_node, None)?;
1949 } else {
1950 let items = get_items(cx);
1951 let node = match items
1952 .elements_iter(cx.no_gc())
1953 .map(UnrootedDom::upcast::<Node>)
1954 .map(Some)
1955 .chain(iter::once(None))
1956 .nth(index as usize)
1957 {
1958 None => return Err(Error::IndexSize(Some("Index is out of bounds".into()))),
1959 Some(node) => node,
1960 };
1961 self.InsertBefore(cx, tr_node, node.map(|node| node.as_rooted()).as_deref())?;
1962 }
1963 }
1964
1965 Ok(DomRoot::upcast::<HTMLElement>(tr))
1966 }
1967
1968 pub(crate) fn delete_cell_or_row<F, G>(
1970 &self,
1971 cx: &mut JSContext,
1972 index: i32,
1973 get_items: F,
1974 is_delete_type: G,
1975 ) -> ErrorResult
1976 where
1977 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1978 G: Fn(&Element) -> bool,
1979 {
1980 let element = match index {
1981 index if index < -1 => {
1982 return Err(Error::IndexSize(Some("Index is out of bounds".into())));
1983 },
1984 -1 => {
1985 let last_child = self.upcast::<Node>().GetLastChild();
1986 match last_child.and_then(|node| {
1987 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
1988 .filter_map(UnrootedDom::downcast::<Element>)
1989 .find(|elem| is_delete_type(elem))
1990 .map(|elem| elem.as_rooted())
1991 }) {
1992 Some(element) => element,
1993 None => return Ok(()),
1994 }
1995 },
1996 index => match get_items(cx).Item(cx, index as u32) {
1997 Some(element) => element,
1998 None => return Err(Error::IndexSize(Some("Index is out of bounds".into()))),
1999 },
2000 };
2001
2002 element.upcast::<Node>().remove_self(cx);
2003 Ok(())
2004 }
2005
2006 pub(crate) fn get_cssom_stylesheet(
2007 &self,
2008 cx: &mut JSContext,
2009 ) -> Option<DomRoot<CSSStyleSheet>> {
2010 if let Some(node) = self.downcast::<HTMLStyleElement>() {
2011 node.get_cssom_stylesheet(cx)
2012 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
2013 node.get_cssom_stylesheet(cx)
2014 } else {
2015 None
2016 }
2017 }
2018
2019 pub(crate) fn get_lang(&self) -> Option<String> {
2021 self.inclusive_ancestors(ShadowIncluding::Yes)
2022 .find_map(|node| {
2023 node.downcast::<Element>().and_then(|el| {
2024 el.get_attribute_string_value_with_namespace(&ns!(xml), &local_name!("lang"))
2025 .or_else(|| el.get_attribute_string_value(&local_name!("lang")))
2026 })
2027 })
2030 }
2031
2032 pub(crate) fn assign_slottables_for_a_tree(
2034 &self,
2035 cx: &JSContext,
2036 force: ForceSlottableNodeReconciliation,
2037 ) {
2038 let is_shadow_root_with_slots = self
2045 .downcast::<ShadowRoot>()
2046 .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
2047 if !is_shadow_root_with_slots &&
2048 !self.is::<HTMLSlotElement>() &&
2049 matches!(force, ForceSlottableNodeReconciliation::Skip)
2050 {
2051 return;
2052 }
2053
2054 for node in self.traverse_preorder_non_rooting(cx, ShadowIncluding::No) {
2057 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
2058 slot.assign_slottables(cx);
2059 }
2060 }
2061 }
2062
2063 pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
2064 let assigned_slot = self
2065 .rare_data
2066 .borrow()
2067 .as_ref()?
2068 .slottable_data
2069 .assigned_slot
2070 .as_ref()?
2071 .as_rooted();
2072 Some(assigned_slot)
2073 }
2074
2075 pub(crate) fn assigned_slot_unrooted<'a>(
2076 &self,
2077 no_gc: &'a NoGC,
2078 ) -> Option<UnrootedDom<'a, HTMLSlotElement>> {
2079 let rare_data = self.rare_data.borrow();
2080 let assigned_slot = rare_data.as_ref()?.slottable_data.assigned_slot.as_ref()?;
2081 Some(UnrootedDom::from_dom(Dom::from_ref(assigned_slot), no_gc))
2082 }
2083
2084 pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
2085 self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
2086 }
2087
2088 pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
2089 let manually_assigned_slot = self
2090 .rare_data
2091 .borrow()
2092 .as_ref()?
2093 .slottable_data
2094 .manual_slot_assignment
2095 .as_ref()?
2096 .as_rooted();
2097 Some(manually_assigned_slot)
2098 }
2099
2100 pub(crate) fn set_manual_slot_assignment(
2101 &self,
2102 manually_assigned_slot: Option<&HTMLSlotElement>,
2103 ) {
2104 self.ensure_rare_data()
2105 .slottable_data
2106 .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
2107 }
2108
2109 pub(crate) fn parent_in_flat_tree<'b>(&self, no_gc: &'b NoGC) -> FlatTreeParent<'b> {
2120 if let Some(assigned_slot) = self.assigned_slot_unrooted(no_gc) {
2121 return FlatTreeParent::Parent(UnrootedDom::upcast::<Node>(assigned_slot));
2122 }
2123
2124 let Some(parent) = self.get_parent_node_unrooted(no_gc) else {
2125 return FlatTreeParent::RootNode;
2126 };
2127
2128 if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
2129 return FlatTreeParent::Parent(UnrootedDom::from_dom(
2130 Dom::from_ref(shadow_root.Host().upcast::<Node>()),
2131 no_gc,
2132 ));
2133 }
2134
2135 if parent
2136 .downcast::<Element>()
2137 .is_some_and(|element| element.is_shadow_host())
2138 {
2139 return FlatTreeParent::NotInFlatTree;
2140 }
2141
2142 if parent
2143 .downcast::<HTMLSlotElement>()
2144 .is_some_and(|slot| slot.has_assigned_nodes())
2145 {
2146 return FlatTreeParent::NotInFlatTree;
2147 }
2148
2149 FlatTreeParent::Parent(parent)
2150 }
2151
2152 pub(crate) fn inclusive_ancestors_in_flat_tree_unrooted<'a>(
2153 &self,
2154 no_gc: &'a NoGC,
2155 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
2156 UnrootedSimpleNodeIterator::new(
2157 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
2158 move |node, no_gc| match node.parent_in_flat_tree(no_gc) {
2159 FlatTreeParent::Parent(parent) => {
2160 Some(UnrootedDom::from_dom(Dom::from_ref(&*parent), no_gc))
2162 },
2163 FlatTreeParent::NotInFlatTree | FlatTreeParent::RootNode => None,
2164 },
2165 no_gc,
2166 )
2167 }
2168
2169 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2171 debug_assert!(self.is_in_ua_widget());
2173 debug_assert!(pseudo_element.is_element_backed());
2174 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2175 }
2176
2177 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2178 self.rare_data
2179 .borrow()
2180 .as_ref()
2181 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2182 }
2183
2184 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2186 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2190 if ancestor.is_editing_host() {
2191 return Some(ancestor);
2192 }
2193 if ancestor
2194 .downcast::<HTMLElement>()
2195 .is_some_and(|el| el.ContentEditable().str() == "false")
2196 {
2197 return None;
2198 }
2199 }
2200 None
2201 }
2202
2203 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2204 self.editing_host_of().is_some()
2205 }
2206
2207 pub(crate) fn is_editing_host(&self) -> bool {
2209 self.downcast::<HTMLElement>()
2210 .is_some_and(HTMLElement::is_editing_host)
2211 }
2212
2213 pub(crate) fn is_editable(&self) -> bool {
2215 if self.is_editing_host() {
2217 return false;
2218 }
2219 let html_element = self.downcast::<HTMLElement>();
2221 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2222 return false;
2223 }
2224 let Some(parent) = self.GetParentNode() else {
2226 return false;
2227 };
2228 if !parent.is_editable_or_editing_host() {
2229 return false;
2230 }
2231 html_element.is_some() || (!self.is::<Element>() && parent.is::<HTMLElement>())
2233 }
2234}
2235
2236fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2238where
2239 I: Iterator<Item = DomRoot<Node>>,
2240{
2241 nodes.find(|node| {
2242 not_in.iter().all(|n| match *n {
2243 NodeOrString::Node(ref n) => n != node,
2244 _ => true,
2245 })
2246 })
2247}
2248
2249#[expect(unsafe_code)]
2252pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2253 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2254 DomRoot::from_ref(node)
2255}
2256
2257#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2259pub(crate) enum CloneChildrenFlag {
2260 CloneChildren,
2261 DoNotCloneChildren,
2262}
2263
2264impl From<bool> for CloneChildrenFlag {
2265 fn from(boolean: bool) -> Self {
2266 if boolean {
2267 CloneChildrenFlag::CloneChildren
2268 } else {
2269 CloneChildrenFlag::DoNotCloneChildren
2270 }
2271 }
2272}
2273
2274pub(super) fn as_uintptr<T>(t: &T) -> uintptr_t {
2275 t as *const T as uintptr_t
2276}
2277
2278impl Node {
2279 pub(crate) fn reflect_node<N>(
2280 cx: &mut JSContext,
2281 node: Box<N>,
2282 document: &Document,
2283 ) -> DomRoot<N>
2284 where
2285 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2286 {
2287 Self::reflect_node_with_proto(cx, node, document, None)
2288 }
2289
2290 pub(crate) fn reflect_node_with_proto<N>(
2291 cx: &mut JSContext,
2292 node: Box<N>,
2293 document: &Document,
2294 proto: Option<HandleObject>,
2295 ) -> DomRoot<N>
2296 where
2297 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2298 {
2299 let window = document.window();
2300 reflect_dom_object_with_proto(cx, node, window, proto)
2301 }
2302
2303 pub(crate) fn reflect_weak_referenceable_node_with_proto<N>(
2304 cx: &mut JSContext,
2305 node: Rc<N>,
2306 document: &Document,
2307 proto: Option<HandleObject>,
2308 ) -> DomRoot<N>
2309 where
2310 N: DerivedFrom<Node> + DomObject + WeakReferenceableDomObjectWrap<crate::DomTypeHolder>,
2311 {
2312 let window = document.window();
2313 reflect_weak_referenceable_dom_object_with_proto(cx, node, window, proto)
2314 }
2315
2316 pub(crate) fn new_inherited(doc: &Document) -> Node {
2317 Node::new_(NodeFlags::empty(), Some(doc))
2318 }
2319
2320 pub(crate) fn new_document_node() -> Node {
2321 Node::new_(
2322 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2323 None,
2324 )
2325 }
2326
2327 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2328 Node {
2329 eventtarget: EventTarget::new_inherited(),
2330 parent_node: Default::default(),
2331 first_child: Default::default(),
2332 last_child: Default::default(),
2333 next_sibling: Default::default(),
2334 prev_sibling: Default::default(),
2335 owner_doc: MutNullableDom::new(doc),
2336 rare_data: Default::default(),
2337 children_count: Cell::new(0u32),
2338 flags: Cell::new(flags),
2339 inclusive_descendants_version: Cell::new(0),
2340 layout_data: Default::default(),
2341 }
2342 }
2343
2344 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2346 document.add_script_and_layout_blocker();
2347
2348 let old_doc = node.owner_doc();
2350 old_doc.add_script_and_layout_blocker();
2351
2352 node.remove_self(cx);
2354
2355 if &*old_doc != document {
2359 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2360 descendant.set_owner_doc(document);
2362
2363 if let Some(shadow_root) = descendant.downcast::<ShadowRoot>() {
2374 if shadow_root
2375 .custom_element_registry()
2376 .is_none_or(|registry| {
2377 CustomElementRegistry::is_a_global_element_registry(Some(&*registry))
2378 })
2379 {
2380 shadow_root.set_custom_element_registry(
2381 document
2382 .effective_global_custom_element_registry()
2383 .as_deref(),
2384 );
2385 }
2386 }
2387 else if let Some(element) = descendant.downcast::<Element>() {
2389 for attribute in element.attrs().borrow().iter() {
2392 if let Some(attr) = attribute.as_attr() {
2393 attr.upcast::<Node>().set_owner_doc(document);
2394 }
2395 }
2396
2397 if element
2403 .custom_element_registry()
2404 .is_none_or(|registry| !registry.is_scoped())
2405 {
2406 element.set_custom_element_registry(
2407 document
2408 .effective_global_custom_element_registry()
2409 .as_deref(),
2410 cx.no_gc(),
2411 );
2412 }
2413
2414 if element.is_custom() {
2418 ScriptThread::custom_element_reaction_stack().enqueue_callback_reaction(
2419 cx,
2420 element,
2421 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2422 None,
2423 );
2424 }
2425 }
2426
2427 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2429 }
2430 }
2431
2432 old_doc.remove_script_and_layout_blocker(cx);
2433 document.remove_script_and_layout_blocker(cx);
2434 }
2435
2436 pub(crate) fn ensure_pre_insertion_validity(
2438 no_gc: &NoGC,
2439 node: &Node,
2440 parent: &Node,
2441 child: Option<&Node>,
2442 ) -> ErrorResult {
2443 match parent.type_id() {
2445 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2446 },
2447 _ => {
2448 return Err(Error::HierarchyRequest(Some(
2449 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2450 )));
2451 },
2452 }
2453
2454 if node.is_host_including_inclusive_ancestor(parent) {
2456 return Err(Error::HierarchyRequest(Some(
2457 "Node is a host-including inclusive ancestor of parent".to_owned(),
2458 )));
2459 }
2460
2461 if let Some(child) = child &&
2463 !parent.is_parent_of(child)
2464 {
2465 return Err(Error::NotFound(Some(
2466 "Child is non-null and its parent is not parent".to_owned(),
2467 )));
2468 }
2469
2470 match node.type_id() {
2471 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2475 if parent.is::<Document>() {
2476 return Err(Error::HierarchyRequest(Some(
2477 "Node is a Text node and parent is a document".to_owned(),
2478 )));
2479 }
2480 },
2481 NodeTypeId::DocumentType => {
2482 if !parent.is::<Document>() {
2483 return Err(Error::HierarchyRequest(Some(
2484 "Node is a doctype and parent is not a document".to_owned(),
2485 )));
2486 }
2487 },
2488 NodeTypeId::DocumentFragment(_) |
2489 NodeTypeId::Element(_) |
2490 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2491 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2492 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2495 return Err(Error::HierarchyRequest(Some(
2496 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2497 .to_owned(),
2498 )));
2499 },
2500 }
2501
2502 if parent.is::<Document>() {
2505 match node.type_id() {
2506 NodeTypeId::DocumentFragment(_) => {
2507 if node.children_unrooted(no_gc).any(|c| c.is::<Text>()) {
2509 return Err(Error::HierarchyRequest(Some(
2510 "Parent is a document and node has a Text node child".into(),
2511 )));
2512 }
2513 match node.child_elements_unrooted(no_gc).count() {
2514 0 => (),
2515 1 => {
2518 if parent.child_elements_unrooted(no_gc).next().is_some() {
2519 return Err(Error::HierarchyRequest(Some(
2520 "Node has one element child and parent has an element child"
2521 .into(),
2522 )));
2523 }
2524 if let Some(child) = child &&
2525 child
2526 .inclusively_following_siblings_unrooted(no_gc)
2527 .any(|child| child.is_doctype())
2528 {
2529 return Err(Error::HierarchyRequest(Some(
2530 "Node has one element child and child is a doctype".into(),
2531 )));
2532 }
2533 },
2534 _ => {
2535 return Err(Error::HierarchyRequest(Some(
2536 "Node cannot have more than one child element".into(),
2537 )));
2538 },
2539 }
2540 },
2541 NodeTypeId::Element(_) => {
2542 if parent.child_elements_unrooted(no_gc).next().is_some() {
2544 return Err(Error::HierarchyRequest(Some(
2545 "Parent has an element child".to_owned(),
2546 )));
2547 }
2548 if let Some(child) = child &&
2549 child
2550 .inclusively_following_siblings_unrooted(no_gc)
2551 .any(|following| following.is_doctype())
2552 {
2553 return Err(Error::HierarchyRequest(Some(
2554 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
2555 )));
2556 }
2557 },
2558 NodeTypeId::DocumentType => {
2559 if parent.children_unrooted(no_gc).any(|c| c.is_doctype()) {
2562 return Err(Error::HierarchyRequest(Some(
2563 "Parent cannot have a doctype child".into(),
2564 )));
2565 }
2566 match child {
2567 Some(child) => {
2568 if parent
2569 .children_unrooted(no_gc)
2570 .take_while(|c| **c != child)
2571 .any(|c| c.is::<Element>())
2572 {
2573 return Err(Error::HierarchyRequest(Some(
2574 "Child is non-null and an element is preceding child".into(),
2575 )));
2576 }
2577 },
2578 None => {
2579 if parent.child_elements_unrooted(no_gc).next().is_some() {
2580 return Err(Error::HierarchyRequest(Some(
2581 "Child is null and parent has an element child".into(),
2582 )));
2583 }
2584 },
2585 }
2586 },
2587 NodeTypeId::CharacterData(_) => (),
2588 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
2591 }
2592 }
2593 Ok(())
2594 }
2595
2596 pub(crate) fn pre_insert(
2598 cx: &mut JSContext,
2599 node: &Node,
2600 parent: &Node,
2601 child: Option<&Node>,
2602 ) -> Fallible<DomRoot<Node>> {
2603 Node::ensure_pre_insertion_validity(cx.no_gc(), node, parent, child)?;
2605
2606 let reference_child_root;
2608 let reference_child = match child {
2609 Some(child) if child == node => {
2611 reference_child_root = node.GetNextSibling();
2612 reference_child_root.as_deref()
2613 },
2614 _ => child,
2615 };
2616
2617 Node::insert(
2619 cx,
2620 node,
2621 parent,
2622 reference_child,
2623 SuppressObserver::Unsuppressed,
2624 );
2625
2626 Ok(DomRoot::from_ref(node))
2628 }
2629
2630 pub(crate) fn insert(
2632 cx: &mut JSContext,
2633 node: &Node,
2634 parent: &Node,
2635 child: Option<&Node>,
2636 suppress_observers: SuppressObserver,
2637 ) {
2638 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
2639
2640 rooted_vec!(let mut new_nodes);
2642 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2643 new_nodes.extend(
2644 node.children_unrooted(cx.no_gc())
2645 .map(|node| Dom::from_ref(&**node)),
2646 );
2647 new_nodes.r()
2648 } else {
2649 from_ref(&node)
2650 };
2651
2652 let count = new_nodes.len();
2654
2655 if count == 0 {
2657 return;
2658 }
2659
2660 let parent_document = parent.owner_doc();
2663 let from_document = node.owner_doc();
2664 from_document.add_script_and_layout_blocker();
2665 parent_document.add_script_and_layout_blocker();
2666
2667 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2669 for kid in new_nodes {
2671 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
2672 }
2673 vtable_for(node).children_changed(cx, &ChildrenMutation::ReplaceAll);
2674
2675 let mutation = LazyCell::new(|| Mutation::ChildList {
2677 added: None,
2678 removed: Some(new_nodes),
2679 prev: None,
2680 next: None,
2681 });
2682 MutationObserver::queue_a_mutation_record(cx, node, mutation);
2683 }
2684
2685 if let Some(child) = child {
2687 let count = count.try_into().unwrap();
2689 if let Some(selection) = parent.owner_document().selection() {
2690 selection.insert_steps(parent, child, count);
2691 }
2692 live_range_insert_steps(parent, child, count);
2693 }
2694
2695 let previous_sibling = match suppress_observers {
2697 SuppressObserver::Unsuppressed => match child {
2698 Some(child) => child.GetPreviousSibling(),
2699 None => parent.GetLastChild(),
2700 },
2701 SuppressObserver::Suppressed => None,
2702 };
2703
2704 let mut static_node_list: SmallVec<[_; 4]> = Default::default();
2706
2707 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
2708 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
2709 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
2710
2711 for kid in new_nodes {
2713 Node::adopt(cx, kid, &parent.owner_document());
2715
2716 parent.add_child(cx, kid, child);
2719
2720 if let Some(ref shadow_root) = parent_shadow_root &&
2723 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
2724 (kid.is::<Element>() || kid.is::<Text>())
2725 {
2726 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(kid)));
2727 slottable.assign_a_slot(cx);
2728 }
2729
2730 if parent_in_shadow_tree &&
2733 let Some(slot_element) = parent_as_slot &&
2734 !slot_element.has_assigned_nodes()
2735 {
2736 slot_element.signal_a_slot_change(cx);
2737 }
2738
2739 kid.GetRootNode(&GetRootNodeOptions::empty())
2741 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
2742
2743 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
2746 if let Some(element) = DomRoot::downcast::<Element>(descendant.clone()) &&
2752 !element.is_custom()
2753 {
2754 try_upgrade_element(cx, &element);
2755 }
2756
2757 if !descendant.is_connected() {
2759 continue;
2760 }
2761
2762 if let Some(element) = DomRoot::downcast::<Element>(descendant.clone()) {
2764 if let Some(registry) = element.custom_element_registry() {
2766 if registry.is_scoped() {
2771 registry.add_scoped_document(&element.owner_document());
2772 }
2773 }
2774 if element.is_custom() {
2782 ScriptThread::custom_element_reaction_stack().enqueue_callback_reaction(
2783 cx,
2784 &element,
2785 CallbackReaction::Connected,
2786 None,
2787 );
2788 }
2789 else {
2791 try_upgrade_element(cx, &element);
2792 }
2793 }
2794 else if let Some(shadow_root) =
2801 DomRoot::downcast::<ShadowRoot>(descendant.clone()) &&
2802 let Some(custom_element_registry) = shadow_root.custom_element_registry() &&
2803 custom_element_registry.is_scoped()
2804 {
2805 custom_element_registry.add_scoped_document(shadow_root.owner_doc());
2806 }
2807
2808 static_node_list.push(descendant.clone());
2811 }
2812 }
2813
2814 Self::maybe_dirty_visible_selection_for_newly_inserted_nodes(cx.no_gc(), parent, new_nodes);
2815
2816 if let SuppressObserver::Unsuppressed = suppress_observers {
2817 vtable_for(parent).children_changed(
2820 cx,
2821 &ChildrenMutation::insert(previous_sibling.as_deref(), child),
2822 );
2823
2824 let mutation = LazyCell::new(|| Mutation::ChildList {
2827 added: Some(new_nodes),
2828 removed: None,
2829 prev: previous_sibling.as_deref(),
2830 next: child,
2831 });
2832 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2833 }
2834
2835 parent_document.add_delayed_task(
2846 task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
2847 for node in static_node_list {
2852 vtable_for(&node).post_connection_steps(cx);
2853 }
2854 }),
2855 );
2856
2857 parent_document.remove_script_and_layout_blocker(cx);
2858 from_document.remove_script_and_layout_blocker(cx);
2859 }
2860
2861 pub(crate) fn maybe_dirty_visible_selection_for_newly_inserted_nodes(
2864 no_gc: &NoGC,
2865 parent: &Node,
2866 inserted_nodes: &[&Node],
2867 ) {
2868 let Some(selection) = parent.owner_document().selection() else {
2869 return;
2870 };
2871
2872 for node in inserted_nodes {
2873 match node.parent_in_flat_tree(no_gc) {
2874 FlatTreeParent::RootNode | FlatTreeParent::NotInFlatTree => {},
2875 FlatTreeParent::Parent(parent) => {
2876 if parent.get_flag(NodeFlags::OVERLAPS_DOCUMENT_SELECTION) {
2877 selection.set_visible_selection_dirty();
2878 return;
2879 }
2880 },
2881 }
2882 }
2883 }
2884
2885 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
2887 parent.owner_doc().add_script_and_layout_blocker();
2888
2889 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
2891
2892 rooted_vec!(let mut added_nodes);
2896 let added_nodes = if let Some(node) = node.as_ref() {
2897 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2898 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
2899 added_nodes.r()
2900 } else {
2901 from_ref(node)
2902 }
2903 } else {
2904 &[] as &[&Node]
2905 };
2906
2907 for child in &*removed_nodes {
2909 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
2910 }
2911
2912 if let Some(node) = node {
2914 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
2915 }
2916
2917 vtable_for(parent).children_changed(cx, &ChildrenMutation::ReplaceAll);
2918
2919 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
2922 let mutation = LazyCell::new(|| Mutation::ChildList {
2923 added: Some(added_nodes),
2924 removed: Some(removed_nodes.r()),
2925 prev: None,
2926 next: None,
2927 });
2928 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2929 }
2930 parent.owner_doc().remove_script_and_layout_blocker(cx);
2931 }
2932
2933 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
2935 if string.is_empty() {
2936 Node::replace_all(cx, None, parent);
2937 } else {
2938 let text = Text::new(cx, string, &parent.owner_document());
2939 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
2940 };
2941 }
2942
2943 pub(super) fn pre_remove(
2945 cx: &mut JSContext,
2946 child: &Node,
2947 parent: &Node,
2948 ) -> Fallible<DomRoot<Node>> {
2949 match child.GetParentNode() {
2951 Some(ref node) if &**node != parent => {
2952 return Err(Error::NotFound(Some(
2953 "Child's parent does not match the parent node provided".into(),
2954 )));
2955 },
2956 None => {
2957 return Err(Error::NotFound(Some(
2958 "Child does not have a parent node".into(),
2959 )));
2960 },
2961 _ => (),
2962 }
2963
2964 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
2966
2967 Ok(DomRoot::from_ref(child))
2969 }
2970
2971 pub(super) fn remove(
2973 cx: &mut JSContext,
2974 node: &Node,
2975 parent: &Node,
2976 suppress_observers: SuppressObserver,
2977 ) {
2978 parent.owner_doc().add_script_and_layout_blocker();
2979
2980 assert!(
2984 node.GetParentNode()
2985 .is_some_and(|node_parent| &*node_parent == parent)
2986 );
2987
2988 let mut cached_index = None;
2990 {
2991 let mut lazy_index = || *cached_index.get_or_insert_with(|| node.index());
2992 if let Some(selection) = node.owner_document().selection() {
2993 selection.remove_steps_for_parent(parent, &mut lazy_index);
2994 }
2995 live_range_pre_remove_steps_for_parent(parent, &mut lazy_index);
2996 }
2997
2998 let old_previous_sibling = node.GetPreviousSibling();
3002
3003 let old_next_sibling = node.GetNextSibling();
3005
3006 parent.remove_child(cx, node, cached_index);
3009
3010 if let Some(slot) = node.assigned_slot() {
3012 slot.assign_slottables(cx);
3013 }
3014
3015 if parent.is_in_a_shadow_tree() &&
3018 let Some(slot_element) = parent.downcast::<HTMLSlotElement>() &&
3019 !slot_element.has_assigned_nodes()
3020 {
3021 slot_element.signal_a_slot_change(cx);
3022 }
3023
3024 let has_slot_descendant = node
3026 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
3027 .any(|elem| elem.is::<HTMLSlotElement>());
3028 if has_slot_descendant {
3029 parent
3031 .GetRootNode(&GetRootNodeOptions::empty())
3032 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
3033
3034 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Force);
3036 }
3037
3038 if let SuppressObserver::Unsuppressed = suppress_observers {
3042 vtable_for(parent).children_changed(
3043 cx,
3044 &ChildrenMutation::replace(
3045 old_previous_sibling.as_deref(),
3046 &Some(node),
3047 old_next_sibling.as_deref(),
3048 ),
3049 );
3050
3051 let removed = [node];
3052 let mutation = LazyCell::new(|| Mutation::ChildList {
3053 added: None,
3054 removed: Some(&removed),
3055 prev: old_previous_sibling.as_deref(),
3056 next: old_next_sibling.as_deref(),
3057 });
3058 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
3059 }
3060 parent.owner_doc().remove_script_and_layout_blocker(cx);
3061 }
3062
3063 pub(crate) fn clone(
3065 cx: &mut JSContext,
3066 node: &Node,
3067 maybe_doc: Option<&Document>,
3068 clone_children: CloneChildrenFlag,
3069 registry: Option<DomRoot<CustomElementRegistry>>,
3070 ) -> DomRoot<Node> {
3071 let document = match maybe_doc {
3073 Some(doc) => DomRoot::from_ref(doc),
3074 None => node.owner_doc(),
3075 };
3076
3077 let copy: DomRoot<Node> = match node.type_id() {
3080 NodeTypeId::DocumentType => {
3081 let doctype = node.downcast::<DocumentType>().unwrap();
3082 let doctype = DocumentType::new(
3083 cx,
3084 doctype.name().clone(),
3085 Some(doctype.public_id().clone()),
3086 Some(doctype.system_id().clone()),
3087 &document,
3088 );
3089 DomRoot::upcast::<Node>(doctype)
3090 },
3091 NodeTypeId::Attr => {
3092 let attr = node.downcast::<Attr>().unwrap();
3093 let attr = Attr::new(
3094 cx,
3095 &document,
3096 attr.local_name().clone(),
3097 attr.value().clone(),
3098 attr.name().clone(),
3099 attr.namespace().clone(),
3100 attr.prefix().cloned(),
3101 None,
3102 );
3103 DomRoot::upcast::<Node>(attr)
3104 },
3105 NodeTypeId::DocumentFragment(_) => {
3106 let doc_fragment = DocumentFragment::new(cx, &document);
3107 DomRoot::upcast::<Node>(doc_fragment)
3108 },
3109 NodeTypeId::CharacterData(_) => {
3110 let cdata = node.downcast::<CharacterData>().unwrap();
3111 cdata.clone_with_data(cx, cdata.Data(), &document)
3112 },
3113 NodeTypeId::Document(_) => {
3114 let document = node.downcast::<Document>().unwrap();
3117 let is_html_doc = if document.is_html_document() {
3118 IsHTMLDocument::HTMLDocument
3119 } else {
3120 IsHTMLDocument::NonHTMLDocument
3121 };
3122 let window = document.window();
3123 let loader = DocumentLoader::new(&document.loader());
3124 let document = Document::new(
3125 cx,
3126 window,
3127 HasBrowsingContext::No,
3128 Some(document.url()),
3129 None,
3130 document.origin().clone(),
3132 is_html_doc,
3133 None,
3134 None,
3135 DocumentActivity::Inactive,
3136 loader,
3137 None,
3138 document.status_code(),
3139 Default::default(),
3140 false,
3141 document.allow_declarative_shadow_roots(),
3142 Some(document.insecure_requests_policy()),
3143 document.has_trustworthy_ancestor_or_current_origin(),
3144 document.custom_element_reaction_stack(),
3145 document.creation_sandboxing_flag_set(),
3146 document.pipeline_id(),
3147 document.image_cache(),
3148 );
3149 DomRoot::upcast::<Node>(document)
3153 },
3154 NodeTypeId::Element(..) => {
3156 let element = node.downcast::<Element>().unwrap();
3157 let registry = element.custom_element_registry().or(registry);
3160 let registry =
3163 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3164 document.effective_global_custom_element_registry()
3165 } else {
3166 registry
3167 };
3168 let name = QualName {
3172 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3173 ns: element.namespace().clone(),
3174 local: element.local_name().clone(),
3175 };
3176 let element = Element::create(
3177 cx,
3178 name,
3179 element.get_is(),
3180 &document,
3181 ElementCreator::ScriptCreated,
3182 CustomElementCreationMode::Asynchronous,
3183 None,
3184 );
3185 element.set_custom_element_registry(registry.as_deref(), cx.no_gc());
3187 DomRoot::upcast::<Node>(element)
3188 },
3189 };
3190
3191 let document = match copy.downcast::<Document>() {
3194 Some(doc) => DomRoot::from_ref(doc),
3195 None => DomRoot::from_ref(&*document),
3196 };
3197 assert!(copy.owner_doc() == document);
3198
3199 match node.type_id() {
3201 NodeTypeId::Document(_) => {
3202 let node_doc = node.downcast::<Document>().unwrap();
3203 let copy_doc = copy.downcast::<Document>().unwrap();
3204 copy_doc.set_encoding(node_doc.encoding());
3205 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3206 },
3207 NodeTypeId::Element(..) => {
3208 let node_elem = node.downcast::<Element>().unwrap();
3209 let copy_elem = copy.downcast::<Element>().unwrap();
3210
3211 node_elem.copy_all_attributes_to_other_element(cx, copy_elem);
3213 },
3214 _ => (),
3215 }
3216
3217 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3220
3221 if clone_children == CloneChildrenFlag::CloneChildren {
3224 for child in node.children() {
3225 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3226 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3227 }
3228 }
3229
3230 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3233 let node_elem = node.downcast::<Element>().unwrap();
3234 let copy_elem = copy.downcast::<Element>().unwrap();
3235
3236 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3237 assert!(!copy_elem.is_shadow_host());
3239
3240 let copy_shadow_root =
3244 copy_elem.attach_shadow(
3245 cx,
3246 IsUserAgentWidget::No,
3247 shadow_root.Mode(),
3248 shadow_root.Clonable(),
3249 shadow_root.Serializable(),
3250 shadow_root.DelegatesFocus(),
3251 shadow_root.SlotAssignment(),
3252 )
3253 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3254
3255 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3257
3258 for child in shadow_root.upcast::<Node>().children() {
3261 let child_copy = Node::clone(
3262 cx,
3263 &child,
3264 Some(&document),
3265 CloneChildrenFlag::CloneChildren,
3266 None,
3267 );
3268
3269 let _inserted_node =
3271 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3272 }
3273 }
3274 }
3275
3276 copy
3278 }
3279
3280 pub(crate) fn child_text_content(&self) -> DOMString {
3282 Node::collect_text_contents(self.children())
3283 }
3284
3285 pub(crate) fn descendant_text_content(&self) -> DOMString {
3287 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3288 }
3289
3290 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3291 iterator: T,
3292 ) -> DOMString {
3293 let mut content = String::new();
3294 for node in iterator {
3295 if let Some(text) = node.downcast::<Text>() {
3296 content.push_str(&text.upcast::<CharacterData>().data());
3297 }
3298 }
3299 DOMString::from(content)
3300 }
3301
3302 pub(crate) fn set_text_content_for_element(
3304 &self,
3305 cx: &mut JSContext,
3306 value: Option<DOMString>,
3307 ) {
3308 assert!(matches!(
3311 self.type_id(),
3312 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3313 ));
3314 let value = value.unwrap_or_default();
3315 let node = if value.is_empty() {
3316 None
3318 } else {
3319 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3322 };
3323
3324 Self::replace_all(cx, node.as_deref(), self);
3326 }
3327
3328 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3329 match namespace {
3330 ns!() => None,
3331 _ => Some(DOMString::from(&*namespace)),
3333 }
3334 }
3335
3336 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3338 match node.type_id() {
3339 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3340 NodeTypeId::Attr => node
3341 .downcast::<Attr>()
3342 .unwrap()
3343 .GetOwnerElement()
3344 .as_ref()
3345 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3346 NodeTypeId::Document(_) => node
3347 .downcast::<Document>()
3348 .unwrap()
3349 .GetDocumentElement()
3350 .as_ref()
3351 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3352 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3353 _ => node
3354 .GetParentElement()
3355 .as_ref()
3356 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3357 }
3358 }
3359
3360 #[expect(unsafe_code)]
3368 pub(crate) unsafe fn from_untrusted_node_address(
3369 candidate: UntrustedNodeAddress,
3370 ) -> &'static Self {
3371 let candidate = candidate.0 as usize;
3373 let object = candidate as *mut JSObject;
3374 if object.is_null() {
3375 panic!("Attempted to create a `Node` from an invalid pointer!")
3376 }
3377
3378 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3379 }
3380
3381 pub(crate) fn html_serialize(
3382 &self,
3383 cx: &mut JSContext,
3384 traversal_scope: html_serialize::TraversalScope,
3385 serialize_shadow_roots: bool,
3386 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3387 ) -> DOMString {
3388 let mut writer = vec![];
3389 let mut serializer = HtmlSerializer::new(
3390 &mut writer,
3391 html_serialize::SerializeOpts {
3392 traversal_scope: traversal_scope.clone(),
3393 ..Default::default()
3394 },
3395 );
3396
3397 serialize_html_fragment(
3398 cx,
3399 self,
3400 &mut serializer,
3401 traversal_scope,
3402 serialize_shadow_roots,
3403 shadow_roots,
3404 )
3405 .expect("Serializing node failed");
3406
3407 DOMString::from(String::from_utf8(writer).unwrap())
3409 }
3410
3411 pub(crate) fn xml_serialize(
3413 &self,
3414 traversal_scope: xml_serialize::TraversalScope,
3415 ) -> Fallible<DOMString> {
3416 let mut writer = vec![];
3417 xml_serialize::serialize(
3418 &mut writer,
3419 &HtmlSerialize::new(self),
3420 xml_serialize::SerializeOpts { traversal_scope },
3421 )
3422 .map_err(|error| {
3423 error!("Cannot serialize node: {error}");
3424 Error::InvalidState(Some("Cannot serialize node".into()))
3425 })?;
3426
3427 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3429 error!("Cannot serialize node: {error}");
3430 Error::InvalidState(Some("Cannot serialize node".into()))
3431 })?);
3432
3433 Ok(string)
3434 }
3435
3436 pub(crate) fn fragment_serialization_algorithm(
3438 &self,
3439 cx: &mut JSContext,
3440 require_well_formed: bool,
3441 ) -> Fallible<DOMString> {
3442 let context_document = self.owner_document();
3444
3445 if context_document.is_html_document() {
3448 return Ok(self.html_serialize(
3449 cx,
3450 html_serialize::TraversalScope::ChildrenOnly(None),
3451 false,
3452 vec![],
3453 ));
3454 }
3455
3456 let _ = require_well_formed;
3459 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3460 }
3461
3462 pub(crate) fn get_next_sibling_unrooted<'a>(
3463 &self,
3464 no_gc: &'a NoGC,
3465 ) -> Option<UnrootedDom<'a, Node>> {
3466 self.next_sibling.get_unrooted(no_gc)
3467 }
3468
3469 pub(crate) fn next_flat_tree_sibling_unrooted<'a>(
3470 &self,
3471 no_gc: &'a NoGC,
3472 ) -> Option<UnrootedDom<'a, Node>> {
3473 if let Some(slot_element) = self.assigned_slot() {
3474 return slot_element
3478 .assigned_nodes()
3479 .iter()
3480 .skip_while(|slottable| &*slottable.0 != self)
3481 .nth(1)
3483 .map(|next_slottable| UnrootedDom::from_dom(next_slottable.0.clone(), no_gc));
3484 }
3485 self.get_next_sibling_unrooted(no_gc)
3486 }
3487
3488 pub(crate) fn get_previous_sibling_unrooted<'a>(
3489 &self,
3490 no_gc: &'a NoGC,
3491 ) -> Option<UnrootedDom<'a, Node>> {
3492 self.prev_sibling.get_unrooted(no_gc)
3493 }
3494
3495 pub(crate) fn get_first_child_unrooted<'a>(
3496 &self,
3497 no_gc: &'a NoGC,
3498 ) -> Option<UnrootedDom<'a, Node>> {
3499 self.first_child.get_unrooted(no_gc)
3500 }
3501
3502 pub(crate) fn first_flat_tree_child_unrooted<'a>(
3503 &self,
3504 no_gc: &'a NoGC,
3505 ) -> Option<UnrootedDom<'a, Node>> {
3506 let Some(element) = self.downcast::<Element>() else {
3507 return self.get_first_child_unrooted(no_gc);
3508 };
3509 if let Some(shadow_root) = element.shadow_root_unrooted(no_gc) {
3510 return shadow_root
3511 .upcast::<Node>()
3512 .first_flat_tree_child_unrooted(no_gc);
3513 };
3514
3515 if let Some(slot_element) = element.downcast::<HTMLSlotElement>() &&
3519 slot_element.has_assigned_nodes() &&
3520 let Some(assigned_node) = slot_element.assigned_nodes().first()
3521 {
3522 return Some(UnrootedDom::from_dom(assigned_node.0.clone(), no_gc));
3523 }
3524
3525 self.get_first_child_unrooted(no_gc)
3526 }
3527
3528 fn get_last_child_unrooted<'b>(&self, no_gc: &'b NoGC) -> Option<UnrootedDom<'b, Node>> {
3529 self.last_child.get_unrooted(no_gc)
3530 }
3531
3532 pub(crate) fn get_parent_node_unrooted<'a>(
3533 &self,
3534 no_gc: &'a NoGC,
3535 ) -> Option<UnrootedDom<'a, Node>> {
3536 self.parent_node.get_unrooted(no_gc)
3537 }
3538
3539 pub(crate) fn compare_dom_tree_position(
3541 &self,
3542 other: &Node,
3543 common_ancestor: &Node,
3544 shadow_including: ShadowIncluding,
3545 ) -> Ordering {
3546 debug_assert!(
3547 self.inclusive_ancestors(shadow_including)
3548 .any(|ancestor| &*ancestor == common_ancestor)
3549 );
3550 debug_assert!(
3551 other
3552 .inclusive_ancestors(shadow_including)
3553 .any(|ancestor| &*ancestor == common_ancestor)
3554 );
3555
3556 if self == other {
3557 return Ordering::Equal;
3558 }
3559
3560 if self == common_ancestor {
3561 return Ordering::Less;
3562 }
3563 if other == common_ancestor {
3564 return Ordering::Greater;
3565 }
3566
3567 let my_ancestors: Vec<_> = self
3568 .inclusive_ancestors(shadow_including)
3569 .take_while(|ancestor| &**ancestor != common_ancestor)
3570 .collect();
3571 let other_ancestors: Vec<_> = other
3572 .inclusive_ancestors(shadow_including)
3573 .take_while(|ancestor| &**ancestor != common_ancestor)
3574 .collect();
3575
3576 let mut i = my_ancestors.len() - 1;
3578 let mut j = other_ancestors.len() - 1;
3579
3580 while my_ancestors[i] == other_ancestors[j] {
3581 if i == 0 {
3582 debug_assert_ne!(j, 0, "Equal inclusive ancestors but nodes are not equal?");
3584 return Ordering::Less;
3585 }
3586 if j == 0 {
3587 return Ordering::Greater;
3589 }
3590
3591 i -= 1;
3592 j -= 1;
3593 }
3594
3595 if my_ancestors[i]
3598 .preceding_siblings()
3599 .any(|sibling| sibling == other_ancestors[j])
3600 {
3601 Ordering::Greater
3603 } else {
3604 debug_assert!(
3606 other_ancestors[j]
3607 .preceding_siblings()
3608 .any(|sibling| sibling == my_ancestors[i])
3609 );
3610 Ordering::Less
3611 }
3612 }
3613}
3614
3615impl NodeMethods<crate::DomTypeHolder> for Node {
3616 fn NodeType(&self) -> u16 {
3618 match self.type_id() {
3619 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3620 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3621 NodeConstants::TEXT_NODE
3622 },
3623 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3624 NodeConstants::CDATA_SECTION_NODE
3625 },
3626 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3627 NodeConstants::PROCESSING_INSTRUCTION_NODE
3628 },
3629 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3630 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3631 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3632 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3633 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3634 }
3635 }
3636
3637 fn NodeName(&self) -> DOMString {
3639 match self.type_id() {
3640 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3641 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3642 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3643 DOMString::from_static("#text")
3644 },
3645 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3646 DOMString::from_static("#cdata-section")
3647 },
3648 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3649 self.downcast::<ProcessingInstruction>().unwrap().Target()
3650 },
3651 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => {
3652 DOMString::from_static("#comment")
3653 },
3654 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3655 NodeTypeId::DocumentFragment(_) => DOMString::from_static("#document-fragment"),
3656 NodeTypeId::Document(_) => DOMString::from_static("#document"),
3657 }
3658 }
3659
3660 fn BaseURI(&self) -> USVString {
3662 USVString(String::from(self.owner_doc().base_url().as_str()))
3663 }
3664
3665 fn IsConnected(&self) -> bool {
3667 self.is_connected()
3668 }
3669
3670 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3672 match self.type_id() {
3673 NodeTypeId::Document(_) => None,
3674 _ => Some(self.owner_doc()),
3675 }
3676 }
3677
3678 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3680 if !options.composed &&
3681 let Some(shadow_root) = self.containing_shadow_root()
3682 {
3683 return DomRoot::upcast(shadow_root);
3684 }
3685
3686 if self.is_connected() {
3687 DomRoot::from_ref(self.owner_doc().upcast::<Node>())
3688 } else {
3689 self.inclusive_ancestors(ShadowIncluding::Yes)
3690 .last()
3691 .unwrap()
3692 }
3693 }
3694
3695 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
3697 self.parent_node().get()
3698 }
3699
3700 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
3702 self.GetParentNode().and_then(DomRoot::downcast)
3703 }
3704
3705 fn HasChildNodes(&self) -> bool {
3707 self.first_child().get().is_some()
3708 }
3709
3710 fn ChildNodes(&self, cx: &mut JSContext) -> DomRoot<NodeList> {
3712 if let Some(list) = self.ensure_rare_data().child_list.get() {
3713 return list;
3714 }
3715
3716 let doc = self.owner_doc();
3717 let window = doc.window();
3718 let list = NodeList::new_child_list(cx, window, self);
3719 self.ensure_rare_data().child_list.set(Some(&list));
3720 list
3721 }
3722
3723 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
3725 self.first_child().get()
3726 }
3727
3728 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
3730 self.last_child().get()
3731 }
3732
3733 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
3735 self.prev_sibling().get()
3736 }
3737
3738 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
3740 self.next_sibling().get()
3741 }
3742
3743 fn GetNodeValue(&self) -> Option<DOMString> {
3745 match self.type_id() {
3746 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3747 NodeTypeId::CharacterData(_) => {
3748 self.downcast::<CharacterData>().map(CharacterData::Data)
3749 },
3750 _ => None,
3751 }
3752 }
3753
3754 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
3756 match self.type_id() {
3757 NodeTypeId::Attr => {
3758 let attr = self.downcast::<Attr>().unwrap();
3759 attr.SetValue(cx, val.unwrap_or_default())?;
3760 },
3761 NodeTypeId::CharacterData(_) => {
3762 let character_data = self.downcast::<CharacterData>().unwrap();
3763 character_data.SetData(cx, val.unwrap_or_default());
3764 },
3765 _ => {},
3766 };
3767 Ok(())
3768 }
3769
3770 fn GetTextContent(&self) -> Option<DOMString> {
3772 match self.type_id() {
3773 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3774 let content =
3775 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
3776 Some(content)
3777 },
3778 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3779 NodeTypeId::CharacterData(..) => {
3780 let characterdata = self.downcast::<CharacterData>().unwrap();
3781 Some(characterdata.Data())
3782 },
3783 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
3784 }
3785 }
3786
3787 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
3789 match self.type_id() {
3790 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3791 self.set_text_content_for_element(cx, value);
3792 },
3793 NodeTypeId::Attr => {
3794 let attr = self.downcast::<Attr>().unwrap();
3795 attr.SetValue(cx, value.unwrap_or_default())?;
3796 },
3797 NodeTypeId::CharacterData(..) => {
3798 let characterdata = self.downcast::<CharacterData>().unwrap();
3799 characterdata.SetData(cx, value.unwrap_or_default());
3800 },
3801 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
3802 };
3803 Ok(())
3804 }
3805
3806 fn InsertBefore(
3808 &self,
3809 cx: &mut JSContext,
3810 node: &Node,
3811 child: Option<&Node>,
3812 ) -> Fallible<DomRoot<Node>> {
3813 Node::pre_insert(cx, node, self, child)
3814 }
3815
3816 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3818 Node::pre_insert(cx, node, self, None)
3819 }
3820
3821 fn ReplaceChild(
3823 &self,
3824 cx: &mut JSContext,
3825 node: &Node,
3826 child: &Node,
3827 ) -> Fallible<DomRoot<Node>> {
3828 match self.type_id() {
3831 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3832 },
3833 _ => {
3834 return Err(Error::HierarchyRequest(Some(
3835 "Parent is not a Document, DocumentFragment, or Element node".into(),
3836 )));
3837 },
3838 }
3839
3840 if node.is_inclusive_ancestor_of(self) {
3843 return Err(Error::HierarchyRequest(Some(
3844 "Node cannot be a host-including ancestor of parent".into(),
3845 )));
3846 }
3847
3848 if !self.is_parent_of(child) {
3850 return Err(Error::NotFound(Some(
3851 "Parent node provided does not match child's parent node".into(),
3852 )));
3853 }
3854
3855 match node.type_id() {
3860 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
3861 return Err(Error::HierarchyRequest(Some(
3862 "Node cannot be a Text node while parent is a document".into(),
3863 )));
3864 },
3865 NodeTypeId::DocumentType if !self.is::<Document>() => {
3866 return Err(Error::HierarchyRequest(Some(
3867 "Node cannot be a doctype when parent is not a document".into(),
3868 )));
3869 },
3870 NodeTypeId::Document(_) | NodeTypeId::Attr => {
3871 return Err(Error::HierarchyRequest(Some(
3872 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
3873 .into(),
3874 )));
3875 },
3876 _ => (),
3877 }
3878
3879 if self.is::<Document>() {
3882 match node.type_id() {
3883 NodeTypeId::DocumentFragment(_) => {
3885 if node.children_unrooted(cx.no_gc()).any(|c| c.is::<Text>()) {
3887 return Err(Error::HierarchyRequest(Some(
3888 "Parent is a document and node has a Text node child".into(),
3889 )));
3890 }
3891 match node.child_elements_unrooted(cx.no_gc()).count() {
3892 0 => (),
3893 1 => {
3895 if self
3896 .child_elements_unrooted(cx.no_gc())
3897 .any(|c| c.upcast::<Node>() != child)
3898 {
3899 return Err(Error::HierarchyRequest(Some(
3900 "Node has one element child and parent's children elements does not include child provided"
3901 .into(),
3902 )));
3903 }
3904 if child.following_siblings().any(|child| child.is_doctype()) {
3905 return Err(Error::HierarchyRequest(Some(
3906 "Node cannot have element child of type document".into(),
3907 )));
3908 }
3909 },
3910 _ => {
3912 return Err(Error::HierarchyRequest(Some(
3913 "Node cannot have more than one child element".into(),
3914 )));
3915 },
3916 }
3917 },
3918 NodeTypeId::Element(..) => {
3920 if self
3921 .child_elements_unrooted(cx.no_gc())
3922 .any(|c| c.upcast::<Node>() != child)
3923 {
3924 return Err(Error::HierarchyRequest(Some(
3925 "Parent's children elements does not include child provided".into(),
3926 )));
3927 }
3928 if child.following_siblings().any(|child| child.is_doctype()) {
3929 return Err(Error::HierarchyRequest(Some(
3930 "Node cannot have element child of type document".into(),
3931 )));
3932 }
3933 },
3934 NodeTypeId::DocumentType => {
3936 if self
3937 .children_unrooted(cx.no_gc())
3938 .any(|c| c.is_doctype() && *c != child)
3939 {
3940 return Err(Error::HierarchyRequest(Some(
3941 "Parent cannot have a doctype child".into(),
3942 )));
3943 }
3944 if self
3945 .children_unrooted(cx.no_gc())
3946 .take_while(|c| **c != child)
3947 .any(|c| c.is::<Element>())
3948 {
3949 return Err(Error::HierarchyRequest(Some(
3950 "An element cannot precede the child given".into(),
3951 )));
3952 }
3953 },
3954 NodeTypeId::CharacterData(..) => (),
3955 NodeTypeId::Document(_) => unreachable!(),
3958 NodeTypeId::Attr => unreachable!(),
3959 }
3960 }
3961
3962 let child_next_sibling = child.GetNextSibling();
3965 let node_next_sibling = node.GetNextSibling();
3966 let reference_child = if child_next_sibling.as_deref() == Some(node) {
3967 node_next_sibling.as_deref()
3968 } else {
3969 child_next_sibling.as_deref()
3970 };
3971
3972 let previous_sibling = child.GetPreviousSibling();
3974
3975 let document = self.owner_document();
3979 Node::adopt(cx, node, &document);
3980
3981 let removed_child = if node != child {
3986 Node::remove(cx, child, self, SuppressObserver::Suppressed);
3988 Some(child)
3989 } else {
3990 None
3991 };
3992
3993 rooted_vec!(let mut nodes);
3995 let nodes = if node.type_id() ==
3996 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
3997 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
3998 {
3999 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
4000 nodes.r()
4001 } else {
4002 from_ref(&node)
4003 };
4004
4005 Node::insert(
4007 cx,
4008 node,
4009 self,
4010 reference_child,
4011 SuppressObserver::Suppressed,
4012 );
4013
4014 vtable_for(self).children_changed(
4015 cx,
4016 &ChildrenMutation::replace(
4017 previous_sibling.as_deref(),
4018 &removed_child,
4019 reference_child,
4020 ),
4021 );
4022
4023 let removed = removed_child.map(|r| [r]);
4026 let mutation = LazyCell::new(|| Mutation::ChildList {
4027 added: Some(nodes),
4028 removed: removed.as_ref().map(|r| &r[..]),
4029 prev: previous_sibling.as_deref(),
4030 next: reference_child,
4031 });
4032
4033 MutationObserver::queue_a_mutation_record(cx, self, mutation);
4034
4035 Ok(DomRoot::from_ref(child))
4037 }
4038
4039 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
4041 Node::pre_remove(cx, node, self)
4042 }
4043
4044 fn Normalize(&self, cx: &mut JSContext) {
4046 let mut children = self.children().peekable();
4047 let selection = self.owner_document().selection();
4048 while let Some(node) = children.next() {
4049 let Some(text) = node.downcast::<Text>() else {
4052 node.Normalize(cx);
4053 continue;
4054 };
4055 if text.is::<CDATASection>() {
4056 continue;
4057 }
4058
4059 let cdata = text.upcast::<CharacterData>();
4061 let mut length = cdata.Length();
4062
4063 if length == 0 {
4066 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
4067 continue;
4068 }
4069
4070 let mut siblings_to_merge: SmallVec<[DomRoot<CharacterData>; 4]> = SmallVec::new();
4073 let mut new_data_length = 0;
4074 while let Some(sibling) = children.peek() {
4075 if !sibling.is::<Text>() || sibling.is::<CDATASection>() {
4076 break;
4077 }
4078
4079 let sibling: DomRoot<CharacterData> =
4080 DomRoot::downcast(children.next().expect("Guaranteed by the peek above"))
4081 .expect("Guaranteed by check above");
4082 new_data_length += sibling.data().len();
4083 siblings_to_merge.push(sibling);
4084 }
4085
4086 if siblings_to_merge.is_empty() {
4087 continue;
4088 }
4089
4090 let mut data = String::with_capacity(new_data_length);
4093 for sibling in &siblings_to_merge {
4094 data.push_str(sibling.data().as_str());
4095 }
4096
4097 cdata.append_data(cx, &data);
4099
4100 let first_sibling_index = LazyCell::new(|| node.index() + 1);
4104 for (current_node_index, current_node) in siblings_to_merge.iter().enumerate() {
4105 let index = &|| *first_sibling_index + current_node_index as u32;
4106 if let Some(selection) = &selection {
4108 selection.normalization_steps(
4109 self,
4110 &node,
4111 current_node.upcast(),
4112 &index,
4113 length,
4114 );
4115 }
4116 live_range_normalization_steps(self, &node, current_node.upcast(), &index, length);
4117 length += current_node.Length();
4119 }
4122
4123 for current_node in siblings_to_merge.into_iter() {
4126 Node::remove(
4127 cx,
4128 current_node.upcast(),
4129 self,
4130 SuppressObserver::Unsuppressed,
4131 );
4132 }
4133 }
4134 }
4135
4136 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
4138 if self.is::<ShadowRoot>() {
4140 return Err(Error::NotSupported(Some(
4141 "Cannot clone a shadow root".into(),
4142 )));
4143 }
4144
4145 let result = Node::clone(
4147 cx,
4148 self,
4149 None,
4150 if subtree {
4151 CloneChildrenFlag::CloneChildren
4152 } else {
4153 CloneChildrenFlag::DoNotCloneChildren
4154 },
4155 None,
4156 );
4157 Ok(result)
4158 }
4159
4160 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
4162 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
4163 let doctype = node.downcast::<DocumentType>().unwrap();
4164 let other_doctype = other.downcast::<DocumentType>().unwrap();
4165 (*doctype.name() == *other_doctype.name()) &&
4166 (*doctype.public_id() == *other_doctype.public_id()) &&
4167 (*doctype.system_id() == *other_doctype.system_id())
4168 }
4169 fn is_equal_element(node: &Node, other: &Node) -> bool {
4170 let element = node.downcast::<Element>().unwrap();
4171 let other_element = other.downcast::<Element>().unwrap();
4172 (*element.namespace() == *other_element.namespace()) &&
4173 (*element.prefix() == *other_element.prefix()) &&
4174 (*element.local_name() == *other_element.local_name()) &&
4175 (element.attrs().borrow().len() == other_element.attrs().borrow().len())
4176 }
4177 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
4178 let pi = node.downcast::<ProcessingInstruction>().unwrap();
4179 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
4180 (*pi.target() == *other_pi.target()) &&
4181 (*pi.upcast::<CharacterData>().data() ==
4182 *other_pi.upcast::<CharacterData>().data())
4183 }
4184 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
4185 let characterdata = node.downcast::<CharacterData>().unwrap();
4186 let other_characterdata = other.downcast::<CharacterData>().unwrap();
4187 *characterdata.data() == *other_characterdata.data()
4188 }
4189 fn is_equal_attr(node: &Node, other: &Node) -> bool {
4190 let attr = node.downcast::<Attr>().unwrap();
4191 let other_attr = other.downcast::<Attr>().unwrap();
4192 (*attr.namespace() == *other_attr.namespace()) &&
4193 (attr.local_name() == other_attr.local_name()) &&
4194 (**attr.value() == **other_attr.value())
4195 }
4196 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
4197 let element = node.downcast::<Element>().unwrap();
4198 let other_element = other.downcast::<Element>().unwrap();
4199 assert!(element.attrs().borrow().len() == other_element.attrs().borrow().len());
4200 element.attrs().borrow().iter().all(|attr| {
4201 other_element.attrs().borrow().iter().any(|other_attr| {
4202 (*attr.namespace() == *other_attr.namespace()) &&
4203 (attr.local_name() == other_attr.local_name()) &&
4204 (**attr.value() == **other_attr.value())
4205 })
4206 })
4207 }
4208
4209 fn is_equal_node(this: &Node, node: &Node) -> bool {
4210 if this.NodeType() != node.NodeType() {
4212 return false;
4213 }
4214
4215 match node.type_id() {
4216 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
4218 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
4219 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
4220 if !is_equal_processinginstruction(this, node) =>
4221 {
4222 return false;
4223 },
4224 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
4225 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
4226 if !is_equal_characterdata(this, node) =>
4227 {
4228 return false;
4229 },
4230 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
4232 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
4233
4234 _ => (),
4235 }
4236
4237 if this.children_count() != node.children_count() {
4239 return false;
4240 }
4241
4242 this.children()
4244 .zip(node.children())
4245 .all(|(child, other_child)| is_equal_node(&child, &other_child))
4246 }
4247 match maybe_node {
4248 None => false,
4250 Some(node) => is_equal_node(self, node),
4252 }
4253 }
4254
4255 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
4257 match other_node {
4258 Some(node) => self == node,
4259 None => false,
4260 }
4261 }
4262
4263 fn CompareDocumentPosition(&self, other: &Node) -> u16 {
4265 if self == other {
4267 return 0;
4268 }
4269
4270 let mut node1 = Some(other);
4272 let mut node2 = Some(self);
4273
4274 let mut attr1: Option<&Attr> = None;
4276 let mut attr2: Option<&Attr> = None;
4277
4278 let attr1owner;
4283 if let Some(a) = other.downcast::<Attr>() {
4284 attr1 = Some(a);
4285 attr1owner = a.GetOwnerElement();
4286 node1 = match attr1owner {
4287 Some(ref e) => Some(e.upcast()),
4288 None => None,
4289 }
4290 }
4291
4292 let attr2owner;
4295 if let Some(a) = self.downcast::<Attr>() {
4296 attr2 = Some(a);
4297 attr2owner = a.GetOwnerElement();
4298 node2 = match attr2owner {
4299 Some(ref e) => Some(e.upcast()),
4300 None => None,
4301 }
4302 }
4303
4304 if let Some(node2) = node2 &&
4309 Some(node2) == node1 &&
4310 let (Some(a1), Some(a2)) = (attr1, attr2)
4311 {
4312 let attrs = node2.downcast::<Element>().unwrap().attrs();
4313 for attr in attrs.borrow().iter() {
4317 if (*attr.namespace() == *a1.namespace()) &&
4318 (attr.local_name() == a1.local_name()) &&
4319 (**attr.value() == **a1.value())
4320 {
4321 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4322 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4323 }
4324 if (*attr.namespace() == *a2.namespace()) &&
4325 (attr.local_name() == a2.local_name()) &&
4326 (**attr.value() == **a2.value())
4327 {
4328 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4329 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4330 }
4331 }
4332 unreachable!();
4335 }
4336
4337 match (node1, node2) {
4339 (None, _) => {
4340 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4342 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4343 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4344 },
4345 (_, None) => {
4346 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4348 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4349 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4350 },
4351 (Some(node1), Some(node2)) => {
4352 let mut self_and_ancestors = node2
4354 .inclusive_ancestors(ShadowIncluding::No)
4355 .collect::<SmallVec<[_; 20]>>();
4356 let mut other_and_ancestors = node1
4357 .inclusive_ancestors(ShadowIncluding::No)
4358 .collect::<SmallVec<[_; 20]>>();
4359
4360 if self_and_ancestors.last() != other_and_ancestors.last() {
4361 let arbitrary = as_uintptr::<Node>(self_and_ancestors.last().unwrap()) <
4364 as_uintptr::<Node>(other_and_ancestors.last().unwrap());
4365 let arbitrary = if arbitrary {
4366 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4367 } else {
4368 NodeConstants::DOCUMENT_POSITION_PRECEDING
4369 };
4370
4371 return arbitrary +
4373 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4374 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4375 }
4376 let mut parent = self_and_ancestors.pop().unwrap();
4378 other_and_ancestors.pop().unwrap();
4379
4380 let mut current_position =
4381 cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
4382
4383 while current_position > 0 {
4384 current_position -= 1;
4385 let child_1 = self_and_ancestors.pop().unwrap();
4386 let child_2 = other_and_ancestors.pop().unwrap();
4387
4388 if child_1 != child_2 {
4389 for child in parent.children() {
4390 if child == child_1 {
4391 return NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4393 }
4394 if child == child_2 {
4395 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4397 }
4398 }
4399 }
4400
4401 parent = child_1;
4402 }
4403
4404 if self_and_ancestors.len() < other_and_ancestors.len() {
4409 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4410 NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
4411 } else {
4412 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4413 NodeConstants::DOCUMENT_POSITION_CONTAINS
4414 }
4415 },
4416 }
4417 }
4418
4419 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4421 match maybe_other {
4422 None => false,
4423 Some(other) => self.is_inclusive_ancestor_of(other),
4424 }
4425 }
4426
4427 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4429 let namespace = namespace_from_domstring(namespace);
4430
4431 if namespace == ns!() {
4433 return None;
4434 }
4435
4436 match self.type_id() {
4438 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4439 NodeTypeId::Document(_) => self
4440 .downcast::<Document>()
4441 .unwrap()
4442 .GetDocumentElement()
4443 .and_then(|element| element.lookup_prefix(namespace)),
4444 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4445 NodeTypeId::Attr => self
4446 .downcast::<Attr>()
4447 .unwrap()
4448 .GetOwnerElement()
4449 .and_then(|element| element.lookup_prefix(namespace)),
4450 _ => self
4451 .GetParentElement()
4452 .and_then(|element| element.lookup_prefix(namespace)),
4453 }
4454 }
4455
4456 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4458 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4460
4461 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4463 }
4464
4465 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4467 let namespace = namespace_from_domstring(namespace);
4469 Node::locate_namespace(self, None) == namespace
4471 }
4472}
4473
4474pub(crate) trait NodeTraits {
4475 fn owner_document(&self) -> DomRoot<Document>;
4479 fn owner_window(&self) -> DomRoot<Window>;
4483 fn owner_global(&self) -> DomRoot<GlobalScope>;
4487 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4489 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4492}
4493
4494impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4495 fn owner_document(&self) -> DomRoot<Document> {
4496 self.upcast().owner_doc()
4497 }
4498
4499 fn owner_window(&self) -> DomRoot<Window> {
4500 DomRoot::from_ref(self.owner_document().window())
4501 }
4502
4503 fn owner_global(&self) -> DomRoot<GlobalScope> {
4504 DomRoot::from_ref(self.owner_window().upcast())
4505 }
4506
4507 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4508 Node::containing_shadow_root(self.upcast())
4509 }
4510
4511 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4512 self.containing_shadow_root()
4513 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4514 .unwrap_or_else(|| {
4515 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4516 })
4517 }
4518}
4519
4520impl VirtualMethods for Node {
4521 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4522 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4523 }
4524
4525 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4526 if let Some(s) = self.super_type() {
4527 s.children_changed(cx, mutation);
4528 }
4529
4530 if let Some(data) = self.rare_data.borrow().as_ref() &&
4531 let Some(list) = data.child_list.get()
4532 {
4533 list.as_children_list().children_changed(mutation);
4534 }
4535
4536 self.owner_doc_unrooted(cx.no_gc())
4537 .content_and_heritage_changed(cx.no_gc(), self);
4538 }
4539
4540 fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
4542 self.super_type().unwrap().unbind_from_tree(cx, context);
4543
4544 let mut cached_index = None;
4545 let mut lazy_index = || *cached_index.get_or_insert_with(|| context.index());
4546 if let Some(selection) = self.owner_document().selection() {
4547 selection.remove_steps_for_removed_subtree(self, context.parent, &mut lazy_index);
4548 }
4549 live_range_pre_remove_steps_for_removed_subtree(self, context.parent, &mut lazy_index);
4550 }
4551
4552 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
4553 if let Some(super_type) = self.super_type() {
4554 super_type.moving_steps(cx, context);
4555 }
4556
4557 self.owner_doc_unrooted(cx.no_gc())
4558 .content_and_heritage_changed(cx.no_gc(), self);
4559
4560 if let Some(parent) = self.GetParentNode() {
4561 Self::maybe_dirty_visible_selection_for_newly_inserted_nodes(
4562 cx.no_gc(),
4563 &parent,
4564 &[self],
4565 );
4566 }
4567 }
4568
4569 fn handle_event(&self, cx: &mut JSContext, event: &Event) {
4570 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4571 return;
4572 }
4573
4574 if let Some(event) = event.downcast::<KeyboardEvent>() {
4575 self.owner_document()
4576 .event_handler()
4577 .run_default_keyboard_event_handler(cx, self, event);
4578 }
4579 }
4580
4581 fn handle_mousedown_event(
4582 &self,
4583 cx: &mut JSContext,
4584 event: &MouseEvent,
4585 hit_test_result: &HitTestResult,
4586 ) {
4587 assert_eq!(event.upcast::<Event>().type_(), atom!("mousedown"));
4588
4589 let document = self.owner_document();
4590 if event.button() == MouseButton::Auxiliary {
4591 let Some(selection) = document.selection() else {
4592 return;
4593 };
4594 let _ = selection.Collapse(cx, None, 0);
4595 event.upcast::<Event>().mark_as_handled();
4596 return;
4597 }
4598
4599 if event.button() != MouseButton::Primary {
4600 return;
4601 }
4602 let Some(selection) = document.GetSelection(cx) else {
4603 return;
4604 };
4605
4606 let (container, offset) = hit_test_result
4610 .dom_position_for_selection
4611 .as_ref()
4612 .map(|(node, offset)| (node, *offset))
4613 .unwrap_or((&hit_test_result.node, Utf32CodeUnitsOrNodeOffset(0)));
4614 selection.collapse_to_dom_position(cx, container, offset);
4615 document
4616 .event_handler()
4617 .install_drag_gesture(DragGesture::new(DragHandler::DocumentSelection(
4618 DocumentSelectionDragHandler,
4619 )));
4620 event.upcast::<Event>().mark_as_handled();
4621 }
4622}
4623
4624#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4626pub(crate) enum NodeDamage {
4627 Style,
4629 ContentOrHeritage,
4632 Other,
4634}
4635
4636pub(crate) struct UniqueId {
4638 cell: UnsafeCell<Option<Box<Uuid>>>,
4639}
4640
4641unsafe_no_jsmanaged_fields!(UniqueId);
4642
4643impl MallocSizeOf for UniqueId {
4644 #[expect(unsafe_code)]
4645 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
4646 if let Some(uuid) = unsafe { &*self.cell.get() } {
4647 unsafe { ops.malloc_size_of(&**uuid) }
4648 } else {
4649 0
4650 }
4651 }
4652}
4653
4654impl UniqueId {
4655 pub(super) fn new() -> UniqueId {
4657 UniqueId {
4658 cell: UnsafeCell::new(None),
4659 }
4660 }
4661
4662 #[expect(unsafe_code)]
4664 pub(super) fn borrow(&self) -> &Uuid {
4665 unsafe {
4666 let ptr = self.cell.get();
4667 if (*ptr).is_none() {
4668 *ptr = Some(Box::new(Uuid::new_v4()));
4669 }
4670 (*ptr).as_ref().unwrap()
4671 }
4672 }
4673}
4674
4675pub(crate) trait VecPreOrderInsertionHelper<T> {
4678 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
4679}
4680
4681impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
4682where
4683 T: DerivedFrom<Node> + DomObject,
4684{
4685 fn insert_pre_order(&mut self, node: &T, tree_root: &Node) {
4690 let Err(insertion_index) = self.binary_search_by(|candidate| {
4691 candidate.upcast().compare_dom_tree_position(
4692 node.upcast(),
4693 tree_root,
4694 ShadowIncluding::No,
4695 )
4696 }) else {
4697 return;
4700 };
4701
4702 self.insert(insertion_index, Dom::from_ref(node));
4703 }
4704}
4705
4706pub(crate) enum FlatTreeParent<'a> {
4708 Parent(UnrootedDom<'a, Node>),
4710 NotInFlatTree,
4713 RootNode,
4715}