1use std::cell::{Cell, LazyCell, UnsafeCell};
8use std::cmp::Ordering;
9use std::default::Default;
10use std::f64::consts::PI;
11use std::ops::Deref;
12use std::rc::Rc;
13use std::slice::from_ref;
14use std::{cmp, fmt, iter};
15
16use app_units::Au;
17use bitflags::bitflags;
18use devtools_traits::NodeInfo;
19use dom_struct::dom_struct;
20use embedder_traits::UntrustedNodeAddress;
21use euclid::default::Size2D;
22use euclid::{Point2D, Rect};
23use html5ever::serialize::HtmlSerializer;
24use html5ever::{Namespace, Prefix, QualName, ns, serialize as html_serialize};
25use js::context::{JSContext, NoGC};
26use js::jsapi::JSObject;
27use js::rust::HandleObject;
28use keyboard_types::Modifiers;
29use layout_api::{
30 AccessibilityDamage, AxesOverflow, BoxAreaType, CSSPixelRectVec, GenericLayoutData,
31 NodeRenderingType, PhysicalSides, TrustedNodeAddress, with_layout_state,
32};
33use libc::{self, uintptr_t};
34use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
35use script_bindings::cell::{DomRefCell, Ref, RefMut};
36use script_bindings::codegen::GenericBindings::ElementBinding::ElementMethods;
37use script_bindings::codegen::GenericBindings::EventBinding::EventMethods;
38use script_bindings::codegen::GenericBindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
39use script_bindings::codegen::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;
45use servo_base::id::PipelineId;
46use servo_config::pref;
47use smallvec::SmallVec;
48use style::Atom;
49use style::context::QuirksMode;
50use style::dom::OpaqueNode;
51use style::dom_apis::{QueryAll, QueryFirst};
52use style::selector_parser::PseudoElement;
53use style_traits::CSSPixel;
54use uuid::Uuid;
55use xml5ever::{local_name, serialize as xml_serialize};
56
57use crate::conversions::Convert;
58use crate::dom::ChildrenMutation;
59use crate::dom::attr::Attr;
60use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
61use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
62use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
63use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
64use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
65use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
66use crate::dom::bindings::codegen::Bindings::NodeBinding::{
67 GetRootNodeOptions, NodeConstants, NodeMethods,
68};
69use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
70use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
71use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
72 ShadowRootMode, SlotAssignmentMode,
73};
74use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
75use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
76use crate::dom::bindings::conversions::{self, DerivedFrom};
77use crate::dom::bindings::domname::namespace_from_domstring;
78use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
79use crate::dom::bindings::inheritance::{
80 Castable, CharacterDataTypeId, EventTargetTypeId, NodeTypeId,
81};
82use crate::dom::bindings::root::{
83 Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout, UnrootedDom,
84};
85use crate::dom::bindings::str::{DOMString, USVString};
86use crate::dom::characterdata::CharacterData;
87use crate::dom::context::{BindContext, IsShadowTree, MoveContext, UnbindContext};
88use crate::dom::css::cssstylesheet::CSSStyleSheet;
89use crate::dom::css::stylesheetlist::StyleSheetListOwner;
90use crate::dom::customelementregistry::{
91 CallbackReaction, CustomElementRegistry, try_upgrade_element,
92};
93use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
94use crate::dom::documentfragment::DocumentFragment;
95use crate::dom::documenttype::DocumentType;
96use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
97use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
98use crate::dom::eventtarget::EventTarget;
99use crate::dom::globalscope::GlobalScope;
100use crate::dom::html::htmlcollection::HTMLCollection;
101use crate::dom::html::htmlelement::HTMLElement;
102use crate::dom::html::htmllinkelement::HTMLLinkElement;
103use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
104use crate::dom::html::htmlstyleelement::HTMLStyleElement;
105use crate::dom::iterators::{
106 ShadowIncluding, UnrootedFollowingFlatTreeNodesTraversal, UnrootedFollowingNodeIterator,
107 UnrootedPrecedingNodeIterator,
108};
109use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
110use crate::dom::node::iterators::{
111 FollowingNodeIterator, PrecedingNodeIterator, SimpleNodeIterator, TreeIterator,
112 UnrootedSimpleNodeIterator, UnrootedTreeIterator,
113};
114use crate::dom::node::nodelist::NodeList;
115use crate::dom::node::virtualmethods::{VirtualMethods, vtable_for};
116use crate::dom::pointerevent::{PointerEvent, PointerId};
117use crate::dom::range::WeakRangeVec;
118use crate::dom::raredata::NodeRareData;
119use crate::dom::servoparser::html::HtmlSerialize;
120use crate::dom::servoparser::serialize_html_fragment;
121use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
122use crate::dom::text::Text;
123use crate::dom::types::{CDATASection, KeyboardEvent, ProcessingInstruction};
124use crate::dom::window::Window;
125use crate::event_loop::document_loader::DocumentLoader;
126use crate::event_loop::script_thread::ScriptThread;
127use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode};
128
129#[dom_struct]
135pub struct Node {
136 eventtarget: EventTarget,
138
139 parent_node: MutNullableDom<Node>,
141
142 first_child: MutNullableDom<Node>,
144
145 last_child: MutNullableDom<Node>,
147
148 next_sibling: MutNullableDom<Node>,
150
151 prev_sibling: MutNullableDom<Node>,
153
154 owner_doc: MutNullableDom<Document>,
156
157 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
159
160 children_count: Cell<u32>,
162
163 flags: Cell<NodeFlags>,
165
166 inclusive_descendants_version: Cell<u64>,
168
169 #[no_trace]
172 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
173}
174
175impl fmt::Debug for Node {
176 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177 if let Some(element) = self.downcast::<Element>() {
178 element.fmt(f)
179 } else if let Some(character_data) = self.downcast::<CharacterData>() {
180 write!(f, "[Text({})]", *character_data.data())
181 } else {
182 write!(f, "[Node({:?})]", self.type_id())
183 }
184 }
185}
186
187#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
189pub(crate) struct NodeFlags(u16);
190
191bitflags! {
192 impl NodeFlags: u16 {
193 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
197
198 const HAS_DIRTY_DESCENDANTS = 1 << 1;
200
201 const CLICK_IN_PROGRESS = 1 << 2;
204
205 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
210
211 const HAS_SNAPSHOT = 1 << 7;
216
217 const HANDLED_SNAPSHOT = 1 << 8;
219
220 const IS_IN_SHADOW_TREE = 1 << 9;
222
223 const IS_CONNECTED = 1 << 10;
227
228 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
231
232 const IS_IN_UA_WIDGET = 1 << 12;
235
236 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
238
239 const OVERLAPS_DOCUMENT_SELECTION = 1 << 14;
246 }
247}
248
249#[derive(Clone, Copy, MallocSizeOf)]
253pub(crate) enum SuppressObserver {
254 Suppressed,
255 Unsuppressed,
256}
257
258pub(crate) enum ForceSlottableNodeReconciliation {
259 Force,
260 Skip,
261}
262
263impl Node {
264 pub(super) fn parent_node(&self) -> &MutNullableDom<Node> {
266 &self.parent_node
267 }
268
269 pub(super) fn first_child(&self) -> &MutNullableDom<Node> {
270 &self.first_child
271 }
272
273 pub(super) fn last_child(&self) -> &MutNullableDom<Node> {
274 &self.last_child
275 }
276
277 pub(super) fn next_sibling(&self) -> &MutNullableDom<Node> {
278 &self.next_sibling
279 }
280
281 pub(super) fn prev_sibling(&self) -> &MutNullableDom<Node> {
282 &self.prev_sibling
283 }
284
285 pub(super) fn get_owner_doc(&self) -> &MutNullableDom<Document> {
286 &self.owner_doc
287 }
288
289 pub(super) fn get_rare_data(&self) -> &DomRefCell<Option<Box<NodeRareData>>> {
290 &self.rare_data
291 }
292
293 pub(super) fn flags(&self) -> &Cell<NodeFlags> {
294 &self.flags
295 }
296
297 pub(super) fn layout_data(&self) -> &DomRefCell<Option<Box<GenericLayoutData>>> {
298 &self.layout_data
299 }
300
301 fn add_child(&self, cx: &mut JSContext, new_child: &Node, before: Option<&Node>) {
305 assert!(new_child.parent_node.get().is_none());
306 assert!(new_child.prev_sibling.get().is_none());
307 assert!(new_child.next_sibling.get().is_none());
308
309 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
310
311 match before {
312 Some(before) => {
313 assert!(before.parent_node.get().as_deref() == Some(self));
314 let prev_sibling = before.GetPreviousSibling();
315 match prev_sibling {
316 None => {
317 assert!(self.first_child.get().as_deref() == Some(before));
318 self.first_child.set(Some(new_child));
319 },
320 Some(ref prev_sibling) => {
321 prev_sibling.next_sibling.set(Some(new_child));
322 new_child.prev_sibling.set(Some(prev_sibling));
323 },
324 }
325 before.prev_sibling.set(Some(new_child));
326 new_child.next_sibling.set(Some(before));
327 },
328 None => {
329 let last_child = self.GetLastChild();
330 match last_child {
331 None => self.first_child.set(Some(new_child)),
332 Some(ref last_child) => {
333 assert!(last_child.next_sibling.get().is_none());
334 last_child.next_sibling.set(Some(new_child));
335 new_child.prev_sibling.set(Some(last_child));
336 },
337 }
338
339 self.last_child.set(Some(new_child));
340 },
341 }
342
343 new_child.parent_node.set(Some(self));
344 self.children_count.set(self.children_count.get() + 1);
345
346 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
347 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
348 let parent_is_connected = self.is_connected();
349 let parent_is_in_ua_widget = self.is_in_ua_widget();
350
351 let context = BindContext::new(self, IsShadowTree::No);
352
353 for node in new_child.traverse_preorder(ShadowIncluding::No) {
354 if parent_in_shadow_tree {
355 if let Some(shadow_root) = self.containing_shadow_root() {
356 node.set_containing_shadow_root(Some(&*shadow_root));
357 }
358 debug_assert!(node.containing_shadow_root().is_some());
359 }
360 node.set_flag(
361 NodeFlags::IS_IN_A_DOCUMENT_TREE,
362 parent_is_in_a_document_tree,
363 );
364 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
365 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
366 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
367
368 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
370 vtable_for(&node).bind_to_tree(cx, &context);
371 }
372 }
373
374 pub(crate) fn complete_remove_subtree(
377 cx: &mut JSContext,
378 root: &Node,
379 context: &UnbindContext,
380 ) {
381 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
383 .union(NodeFlags::IS_CONNECTED)
384 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
385 .union(NodeFlags::HAS_SNAPSHOT)
386 .union(NodeFlags::HANDLED_SNAPSHOT)
387 .union(NodeFlags::OVERLAPS_DOCUMENT_SELECTION);
388
389 for node in root.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No) {
390 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
391
392 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
395 for node in shadow_root
396 .upcast::<Node>()
397 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
398 {
399 node.set_flag(RESET_FLAGS, false);
400 }
401 }
402 }
403
404 let is_parent_connected = context.parent.is_connected();
406 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
407
408 let document = root.owner_doc();
411 let cleanup_node = |cx: &mut JSContext, node: &Node| {
412 document.cancel_animations_for_node(node);
413 document.clean_up_style_and_layout_data_for_node(node);
414
415 vtable_for(node).unbind_from_tree(cx, context);
420
421 if is_parent_connected && let Some(element) = node.as_custom_element() {
423 custom_element_reaction_stack.enqueue_callback_reaction(
424 cx,
425 &element,
426 CallbackReaction::Disconnected,
427 None,
428 );
429 }
430 };
431
432 for node in root.traverse_preorder(ShadowIncluding::No) {
433 cleanup_node(cx, &node);
434
435 if node.containing_shadow_root().is_some() {
438 node.set_containing_shadow_root(None);
441 }
442
443 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
446 for node in shadow_root
447 .upcast::<Node>()
448 .traverse_preorder(ShadowIncluding::Yes)
449 {
450 cleanup_node(cx, &node);
451 }
452 }
453 }
454
455 if root.owner_document().accessibility_active() {
458 root.owner_document()
459 .accessibility_data_mut()
460 .root_removed_node(cx.no_gc(), root);
461 }
462 }
463
464 pub(crate) fn complete_move_subtree(cx: &mut JSContext, root: &Node) {
465 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
467 .union(NodeFlags::IS_CONNECTED)
468 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
469 .union(NodeFlags::HAS_SNAPSHOT)
470 .union(NodeFlags::HANDLED_SNAPSHOT)
471 .union(NodeFlags::OVERLAPS_DOCUMENT_SELECTION);
472
473 let document = root.owner_document();
474 for node in root.traverse_preorder(ShadowIncluding::No) {
475 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
476 document.clean_up_style_and_layout_data_for_node(&node);
477
478 if let Some(element) = node.downcast::<Element>() {
481 element.unregister_current_id_and_name_attribute(cx);
482 }
483
484 if node.containing_shadow_root().is_some() {
487 node.set_containing_shadow_root(None);
490 }
491
492 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
496 for node in shadow_root
497 .upcast::<Node>()
498 .traverse_preorder(ShadowIncluding::Yes)
499 {
500 node.set_flag(RESET_FLAGS, false);
501 document.clean_up_style_and_layout_data_for_node(&node);
502 }
503 }
504 }
505 }
506
507 fn remove_child(&self, cx: &mut JSContext, child: &Node, cached_index: Option<u32>) {
511 assert!(child.parent_node.get().as_deref() == Some(self));
512
513 if let Some(element) = self.downcast::<Element>() {
514 element.note_dirty_descendants(cx.no_gc());
515 }
516 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
517
518 let prev_sibling = child.GetPreviousSibling();
519 match prev_sibling {
520 None => {
521 self.first_child.set(child.next_sibling.get().as_deref());
522 },
523 Some(ref prev_sibling) => {
524 prev_sibling
525 .next_sibling
526 .set(child.next_sibling.get().as_deref());
527 },
528 }
529 let next_sibling = child.GetNextSibling();
530 match next_sibling {
531 None => {
532 self.last_child.set(child.prev_sibling.get().as_deref());
533 },
534 Some(ref next_sibling) => {
535 next_sibling
536 .prev_sibling
537 .set(child.prev_sibling.get().as_deref());
538 },
539 }
540
541 let context = UnbindContext::new(
542 self,
543 prev_sibling.as_deref(),
544 next_sibling.as_deref(),
545 cached_index,
546 );
547
548 child.prev_sibling.set(None);
549 child.next_sibling.set(None);
550 child.parent_node.set(None);
551 self.children_count.set(self.children_count.get() - 1);
552
553 Self::complete_remove_subtree(cx, child, &context);
554 }
555
556 fn move_child(&self, cx: &mut JSContext, child: &Node) {
557 assert!(child.parent_node.get().as_deref() == Some(self));
558 self.dirty(cx.no_gc(), NodeDamage::ContentOrHeritage);
559 if let Some(element) = self.downcast::<Element>() {
560 element.note_dirty_descendants(cx.no_gc());
561 }
562
563 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
564
565 child.prev_sibling.set(None);
566 child.next_sibling.set(None);
567 child.parent_node.set(None);
568 self.children_count.set(self.children_count.get() - 1);
569 Self::complete_move_subtree(cx, child)
570 }
571
572 pub(crate) fn to_opaque(&self) -> OpaqueNode {
573 OpaqueNode(self.reflector().get_jsobject().get() as usize)
574 }
575
576 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
577 self.downcast::<Element>().and_then(|element| {
578 if element.is_custom() {
579 assert!(element.get_custom_element_definition().is_some());
580 Some(DomRoot::from_ref(element))
581 } else {
582 None
583 }
584 })
585 }
586
587 pub(crate) fn fire_synthetic_pointer_event_not_trusted(
589 &self,
590 cx: &mut JSContext,
591 event_type: Atom,
592 ) {
593 let window = self.owner_window();
597
598 let pointer_event = PointerEvent::new(
600 cx,
601 &window, event_type,
603 EventBubbles::Bubbles, EventCancelable::Cancelable, Some(&window), 0, Point2D::zero(), Point2D::zero(), Point2D::zero(), Modifiers::empty(), 0, 0, None, None, PointerId::NonPointerDevice as i32, 1, 1, 0.5, 0.0, 0, 0, 0, PI / 2.0, 0.0, DOMString::from(""), false, vec![], vec![], );
630
631 pointer_event.upcast::<Event>().set_composed(true);
633
634 pointer_event.upcast::<Event>().set_trusted(false);
636
637 pointer_event
640 .upcast::<Event>()
641 .dispatch(cx, self.upcast::<EventTarget>(), false);
642 }
643
644 pub(crate) fn parent_directionality(&self) -> String {
645 let mut current = self.GetParentNode();
646
647 loop {
648 match current {
649 Some(node) => {
650 if let Some(directionality) = node
651 .downcast::<HTMLElement>()
652 .and_then(|html_element| html_element.directionality())
653 {
654 return directionality;
655 } else {
656 current = node.GetParentNode();
657 }
658 },
659 None => return "ltr".to_owned(),
660 }
661 }
662 }
663
664 pub(crate) fn is_being_rendered_or_delegates_rendering(
668 &self,
669 pseudo_element: Option<PseudoElement>,
670 ) -> bool {
671 matches!(
672 self.owner_window()
673 .layout()
674 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
675 NodeRenderingType::Rendered | NodeRenderingType::DelegatesRendering
676 )
677 }
678
679 pub(crate) fn is_being_rendered(&self, pseudo_element: Option<PseudoElement>) -> bool {
681 matches!(
682 self.owner_window()
683 .layout()
684 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
685 NodeRenderingType::Rendered
686 )
687 }
688
689 fn add_pending_accessibility_damage(&self, damage: AccessibilityDamage) {
690 if !self.owner_doc().accessibility_active() {
691 return;
692 }
693
694 self.owner_doc()
695 .accessibility_data_mut()
696 .add_pending_accessibility_damage_for_node(self, damage);
697
698 self.owner_window()
699 .layout()
700 .set_needs_accessibility_update();
701 }
702}
703
704impl Node {
705 fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
706 let mut rare_data = self.rare_data.borrow_mut();
707 if rare_data.is_none() {
708 *rare_data = Some(Default::default());
709 }
710 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
711 }
712
713 pub(crate) fn is_before(&self, other: &Node) -> bool {
716 let cmp = other.CompareDocumentPosition(self);
717 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
718 return false;
719 }
720
721 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
722 }
723
724 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
727 RefMut::map(self.ensure_rare_data(), |rare_data| {
728 &mut rare_data.mutation_observers
729 })
730 }
731
732 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
733 let rare_data = self.rare_data.borrow();
734 if rare_data.is_none() {
735 return None;
736 }
737 Some(Ref::map(rare_data, |rare_data| {
738 &rare_data.as_ref().unwrap().mutation_observers
739 }))
740 }
741
742 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
744 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
745 self.ensure_rare_data().mutation_observers.push(observer);
746 }
747
748 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
750 let mut rare_data = self.rare_data.borrow_mut();
751 let Some(rare_data) = rare_data.as_mut() else {
752 return;
753 };
754 rare_data
755 .mutation_observers
756 .retain(|registered_observer| &*registered_observer.observer != observer)
757 }
758
759 pub(crate) fn debug_str(&self) -> String {
761 format!("{:?}", self.type_id())
762 }
763
764 pub(crate) fn is_in_a_document_tree(&self) -> bool {
766 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
767 }
768
769 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
771 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
772 }
773
774 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
775 self.flags
776 .get()
777 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
778 }
779
780 pub(crate) fn set_weird_parser_insertion_mode(&self) {
781 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
782 }
783
784 pub(crate) fn is_connected(&self) -> bool {
786 self.flags.get().contains(NodeFlags::IS_CONNECTED)
787 }
788
789 pub(crate) fn set_in_ua_widget(&self, in_ua_widget: bool) {
790 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, in_ua_widget)
791 }
792
793 pub(crate) fn is_in_ua_widget(&self) -> bool {
794 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
795 }
796
797 pub(crate) fn type_id(&self) -> NodeTypeId {
799 match *self.eventtarget.type_id() {
800 EventTargetTypeId::Node(type_id) => type_id,
801 _ => unreachable!(),
802 }
803 }
804
805 pub(crate) fn len(&self) -> u32 {
807 match self.type_id() {
808 NodeTypeId::DocumentType => 0,
809 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
810 _ => self.children_count(),
811 }
812 }
813
814 pub(crate) fn is_empty(&self) -> bool {
815 self.len() == 0
817 }
818
819 pub(crate) fn index(&self) -> u32 {
821 self.preceding_siblings().count() as u32
822 }
823
824 pub(crate) fn has_parent(&self) -> bool {
826 self.parent_node.get().is_some()
827 }
828
829 pub(crate) fn children_count(&self) -> u32 {
830 self.children_count.get()
831 }
832
833 pub(crate) fn weak_ranges_mut(&self) -> Option<RefMut<'_, WeakRangeVec>> {
834 let rare_data = self.rare_data.borrow_mut();
835 if rare_data.is_none() {
836 return None;
837 }
838 Some(RefMut::map(rare_data, |rare_data| {
839 &mut rare_data.as_mut().unwrap().weak_ranges
840 }))
841 }
842
843 pub(crate) fn ensure_weak_ranges(&self) -> RefMut<'_, WeakRangeVec> {
844 RefMut::map(self.ensure_rare_data(), |rare_data| {
845 &mut rare_data.weak_ranges
846 })
847 }
848
849 pub(crate) fn weak_ranges_is_empty(&self) -> bool {
850 self.rare_data
851 .borrow()
852 .as_ref()
853 .is_none_or(|data| data.weak_ranges.is_empty())
854 }
855
856 #[inline]
857 pub(crate) fn is_doctype(&self) -> bool {
858 self.type_id() == NodeTypeId::DocumentType
859 }
860
861 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
862 self.flags.get().contains(flag)
863 }
864
865 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
866 let mut flags = self.flags.get();
867
868 if value {
869 flags.insert(flag);
870 } else {
871 flags.remove(flag);
872 }
873
874 self.flags.set(flags);
875 }
876
877 pub(crate) fn rev_version(&self, no_gc: &NoGC) {
878 let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
883 let version = cmp::max(
884 self.inclusive_descendants_version(),
885 doc.inclusive_descendants_version(),
886 ) + 1;
887
888 for node in self.inclusive_ancestors_unrooted(no_gc, ShadowIncluding::No) {
889 node.inclusive_descendants_version.set(version);
890 }
891 doc.inclusive_descendants_version.set(version);
892 }
893
894 pub(crate) fn clear_layout_data(&self) {
895 self.layout_data.take();
896 }
897
898 pub(crate) fn dirty(&self, no_gc: &NoGC, damage: NodeDamage) {
899 self.rev_version(no_gc);
900 if !self.is_connected() {
901 return;
902 }
903
904 match self.type_id() {
905 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..)) => {
906 *self.layout_data.borrow_mut() = None;
909
910 self.parent_node
914 .get()
915 .unwrap()
916 .dirty(no_gc, NodeDamage::ContentOrHeritage);
917
918 if damage == NodeDamage::Other {
919 self.add_pending_accessibility_damage(AccessibilityDamage::Text);
920 }
921 },
922 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(no_gc, damage),
923 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
924 .downcast::<ShadowRoot>()
925 .unwrap()
926 .Host()
927 .upcast::<Element>()
928 .restyle(no_gc, damage),
929 _ => {},
930 };
931 }
932
933 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
935 self.inclusive_descendants_version.get()
936 }
937
938 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
940 TreeIterator::new(self, shadow_including)
941 }
942
943 pub(crate) fn traverse_preorder_non_rooting<'b>(
946 &self,
947 no_gc: &'b NoGC,
948 shadow_including: ShadowIncluding,
949 ) -> UnrootedTreeIterator<'b> {
950 UnrootedTreeIterator::new(self, shadow_including, no_gc)
951 }
952
953 pub(crate) fn inclusively_following_siblings(
954 &self,
955 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
956 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), |n| n.GetNextSibling())
957 }
958
959 pub(crate) fn inclusively_following_siblings_unrooted<'b>(
960 &self,
961 no_gc: &'b NoGC,
962 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
963 UnrootedSimpleNodeIterator::new(
964 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
965 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
966 no_gc,
967 )
968 }
969
970 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
971 &self,
972 no_gc: &'b NoGC,
973 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
974 UnrootedSimpleNodeIterator::new(
975 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
976 |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
977 no_gc,
978 )
979 }
980
981 pub(crate) fn common_ancestor(
982 &self,
983 other: &Node,
984 shadow_including: ShadowIncluding,
985 ) -> Option<DomRoot<Node>> {
986 self.inclusive_ancestors(shadow_including).find(|ancestor| {
987 other
988 .inclusive_ancestors(shadow_including)
989 .any(|node| node == *ancestor)
990 })
991 }
992
993 pub(crate) fn common_ancestor_in_flat_tree(
994 &self,
995 no_gc: &NoGC,
996 other: &Node,
997 ) -> Option<DomRoot<Node>> {
998 self.inclusive_ancestors_in_flat_tree_unrooted(no_gc)
999 .find(|ancestor| {
1000 other
1001 .inclusive_ancestors_in_flat_tree_unrooted(no_gc)
1002 .any(|node| node == *ancestor)
1003 })
1004 .map(|node| node.as_rooted())
1005 }
1006
1007 pub(crate) fn following_flat_tree_nodes_unrooted<'no_gc>(
1008 &self,
1009 no_gc: &'no_gc NoGC,
1010 ) -> UnrootedFollowingFlatTreeNodesTraversal<'no_gc> {
1011 UnrootedFollowingFlatTreeNodesTraversal::new(self, no_gc)
1012 }
1013
1014 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
1016 self == child || self.is_ancestor_of(child)
1018 }
1019
1020 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
1022 let mut current = &possible_descendant.parent_node;
1024 let mut done = false;
1025
1026 while let Some(node) = current.if_is_some(|node| {
1027 done = node == self;
1028 &node.parent_node
1029 }) {
1030 if done {
1031 break;
1032 }
1033 current = node
1034 }
1035 done
1036 }
1037
1038 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
1040 self.is_inclusive_ancestor_of(child) ||
1043 child
1044 .GetRootNode(&GetRootNodeOptions::empty())
1045 .downcast::<DocumentFragment>()
1046 .and_then(|fragment| fragment.host())
1047 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1048 }
1049
1050 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1052 node.inclusive_ancestors(ShadowIncluding::Yes)
1053 .any(|ancestor| &*ancestor == self)
1054 }
1055
1056 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1057 SimpleNodeIterator::new(self.GetNextSibling(), |n| n.GetNextSibling())
1058 }
1059
1060 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1061 SimpleNodeIterator::new(self.GetPreviousSibling(), |n| n.GetPreviousSibling())
1062 }
1063
1064 pub(crate) fn following_nodes(
1065 &self,
1066 root: &Node,
1067 shadow_including: ShadowIncluding,
1068 ) -> FollowingNodeIterator {
1069 FollowingNodeIterator::new(
1070 Some(DomRoot::from_ref(self)),
1071 DomRoot::from_ref(root),
1072 shadow_including,
1073 )
1074 }
1075
1076 pub(crate) fn following_nodes_unrooted<'b>(
1077 &self,
1078 no_gc: &'b NoGC,
1079 root: &Node,
1080 shadow_including: ShadowIncluding,
1081 ) -> UnrootedFollowingNodeIterator<'b> {
1082 UnrootedFollowingNodeIterator::new(
1083 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1084 UnrootedDom::from_dom(Dom::from_ref(root), no_gc),
1085 shadow_including,
1086 no_gc,
1087 )
1088 }
1089
1090 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1091 PrecedingNodeIterator::new(Some(DomRoot::from_ref(self)), DomRoot::from_ref(root))
1092 }
1093
1094 pub(crate) fn preceding_nodes_unrooted<'b>(
1095 &self,
1096 no_gc: &'b NoGC,
1097 root: &Node,
1098 ) -> UnrootedPrecedingNodeIterator<'b> {
1099 UnrootedPrecedingNodeIterator::new(
1100 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1101 UnrootedDom::from_dom(Dom::from_ref(root), no_gc),
1102 no_gc,
1103 )
1104 }
1105
1106 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1109 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetLastChild())
1110 }
1111
1112 pub(crate) fn descending_last_children_unrooted<'b>(
1113 &self,
1114 no_gc: &'b NoGC,
1115 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> {
1116 UnrootedSimpleNodeIterator::new(
1117 self.get_last_child_unrooted(no_gc),
1118 |n, no_gc| n.get_last_child_unrooted(no_gc),
1119 no_gc,
1120 )
1121 }
1122
1123 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1124 child
1125 .parent_node
1126 .get()
1127 .is_some_and(|parent| &*parent == self)
1128 }
1129
1130 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1131 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1132 }
1133
1134 pub(crate) fn containing_block_node_without_reflow(&self) -> Option<DomRoot<Node>> {
1136 self.owner_window()
1137 .containing_block_node_query_without_reflow(self)
1138 }
1139
1140 pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1141 self.owner_window().padding_query_without_reflow(self)
1142 }
1143
1144 pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1145 self.owner_window()
1146 .box_area_query(self, BoxAreaType::Content, false)
1147 }
1148
1149 pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1150 self.owner_window()
1151 .box_area_query(self, BoxAreaType::Border, false)
1152 }
1153
1154 pub(crate) fn border_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1155 self.owner_window()
1156 .box_area_query_without_reflow(self, BoxAreaType::Border, false)
1157 }
1158
1159 pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1160 self.owner_window()
1161 .box_area_query(self, BoxAreaType::Padding, false)
1162 }
1163
1164 pub(crate) fn padding_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1165 self.owner_window()
1166 .box_area_query_without_reflow(self, BoxAreaType::Padding, false)
1167 }
1168
1169 pub(crate) fn border_boxes(&self) -> CSSPixelRectVec {
1170 self.owner_window()
1171 .box_areas_query(self, BoxAreaType::Border)
1172 }
1173
1174 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1175 self.owner_window().client_rect_query(self)
1176 }
1177
1178 pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1181 let document = self.owner_doc();
1183
1184 if !document.is_active() {
1186 return Rect::zero();
1187 }
1188
1189 let window = document.window();
1192 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1193
1194 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1195 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1196 let is_body_element = self
1197 .downcast::<HTMLElement>()
1198 .is_some_and(|e| e.is_body_element());
1199
1200 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1206 let viewport_scrolling_area = window.scrolling_area_query(None);
1207 return Rect::new(
1208 viewport_scrolling_area.origin,
1209 viewport_scrolling_area.size.max(viewport),
1210 );
1211 }
1212
1213 window.scrolling_area_query(Some(self))
1217 }
1218
1219 pub(crate) fn effective_overflow(&self) -> Option<AxesOverflow> {
1220 self.owner_window().query_effective_overflow(self)
1221 }
1222
1223 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1224 self.owner_window()
1225 .query_effective_overflow_without_reflow(self)
1226 }
1227
1228 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1230 let parent = &self.parent_node;
1232
1233 let parent = match parent.get() {
1235 None => return Ok(()),
1236 Some(parent) => parent,
1237 };
1238
1239 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1241
1242 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1244
1245 let viable_previous_sibling = match viable_previous_sibling {
1247 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1248 None => parent.first_child.get(),
1249 };
1250
1251 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1253
1254 Ok(())
1255 }
1256
1257 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1259 let parent = &self.parent_node;
1261
1262 let parent = match parent.get() {
1264 None => return Ok(()),
1265 Some(parent) => parent,
1266 };
1267
1268 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1270
1271 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1273
1274 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1276
1277 Ok(())
1278 }
1279
1280 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1282 let Some(parent) = self.GetParentNode() else {
1284 return Ok(());
1286 };
1287
1288 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1290
1291 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1293
1294 if self.parent_node == Some(&*parent) {
1295 parent.ReplaceChild(cx, &node, self)?;
1297 } else {
1298 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1300 }
1301 Ok(())
1302 }
1303
1304 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1306 let doc = self.owner_doc();
1308 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1309 let first_child = self.first_child.get();
1311 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1312 }
1313
1314 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1316 let doc = self.owner_doc();
1318 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1319 self.AppendChild(cx, &node).map(|_| ())
1321 }
1322
1323 pub(crate) fn replace_children(
1325 &self,
1326 cx: &mut JSContext,
1327 nodes: Vec<NodeOrString>,
1328 ) -> ErrorResult {
1329 let doc = self.owner_doc();
1332 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1333
1334 Node::ensure_pre_insertion_validity(cx.no_gc(), &node, self, None)?;
1336
1337 Node::replace_all(cx, Some(&node), self);
1339 Ok(())
1340 }
1341
1342 pub(crate) fn move_before(
1344 &self,
1345 cx: &mut JSContext,
1346 node: &Node,
1347 child: Option<&Node>,
1348 ) -> ErrorResult {
1349 let reference_child_root;
1352 let reference_child = match child {
1353 Some(child) if child == node => {
1354 reference_child_root = node.GetNextSibling();
1355 reference_child_root.as_deref()
1356 },
1357 _ => child,
1358 };
1359
1360 Node::move_fn(cx, node, self, reference_child)
1362 }
1363
1364 fn move_fn(
1366 cx: &mut JSContext,
1367 node: &Node,
1368 new_parent: &Node,
1369 child: Option<&Node>,
1370 ) -> ErrorResult {
1371 let mut options = GetRootNodeOptions::empty();
1376 options.composed = true;
1377 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1378 return Err(Error::HierarchyRequest(None));
1379 }
1380
1381 if node.is_inclusive_ancestor_of(new_parent) {
1384 return Err(Error::HierarchyRequest(None));
1385 }
1386
1387 if let Some(child) = child &&
1390 !new_parent.is_parent_of(child)
1391 {
1392 return Err(Error::NotFound(None));
1393 }
1394
1395 match node.type_id() {
1400 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1401 if new_parent.is::<Document>() {
1402 return Err(Error::HierarchyRequest(None));
1403 }
1404 },
1405 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1406 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1407 NodeTypeId::Element(_) => (),
1408 NodeTypeId::DocumentFragment(_) |
1409 NodeTypeId::DocumentType |
1410 NodeTypeId::Document(_) |
1411 NodeTypeId::Attr => {
1412 return Err(Error::HierarchyRequest(None));
1413 },
1414 }
1415
1416 if new_parent.is::<Document>() && node.is::<Element>() {
1420 if new_parent.child_elements().next().is_some() {
1422 return Err(Error::HierarchyRequest(None));
1423 }
1424
1425 if child.is_some_and(|child| {
1428 child
1429 .inclusively_following_siblings_unrooted(cx.no_gc())
1430 .any(|child| child.is_doctype())
1431 }) {
1432 return Err(Error::HierarchyRequest(None));
1433 }
1434 }
1435
1436 let old_parent = node
1439 .parent_node
1440 .get()
1441 .expect("old_parent should always be initialized");
1442
1443 let cached_index = Node::live_range_pre_remove_steps(node, &old_parent);
1445
1446 let old_previous_sibling = node.prev_sibling.get();
1451
1452 let old_next_sibling = node.next_sibling.get();
1454
1455 let prev_sibling = node.GetPreviousSibling();
1456 match prev_sibling {
1457 None => {
1458 old_parent
1459 .first_child
1460 .set(node.next_sibling.get().as_deref());
1461 },
1462 Some(ref prev_sibling) => {
1463 prev_sibling
1464 .next_sibling
1465 .set(node.next_sibling.get().as_deref());
1466 },
1467 }
1468 let next_sibling = node.GetNextSibling();
1469 match next_sibling {
1470 None => {
1471 old_parent
1472 .last_child
1473 .set(node.prev_sibling.get().as_deref());
1474 },
1475 Some(ref next_sibling) => {
1476 next_sibling
1477 .prev_sibling
1478 .set(node.prev_sibling.get().as_deref());
1479 },
1480 }
1481
1482 let mut context =
1483 MoveContext::new(Some(&old_parent), prev_sibling.as_deref(), cached_index);
1484
1485 old_parent.move_child(cx, node);
1487
1488 if let Some(slot) = node.assigned_slot() {
1490 slot.assign_slottables(cx);
1491 }
1492
1493 if old_parent.is_in_a_shadow_tree() &&
1496 let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() &&
1497 !slot_element.has_assigned_nodes()
1498 {
1499 slot_element.signal_a_slot_change(cx);
1500 }
1501
1502 let has_slot_descendant = node
1504 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
1505 .any(|element| element.is::<HTMLSlotElement>());
1506 if has_slot_descendant {
1507 old_parent
1509 .GetRootNode(&GetRootNodeOptions::empty())
1510 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1511
1512 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1514 }
1515
1516 if let Some(child) = child &&
1518 let Some(new_parent_ranges) = new_parent.weak_ranges_mut()
1519 {
1520 new_parent_ranges.increase_above(new_parent, child.index(), 1)
1525 }
1526
1527 let new_previous_sibling = child.map_or_else(
1530 || new_parent.last_child.get(),
1531 |child| child.prev_sibling.get(),
1532 );
1533
1534 new_parent.add_child(cx, node, child);
1537
1538 if let Some(shadow_root) = new_parent
1541 .downcast::<Element>()
1542 .and_then(Element::shadow_root) &&
1543 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1544 (node.is::<Element>() || node.is::<Text>())
1545 {
1546 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1547 slottable.assign_a_slot(cx);
1548 }
1549
1550 if new_parent.is_in_a_shadow_tree() &&
1553 let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() &&
1554 !slot_element.has_assigned_nodes()
1555 {
1556 slot_element.signal_a_slot_change(cx);
1557 }
1558
1559 node.GetRootNode(&GetRootNodeOptions::empty())
1561 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1562
1563 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1566 if descendant.deref() == node {
1570 vtable_for(&descendant).moving_steps(cx, &context);
1571 } else {
1572 context.old_parent = None;
1573 vtable_for(&descendant).moving_steps(cx, &context);
1574 }
1575
1576 if let Some(descendant) = descendant.downcast::<Element>() &&
1578 descendant.is_custom() &&
1579 new_parent.is_connected()
1580 {
1581 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
1584 custom_element_reaction_stack.enqueue_callback_reaction(
1585 cx,
1586 descendant,
1587 CallbackReaction::ConnectedMove,
1588 None,
1589 );
1590 }
1591 }
1592
1593 let moved = [node];
1596 let mutation = LazyCell::new(|| Mutation::ChildList {
1597 added: None,
1598 removed: Some(&moved),
1599 prev: old_previous_sibling.as_deref(),
1600 next: old_next_sibling.as_deref(),
1601 });
1602 MutationObserver::queue_a_mutation_record(cx, &old_parent, mutation);
1603
1604 let mutation = LazyCell::new(|| Mutation::ChildList {
1607 added: Some(&moved),
1608 removed: None,
1609 prev: new_previous_sibling.as_deref(),
1610 next: child,
1611 });
1612 MutationObserver::queue_a_mutation_record(cx, new_parent, mutation);
1613
1614 Ok(())
1615 }
1616
1617 #[allow(unsafe_code)]
1619 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1620 pub(crate) fn query_selector(
1621 &self,
1622 no_gc: &NoGC,
1623 selectors: DOMString,
1624 ) -> Fallible<Option<DomRoot<Element>>> {
1625 let document_url = self.owner_document().url().get_arc();
1628
1629 self.owner_document()
1632 .id_map()
1633 .resolve_all(no_gc, self.owner_doc().upcast());
1634
1635 let traced_node = Dom::from_ref(self);
1637
1638 let first_matching_element = with_layout_state(|| {
1639 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1640 ServoDangerousStyleNode::from(layout_node)
1641 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1642 })?;
1643
1644 Ok(first_matching_element.map(ServoDangerousStyleElement::rooted))
1645 }
1646
1647 #[allow(unsafe_code)]
1649 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1650 pub(crate) fn query_selector_all(
1651 &self,
1652 cx: &mut JSContext,
1653 selectors: DOMString,
1654 ) -> Fallible<DomRoot<NodeList>> {
1655 let document_url = self.owner_document().url().get_arc();
1658
1659 self.owner_document()
1662 .id_map()
1663 .resolve_all(cx.no_gc(), self.owner_doc().upcast());
1664
1665 let traced_node = UnrootedDom::from_dom(Dom::from_ref(self), cx.no_gc());
1666 let matching_elements = with_layout_state(|| {
1667 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1668 ServoDangerousStyleNode::from(layout_node)
1669 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1670 })?;
1671 let iter = matching_elements
1672 .into_iter()
1673 .map(ServoDangerousStyleElement::rooted)
1674 .map(DomRoot::upcast::<Node>);
1675
1676 Ok(NodeList::new_simple_list(cx, &self.owner_window(), iter))
1679 }
1680
1681 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1682 SimpleNodeIterator::new(self.GetParentNode(), |n| n.GetParentNode())
1683 }
1684
1685 pub(crate) fn inclusive_ancestors(
1687 &self,
1688 shadow_including: ShadowIncluding,
1689 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1690 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |n| {
1691 if shadow_including == ShadowIncluding::Yes &&
1692 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1693 {
1694 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1695 }
1696 n.GetParentNode()
1697 })
1698 }
1699
1700 pub(crate) fn inclusive_ancestors_unrooted<'a>(
1701 &self,
1702 no_gc: &'a NoGC,
1703 shadow_including: ShadowIncluding,
1704 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1705 UnrootedSimpleNodeIterator::new(
1706 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1707 move |n, no_gc| {
1708 if shadow_including == ShadowIncluding::Yes &&
1709 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1710 {
1711 return Some(UnrootedDom::from_dom(
1712 Dom::from_ref(shadow_root.host_unrooted(no_gc).upcast::<Node>()),
1713 no_gc,
1714 ));
1715 }
1716 n.get_parent_node_unrooted(no_gc)
1717 },
1718 no_gc,
1719 )
1720 }
1721
1722 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1723 self.owner_doc.get().unwrap()
1724 }
1725
1726 pub(crate) fn owner_doc_unrooted<'a>(&self, no_gc: &'a NoGC) -> UnrootedDom<'a, Document> {
1727 self.owner_doc.get_unrooted(no_gc).unwrap()
1728 }
1729
1730 pub(crate) fn set_owner_doc(&self, document: &Document) {
1731 self.owner_doc.set(Some(document));
1732 }
1733
1734 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1735 self.rare_data
1736 .borrow()
1737 .as_ref()?
1738 .containing_shadow_root
1739 .as_ref()
1740 .map(|sr| DomRoot::from_ref(&**sr))
1741 }
1742
1743 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1744 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1745 }
1746
1747 pub(crate) fn is_in_html_doc(&self) -> bool {
1748 self.owner_doc().is_html_document()
1749 }
1750
1751 pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1752 self.is_connected() && self.owner_doc().browsing_context().is_some()
1753 }
1754
1755 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1756 SimpleNodeIterator::new(self.GetFirstChild(), |n| n.GetNextSibling())
1757 }
1758
1759 pub(crate) fn children_unrooted<'a>(
1760 &self,
1761 no_gc: &'a NoGC,
1762 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1763 UnrootedSimpleNodeIterator::new(
1764 self.get_first_child_unrooted(no_gc),
1765 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1766 no_gc,
1767 )
1768 }
1769
1770 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1771 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetPreviousSibling())
1772 }
1773
1774 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1776 self.children()
1777 .filter_map(DomRoot::downcast as fn(_) -> _)
1778 .peekable()
1779 }
1780
1781 pub(crate) fn child_elements_unrooted<'a>(
1782 &self,
1783 no_gc: &'a NoGC,
1784 ) -> impl Iterator<Item = UnrootedDom<'a, Element>> + use<'a> {
1785 self.children_unrooted(no_gc)
1786 .filter_map(UnrootedDom::downcast)
1787 .peekable()
1788 }
1789
1790 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1791 if let Some(ref parent) = self.GetParentNode() {
1792 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1793 }
1794 }
1795
1796 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1798 Ref::filter_map(self.rare_data.borrow(), |rare_data| {
1799 rare_data
1800 .as_ref()
1801 .and_then(|rare_data| rare_data.unique_id.as_ref())
1802 })
1803 .ok()
1804 .map(|unique_id| unique_id.borrow().simple().to_string())
1805 }
1806
1807 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1808 let mut rare_data = self.ensure_rare_data();
1809
1810 if rare_data.unique_id.is_none() {
1811 let node_id = UniqueId::new();
1812 ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string());
1813 rare_data.unique_id = Some(node_id);
1814 }
1815 rare_data
1816 .unique_id
1817 .as_ref()
1818 .unwrap()
1819 .borrow()
1820 .simple()
1821 .to_string()
1822 }
1823
1824 pub(crate) fn summarize(&self, cx: &mut JSContext) -> NodeInfo {
1825 let USVString(base_uri) = self.BaseURI();
1826 let node_type = self.NodeType();
1827 let pipeline = self.owner_window().pipeline_id();
1828
1829 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1830 let shadow_root_mode = maybe_shadow_root
1831 .map(ShadowRoot::Mode)
1832 .map(ShadowRootMode::convert);
1833 let host = maybe_shadow_root
1834 .map(ShadowRoot::Host)
1835 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1836 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1837 let Some(root) = potential_host.shadow_root() else {
1838 return false;
1839 };
1840 !root.is_user_agent_widget() || pref!(inspector_show_servo_internal_shadow_roots)
1841 });
1842
1843 let num_children = if is_shadow_host {
1844 self.ChildNodes(cx).Length() as usize + 1
1846 } else {
1847 self.ChildNodes(cx).Length() as usize
1848 };
1849
1850 let window = self.owner_window();
1851 let element = self.downcast::<Element>();
1852 let display = element
1853 .map(|elem| window.GetComputedStyle(cx, elem, None))
1854 .map(|style| style.Display().into());
1855
1856 let is_displayed =
1862 element.is_none_or(|element| !element.is_display_none()) || self.is::<DocumentType>();
1863 let attrs = element.map(Element::summarize).unwrap_or_default();
1864
1865 NodeInfo {
1866 unique_id: self.unique_id(pipeline),
1867 host,
1868 base_uri,
1869 parent: self
1870 .GetParentNode()
1871 .map_or("".to_owned(), |node| node.unique_id(pipeline)),
1872 node_type,
1873 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1874 node_name: String::from(self.NodeName()),
1875 node_value: self.GetNodeValue().map(|v| v.into()),
1876 num_children,
1877 attrs,
1878 is_shadow_host,
1879 shadow_root_mode,
1880 display,
1881 is_displayed,
1882 doctype_name: self
1883 .downcast::<DocumentType>()
1884 .map(DocumentType::name)
1885 .cloned()
1886 .map(String::from),
1887 doctype_public_identifier: self
1888 .downcast::<DocumentType>()
1889 .map(DocumentType::public_id)
1890 .cloned()
1891 .map(String::from),
1892 doctype_system_identifier: self
1893 .downcast::<DocumentType>()
1894 .map(DocumentType::system_id)
1895 .cloned()
1896 .map(String::from),
1897 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1898 }
1899 }
1900
1901 pub(crate) fn insert_cell_or_row<F, G, I>(
1903 &self,
1904 cx: &mut JSContext,
1905 index: i32,
1906 get_items: F,
1907 new_child: G,
1908 ) -> Fallible<DomRoot<HTMLElement>>
1909 where
1910 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1911 G: Fn(&mut JSContext) -> DomRoot<I>,
1912 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1913 {
1914 if index < -1 {
1915 return Err(Error::IndexSize(None));
1916 }
1917
1918 let tr = new_child(cx);
1919
1920 {
1921 let tr_node = tr.upcast::<Node>();
1922 if index == -1 {
1923 self.InsertBefore(cx, tr_node, None)?;
1924 } else {
1925 let items = get_items(cx);
1926 let node = match items
1927 .elements_iter(cx.no_gc())
1928 .map(UnrootedDom::upcast::<Node>)
1929 .map(Some)
1930 .chain(iter::once(None))
1931 .nth(index as usize)
1932 {
1933 None => return Err(Error::IndexSize(None)),
1934 Some(node) => node,
1935 };
1936 self.InsertBefore(cx, tr_node, node.map(|node| node.as_rooted()).as_deref())?;
1937 }
1938 }
1939
1940 Ok(DomRoot::upcast::<HTMLElement>(tr))
1941 }
1942
1943 pub(crate) fn delete_cell_or_row<F, G>(
1945 &self,
1946 cx: &mut JSContext,
1947 index: i32,
1948 get_items: F,
1949 is_delete_type: G,
1950 ) -> ErrorResult
1951 where
1952 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1953 G: Fn(&Element) -> bool,
1954 {
1955 let element = match index {
1956 index if index < -1 => return Err(Error::IndexSize(None)),
1957 -1 => {
1958 let last_child = self.upcast::<Node>().GetLastChild();
1959 match last_child.and_then(|node| {
1960 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
1961 .filter_map(UnrootedDom::downcast::<Element>)
1962 .find(|elem| is_delete_type(elem))
1963 .map(|elem| elem.as_rooted())
1964 }) {
1965 Some(element) => element,
1966 None => return Ok(()),
1967 }
1968 },
1969 index => match get_items(cx).Item(cx, index as u32) {
1970 Some(element) => element,
1971 None => return Err(Error::IndexSize(None)),
1972 },
1973 };
1974
1975 element.upcast::<Node>().remove_self(cx);
1976 Ok(())
1977 }
1978
1979 pub(crate) fn get_cssom_stylesheet(
1980 &self,
1981 cx: &mut JSContext,
1982 ) -> Option<DomRoot<CSSStyleSheet>> {
1983 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1984 node.get_cssom_stylesheet(cx)
1985 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1986 node.get_cssom_stylesheet(cx)
1987 } else {
1988 None
1989 }
1990 }
1991
1992 pub(crate) fn get_lang(&self) -> Option<String> {
1994 self.inclusive_ancestors(ShadowIncluding::Yes)
1995 .find_map(|node| {
1996 node.downcast::<Element>().and_then(|el| {
1997 el.get_attribute_string_value_with_namespace(&ns!(xml), &local_name!("lang"))
1998 .or_else(|| el.get_attribute_string_value(&local_name!("lang")))
1999 })
2000 })
2003 }
2004
2005 pub(crate) fn assign_slottables_for_a_tree(
2007 &self,
2008 cx: &JSContext,
2009 force: ForceSlottableNodeReconciliation,
2010 ) {
2011 let is_shadow_root_with_slots = self
2018 .downcast::<ShadowRoot>()
2019 .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
2020 if !is_shadow_root_with_slots &&
2021 !self.is::<HTMLSlotElement>() &&
2022 matches!(force, ForceSlottableNodeReconciliation::Skip)
2023 {
2024 return;
2025 }
2026
2027 for node in self.traverse_preorder_non_rooting(cx, ShadowIncluding::No) {
2030 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
2031 slot.assign_slottables(cx);
2032 }
2033 }
2034 }
2035
2036 pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
2037 let assigned_slot = self
2038 .rare_data
2039 .borrow()
2040 .as_ref()?
2041 .slottable_data
2042 .assigned_slot
2043 .as_ref()?
2044 .as_rooted();
2045 Some(assigned_slot)
2046 }
2047
2048 pub(crate) fn assigned_slot_unrooted<'a>(
2049 &self,
2050 no_gc: &'a NoGC,
2051 ) -> Option<UnrootedDom<'a, HTMLSlotElement>> {
2052 let rare_data = self.rare_data.borrow();
2053 let assigned_slot = rare_data.as_ref()?.slottable_data.assigned_slot.as_ref()?;
2054 Some(UnrootedDom::from_dom(Dom::from_ref(assigned_slot), no_gc))
2055 }
2056
2057 pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
2058 self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
2059 }
2060
2061 pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
2062 let manually_assigned_slot = self
2063 .rare_data
2064 .borrow()
2065 .as_ref()?
2066 .slottable_data
2067 .manual_slot_assignment
2068 .as_ref()?
2069 .as_rooted();
2070 Some(manually_assigned_slot)
2071 }
2072
2073 pub(crate) fn set_manual_slot_assignment(
2074 &self,
2075 manually_assigned_slot: Option<&HTMLSlotElement>,
2076 ) {
2077 self.ensure_rare_data()
2078 .slottable_data
2079 .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
2080 }
2081
2082 pub(crate) fn parent_in_flat_tree<'b>(&self, no_gc: &'b NoGC) -> FlatTreeParent<'b> {
2093 if let Some(assigned_slot) = self.assigned_slot_unrooted(no_gc) {
2094 return FlatTreeParent::Parent(UnrootedDom::upcast::<Node>(assigned_slot));
2095 }
2096
2097 let Some(parent) = self.get_parent_node_unrooted(no_gc) else {
2098 return FlatTreeParent::RootNode;
2099 };
2100
2101 if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
2102 return FlatTreeParent::Parent(UnrootedDom::from_dom(
2103 Dom::from_ref(shadow_root.Host().upcast::<Node>()),
2104 no_gc,
2105 ));
2106 }
2107
2108 if parent
2109 .downcast::<Element>()
2110 .is_some_and(|element| element.is_shadow_host())
2111 {
2112 return FlatTreeParent::NotInFlatTree;
2113 }
2114
2115 if parent
2116 .downcast::<HTMLSlotElement>()
2117 .is_some_and(|slot| slot.has_assigned_nodes())
2118 {
2119 return FlatTreeParent::NotInFlatTree;
2120 }
2121
2122 FlatTreeParent::Parent(parent)
2123 }
2124
2125 pub(crate) fn inclusive_ancestors_in_flat_tree_unrooted<'a>(
2126 &self,
2127 no_gc: &'a NoGC,
2128 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
2129 UnrootedSimpleNodeIterator::new(
2130 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
2131 move |node, no_gc| match node.parent_in_flat_tree(no_gc) {
2132 FlatTreeParent::Parent(parent) => {
2133 Some(UnrootedDom::from_dom(Dom::from_ref(&*parent), no_gc))
2135 },
2136 FlatTreeParent::NotInFlatTree | FlatTreeParent::RootNode => None,
2137 },
2138 no_gc,
2139 )
2140 }
2141
2142 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2144 debug_assert!(self.is_in_ua_widget());
2146 debug_assert!(pseudo_element.is_element_backed());
2147 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2148 }
2149
2150 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2151 self.rare_data
2152 .borrow()
2153 .as_ref()
2154 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2155 }
2156
2157 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2159 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2163 if ancestor.is_editing_host() {
2164 return Some(ancestor);
2165 }
2166 if ancestor
2167 .downcast::<HTMLElement>()
2168 .is_some_and(|el| el.ContentEditable().str() == "false")
2169 {
2170 return None;
2171 }
2172 }
2173 None
2174 }
2175
2176 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2177 self.editing_host_of().is_some()
2178 }
2179
2180 pub(crate) fn is_editing_host(&self) -> bool {
2182 self.downcast::<HTMLElement>()
2183 .is_some_and(HTMLElement::is_editing_host)
2184 }
2185
2186 pub(crate) fn is_editable(&self) -> bool {
2188 if self.is_editing_host() {
2190 return false;
2191 }
2192 let html_element = self.downcast::<HTMLElement>();
2194 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2195 return false;
2196 }
2197 let Some(parent) = self.GetParentNode() else {
2199 return false;
2200 };
2201 if !parent.is_editable_or_editing_host() {
2202 return false;
2203 }
2204 html_element.is_some() || (!self.is::<Element>() && parent.is::<HTMLElement>())
2206 }
2207}
2208
2209fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2211where
2212 I: Iterator<Item = DomRoot<Node>>,
2213{
2214 nodes.find(|node| {
2215 not_in.iter().all(|n| match *n {
2216 NodeOrString::Node(ref n) => n != node,
2217 _ => true,
2218 })
2219 })
2220}
2221
2222#[expect(unsafe_code)]
2225pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2226 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2227 DomRoot::from_ref(node)
2228}
2229
2230#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2232pub(crate) enum CloneChildrenFlag {
2233 CloneChildren,
2234 DoNotCloneChildren,
2235}
2236
2237impl From<bool> for CloneChildrenFlag {
2238 fn from(boolean: bool) -> Self {
2239 if boolean {
2240 CloneChildrenFlag::CloneChildren
2241 } else {
2242 CloneChildrenFlag::DoNotCloneChildren
2243 }
2244 }
2245}
2246
2247pub(super) fn as_uintptr<T>(t: &T) -> uintptr_t {
2248 t as *const T as uintptr_t
2249}
2250
2251impl Node {
2252 pub(crate) fn reflect_node<N>(
2253 cx: &mut JSContext,
2254 node: Box<N>,
2255 document: &Document,
2256 ) -> DomRoot<N>
2257 where
2258 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2259 {
2260 Self::reflect_node_with_proto(cx, node, document, None)
2261 }
2262
2263 pub(crate) fn reflect_node_with_proto<N>(
2264 cx: &mut JSContext,
2265 node: Box<N>,
2266 document: &Document,
2267 proto: Option<HandleObject>,
2268 ) -> DomRoot<N>
2269 where
2270 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2271 {
2272 let window = document.window();
2273 reflect_dom_object_with_proto(cx, node, window, proto)
2274 }
2275
2276 pub(crate) fn reflect_weak_referenceable_node_with_proto<N>(
2277 cx: &mut JSContext,
2278 node: Rc<N>,
2279 document: &Document,
2280 proto: Option<HandleObject>,
2281 ) -> DomRoot<N>
2282 where
2283 N: DerivedFrom<Node> + DomObject + WeakReferenceableDomObjectWrap<crate::DomTypeHolder>,
2284 {
2285 let window = document.window();
2286 reflect_weak_referenceable_dom_object_with_proto(cx, node, window, proto)
2287 }
2288
2289 pub(crate) fn new_inherited(doc: &Document) -> Node {
2290 Node::new_(NodeFlags::empty(), Some(doc))
2291 }
2292
2293 pub(crate) fn new_document_node() -> Node {
2294 Node::new_(
2295 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2296 None,
2297 )
2298 }
2299
2300 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2301 Node {
2302 eventtarget: EventTarget::new_inherited(),
2303 parent_node: Default::default(),
2304 first_child: Default::default(),
2305 last_child: Default::default(),
2306 next_sibling: Default::default(),
2307 prev_sibling: Default::default(),
2308 owner_doc: MutNullableDom::new(doc),
2309 rare_data: Default::default(),
2310 children_count: Cell::new(0u32),
2311 flags: Cell::new(flags),
2312 inclusive_descendants_version: Cell::new(0),
2313 layout_data: Default::default(),
2314 }
2315 }
2316
2317 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2319 document.add_script_and_layout_blocker();
2320
2321 let old_doc = node.owner_doc();
2323 old_doc.add_script_and_layout_blocker();
2324
2325 node.remove_self(cx);
2327
2328 if &*old_doc != document {
2330 for descendant in node.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes) {
2332 descendant.set_owner_doc(document);
2334
2335 if let Some(element) = descendant.downcast::<Element>() {
2338 for attribute in element.attrs().borrow().iter() {
2339 if let Some(attr) = attribute.as_attr() {
2340 attr.upcast::<Node>().set_owner_doc(document);
2341 }
2342 }
2343 }
2344 }
2345
2346 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2350 for descendant in node
2351 .traverse_preorder(ShadowIncluding::Yes)
2352 .filter_map(|d| d.as_custom_element())
2353 {
2354 custom_element_reaction_stack.enqueue_callback_reaction(
2355 cx,
2356 &descendant,
2357 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2358 None,
2359 );
2360 }
2361
2362 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2365 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2366 }
2367 }
2368
2369 old_doc.remove_script_and_layout_blocker(cx);
2370 document.remove_script_and_layout_blocker(cx);
2371 }
2372
2373 pub(crate) fn ensure_pre_insertion_validity(
2375 no_gc: &NoGC,
2376 node: &Node,
2377 parent: &Node,
2378 child: Option<&Node>,
2379 ) -> ErrorResult {
2380 match parent.type_id() {
2382 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2383 },
2384 _ => {
2385 return Err(Error::HierarchyRequest(Some(
2386 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2387 )));
2388 },
2389 }
2390
2391 if node.is_host_including_inclusive_ancestor(parent) {
2393 return Err(Error::HierarchyRequest(Some(
2394 "Node is a host-including inclusive ancestor of parent".to_owned(),
2395 )));
2396 }
2397
2398 if let Some(child) = child &&
2400 !parent.is_parent_of(child)
2401 {
2402 return Err(Error::NotFound(Some(
2403 "Child is non-null and its parent is not parent".to_owned(),
2404 )));
2405 }
2406
2407 match node.type_id() {
2408 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2412 if parent.is::<Document>() {
2413 return Err(Error::HierarchyRequest(Some(
2414 "Node is a Text node and parent is a document".to_owned(),
2415 )));
2416 }
2417 },
2418 NodeTypeId::DocumentType => {
2419 if !parent.is::<Document>() {
2420 return Err(Error::HierarchyRequest(Some(
2421 "Node is a doctype and parent is not a document".to_owned(),
2422 )));
2423 }
2424 },
2425 NodeTypeId::DocumentFragment(_) |
2426 NodeTypeId::Element(_) |
2427 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2428 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2429 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2432 return Err(Error::HierarchyRequest(Some(
2433 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2434 .to_owned(),
2435 )));
2436 },
2437 }
2438
2439 if parent.is::<Document>() {
2442 match node.type_id() {
2443 NodeTypeId::DocumentFragment(_) => {
2444 if node.children_unrooted(no_gc).any(|c| c.is::<Text>()) {
2446 return Err(Error::HierarchyRequest(None));
2447 }
2448 match node.child_elements_unrooted(no_gc).count() {
2449 0 => (),
2450 1 => {
2453 if parent.child_elements_unrooted(no_gc).next().is_some() {
2454 return Err(Error::HierarchyRequest(None));
2455 }
2456 if let Some(child) = child &&
2457 child
2458 .inclusively_following_siblings_unrooted(no_gc)
2459 .any(|child| child.is_doctype())
2460 {
2461 return Err(Error::HierarchyRequest(None));
2462 }
2463 },
2464 _ => return Err(Error::HierarchyRequest(None)),
2465 }
2466 },
2467 NodeTypeId::Element(_) => {
2468 if parent.child_elements_unrooted(no_gc).next().is_some() {
2470 return Err(Error::HierarchyRequest(Some(
2471 "Parent has an element child".to_owned(),
2472 )));
2473 }
2474 if let Some(child) = child &&
2475 child
2476 .inclusively_following_siblings_unrooted(no_gc)
2477 .any(|following| following.is_doctype())
2478 {
2479 return Err(Error::HierarchyRequest(Some(
2480 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
2481 )));
2482 }
2483 },
2484 NodeTypeId::DocumentType => {
2485 if parent.children_unrooted(no_gc).any(|c| c.is_doctype()) {
2488 return Err(Error::HierarchyRequest(None));
2489 }
2490 match child {
2491 Some(child) => {
2492 if parent
2493 .children_unrooted(no_gc)
2494 .take_while(|c| **c != child)
2495 .any(|c| c.is::<Element>())
2496 {
2497 return Err(Error::HierarchyRequest(None));
2498 }
2499 },
2500 None => {
2501 if parent.child_elements_unrooted(no_gc).next().is_some() {
2502 return Err(Error::HierarchyRequest(None));
2503 }
2504 },
2505 }
2506 },
2507 NodeTypeId::CharacterData(_) => (),
2508 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
2511 }
2512 }
2513 Ok(())
2514 }
2515
2516 pub(crate) fn pre_insert(
2518 cx: &mut JSContext,
2519 node: &Node,
2520 parent: &Node,
2521 child: Option<&Node>,
2522 ) -> Fallible<DomRoot<Node>> {
2523 Node::ensure_pre_insertion_validity(cx.no_gc(), node, parent, child)?;
2525
2526 let reference_child_root;
2528 let reference_child = match child {
2529 Some(child) if child == node => {
2531 reference_child_root = node.GetNextSibling();
2532 reference_child_root.as_deref()
2533 },
2534 _ => child,
2535 };
2536
2537 Node::insert(
2539 cx,
2540 node,
2541 parent,
2542 reference_child,
2543 SuppressObserver::Unsuppressed,
2544 );
2545
2546 Ok(DomRoot::from_ref(node))
2548 }
2549
2550 pub(crate) fn insert(
2552 cx: &mut JSContext,
2553 node: &Node,
2554 parent: &Node,
2555 child: Option<&Node>,
2556 suppress_observers: SuppressObserver,
2557 ) {
2558 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
2559
2560 rooted_vec!(let mut new_nodes);
2562 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2563 new_nodes.extend(
2564 node.children_unrooted(cx.no_gc())
2565 .map(|node| Dom::from_ref(&**node)),
2566 );
2567 new_nodes.r()
2568 } else {
2569 from_ref(&node)
2570 };
2571
2572 let count = new_nodes.len();
2574
2575 if count == 0 {
2577 return;
2578 }
2579
2580 let parent_document = parent.owner_doc();
2583 let from_document = node.owner_doc();
2584 from_document.add_script_and_layout_blocker();
2585 parent_document.add_script_and_layout_blocker();
2586
2587 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2589 for kid in new_nodes {
2591 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
2592 }
2593 vtable_for(node).children_changed(cx, &ChildrenMutation::ReplaceAll);
2594
2595 let mutation = LazyCell::new(|| Mutation::ChildList {
2597 added: None,
2598 removed: Some(new_nodes),
2599 prev: None,
2600 next: None,
2601 });
2602 MutationObserver::queue_a_mutation_record(cx, node, mutation);
2603 }
2604
2605 if let Some(child) = child &&
2611 let Some(parent_weak_ranges) = parent.weak_ranges_mut()
2612 {
2613 parent_weak_ranges.increase_above(parent, child.index(), count.try_into().unwrap());
2614 }
2615
2616 let previous_sibling = match suppress_observers {
2618 SuppressObserver::Unsuppressed => match child {
2619 Some(child) => child.GetPreviousSibling(),
2620 None => parent.GetLastChild(),
2621 },
2622 SuppressObserver::Suppressed => None,
2623 };
2624
2625 let mut static_node_list: SmallVec<[_; 4]> = Default::default();
2627
2628 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
2629 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
2630 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
2631
2632 for kid in new_nodes {
2634 Node::adopt(cx, kid, &parent.owner_document());
2636
2637 parent.add_child(cx, kid, child);
2640
2641 if let Some(ref shadow_root) = parent_shadow_root &&
2644 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
2645 (kid.is::<Element>() || kid.is::<Text>())
2646 {
2647 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(kid)));
2648 slottable.assign_a_slot(cx);
2649 }
2650
2651 if parent_in_shadow_tree &&
2654 let Some(slot_element) = parent_as_slot &&
2655 !slot_element.has_assigned_nodes()
2656 {
2657 slot_element.signal_a_slot_change(cx);
2658 }
2659
2660 kid.GetRootNode(&GetRootNodeOptions::empty())
2662 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
2663
2664 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
2667 if let Some(element) = DomRoot::downcast::<Element>(descendant.clone()) &&
2673 !element.is_custom()
2674 {
2675 try_upgrade_element(cx, &element);
2676 }
2677
2678 if !descendant.is_connected() {
2680 continue;
2681 }
2682
2683 if let Some(element) = DomRoot::downcast::<Element>(descendant.clone()) {
2685 if let Some(registry) = element.custom_element_registry() {
2687 if registry.is_scoped() {
2692 registry.add_scoped_document(&element.owner_document());
2693 }
2694 }
2695 if element.is_custom() {
2703 ScriptThread::custom_element_reaction_stack().enqueue_callback_reaction(
2704 cx,
2705 &element,
2706 CallbackReaction::Connected,
2707 None,
2708 );
2709 }
2710 else {
2712 try_upgrade_element(cx, &element);
2713 }
2714 }
2715 else if let Some(shadow_root) =
2722 DomRoot::downcast::<ShadowRoot>(descendant.clone()) &&
2723 let Some(custom_element_registry) = shadow_root.custom_element_registry() &&
2724 custom_element_registry.is_scoped()
2725 {
2726 custom_element_registry.add_scoped_document(shadow_root.owner_doc());
2727 }
2728
2729 static_node_list.push(descendant.clone());
2732 }
2733 }
2734
2735 Self::maybe_dirty_visible_selection_for_newly_inserted_nodes(cx.no_gc(), parent, new_nodes);
2736
2737 if let SuppressObserver::Unsuppressed = suppress_observers {
2738 vtable_for(parent).children_changed(
2741 cx,
2742 &ChildrenMutation::insert(previous_sibling.as_deref(), child),
2743 );
2744
2745 let mutation = LazyCell::new(|| Mutation::ChildList {
2748 added: Some(new_nodes),
2749 removed: None,
2750 prev: previous_sibling.as_deref(),
2751 next: child,
2752 });
2753 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2754 }
2755
2756 parent_document.add_delayed_task(
2767 task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
2768 for node in static_node_list {
2773 vtable_for(&node).post_connection_steps(cx);
2774 }
2775 }),
2776 );
2777
2778 parent_document.remove_script_and_layout_blocker(cx);
2779 from_document.remove_script_and_layout_blocker(cx);
2780 }
2781
2782 pub(crate) fn maybe_dirty_visible_selection_for_newly_inserted_nodes(
2785 no_gc: &NoGC,
2786 parent: &Node,
2787 inserted_nodes: &[&Node],
2788 ) {
2789 let Some(selection) = parent.owner_document().selection() else {
2790 return;
2791 };
2792
2793 for node in inserted_nodes {
2794 match node.parent_in_flat_tree(no_gc) {
2795 FlatTreeParent::RootNode | FlatTreeParent::NotInFlatTree => {},
2796 FlatTreeParent::Parent(parent) => {
2797 if parent.get_flag(NodeFlags::OVERLAPS_DOCUMENT_SELECTION) {
2798 selection.set_visible_selection_dirty();
2799 return;
2800 }
2801 },
2802 }
2803 }
2804 }
2805
2806 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
2808 parent.owner_doc().add_script_and_layout_blocker();
2809
2810 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
2812
2813 rooted_vec!(let mut added_nodes);
2817 let added_nodes = if let Some(node) = node.as_ref() {
2818 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2819 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
2820 added_nodes.r()
2821 } else {
2822 from_ref(node)
2823 }
2824 } else {
2825 &[] as &[&Node]
2826 };
2827
2828 for child in &*removed_nodes {
2830 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
2831 }
2832
2833 if let Some(node) = node {
2835 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
2836 }
2837
2838 vtable_for(parent).children_changed(cx, &ChildrenMutation::ReplaceAll);
2839
2840 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
2843 let mutation = LazyCell::new(|| Mutation::ChildList {
2844 added: Some(added_nodes),
2845 removed: Some(removed_nodes.r()),
2846 prev: None,
2847 next: None,
2848 });
2849 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2850 }
2851 parent.owner_doc().remove_script_and_layout_blocker(cx);
2852 }
2853
2854 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
2856 if string.is_empty() {
2857 Node::replace_all(cx, None, parent);
2858 } else {
2859 let text = Text::new(cx, string, &parent.owner_document());
2860 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
2861 };
2862 }
2863
2864 pub(super) fn pre_remove(
2866 cx: &mut JSContext,
2867 child: &Node,
2868 parent: &Node,
2869 ) -> Fallible<DomRoot<Node>> {
2870 match child.GetParentNode() {
2872 Some(ref node) if &**node != parent => return Err(Error::NotFound(None)),
2873 None => return Err(Error::NotFound(None)),
2874 _ => (),
2875 }
2876
2877 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
2879
2880 Ok(DomRoot::from_ref(child))
2882 }
2883
2884 pub(super) fn remove(
2886 cx: &mut JSContext,
2887 node: &Node,
2888 parent: &Node,
2889 suppress_observers: SuppressObserver,
2890 ) {
2891 parent.owner_doc().add_script_and_layout_blocker();
2892
2893 assert!(
2897 node.GetParentNode()
2898 .is_some_and(|node_parent| &*node_parent == parent)
2899 );
2900
2901 let cached_index = Node::live_range_pre_remove_steps(node, parent);
2904
2905 let old_previous_sibling = node.GetPreviousSibling();
2909
2910 let old_next_sibling = node.GetNextSibling();
2912
2913 parent.remove_child(cx, node, cached_index);
2916
2917 if let Some(slot) = node.assigned_slot() {
2919 slot.assign_slottables(cx);
2920 }
2921
2922 if parent.is_in_a_shadow_tree() &&
2925 let Some(slot_element) = parent.downcast::<HTMLSlotElement>() &&
2926 !slot_element.has_assigned_nodes()
2927 {
2928 slot_element.signal_a_slot_change(cx);
2929 }
2930
2931 let has_slot_descendant = node
2933 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
2934 .any(|elem| elem.is::<HTMLSlotElement>());
2935 if has_slot_descendant {
2936 parent
2938 .GetRootNode(&GetRootNodeOptions::empty())
2939 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
2940
2941 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Force);
2943 }
2944
2945 if let SuppressObserver::Unsuppressed = suppress_observers {
2949 vtable_for(parent).children_changed(
2950 cx,
2951 &ChildrenMutation::replace(
2952 old_previous_sibling.as_deref(),
2953 &Some(node),
2954 old_next_sibling.as_deref(),
2955 ),
2956 );
2957
2958 let removed = [node];
2959 let mutation = LazyCell::new(|| Mutation::ChildList {
2960 added: None,
2961 removed: Some(&removed),
2962 prev: old_previous_sibling.as_deref(),
2963 next: old_next_sibling.as_deref(),
2964 });
2965 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2966 }
2967 parent.owner_doc().remove_script_and_layout_blocker(cx);
2968 }
2969
2970 fn live_range_pre_remove_steps(node: &Node, parent: &Node) -> Option<u32> {
2972 if parent.weak_ranges_is_empty() {
2973 return None;
2974 }
2975
2976 let index = node.index();
2982
2983 if let Some(parent_weak_ranges) = parent.weak_ranges_mut() {
2990 parent_weak_ranges.decrease_above(parent, index, 1);
2991 }
2992
2993 Some(index)
2997 }
2998
2999 pub(crate) fn clone(
3001 cx: &mut JSContext,
3002 node: &Node,
3003 maybe_doc: Option<&Document>,
3004 clone_children: CloneChildrenFlag,
3005 registry: Option<DomRoot<CustomElementRegistry>>,
3006 ) -> DomRoot<Node> {
3007 let document = match maybe_doc {
3009 Some(doc) => DomRoot::from_ref(doc),
3010 None => node.owner_doc(),
3011 };
3012
3013 let copy: DomRoot<Node> = match node.type_id() {
3016 NodeTypeId::DocumentType => {
3017 let doctype = node.downcast::<DocumentType>().unwrap();
3018 let doctype = DocumentType::new(
3019 cx,
3020 doctype.name().clone(),
3021 Some(doctype.public_id().clone()),
3022 Some(doctype.system_id().clone()),
3023 &document,
3024 );
3025 DomRoot::upcast::<Node>(doctype)
3026 },
3027 NodeTypeId::Attr => {
3028 let attr = node.downcast::<Attr>().unwrap();
3029 let attr = Attr::new(
3030 cx,
3031 &document,
3032 attr.local_name().clone(),
3033 attr.value().clone(),
3034 attr.name().clone(),
3035 attr.namespace().clone(),
3036 attr.prefix().cloned(),
3037 None,
3038 );
3039 DomRoot::upcast::<Node>(attr)
3040 },
3041 NodeTypeId::DocumentFragment(_) => {
3042 let doc_fragment = DocumentFragment::new(cx, &document);
3043 DomRoot::upcast::<Node>(doc_fragment)
3044 },
3045 NodeTypeId::CharacterData(_) => {
3046 let cdata = node.downcast::<CharacterData>().unwrap();
3047 cdata.clone_with_data(cx, cdata.Data(), &document)
3048 },
3049 NodeTypeId::Document(_) => {
3050 let document = node.downcast::<Document>().unwrap();
3053 let is_html_doc = if document.is_html_document() {
3054 IsHTMLDocument::HTMLDocument
3055 } else {
3056 IsHTMLDocument::NonHTMLDocument
3057 };
3058 let window = document.window();
3059 let loader = DocumentLoader::new(&document.loader());
3060 let document = Document::new(
3061 cx,
3062 window,
3063 HasBrowsingContext::No,
3064 Some(document.url()),
3065 None,
3066 document.origin().clone(),
3068 is_html_doc,
3069 None,
3070 None,
3071 DocumentActivity::Inactive,
3072 DocumentSource::NotFromParser,
3073 loader,
3074 None,
3075 document.status_code(),
3076 Default::default(),
3077 false,
3078 document.allow_declarative_shadow_roots(),
3079 Some(document.insecure_requests_policy()),
3080 document.has_trustworthy_ancestor_or_current_origin(),
3081 document.custom_element_reaction_stack(),
3082 document.creation_sandboxing_flag_set(),
3083 document.pipeline_id(),
3084 document.image_cache(),
3085 );
3086 DomRoot::upcast::<Node>(document)
3090 },
3091 NodeTypeId::Element(..) => {
3093 let element = node.downcast::<Element>().unwrap();
3094 let registry = element.custom_element_registry().or(registry);
3097 let registry =
3100 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3101 document.custom_element_registry()
3102 } else {
3103 registry
3104 };
3105 let name = QualName {
3109 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3110 ns: element.namespace().clone(),
3111 local: element.local_name().clone(),
3112 };
3113 let element = Element::create(
3114 cx,
3115 name,
3116 element.get_is(),
3117 &document,
3118 ElementCreator::ScriptCreated,
3119 CustomElementCreationMode::Asynchronous,
3120 None,
3121 );
3122 element.set_custom_element_registry(registry.as_deref(), cx.no_gc());
3124 DomRoot::upcast::<Node>(element)
3125 },
3126 };
3127
3128 let document = match copy.downcast::<Document>() {
3131 Some(doc) => DomRoot::from_ref(doc),
3132 None => DomRoot::from_ref(&*document),
3133 };
3134 assert!(copy.owner_doc() == document);
3135
3136 match node.type_id() {
3138 NodeTypeId::Document(_) => {
3139 let node_doc = node.downcast::<Document>().unwrap();
3140 let copy_doc = copy.downcast::<Document>().unwrap();
3141 copy_doc.set_encoding(node_doc.encoding());
3142 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3143 },
3144 NodeTypeId::Element(..) => {
3145 let node_elem = node.downcast::<Element>().unwrap();
3146 let copy_elem = copy.downcast::<Element>().unwrap();
3147
3148 node_elem.copy_all_attributes_to_other_element(cx, copy_elem);
3150 },
3151 _ => (),
3152 }
3153
3154 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3157
3158 if clone_children == CloneChildrenFlag::CloneChildren {
3161 for child in node.children() {
3162 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3163 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3164 }
3165 }
3166
3167 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3170 let node_elem = node.downcast::<Element>().unwrap();
3171 let copy_elem = copy.downcast::<Element>().unwrap();
3172
3173 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3174 assert!(!copy_elem.is_shadow_host());
3176
3177 let copy_shadow_root =
3181 copy_elem.attach_shadow(
3182 cx,
3183 IsUserAgentWidget::No,
3184 shadow_root.Mode(),
3185 shadow_root.Clonable(),
3186 shadow_root.Serializable(),
3187 shadow_root.DelegatesFocus(),
3188 shadow_root.SlotAssignment(),
3189 )
3190 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3191
3192 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3194
3195 for child in shadow_root.upcast::<Node>().children() {
3198 let child_copy = Node::clone(
3199 cx,
3200 &child,
3201 Some(&document),
3202 CloneChildrenFlag::CloneChildren,
3203 None,
3204 );
3205
3206 let _inserted_node =
3208 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3209 }
3210 }
3211 }
3212
3213 copy
3215 }
3216
3217 pub(crate) fn child_text_content(&self) -> DOMString {
3219 Node::collect_text_contents(self.children())
3220 }
3221
3222 pub(crate) fn descendant_text_content(&self) -> DOMString {
3224 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3225 }
3226
3227 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3228 iterator: T,
3229 ) -> DOMString {
3230 let mut content = String::new();
3231 for node in iterator {
3232 if let Some(text) = node.downcast::<Text>() {
3233 content.push_str(&text.upcast::<CharacterData>().data());
3234 }
3235 }
3236 DOMString::from(content)
3237 }
3238
3239 pub(crate) fn set_text_content_for_element(
3241 &self,
3242 cx: &mut JSContext,
3243 value: Option<DOMString>,
3244 ) {
3245 assert!(matches!(
3248 self.type_id(),
3249 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3250 ));
3251 let value = value.unwrap_or_default();
3252 let node = if value.is_empty() {
3253 None
3255 } else {
3256 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3259 };
3260
3261 Self::replace_all(cx, node.as_deref(), self);
3263 }
3264
3265 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3266 match namespace {
3267 ns!() => None,
3268 _ => Some(DOMString::from(&*namespace)),
3270 }
3271 }
3272
3273 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3275 match node.type_id() {
3276 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3277 NodeTypeId::Attr => node
3278 .downcast::<Attr>()
3279 .unwrap()
3280 .GetOwnerElement()
3281 .as_ref()
3282 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3283 NodeTypeId::Document(_) => node
3284 .downcast::<Document>()
3285 .unwrap()
3286 .GetDocumentElement()
3287 .as_ref()
3288 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3289 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3290 _ => node
3291 .GetParentElement()
3292 .as_ref()
3293 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3294 }
3295 }
3296
3297 #[expect(unsafe_code)]
3305 pub(crate) unsafe fn from_untrusted_node_address(
3306 candidate: UntrustedNodeAddress,
3307 ) -> &'static Self {
3308 let candidate = candidate.0 as usize;
3310 let object = candidate as *mut JSObject;
3311 if object.is_null() {
3312 panic!("Attempted to create a `Node` from an invalid pointer!")
3313 }
3314
3315 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3316 }
3317
3318 pub(crate) fn html_serialize(
3319 &self,
3320 cx: &mut JSContext,
3321 traversal_scope: html_serialize::TraversalScope,
3322 serialize_shadow_roots: bool,
3323 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3324 ) -> DOMString {
3325 let mut writer = vec![];
3326 let mut serializer = HtmlSerializer::new(
3327 &mut writer,
3328 html_serialize::SerializeOpts {
3329 traversal_scope: traversal_scope.clone(),
3330 ..Default::default()
3331 },
3332 );
3333
3334 serialize_html_fragment(
3335 cx,
3336 self,
3337 &mut serializer,
3338 traversal_scope,
3339 serialize_shadow_roots,
3340 shadow_roots,
3341 )
3342 .expect("Serializing node failed");
3343
3344 DOMString::from(String::from_utf8(writer).unwrap())
3346 }
3347
3348 pub(crate) fn xml_serialize(
3350 &self,
3351 traversal_scope: xml_serialize::TraversalScope,
3352 ) -> Fallible<DOMString> {
3353 let mut writer = vec![];
3354 xml_serialize::serialize(
3355 &mut writer,
3356 &HtmlSerialize::new(self),
3357 xml_serialize::SerializeOpts { traversal_scope },
3358 )
3359 .map_err(|error| {
3360 error!("Cannot serialize node: {error}");
3361 Error::InvalidState(None)
3362 })?;
3363
3364 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3366 error!("Cannot serialize node: {error}");
3367 Error::InvalidState(None)
3368 })?);
3369
3370 Ok(string)
3371 }
3372
3373 pub(crate) fn fragment_serialization_algorithm(
3375 &self,
3376 cx: &mut JSContext,
3377 require_well_formed: bool,
3378 ) -> Fallible<DOMString> {
3379 let context_document = self.owner_document();
3381
3382 if context_document.is_html_document() {
3385 return Ok(self.html_serialize(
3386 cx,
3387 html_serialize::TraversalScope::ChildrenOnly(None),
3388 false,
3389 vec![],
3390 ));
3391 }
3392
3393 let _ = require_well_formed;
3396 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3397 }
3398
3399 pub(crate) fn get_next_sibling_unrooted<'a>(
3400 &self,
3401 no_gc: &'a NoGC,
3402 ) -> Option<UnrootedDom<'a, Node>> {
3403 self.next_sibling.get_unrooted(no_gc)
3404 }
3405
3406 pub(crate) fn next_flat_tree_sibling_unrooted<'a>(
3407 &self,
3408 no_gc: &'a NoGC,
3409 ) -> Option<UnrootedDom<'a, Node>> {
3410 if let Some(slot_element) = self.assigned_slot() {
3411 return slot_element
3415 .assigned_nodes()
3416 .iter()
3417 .skip_while(|slottable| &*slottable.0 != self)
3418 .nth(1)
3420 .map(|next_slottable| UnrootedDom::from_dom(next_slottable.0.clone(), no_gc));
3421 }
3422 self.get_next_sibling_unrooted(no_gc)
3423 }
3424
3425 pub(crate) fn get_previous_sibling_unrooted<'a>(
3426 &self,
3427 no_gc: &'a NoGC,
3428 ) -> Option<UnrootedDom<'a, Node>> {
3429 self.prev_sibling.get_unrooted(no_gc)
3430 }
3431
3432 pub(crate) fn get_first_child_unrooted<'a>(
3433 &self,
3434 no_gc: &'a NoGC,
3435 ) -> Option<UnrootedDom<'a, Node>> {
3436 self.first_child.get_unrooted(no_gc)
3437 }
3438
3439 pub(crate) fn first_flat_tree_child_unrooted<'a>(
3440 &self,
3441 no_gc: &'a NoGC,
3442 ) -> Option<UnrootedDom<'a, Node>> {
3443 let Some(element) = self.downcast::<Element>() else {
3444 return self.get_first_child_unrooted(no_gc);
3445 };
3446 if let Some(shadow_root) = element.shadow_root_unrooted(no_gc) {
3447 return shadow_root
3448 .upcast::<Node>()
3449 .first_flat_tree_child_unrooted(no_gc);
3450 };
3451
3452 if let Some(slot_element) = element.downcast::<HTMLSlotElement>() &&
3456 slot_element.has_assigned_nodes() &&
3457 let Some(assigned_node) = slot_element.assigned_nodes().first()
3458 {
3459 return Some(UnrootedDom::from_dom(assigned_node.0.clone(), no_gc));
3460 }
3461
3462 self.get_first_child_unrooted(no_gc)
3463 }
3464
3465 fn get_last_child_unrooted<'b>(&self, no_gc: &'b NoGC) -> Option<UnrootedDom<'b, Node>> {
3466 self.last_child.get_unrooted(no_gc)
3467 }
3468
3469 pub(crate) fn get_parent_node_unrooted<'a>(
3470 &self,
3471 no_gc: &'a NoGC,
3472 ) -> Option<UnrootedDom<'a, Node>> {
3473 self.parent_node.get_unrooted(no_gc)
3474 }
3475
3476 pub(crate) fn compare_dom_tree_position(
3478 &self,
3479 other: &Node,
3480 common_ancestor: &Node,
3481 shadow_including: ShadowIncluding,
3482 ) -> Ordering {
3483 debug_assert!(
3484 self.inclusive_ancestors(shadow_including)
3485 .any(|ancestor| &*ancestor == common_ancestor)
3486 );
3487 debug_assert!(
3488 other
3489 .inclusive_ancestors(shadow_including)
3490 .any(|ancestor| &*ancestor == common_ancestor)
3491 );
3492
3493 if self == other {
3494 return Ordering::Equal;
3495 }
3496
3497 if self == common_ancestor {
3498 return Ordering::Less;
3499 }
3500 if other == common_ancestor {
3501 return Ordering::Greater;
3502 }
3503
3504 let my_ancestors: Vec<_> = self
3505 .inclusive_ancestors(shadow_including)
3506 .take_while(|ancestor| &**ancestor != common_ancestor)
3507 .collect();
3508 let other_ancestors: Vec<_> = other
3509 .inclusive_ancestors(shadow_including)
3510 .take_while(|ancestor| &**ancestor != common_ancestor)
3511 .collect();
3512
3513 let mut i = my_ancestors.len() - 1;
3515 let mut j = other_ancestors.len() - 1;
3516
3517 while my_ancestors[i] == other_ancestors[j] {
3518 if i == 0 {
3519 debug_assert_ne!(j, 0, "Equal inclusive ancestors but nodes are not equal?");
3521 return Ordering::Less;
3522 }
3523 if j == 0 {
3524 return Ordering::Greater;
3526 }
3527
3528 i -= 1;
3529 j -= 1;
3530 }
3531
3532 if my_ancestors[i]
3535 .preceding_siblings()
3536 .any(|sibling| sibling == other_ancestors[j])
3537 {
3538 Ordering::Greater
3540 } else {
3541 debug_assert!(
3543 other_ancestors[j]
3544 .preceding_siblings()
3545 .any(|sibling| sibling == my_ancestors[i])
3546 );
3547 Ordering::Less
3548 }
3549 }
3550}
3551
3552impl NodeMethods<crate::DomTypeHolder> for Node {
3553 fn NodeType(&self) -> u16 {
3555 match self.type_id() {
3556 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3557 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3558 NodeConstants::TEXT_NODE
3559 },
3560 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3561 NodeConstants::CDATA_SECTION_NODE
3562 },
3563 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3564 NodeConstants::PROCESSING_INSTRUCTION_NODE
3565 },
3566 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3567 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3568 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3569 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3570 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3571 }
3572 }
3573
3574 fn NodeName(&self) -> DOMString {
3576 match self.type_id() {
3577 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3578 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3579 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3580 DOMString::from("#text")
3581 },
3582 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3583 DOMString::from("#cdata-section")
3584 },
3585 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3586 self.downcast::<ProcessingInstruction>().unwrap().Target()
3587 },
3588 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => DOMString::from("#comment"),
3589 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3590 NodeTypeId::DocumentFragment(_) => DOMString::from("#document-fragment"),
3591 NodeTypeId::Document(_) => DOMString::from("#document"),
3592 }
3593 }
3594
3595 fn BaseURI(&self) -> USVString {
3597 USVString(String::from(self.owner_doc().base_url().as_str()))
3598 }
3599
3600 fn IsConnected(&self) -> bool {
3602 self.is_connected()
3603 }
3604
3605 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3607 match self.type_id() {
3608 NodeTypeId::Document(_) => None,
3609 _ => Some(self.owner_doc()),
3610 }
3611 }
3612
3613 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3615 if !options.composed &&
3616 let Some(shadow_root) = self.containing_shadow_root()
3617 {
3618 return DomRoot::upcast(shadow_root);
3619 }
3620
3621 if self.is_connected() {
3622 DomRoot::from_ref(self.owner_doc().upcast::<Node>())
3623 } else {
3624 self.inclusive_ancestors(ShadowIncluding::Yes)
3625 .last()
3626 .unwrap()
3627 }
3628 }
3629
3630 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
3632 self.parent_node().get()
3633 }
3634
3635 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
3637 self.GetParentNode().and_then(DomRoot::downcast)
3638 }
3639
3640 fn HasChildNodes(&self) -> bool {
3642 self.first_child().get().is_some()
3643 }
3644
3645 fn ChildNodes(&self, cx: &mut JSContext) -> DomRoot<NodeList> {
3647 if let Some(list) = self.ensure_rare_data().child_list.get() {
3648 return list;
3649 }
3650
3651 let doc = self.owner_doc();
3652 let window = doc.window();
3653 let list = NodeList::new_child_list(cx, window, self);
3654 self.ensure_rare_data().child_list.set(Some(&list));
3655 list
3656 }
3657
3658 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
3660 self.first_child().get()
3661 }
3662
3663 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
3665 self.last_child().get()
3666 }
3667
3668 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
3670 self.prev_sibling().get()
3671 }
3672
3673 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
3675 self.next_sibling().get()
3676 }
3677
3678 fn GetNodeValue(&self) -> Option<DOMString> {
3680 match self.type_id() {
3681 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3682 NodeTypeId::CharacterData(_) => {
3683 self.downcast::<CharacterData>().map(CharacterData::Data)
3684 },
3685 _ => None,
3686 }
3687 }
3688
3689 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
3691 match self.type_id() {
3692 NodeTypeId::Attr => {
3693 let attr = self.downcast::<Attr>().unwrap();
3694 attr.SetValue(cx, val.unwrap_or_default())?;
3695 },
3696 NodeTypeId::CharacterData(_) => {
3697 let character_data = self.downcast::<CharacterData>().unwrap();
3698 character_data.SetData(cx, val.unwrap_or_default());
3699 },
3700 _ => {},
3701 };
3702 Ok(())
3703 }
3704
3705 fn GetTextContent(&self) -> Option<DOMString> {
3707 match self.type_id() {
3708 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3709 let content =
3710 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
3711 Some(content)
3712 },
3713 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3714 NodeTypeId::CharacterData(..) => {
3715 let characterdata = self.downcast::<CharacterData>().unwrap();
3716 Some(characterdata.Data())
3717 },
3718 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
3719 }
3720 }
3721
3722 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
3724 match self.type_id() {
3725 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3726 self.set_text_content_for_element(cx, value);
3727 },
3728 NodeTypeId::Attr => {
3729 let attr = self.downcast::<Attr>().unwrap();
3730 attr.SetValue(cx, value.unwrap_or_default())?;
3731 },
3732 NodeTypeId::CharacterData(..) => {
3733 let characterdata = self.downcast::<CharacterData>().unwrap();
3734 characterdata.SetData(cx, value.unwrap_or_default());
3735 },
3736 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
3737 };
3738 Ok(())
3739 }
3740
3741 fn InsertBefore(
3743 &self,
3744 cx: &mut JSContext,
3745 node: &Node,
3746 child: Option<&Node>,
3747 ) -> Fallible<DomRoot<Node>> {
3748 Node::pre_insert(cx, node, self, child)
3749 }
3750
3751 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3753 Node::pre_insert(cx, node, self, None)
3754 }
3755
3756 fn ReplaceChild(
3758 &self,
3759 cx: &mut JSContext,
3760 node: &Node,
3761 child: &Node,
3762 ) -> Fallible<DomRoot<Node>> {
3763 match self.type_id() {
3766 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3767 },
3768 _ => return Err(Error::HierarchyRequest(None)),
3769 }
3770
3771 if node.is_inclusive_ancestor_of(self) {
3774 return Err(Error::HierarchyRequest(None));
3775 }
3776
3777 if !self.is_parent_of(child) {
3779 return Err(Error::NotFound(None));
3780 }
3781
3782 match node.type_id() {
3787 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
3788 return Err(Error::HierarchyRequest(None));
3789 },
3790 NodeTypeId::DocumentType if !self.is::<Document>() => {
3791 return Err(Error::HierarchyRequest(None));
3792 },
3793 NodeTypeId::Document(_) | NodeTypeId::Attr => {
3794 return Err(Error::HierarchyRequest(None));
3795 },
3796 _ => (),
3797 }
3798
3799 if self.is::<Document>() {
3802 match node.type_id() {
3803 NodeTypeId::DocumentFragment(_) => {
3805 if node.children_unrooted(cx.no_gc()).any(|c| c.is::<Text>()) {
3807 return Err(Error::HierarchyRequest(None));
3808 }
3809 match node.child_elements_unrooted(cx.no_gc()).count() {
3810 0 => (),
3811 1 => {
3813 if self
3814 .child_elements_unrooted(cx.no_gc())
3815 .any(|c| c.upcast::<Node>() != child)
3816 {
3817 return Err(Error::HierarchyRequest(None));
3818 }
3819 if child.following_siblings().any(|child| child.is_doctype()) {
3820 return Err(Error::HierarchyRequest(None));
3821 }
3822 },
3823 _ => return Err(Error::HierarchyRequest(None)),
3825 }
3826 },
3827 NodeTypeId::Element(..) => {
3829 if self
3830 .child_elements_unrooted(cx.no_gc())
3831 .any(|c| c.upcast::<Node>() != child)
3832 {
3833 return Err(Error::HierarchyRequest(None));
3834 }
3835 if child.following_siblings().any(|child| child.is_doctype()) {
3836 return Err(Error::HierarchyRequest(None));
3837 }
3838 },
3839 NodeTypeId::DocumentType => {
3841 if self
3842 .children_unrooted(cx.no_gc())
3843 .any(|c| c.is_doctype() && *c != child)
3844 {
3845 return Err(Error::HierarchyRequest(None));
3846 }
3847 if self
3848 .children_unrooted(cx.no_gc())
3849 .take_while(|c| **c != child)
3850 .any(|c| c.is::<Element>())
3851 {
3852 return Err(Error::HierarchyRequest(None));
3853 }
3854 },
3855 NodeTypeId::CharacterData(..) => (),
3856 NodeTypeId::Document(_) => unreachable!(),
3859 NodeTypeId::Attr => unreachable!(),
3860 }
3861 }
3862
3863 let child_next_sibling = child.GetNextSibling();
3866 let node_next_sibling = node.GetNextSibling();
3867 let reference_child = if child_next_sibling.as_deref() == Some(node) {
3868 node_next_sibling.as_deref()
3869 } else {
3870 child_next_sibling.as_deref()
3871 };
3872
3873 let previous_sibling = child.GetPreviousSibling();
3875
3876 let document = self.owner_document();
3880 Node::adopt(cx, node, &document);
3881
3882 let removed_child = if node != child {
3887 Node::remove(cx, child, self, SuppressObserver::Suppressed);
3889 Some(child)
3890 } else {
3891 None
3892 };
3893
3894 rooted_vec!(let mut nodes);
3896 let nodes = if node.type_id() ==
3897 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
3898 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
3899 {
3900 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
3901 nodes.r()
3902 } else {
3903 from_ref(&node)
3904 };
3905
3906 Node::insert(
3908 cx,
3909 node,
3910 self,
3911 reference_child,
3912 SuppressObserver::Suppressed,
3913 );
3914
3915 vtable_for(self).children_changed(
3916 cx,
3917 &ChildrenMutation::replace(
3918 previous_sibling.as_deref(),
3919 &removed_child,
3920 reference_child,
3921 ),
3922 );
3923
3924 let removed = removed_child.map(|r| [r]);
3927 let mutation = LazyCell::new(|| Mutation::ChildList {
3928 added: Some(nodes),
3929 removed: removed.as_ref().map(|r| &r[..]),
3930 prev: previous_sibling.as_deref(),
3931 next: reference_child,
3932 });
3933
3934 MutationObserver::queue_a_mutation_record(cx, self, mutation);
3935
3936 Ok(DomRoot::from_ref(child))
3938 }
3939
3940 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3942 Node::pre_remove(cx, node, self)
3943 }
3944
3945 fn Normalize(&self, cx: &mut JSContext) {
3947 let mut children = self.children().enumerate().peekable();
3948 while let Some((_, node)) = children.next() {
3949 if let Some(text) = node.downcast::<Text>() {
3950 if text.is::<CDATASection>() {
3951 continue;
3952 }
3953 let cdata = text.upcast::<CharacterData>();
3954 let mut length = cdata.Length();
3955 if length == 0 {
3956 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
3957 continue;
3958 }
3959 while children.peek().is_some_and(|(_, sibling)| {
3960 sibling.is::<Text>() && !sibling.is::<CDATASection>()
3961 }) {
3962 let (index, sibling) = children.next().unwrap();
3963 if let Some(sibling_weak_ranges) = sibling.weak_ranges_mut() {
3964 sibling_weak_ranges
3965 .drain_to_preceding_text_sibling(&sibling, &node, length);
3966 }
3967 if let Some(weak_ranges) = self.weak_ranges_mut() {
3968 weak_ranges.move_to_text_child_at(self, index as u32, &node, length);
3969 }
3970 let sibling_cdata = sibling.downcast::<CharacterData>().unwrap();
3971 length += sibling_cdata.Length();
3972 cdata.append_data(cx, &sibling_cdata.data());
3973 Node::remove(cx, &sibling, self, SuppressObserver::Unsuppressed);
3974 }
3975 } else {
3976 node.Normalize(cx);
3977 }
3978 }
3979 }
3980
3981 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
3983 if self.is::<ShadowRoot>() {
3985 return Err(Error::NotSupported(None));
3986 }
3987
3988 let result = Node::clone(
3990 cx,
3991 self,
3992 None,
3993 if subtree {
3994 CloneChildrenFlag::CloneChildren
3995 } else {
3996 CloneChildrenFlag::DoNotCloneChildren
3997 },
3998 None,
3999 );
4000 Ok(result)
4001 }
4002
4003 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
4005 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
4006 let doctype = node.downcast::<DocumentType>().unwrap();
4007 let other_doctype = other.downcast::<DocumentType>().unwrap();
4008 (*doctype.name() == *other_doctype.name()) &&
4009 (*doctype.public_id() == *other_doctype.public_id()) &&
4010 (*doctype.system_id() == *other_doctype.system_id())
4011 }
4012 fn is_equal_element(node: &Node, other: &Node) -> bool {
4013 let element = node.downcast::<Element>().unwrap();
4014 let other_element = other.downcast::<Element>().unwrap();
4015 (*element.namespace() == *other_element.namespace()) &&
4016 (*element.prefix() == *other_element.prefix()) &&
4017 (*element.local_name() == *other_element.local_name()) &&
4018 (element.attrs().borrow().len() == other_element.attrs().borrow().len())
4019 }
4020 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
4021 let pi = node.downcast::<ProcessingInstruction>().unwrap();
4022 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
4023 (*pi.target() == *other_pi.target()) &&
4024 (*pi.upcast::<CharacterData>().data() ==
4025 *other_pi.upcast::<CharacterData>().data())
4026 }
4027 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
4028 let characterdata = node.downcast::<CharacterData>().unwrap();
4029 let other_characterdata = other.downcast::<CharacterData>().unwrap();
4030 *characterdata.data() == *other_characterdata.data()
4031 }
4032 fn is_equal_attr(node: &Node, other: &Node) -> bool {
4033 let attr = node.downcast::<Attr>().unwrap();
4034 let other_attr = other.downcast::<Attr>().unwrap();
4035 (*attr.namespace() == *other_attr.namespace()) &&
4036 (attr.local_name() == other_attr.local_name()) &&
4037 (**attr.value() == **other_attr.value())
4038 }
4039 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
4040 let element = node.downcast::<Element>().unwrap();
4041 let other_element = other.downcast::<Element>().unwrap();
4042 assert!(element.attrs().borrow().len() == other_element.attrs().borrow().len());
4043 element.attrs().borrow().iter().all(|attr| {
4044 other_element.attrs().borrow().iter().any(|other_attr| {
4045 (*attr.namespace() == *other_attr.namespace()) &&
4046 (attr.local_name() == other_attr.local_name()) &&
4047 (**attr.value() == **other_attr.value())
4048 })
4049 })
4050 }
4051
4052 fn is_equal_node(this: &Node, node: &Node) -> bool {
4053 if this.NodeType() != node.NodeType() {
4055 return false;
4056 }
4057
4058 match node.type_id() {
4059 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
4061 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
4062 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
4063 if !is_equal_processinginstruction(this, node) =>
4064 {
4065 return false;
4066 },
4067 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
4068 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
4069 if !is_equal_characterdata(this, node) =>
4070 {
4071 return false;
4072 },
4073 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
4075 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
4076
4077 _ => (),
4078 }
4079
4080 if this.children_count() != node.children_count() {
4082 return false;
4083 }
4084
4085 this.children()
4087 .zip(node.children())
4088 .all(|(child, other_child)| is_equal_node(&child, &other_child))
4089 }
4090 match maybe_node {
4091 None => false,
4093 Some(node) => is_equal_node(self, node),
4095 }
4096 }
4097
4098 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
4100 match other_node {
4101 Some(node) => self == node,
4102 None => false,
4103 }
4104 }
4105
4106 fn CompareDocumentPosition(&self, other: &Node) -> u16 {
4108 if self == other {
4110 return 0;
4111 }
4112
4113 let mut node1 = Some(other);
4115 let mut node2 = Some(self);
4116
4117 let mut attr1: Option<&Attr> = None;
4119 let mut attr2: Option<&Attr> = None;
4120
4121 let attr1owner;
4126 if let Some(a) = other.downcast::<Attr>() {
4127 attr1 = Some(a);
4128 attr1owner = a.GetOwnerElement();
4129 node1 = match attr1owner {
4130 Some(ref e) => Some(e.upcast()),
4131 None => None,
4132 }
4133 }
4134
4135 let attr2owner;
4138 if let Some(a) = self.downcast::<Attr>() {
4139 attr2 = Some(a);
4140 attr2owner = a.GetOwnerElement();
4141 node2 = match attr2owner {
4142 Some(ref e) => Some(e.upcast()),
4143 None => None,
4144 }
4145 }
4146
4147 if let Some(node2) = node2 &&
4152 Some(node2) == node1 &&
4153 let (Some(a1), Some(a2)) = (attr1, attr2)
4154 {
4155 let attrs = node2.downcast::<Element>().unwrap().attrs();
4156 for attr in attrs.borrow().iter() {
4160 if (*attr.namespace() == *a1.namespace()) &&
4161 (attr.local_name() == a1.local_name()) &&
4162 (**attr.value() == **a1.value())
4163 {
4164 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4165 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4166 }
4167 if (*attr.namespace() == *a2.namespace()) &&
4168 (attr.local_name() == a2.local_name()) &&
4169 (**attr.value() == **a2.value())
4170 {
4171 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4172 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4173 }
4174 }
4175 unreachable!();
4178 }
4179
4180 match (node1, node2) {
4182 (None, _) => {
4183 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4185 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4186 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4187 },
4188 (_, None) => {
4189 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4191 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4192 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4193 },
4194 (Some(node1), Some(node2)) => {
4195 let mut self_and_ancestors = node2
4197 .inclusive_ancestors(ShadowIncluding::No)
4198 .collect::<SmallVec<[_; 20]>>();
4199 let mut other_and_ancestors = node1
4200 .inclusive_ancestors(ShadowIncluding::No)
4201 .collect::<SmallVec<[_; 20]>>();
4202
4203 if self_and_ancestors.last() != other_and_ancestors.last() {
4204 let arbitrary = as_uintptr::<Node>(self_and_ancestors.last().unwrap()) <
4207 as_uintptr::<Node>(other_and_ancestors.last().unwrap());
4208 let arbitrary = if arbitrary {
4209 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4210 } else {
4211 NodeConstants::DOCUMENT_POSITION_PRECEDING
4212 };
4213
4214 return arbitrary +
4216 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4217 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4218 }
4219 let mut parent = self_and_ancestors.pop().unwrap();
4221 other_and_ancestors.pop().unwrap();
4222
4223 let mut current_position =
4224 cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
4225
4226 while current_position > 0 {
4227 current_position -= 1;
4228 let child_1 = self_and_ancestors.pop().unwrap();
4229 let child_2 = other_and_ancestors.pop().unwrap();
4230
4231 if child_1 != child_2 {
4232 for child in parent.children() {
4233 if child == child_1 {
4234 return NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4236 }
4237 if child == child_2 {
4238 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4240 }
4241 }
4242 }
4243
4244 parent = child_1;
4245 }
4246
4247 if self_and_ancestors.len() < other_and_ancestors.len() {
4252 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4253 NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
4254 } else {
4255 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4256 NodeConstants::DOCUMENT_POSITION_CONTAINS
4257 }
4258 },
4259 }
4260 }
4261
4262 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4264 match maybe_other {
4265 None => false,
4266 Some(other) => self.is_inclusive_ancestor_of(other),
4267 }
4268 }
4269
4270 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4272 let namespace = namespace_from_domstring(namespace);
4273
4274 if namespace == ns!() {
4276 return None;
4277 }
4278
4279 match self.type_id() {
4281 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4282 NodeTypeId::Document(_) => self
4283 .downcast::<Document>()
4284 .unwrap()
4285 .GetDocumentElement()
4286 .and_then(|element| element.lookup_prefix(namespace)),
4287 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4288 NodeTypeId::Attr => self
4289 .downcast::<Attr>()
4290 .unwrap()
4291 .GetOwnerElement()
4292 .and_then(|element| element.lookup_prefix(namespace)),
4293 _ => self
4294 .GetParentElement()
4295 .and_then(|element| element.lookup_prefix(namespace)),
4296 }
4297 }
4298
4299 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4301 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4303
4304 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4306 }
4307
4308 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4310 let namespace = namespace_from_domstring(namespace);
4312 Node::locate_namespace(self, None) == namespace
4314 }
4315}
4316
4317pub(crate) trait NodeTraits {
4318 fn owner_document(&self) -> DomRoot<Document>;
4322 fn owner_window(&self) -> DomRoot<Window>;
4326 fn owner_global(&self) -> DomRoot<GlobalScope>;
4330 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4332 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4335}
4336
4337impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4338 fn owner_document(&self) -> DomRoot<Document> {
4339 self.upcast().owner_doc()
4340 }
4341
4342 fn owner_window(&self) -> DomRoot<Window> {
4343 DomRoot::from_ref(self.owner_document().window())
4344 }
4345
4346 fn owner_global(&self) -> DomRoot<GlobalScope> {
4347 DomRoot::from_ref(self.owner_window().upcast())
4348 }
4349
4350 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4351 Node::containing_shadow_root(self.upcast())
4352 }
4353
4354 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4355 self.containing_shadow_root()
4356 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4357 .unwrap_or_else(|| {
4358 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4359 })
4360 }
4361}
4362
4363impl VirtualMethods for Node {
4364 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4365 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4366 }
4367
4368 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4369 if let Some(s) = self.super_type() {
4370 s.children_changed(cx, mutation);
4371 }
4372
4373 if let Some(data) = self.rare_data.borrow().as_ref() &&
4374 let Some(list) = data.child_list.get()
4375 {
4376 list.as_children_list().children_changed(mutation);
4377 }
4378
4379 self.owner_doc_unrooted(cx.no_gc())
4380 .content_and_heritage_changed(cx.no_gc(), self);
4381 }
4382
4383 fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
4386 self.super_type().unwrap().unbind_from_tree(cx, context);
4387
4388 if !self.is_in_a_shadow_tree() &&
4393 let Some(weak_ranges) = self.weak_ranges_mut() &&
4394 !weak_ranges.is_empty()
4395 {
4396 weak_ranges.drain_to_parent(context.parent, context.index(), self);
4397 }
4398 }
4399
4400 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
4401 if let Some(super_type) = self.super_type() {
4402 super_type.moving_steps(cx, context);
4403 }
4404
4405 if let Some(old_parent) = context.old_parent &&
4410 !self.is_in_a_shadow_tree() &&
4411 let Some(weak_ranges) = self.weak_ranges_mut() &&
4412 !weak_ranges.is_empty()
4413 {
4414 weak_ranges.drain_to_parent(old_parent, context.index(), self);
4415 }
4416
4417 self.owner_doc_unrooted(cx.no_gc())
4418 .content_and_heritage_changed(cx.no_gc(), self);
4419
4420 if let Some(parent) = self.GetParentNode() {
4421 Self::maybe_dirty_visible_selection_for_newly_inserted_nodes(
4422 cx.no_gc(),
4423 &parent,
4424 &[self],
4425 );
4426 }
4427 }
4428
4429 fn handle_event(&self, cx: &mut JSContext, event: &Event) {
4430 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4431 return;
4432 }
4433
4434 if let Some(event) = event.downcast::<KeyboardEvent>() {
4435 self.owner_document()
4436 .event_handler()
4437 .run_default_keyboard_event_handler(cx, self, event);
4438 }
4439 }
4440}
4441
4442#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4444pub(crate) enum NodeDamage {
4445 Style,
4447 ContentOrHeritage,
4450 Other,
4452}
4453
4454pub(crate) struct UniqueId {
4456 cell: UnsafeCell<Option<Box<Uuid>>>,
4457}
4458
4459unsafe_no_jsmanaged_fields!(UniqueId);
4460
4461impl MallocSizeOf for UniqueId {
4462 #[expect(unsafe_code)]
4463 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
4464 if let Some(uuid) = unsafe { &*self.cell.get() } {
4465 unsafe { ops.malloc_size_of(&**uuid) }
4466 } else {
4467 0
4468 }
4469 }
4470}
4471
4472impl UniqueId {
4473 pub(super) fn new() -> UniqueId {
4475 UniqueId {
4476 cell: UnsafeCell::new(None),
4477 }
4478 }
4479
4480 #[expect(unsafe_code)]
4482 pub(super) fn borrow(&self) -> &Uuid {
4483 unsafe {
4484 let ptr = self.cell.get();
4485 if (*ptr).is_none() {
4486 *ptr = Some(Box::new(Uuid::new_v4()));
4487 }
4488 (*ptr).as_ref().unwrap()
4489 }
4490 }
4491}
4492
4493pub(crate) trait VecPreOrderInsertionHelper<T> {
4496 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
4497}
4498
4499impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
4500where
4501 T: DerivedFrom<Node> + DomObject,
4502{
4503 fn insert_pre_order(&mut self, node: &T, tree_root: &Node) {
4508 let Err(insertion_index) = self.binary_search_by(|candidate| {
4509 candidate.upcast().compare_dom_tree_position(
4510 node.upcast(),
4511 tree_root,
4512 ShadowIncluding::No,
4513 )
4514 }) else {
4515 return;
4518 };
4519
4520 self.insert(insertion_index, Dom::from_ref(node));
4521 }
4522}
4523
4524pub(crate) enum FlatTreeParent<'a> {
4526 Parent(UnrootedDom<'a, Node>),
4528 NotInFlatTree,
4531 RootNode,
4533}