1use std::cell::{Cell, LazyCell};
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 script_bindings::cell::{DomRefCell, Ref, RefMut};
35use script_bindings::codegen::GenericBindings::ElementBinding::ElementMethods;
36use script_bindings::codegen::GenericBindings::EventBinding::EventMethods;
37use script_bindings::codegen::GenericBindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
38use script_bindings::codegen::GenericBindings::SelectionBinding::SelectionMethods;
39use script_bindings::codegen::InheritTypes::{DocumentFragmentTypeId, TextTypeId};
40use script_bindings::reflector::{
41 DomObject, DomObjectWrap, WeakReferenceableDomObjectWrap, reflect_dom_object_with_proto,
42 reflect_weak_referenceable_dom_object_with_proto,
43};
44use script_traits::{DocumentActivity, MouseButtons};
45use servo_base::id::PipelineId;
46use servo_base::text::Utf32CodeUnitsOrNodeOffset;
47use servo_config::pref;
48use smallvec::SmallVec;
49use style::Atom;
50use style::context::QuirksMode;
51use style::dom::OpaqueNode;
52use style::dom_apis::{QueryAll, QueryFirst};
53use style::selector_parser::PseudoElement;
54use style_traits::CSSPixel;
55use uuid::Uuid;
56use xml5ever::{local_name, serialize as xml_serialize};
57
58use crate::conversions::Convert;
59use crate::dom::ChildrenMutation;
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::comparator::{DomPositionContainment, compare_dom_positions};
89use crate::dom::context::{BindContext, IsShadowTree, MoveContext, UnbindContext};
90use crate::dom::css::cssstylesheet::CSSStyleSheet;
91use crate::dom::css::stylesheetlist::StyleSheetListOwner;
92use crate::dom::customelementregistry::{
93 CallbackReaction, CustomElementRegistry, try_upgrade_element,
94};
95use crate::dom::document::{Document, HasBrowsingContext, IsHTMLDocument};
96use crate::dom::documentfragment::DocumentFragment;
97use crate::dom::documenttype::DocumentType;
98use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
99use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
100use crate::dom::eventtarget::EventTarget;
101use crate::dom::globalscope::GlobalScope;
102use crate::dom::html::htmlcollection::HTMLCollection;
103use crate::dom::html::htmlelement::HTMLElement;
104use crate::dom::html::htmllinkelement::HTMLLinkElement;
105use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
106use crate::dom::html::htmlstyleelement::HTMLStyleElement;
107use crate::dom::inputevent::HitTestResult;
108use crate::dom::iterators::{
109 ShadowIncluding, UnrootedAncestorIterator, UnrootedFollowingFlatTreeNodesTraversal,
110 UnrootedFollowingNodeIterator, UnrootedPrecedingNodeIterator,
111};
112use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
113use crate::dom::node::iterators::{
114 FollowingNodeIterator, PrecedingNodeIterator, SimpleNodeIterator, TreeIterator,
115 UnrootedSimpleNodeIterator, UnrootedTreeIterator,
116};
117use crate::dom::node::nodelist::NodeList;
118use crate::dom::node::virtualmethods::{VirtualMethods, vtable_for};
119use crate::dom::pointerevent::{PointerEvent, PointerId};
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::traversal::LightDomNoGcTraversal;
126use crate::dom::types::{CDATASection, KeyboardEvent, MouseEvent, ProcessingInstruction};
127use crate::dom::window::Window;
128use crate::drag::document_selection_drag::{
129 DocumentSelectionDragHandler, adjust_anchor_for_user_select,
130};
131use crate::drag::drag_gesture::{DragGesture, DragHandler};
132use crate::event_loop::document_loader::DocumentLoader;
133use crate::event_loop::script_thread::ScriptThread;
134use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode};
135
136#[dom_struct]
138pub struct Node {
139 eventtarget: EventTarget,
141
142 parent_node: MutNullableDom<Node>,
144
145 first_child: MutNullableDom<Node>,
147
148 last_child: MutNullableDom<Node>,
150
151 next_sibling: MutNullableDom<Node>,
153
154 prev_sibling: MutNullableDom<Node>,
156
157 owner_doc: MutNullableDom<Document>,
159
160 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
162
163 children_count: Cell<u32>,
165
166 flags: Cell<NodeFlags>,
168
169 inclusive_descendants_version: Cell<u64>,
171
172 #[no_trace]
175 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
176}
177
178impl fmt::Debug for Node {
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 if let Some(element) = self.downcast::<Element>() {
181 element.fmt(f)
182 } else if let Some(character_data) = self.downcast::<CharacterData>() {
183 write!(f, "[Text({})]", *character_data.data())
184 } else {
185 write!(f, "[Node({:?})]", self.type_id())
186 }
187 }
188}
189
190#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
192pub(crate) struct NodeFlags(u16);
193
194bitflags! {
195 impl NodeFlags: u16 {
196 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
200
201 const HAS_DIRTY_DESCENDANTS = 1 << 1;
203
204 const CLICK_IN_PROGRESS = 1 << 2;
207
208 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
213
214 const HAS_SNAPSHOT = 1 << 7;
219
220 const HANDLED_SNAPSHOT = 1 << 8;
222
223 const IS_IN_SHADOW_TREE = 1 << 9;
225
226 const IS_CONNECTED = 1 << 10;
230
231 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
234
235 const IS_IN_UA_WIDGET = 1 << 12;
238
239 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
241
242 const OVERLAPS_DOCUMENT_SELECTION = 1 << 14;
249
250 const SELECTION_INHIBITED = 1 << 15;
253 }
254}
255
256#[derive(Clone, Copy, MallocSizeOf)]
260pub(crate) enum SuppressObserver {
261 Suppressed,
262 Unsuppressed,
263}
264
265pub(crate) enum ForceSlottableNodeReconciliation {
266 Force,
267 Skip,
268}
269
270impl Node {
271 pub(super) fn parent_node(&self) -> &MutNullableDom<Node> {
273 &self.parent_node
274 }
275
276 pub(super) fn first_child(&self) -> &MutNullableDom<Node> {
277 &self.first_child
278 }
279
280 pub(super) fn last_child(&self) -> &MutNullableDom<Node> {
281 &self.last_child
282 }
283
284 pub(super) fn next_sibling(&self) -> &MutNullableDom<Node> {
285 &self.next_sibling
286 }
287
288 pub(super) fn prev_sibling(&self) -> &MutNullableDom<Node> {
289 &self.prev_sibling
290 }
291
292 pub(super) fn get_owner_doc(&self) -> &MutNullableDom<Document> {
293 &self.owner_doc
294 }
295
296 pub(super) fn get_rare_data(&self) -> &DomRefCell<Option<Box<NodeRareData>>> {
297 &self.rare_data
298 }
299
300 pub(super) fn flags(&self) -> &Cell<NodeFlags> {
301 &self.flags
302 }
303
304 pub(crate) fn layout_data(&self) -> &DomRefCell<Option<Box<GenericLayoutData>>> {
305 &self.layout_data
306 }
307
308 fn add_child(&self, cx: &mut JSContext, new_child: &Node, before: Option<&Node>) {
312 assert!(new_child.parent_node.get().is_none());
313 assert!(new_child.prev_sibling.get().is_none());
314 assert!(new_child.next_sibling.get().is_none());
315
316 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
317
318 match before {
319 Some(before) => {
320 assert!(before.parent_node.get().as_deref() == Some(self));
321 let prev_sibling = before.GetPreviousSibling();
322 match prev_sibling {
323 None => {
324 assert!(self.first_child.get().as_deref() == Some(before));
325 self.first_child.set(Some(new_child));
326 },
327 Some(ref prev_sibling) => {
328 prev_sibling.next_sibling.set(Some(new_child));
329 new_child.prev_sibling.set(Some(prev_sibling));
330 },
331 }
332 before.prev_sibling.set(Some(new_child));
333 new_child.next_sibling.set(Some(before));
334 },
335 None => {
336 let last_child = self.GetLastChild();
337 match last_child {
338 None => self.first_child.set(Some(new_child)),
339 Some(ref last_child) => {
340 assert!(last_child.next_sibling.get().is_none());
341 last_child.next_sibling.set(Some(new_child));
342 new_child.prev_sibling.set(Some(last_child));
343 },
344 }
345
346 self.last_child.set(Some(new_child));
347 },
348 }
349
350 new_child.parent_node.set(Some(self));
351 self.children_count.set(self.children_count.get() + 1);
352
353 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
354 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
355 let parent_is_connected = self.is_connected();
356 let parent_is_in_ua_widget = self.is_in_ua_widget();
357
358 let context = BindContext::new(self, IsShadowTree::No);
359
360 for node in new_child.traverse_preorder(ShadowIncluding::No) {
361 if parent_in_shadow_tree {
362 if let Some(shadow_root) = self.containing_shadow_root() {
363 node.set_containing_shadow_root(Some(&*shadow_root));
364 }
365 debug_assert!(node.containing_shadow_root().is_some());
366 }
367 node.set_flag(
368 NodeFlags::IS_IN_A_DOCUMENT_TREE,
369 parent_is_in_a_document_tree,
370 );
371 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
372 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
373 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
374
375 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
377 vtable_for(&node).bind_to_tree(cx, &context);
378 }
379 }
380
381 pub(crate) fn complete_remove_subtree(
384 cx: &mut JSContext,
385 root: &Node,
386 context: &UnbindContext,
387 ) {
388 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
390 .union(NodeFlags::IS_CONNECTED)
391 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
392 .union(NodeFlags::HAS_SNAPSHOT)
393 .union(NodeFlags::HANDLED_SNAPSHOT)
394 .union(NodeFlags::OVERLAPS_DOCUMENT_SELECTION)
395 .union(NodeFlags::SELECTION_INHIBITED);
396
397 for node in root.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No) {
398 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
399
400 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
403 for node in shadow_root
404 .upcast::<Node>()
405 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
406 {
407 node.set_flag(RESET_FLAGS, false);
408 }
409 }
410 }
411
412 let is_parent_connected = context.parent.is_connected();
414 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
415
416 let document = root.owner_doc();
419 let cleanup_node = |cx: &mut JSContext, node: &Node| {
420 document.cancel_animations_for_node(node);
421 document.clean_up_style_and_layout_data_for_node(node);
422
423 vtable_for(node).unbind_from_tree(cx, context);
428
429 if is_parent_connected && let Some(element) = node.as_custom_element() {
431 custom_element_reaction_stack.enqueue_callback_reaction(
432 cx,
433 &element,
434 CallbackReaction::Disconnected,
435 None,
436 );
437 }
438 };
439
440 for node in root.traverse_preorder(ShadowIncluding::No) {
441 cleanup_node(cx, &node);
442
443 if node.containing_shadow_root().is_some() {
446 node.set_containing_shadow_root(None);
449 }
450
451 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
454 for node in shadow_root
455 .upcast::<Node>()
456 .traverse_preorder(ShadowIncluding::Yes)
457 {
458 cleanup_node(cx, &node);
459 }
460 }
461 }
462
463 if root.owner_document().accessibility_active() {
466 root.owner_document()
467 .accessibility_data_mut()
468 .root_removed_node(cx.no_gc(), root);
469 }
470 }
471
472 pub(crate) fn complete_move_subtree(cx: &mut JSContext, root: &Node) {
473 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
475 .union(NodeFlags::IS_CONNECTED)
476 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
477 .union(NodeFlags::HAS_SNAPSHOT)
478 .union(NodeFlags::HANDLED_SNAPSHOT)
479 .union(NodeFlags::OVERLAPS_DOCUMENT_SELECTION)
480 .union(NodeFlags::SELECTION_INHIBITED);
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) {
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(self, next_sibling.as_deref());
551
552 child.prev_sibling.set(None);
553 child.next_sibling.set(None);
554 child.parent_node.set(None);
555 self.children_count.set(self.children_count.get() - 1);
556
557 Self::complete_remove_subtree(cx, child, &context);
558 }
559
560 fn move_child(&self, cx: &mut JSContext, child: &Node) {
561 assert!(child.parent_node.get().as_deref() == Some(self));
562 self.dirty(cx.no_gc(), NodeDamage::ContentOrHeritage);
563 if let Some(element) = self.downcast::<Element>() {
564 element.note_dirty_descendants(cx.no_gc());
565 }
566
567 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
568
569 child.prev_sibling.set(None);
570 child.next_sibling.set(None);
571 child.parent_node.set(None);
572 self.children_count.set(self.children_count.get() - 1);
573 Self::complete_move_subtree(cx, child)
574 }
575
576 pub(crate) fn to_opaque(&self) -> OpaqueNode {
577 OpaqueNode(self.reflector().get_jsobject().get() as usize)
578 }
579
580 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
581 self.downcast::<Element>().and_then(|element| {
582 if element.is_custom() {
583 assert!(element.get_custom_element_definition().is_some());
584 Some(DomRoot::from_ref(element))
585 } else {
586 None
587 }
588 })
589 }
590
591 pub(crate) fn fire_synthetic_pointer_event_not_trusted(
593 &self,
594 cx: &mut JSContext,
595 event_type: Atom,
596 ) {
597 let window = self.owner_window();
601
602 let pointer_event = PointerEvent::new(
604 cx,
605 &window, event_type,
607 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::new(), false, vec![], vec![], );
634
635 pointer_event.upcast::<Event>().set_composed(true);
637
638 pointer_event.upcast::<Event>().set_trusted(false);
640
641 pointer_event
644 .upcast::<Event>()
645 .dispatch(cx, self.upcast::<EventTarget>(), false);
646 }
647
648 pub(crate) fn parent_directionality(&self) -> String {
649 let mut current = self.GetParentNode();
650
651 loop {
652 match current {
653 Some(node) => {
654 if let Some(directionality) = node
655 .downcast::<HTMLElement>()
656 .and_then(|html_element| html_element.directionality())
657 {
658 return directionality;
659 } else {
660 current = node.GetParentNode();
661 }
662 },
663 None => return "ltr".to_owned(),
664 }
665 }
666 }
667
668 pub(crate) fn is_being_rendered_or_delegates_rendering(
672 &self,
673 pseudo_element: Option<PseudoElement>,
674 ) -> bool {
675 matches!(
676 self.owner_window()
677 .layout()
678 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
679 NodeRenderingType::Rendered | NodeRenderingType::DelegatesRendering
680 )
681 }
682
683 pub(crate) fn is_being_rendered(&self, pseudo_element: Option<PseudoElement>) -> bool {
685 matches!(
686 self.owner_window()
687 .layout()
688 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
689 NodeRenderingType::Rendered
690 )
691 }
692
693 pub(crate) fn add_pending_accessibility_damage(&self, damage: AccessibilityDamage) {
694 if !self.owner_doc().accessibility_active() {
695 return;
696 }
697
698 self.owner_doc()
699 .accessibility_data_mut()
700 .add_pending_accessibility_damage_for_node(self, damage);
701 }
702
703 pub(crate) fn set_element_selection(&self, selected: bool) -> bool {
706 debug_assert!(
707 self.downcast::<CharacterData>().is_none(),
708 "Should never be called on CharacterData"
709 );
710 self.layout_data()
711 .borrow()
712 .as_ref()
713 .is_some_and(|layout_data| layout_data.set_element_selection(selected))
714 }
715}
716
717impl Node {
718 fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
719 let mut rare_data = self.rare_data.borrow_mut();
720 if rare_data.is_none() {
721 *rare_data = Some(Default::default());
722 }
723 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
724 }
725
726 pub(crate) fn is_before(&self, no_gc: &NoGC, other: &Node) -> bool {
729 let cmp = other.CompareDocumentPosition(no_gc, self);
730 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
731 return false;
732 }
733
734 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
735 }
736
737 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
740 RefMut::map(self.ensure_rare_data(), |rare_data| {
741 &mut rare_data.mutation_observers
742 })
743 }
744
745 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
746 let rare_data = self.rare_data.borrow();
747 if rare_data.is_none() {
748 return None;
749 }
750 Some(Ref::map(rare_data, |rare_data| {
751 &rare_data.as_ref().unwrap().mutation_observers
752 }))
753 }
754
755 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
757 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
758 self.ensure_rare_data().mutation_observers.push(observer);
759 }
760
761 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
763 let mut rare_data = self.rare_data.borrow_mut();
764 let Some(rare_data) = rare_data.as_mut() else {
765 return;
766 };
767 rare_data
768 .mutation_observers
769 .retain(|registered_observer| &*registered_observer.observer != observer)
770 }
771
772 pub(crate) fn debug_str(&self) -> String {
774 format!("{:?}", self.type_id())
775 }
776
777 pub(crate) fn is_in_a_document_tree(&self) -> bool {
779 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
780 }
781
782 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
784 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
785 }
786
787 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
788 self.flags
789 .get()
790 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
791 }
792
793 pub(crate) fn set_weird_parser_insertion_mode(&self) {
794 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
795 }
796
797 pub(crate) fn is_connected(&self) -> bool {
799 self.flags.get().contains(NodeFlags::IS_CONNECTED)
800 }
801
802 pub(crate) fn is_in_flat_tree(&self, no_gc: &NoGC) -> bool {
807 if !self.is_connected() {
808 return false;
809 }
810
811 let mut node = UnrootedDom::from_ref(self, no_gc);
812 loop {
813 match node.parent_in_flat_tree(no_gc) {
814 FlatTreeParent::Parent(parent) => node = parent,
815 FlatTreeParent::NotInFlatTree => return false,
816 FlatTreeParent::RootNode => return true,
817 }
818 }
819 }
820
821 pub(crate) fn set_in_ua_widget(&self, in_ua_widget: bool) {
822 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, in_ua_widget)
823 }
824
825 pub(crate) fn is_in_ua_widget(&self) -> bool {
826 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
827 }
828
829 pub(crate) fn type_id(&self) -> NodeTypeId {
831 match *self.eventtarget.type_id() {
832 EventTargetTypeId::Node(type_id) => type_id,
833 _ => unreachable!(),
834 }
835 }
836
837 pub(crate) fn len(&self) -> u32 {
839 match self.type_id() {
840 NodeTypeId::DocumentType => 0,
841 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
842 _ => self.children_count(),
843 }
844 }
845
846 pub(crate) fn is_empty(&self) -> bool {
847 self.len() == 0
849 }
850
851 pub(crate) fn index(&self) -> u32 {
853 self.preceding_siblings().count() as u32
854 }
855
856 pub(crate) fn has_parent(&self) -> bool {
858 self.parent_node.get().is_some()
859 }
860
861 pub(crate) fn children_count(&self) -> u32 {
862 self.children_count.get()
863 }
864
865 #[inline]
866 pub(crate) fn is_doctype(&self) -> bool {
867 self.type_id() == NodeTypeId::DocumentType
868 }
869
870 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
871 self.flags.get().contains(flag)
872 }
873
874 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
875 let mut flags = self.flags.get();
876
877 if value {
878 flags.insert(flag);
879 } else {
880 flags.remove(flag);
881 }
882
883 self.flags.set(flags);
884 }
885
886 pub(crate) fn rev_version(&self, no_gc: &NoGC) {
887 let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
892 let version = cmp::max(
893 self.inclusive_descendants_version(),
894 doc.inclusive_descendants_version(),
895 ) + 1;
896
897 for node in self.inclusive_ancestors_unrooted(no_gc, ShadowIncluding::No) {
898 node.inclusive_descendants_version.set(version);
899 }
900 doc.inclusive_descendants_version.set(version);
901 }
902
903 pub(crate) fn clear_layout_data(&self) {
904 self.layout_data.take();
905 }
906
907 pub(crate) fn dirty(&self, no_gc: &NoGC, damage: NodeDamage) {
908 self.rev_version(no_gc);
909 if !self.is_connected() {
910 return;
911 }
912
913 match self.type_id() {
914 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..)) => {
915 *self.layout_data.borrow_mut() = None;
918
919 self.parent_node
923 .get()
924 .unwrap()
925 .dirty(no_gc, NodeDamage::ContentOrHeritage);
926
927 if damage == NodeDamage::Other {
928 self.add_pending_accessibility_damage(AccessibilityDamage::Node);
929 }
930 },
931 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(no_gc, damage),
932 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
933 .downcast::<ShadowRoot>()
934 .unwrap()
935 .Host()
936 .upcast::<Element>()
937 .restyle(no_gc, damage),
938 _ => {},
939 };
940 }
941
942 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
944 self.inclusive_descendants_version.get()
945 }
946
947 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
949 TreeIterator::new(self, shadow_including)
950 }
951
952 pub(crate) fn traverse_preorder_non_rooting<'b>(
955 &self,
956 no_gc: &'b NoGC,
957 shadow_including: ShadowIncluding,
958 ) -> UnrootedTreeIterator<'b> {
959 UnrootedTreeIterator::new(self, shadow_including, no_gc)
960 }
961
962 pub(crate) fn inclusively_following_siblings(
963 &self,
964 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
965 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), |n| n.GetNextSibling())
966 }
967
968 pub(crate) fn inclusively_following_siblings_unrooted<'b>(
969 &self,
970 no_gc: &'b NoGC,
971 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
972 UnrootedSimpleNodeIterator::new(
973 Some(UnrootedDom::from_ref(self, no_gc)),
974 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
975 no_gc,
976 )
977 }
978
979 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
980 &self,
981 no_gc: &'b NoGC,
982 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
983 UnrootedSimpleNodeIterator::new(
984 Some(UnrootedDom::from_ref(self, no_gc)),
985 |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
986 no_gc,
987 )
988 }
989
990 pub(crate) fn common_ancestor(
991 &self,
992 other: &Node,
993 shadow_including: ShadowIncluding,
994 ) -> Option<DomRoot<Node>> {
995 self.inclusive_ancestors(shadow_including).find(|ancestor| {
996 other
997 .inclusive_ancestors(shadow_including)
998 .any(|node| node == *ancestor)
999 })
1000 }
1001
1002 pub(crate) fn common_ancestor_in_flat_tree(
1003 &self,
1004 no_gc: &NoGC,
1005 other: &Node,
1006 ) -> Option<DomRoot<Node>> {
1007 self.inclusive_ancestors_in_flat_tree_unrooted(no_gc)
1008 .find(|ancestor| {
1009 other
1010 .inclusive_ancestors_in_flat_tree_unrooted(no_gc)
1011 .any(|node| node == *ancestor)
1012 })
1013 .map(|node| node.as_rooted())
1014 }
1015
1016 pub(crate) fn following_flat_tree_nodes_unrooted<'no_gc>(
1017 &self,
1018 no_gc: &'no_gc NoGC,
1019 ) -> UnrootedFollowingFlatTreeNodesTraversal<'no_gc> {
1020 UnrootedFollowingFlatTreeNodesTraversal::new(self, no_gc)
1021 }
1022
1023 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
1025 self == child || self.is_ancestor_of(child)
1027 }
1028
1029 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
1031 let mut current = &possible_descendant.parent_node;
1033 let mut done = false;
1034
1035 while let Some(node) = current.if_is_some(|node| {
1036 done = node == self;
1037 &node.parent_node
1038 }) {
1039 if done {
1040 break;
1041 }
1042 current = node
1043 }
1044 done
1045 }
1046
1047 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
1049 self.is_inclusive_ancestor_of(child) ||
1052 child
1053 .GetRootNode(&GetRootNodeOptions::empty())
1054 .downcast::<DocumentFragment>()
1055 .and_then(|fragment| fragment.host())
1056 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1057 }
1058
1059 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1061 node.inclusive_ancestors(ShadowIncluding::Yes)
1062 .any(|ancestor| &*ancestor == self)
1063 }
1064
1065 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1066 SimpleNodeIterator::new(self.GetNextSibling(), |n| n.GetNextSibling())
1067 }
1068
1069 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1070 SimpleNodeIterator::new(self.GetPreviousSibling(), |n| n.GetPreviousSibling())
1071 }
1072
1073 pub(crate) fn following_nodes(
1074 &self,
1075 root: &Node,
1076 shadow_including: ShadowIncluding,
1077 ) -> FollowingNodeIterator {
1078 FollowingNodeIterator::new(
1079 Some(DomRoot::from_ref(self)),
1080 DomRoot::from_ref(root),
1081 shadow_including,
1082 )
1083 }
1084
1085 pub(crate) fn following_nodes_unrooted<'b>(
1086 &self,
1087 no_gc: &'b NoGC,
1088 root: &Node,
1089 shadow_including: ShadowIncluding,
1090 ) -> UnrootedFollowingNodeIterator<'b> {
1091 UnrootedFollowingNodeIterator::new(
1092 Some(UnrootedDom::from_ref(self, no_gc)),
1093 UnrootedDom::from_ref(root, no_gc),
1094 shadow_including,
1095 no_gc,
1096 )
1097 }
1098
1099 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1100 PrecedingNodeIterator::new(Some(DomRoot::from_ref(self)), DomRoot::from_ref(root))
1101 }
1102
1103 pub(crate) fn preceding_nodes_unrooted<'b>(
1104 &self,
1105 no_gc: &'b NoGC,
1106 root: &Node,
1107 ) -> UnrootedPrecedingNodeIterator<'b> {
1108 UnrootedPrecedingNodeIterator::new(
1109 Some(UnrootedDom::from_ref(self, no_gc)),
1110 UnrootedDom::from_ref(root, no_gc),
1111 no_gc,
1112 )
1113 }
1114
1115 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1118 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetLastChild())
1119 }
1120
1121 pub(crate) fn descending_last_children_unrooted<'b>(
1122 &self,
1123 no_gc: &'b NoGC,
1124 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> {
1125 UnrootedSimpleNodeIterator::new(
1126 self.get_last_child_unrooted(no_gc),
1127 |n, no_gc| n.get_last_child_unrooted(no_gc),
1128 no_gc,
1129 )
1130 }
1131
1132 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1133 child
1134 .parent_node
1135 .get()
1136 .is_some_and(|parent| &*parent == self)
1137 }
1138
1139 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1140 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1141 }
1142
1143 pub(crate) fn containing_block_node_without_reflow(&self) -> Option<DomRoot<Node>> {
1145 self.owner_window()
1146 .containing_block_node_query_without_reflow(self)
1147 }
1148
1149 pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1150 self.owner_window().padding_query_without_reflow(self)
1151 }
1152
1153 pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1154 self.owner_window()
1155 .box_area_query(self, BoxAreaType::Content, false)
1156 }
1157
1158 pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1159 self.owner_window()
1160 .box_area_query(self, BoxAreaType::Border, false)
1161 }
1162
1163 pub(crate) fn border_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1164 self.owner_window()
1165 .box_area_query_without_reflow(self, BoxAreaType::Border, false)
1166 }
1167
1168 pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1169 self.owner_window()
1170 .box_area_query(self, BoxAreaType::Padding, false)
1171 }
1172
1173 pub(crate) fn padding_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1174 self.owner_window()
1175 .box_area_query_without_reflow(self, BoxAreaType::Padding, false)
1176 }
1177
1178 pub(crate) fn border_boxes(&self) -> CSSPixelRectVec {
1179 self.owner_window()
1180 .box_areas_query(self, BoxAreaType::Border)
1181 }
1182
1183 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1184 self.owner_window().client_rect_query(self)
1185 }
1186
1187 pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1190 let document = self.owner_doc();
1192
1193 if !document.is_active() {
1195 return Rect::zero();
1196 }
1197
1198 let window = document.window();
1201 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1202
1203 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1204 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1205 let is_body_element = self
1206 .downcast::<HTMLElement>()
1207 .is_some_and(|e| e.is_body_element());
1208
1209 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1215 let viewport_scrolling_area = window.scrolling_area_query(None);
1216 return Rect::new(
1217 viewport_scrolling_area.origin,
1218 viewport_scrolling_area.size.max(viewport),
1219 );
1220 }
1221
1222 window.scrolling_area_query(Some(self))
1226 }
1227
1228 pub(crate) fn effective_overflow(&self) -> Option<AxesOverflow> {
1229 self.owner_window().query_effective_overflow(self)
1230 }
1231
1232 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1233 self.owner_window()
1234 .query_effective_overflow_without_reflow(self)
1235 }
1236
1237 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1239 let parent = &self.parent_node;
1241
1242 let parent = match parent.get() {
1244 None => return Ok(()),
1245 Some(parent) => parent,
1246 };
1247
1248 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1250
1251 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1253
1254 let viable_previous_sibling = match viable_previous_sibling {
1256 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1257 None => parent.first_child.get(),
1258 };
1259
1260 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1262
1263 Ok(())
1264 }
1265
1266 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1268 let parent = &self.parent_node;
1270
1271 let parent = match parent.get() {
1273 None => return Ok(()),
1274 Some(parent) => parent,
1275 };
1276
1277 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1279
1280 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1282
1283 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1285
1286 Ok(())
1287 }
1288
1289 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1291 let Some(parent) = self.GetParentNode() else {
1293 return Ok(());
1295 };
1296
1297 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1299
1300 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1302
1303 if self.parent_node == Some(&*parent) {
1304 parent.ReplaceChild(cx, &node, self)?;
1306 } else {
1307 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1309 }
1310 Ok(())
1311 }
1312
1313 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1315 let doc = self.owner_doc();
1317 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1318 let first_child = self.first_child.get();
1320 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1321 }
1322
1323 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1325 let doc = self.owner_doc();
1327 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1328 self.AppendChild(cx, &node).map(|_| ())
1330 }
1331
1332 pub(crate) fn replace_children(
1334 &self,
1335 cx: &mut JSContext,
1336 nodes: Vec<NodeOrString>,
1337 ) -> ErrorResult {
1338 let doc = self.owner_doc();
1341 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1342
1343 Node::ensure_pre_insertion_validity(cx.no_gc(), &node, self, None)?;
1345
1346 Node::replace_all(cx, Some(&node), self);
1348 Ok(())
1349 }
1350
1351 pub(crate) fn move_before(
1353 &self,
1354 cx: &mut JSContext,
1355 node: &Node,
1356 child: Option<&Node>,
1357 ) -> ErrorResult {
1358 let reference_child_root;
1361 let reference_child = match child {
1362 Some(child) if child == node => {
1363 reference_child_root = node.GetNextSibling();
1364 reference_child_root.as_deref()
1365 },
1366 _ => child,
1367 };
1368
1369 Node::move_fn(cx, node, self, reference_child)
1371 }
1372
1373 fn move_fn(
1375 cx: &mut JSContext,
1376 node: &Node,
1377 new_parent: &Node,
1378 child: Option<&Node>,
1379 ) -> ErrorResult {
1380 let mut options = GetRootNodeOptions::empty();
1385 options.composed = true;
1386 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1387 return Err(Error::HierarchyRequest(Some(
1388 "The `newParent` node's shadow root is not the same as the `node`'s shadow root"
1389 .into(),
1390 )));
1391 }
1392
1393 if node.is_inclusive_ancestor_of(new_parent) {
1396 return Err(Error::HierarchyRequest(Some(
1397 "`node` node cannot be the inclusive ancestor of the `newParent` node".into(),
1398 )));
1399 }
1400
1401 if let Some(child) = child &&
1404 !new_parent.is_parent_of(child)
1405 {
1406 return Err(Error::NotFound(Some(
1407 "`child` node's parent node is not `newParent`".into(),
1408 )));
1409 }
1410
1411 match node.type_id() {
1416 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1417 if new_parent.is::<Document>() {
1418 return Err(Error::HierarchyRequest(Some(
1419 "`node` cannot be a text node when `newParent` is a document".into(),
1420 )));
1421 }
1422 },
1423 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1424 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1425 NodeTypeId::Element(_) => (),
1426 NodeTypeId::DocumentFragment(_) |
1427 NodeTypeId::DocumentType |
1428 NodeTypeId::Document(_) |
1429 NodeTypeId::Attr => {
1430 return Err(Error::HierarchyRequest(Some(
1431 "To move `node` into a `newParent`, it must be an Element".into(),
1432 )));
1433 },
1434 }
1435
1436 if new_parent.is::<Document>() && node.is::<Element>() {
1440 if new_parent.child_elements().next().is_some() {
1442 return Err(Error::HierarchyRequest(Some(
1443 "`newParent` document cannot have an element child".into(),
1444 )));
1445 }
1446
1447 if child.is_some_and(|child| {
1450 child
1451 .inclusively_following_siblings_unrooted(cx.no_gc())
1452 .any(|child| child.is_doctype())
1453 }) {
1454 return Err(Error::HierarchyRequest(Some(
1455 "`child` node has a document node following it".into(),
1456 )));
1457 }
1458 }
1459
1460 let old_parent = node
1463 .parent_node
1464 .get()
1465 .expect("old_parent should always be initialized");
1466
1467 let document = node.owner_doc_unrooted(cx.no_gc());
1469 let mut cached_index = None;
1470 let mut lazy_index = || *cached_index.get_or_insert_with(|| node.index());
1471 if let Some(selection) = document.selection() {
1472 selection.pre_remove_steps(node, &old_parent, &mut lazy_index);
1473 }
1474 document.live_range_pre_remove_steps(cx.no_gc(), node, &old_parent, &mut lazy_index);
1475
1476 let old_previous_sibling = node.prev_sibling.get();
1481
1482 let old_next_sibling = node.next_sibling.get();
1484
1485 let prev_sibling = node.GetPreviousSibling();
1486 match prev_sibling {
1487 None => {
1488 old_parent
1489 .first_child
1490 .set(node.next_sibling.get().as_deref());
1491 },
1492 Some(ref prev_sibling) => {
1493 prev_sibling
1494 .next_sibling
1495 .set(node.next_sibling.get().as_deref());
1496 },
1497 }
1498 let next_sibling = node.GetNextSibling();
1499 match next_sibling {
1500 None => {
1501 old_parent
1502 .last_child
1503 .set(node.prev_sibling.get().as_deref());
1504 },
1505 Some(ref next_sibling) => {
1506 next_sibling
1507 .prev_sibling
1508 .set(node.prev_sibling.get().as_deref());
1509 },
1510 }
1511
1512 old_parent.move_child(cx, node);
1514
1515 if let Some(slot) = node.assigned_slot() {
1517 slot.assign_slottables(cx);
1518 }
1519
1520 if old_parent.is_in_a_shadow_tree() &&
1523 let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() &&
1524 !slot_element.has_assigned_nodes()
1525 {
1526 slot_element.signal_a_slot_change(cx);
1527 }
1528
1529 let has_slot_descendant = node
1531 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
1532 .any(|element| element.is::<HTMLSlotElement>());
1533 if has_slot_descendant {
1534 old_parent
1536 .GetRootNode(&GetRootNodeOptions::empty())
1537 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1538
1539 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1541 }
1542
1543 if let Some(child) = child {
1545 let document = new_parent.owner_doc_unrooted(cx.no_gc());
1547 if let Some(selection) = document.selection() {
1548 selection.insert_steps(new_parent, child, 1);
1549 }
1550 document.live_range_insert_steps(cx.no_gc(), new_parent, child, 1);
1551 }
1552
1553 let new_previous_sibling = child.map_or_else(
1556 || new_parent.last_child.get(),
1557 |child| child.prev_sibling.get(),
1558 );
1559
1560 new_parent.add_child(cx, node, child);
1563
1564 if let Some(shadow_root) = new_parent
1567 .downcast::<Element>()
1568 .and_then(Element::shadow_root) &&
1569 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1570 (node.is::<Element>() || node.is::<Text>())
1571 {
1572 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1573 slottable.assign_a_slot(cx);
1574 }
1575
1576 if new_parent.is_in_a_shadow_tree() &&
1579 let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() &&
1580 !slot_element.has_assigned_nodes()
1581 {
1582 slot_element.signal_a_slot_change(cx);
1583 }
1584
1585 node.GetRootNode(&GetRootNodeOptions::empty())
1587 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1588
1589 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1592 if descendant.deref() == node {
1596 vtable_for(&descendant).moving_steps(cx, &MoveContext::new(Some(&old_parent)));
1597 } else {
1598 vtable_for(&descendant).moving_steps(cx, &MoveContext::new(None));
1599 }
1600
1601 if let Some(descendant) = descendant.downcast::<Element>() &&
1603 descendant.is_custom() &&
1604 new_parent.is_connected()
1605 {
1606 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
1609 custom_element_reaction_stack.enqueue_callback_reaction(
1610 cx,
1611 descendant,
1612 CallbackReaction::ConnectedMove,
1613 None,
1614 );
1615 }
1616 }
1617
1618 let moved = [node];
1621 let mutation = LazyCell::new(|| Mutation::ChildList {
1622 added: None,
1623 removed: Some(&moved),
1624 prev: old_previous_sibling.as_deref(),
1625 next: old_next_sibling.as_deref(),
1626 });
1627 MutationObserver::queue_a_mutation_record(cx, &old_parent, mutation);
1628
1629 let mutation = LazyCell::new(|| Mutation::ChildList {
1632 added: Some(&moved),
1633 removed: None,
1634 prev: new_previous_sibling.as_deref(),
1635 next: child,
1636 });
1637 MutationObserver::queue_a_mutation_record(cx, new_parent, mutation);
1638
1639 Ok(())
1640 }
1641
1642 #[allow(unsafe_code)]
1644 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1645 pub(crate) fn query_selector(
1646 &self,
1647 no_gc: &NoGC,
1648 selectors: DOMString,
1649 ) -> Fallible<Option<DomRoot<Element>>> {
1650 let document_url = self.owner_document().url().get_arc();
1653
1654 self.owner_document()
1657 .id_map()
1658 .resolve_all(no_gc, self.owner_doc().upcast());
1659
1660 let traced_node = Dom::from_ref(self);
1662
1663 let first_matching_element = with_layout_state(|| {
1664 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1665 ServoDangerousStyleNode::from(layout_node)
1666 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1667 })?;
1668
1669 Ok(first_matching_element.map(ServoDangerousStyleElement::rooted))
1670 }
1671
1672 #[allow(unsafe_code)]
1674 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1675 pub(crate) fn query_selector_all(
1676 &self,
1677 cx: &mut JSContext,
1678 selectors: DOMString,
1679 ) -> Fallible<DomRoot<NodeList>> {
1680 let document_url = self.owner_document().url().get_arc();
1683
1684 self.owner_document()
1687 .id_map()
1688 .resolve_all(cx.no_gc(), self.owner_doc().upcast());
1689
1690 let unrooted_node = UnrootedDom::from_ref(self, cx.no_gc());
1691 let matching_elements = with_layout_state(|| {
1692 let layout_node: LayoutDom<'_, _> = unsafe { unrooted_node.to_layout() };
1693 ServoDangerousStyleNode::from(layout_node)
1694 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1695 })?;
1696 let iter = matching_elements
1697 .into_iter()
1698 .map(ServoDangerousStyleElement::rooted)
1699 .map(DomRoot::upcast::<Node>);
1700
1701 Ok(NodeList::new_simple_list(cx, &self.owner_window(), iter))
1704 }
1705
1706 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1707 SimpleNodeIterator::new(self.GetParentNode(), |n| n.GetParentNode())
1708 }
1709
1710 pub(crate) fn ancestors_unrooted<'a>(&self, no_gc: &'a NoGC) -> UnrootedAncestorIterator<'a> {
1711 UnrootedSimpleNodeIterator::new(
1712 self.get_parent_node_unrooted(no_gc),
1713 |node, no_gc| node.get_parent_node_unrooted(no_gc),
1714 no_gc,
1715 )
1716 }
1717
1718 pub(crate) fn inclusive_ancestors(
1720 &self,
1721 shadow_including: ShadowIncluding,
1722 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1723 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |n| {
1724 if shadow_including == ShadowIncluding::Yes &&
1725 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1726 {
1727 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1728 }
1729 n.GetParentNode()
1730 })
1731 }
1732
1733 pub(crate) fn inclusive_ancestors_unrooted<'a>(
1734 &self,
1735 no_gc: &'a NoGC,
1736 shadow_including: ShadowIncluding,
1737 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1738 UnrootedSimpleNodeIterator::new(
1739 Some(UnrootedDom::from_ref(self, no_gc)),
1740 move |node, no_gc| {
1741 if shadow_including == ShadowIncluding::Yes &&
1742 let Some(shadow_root) = node.downcast::<ShadowRoot>()
1743 {
1744 return Some(UnrootedDom::upcast(shadow_root.host_unrooted(no_gc)));
1745 }
1746 node.get_parent_node_unrooted(no_gc)
1747 },
1748 no_gc,
1749 )
1750 }
1751
1752 pub(crate) fn ancestors_in_flat_tree_unrooted<'a>(
1753 &self,
1754 no_gc: &'a NoGC,
1755 ) -> UnrootedAncestorIterator<'a> {
1756 UnrootedSimpleNodeIterator::new(
1757 self.parent_in_flat_tree(no_gc).into_parent(),
1758 |node, no_gc| node.parent_in_flat_tree(no_gc).into_parent(),
1759 no_gc,
1760 )
1761 }
1762
1763 pub(crate) fn inclusive_ancestors_in_flat_tree_unrooted<'a>(
1764 &self,
1765 no_gc: &'a NoGC,
1766 ) -> UnrootedAncestorIterator<'a> {
1767 UnrootedSimpleNodeIterator::new(
1768 Some(UnrootedDom::from_ref(self, no_gc)),
1769 |node, no_gc| node.parent_in_flat_tree(no_gc).into_parent(),
1770 no_gc,
1771 )
1772 }
1773
1774 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1775 self.owner_doc.get().unwrap()
1776 }
1777
1778 pub(crate) fn owner_doc_unrooted<'a>(&self, no_gc: &'a NoGC) -> UnrootedDom<'a, Document> {
1779 self.owner_doc.get_unrooted(no_gc).unwrap()
1780 }
1781
1782 pub(crate) fn set_owner_doc(&self, document: &Document) {
1783 self.owner_doc.set(Some(document));
1784 }
1785
1786 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1787 self.rare_data
1788 .borrow()
1789 .as_ref()?
1790 .containing_shadow_root
1791 .as_ref()
1792 .map(|shadow_root| DomRoot::from_ref(&**shadow_root))
1793 }
1794
1795 pub(crate) fn containing_shadow_root_unrooted<'a>(
1796 &self,
1797 no_gc: &'a NoGC,
1798 ) -> Option<UnrootedDom<'a, ShadowRoot>> {
1799 self.rare_data
1800 .borrow()
1801 .as_ref()?
1802 .containing_shadow_root
1803 .as_ref()
1804 .map(|shadow_root| shadow_root.as_unrooted(no_gc))
1805 }
1806
1807 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1808 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1809 }
1810
1811 pub(crate) fn is_in_html_doc(&self) -> bool {
1812 self.owner_doc().is_html_document()
1813 }
1814
1815 pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1816 self.is_connected() && self.owner_doc().browsing_context().is_some()
1817 }
1818
1819 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1820 SimpleNodeIterator::new(self.GetFirstChild(), |n| n.GetNextSibling())
1821 }
1822
1823 pub(crate) fn children_unrooted<'a>(
1824 &self,
1825 no_gc: &'a NoGC,
1826 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1827 UnrootedSimpleNodeIterator::new(
1828 self.get_first_child_unrooted(no_gc),
1829 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1830 no_gc,
1831 )
1832 }
1833
1834 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1835 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetPreviousSibling())
1836 }
1837
1838 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1840 self.children()
1841 .filter_map(DomRoot::downcast as fn(_) -> _)
1842 .peekable()
1843 }
1844
1845 pub(crate) fn child_elements_unrooted<'a>(
1846 &self,
1847 no_gc: &'a NoGC,
1848 ) -> impl Iterator<Item = UnrootedDom<'a, Element>> + use<'a> {
1849 self.children_unrooted(no_gc)
1850 .filter_map(UnrootedDom::downcast)
1851 .peekable()
1852 }
1853
1854 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1855 if let Some(ref parent) = self.GetParentNode() {
1856 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1857 }
1858 }
1859
1860 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1862 Ref::filter_map(self.rare_data.borrow(), |rare_data| {
1863 rare_data
1864 .as_ref()
1865 .and_then(|rare_data| rare_data.unique_id.as_ref())
1866 })
1867 .ok()
1868 .map(|unique_id| unique_id.simple().to_string())
1869 }
1870
1871 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1872 let mut rare_data = self.ensure_rare_data();
1873
1874 if rare_data.unique_id.is_none() {
1875 let node_id = Uuid::new_v4();
1876 ScriptThread::save_node_id(pipeline, node_id.simple().to_string());
1877 rare_data.unique_id = Some(node_id);
1878 }
1879 rare_data.unique_id.as_ref().unwrap().simple().to_string()
1880 }
1881
1882 pub(crate) fn summarize(&self, cx: &mut JSContext) -> NodeInfo {
1883 let USVString(base_uri) = self.BaseURI();
1884 let node_type = self.NodeType();
1885 let pipeline = self.owner_window().pipeline_id();
1886
1887 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1888 let shadow_root_mode = maybe_shadow_root
1889 .map(ShadowRoot::Mode)
1890 .map(ShadowRootMode::convert);
1891 let host = maybe_shadow_root
1892 .map(ShadowRoot::Host)
1893 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1894 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1895 let Some(root) = potential_host.shadow_root() else {
1896 return false;
1897 };
1898 !root.is_user_agent_widget() || pref!(inspector_show_servo_internal_shadow_roots)
1899 });
1900
1901 let num_children = if is_shadow_host {
1902 self.ChildNodes(cx).Length(cx.no_gc()) as usize + 1
1904 } else {
1905 self.ChildNodes(cx).Length(cx.no_gc()) as usize
1906 };
1907
1908 let window = self.owner_window();
1909 let element = self.downcast::<Element>();
1910 let display = element
1911 .map(|elem| window.GetComputedStyle(cx, elem, None))
1912 .map(|style| style.Display().into());
1913
1914 let is_displayed =
1920 element.is_none_or(|element| !element.is_display_none()) || self.is::<DocumentType>();
1921 let attrs = element.map(Element::summarize).unwrap_or_default();
1922
1923 NodeInfo {
1924 unique_id: self.unique_id(pipeline),
1925 host,
1926 base_uri,
1927 parent: self
1928 .GetParentNode()
1929 .map_or(String::new(), |node| node.unique_id(pipeline)),
1930 node_type,
1931 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1932 node_name: String::from(self.NodeName()),
1933 node_value: self.GetNodeValue().map(|v| v.into()),
1934 num_children,
1935 attrs,
1936 is_shadow_host,
1937 shadow_root_mode,
1938 display,
1939 is_displayed,
1940 doctype_name: self
1941 .downcast::<DocumentType>()
1942 .map(DocumentType::name)
1943 .cloned()
1944 .map(String::from),
1945 doctype_public_identifier: self
1946 .downcast::<DocumentType>()
1947 .map(DocumentType::public_id)
1948 .cloned()
1949 .map(String::from),
1950 doctype_system_identifier: self
1951 .downcast::<DocumentType>()
1952 .map(DocumentType::system_id)
1953 .cloned()
1954 .map(String::from),
1955 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1956 }
1957 }
1958
1959 pub(crate) fn insert_cell_or_row<F, G, I>(
1961 &self,
1962 cx: &mut JSContext,
1963 index: i32,
1964 get_items: F,
1965 new_child: G,
1966 ) -> Fallible<DomRoot<HTMLElement>>
1967 where
1968 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1969 G: Fn(&mut JSContext) -> DomRoot<I>,
1970 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1971 {
1972 if index < -1 {
1973 return Err(Error::IndexSize(Some("Index is out of bounds".into())));
1974 }
1975
1976 let tr = new_child(cx);
1977
1978 {
1979 let tr_node = tr.upcast::<Node>();
1980 if index == -1 {
1981 self.InsertBefore(cx, tr_node, None)?;
1982 } else {
1983 let items = get_items(cx);
1984 let node = match items
1985 .elements_iter(cx.no_gc())
1986 .map(UnrootedDom::upcast::<Node>)
1987 .map(Some)
1988 .chain(iter::once(None))
1989 .nth(index as usize)
1990 {
1991 None => return Err(Error::IndexSize(Some("Index is out of bounds".into()))),
1992 Some(node) => node,
1993 };
1994 self.InsertBefore(cx, tr_node, node.map(|node| node.as_rooted()).as_deref())?;
1995 }
1996 }
1997
1998 Ok(DomRoot::upcast::<HTMLElement>(tr))
1999 }
2000
2001 pub(crate) fn delete_cell_or_row<F, G>(
2003 &self,
2004 cx: &mut JSContext,
2005 index: i32,
2006 get_items: F,
2007 is_delete_type: G,
2008 ) -> ErrorResult
2009 where
2010 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
2011 G: Fn(&Element) -> bool,
2012 {
2013 let element = match index {
2014 index if index < -1 => {
2015 return Err(Error::IndexSize(Some("Index is out of bounds".into())));
2016 },
2017 -1 => {
2018 let last_child = self.upcast::<Node>().GetLastChild();
2019 match last_child.and_then(|node| {
2020 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
2021 .filter_map(UnrootedDom::downcast::<Element>)
2022 .find(|elem| is_delete_type(elem))
2023 .map(|elem| elem.as_rooted())
2024 }) {
2025 Some(element) => element,
2026 None => return Ok(()),
2027 }
2028 },
2029 index => match get_items(cx).Item(cx, index as u32) {
2030 Some(element) => element,
2031 None => return Err(Error::IndexSize(Some("Index is out of bounds".into()))),
2032 },
2033 };
2034
2035 element.upcast::<Node>().remove_self(cx);
2036 Ok(())
2037 }
2038
2039 pub(crate) fn get_cssom_stylesheet(
2040 &self,
2041 cx: &mut JSContext,
2042 ) -> Option<DomRoot<CSSStyleSheet>> {
2043 if let Some(node) = self.downcast::<HTMLStyleElement>() {
2044 node.get_cssom_stylesheet(cx)
2045 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
2046 node.get_cssom_stylesheet(cx)
2047 } else {
2048 None
2049 }
2050 }
2051
2052 pub(crate) fn get_lang(&self) -> Option<String> {
2054 self.inclusive_ancestors(ShadowIncluding::Yes)
2062 .find_map(|node| {
2063 node.downcast::<Element>().and_then(|element| {
2064 element
2067 .get_attribute_string_value_with_namespace(&ns!(xml), &local_name!("lang"))
2068 .or_else(|| {
2072 if element.namespace() == &ns!() || element.namespace() == &ns!(svg) {
2073 element.get_attribute_string_value(&local_name!("lang"))
2074 } else {
2075 None
2076 }
2077 })
2078 })
2079 })
2080 .or_else(|| self.owner_document().default_language())
2095 }
2096
2097 pub(crate) fn assign_slottables_for_a_tree(
2099 &self,
2100 cx: &JSContext,
2101 force: ForceSlottableNodeReconciliation,
2102 ) {
2103 let is_shadow_root_with_slots = self
2110 .downcast::<ShadowRoot>()
2111 .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
2112 if !is_shadow_root_with_slots &&
2113 !self.is::<HTMLSlotElement>() &&
2114 matches!(force, ForceSlottableNodeReconciliation::Skip)
2115 {
2116 return;
2117 }
2118
2119 for node in self.traverse_preorder_non_rooting(cx, ShadowIncluding::No) {
2122 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
2123 slot.assign_slottables(cx);
2124 }
2125 }
2126 }
2127
2128 pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
2129 let assigned_slot = self
2130 .rare_data
2131 .borrow()
2132 .as_ref()?
2133 .slottable_data
2134 .assigned_slot
2135 .as_ref()?
2136 .as_rooted();
2137 Some(assigned_slot)
2138 }
2139
2140 pub(crate) fn assigned_slot_unrooted<'a>(
2141 &self,
2142 no_gc: &'a NoGC,
2143 ) -> Option<UnrootedDom<'a, HTMLSlotElement>> {
2144 let rare_data = self.rare_data.borrow();
2145 let assigned_slot = rare_data.as_ref()?.slottable_data.assigned_slot.as_ref()?;
2146 Some(UnrootedDom::from_ref(assigned_slot, no_gc))
2147 }
2148
2149 pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
2150 self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
2151 }
2152
2153 pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
2154 let manually_assigned_slot = self
2155 .rare_data
2156 .borrow()
2157 .as_ref()?
2158 .slottable_data
2159 .manual_slot_assignment
2160 .as_ref()?
2161 .as_rooted();
2162 Some(manually_assigned_slot)
2163 }
2164
2165 pub(crate) fn set_manual_slot_assignment(
2166 &self,
2167 manually_assigned_slot: Option<&HTMLSlotElement>,
2168 ) {
2169 self.ensure_rare_data()
2170 .slottable_data
2171 .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
2172 }
2173
2174 pub(crate) fn parent_in_flat_tree<'b>(&self, no_gc: &'b NoGC) -> FlatTreeParent<'b> {
2185 if let Some(assigned_slot) = self.assigned_slot_unrooted(no_gc) {
2186 return FlatTreeParent::Parent(UnrootedDom::upcast::<Node>(assigned_slot));
2187 }
2188
2189 let Some(parent) = self.get_parent_node_unrooted(no_gc) else {
2190 return FlatTreeParent::RootNode;
2191 };
2192
2193 if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
2194 return FlatTreeParent::Parent(UnrootedDom::upcast(shadow_root.host_unrooted(no_gc)));
2195 }
2196
2197 if parent
2198 .downcast::<Element>()
2199 .is_some_and(|element| element.is_shadow_host())
2200 {
2201 return FlatTreeParent::NotInFlatTree;
2202 }
2203
2204 if parent
2205 .downcast::<HTMLSlotElement>()
2206 .is_some_and(|slot| slot.has_assigned_nodes())
2207 {
2208 return FlatTreeParent::NotInFlatTree;
2209 }
2210
2211 FlatTreeParent::Parent(parent)
2212 }
2213
2214 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2216 debug_assert!(self.is_in_ua_widget());
2218 debug_assert!(pseudo_element.is_element_backed());
2219 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2220 }
2221
2222 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2223 self.rare_data
2224 .borrow()
2225 .as_ref()
2226 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2227 }
2228
2229 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2231 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2235 if ancestor.is_editing_host() {
2236 return Some(ancestor);
2237 }
2238 if ancestor
2239 .downcast::<HTMLElement>()
2240 .is_some_and(|el| el.ContentEditable().str() == "false")
2241 {
2242 return None;
2243 }
2244 }
2245 None
2246 }
2247
2248 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2249 self.editing_host_of().is_some()
2250 }
2251
2252 pub(crate) fn is_editing_host(&self) -> bool {
2254 self.downcast::<HTMLElement>()
2255 .is_some_and(HTMLElement::is_editing_host)
2256 }
2257
2258 pub(crate) fn is_editable(&self) -> bool {
2260 if self.is_editing_host() {
2262 return false;
2263 }
2264 let html_element = self.downcast::<HTMLElement>();
2266 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2267 return false;
2268 }
2269 let Some(parent) = self.GetParentNode() else {
2271 return false;
2272 };
2273 if !parent.is_editable_or_editing_host() {
2274 return false;
2275 }
2276 html_element.is_some() || (!self.is::<Element>() && parent.is::<HTMLElement>())
2278 }
2279}
2280
2281fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2283where
2284 I: Iterator<Item = DomRoot<Node>>,
2285{
2286 nodes.find(|node| {
2287 not_in.iter().all(|n| match *n {
2288 NodeOrString::Node(ref n) => n != node,
2289 _ => true,
2290 })
2291 })
2292}
2293
2294#[expect(unsafe_code)]
2297pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2298 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2299 DomRoot::from_ref(node)
2300}
2301
2302#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2304pub(crate) enum CloneChildrenFlag {
2305 CloneChildren,
2306 DoNotCloneChildren,
2307}
2308
2309impl From<bool> for CloneChildrenFlag {
2310 fn from(boolean: bool) -> Self {
2311 if boolean {
2312 CloneChildrenFlag::CloneChildren
2313 } else {
2314 CloneChildrenFlag::DoNotCloneChildren
2315 }
2316 }
2317}
2318
2319pub(super) fn as_uintptr<T>(t: &T) -> uintptr_t {
2320 t as *const T as uintptr_t
2321}
2322
2323impl Node {
2324 pub(crate) fn reflect_node<N>(
2325 cx: &mut JSContext,
2326 node: Box<N>,
2327 document: &Document,
2328 ) -> DomRoot<N>
2329 where
2330 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2331 {
2332 Self::reflect_node_with_proto(cx, node, document, None)
2333 }
2334
2335 pub(crate) fn reflect_node_with_proto<N>(
2336 cx: &mut JSContext,
2337 node: Box<N>,
2338 document: &Document,
2339 proto: Option<HandleObject>,
2340 ) -> DomRoot<N>
2341 where
2342 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2343 {
2344 let window = document.window();
2345 reflect_dom_object_with_proto(cx, node, window, proto)
2346 }
2347
2348 pub(crate) fn reflect_weak_referenceable_node_with_proto<N>(
2349 cx: &mut JSContext,
2350 node: Rc<N>,
2351 document: &Document,
2352 proto: Option<HandleObject>,
2353 ) -> DomRoot<N>
2354 where
2355 N: DerivedFrom<Node> + DomObject + WeakReferenceableDomObjectWrap<crate::DomTypeHolder>,
2356 {
2357 let window = document.window();
2358 reflect_weak_referenceable_dom_object_with_proto(cx, node, window, proto)
2359 }
2360
2361 pub(crate) fn new_inherited(doc: &Document) -> Node {
2362 Node::new_(NodeFlags::empty(), Some(doc))
2363 }
2364
2365 pub(crate) fn new_document_node() -> Node {
2366 Node::new_(
2367 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2368 None,
2369 )
2370 }
2371
2372 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2373 Node {
2374 eventtarget: EventTarget::new_inherited(),
2375 parent_node: Default::default(),
2376 first_child: Default::default(),
2377 last_child: Default::default(),
2378 next_sibling: Default::default(),
2379 prev_sibling: Default::default(),
2380 owner_doc: MutNullableDom::new(doc),
2381 rare_data: Default::default(),
2382 children_count: Cell::new(0u32),
2383 flags: Cell::new(flags),
2384 inclusive_descendants_version: Cell::new(0),
2385 layout_data: Default::default(),
2386 }
2387 }
2388
2389 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2391 document.add_script_and_layout_blocker();
2392
2393 let old_doc = node.owner_doc();
2395 old_doc.add_script_and_layout_blocker();
2396
2397 node.remove_self(cx);
2399
2400 if &*old_doc != document {
2404 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2405 descendant.set_owner_doc(document);
2407
2408 if let Some(shadow_root) = descendant.downcast::<ShadowRoot>() {
2419 if shadow_root
2420 .custom_element_registry()
2421 .is_none_or(|registry| {
2422 CustomElementRegistry::is_a_global_element_registry(Some(&*registry))
2423 })
2424 {
2425 shadow_root.set_custom_element_registry(
2426 document
2427 .effective_global_custom_element_registry()
2428 .as_deref(),
2429 );
2430 }
2431 }
2432 else if let Some(element) = descendant.downcast::<Element>() {
2434 for attribute in element.attrs().borrow().iter() {
2437 if let Some(attr) = attribute.as_attr() {
2438 attr.upcast::<Node>().set_owner_doc(document);
2439 }
2440 }
2441
2442 if element
2448 .custom_element_registry()
2449 .is_none_or(|registry| !registry.is_scoped())
2450 {
2451 element.set_custom_element_registry(
2452 document
2453 .effective_global_custom_element_registry()
2454 .as_deref(),
2455 cx.no_gc(),
2456 );
2457 }
2458
2459 if element.is_custom() {
2463 ScriptThread::custom_element_reaction_stack().enqueue_callback_reaction(
2464 cx,
2465 element,
2466 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2467 None,
2468 );
2469 }
2470 }
2471
2472 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2474 }
2475
2476 for range in old_doc.live_ranges().as_vec() {
2480 range.maybe_update_document();
2481 }
2482 }
2483
2484 old_doc.remove_script_and_layout_blocker(cx);
2485 document.remove_script_and_layout_blocker(cx);
2486 }
2487
2488 pub(crate) fn ensure_pre_insertion_validity(
2490 no_gc: &NoGC,
2491 node: &Node,
2492 parent: &Node,
2493 child: Option<&Node>,
2494 ) -> ErrorResult {
2495 match parent.type_id() {
2497 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2498 },
2499 _ => {
2500 return Err(Error::HierarchyRequest(Some(
2501 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2502 )));
2503 },
2504 }
2505
2506 if node.is_host_including_inclusive_ancestor(parent) {
2508 return Err(Error::HierarchyRequest(Some(
2509 "Node is a host-including inclusive ancestor of parent".to_owned(),
2510 )));
2511 }
2512
2513 if let Some(child) = child &&
2515 !parent.is_parent_of(child)
2516 {
2517 return Err(Error::NotFound(Some(
2518 "Child is non-null and its parent is not parent".to_owned(),
2519 )));
2520 }
2521
2522 match node.type_id() {
2523 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2527 if parent.is::<Document>() {
2528 return Err(Error::HierarchyRequest(Some(
2529 "Node is a Text node and parent is a document".to_owned(),
2530 )));
2531 }
2532 },
2533 NodeTypeId::DocumentType => {
2534 if !parent.is::<Document>() {
2535 return Err(Error::HierarchyRequest(Some(
2536 "Node is a doctype and parent is not a document".to_owned(),
2537 )));
2538 }
2539 },
2540 NodeTypeId::DocumentFragment(_) |
2541 NodeTypeId::Element(_) |
2542 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2543 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2544 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2547 return Err(Error::HierarchyRequest(Some(
2548 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2549 .to_owned(),
2550 )));
2551 },
2552 }
2553
2554 if parent.is::<Document>() {
2557 match node.type_id() {
2558 NodeTypeId::DocumentFragment(_) => {
2559 if node.children_unrooted(no_gc).any(|c| c.is::<Text>()) {
2561 return Err(Error::HierarchyRequest(Some(
2562 "Parent is a document and node has a Text node child".into(),
2563 )));
2564 }
2565 match node.child_elements_unrooted(no_gc).count() {
2566 0 => (),
2567 1 => {
2570 if parent.child_elements_unrooted(no_gc).next().is_some() {
2571 return Err(Error::HierarchyRequest(Some(
2572 "Node has one element child and parent has an element child"
2573 .into(),
2574 )));
2575 }
2576 if let Some(child) = child &&
2577 child
2578 .inclusively_following_siblings_unrooted(no_gc)
2579 .any(|child| child.is_doctype())
2580 {
2581 return Err(Error::HierarchyRequest(Some(
2582 "Node has one element child and child is a doctype".into(),
2583 )));
2584 }
2585 },
2586 _ => {
2587 return Err(Error::HierarchyRequest(Some(
2588 "Node cannot have more than one child element".into(),
2589 )));
2590 },
2591 }
2592 },
2593 NodeTypeId::Element(_) => {
2594 if parent.child_elements_unrooted(no_gc).next().is_some() {
2596 return Err(Error::HierarchyRequest(Some(
2597 "Parent has an element child".to_owned(),
2598 )));
2599 }
2600 if let Some(child) = child &&
2601 child
2602 .inclusively_following_siblings_unrooted(no_gc)
2603 .any(|following| following.is_doctype())
2604 {
2605 return Err(Error::HierarchyRequest(Some(
2606 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
2607 )));
2608 }
2609 },
2610 NodeTypeId::DocumentType => {
2611 if parent.children_unrooted(no_gc).any(|c| c.is_doctype()) {
2614 return Err(Error::HierarchyRequest(Some(
2615 "Parent cannot have a doctype child".into(),
2616 )));
2617 }
2618 match child {
2619 Some(child) => {
2620 if parent
2621 .children_unrooted(no_gc)
2622 .take_while(|c| **c != child)
2623 .any(|c| c.is::<Element>())
2624 {
2625 return Err(Error::HierarchyRequest(Some(
2626 "Child is non-null and an element is preceding child".into(),
2627 )));
2628 }
2629 },
2630 None => {
2631 if parent.child_elements_unrooted(no_gc).next().is_some() {
2632 return Err(Error::HierarchyRequest(Some(
2633 "Child is null and parent has an element child".into(),
2634 )));
2635 }
2636 },
2637 }
2638 },
2639 NodeTypeId::CharacterData(_) => (),
2640 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
2643 }
2644 }
2645 Ok(())
2646 }
2647
2648 pub(crate) fn pre_insert(
2650 cx: &mut JSContext,
2651 node: &Node,
2652 parent: &Node,
2653 child: Option<&Node>,
2654 ) -> Fallible<DomRoot<Node>> {
2655 Node::ensure_pre_insertion_validity(cx.no_gc(), node, parent, child)?;
2657
2658 let reference_child_root;
2660 let reference_child = match child {
2661 Some(child) if child == node => {
2663 reference_child_root = node.GetNextSibling();
2664 reference_child_root.as_deref()
2665 },
2666 _ => child,
2667 };
2668
2669 Node::insert(
2671 cx,
2672 node,
2673 parent,
2674 reference_child,
2675 SuppressObserver::Unsuppressed,
2676 );
2677
2678 Ok(DomRoot::from_ref(node))
2680 }
2681
2682 pub(crate) fn insert(
2684 cx: &mut JSContext,
2685 node: &Node,
2686 parent: &Node,
2687 child: Option<&Node>,
2688 suppress_observers: SuppressObserver,
2689 ) {
2690 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
2691
2692 rooted_vec!(let mut new_nodes);
2694 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2695 new_nodes.extend(
2696 node.children_unrooted(cx.no_gc())
2697 .map(|node| Dom::from_ref(&**node)),
2698 );
2699 new_nodes.r()
2700 } else {
2701 from_ref(&node)
2702 };
2703
2704 let count = new_nodes.len();
2706
2707 if count == 0 {
2709 return;
2710 }
2711
2712 let parent_document = parent.owner_doc();
2715 let from_document = node.owner_doc();
2716 from_document.add_script_and_layout_blocker();
2717 parent_document.add_script_and_layout_blocker();
2718
2719 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2721 for kid in new_nodes {
2723 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
2724 }
2725 vtable_for(node).children_changed(cx, &ChildrenMutation::ReplaceAll);
2726
2727 let mutation = LazyCell::new(|| Mutation::ChildList {
2729 added: None,
2730 removed: Some(new_nodes),
2731 prev: None,
2732 next: None,
2733 });
2734 MutationObserver::queue_a_mutation_record(cx, node, mutation);
2735 }
2736
2737 if let Some(child) = child {
2739 let count = count.try_into().unwrap();
2741 let document = parent.owner_doc_unrooted(cx.no_gc());
2742 if let Some(selection) = document.selection() {
2743 selection.insert_steps(parent, child, count);
2744 }
2745 document.live_range_insert_steps(cx.no_gc(), parent, child, count);
2746 }
2747
2748 let previous_sibling = match suppress_observers {
2750 SuppressObserver::Unsuppressed => match child {
2751 Some(child) => child.GetPreviousSibling(),
2752 None => parent.GetLastChild(),
2753 },
2754 SuppressObserver::Suppressed => None,
2755 };
2756
2757 let mut static_node_list: SmallVec<[_; 4]> = Default::default();
2759
2760 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
2761 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
2762 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
2763
2764 for kid in new_nodes {
2766 Node::adopt(cx, kid, &parent.owner_document());
2768
2769 parent.add_child(cx, kid, child);
2772
2773 if let Some(ref shadow_root) = parent_shadow_root &&
2776 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
2777 (kid.is::<Element>() || kid.is::<Text>())
2778 {
2779 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(kid)));
2780 slottable.assign_a_slot(cx);
2781 }
2782
2783 if parent_in_shadow_tree &&
2786 let Some(slot_element) = parent_as_slot &&
2787 !slot_element.has_assigned_nodes()
2788 {
2789 slot_element.signal_a_slot_change(cx);
2790 }
2791
2792 kid.GetRootNode(&GetRootNodeOptions::empty())
2794 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
2795
2796 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
2799 if let Some(element) = DomRoot::downcast::<Element>(descendant.clone()) &&
2805 !element.is_custom()
2806 {
2807 try_upgrade_element(cx, &element);
2808 }
2809
2810 if !descendant.is_connected() {
2812 continue;
2813 }
2814
2815 if let Some(element) = DomRoot::downcast::<Element>(descendant.clone()) {
2817 if let Some(registry) = element.custom_element_registry() {
2819 if registry.is_scoped() {
2824 registry.add_scoped_document(&element.owner_document());
2825 }
2826 }
2827 if element.is_custom() {
2835 ScriptThread::custom_element_reaction_stack().enqueue_callback_reaction(
2836 cx,
2837 &element,
2838 CallbackReaction::Connected,
2839 None,
2840 );
2841 }
2842 else {
2844 try_upgrade_element(cx, &element);
2845 }
2846 }
2847 else if let Some(shadow_root) =
2854 DomRoot::downcast::<ShadowRoot>(descendant.clone()) &&
2855 let Some(custom_element_registry) = shadow_root.custom_element_registry() &&
2856 custom_element_registry.is_scoped()
2857 {
2858 custom_element_registry.add_scoped_document(shadow_root.owner_doc());
2859 }
2860
2861 static_node_list.push(descendant.clone());
2864 }
2865 }
2866
2867 Self::maybe_dirty_visible_selection_for_newly_inserted_nodes(cx.no_gc(), parent, new_nodes);
2868
2869 if let SuppressObserver::Unsuppressed = suppress_observers {
2870 vtable_for(parent).children_changed(
2873 cx,
2874 &ChildrenMutation::insert(previous_sibling.as_deref(), child),
2875 );
2876
2877 let mutation = LazyCell::new(|| Mutation::ChildList {
2880 added: Some(new_nodes),
2881 removed: None,
2882 prev: previous_sibling.as_deref(),
2883 next: child,
2884 });
2885 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2886 }
2887
2888 parent_document.add_delayed_task(
2899 task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
2900 for node in static_node_list {
2905 vtable_for(&node).post_connection_steps(cx);
2906 }
2907 }),
2908 );
2909
2910 parent_document.remove_script_and_layout_blocker(cx);
2911 from_document.remove_script_and_layout_blocker(cx);
2912 }
2913
2914 pub(crate) fn maybe_dirty_visible_selection_for_newly_inserted_nodes(
2917 no_gc: &NoGC,
2918 parent: &Node,
2919 inserted_nodes: &[&Node],
2920 ) {
2921 let Some(selection) = parent.owner_document().selection() else {
2922 return;
2923 };
2924
2925 for node in inserted_nodes {
2926 match node.parent_in_flat_tree(no_gc) {
2927 FlatTreeParent::RootNode | FlatTreeParent::NotInFlatTree => {},
2928 FlatTreeParent::Parent(parent) => {
2929 if parent.get_flag(NodeFlags::OVERLAPS_DOCUMENT_SELECTION) {
2930 selection.set_visible_selection_dirty();
2931 return;
2932 }
2933 },
2934 }
2935 }
2936 }
2937
2938 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
2940 parent.owner_doc().add_script_and_layout_blocker();
2941
2942 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
2944
2945 rooted_vec!(let mut added_nodes);
2949 let added_nodes = if let Some(node) = node.as_ref() {
2950 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2951 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
2952 added_nodes.r()
2953 } else {
2954 from_ref(node)
2955 }
2956 } else {
2957 &[] as &[&Node]
2958 };
2959
2960 for child in &*removed_nodes {
2962 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
2963 }
2964
2965 if let Some(node) = node {
2967 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
2968 }
2969
2970 vtable_for(parent).children_changed(cx, &ChildrenMutation::ReplaceAll);
2971
2972 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
2975 let mutation = LazyCell::new(|| Mutation::ChildList {
2976 added: Some(added_nodes),
2977 removed: Some(removed_nodes.r()),
2978 prev: None,
2979 next: None,
2980 });
2981 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2982 }
2983 parent.owner_doc().remove_script_and_layout_blocker(cx);
2984 }
2985
2986 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
2988 if string.is_empty() {
2989 Node::replace_all(cx, None, parent);
2990 } else {
2991 let text = Text::new(cx, string, &parent.owner_document());
2992 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
2993 };
2994 }
2995
2996 pub(super) fn pre_remove(
2998 cx: &mut JSContext,
2999 child: &Node,
3000 parent: &Node,
3001 ) -> Fallible<DomRoot<Node>> {
3002 match child.GetParentNode() {
3004 Some(ref node) if &**node != parent => {
3005 return Err(Error::NotFound(Some(
3006 "Child's parent does not match the parent node provided".into(),
3007 )));
3008 },
3009 None => {
3010 return Err(Error::NotFound(Some(
3011 "Child does not have a parent node".into(),
3012 )));
3013 },
3014 _ => (),
3015 }
3016
3017 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
3019
3020 Ok(DomRoot::from_ref(child))
3022 }
3023
3024 pub(super) fn remove(
3026 cx: &mut JSContext,
3027 node: &Node,
3028 parent: &Node,
3029 suppress_observers: SuppressObserver,
3030 ) {
3031 parent.owner_doc().add_script_and_layout_blocker();
3032
3033 assert!(
3037 node.GetParentNode()
3038 .is_some_and(|node_parent| &*node_parent == parent)
3039 );
3040
3041 let mut cached_index = None;
3043 {
3044 let mut lazy_index = || *cached_index.get_or_insert_with(|| node.index());
3045 let document = parent.owner_doc_unrooted(cx.no_gc());
3046 if let Some(selection) = document.selection() {
3047 selection.pre_remove_steps(node, parent, &mut lazy_index);
3048 }
3049 document.live_range_pre_remove_steps(cx.no_gc(), node, parent, &mut lazy_index);
3050 }
3051
3052 let old_previous_sibling = node.GetPreviousSibling();
3056
3057 let old_next_sibling = node.GetNextSibling();
3059
3060 parent.remove_child(cx, node);
3063
3064 if let Some(slot) = node.assigned_slot() {
3066 slot.assign_slottables(cx);
3067 }
3068
3069 if parent.is_in_a_shadow_tree() &&
3072 let Some(slot_element) = parent.downcast::<HTMLSlotElement>() &&
3073 !slot_element.has_assigned_nodes()
3074 {
3075 slot_element.signal_a_slot_change(cx);
3076 }
3077
3078 let has_slot_descendant = node
3080 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
3081 .any(|elem| elem.is::<HTMLSlotElement>());
3082 if has_slot_descendant {
3083 parent
3085 .GetRootNode(&GetRootNodeOptions::empty())
3086 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
3087
3088 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Force);
3090 }
3091
3092 if let SuppressObserver::Unsuppressed = suppress_observers {
3096 vtable_for(parent).children_changed(
3097 cx,
3098 &ChildrenMutation::replace(
3099 old_previous_sibling.as_deref(),
3100 &Some(node),
3101 old_next_sibling.as_deref(),
3102 ),
3103 );
3104
3105 let removed = [node];
3106 let mutation = LazyCell::new(|| Mutation::ChildList {
3107 added: None,
3108 removed: Some(&removed),
3109 prev: old_previous_sibling.as_deref(),
3110 next: old_next_sibling.as_deref(),
3111 });
3112 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
3113 }
3114 parent.owner_doc().remove_script_and_layout_blocker(cx);
3115 }
3116
3117 pub(crate) fn clone(
3119 cx: &mut JSContext,
3120 node: &Node,
3121 maybe_doc: Option<&Document>,
3122 clone_children: CloneChildrenFlag,
3123 registry: Option<DomRoot<CustomElementRegistry>>,
3124 ) -> DomRoot<Node> {
3125 let document = match maybe_doc {
3127 Some(doc) => DomRoot::from_ref(doc),
3128 None => node.owner_doc(),
3129 };
3130
3131 let copy: DomRoot<Node> = match node.type_id() {
3134 NodeTypeId::DocumentType => {
3135 let doctype = node.downcast::<DocumentType>().unwrap();
3136 let doctype = DocumentType::new(
3137 cx,
3138 doctype.name().clone(),
3139 Some(doctype.public_id().clone()),
3140 Some(doctype.system_id().clone()),
3141 &document,
3142 );
3143 DomRoot::upcast::<Node>(doctype)
3144 },
3145 NodeTypeId::Attr => {
3146 let attr = node.downcast::<Attr>().unwrap();
3147 let attr = Attr::new(
3148 cx,
3149 &document,
3150 attr.local_name().clone(),
3151 attr.value().clone(),
3152 attr.name().clone(),
3153 attr.namespace().clone(),
3154 attr.prefix().cloned(),
3155 None,
3156 );
3157 DomRoot::upcast::<Node>(attr)
3158 },
3159 NodeTypeId::DocumentFragment(_) => {
3160 let doc_fragment = DocumentFragment::new(cx, &document);
3161 DomRoot::upcast::<Node>(doc_fragment)
3162 },
3163 NodeTypeId::CharacterData(_) => {
3164 let cdata = node.downcast::<CharacterData>().unwrap();
3165 cdata.clone_with_data(cx, cdata.Data(), &document)
3166 },
3167 NodeTypeId::Document(_) => {
3168 let document = node.downcast::<Document>().unwrap();
3171 let is_html_doc = if document.is_html_document() {
3172 IsHTMLDocument::HTMLDocument
3173 } else {
3174 IsHTMLDocument::NonHTMLDocument
3175 };
3176 let window = document.window();
3177 let loader = DocumentLoader::new(&document.loader());
3178 let document = Document::new(
3179 cx,
3180 window,
3181 HasBrowsingContext::No,
3182 Some(document.url()),
3183 None,
3184 document.origin().clone(),
3186 is_html_doc,
3187 None,
3188 None,
3189 DocumentActivity::Inactive,
3190 loader,
3191 None,
3192 document.status_code(),
3193 Default::default(),
3194 false,
3195 document.allow_declarative_shadow_roots(),
3196 Some(document.insecure_requests_policy()),
3197 document.has_trustworthy_ancestor_or_current_origin(),
3198 document.custom_element_reaction_stack(),
3199 document.creation_sandboxing_flag_set(),
3200 document.pipeline_id(),
3201 document.image_cache(),
3202 );
3203 DomRoot::upcast::<Node>(document)
3207 },
3208 NodeTypeId::Element(..) => {
3210 let element = node.downcast::<Element>().unwrap();
3211 let registry = element.custom_element_registry().or(registry);
3214 let registry =
3217 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3218 document.effective_global_custom_element_registry()
3219 } else {
3220 registry
3221 };
3222 let name = QualName {
3226 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3227 ns: element.namespace().clone(),
3228 local: element.local_name().clone(),
3229 };
3230 let element = Element::create(
3231 cx,
3232 name,
3233 element.get_is(),
3234 &document,
3235 ElementCreator::ScriptCreated,
3236 CustomElementCreationMode::Asynchronous,
3237 None,
3238 );
3239 element.set_custom_element_registry(registry.as_deref(), cx.no_gc());
3241 DomRoot::upcast::<Node>(element)
3242 },
3243 };
3244
3245 let document = match copy.downcast::<Document>() {
3248 Some(doc) => DomRoot::from_ref(doc),
3249 None => DomRoot::from_ref(&*document),
3250 };
3251 assert!(copy.owner_doc() == document);
3252
3253 match node.type_id() {
3255 NodeTypeId::Document(_) => {
3256 let node_doc = node.downcast::<Document>().unwrap();
3257 let copy_doc = copy.downcast::<Document>().unwrap();
3258 copy_doc.set_encoding(node_doc.encoding());
3259 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3260 },
3261 NodeTypeId::Element(..) => {
3262 let node_elem = node.downcast::<Element>().unwrap();
3263 let copy_elem = copy.downcast::<Element>().unwrap();
3264
3265 node_elem.copy_all_attributes_to_other_element(cx, copy_elem);
3267 },
3268 _ => (),
3269 }
3270
3271 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3274
3275 if clone_children == CloneChildrenFlag::CloneChildren {
3278 for child in node.children() {
3279 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3280 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3281 }
3282 }
3283
3284 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3287 let node_elem = node.downcast::<Element>().unwrap();
3288 let copy_elem = copy.downcast::<Element>().unwrap();
3289
3290 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3291 assert!(!copy_elem.is_shadow_host());
3293
3294 let copy_shadow_root =
3298 copy_elem.attach_shadow(
3299 cx,
3300 IsUserAgentWidget::No,
3301 shadow_root.Mode(),
3302 shadow_root.Clonable(),
3303 shadow_root.Serializable(),
3304 shadow_root.DelegatesFocus(),
3305 shadow_root.SlotAssignment(),
3306 )
3307 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3308
3309 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3311
3312 for child in shadow_root.upcast::<Node>().children() {
3315 let child_copy = Node::clone(
3316 cx,
3317 &child,
3318 Some(&document),
3319 CloneChildrenFlag::CloneChildren,
3320 None,
3321 );
3322
3323 let _inserted_node =
3325 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3326 }
3327 }
3328 }
3329
3330 copy
3332 }
3333
3334 pub(crate) fn child_text_content(&self) -> DOMString {
3336 Node::collect_text_contents(self.children())
3337 }
3338
3339 pub(crate) fn descendant_text_content(&self) -> DOMString {
3341 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3342 }
3343
3344 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3345 iterator: T,
3346 ) -> DOMString {
3347 let mut content = String::new();
3348 for node in iterator {
3349 if let Some(text) = node.downcast::<Text>() {
3350 content.push_str(&text.upcast::<CharacterData>().data());
3351 }
3352 }
3353 DOMString::from(content)
3354 }
3355
3356 pub(crate) fn set_text_content_for_element(
3358 &self,
3359 cx: &mut JSContext,
3360 value: Option<DOMString>,
3361 ) {
3362 assert!(matches!(
3365 self.type_id(),
3366 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3367 ));
3368 let value = value.unwrap_or_default();
3369 let node = if value.is_empty() {
3370 None
3372 } else {
3373 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3376 };
3377
3378 Self::replace_all(cx, node.as_deref(), self);
3380 }
3381
3382 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3383 match namespace {
3384 ns!() => None,
3385 _ => Some(DOMString::from(&*namespace)),
3387 }
3388 }
3389
3390 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3392 match node.type_id() {
3393 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3394 NodeTypeId::Attr => node
3395 .downcast::<Attr>()
3396 .unwrap()
3397 .GetOwnerElement()
3398 .as_ref()
3399 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3400 NodeTypeId::Document(_) => node
3401 .downcast::<Document>()
3402 .unwrap()
3403 .GetDocumentElement()
3404 .as_ref()
3405 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3406 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3407 _ => node
3408 .GetParentElement()
3409 .as_ref()
3410 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3411 }
3412 }
3413
3414 #[expect(unsafe_code)]
3422 pub(crate) unsafe fn from_untrusted_node_address(
3423 candidate: UntrustedNodeAddress,
3424 ) -> &'static Self {
3425 let candidate = candidate.0 as usize;
3427 let object = candidate as *mut JSObject;
3428 if object.is_null() {
3429 panic!("Attempted to create a `Node` from an invalid pointer!")
3430 }
3431
3432 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3433 }
3434
3435 pub(crate) fn html_serialize(
3436 &self,
3437 cx: &mut JSContext,
3438 traversal_scope: html_serialize::TraversalScope,
3439 serialize_shadow_roots: bool,
3440 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3441 ) -> DOMString {
3442 let mut writer = vec![];
3443 let mut serializer = HtmlSerializer::new(
3444 &mut writer,
3445 html_serialize::SerializeOpts {
3446 traversal_scope: traversal_scope.clone(),
3447 ..Default::default()
3448 },
3449 );
3450
3451 serialize_html_fragment(
3452 cx,
3453 self,
3454 &mut serializer,
3455 traversal_scope,
3456 serialize_shadow_roots,
3457 shadow_roots,
3458 )
3459 .expect("Serializing node failed");
3460
3461 DOMString::from(String::from_utf8(writer).unwrap())
3463 }
3464
3465 pub(crate) fn xml_serialize(
3467 &self,
3468 traversal_scope: xml_serialize::TraversalScope,
3469 ) -> Fallible<DOMString> {
3470 let mut writer = vec![];
3471 xml_serialize::serialize(
3472 &mut writer,
3473 &HtmlSerialize::new(self),
3474 xml_serialize::SerializeOpts { traversal_scope },
3475 )
3476 .map_err(|error| {
3477 error!("Cannot serialize node: {error}");
3478 Error::InvalidState(Some("Cannot serialize node".into()))
3479 })?;
3480
3481 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3483 error!("Cannot serialize node: {error}");
3484 Error::InvalidState(Some("Cannot serialize node".into()))
3485 })?);
3486
3487 Ok(string)
3488 }
3489
3490 pub(crate) fn fragment_serialization_algorithm(
3492 &self,
3493 cx: &mut JSContext,
3494 require_well_formed: bool,
3495 ) -> Fallible<DOMString> {
3496 let context_document = self.owner_document();
3498
3499 if context_document.is_html_document() {
3502 return Ok(self.html_serialize(
3503 cx,
3504 html_serialize::TraversalScope::ChildrenOnly(None),
3505 false,
3506 vec![],
3507 ));
3508 }
3509
3510 let _ = require_well_formed;
3513 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3514 }
3515
3516 pub(crate) fn get_next_sibling_unrooted<'a>(
3517 &self,
3518 no_gc: &'a NoGC,
3519 ) -> Option<UnrootedDom<'a, Node>> {
3520 self.next_sibling.get_unrooted(no_gc)
3521 }
3522
3523 pub(crate) fn next_flat_tree_sibling_unrooted<'a>(
3524 &self,
3525 no_gc: &'a NoGC,
3526 ) -> Option<UnrootedDom<'a, Node>> {
3527 if let Some(slot_element) = self.assigned_slot() {
3528 return slot_element
3532 .assigned_nodes()
3533 .iter()
3534 .skip_while(|slottable| &*slottable.0 != self)
3535 .nth(1)
3537 .map(|next_slottable| next_slottable.0.as_unrooted(no_gc));
3538 }
3539 self.get_next_sibling_unrooted(no_gc)
3540 }
3541
3542 pub(crate) fn get_previous_sibling_unrooted<'a>(
3543 &self,
3544 no_gc: &'a NoGC,
3545 ) -> Option<UnrootedDom<'a, Node>> {
3546 self.prev_sibling.get_unrooted(no_gc)
3547 }
3548
3549 pub(crate) fn get_first_child_unrooted<'a>(
3550 &self,
3551 no_gc: &'a NoGC,
3552 ) -> Option<UnrootedDom<'a, Node>> {
3553 self.first_child.get_unrooted(no_gc)
3554 }
3555
3556 pub(crate) fn first_flat_tree_child_unrooted<'a>(
3557 &self,
3558 no_gc: &'a NoGC,
3559 ) -> Option<UnrootedDom<'a, Node>> {
3560 let Some(element) = self.downcast::<Element>() else {
3561 return self.get_first_child_unrooted(no_gc);
3562 };
3563 if let Some(shadow_root) = element.shadow_root_unrooted(no_gc) {
3564 return shadow_root
3565 .upcast::<Node>()
3566 .first_flat_tree_child_unrooted(no_gc);
3567 };
3568
3569 if let Some(slot_element) = element.downcast::<HTMLSlotElement>() &&
3573 slot_element.has_assigned_nodes() &&
3574 let Some(assigned_node) = slot_element.assigned_nodes().first()
3575 {
3576 return Some(assigned_node.0.as_unrooted(no_gc));
3577 }
3578
3579 self.get_first_child_unrooted(no_gc)
3580 }
3581
3582 fn get_last_child_unrooted<'b>(&self, no_gc: &'b NoGC) -> Option<UnrootedDom<'b, Node>> {
3583 self.last_child.get_unrooted(no_gc)
3584 }
3585
3586 pub(crate) fn get_parent_node_unrooted<'a>(
3587 &self,
3588 no_gc: &'a NoGC,
3589 ) -> Option<UnrootedDom<'a, Node>> {
3590 self.parent_node.get_unrooted(no_gc)
3591 }
3592
3593 pub(crate) fn compare_dom_tree_position(
3595 &self,
3596 other: &Node,
3597 common_ancestor: &Node,
3598 shadow_including: ShadowIncluding,
3599 ) -> Ordering {
3600 debug_assert!(
3601 self.inclusive_ancestors(shadow_including)
3602 .any(|ancestor| &*ancestor == common_ancestor)
3603 );
3604 debug_assert!(
3605 other
3606 .inclusive_ancestors(shadow_including)
3607 .any(|ancestor| &*ancestor == common_ancestor)
3608 );
3609
3610 if self == other {
3611 return Ordering::Equal;
3612 }
3613
3614 if self == common_ancestor {
3615 return Ordering::Less;
3616 }
3617 if other == common_ancestor {
3618 return Ordering::Greater;
3619 }
3620
3621 let my_ancestors: Vec<_> = self
3622 .inclusive_ancestors(shadow_including)
3623 .take_while(|ancestor| &**ancestor != common_ancestor)
3624 .collect();
3625 let other_ancestors: Vec<_> = other
3626 .inclusive_ancestors(shadow_including)
3627 .take_while(|ancestor| &**ancestor != common_ancestor)
3628 .collect();
3629
3630 let mut i = my_ancestors.len() - 1;
3632 let mut j = other_ancestors.len() - 1;
3633
3634 while my_ancestors[i] == other_ancestors[j] {
3635 if i == 0 {
3636 debug_assert_ne!(j, 0, "Equal inclusive ancestors but nodes are not equal?");
3638 return Ordering::Less;
3639 }
3640 if j == 0 {
3641 return Ordering::Greater;
3643 }
3644
3645 i -= 1;
3646 j -= 1;
3647 }
3648
3649 if my_ancestors[i]
3652 .preceding_siblings()
3653 .any(|sibling| sibling == other_ancestors[j])
3654 {
3655 Ordering::Greater
3657 } else {
3658 debug_assert!(
3660 other_ancestors[j]
3661 .preceding_siblings()
3662 .any(|sibling| sibling == my_ancestors[i])
3663 );
3664 Ordering::Less
3665 }
3666 }
3667}
3668
3669impl NodeMethods<crate::DomTypeHolder> for Node {
3670 fn NodeType(&self) -> u16 {
3672 match self.type_id() {
3673 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3674 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3675 NodeConstants::TEXT_NODE
3676 },
3677 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3678 NodeConstants::CDATA_SECTION_NODE
3679 },
3680 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3681 NodeConstants::PROCESSING_INSTRUCTION_NODE
3682 },
3683 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3684 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3685 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3686 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3687 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3688 }
3689 }
3690
3691 fn NodeName(&self) -> DOMString {
3693 match self.type_id() {
3694 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3695 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3696 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3697 DOMString::from_static("#text")
3698 },
3699 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3700 DOMString::from_static("#cdata-section")
3701 },
3702 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3703 self.downcast::<ProcessingInstruction>().unwrap().Target()
3704 },
3705 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => {
3706 DOMString::from_static("#comment")
3707 },
3708 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3709 NodeTypeId::DocumentFragment(_) => DOMString::from_static("#document-fragment"),
3710 NodeTypeId::Document(_) => DOMString::from_static("#document"),
3711 }
3712 }
3713
3714 fn BaseURI(&self) -> USVString {
3716 USVString(String::from(self.owner_doc().base_url().as_str()))
3717 }
3718
3719 fn IsConnected(&self) -> bool {
3721 self.is_connected()
3722 }
3723
3724 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3726 match self.type_id() {
3727 NodeTypeId::Document(_) => None,
3728 _ => Some(self.owner_doc()),
3729 }
3730 }
3731
3732 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3734 if !options.composed &&
3735 let Some(shadow_root) = self.containing_shadow_root()
3736 {
3737 return DomRoot::upcast(shadow_root);
3738 }
3739
3740 if self.is_connected() {
3741 DomRoot::from_ref(self.owner_doc().upcast::<Node>())
3742 } else {
3743 self.inclusive_ancestors(ShadowIncluding::Yes)
3744 .last()
3745 .unwrap()
3746 }
3747 }
3748
3749 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
3751 self.parent_node().get()
3752 }
3753
3754 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
3756 self.GetParentNode().and_then(DomRoot::downcast)
3757 }
3758
3759 fn HasChildNodes(&self) -> bool {
3761 self.first_child().get().is_some()
3762 }
3763
3764 fn ChildNodes(&self, cx: &mut JSContext) -> DomRoot<NodeList> {
3766 if let Some(list) = self.ensure_rare_data().child_list.get() {
3767 return list;
3768 }
3769
3770 let doc = self.owner_doc();
3771 let window = doc.window();
3772 let list = NodeList::new_child_list(cx, window, self);
3773 self.ensure_rare_data().child_list.set(Some(&list));
3774 list
3775 }
3776
3777 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
3779 self.first_child().get()
3780 }
3781
3782 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
3784 self.last_child().get()
3785 }
3786
3787 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
3789 self.prev_sibling().get()
3790 }
3791
3792 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
3794 self.next_sibling().get()
3795 }
3796
3797 fn GetNodeValue(&self) -> Option<DOMString> {
3799 match self.type_id() {
3800 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3801 NodeTypeId::CharacterData(_) => {
3802 self.downcast::<CharacterData>().map(CharacterData::Data)
3803 },
3804 _ => None,
3805 }
3806 }
3807
3808 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
3810 match self.type_id() {
3811 NodeTypeId::Attr => {
3812 let attr = self.downcast::<Attr>().unwrap();
3813 attr.SetValue(cx, val.unwrap_or_default())?;
3814 },
3815 NodeTypeId::CharacterData(_) => {
3816 let character_data = self.downcast::<CharacterData>().unwrap();
3817 character_data.SetData(cx, val.unwrap_or_default());
3818 },
3819 _ => {},
3820 };
3821 Ok(())
3822 }
3823
3824 fn GetTextContent(&self) -> Option<DOMString> {
3826 match self.type_id() {
3827 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3828 let content =
3829 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
3830 Some(content)
3831 },
3832 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3833 NodeTypeId::CharacterData(..) => {
3834 let characterdata = self.downcast::<CharacterData>().unwrap();
3835 Some(characterdata.Data())
3836 },
3837 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
3838 }
3839 }
3840
3841 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
3843 match self.type_id() {
3844 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3845 self.set_text_content_for_element(cx, value);
3846 },
3847 NodeTypeId::Attr => {
3848 let attr = self.downcast::<Attr>().unwrap();
3849 attr.SetValue(cx, value.unwrap_or_default())?;
3850 },
3851 NodeTypeId::CharacterData(..) => {
3852 let characterdata = self.downcast::<CharacterData>().unwrap();
3853 characterdata.SetData(cx, value.unwrap_or_default());
3854 },
3855 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
3856 };
3857 Ok(())
3858 }
3859
3860 fn InsertBefore(
3862 &self,
3863 cx: &mut JSContext,
3864 node: &Node,
3865 child: Option<&Node>,
3866 ) -> Fallible<DomRoot<Node>> {
3867 Node::pre_insert(cx, node, self, child)
3868 }
3869
3870 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3872 Node::pre_insert(cx, node, self, None)
3873 }
3874
3875 fn ReplaceChild(
3877 &self,
3878 cx: &mut JSContext,
3879 node: &Node,
3880 child: &Node,
3881 ) -> Fallible<DomRoot<Node>> {
3882 match self.type_id() {
3885 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3886 },
3887 _ => {
3888 return Err(Error::HierarchyRequest(Some(
3889 "Parent is not a Document, DocumentFragment, or Element node".into(),
3890 )));
3891 },
3892 }
3893
3894 if node.is_inclusive_ancestor_of(self) {
3897 return Err(Error::HierarchyRequest(Some(
3898 "Node cannot be a host-including ancestor of parent".into(),
3899 )));
3900 }
3901
3902 if !self.is_parent_of(child) {
3904 return Err(Error::NotFound(Some(
3905 "Parent node provided does not match child's parent node".into(),
3906 )));
3907 }
3908
3909 match node.type_id() {
3914 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
3915 return Err(Error::HierarchyRequest(Some(
3916 "Node cannot be a Text node while parent is a document".into(),
3917 )));
3918 },
3919 NodeTypeId::DocumentType if !self.is::<Document>() => {
3920 return Err(Error::HierarchyRequest(Some(
3921 "Node cannot be a doctype when parent is not a document".into(),
3922 )));
3923 },
3924 NodeTypeId::Document(_) | NodeTypeId::Attr => {
3925 return Err(Error::HierarchyRequest(Some(
3926 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
3927 .into(),
3928 )));
3929 },
3930 _ => (),
3931 }
3932
3933 if self.is::<Document>() {
3936 match node.type_id() {
3937 NodeTypeId::DocumentFragment(_) => {
3939 if node.children_unrooted(cx.no_gc()).any(|c| c.is::<Text>()) {
3941 return Err(Error::HierarchyRequest(Some(
3942 "Parent is a document and node has a Text node child".into(),
3943 )));
3944 }
3945 match node.child_elements_unrooted(cx.no_gc()).count() {
3946 0 => (),
3947 1 => {
3949 if self
3950 .child_elements_unrooted(cx.no_gc())
3951 .any(|c| c.upcast::<Node>() != child)
3952 {
3953 return Err(Error::HierarchyRequest(Some(
3954 "Node has one element child and parent's children elements does not include child provided"
3955 .into(),
3956 )));
3957 }
3958 if child.following_siblings().any(|child| child.is_doctype()) {
3959 return Err(Error::HierarchyRequest(Some(
3960 "Node cannot have element child of type document".into(),
3961 )));
3962 }
3963 },
3964 _ => {
3966 return Err(Error::HierarchyRequest(Some(
3967 "Node cannot have more than one child element".into(),
3968 )));
3969 },
3970 }
3971 },
3972 NodeTypeId::Element(..) => {
3974 if self
3975 .child_elements_unrooted(cx.no_gc())
3976 .any(|c| c.upcast::<Node>() != child)
3977 {
3978 return Err(Error::HierarchyRequest(Some(
3979 "Parent's children elements does not include child provided".into(),
3980 )));
3981 }
3982 if child.following_siblings().any(|child| child.is_doctype()) {
3983 return Err(Error::HierarchyRequest(Some(
3984 "Node cannot have element child of type document".into(),
3985 )));
3986 }
3987 },
3988 NodeTypeId::DocumentType => {
3990 if self
3991 .children_unrooted(cx.no_gc())
3992 .any(|c| c.is_doctype() && *c != child)
3993 {
3994 return Err(Error::HierarchyRequest(Some(
3995 "Parent cannot have a doctype child".into(),
3996 )));
3997 }
3998 if self
3999 .children_unrooted(cx.no_gc())
4000 .take_while(|c| **c != child)
4001 .any(|c| c.is::<Element>())
4002 {
4003 return Err(Error::HierarchyRequest(Some(
4004 "An element cannot precede the child given".into(),
4005 )));
4006 }
4007 },
4008 NodeTypeId::CharacterData(..) => (),
4009 NodeTypeId::Document(_) => unreachable!(),
4012 NodeTypeId::Attr => unreachable!(),
4013 }
4014 }
4015
4016 let child_next_sibling = child.GetNextSibling();
4019 let node_next_sibling = node.GetNextSibling();
4020 let reference_child = if child_next_sibling.as_deref() == Some(node) {
4021 node_next_sibling.as_deref()
4022 } else {
4023 child_next_sibling.as_deref()
4024 };
4025
4026 let previous_sibling = child.GetPreviousSibling();
4028
4029 let document = self.owner_document();
4033 Node::adopt(cx, node, &document);
4034
4035 let removed_child = if node != child {
4040 Node::remove(cx, child, self, SuppressObserver::Suppressed);
4042 Some(child)
4043 } else {
4044 None
4045 };
4046
4047 rooted_vec!(let mut nodes);
4049 let nodes = if node.type_id() ==
4050 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
4051 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
4052 {
4053 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
4054 nodes.r()
4055 } else {
4056 from_ref(&node)
4057 };
4058
4059 Node::insert(
4061 cx,
4062 node,
4063 self,
4064 reference_child,
4065 SuppressObserver::Suppressed,
4066 );
4067
4068 vtable_for(self).children_changed(
4069 cx,
4070 &ChildrenMutation::replace(
4071 previous_sibling.as_deref(),
4072 &removed_child,
4073 reference_child,
4074 ),
4075 );
4076
4077 let removed = removed_child.map(|r| [r]);
4080 let mutation = LazyCell::new(|| Mutation::ChildList {
4081 added: Some(nodes),
4082 removed: removed.as_ref().map(|r| &r[..]),
4083 prev: previous_sibling.as_deref(),
4084 next: reference_child,
4085 });
4086
4087 MutationObserver::queue_a_mutation_record(cx, self, mutation);
4088
4089 Ok(DomRoot::from_ref(child))
4091 }
4092
4093 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
4095 Node::pre_remove(cx, node, self)
4096 }
4097
4098 fn Normalize(&self, cx: &mut JSContext) {
4100 let mut children = self.children().peekable();
4101
4102 let document = self.owner_document();
4103 let selection = document.selection();
4104 while let Some(node) = children.next() {
4105 let Some(text) = node.downcast::<Text>() else {
4108 node.Normalize(cx);
4109 continue;
4110 };
4111 if text.is::<CDATASection>() {
4112 continue;
4113 }
4114
4115 let cdata = text.upcast::<CharacterData>();
4117 let mut length = cdata.Length();
4118
4119 if length == 0 {
4122 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
4123 continue;
4124 }
4125
4126 let mut siblings_to_merge: SmallVec<[DomRoot<CharacterData>; 4]> = SmallVec::new();
4129 let mut new_data_length = 0;
4130 while let Some(sibling) = children.peek() {
4131 if !sibling.is::<Text>() || sibling.is::<CDATASection>() {
4132 break;
4133 }
4134
4135 let sibling: DomRoot<CharacterData> =
4136 DomRoot::downcast(children.next().expect("Guaranteed by the peek above"))
4137 .expect("Guaranteed by check above");
4138 new_data_length += sibling.data().len();
4139 siblings_to_merge.push(sibling);
4140 }
4141
4142 if siblings_to_merge.is_empty() {
4143 continue;
4144 }
4145
4146 let mut data = String::with_capacity(new_data_length);
4149 for sibling in &siblings_to_merge {
4150 data.push_str(sibling.data().as_str());
4151 }
4152
4153 cdata.append_data(cx, &data);
4155
4156 let first_sibling_index = LazyCell::new(|| node.index() + 1);
4160 for (current_node_index, current_node) in siblings_to_merge.iter().enumerate() {
4161 let index = &|| *first_sibling_index + current_node_index as u32;
4162 if let Some(selection) = &selection {
4164 selection.normalization_steps(
4165 self,
4166 &node,
4167 current_node.upcast(),
4168 &index,
4169 length,
4170 );
4171 }
4172 document.live_range_normalization_steps(
4173 cx.no_gc(),
4174 self,
4175 &node,
4176 current_node.upcast(),
4177 &index,
4178 length,
4179 );
4180 length += current_node.Length();
4182 }
4185
4186 for current_node in siblings_to_merge.into_iter() {
4189 Node::remove(
4190 cx,
4191 current_node.upcast(),
4192 self,
4193 SuppressObserver::Unsuppressed,
4194 );
4195 }
4196 }
4197 }
4198
4199 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
4201 if self.is::<ShadowRoot>() {
4203 return Err(Error::NotSupported(Some(
4204 "Cannot clone a shadow root".into(),
4205 )));
4206 }
4207
4208 let result = Node::clone(
4210 cx,
4211 self,
4212 None,
4213 if subtree {
4214 CloneChildrenFlag::CloneChildren
4215 } else {
4216 CloneChildrenFlag::DoNotCloneChildren
4217 },
4218 None,
4219 );
4220 Ok(result)
4221 }
4222
4223 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
4225 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
4226 let doctype = node.downcast::<DocumentType>().unwrap();
4227 let other_doctype = other.downcast::<DocumentType>().unwrap();
4228 (*doctype.name() == *other_doctype.name()) &&
4229 (*doctype.public_id() == *other_doctype.public_id()) &&
4230 (*doctype.system_id() == *other_doctype.system_id())
4231 }
4232 fn is_equal_element(node: &Node, other: &Node) -> bool {
4233 let element = node.downcast::<Element>().unwrap();
4234 let other_element = other.downcast::<Element>().unwrap();
4235 (*element.namespace() == *other_element.namespace()) &&
4236 (*element.prefix() == *other_element.prefix()) &&
4237 (*element.local_name() == *other_element.local_name()) &&
4238 (element.attrs().borrow().len() == other_element.attrs().borrow().len())
4239 }
4240 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
4241 let pi = node.downcast::<ProcessingInstruction>().unwrap();
4242 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
4243 (*pi.target() == *other_pi.target()) &&
4244 (*pi.upcast::<CharacterData>().data() ==
4245 *other_pi.upcast::<CharacterData>().data())
4246 }
4247 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
4248 let characterdata = node.downcast::<CharacterData>().unwrap();
4249 let other_characterdata = other.downcast::<CharacterData>().unwrap();
4250 *characterdata.data() == *other_characterdata.data()
4251 }
4252 fn is_equal_attr(node: &Node, other: &Node) -> bool {
4253 let attr = node.downcast::<Attr>().unwrap();
4254 let other_attr = other.downcast::<Attr>().unwrap();
4255 (*attr.namespace() == *other_attr.namespace()) &&
4256 (attr.local_name() == other_attr.local_name()) &&
4257 (**attr.value() == **other_attr.value())
4258 }
4259 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
4260 let element = node.downcast::<Element>().unwrap();
4261 let other_element = other.downcast::<Element>().unwrap();
4262 assert!(element.attrs().borrow().len() == other_element.attrs().borrow().len());
4263 element.attrs().borrow().iter().all(|attr| {
4264 other_element.attrs().borrow().iter().any(|other_attr| {
4265 (*attr.namespace() == *other_attr.namespace()) &&
4266 (attr.local_name() == other_attr.local_name()) &&
4267 (**attr.value() == **other_attr.value())
4268 })
4269 })
4270 }
4271
4272 fn is_equal_node(this: &Node, node: &Node) -> bool {
4273 if this.NodeType() != node.NodeType() {
4275 return false;
4276 }
4277
4278 match node.type_id() {
4279 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
4281 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
4282 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
4283 if !is_equal_processinginstruction(this, node) =>
4284 {
4285 return false;
4286 },
4287 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
4288 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
4289 if !is_equal_characterdata(this, node) =>
4290 {
4291 return false;
4292 },
4293 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
4295 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
4296
4297 _ => (),
4298 }
4299
4300 if this.children_count() != node.children_count() {
4302 return false;
4303 }
4304
4305 this.children()
4307 .zip(node.children())
4308 .all(|(child, other_child)| is_equal_node(&child, &other_child))
4309 }
4310 match maybe_node {
4311 None => false,
4313 Some(node) => is_equal_node(self, node),
4315 }
4316 }
4317
4318 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
4320 match other_node {
4321 Some(node) => self == node,
4322 None => false,
4323 }
4324 }
4325
4326 fn CompareDocumentPosition(&self, no_gc: &NoGC, other: &Node) -> u16 {
4328 if self == other {
4330 return 0;
4331 }
4332
4333 let mut node1 = Some(other);
4335 let mut node2 = Some(self);
4336
4337 let mut attr1: Option<&Attr> = None;
4339 let mut attr2: Option<&Attr> = None;
4340
4341 let attr1owner;
4346 if let Some(a) = other.downcast::<Attr>() {
4347 attr1 = Some(a);
4348 attr1owner = a.GetOwnerElement();
4349 node1 = match attr1owner {
4350 Some(ref e) => Some(e.upcast()),
4351 None => None,
4352 }
4353 }
4354
4355 let attr2owner;
4358 if let Some(a) = self.downcast::<Attr>() {
4359 attr2 = Some(a);
4360 attr2owner = a.GetOwnerElement();
4361 node2 = match attr2owner {
4362 Some(ref e) => Some(e.upcast()),
4363 None => None,
4364 }
4365 }
4366
4367 if let Some(node2) = node2 &&
4372 Some(node2) == node1 &&
4373 let (Some(a1), Some(a2)) = (attr1, attr2)
4374 {
4375 let attrs = node2.downcast::<Element>().unwrap().attrs();
4376 for attr in attrs.borrow().iter() {
4380 if (*attr.namespace() == *a1.namespace()) &&
4381 (attr.local_name() == a1.local_name()) &&
4382 (**attr.value() == **a1.value())
4383 {
4384 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4385 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4386 }
4387 if (*attr.namespace() == *a2.namespace()) &&
4388 (attr.local_name() == a2.local_name()) &&
4389 (**attr.value() == **a2.value())
4390 {
4391 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4392 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4393 }
4394 }
4395 unreachable!();
4398 }
4399
4400 let options = GetRootNodeOptions { composed: false };
4406 let node1_root = node1.map(|node| node.GetRootNode(&options));
4407 let node2_root = node2.map(|node| node.GetRootNode(&options));
4408 if node1_root.is_none() || node2_root.is_none() || node1_root != node2_root {
4409 let pointer1 = node1.map(as_uintptr::<Node>).unwrap_or_default();
4412 let pointer2 = node2.map(as_uintptr::<Node>).unwrap_or_default();
4413 let arbitrary_order = if pointer1 < pointer2 {
4414 NodeConstants::DOCUMENT_POSITION_PRECEDING
4415 } else {
4416 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4417 };
4418
4419 return arbitrary_order +
4420 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4421 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4422 }
4423
4424 let (ordering, containment_flags) = match (node1, node2) {
4426 (Some(node1), Some(node2)) => {
4427 compare_dom_positions::<LightDomNoGcTraversal>(no_gc, node1, 0, node2, 0)
4428 },
4429 _ => (None, DomPositionContainment::empty()),
4430 };
4431
4432 if (containment_flags.contains(DomPositionContainment::AContainsB) && attr1.is_none()) ||
4436 (node1 == node2 && attr2.is_some())
4437 {
4438 return NodeConstants::DOCUMENT_POSITION_CONTAINS +
4439 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4440 }
4441
4442 if (containment_flags.contains(DomPositionContainment::BContainsA) && attr2.is_none()) ||
4446 (node1 == node2 && attr1.is_some())
4447 {
4448 return NodeConstants::DOCUMENT_POSITION_CONTAINED_BY +
4449 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4450 }
4451
4452 if ordering == Some(Ordering::Less) {
4454 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4455 }
4456
4457 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4459 }
4460
4461 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4463 match maybe_other {
4464 None => false,
4465 Some(other) => self.is_inclusive_ancestor_of(other),
4466 }
4467 }
4468
4469 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4471 let namespace = namespace_from_domstring(namespace);
4472
4473 if namespace == ns!() {
4475 return None;
4476 }
4477
4478 match self.type_id() {
4480 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4481 NodeTypeId::Document(_) => self
4482 .downcast::<Document>()
4483 .unwrap()
4484 .GetDocumentElement()
4485 .and_then(|element| element.lookup_prefix(namespace)),
4486 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4487 NodeTypeId::Attr => self
4488 .downcast::<Attr>()
4489 .unwrap()
4490 .GetOwnerElement()
4491 .and_then(|element| element.lookup_prefix(namespace)),
4492 _ => self
4493 .GetParentElement()
4494 .and_then(|element| element.lookup_prefix(namespace)),
4495 }
4496 }
4497
4498 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4500 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4502
4503 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4505 }
4506
4507 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4509 let namespace = namespace_from_domstring(namespace);
4511 Node::locate_namespace(self, None) == namespace
4513 }
4514}
4515
4516pub(crate) trait NodeTraits {
4517 fn owner_document(&self) -> DomRoot<Document>;
4521 fn owner_window(&self) -> DomRoot<Window>;
4525 fn owner_global(&self) -> DomRoot<GlobalScope>;
4529 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4531 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4534}
4535
4536impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4537 fn owner_document(&self) -> DomRoot<Document> {
4538 self.upcast().owner_doc()
4539 }
4540
4541 fn owner_window(&self) -> DomRoot<Window> {
4542 DomRoot::from_ref(self.owner_document().window())
4543 }
4544
4545 fn owner_global(&self) -> DomRoot<GlobalScope> {
4546 DomRoot::from_ref(self.owner_window().upcast())
4547 }
4548
4549 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4550 Node::containing_shadow_root(self.upcast())
4551 }
4552
4553 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4554 self.containing_shadow_root()
4555 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4556 .unwrap_or_else(|| {
4557 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4558 })
4559 }
4560}
4561
4562impl VirtualMethods for Node {
4563 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4564 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4565 }
4566
4567 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4568 if let Some(s) = self.super_type() {
4569 s.children_changed(cx, mutation);
4570 }
4571
4572 if let Some(data) = self.rare_data.borrow().as_ref() &&
4573 let Some(list) = data.child_list.get()
4574 {
4575 list.as_children_list().children_changed(mutation);
4576 }
4577
4578 self.owner_doc_unrooted(cx.no_gc())
4579 .content_and_heritage_changed(cx.no_gc(), self);
4580 }
4581
4582 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
4583 if let Some(super_type) = self.super_type() {
4584 super_type.moving_steps(cx, context);
4585 }
4586
4587 self.owner_doc_unrooted(cx.no_gc())
4588 .content_and_heritage_changed(cx.no_gc(), self);
4589
4590 if let Some(parent) = self.GetParentNode() {
4591 Self::maybe_dirty_visible_selection_for_newly_inserted_nodes(
4592 cx.no_gc(),
4593 &parent,
4594 &[self],
4595 );
4596 }
4597 }
4598
4599 fn handle_event(&self, cx: &mut JSContext, event: &Event) {
4600 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4601 return;
4602 }
4603
4604 if let Some(event) = event.downcast::<KeyboardEvent>() {
4605 self.owner_document()
4606 .event_handler()
4607 .run_default_keyboard_event_handler(cx, self, event);
4608 }
4609 }
4610
4611 fn handle_mousedown_event(
4612 &self,
4613 cx: &mut JSContext,
4614 event: &MouseEvent,
4615 hit_test_result: &HitTestResult,
4616 ) {
4617 assert_eq!(event.upcast::<Event>().type_(), atom!("mousedown"));
4618
4619 let document = self.owner_document();
4620 if event.button() == MouseButton::Auxiliary {
4621 let Some(selection) = document.selection() else {
4622 return;
4623 };
4624 let _ = selection.Collapse(cx, None, 0);
4625 event.upcast::<Event>().mark_as_handled();
4626 return;
4627 }
4628
4629 if event.button() != MouseButton::Primary {
4630 return;
4631 }
4632 let Some(selection) = document.GetSelection(cx) else {
4633 return;
4634 };
4635
4636 let (container, offset) = hit_test_result
4640 .dom_position_for_selection
4641 .as_ref()
4642 .map(|(node, offset)| (node, *offset))
4643 .unwrap_or((&hit_test_result.node, Utf32CodeUnitsOrNodeOffset(0)));
4644 let Some((container, offset, user_select_contain_node)) =
4645 adjust_anchor_for_user_select(cx, container.clone(), offset)
4646 else {
4647 return;
4648 };
4649 selection.collapse_to_dom_position(cx, &container, offset);
4650 document
4651 .event_handler()
4652 .install_drag_gesture(DragGesture::new(DragHandler::DocumentSelection(
4653 DocumentSelectionDragHandler::new(user_select_contain_node.as_deref()),
4654 )));
4655 event.upcast::<Event>().mark_as_handled();
4656 }
4657}
4658
4659#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4661pub(crate) enum NodeDamage {
4662 Style,
4664 ContentOrHeritage,
4667 Other,
4669}
4670
4671pub(crate) trait VecPreOrderInsertionHelper<T> {
4674 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
4675}
4676
4677impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
4678where
4679 T: DerivedFrom<Node> + DomObject,
4680{
4681 fn insert_pre_order(&mut self, node: &T, tree_root: &Node) {
4686 let Err(insertion_index) = self.binary_search_by(|candidate| {
4687 candidate.upcast().compare_dom_tree_position(
4688 node.upcast(),
4689 tree_root,
4690 ShadowIncluding::No,
4691 )
4692 }) else {
4693 return;
4696 };
4697
4698 self.insert(insertion_index, Dom::from_ref(node));
4699 }
4700}
4701
4702pub(crate) enum FlatTreeParent<'a> {
4704 Parent(UnrootedDom<'a, Node>),
4706 NotInFlatTree,
4709 RootNode,
4711}
4712
4713impl<'a> FlatTreeParent<'a> {
4714 pub(crate) fn into_parent(self) -> Option<UnrootedDom<'a, Node>> {
4715 match self {
4716 FlatTreeParent::Parent(parent) => Some(parent),
4717 FlatTreeParent::NotInFlatTree | FlatTreeParent::RootNode => None,
4718 }
4719 }
4720}