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_and_cx,
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::document_loader::DocumentLoader;
59use crate::dom::ChildrenMutation;
60use crate::dom::attr::Attr;
61use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
62use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
63use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
64use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
65use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
66use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
67use crate::dom::bindings::codegen::Bindings::NodeBinding::{
68 GetRootNodeOptions, NodeConstants, NodeMethods,
69};
70use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
71use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
72use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
73 ShadowRootMode, SlotAssignmentMode,
74};
75use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
76use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
77use crate::dom::bindings::conversions::{self, DerivedFrom};
78use crate::dom::bindings::domname::namespace_from_domstring;
79use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
80use crate::dom::bindings::inheritance::{
81 Castable, CharacterDataTypeId, EventTargetTypeId, NodeTypeId,
82};
83use crate::dom::bindings::root::{
84 Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout, UnrootedDom,
85};
86use crate::dom::bindings::str::{DOMString, USVString};
87use crate::dom::characterdata::CharacterData;
88use crate::dom::context::{BindContext, IsShadowTree, MoveContext, UnbindContext};
89use crate::dom::css::cssstylesheet::CSSStyleSheet;
90use crate::dom::css::stylesheetlist::StyleSheetListOwner;
91use crate::dom::customelementregistry::{
92 CallbackReaction, CustomElementRegistry, try_upgrade_element,
93};
94use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
95use crate::dom::documentfragment::DocumentFragment;
96use crate::dom::documenttype::DocumentType;
97use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
98use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
99use crate::dom::eventtarget::EventTarget;
100use crate::dom::globalscope::GlobalScope;
101use crate::dom::html::htmlcollection::HTMLCollection;
102use crate::dom::html::htmlelement::HTMLElement;
103use crate::dom::html::htmllinkelement::HTMLLinkElement;
104use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
105use crate::dom::html::htmlstyleelement::HTMLStyleElement;
106use crate::dom::iterators::{
107 ShadowIncluding, UnrootedFollowingNodeIterator, 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::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode};
126use crate::script_thread::ScriptThread;
127
128#[dom_struct]
134pub struct Node {
135 eventtarget: EventTarget,
137
138 parent_node: MutNullableDom<Node>,
140
141 first_child: MutNullableDom<Node>,
143
144 last_child: MutNullableDom<Node>,
146
147 next_sibling: MutNullableDom<Node>,
149
150 prev_sibling: MutNullableDom<Node>,
152
153 owner_doc: MutNullableDom<Document>,
155
156 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
158
159 children_count: Cell<u32>,
161
162 flags: Cell<NodeFlags>,
164
165 inclusive_descendants_version: Cell<u64>,
167
168 #[no_trace]
171 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
172}
173
174impl fmt::Debug for Node {
175 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176 if let Some(element) = self.downcast::<Element>() {
177 element.fmt(f)
178 } else if let Some(character_data) = self.downcast::<CharacterData>() {
179 write!(f, "[Text({})]", character_data.data())
180 } else {
181 write!(f, "[Node({:?})]", self.type_id())
182 }
183 }
184}
185
186#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
188pub(crate) struct NodeFlags(u16);
189
190bitflags! {
191 impl NodeFlags: u16 {
192 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
196
197 const HAS_DIRTY_DESCENDANTS = 1 << 1;
199
200 const CLICK_IN_PROGRESS = 1 << 2;
203
204 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
209
210 const HAS_SNAPSHOT = 1 << 7;
215
216 const HANDLED_SNAPSHOT = 1 << 8;
218
219 const IS_IN_SHADOW_TREE = 1 << 9;
221
222 const IS_CONNECTED = 1 << 10;
226
227 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
230
231 const IS_IN_UA_WIDGET = 1 << 12;
234
235 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
237 }
238}
239
240#[derive(Clone, Copy, MallocSizeOf)]
244pub(crate) enum SuppressObserver {
245 Suppressed,
246 Unsuppressed,
247}
248
249pub(crate) enum ForceSlottableNodeReconciliation {
250 Force,
251 Skip,
252}
253
254impl Node {
255 pub(super) fn parent_node(&self) -> &MutNullableDom<Node> {
257 &self.parent_node
258 }
259
260 pub(super) fn first_child(&self) -> &MutNullableDom<Node> {
261 &self.first_child
262 }
263
264 pub(super) fn last_child(&self) -> &MutNullableDom<Node> {
265 &self.last_child
266 }
267
268 pub(super) fn next_sibling(&self) -> &MutNullableDom<Node> {
269 &self.next_sibling
270 }
271
272 pub(super) fn prev_sibling(&self) -> &MutNullableDom<Node> {
273 &self.prev_sibling
274 }
275
276 pub(super) fn get_owner_doc(&self) -> &MutNullableDom<Document> {
277 &self.owner_doc
278 }
279
280 pub(super) fn get_rare_data(&self) -> &DomRefCell<Option<Box<NodeRareData>>> {
281 &self.rare_data
282 }
283
284 pub(super) fn flags(&self) -> &Cell<NodeFlags> {
285 &self.flags
286 }
287
288 pub(super) fn layout_data(&self) -> &DomRefCell<Option<Box<GenericLayoutData>>> {
289 &self.layout_data
290 }
291
292 fn add_child(&self, cx: &mut JSContext, new_child: &Node, before: Option<&Node>) {
296 assert!(new_child.parent_node.get().is_none());
297 assert!(new_child.prev_sibling.get().is_none());
298 assert!(new_child.next_sibling.get().is_none());
299
300 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
301
302 match before {
303 Some(before) => {
304 assert!(before.parent_node.get().as_deref() == Some(self));
305 let prev_sibling = before.GetPreviousSibling();
306 match prev_sibling {
307 None => {
308 assert!(self.first_child.get().as_deref() == Some(before));
309 self.first_child.set(Some(new_child));
310 },
311 Some(ref prev_sibling) => {
312 prev_sibling.next_sibling.set(Some(new_child));
313 new_child.prev_sibling.set(Some(prev_sibling));
314 },
315 }
316 before.prev_sibling.set(Some(new_child));
317 new_child.next_sibling.set(Some(before));
318 },
319 None => {
320 let last_child = self.GetLastChild();
321 match last_child {
322 None => self.first_child.set(Some(new_child)),
323 Some(ref last_child) => {
324 assert!(last_child.next_sibling.get().is_none());
325 last_child.next_sibling.set(Some(new_child));
326 new_child.prev_sibling.set(Some(last_child));
327 },
328 }
329
330 self.last_child.set(Some(new_child));
331 },
332 }
333
334 new_child.parent_node.set(Some(self));
335 self.children_count.set(self.children_count.get() + 1);
336
337 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
338 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
339 let parent_is_connected = self.is_connected();
340 let parent_is_in_ua_widget = self.is_in_ua_widget();
341
342 let context = BindContext::new(self, IsShadowTree::No);
343
344 for node in new_child.traverse_preorder(ShadowIncluding::No) {
345 if parent_in_shadow_tree {
346 if let Some(shadow_root) = self.containing_shadow_root() {
347 node.set_containing_shadow_root(Some(&*shadow_root));
348 }
349 debug_assert!(node.containing_shadow_root().is_some());
350 }
351 node.set_flag(
352 NodeFlags::IS_IN_A_DOCUMENT_TREE,
353 parent_is_in_a_document_tree,
354 );
355 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
356 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
357 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
358
359 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
361 vtable_for(&node).bind_to_tree(cx, &context);
362 }
363 }
364
365 pub(crate) fn remove_style_and_layout_data_from_subtree(&self, no_gc: &NoGC) {
369 for node in self.traverse_preorder_non_rooting(no_gc, ShadowIncluding::Yes) {
370 node.clean_up_style_and_layout_data();
371 }
372 }
373
374 fn clean_up_style_and_layout_data(&self) {
375 self.layout_data.borrow_mut().take();
376 if let Some(element) = self.downcast::<Element>() {
377 element.clean_up_style_data();
378 }
379 }
380
381 pub(crate) fn complete_remove_subtree(
384 cx: &mut JSContext,
385 root: &Node,
386 context: &UnbindContext,
387 ) {
388 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
390 .union(NodeFlags::IS_CONNECTED)
391 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
392 .union(NodeFlags::HAS_SNAPSHOT)
393 .union(NodeFlags::HANDLED_SNAPSHOT);
394
395 for node in root.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No) {
396 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
397
398 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
401 for node in shadow_root
402 .upcast::<Node>()
403 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
404 {
405 node.set_flag(RESET_FLAGS, false);
406 }
407 }
408 }
409
410 let is_parent_connected = context.parent.is_connected();
412 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
413
414 let cleanup_node = |cx: &mut JSContext, node: &Node| {
417 node.owner_doc().cancel_animations_for_node(node);
418 node.clean_up_style_and_layout_data();
419
420 vtable_for(node).unbind_from_tree(cx, context);
425
426 if is_parent_connected && let Some(element) = node.as_custom_element() {
428 custom_element_reaction_stack.enqueue_callback_reaction(
429 cx,
430 &element,
431 CallbackReaction::Disconnected,
432 None,
433 );
434 }
435 };
436
437 for node in root.traverse_preorder(ShadowIncluding::No) {
438 cleanup_node(cx, &node);
439
440 if node.containing_shadow_root().is_some() {
443 node.set_containing_shadow_root(None);
446 }
447
448 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
451 for node in shadow_root
452 .upcast::<Node>()
453 .traverse_preorder(ShadowIncluding::Yes)
454 {
455 cleanup_node(cx, &node);
456 }
457 }
458 }
459
460 if root.owner_document().accessibility_active() {
463 root.owner_document()
464 .accessibility_data_mut()
465 .root_removed_node(cx.no_gc(), root);
466 }
467 }
468
469 pub(crate) fn complete_move_subtree(cx: &mut JSContext, root: &Node) {
470 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
472 .union(NodeFlags::IS_CONNECTED)
473 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
474 .union(NodeFlags::HAS_SNAPSHOT)
475 .union(NodeFlags::HANDLED_SNAPSHOT);
476
477 for node in root.traverse_preorder(ShadowIncluding::No) {
478 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
479 node.clean_up_style_and_layout_data();
480
481 if let Some(element) = node.downcast::<Element>() {
484 element.unregister_current_id_and_name_attribute(cx);
485 }
486
487 if node.containing_shadow_root().is_some() {
490 node.set_containing_shadow_root(None);
493 }
494
495 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
499 for node in shadow_root
500 .upcast::<Node>()
501 .traverse_preorder(ShadowIncluding::Yes)
502 {
503 node.set_flag(RESET_FLAGS, false);
504 node.clean_up_style_and_layout_data();
505 }
506 }
507 }
508 }
509
510 fn remove_child(&self, cx: &mut JSContext, child: &Node, cached_index: Option<u32>) {
514 assert!(child.parent_node.get().as_deref() == Some(self));
515 self.note_dirty_descendants(cx.no_gc());
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(NodeDamage::ContentOrHeritage);
559 self.note_dirty_descendants(cx.no_gc());
560 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
561
562 child.prev_sibling.set(None);
563 child.next_sibling.set(None);
564 child.parent_node.set(None);
565 self.children_count.set(self.children_count.get() - 1);
566 Self::complete_move_subtree(cx, child)
567 }
568
569 pub(crate) fn to_opaque(&self) -> OpaqueNode {
570 OpaqueNode(self.reflector().get_jsobject().get() as usize)
571 }
572
573 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
574 self.downcast::<Element>().and_then(|element| {
575 if element.is_custom() {
576 assert!(element.get_custom_element_definition().is_some());
577 Some(DomRoot::from_ref(element))
578 } else {
579 None
580 }
581 })
582 }
583
584 pub(crate) fn fire_synthetic_pointer_event_not_trusted(
586 &self,
587 cx: &mut JSContext,
588 event_type: Atom,
589 ) {
590 let window = self.owner_window();
594
595 let pointer_event = PointerEvent::new(
597 cx,
598 &window, event_type,
600 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![], );
627
628 pointer_event.upcast::<Event>().set_composed(true);
630
631 pointer_event.upcast::<Event>().set_trusted(false);
633
634 pointer_event
637 .upcast::<Event>()
638 .dispatch(cx, self.upcast::<EventTarget>(), false);
639 }
640
641 pub(crate) fn parent_directionality(&self) -> String {
642 let mut current = self.GetParentNode();
643
644 loop {
645 match current {
646 Some(node) => {
647 if let Some(directionality) = node
648 .downcast::<HTMLElement>()
649 .and_then(|html_element| html_element.directionality())
650 {
651 return directionality;
652 } else {
653 current = node.GetParentNode();
654 }
655 },
656 None => return "ltr".to_owned(),
657 }
658 }
659 }
660
661 pub(crate) fn is_being_rendered_or_delegates_rendering(
665 &self,
666 pseudo_element: Option<PseudoElement>,
667 ) -> bool {
668 matches!(
669 self.owner_window()
670 .layout()
671 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
672 NodeRenderingType::Rendered | NodeRenderingType::DelegatesRendering
673 )
674 }
675
676 pub(crate) fn is_being_rendered(&self, pseudo_element: Option<PseudoElement>) -> bool {
678 matches!(
679 self.owner_window()
680 .layout()
681 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
682 NodeRenderingType::Rendered
683 )
684 }
685
686 fn add_pending_accessibility_damage(&self, damage: AccessibilityDamage) {
687 if !self.owner_doc().accessibility_active() {
688 return;
689 }
690
691 self.owner_doc()
692 .accessibility_data_mut()
693 .add_pending_accessibility_damage_for_node(self, damage);
694
695 self.owner_window()
696 .layout()
697 .set_needs_accessibility_update();
698 }
699}
700
701impl Node {
702 fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
703 let mut rare_data = self.rare_data.borrow_mut();
704 if rare_data.is_none() {
705 *rare_data = Some(Default::default());
706 }
707 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
708 }
709
710 pub(crate) fn is_before(&self, other: &Node) -> bool {
713 let cmp = other.CompareDocumentPosition(self);
714 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
715 return false;
716 }
717
718 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
719 }
720
721 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
724 RefMut::map(self.ensure_rare_data(), |rare_data| {
725 &mut rare_data.mutation_observers
726 })
727 }
728
729 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
730 let rare_data = self.rare_data.borrow();
731 if rare_data.is_none() {
732 return None;
733 }
734 Some(Ref::map(rare_data, |rare_data| {
735 &rare_data.as_ref().unwrap().mutation_observers
736 }))
737 }
738
739 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
741 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
742 self.ensure_rare_data().mutation_observers.push(observer);
743 }
744
745 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
747 let mut rare_data = self.rare_data.borrow_mut();
748 let Some(rare_data) = rare_data.as_mut() else {
749 return;
750 };
751 rare_data
752 .mutation_observers
753 .retain(|registered_observer| &*registered_observer.observer != observer)
754 }
755
756 pub(crate) fn debug_str(&self) -> String {
758 format!("{:?}", self.type_id())
759 }
760
761 pub(crate) fn is_in_a_document_tree(&self) -> bool {
763 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
764 }
765
766 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
768 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
769 }
770
771 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
772 self.flags
773 .get()
774 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
775 }
776
777 pub(crate) fn set_weird_parser_insertion_mode(&self) {
778 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
779 }
780
781 pub(crate) fn is_connected(&self) -> bool {
783 self.flags.get().contains(NodeFlags::IS_CONNECTED)
784 }
785
786 pub(crate) fn set_in_ua_widget(&self, in_ua_widget: bool) {
787 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, in_ua_widget)
788 }
789
790 pub(crate) fn is_in_ua_widget(&self) -> bool {
791 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
792 }
793
794 pub(crate) fn type_id(&self) -> NodeTypeId {
796 match *self.eventtarget.type_id() {
797 EventTargetTypeId::Node(type_id) => type_id,
798 _ => unreachable!(),
799 }
800 }
801
802 pub(crate) fn len(&self) -> u32 {
804 match self.type_id() {
805 NodeTypeId::DocumentType => 0,
806 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
807 _ => self.children_count(),
808 }
809 }
810
811 pub(crate) fn is_empty(&self) -> bool {
812 self.len() == 0
814 }
815
816 pub(crate) fn index(&self) -> u32 {
818 self.preceding_siblings().count() as u32
819 }
820
821 pub(crate) fn has_parent(&self) -> bool {
823 self.parent_node.get().is_some()
824 }
825
826 pub(crate) fn children_count(&self) -> u32 {
827 self.children_count.get()
828 }
829
830 pub(crate) fn weak_ranges_mut(&self) -> Option<RefMut<'_, WeakRangeVec>> {
831 let rare_data = self.rare_data.borrow_mut();
832 if rare_data.is_none() {
833 return None;
834 }
835 Some(RefMut::map(rare_data, |rare_data| {
836 &mut rare_data.as_mut().unwrap().weak_ranges
837 }))
838 }
839
840 pub(crate) fn ensure_weak_ranges(&self) -> RefMut<'_, WeakRangeVec> {
841 RefMut::map(self.ensure_rare_data(), |rare_data| {
842 &mut rare_data.weak_ranges
843 })
844 }
845
846 pub(crate) fn weak_ranges_is_empty(&self) -> bool {
847 self.rare_data
848 .borrow()
849 .as_ref()
850 .is_none_or(|data| data.weak_ranges.is_empty())
851 }
852
853 #[inline]
854 pub(crate) fn is_doctype(&self) -> bool {
855 self.type_id() == NodeTypeId::DocumentType
856 }
857
858 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
859 self.flags.get().contains(flag)
860 }
861
862 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
863 let mut flags = self.flags.get();
864
865 if value {
866 flags.insert(flag);
867 } else {
868 flags.remove(flag);
869 }
870
871 self.flags.set(flags);
872 }
873
874 pub(crate) fn note_dirty_descendants(&self, no_gc: &NoGC) {
876 self.owner_doc_unrooted(no_gc)
877 .note_node_with_dirty_descendants(self);
878 }
879
880 pub(crate) fn has_dirty_descendants(&self) -> bool {
881 self.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)
882 }
883
884 pub(crate) fn rev_version(&self) {
885 let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
890 let version = cmp::max(
891 self.inclusive_descendants_version(),
892 doc.inclusive_descendants_version(),
893 ) + 1;
894
895 let mut node = &MutNullableDom::new(Some(self));
898 while let Some(p) = node.if_is_some(|p| {
899 p.inclusive_descendants_version.set(version);
900 &p.parent_node
901 }) {
902 node = p
903 }
904 doc.inclusive_descendants_version.set(version);
905 }
906
907 pub(crate) fn dirty(&self, damage: NodeDamage) {
908 self.rev_version();
909 if !self.is_connected() {
910 return;
911 }
912
913 match self.type_id() {
914 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..)) => {
915 *self.layout_data.borrow_mut() = None;
918
919 self.parent_node
923 .get()
924 .unwrap()
925 .dirty(NodeDamage::ContentOrHeritage);
926
927 if damage == NodeDamage::Other {
928 self.add_pending_accessibility_damage(AccessibilityDamage::Text);
929 }
930 },
931 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(damage),
932 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
933 .downcast::<ShadowRoot>()
934 .unwrap()
935 .Host()
936 .upcast::<Element>()
937 .restyle(damage),
938 _ => {},
939 };
940 }
941
942 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
944 self.inclusive_descendants_version.get()
945 }
946
947 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
949 TreeIterator::new(self, shadow_including)
950 }
951
952 pub(crate) fn traverse_preorder_non_rooting<'b>(
954 &self,
955 no_gc: &'b NoGC,
956 shadow_including: ShadowIncluding,
957 ) -> UnrootedTreeIterator<'b> {
958 UnrootedTreeIterator::new(self, shadow_including, no_gc)
959 }
960
961 pub(crate) fn inclusively_following_siblings(
962 &self,
963 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
964 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), |n| n.GetNextSibling())
965 }
966
967 pub(crate) fn inclusively_following_siblings_unrooted<'b>(
968 &self,
969 no_gc: &'b NoGC,
970 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
971 UnrootedSimpleNodeIterator::new(
972 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
973 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
974 no_gc,
975 )
976 }
977
978 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
979 &self,
980 no_gc: &'b NoGC,
981 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
982 UnrootedSimpleNodeIterator::new(
983 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
984 |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
985 no_gc,
986 )
987 }
988
989 pub(crate) fn common_ancestor(
990 &self,
991 other: &Node,
992 shadow_including: ShadowIncluding,
993 ) -> Option<DomRoot<Node>> {
994 self.inclusive_ancestors(shadow_including).find(|ancestor| {
995 other
996 .inclusive_ancestors(shadow_including)
997 .any(|node| node == *ancestor)
998 })
999 }
1000
1001 pub(crate) fn common_ancestor_in_flat_tree(&self, other: &Node) -> Option<DomRoot<Node>> {
1002 self.inclusive_ancestors_in_flat_tree().find(|ancestor| {
1003 other
1004 .inclusive_ancestors_in_flat_tree()
1005 .any(|node| node == *ancestor)
1006 })
1007 }
1008
1009 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
1011 self == child || self.is_ancestor_of(child)
1013 }
1014
1015 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
1017 let mut current = &possible_descendant.parent_node;
1019 let mut done = false;
1020
1021 while let Some(node) = current.if_is_some(|node| {
1022 done = node == self;
1023 &node.parent_node
1024 }) {
1025 if done {
1026 break;
1027 }
1028 current = node
1029 }
1030 done
1031 }
1032
1033 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
1035 self.is_inclusive_ancestor_of(child) ||
1038 child
1039 .GetRootNode(&GetRootNodeOptions::empty())
1040 .downcast::<DocumentFragment>()
1041 .and_then(|fragment| fragment.host())
1042 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1043 }
1044
1045 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1047 node.inclusive_ancestors(ShadowIncluding::Yes)
1048 .any(|ancestor| &*ancestor == self)
1049 }
1050
1051 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1052 SimpleNodeIterator::new(self.GetNextSibling(), |n| n.GetNextSibling())
1053 }
1054
1055 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1056 SimpleNodeIterator::new(self.GetPreviousSibling(), |n| n.GetPreviousSibling())
1057 }
1058
1059 pub(crate) fn following_nodes(
1060 &self,
1061 root: &Node,
1062 shadow_including: ShadowIncluding,
1063 ) -> FollowingNodeIterator {
1064 FollowingNodeIterator::new(
1065 Some(DomRoot::from_ref(self)),
1066 DomRoot::from_ref(root),
1067 shadow_including,
1068 )
1069 }
1070
1071 pub(crate) fn following_nodes_unrooted<'b>(
1072 &self,
1073 no_gc: &'b NoGC,
1074 root: &Node,
1075 shadow_including: ShadowIncluding,
1076 ) -> UnrootedFollowingNodeIterator<'b> {
1077 UnrootedFollowingNodeIterator::new(
1078 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1079 UnrootedDom::from_dom(Dom::from_ref(root), no_gc),
1080 shadow_including,
1081 no_gc,
1082 )
1083 }
1084
1085 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1086 PrecedingNodeIterator::new(Some(DomRoot::from_ref(self)), DomRoot::from_ref(root))
1087 }
1088
1089 pub(crate) fn preceding_nodes_unrooted<'b>(
1090 &self,
1091 no_gc: &'b NoGC,
1092 root: &Node,
1093 ) -> UnrootedPrecedingNodeIterator<'b> {
1094 UnrootedPrecedingNodeIterator::new(
1095 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1096 UnrootedDom::from_dom(Dom::from_ref(root), no_gc),
1097 no_gc,
1098 )
1099 }
1100
1101 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1104 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetLastChild())
1105 }
1106
1107 pub(crate) fn descending_last_children_unrooted<'b>(
1108 &self,
1109 no_gc: &'b NoGC,
1110 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> {
1111 UnrootedSimpleNodeIterator::new(
1112 self.get_last_child_unrooted(no_gc),
1113 |n, no_gc| n.get_last_child_unrooted(no_gc),
1114 no_gc,
1115 )
1116 }
1117
1118 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1119 child
1120 .parent_node
1121 .get()
1122 .is_some_and(|parent| &*parent == self)
1123 }
1124
1125 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1126 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1127 }
1128
1129 pub(crate) fn containing_block_node_without_reflow(&self) -> Option<DomRoot<Node>> {
1131 self.owner_window()
1132 .containing_block_node_query_without_reflow(self)
1133 }
1134
1135 pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1136 self.owner_window().padding_query_without_reflow(self)
1137 }
1138
1139 pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1140 self.owner_window()
1141 .box_area_query(self, BoxAreaType::Content, false)
1142 }
1143
1144 pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1145 self.owner_window()
1146 .box_area_query(self, BoxAreaType::Border, false)
1147 }
1148
1149 pub(crate) fn border_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1150 self.owner_window()
1151 .box_area_query_without_reflow(self, BoxAreaType::Border, false)
1152 }
1153
1154 pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1155 self.owner_window()
1156 .box_area_query(self, BoxAreaType::Padding, false)
1157 }
1158
1159 pub(crate) fn padding_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1160 self.owner_window()
1161 .box_area_query_without_reflow(self, BoxAreaType::Padding, false)
1162 }
1163
1164 pub(crate) fn border_boxes(&self) -> CSSPixelRectVec {
1165 self.owner_window()
1166 .box_areas_query(self, BoxAreaType::Border)
1167 }
1168
1169 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1170 self.owner_window().client_rect_query(self)
1171 }
1172
1173 pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1176 let document = self.owner_doc();
1178
1179 if !document.is_active() {
1181 return Rect::zero();
1182 }
1183
1184 let window = document.window();
1187 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1188
1189 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1190 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1191 let is_body_element = self
1192 .downcast::<HTMLElement>()
1193 .is_some_and(|e| e.is_body_element());
1194
1195 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1201 let viewport_scrolling_area = window.scrolling_area_query(None);
1202 return Rect::new(
1203 viewport_scrolling_area.origin,
1204 viewport_scrolling_area.size.max(viewport),
1205 );
1206 }
1207
1208 window.scrolling_area_query(Some(self))
1212 }
1213
1214 pub(crate) fn effective_overflow(&self) -> Option<AxesOverflow> {
1215 self.owner_window().query_effective_overflow(self)
1216 }
1217
1218 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1219 self.owner_window()
1220 .query_effective_overflow_without_reflow(self)
1221 }
1222
1223 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1225 let parent = &self.parent_node;
1227
1228 let parent = match parent.get() {
1230 None => return Ok(()),
1231 Some(parent) => parent,
1232 };
1233
1234 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1236
1237 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1239
1240 let viable_previous_sibling = match viable_previous_sibling {
1242 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1243 None => parent.first_child.get(),
1244 };
1245
1246 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1248
1249 Ok(())
1250 }
1251
1252 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1254 let parent = &self.parent_node;
1256
1257 let parent = match parent.get() {
1259 None => return Ok(()),
1260 Some(parent) => parent,
1261 };
1262
1263 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1265
1266 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1268
1269 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1271
1272 Ok(())
1273 }
1274
1275 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1277 let Some(parent) = self.GetParentNode() else {
1279 return Ok(());
1281 };
1282
1283 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1285
1286 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1288
1289 if self.parent_node == Some(&*parent) {
1290 parent.ReplaceChild(cx, &node, self)?;
1292 } else {
1293 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1295 }
1296 Ok(())
1297 }
1298
1299 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1301 let doc = self.owner_doc();
1303 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1304 let first_child = self.first_child.get();
1306 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1307 }
1308
1309 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1311 let doc = self.owner_doc();
1313 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1314 self.AppendChild(cx, &node).map(|_| ())
1316 }
1317
1318 pub(crate) fn replace_children(
1320 &self,
1321 cx: &mut JSContext,
1322 nodes: Vec<NodeOrString>,
1323 ) -> ErrorResult {
1324 let doc = self.owner_doc();
1327 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1328
1329 Node::ensure_pre_insertion_validity(cx.no_gc(), &node, self, None)?;
1331
1332 Node::replace_all(cx, Some(&node), self);
1334 Ok(())
1335 }
1336
1337 pub(crate) fn move_before(
1339 &self,
1340 cx: &mut JSContext,
1341 node: &Node,
1342 child: Option<&Node>,
1343 ) -> ErrorResult {
1344 let reference_child_root;
1347 let reference_child = match child {
1348 Some(child) if child == node => {
1349 reference_child_root = node.GetNextSibling();
1350 reference_child_root.as_deref()
1351 },
1352 _ => child,
1353 };
1354
1355 Node::move_fn(cx, node, self, reference_child)
1357 }
1358
1359 fn move_fn(
1361 cx: &mut JSContext,
1362 node: &Node,
1363 new_parent: &Node,
1364 child: Option<&Node>,
1365 ) -> ErrorResult {
1366 let mut options = GetRootNodeOptions::empty();
1371 options.composed = true;
1372 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1373 return Err(Error::HierarchyRequest(None));
1374 }
1375
1376 if node.is_inclusive_ancestor_of(new_parent) {
1379 return Err(Error::HierarchyRequest(None));
1380 }
1381
1382 if let Some(child) = child &&
1385 !new_parent.is_parent_of(child)
1386 {
1387 return Err(Error::NotFound(None));
1388 }
1389
1390 match node.type_id() {
1395 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1396 if new_parent.is::<Document>() {
1397 return Err(Error::HierarchyRequest(None));
1398 }
1399 },
1400 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1401 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1402 NodeTypeId::Element(_) => (),
1403 NodeTypeId::DocumentFragment(_) |
1404 NodeTypeId::DocumentType |
1405 NodeTypeId::Document(_) |
1406 NodeTypeId::Attr => {
1407 return Err(Error::HierarchyRequest(None));
1408 },
1409 }
1410
1411 if new_parent.is::<Document>() && node.is::<Element>() {
1415 if new_parent.child_elements().next().is_some() {
1417 return Err(Error::HierarchyRequest(None));
1418 }
1419
1420 if child.is_some_and(|child| {
1423 child
1424 .inclusively_following_siblings_unrooted(cx.no_gc())
1425 .any(|child| child.is_doctype())
1426 }) {
1427 return Err(Error::HierarchyRequest(None));
1428 }
1429 }
1430
1431 let old_parent = node
1434 .parent_node
1435 .get()
1436 .expect("old_parent should always be initialized");
1437
1438 let cached_index = Node::live_range_pre_remove_steps(node, &old_parent);
1440
1441 let old_previous_sibling = node.prev_sibling.get();
1446
1447 let old_next_sibling = node.next_sibling.get();
1449
1450 let prev_sibling = node.GetPreviousSibling();
1451 match prev_sibling {
1452 None => {
1453 old_parent
1454 .first_child
1455 .set(node.next_sibling.get().as_deref());
1456 },
1457 Some(ref prev_sibling) => {
1458 prev_sibling
1459 .next_sibling
1460 .set(node.next_sibling.get().as_deref());
1461 },
1462 }
1463 let next_sibling = node.GetNextSibling();
1464 match next_sibling {
1465 None => {
1466 old_parent
1467 .last_child
1468 .set(node.prev_sibling.get().as_deref());
1469 },
1470 Some(ref next_sibling) => {
1471 next_sibling
1472 .prev_sibling
1473 .set(node.prev_sibling.get().as_deref());
1474 },
1475 }
1476
1477 let mut context =
1478 MoveContext::new(Some(&old_parent), prev_sibling.as_deref(), cached_index);
1479
1480 old_parent.move_child(cx, node);
1482
1483 if let Some(slot) = node.assigned_slot() {
1485 slot.assign_slottables(cx);
1486 }
1487
1488 if old_parent.is_in_a_shadow_tree() &&
1491 let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() &&
1492 !slot_element.has_assigned_nodes()
1493 {
1494 slot_element.signal_a_slot_change(cx);
1495 }
1496
1497 let has_slot_descendant = node
1499 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
1500 .any(|element| element.is::<HTMLSlotElement>());
1501 if has_slot_descendant {
1502 old_parent
1504 .GetRootNode(&GetRootNodeOptions::empty())
1505 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1506
1507 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1509 }
1510
1511 if let Some(child) = child &&
1513 let Some(new_parent_ranges) = new_parent.weak_ranges_mut()
1514 {
1515 new_parent_ranges.increase_above(new_parent, child.index(), 1)
1520 }
1521
1522 let new_previous_sibling = child.map_or_else(
1525 || new_parent.last_child.get(),
1526 |child| child.prev_sibling.get(),
1527 );
1528
1529 new_parent.add_child(cx, node, child);
1532
1533 if let Some(shadow_root) = new_parent
1536 .downcast::<Element>()
1537 .and_then(Element::shadow_root) &&
1538 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1539 (node.is::<Element>() || node.is::<Text>())
1540 {
1541 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1542 slottable.assign_a_slot(cx);
1543 }
1544
1545 if new_parent.is_in_a_shadow_tree() &&
1548 let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() &&
1549 !slot_element.has_assigned_nodes()
1550 {
1551 slot_element.signal_a_slot_change(cx);
1552 }
1553
1554 node.GetRootNode(&GetRootNodeOptions::empty())
1556 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1557
1558 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1561 if descendant.deref() == node {
1565 vtable_for(&descendant).moving_steps(cx, &context);
1566 } else {
1567 context.old_parent = None;
1568 vtable_for(&descendant).moving_steps(cx, &context);
1569 }
1570
1571 if let Some(descendant) = descendant.downcast::<Element>() &&
1573 descendant.is_custom() &&
1574 new_parent.is_connected()
1575 {
1576 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
1579 custom_element_reaction_stack.enqueue_callback_reaction(
1580 cx,
1581 descendant,
1582 CallbackReaction::ConnectedMove,
1583 None,
1584 );
1585 }
1586 }
1587
1588 let moved = [node];
1591 let mutation = LazyCell::new(|| Mutation::ChildList {
1592 added: None,
1593 removed: Some(&moved),
1594 prev: old_previous_sibling.as_deref(),
1595 next: old_next_sibling.as_deref(),
1596 });
1597 MutationObserver::queue_a_mutation_record(cx, &old_parent, mutation);
1598
1599 let mutation = LazyCell::new(|| Mutation::ChildList {
1602 added: Some(&moved),
1603 removed: None,
1604 prev: new_previous_sibling.as_deref(),
1605 next: child,
1606 });
1607 MutationObserver::queue_a_mutation_record(cx, new_parent, mutation);
1608
1609 Ok(())
1610 }
1611
1612 #[allow(unsafe_code)]
1614 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1615 pub(crate) fn query_selector(
1616 &self,
1617 no_gc: &NoGC,
1618 selectors: DOMString,
1619 ) -> Fallible<Option<DomRoot<Element>>> {
1620 let document_url = self.owner_document().url().get_arc();
1623
1624 self.owner_document()
1627 .id_map()
1628 .resolve_all(no_gc, self.owner_doc().upcast());
1629
1630 let traced_node = Dom::from_ref(self);
1632
1633 let first_matching_element = with_layout_state(|| {
1634 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1635 ServoDangerousStyleNode::from(layout_node)
1636 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1637 })?;
1638
1639 Ok(first_matching_element.map(ServoDangerousStyleElement::rooted))
1640 }
1641
1642 #[allow(unsafe_code)]
1644 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1645 pub(crate) fn query_selector_all(
1646 &self,
1647 cx: &mut JSContext,
1648 selectors: DOMString,
1649 ) -> Fallible<DomRoot<NodeList>> {
1650 let document_url = self.owner_document().url().get_arc();
1653
1654 self.owner_document()
1657 .id_map()
1658 .resolve_all(cx.no_gc(), self.owner_doc().upcast());
1659
1660 let traced_node = UnrootedDom::from_dom(Dom::from_ref(self), cx.no_gc());
1661 let matching_elements = with_layout_state(|| {
1662 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1663 ServoDangerousStyleNode::from(layout_node)
1664 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1665 })?;
1666 let iter = matching_elements
1667 .into_iter()
1668 .map(ServoDangerousStyleElement::rooted)
1669 .map(DomRoot::upcast::<Node>);
1670
1671 Ok(NodeList::new_simple_list(cx, &self.owner_window(), iter))
1674 }
1675
1676 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1677 SimpleNodeIterator::new(self.GetParentNode(), |n| n.GetParentNode())
1678 }
1679
1680 pub(crate) fn inclusive_ancestors(
1682 &self,
1683 shadow_including: ShadowIncluding,
1684 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1685 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |n| {
1686 if shadow_including == ShadowIncluding::Yes &&
1687 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1688 {
1689 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1690 }
1691 n.GetParentNode()
1692 })
1693 }
1694
1695 pub(crate) fn inclusive_ancestors_unrooted<'a>(
1696 &self,
1697 no_gc: &'a NoGC,
1698 shadow_including: ShadowIncluding,
1699 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1700 UnrootedSimpleNodeIterator::new(
1701 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1702 move |n, no_gc| {
1703 if shadow_including == ShadowIncluding::Yes &&
1704 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1705 {
1706 return Some(UnrootedDom::from_dom(
1707 Dom::from_ref(shadow_root.Host().upcast::<Node>()),
1708 no_gc,
1709 ));
1710 }
1711 n.get_parent_node_unrooted(no_gc)
1712 },
1713 no_gc,
1714 )
1715 }
1716
1717 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1718 self.owner_doc.get().unwrap()
1719 }
1720
1721 pub(crate) fn owner_doc_unrooted<'a>(&self, no_gc: &'a NoGC) -> UnrootedDom<'a, Document> {
1722 self.owner_doc.get_unrooted(no_gc).unwrap()
1723 }
1724
1725 pub(crate) fn set_owner_doc(&self, document: &Document) {
1726 self.owner_doc.set(Some(document));
1727 }
1728
1729 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1730 self.rare_data
1731 .borrow()
1732 .as_ref()?
1733 .containing_shadow_root
1734 .as_ref()
1735 .map(|sr| DomRoot::from_ref(&**sr))
1736 }
1737
1738 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1739 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1740 }
1741
1742 pub(crate) fn is_in_html_doc(&self) -> bool {
1743 self.owner_doc().is_html_document()
1744 }
1745
1746 pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1747 self.is_connected() && self.owner_doc().browsing_context().is_some()
1748 }
1749
1750 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1751 SimpleNodeIterator::new(self.GetFirstChild(), |n| n.GetNextSibling())
1752 }
1753
1754 pub(crate) fn children_unrooted<'a>(
1755 &self,
1756 no_gc: &'a NoGC,
1757 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1758 UnrootedSimpleNodeIterator::new(
1759 self.get_first_child_unrooted(no_gc),
1760 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1761 no_gc,
1762 )
1763 }
1764
1765 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1766 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetPreviousSibling())
1767 }
1768
1769 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1771 self.children()
1772 .filter_map(DomRoot::downcast as fn(_) -> _)
1773 .peekable()
1774 }
1775
1776 pub(crate) fn child_elements_unrooted<'a>(
1777 &self,
1778 no_gc: &'a NoGC,
1779 ) -> impl Iterator<Item = UnrootedDom<'a, Element>> + use<'a> {
1780 self.children_unrooted(no_gc)
1781 .filter_map(UnrootedDom::downcast)
1782 .peekable()
1783 }
1784
1785 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1786 if let Some(ref parent) = self.GetParentNode() {
1787 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1788 }
1789 }
1790
1791 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1793 Ref::filter_map(self.rare_data.borrow(), |rare_data| {
1794 rare_data
1795 .as_ref()
1796 .and_then(|rare_data| rare_data.unique_id.as_ref())
1797 })
1798 .ok()
1799 .map(|unique_id| unique_id.borrow().simple().to_string())
1800 }
1801
1802 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1803 let mut rare_data = self.ensure_rare_data();
1804
1805 if rare_data.unique_id.is_none() {
1806 let node_id = UniqueId::new();
1807 ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string());
1808 rare_data.unique_id = Some(node_id);
1809 }
1810 rare_data
1811 .unique_id
1812 .as_ref()
1813 .unwrap()
1814 .borrow()
1815 .simple()
1816 .to_string()
1817 }
1818
1819 pub(crate) fn summarize(&self, cx: &mut JSContext) -> NodeInfo {
1820 let USVString(base_uri) = self.BaseURI();
1821 let node_type = self.NodeType();
1822 let pipeline = self.owner_window().pipeline_id();
1823
1824 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1825 let shadow_root_mode = maybe_shadow_root
1826 .map(ShadowRoot::Mode)
1827 .map(ShadowRootMode::convert);
1828 let host = maybe_shadow_root
1829 .map(ShadowRoot::Host)
1830 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1831 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1832 let Some(root) = potential_host.shadow_root() else {
1833 return false;
1834 };
1835 !root.is_user_agent_widget() || pref!(inspector_show_servo_internal_shadow_roots)
1836 });
1837
1838 let num_children = if is_shadow_host {
1839 self.ChildNodes(cx).Length() as usize + 1
1841 } else {
1842 self.ChildNodes(cx).Length() as usize
1843 };
1844
1845 let window = self.owner_window();
1846 let element = self.downcast::<Element>();
1847 let display = element
1848 .map(|elem| window.GetComputedStyle(cx, elem, None))
1849 .map(|style| style.Display().into());
1850
1851 let is_displayed =
1857 element.is_none_or(|element| !element.is_display_none()) || self.is::<DocumentType>();
1858 let attrs = element.map(Element::summarize).unwrap_or_default();
1859
1860 NodeInfo {
1861 unique_id: self.unique_id(pipeline),
1862 host,
1863 base_uri,
1864 parent: self
1865 .GetParentNode()
1866 .map_or("".to_owned(), |node| node.unique_id(pipeline)),
1867 node_type,
1868 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1869 node_name: String::from(self.NodeName()),
1870 node_value: self.GetNodeValue().map(|v| v.into()),
1871 num_children,
1872 attrs,
1873 is_shadow_host,
1874 shadow_root_mode,
1875 display,
1876 is_displayed,
1877 doctype_name: self
1878 .downcast::<DocumentType>()
1879 .map(DocumentType::name)
1880 .cloned()
1881 .map(String::from),
1882 doctype_public_identifier: self
1883 .downcast::<DocumentType>()
1884 .map(DocumentType::public_id)
1885 .cloned()
1886 .map(String::from),
1887 doctype_system_identifier: self
1888 .downcast::<DocumentType>()
1889 .map(DocumentType::system_id)
1890 .cloned()
1891 .map(String::from),
1892 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1893 }
1894 }
1895
1896 pub(crate) fn insert_cell_or_row<F, G, I>(
1898 &self,
1899 cx: &mut JSContext,
1900 index: i32,
1901 get_items: F,
1902 new_child: G,
1903 ) -> Fallible<DomRoot<HTMLElement>>
1904 where
1905 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1906 G: Fn(&mut JSContext) -> DomRoot<I>,
1907 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1908 {
1909 if index < -1 {
1910 return Err(Error::IndexSize(None));
1911 }
1912
1913 let tr = new_child(cx);
1914
1915 {
1916 let tr_node = tr.upcast::<Node>();
1917 if index == -1 {
1918 self.InsertBefore(cx, tr_node, None)?;
1919 } else {
1920 let items = get_items(cx);
1921 let node = match items
1922 .elements_iter(cx.no_gc())
1923 .map(UnrootedDom::upcast::<Node>)
1924 .map(Some)
1925 .chain(iter::once(None))
1926 .nth(index as usize)
1927 {
1928 None => return Err(Error::IndexSize(None)),
1929 Some(node) => node,
1930 };
1931 self.InsertBefore(cx, tr_node, node.map(|node| node.as_rooted()).as_deref())?;
1932 }
1933 }
1934
1935 Ok(DomRoot::upcast::<HTMLElement>(tr))
1936 }
1937
1938 pub(crate) fn delete_cell_or_row<F, G>(
1940 &self,
1941 cx: &mut JSContext,
1942 index: i32,
1943 get_items: F,
1944 is_delete_type: G,
1945 ) -> ErrorResult
1946 where
1947 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1948 G: Fn(&Element) -> bool,
1949 {
1950 let element = match index {
1951 index if index < -1 => return Err(Error::IndexSize(None)),
1952 -1 => {
1953 let last_child = self.upcast::<Node>().GetLastChild();
1954 match last_child.and_then(|node| {
1955 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
1956 .filter_map(UnrootedDom::downcast::<Element>)
1957 .find(|elem| is_delete_type(elem))
1958 .map(|elem| elem.as_rooted())
1959 }) {
1960 Some(element) => element,
1961 None => return Ok(()),
1962 }
1963 },
1964 index => match get_items(cx).Item(cx, index as u32) {
1965 Some(element) => element,
1966 None => return Err(Error::IndexSize(None)),
1967 },
1968 };
1969
1970 element.upcast::<Node>().remove_self(cx);
1971 Ok(())
1972 }
1973
1974 pub(crate) fn get_cssom_stylesheet(
1975 &self,
1976 cx: &mut JSContext,
1977 ) -> Option<DomRoot<CSSStyleSheet>> {
1978 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1979 node.get_cssom_stylesheet(cx)
1980 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1981 node.get_cssom_stylesheet(cx)
1982 } else {
1983 None
1984 }
1985 }
1986
1987 pub(crate) fn get_lang(&self) -> Option<String> {
1989 self.inclusive_ancestors(ShadowIncluding::Yes)
1990 .find_map(|node| {
1991 node.downcast::<Element>().and_then(|el| {
1992 el.get_attribute_string_value_with_namespace(&ns!(xml), &local_name!("lang"))
1993 .or_else(|| el.get_attribute_string_value(&local_name!("lang")))
1994 })
1995 })
1998 }
1999
2000 pub(crate) fn assign_slottables_for_a_tree(
2002 &self,
2003 cx: &JSContext,
2004 force: ForceSlottableNodeReconciliation,
2005 ) {
2006 let is_shadow_root_with_slots = self
2013 .downcast::<ShadowRoot>()
2014 .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
2015 if !is_shadow_root_with_slots &&
2016 !self.is::<HTMLSlotElement>() &&
2017 matches!(force, ForceSlottableNodeReconciliation::Skip)
2018 {
2019 return;
2020 }
2021
2022 for node in self.traverse_preorder_non_rooting(cx, ShadowIncluding::No) {
2025 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
2026 slot.assign_slottables(cx);
2027 }
2028 }
2029 }
2030
2031 pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
2032 let assigned_slot = self
2033 .rare_data
2034 .borrow()
2035 .as_ref()?
2036 .slottable_data
2037 .assigned_slot
2038 .as_ref()?
2039 .as_rooted();
2040 Some(assigned_slot)
2041 }
2042
2043 pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
2044 self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
2045 }
2046
2047 pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
2048 let manually_assigned_slot = self
2049 .rare_data
2050 .borrow()
2051 .as_ref()?
2052 .slottable_data
2053 .manual_slot_assignment
2054 .as_ref()?
2055 .as_rooted();
2056 Some(manually_assigned_slot)
2057 }
2058
2059 pub(crate) fn set_manual_slot_assignment(
2060 &self,
2061 manually_assigned_slot: Option<&HTMLSlotElement>,
2062 ) {
2063 self.ensure_rare_data()
2064 .slottable_data
2065 .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
2066 }
2067
2068 pub(crate) fn parent_in_flat_tree(&self) -> FlatTreeParent {
2079 if let Some(assigned_slot) = self.assigned_slot() {
2080 return FlatTreeParent::Parent(DomRoot::upcast(assigned_slot));
2081 }
2082
2083 let Some(parent) = self.GetParentNode() else {
2084 return FlatTreeParent::RootNode;
2085 };
2086
2087 if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
2088 return FlatTreeParent::Parent(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
2089 }
2090
2091 if parent
2092 .downcast::<Element>()
2093 .is_some_and(|element| element.is_shadow_host())
2094 {
2095 return FlatTreeParent::NotInFlatTree;
2096 }
2097
2098 if parent
2099 .downcast::<HTMLSlotElement>()
2100 .is_some_and(|slot| slot.has_assigned_nodes())
2101 {
2102 return FlatTreeParent::NotInFlatTree;
2103 }
2104
2105 FlatTreeParent::Parent(parent)
2106 }
2107
2108 pub(crate) fn inclusive_ancestors_in_flat_tree(
2109 &self,
2110 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
2111 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |node| {
2112 match node.parent_in_flat_tree() {
2113 FlatTreeParent::Parent(parent) => Some(parent),
2114 FlatTreeParent::NotInFlatTree | FlatTreeParent::RootNode => None,
2115 }
2116 })
2117 }
2118
2119 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2121 debug_assert!(self.is_in_ua_widget());
2123 debug_assert!(pseudo_element.is_element_backed());
2124 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2125 }
2126
2127 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2128 self.rare_data
2129 .borrow()
2130 .as_ref()
2131 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2132 }
2133
2134 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2136 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2140 if ancestor.is_editing_host() {
2141 return Some(ancestor);
2142 }
2143 if ancestor
2144 .downcast::<HTMLElement>()
2145 .is_some_and(|el| el.ContentEditable().str() == "false")
2146 {
2147 return None;
2148 }
2149 }
2150 None
2151 }
2152
2153 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2154 self.editing_host_of().is_some()
2155 }
2156
2157 pub(crate) fn is_editing_host(&self) -> bool {
2159 self.downcast::<HTMLElement>()
2160 .is_some_and(HTMLElement::is_editing_host)
2161 }
2162
2163 pub(crate) fn is_editable(&self) -> bool {
2165 if self.is_editing_host() {
2167 return false;
2168 }
2169 let html_element = self.downcast::<HTMLElement>();
2171 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2172 return false;
2173 }
2174 let Some(parent) = self.GetParentNode() else {
2176 return false;
2177 };
2178 if !parent.is_editable_or_editing_host() {
2179 return false;
2180 }
2181 html_element.is_some() || (!self.is::<Element>() && parent.is::<HTMLElement>())
2183 }
2184}
2185
2186fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2188where
2189 I: Iterator<Item = DomRoot<Node>>,
2190{
2191 nodes.find(|node| {
2192 not_in.iter().all(|n| match *n {
2193 NodeOrString::Node(ref n) => n != node,
2194 _ => true,
2195 })
2196 })
2197}
2198
2199#[expect(unsafe_code)]
2202pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2203 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2204 DomRoot::from_ref(node)
2205}
2206
2207#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2209pub(crate) enum CloneChildrenFlag {
2210 CloneChildren,
2211 DoNotCloneChildren,
2212}
2213
2214impl From<bool> for CloneChildrenFlag {
2215 fn from(boolean: bool) -> Self {
2216 if boolean {
2217 CloneChildrenFlag::CloneChildren
2218 } else {
2219 CloneChildrenFlag::DoNotCloneChildren
2220 }
2221 }
2222}
2223
2224pub(super) fn as_uintptr<T>(t: &T) -> uintptr_t {
2225 t as *const T as uintptr_t
2226}
2227
2228impl Node {
2229 pub(crate) fn reflect_node<N>(
2230 cx: &mut JSContext,
2231 node: Box<N>,
2232 document: &Document,
2233 ) -> DomRoot<N>
2234 where
2235 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2236 {
2237 Self::reflect_node_with_proto(cx, node, document, None)
2238 }
2239
2240 pub(crate) fn reflect_node_with_proto<N>(
2241 cx: &mut JSContext,
2242 node: Box<N>,
2243 document: &Document,
2244 proto: Option<HandleObject>,
2245 ) -> DomRoot<N>
2246 where
2247 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2248 {
2249 let window = document.window();
2250 reflect_dom_object_with_proto_and_cx(node, window, proto, cx)
2251 }
2252
2253 pub(crate) fn reflect_weak_referenceable_node_with_proto<N>(
2254 cx: &mut JSContext,
2255 node: Rc<N>,
2256 document: &Document,
2257 proto: Option<HandleObject>,
2258 ) -> DomRoot<N>
2259 where
2260 N: DerivedFrom<Node> + DomObject + WeakReferenceableDomObjectWrap<crate::DomTypeHolder>,
2261 {
2262 let window = document.window();
2263 reflect_weak_referenceable_dom_object_with_proto(cx, node, window, proto)
2264 }
2265
2266 pub(crate) fn new_inherited(doc: &Document) -> Node {
2267 Node::new_(NodeFlags::empty(), Some(doc))
2268 }
2269
2270 pub(crate) fn new_document_node() -> Node {
2271 Node::new_(
2272 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2273 None,
2274 )
2275 }
2276
2277 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2278 Node {
2279 eventtarget: EventTarget::new_inherited(),
2280 parent_node: Default::default(),
2281 first_child: Default::default(),
2282 last_child: Default::default(),
2283 next_sibling: Default::default(),
2284 prev_sibling: Default::default(),
2285 owner_doc: MutNullableDom::new(doc),
2286 rare_data: Default::default(),
2287 children_count: Cell::new(0u32),
2288 flags: Cell::new(flags),
2289 inclusive_descendants_version: Cell::new(0),
2290 layout_data: Default::default(),
2291 }
2292 }
2293
2294 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2296 document.add_script_and_layout_blocker();
2297
2298 let old_doc = node.owner_doc();
2300 old_doc.add_script_and_layout_blocker();
2301
2302 node.remove_self(cx);
2304
2305 if &*old_doc != document {
2307 for descendant in node.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes) {
2309 descendant.set_owner_doc(document);
2311
2312 if let Some(element) = descendant.downcast::<Element>() {
2315 for attribute in element.attrs().borrow().iter() {
2316 if let Some(attr) = attribute.as_attr() {
2317 attr.upcast::<Node>().set_owner_doc(document);
2318 }
2319 }
2320 }
2321 }
2322
2323 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2327 for descendant in node
2328 .traverse_preorder(ShadowIncluding::Yes)
2329 .filter_map(|d| d.as_custom_element())
2330 {
2331 custom_element_reaction_stack.enqueue_callback_reaction(
2332 cx,
2333 &descendant,
2334 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2335 None,
2336 );
2337 }
2338
2339 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2342 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2343 }
2344 }
2345
2346 old_doc.remove_script_and_layout_blocker(cx);
2347 document.remove_script_and_layout_blocker(cx);
2348 }
2349
2350 pub(crate) fn ensure_pre_insertion_validity(
2352 no_gc: &NoGC,
2353 node: &Node,
2354 parent: &Node,
2355 child: Option<&Node>,
2356 ) -> ErrorResult {
2357 match parent.type_id() {
2359 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2360 },
2361 _ => {
2362 return Err(Error::HierarchyRequest(Some(
2363 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2364 )));
2365 },
2366 }
2367
2368 if node.is_host_including_inclusive_ancestor(parent) {
2370 return Err(Error::HierarchyRequest(Some(
2371 "Node is a host-including inclusive ancestor of parent".to_owned(),
2372 )));
2373 }
2374
2375 if let Some(child) = child &&
2377 !parent.is_parent_of(child)
2378 {
2379 return Err(Error::NotFound(Some(
2380 "Child is non-null and its parent is not parent".to_owned(),
2381 )));
2382 }
2383
2384 match node.type_id() {
2385 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2389 if parent.is::<Document>() {
2390 return Err(Error::HierarchyRequest(Some(
2391 "Node is a Text node and parent is a document".to_owned(),
2392 )));
2393 }
2394 },
2395 NodeTypeId::DocumentType => {
2396 if !parent.is::<Document>() {
2397 return Err(Error::HierarchyRequest(Some(
2398 "Node is a doctype and parent is not a document".to_owned(),
2399 )));
2400 }
2401 },
2402 NodeTypeId::DocumentFragment(_) |
2403 NodeTypeId::Element(_) |
2404 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2405 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2406 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2409 return Err(Error::HierarchyRequest(Some(
2410 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2411 .to_owned(),
2412 )));
2413 },
2414 }
2415
2416 if parent.is::<Document>() {
2419 match node.type_id() {
2420 NodeTypeId::DocumentFragment(_) => {
2421 if node.children_unrooted(no_gc).any(|c| c.is::<Text>()) {
2423 return Err(Error::HierarchyRequest(None));
2424 }
2425 match node.child_elements_unrooted(no_gc).count() {
2426 0 => (),
2427 1 => {
2430 if parent.child_elements_unrooted(no_gc).next().is_some() {
2431 return Err(Error::HierarchyRequest(None));
2432 }
2433 if let Some(child) = child &&
2434 child
2435 .inclusively_following_siblings_unrooted(no_gc)
2436 .any(|child| child.is_doctype())
2437 {
2438 return Err(Error::HierarchyRequest(None));
2439 }
2440 },
2441 _ => return Err(Error::HierarchyRequest(None)),
2442 }
2443 },
2444 NodeTypeId::Element(_) => {
2445 if parent.child_elements_unrooted(no_gc).next().is_some() {
2447 return Err(Error::HierarchyRequest(Some(
2448 "Parent has an element child".to_owned(),
2449 )));
2450 }
2451 if let Some(child) = child &&
2452 child
2453 .inclusively_following_siblings_unrooted(no_gc)
2454 .any(|following| following.is_doctype())
2455 {
2456 return Err(Error::HierarchyRequest(Some(
2457 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
2458 )));
2459 }
2460 },
2461 NodeTypeId::DocumentType => {
2462 if parent.children_unrooted(no_gc).any(|c| c.is_doctype()) {
2465 return Err(Error::HierarchyRequest(None));
2466 }
2467 match child {
2468 Some(child) => {
2469 if parent
2470 .children_unrooted(no_gc)
2471 .take_while(|c| **c != child)
2472 .any(|c| c.is::<Element>())
2473 {
2474 return Err(Error::HierarchyRequest(None));
2475 }
2476 },
2477 None => {
2478 if parent.child_elements_unrooted(no_gc).next().is_some() {
2479 return Err(Error::HierarchyRequest(None));
2480 }
2481 },
2482 }
2483 },
2484 NodeTypeId::CharacterData(_) => (),
2485 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
2488 }
2489 }
2490 Ok(())
2491 }
2492
2493 pub(crate) fn pre_insert(
2495 cx: &mut JSContext,
2496 node: &Node,
2497 parent: &Node,
2498 child: Option<&Node>,
2499 ) -> Fallible<DomRoot<Node>> {
2500 Node::ensure_pre_insertion_validity(cx.no_gc(), node, parent, child)?;
2502
2503 let reference_child_root;
2505 let reference_child = match child {
2506 Some(child) if child == node => {
2508 reference_child_root = node.GetNextSibling();
2509 reference_child_root.as_deref()
2510 },
2511 _ => child,
2512 };
2513
2514 Node::insert(
2516 cx,
2517 node,
2518 parent,
2519 reference_child,
2520 SuppressObserver::Unsuppressed,
2521 );
2522
2523 Ok(DomRoot::from_ref(node))
2525 }
2526
2527 pub(crate) fn insert(
2529 cx: &mut JSContext,
2530 node: &Node,
2531 parent: &Node,
2532 child: Option<&Node>,
2533 suppress_observers: SuppressObserver,
2534 ) {
2535 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
2536
2537 rooted_vec!(let mut new_nodes);
2539 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2540 new_nodes.extend(
2541 node.children_unrooted(cx.no_gc())
2542 .map(|node| Dom::from_ref(&**node)),
2543 );
2544 new_nodes.r()
2545 } else {
2546 from_ref(&node)
2547 };
2548
2549 let count = new_nodes.len();
2551
2552 if count == 0 {
2554 return;
2555 }
2556
2557 let parent_document = parent.owner_doc();
2560 let from_document = node.owner_doc();
2561 from_document.add_script_and_layout_blocker();
2562 parent_document.add_script_and_layout_blocker();
2563
2564 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2566 for kid in new_nodes {
2568 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
2569 }
2570 vtable_for(node).children_changed(cx, &ChildrenMutation::ReplaceAll);
2571
2572 let mutation = LazyCell::new(|| Mutation::ChildList {
2574 added: None,
2575 removed: Some(new_nodes),
2576 prev: None,
2577 next: None,
2578 });
2579 MutationObserver::queue_a_mutation_record(cx, node, mutation);
2580 }
2581
2582 if let Some(child) = child &&
2588 let Some(parent_weak_ranges) = parent.weak_ranges_mut()
2589 {
2590 parent_weak_ranges.increase_above(parent, child.index(), count.try_into().unwrap());
2591 }
2592
2593 let previous_sibling = match suppress_observers {
2595 SuppressObserver::Unsuppressed => match child {
2596 Some(child) => child.GetPreviousSibling(),
2597 None => parent.GetLastChild(),
2598 },
2599 SuppressObserver::Suppressed => None,
2600 };
2601
2602 let mut static_node_list: SmallVec<[_; 4]> = Default::default();
2604
2605 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
2606 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
2607 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
2608
2609 for kid in new_nodes {
2611 Node::adopt(cx, kid, &parent.owner_document());
2613
2614 parent.add_child(cx, kid, child);
2617
2618 if let Some(ref shadow_root) = parent_shadow_root &&
2621 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
2622 (kid.is::<Element>() || kid.is::<Text>())
2623 {
2624 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(kid)));
2625 slottable.assign_a_slot(cx);
2626 }
2627
2628 if parent_in_shadow_tree &&
2631 let Some(slot_element) = parent_as_slot &&
2632 !slot_element.has_assigned_nodes()
2633 {
2634 slot_element.signal_a_slot_change(cx);
2635 }
2636
2637 kid.GetRootNode(&GetRootNodeOptions::empty())
2639 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
2640
2641 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
2644 if let Some(element) = DomRoot::downcast::<Element>(descendant.clone()) &&
2650 !element.is_custom()
2651 {
2652 try_upgrade_element(cx, &element);
2653 }
2654
2655 if !descendant.is_connected() {
2657 continue;
2658 }
2659
2660 if let Some(element) = DomRoot::downcast::<Element>(descendant.clone()) {
2662 if let Some(registry) = element.custom_element_registry() {
2664 if registry.is_scoped() {
2669 registry.add_scoped_document(&element.owner_document());
2670 }
2671 }
2672 if element.is_custom() {
2680 ScriptThread::custom_element_reaction_stack().enqueue_callback_reaction(
2681 cx,
2682 &element,
2683 CallbackReaction::Connected,
2684 None,
2685 );
2686 }
2687 else {
2689 try_upgrade_element(cx, &element);
2690 }
2691 }
2692 else if let Some(shadow_root) =
2699 DomRoot::downcast::<ShadowRoot>(descendant.clone()) &&
2700 let Some(custom_element_registry) = shadow_root.custom_element_registry() &&
2701 custom_element_registry.is_scoped()
2702 {
2703 custom_element_registry.add_scoped_document(shadow_root.owner_doc());
2704 }
2705
2706 static_node_list.push(descendant.clone());
2709 }
2710 }
2711
2712 if let SuppressObserver::Unsuppressed = suppress_observers {
2713 vtable_for(parent).children_changed(
2716 cx,
2717 &ChildrenMutation::insert(previous_sibling.as_deref(), child),
2718 );
2719
2720 let mutation = LazyCell::new(|| Mutation::ChildList {
2723 added: Some(new_nodes),
2724 removed: None,
2725 prev: previous_sibling.as_deref(),
2726 next: child,
2727 });
2728 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2729 }
2730
2731 parent_document.add_delayed_task(
2742 task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
2743 for node in static_node_list {
2748 vtable_for(&node).post_connection_steps(cx);
2749 }
2750 }),
2751 );
2752
2753 parent_document.remove_script_and_layout_blocker(cx);
2754 from_document.remove_script_and_layout_blocker(cx);
2755 }
2756
2757 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
2759 parent.owner_doc().add_script_and_layout_blocker();
2760
2761 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
2763
2764 rooted_vec!(let mut added_nodes);
2768 let added_nodes = if let Some(node) = node.as_ref() {
2769 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2770 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
2771 added_nodes.r()
2772 } else {
2773 from_ref(node)
2774 }
2775 } else {
2776 &[] as &[&Node]
2777 };
2778
2779 for child in &*removed_nodes {
2781 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
2782 }
2783
2784 if let Some(node) = node {
2786 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
2787 }
2788
2789 vtable_for(parent).children_changed(cx, &ChildrenMutation::ReplaceAll);
2790
2791 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
2794 let mutation = LazyCell::new(|| Mutation::ChildList {
2795 added: Some(added_nodes),
2796 removed: Some(removed_nodes.r()),
2797 prev: None,
2798 next: None,
2799 });
2800 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2801 }
2802 parent.owner_doc().remove_script_and_layout_blocker(cx);
2803 }
2804
2805 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
2807 if string.is_empty() {
2808 Node::replace_all(cx, None, parent);
2809 } else {
2810 let text = Text::new(cx, string, &parent.owner_document());
2811 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
2812 };
2813 }
2814
2815 pub(super) fn pre_remove(
2817 cx: &mut JSContext,
2818 child: &Node,
2819 parent: &Node,
2820 ) -> Fallible<DomRoot<Node>> {
2821 match child.GetParentNode() {
2823 Some(ref node) if &**node != parent => return Err(Error::NotFound(None)),
2824 None => return Err(Error::NotFound(None)),
2825 _ => (),
2826 }
2827
2828 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
2830
2831 Ok(DomRoot::from_ref(child))
2833 }
2834
2835 pub(super) fn remove(
2837 cx: &mut JSContext,
2838 node: &Node,
2839 parent: &Node,
2840 suppress_observers: SuppressObserver,
2841 ) {
2842 parent.owner_doc().add_script_and_layout_blocker();
2843
2844 assert!(
2848 node.GetParentNode()
2849 .is_some_and(|node_parent| &*node_parent == parent)
2850 );
2851
2852 let cached_index = Node::live_range_pre_remove_steps(node, parent);
2855
2856 let old_previous_sibling = node.GetPreviousSibling();
2860
2861 let old_next_sibling = node.GetNextSibling();
2863
2864 parent.remove_child(cx, node, cached_index);
2867
2868 if let Some(slot) = node.assigned_slot() {
2870 slot.assign_slottables(cx);
2871 }
2872
2873 if parent.is_in_a_shadow_tree() &&
2876 let Some(slot_element) = parent.downcast::<HTMLSlotElement>() &&
2877 !slot_element.has_assigned_nodes()
2878 {
2879 slot_element.signal_a_slot_change(cx);
2880 }
2881
2882 let has_slot_descendant = node
2884 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
2885 .any(|elem| elem.is::<HTMLSlotElement>());
2886 if has_slot_descendant {
2887 parent
2889 .GetRootNode(&GetRootNodeOptions::empty())
2890 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
2891
2892 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Force);
2894 }
2895
2896 if let SuppressObserver::Unsuppressed = suppress_observers {
2900 vtable_for(parent).children_changed(
2901 cx,
2902 &ChildrenMutation::replace(
2903 old_previous_sibling.as_deref(),
2904 &Some(node),
2905 old_next_sibling.as_deref(),
2906 ),
2907 );
2908
2909 let removed = [node];
2910 let mutation = LazyCell::new(|| Mutation::ChildList {
2911 added: None,
2912 removed: Some(&removed),
2913 prev: old_previous_sibling.as_deref(),
2914 next: old_next_sibling.as_deref(),
2915 });
2916 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2917 }
2918 parent.owner_doc().remove_script_and_layout_blocker(cx);
2919 }
2920
2921 fn live_range_pre_remove_steps(node: &Node, parent: &Node) -> Option<u32> {
2923 if parent.weak_ranges_is_empty() {
2924 return None;
2925 }
2926
2927 let index = node.index();
2933
2934 if let Some(parent_weak_ranges) = parent.weak_ranges_mut() {
2941 parent_weak_ranges.decrease_above(parent, index, 1);
2942 }
2943
2944 Some(index)
2948 }
2949
2950 pub(crate) fn clone(
2952 cx: &mut JSContext,
2953 node: &Node,
2954 maybe_doc: Option<&Document>,
2955 clone_children: CloneChildrenFlag,
2956 registry: Option<DomRoot<CustomElementRegistry>>,
2957 ) -> DomRoot<Node> {
2958 let document = match maybe_doc {
2960 Some(doc) => DomRoot::from_ref(doc),
2961 None => node.owner_doc(),
2962 };
2963
2964 let copy: DomRoot<Node> = match node.type_id() {
2967 NodeTypeId::DocumentType => {
2968 let doctype = node.downcast::<DocumentType>().unwrap();
2969 let doctype = DocumentType::new(
2970 cx,
2971 doctype.name().clone(),
2972 Some(doctype.public_id().clone()),
2973 Some(doctype.system_id().clone()),
2974 &document,
2975 );
2976 DomRoot::upcast::<Node>(doctype)
2977 },
2978 NodeTypeId::Attr => {
2979 let attr = node.downcast::<Attr>().unwrap();
2980 let attr = Attr::new(
2981 cx,
2982 &document,
2983 attr.local_name().clone(),
2984 attr.value().clone(),
2985 attr.name().clone(),
2986 attr.namespace().clone(),
2987 attr.prefix().cloned(),
2988 None,
2989 );
2990 DomRoot::upcast::<Node>(attr)
2991 },
2992 NodeTypeId::DocumentFragment(_) => {
2993 let doc_fragment = DocumentFragment::new(cx, &document);
2994 DomRoot::upcast::<Node>(doc_fragment)
2995 },
2996 NodeTypeId::CharacterData(_) => {
2997 let cdata = node.downcast::<CharacterData>().unwrap();
2998 cdata.clone_with_data(cx, cdata.Data(), &document)
2999 },
3000 NodeTypeId::Document(_) => {
3001 let document = node.downcast::<Document>().unwrap();
3004 let is_html_doc = if document.is_html_document() {
3005 IsHTMLDocument::HTMLDocument
3006 } else {
3007 IsHTMLDocument::NonHTMLDocument
3008 };
3009 let window = document.window();
3010 let loader = DocumentLoader::new(&document.loader());
3011 let document = Document::new(
3012 cx,
3013 window,
3014 HasBrowsingContext::No,
3015 Some(document.url()),
3016 None,
3017 document.origin().clone(),
3019 is_html_doc,
3020 None,
3021 None,
3022 DocumentActivity::Inactive,
3023 DocumentSource::NotFromParser,
3024 loader,
3025 None,
3026 document.status_code(),
3027 Default::default(),
3028 false,
3029 document.allow_declarative_shadow_roots(),
3030 Some(document.insecure_requests_policy()),
3031 document.has_trustworthy_ancestor_or_current_origin(),
3032 document.custom_element_reaction_stack(),
3033 document.creation_sandboxing_flag_set(),
3034 document.pipeline_id(),
3035 document.image_cache(),
3036 );
3037 DomRoot::upcast::<Node>(document)
3041 },
3042 NodeTypeId::Element(..) => {
3044 let element = node.downcast::<Element>().unwrap();
3045 let registry = element.custom_element_registry().or(registry);
3048 let registry =
3051 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3052 document.custom_element_registry()
3053 } else {
3054 registry
3055 };
3056 let name = QualName {
3060 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3061 ns: element.namespace().clone(),
3062 local: element.local_name().clone(),
3063 };
3064 let element = Element::create(
3065 cx,
3066 name,
3067 element.get_is(),
3068 &document,
3069 ElementCreator::ScriptCreated,
3070 CustomElementCreationMode::Asynchronous,
3071 None,
3072 );
3073 element.set_custom_element_registry(registry.as_deref());
3075 DomRoot::upcast::<Node>(element)
3076 },
3077 };
3078
3079 let document = match copy.downcast::<Document>() {
3082 Some(doc) => DomRoot::from_ref(doc),
3083 None => DomRoot::from_ref(&*document),
3084 };
3085 assert!(copy.owner_doc() == document);
3086
3087 match node.type_id() {
3089 NodeTypeId::Document(_) => {
3090 let node_doc = node.downcast::<Document>().unwrap();
3091 let copy_doc = copy.downcast::<Document>().unwrap();
3092 copy_doc.set_encoding(node_doc.encoding());
3093 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3094 },
3095 NodeTypeId::Element(..) => {
3096 let node_elem = node.downcast::<Element>().unwrap();
3097 let copy_elem = copy.downcast::<Element>().unwrap();
3098
3099 node_elem.copy_all_attributes_to_other_element(cx, copy_elem);
3101 },
3102 _ => (),
3103 }
3104
3105 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3108
3109 if clone_children == CloneChildrenFlag::CloneChildren {
3112 for child in node.children() {
3113 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3114 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3115 }
3116 }
3117
3118 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3121 let node_elem = node.downcast::<Element>().unwrap();
3122 let copy_elem = copy.downcast::<Element>().unwrap();
3123
3124 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3125 assert!(!copy_elem.is_shadow_host());
3127
3128 let copy_shadow_root =
3132 copy_elem.attach_shadow(
3133 cx,
3134 IsUserAgentWidget::No,
3135 shadow_root.Mode(),
3136 shadow_root.Clonable(),
3137 shadow_root.Serializable(),
3138 shadow_root.DelegatesFocus(),
3139 shadow_root.SlotAssignment(),
3140 )
3141 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3142
3143 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3145
3146 for child in shadow_root.upcast::<Node>().children() {
3149 let child_copy = Node::clone(
3150 cx,
3151 &child,
3152 Some(&document),
3153 CloneChildrenFlag::CloneChildren,
3154 None,
3155 );
3156
3157 let _inserted_node =
3159 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3160 }
3161 }
3162 }
3163
3164 copy
3166 }
3167
3168 pub(crate) fn child_text_content(&self) -> DOMString {
3170 Node::collect_text_contents(self.children())
3171 }
3172
3173 pub(crate) fn descendant_text_content(&self) -> DOMString {
3175 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3176 }
3177
3178 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3179 iterator: T,
3180 ) -> DOMString {
3181 let mut content = String::new();
3182 for node in iterator {
3183 if let Some(text) = node.downcast::<Text>() {
3184 content.push_str(&text.upcast::<CharacterData>().data());
3185 }
3186 }
3187 DOMString::from(content)
3188 }
3189
3190 pub(crate) fn set_text_content_for_element(
3192 &self,
3193 cx: &mut JSContext,
3194 value: Option<DOMString>,
3195 ) {
3196 assert!(matches!(
3199 self.type_id(),
3200 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3201 ));
3202 let value = value.unwrap_or_default();
3203 let node = if value.is_empty() {
3204 None
3206 } else {
3207 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3210 };
3211
3212 Self::replace_all(cx, node.as_deref(), self);
3214 }
3215
3216 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3217 match namespace {
3218 ns!() => None,
3219 _ => Some(DOMString::from(&*namespace)),
3221 }
3222 }
3223
3224 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3226 match node.type_id() {
3227 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3228 NodeTypeId::Attr => node
3229 .downcast::<Attr>()
3230 .unwrap()
3231 .GetOwnerElement()
3232 .as_ref()
3233 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3234 NodeTypeId::Document(_) => node
3235 .downcast::<Document>()
3236 .unwrap()
3237 .GetDocumentElement()
3238 .as_ref()
3239 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3240 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3241 _ => node
3242 .GetParentElement()
3243 .as_ref()
3244 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3245 }
3246 }
3247
3248 #[expect(unsafe_code)]
3256 pub(crate) unsafe fn from_untrusted_node_address(
3257 candidate: UntrustedNodeAddress,
3258 ) -> &'static Self {
3259 let candidate = candidate.0 as usize;
3261 let object = candidate as *mut JSObject;
3262 if object.is_null() {
3263 panic!("Attempted to create a `Node` from an invalid pointer!")
3264 }
3265
3266 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3267 }
3268
3269 pub(crate) fn html_serialize(
3270 &self,
3271 cx: &mut JSContext,
3272 traversal_scope: html_serialize::TraversalScope,
3273 serialize_shadow_roots: bool,
3274 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3275 ) -> DOMString {
3276 let mut writer = vec![];
3277 let mut serializer = HtmlSerializer::new(
3278 &mut writer,
3279 html_serialize::SerializeOpts {
3280 traversal_scope: traversal_scope.clone(),
3281 ..Default::default()
3282 },
3283 );
3284
3285 serialize_html_fragment(
3286 cx,
3287 self,
3288 &mut serializer,
3289 traversal_scope,
3290 serialize_shadow_roots,
3291 shadow_roots,
3292 )
3293 .expect("Serializing node failed");
3294
3295 DOMString::from(String::from_utf8(writer).unwrap())
3297 }
3298
3299 pub(crate) fn xml_serialize(
3301 &self,
3302 traversal_scope: xml_serialize::TraversalScope,
3303 ) -> Fallible<DOMString> {
3304 let mut writer = vec![];
3305 xml_serialize::serialize(
3306 &mut writer,
3307 &HtmlSerialize::new(self),
3308 xml_serialize::SerializeOpts { traversal_scope },
3309 )
3310 .map_err(|error| {
3311 error!("Cannot serialize node: {error}");
3312 Error::InvalidState(None)
3313 })?;
3314
3315 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3317 error!("Cannot serialize node: {error}");
3318 Error::InvalidState(None)
3319 })?);
3320
3321 Ok(string)
3322 }
3323
3324 pub(crate) fn fragment_serialization_algorithm(
3326 &self,
3327 cx: &mut JSContext,
3328 require_well_formed: bool,
3329 ) -> Fallible<DOMString> {
3330 let context_document = self.owner_document();
3332
3333 if context_document.is_html_document() {
3336 return Ok(self.html_serialize(
3337 cx,
3338 html_serialize::TraversalScope::ChildrenOnly(None),
3339 false,
3340 vec![],
3341 ));
3342 }
3343
3344 let _ = require_well_formed;
3347 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3348 }
3349
3350 pub(crate) fn get_next_sibling_unrooted<'a>(
3351 &self,
3352 no_gc: &'a NoGC,
3353 ) -> Option<UnrootedDom<'a, Node>> {
3354 self.next_sibling.get_unrooted(no_gc)
3355 }
3356
3357 pub(crate) fn get_previous_sibling_unrooted<'a>(
3358 &self,
3359 no_gc: &'a NoGC,
3360 ) -> Option<UnrootedDom<'a, Node>> {
3361 self.prev_sibling.get_unrooted(no_gc)
3362 }
3363
3364 pub(crate) fn get_first_child_unrooted<'a>(
3365 &self,
3366 no_gc: &'a NoGC,
3367 ) -> Option<UnrootedDom<'a, Node>> {
3368 self.first_child.get_unrooted(no_gc)
3369 }
3370
3371 fn get_last_child_unrooted<'b>(&self, no_gc: &'b NoGC) -> Option<UnrootedDom<'b, Node>> {
3372 self.last_child.get_unrooted(no_gc)
3373 }
3374
3375 pub(crate) fn get_parent_node_unrooted<'a>(
3376 &self,
3377 no_gc: &'a NoGC,
3378 ) -> Option<UnrootedDom<'a, Node>> {
3379 self.parent_node.get_unrooted(no_gc)
3380 }
3381
3382 pub(crate) fn compare_dom_tree_position(
3384 &self,
3385 other: &Node,
3386 common_ancestor: &Node,
3387 shadow_including: ShadowIncluding,
3388 ) -> Ordering {
3389 debug_assert!(
3390 self.inclusive_ancestors(shadow_including)
3391 .any(|ancestor| &*ancestor == common_ancestor)
3392 );
3393 debug_assert!(
3394 other
3395 .inclusive_ancestors(shadow_including)
3396 .any(|ancestor| &*ancestor == common_ancestor)
3397 );
3398
3399 if self == other {
3400 return Ordering::Equal;
3401 }
3402
3403 if self == common_ancestor {
3404 return Ordering::Less;
3405 }
3406 if other == common_ancestor {
3407 return Ordering::Greater;
3408 }
3409
3410 let my_ancestors: Vec<_> = self
3411 .inclusive_ancestors(shadow_including)
3412 .take_while(|ancestor| &**ancestor != common_ancestor)
3413 .collect();
3414 let other_ancestors: Vec<_> = other
3415 .inclusive_ancestors(shadow_including)
3416 .take_while(|ancestor| &**ancestor != common_ancestor)
3417 .collect();
3418
3419 let mut i = my_ancestors.len() - 1;
3421 let mut j = other_ancestors.len() - 1;
3422
3423 while my_ancestors[i] == other_ancestors[j] {
3424 if i == 0 {
3425 debug_assert_ne!(j, 0, "Equal inclusive ancestors but nodes are not equal?");
3427 return Ordering::Less;
3428 }
3429 if j == 0 {
3430 return Ordering::Greater;
3432 }
3433
3434 i -= 1;
3435 j -= 1;
3436 }
3437
3438 if my_ancestors[i]
3441 .preceding_siblings()
3442 .any(|sibling| sibling == other_ancestors[j])
3443 {
3444 Ordering::Greater
3446 } else {
3447 debug_assert!(
3449 other_ancestors[j]
3450 .preceding_siblings()
3451 .any(|sibling| sibling == my_ancestors[i])
3452 );
3453 Ordering::Less
3454 }
3455 }
3456}
3457
3458impl NodeMethods<crate::DomTypeHolder> for Node {
3459 fn NodeType(&self) -> u16 {
3461 match self.type_id() {
3462 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3463 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3464 NodeConstants::TEXT_NODE
3465 },
3466 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3467 NodeConstants::CDATA_SECTION_NODE
3468 },
3469 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3470 NodeConstants::PROCESSING_INSTRUCTION_NODE
3471 },
3472 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3473 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3474 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3475 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3476 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3477 }
3478 }
3479
3480 fn NodeName(&self) -> DOMString {
3482 match self.type_id() {
3483 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3484 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3485 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3486 DOMString::from("#text")
3487 },
3488 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3489 DOMString::from("#cdata-section")
3490 },
3491 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3492 self.downcast::<ProcessingInstruction>().unwrap().Target()
3493 },
3494 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => DOMString::from("#comment"),
3495 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3496 NodeTypeId::DocumentFragment(_) => DOMString::from("#document-fragment"),
3497 NodeTypeId::Document(_) => DOMString::from("#document"),
3498 }
3499 }
3500
3501 fn BaseURI(&self) -> USVString {
3503 USVString(String::from(self.owner_doc().base_url().as_str()))
3504 }
3505
3506 fn IsConnected(&self) -> bool {
3508 self.is_connected()
3509 }
3510
3511 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3513 match self.type_id() {
3514 NodeTypeId::Document(_) => None,
3515 _ => Some(self.owner_doc()),
3516 }
3517 }
3518
3519 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3521 if !options.composed &&
3522 let Some(shadow_root) = self.containing_shadow_root()
3523 {
3524 return DomRoot::upcast(shadow_root);
3525 }
3526
3527 if self.is_connected() {
3528 DomRoot::from_ref(self.owner_doc().upcast::<Node>())
3529 } else {
3530 self.inclusive_ancestors(ShadowIncluding::Yes)
3531 .last()
3532 .unwrap()
3533 }
3534 }
3535
3536 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
3538 self.parent_node().get()
3539 }
3540
3541 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
3543 self.GetParentNode().and_then(DomRoot::downcast)
3544 }
3545
3546 fn HasChildNodes(&self) -> bool {
3548 self.first_child().get().is_some()
3549 }
3550
3551 fn ChildNodes(&self, cx: &mut JSContext) -> DomRoot<NodeList> {
3553 if let Some(list) = self.ensure_rare_data().child_list.get() {
3554 return list;
3555 }
3556
3557 let doc = self.owner_doc();
3558 let window = doc.window();
3559 let list = NodeList::new_child_list(cx, window, self);
3560 self.ensure_rare_data().child_list.set(Some(&list));
3561 list
3562 }
3563
3564 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
3566 self.first_child().get()
3567 }
3568
3569 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
3571 self.last_child().get()
3572 }
3573
3574 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
3576 self.prev_sibling().get()
3577 }
3578
3579 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
3581 self.next_sibling().get()
3582 }
3583
3584 fn GetNodeValue(&self) -> Option<DOMString> {
3586 match self.type_id() {
3587 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3588 NodeTypeId::CharacterData(_) => {
3589 self.downcast::<CharacterData>().map(CharacterData::Data)
3590 },
3591 _ => None,
3592 }
3593 }
3594
3595 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
3597 match self.type_id() {
3598 NodeTypeId::Attr => {
3599 let attr = self.downcast::<Attr>().unwrap();
3600 attr.SetValue(cx, val.unwrap_or_default())?;
3601 },
3602 NodeTypeId::CharacterData(_) => {
3603 let character_data = self.downcast::<CharacterData>().unwrap();
3604 character_data.SetData(cx, val.unwrap_or_default());
3605 },
3606 _ => {},
3607 };
3608 Ok(())
3609 }
3610
3611 fn GetTextContent(&self) -> Option<DOMString> {
3613 match self.type_id() {
3614 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3615 let content =
3616 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
3617 Some(content)
3618 },
3619 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3620 NodeTypeId::CharacterData(..) => {
3621 let characterdata = self.downcast::<CharacterData>().unwrap();
3622 Some(characterdata.Data())
3623 },
3624 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
3625 }
3626 }
3627
3628 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
3630 match self.type_id() {
3631 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3632 self.set_text_content_for_element(cx, value);
3633 },
3634 NodeTypeId::Attr => {
3635 let attr = self.downcast::<Attr>().unwrap();
3636 attr.SetValue(cx, value.unwrap_or_default())?;
3637 },
3638 NodeTypeId::CharacterData(..) => {
3639 let characterdata = self.downcast::<CharacterData>().unwrap();
3640 characterdata.SetData(cx, value.unwrap_or_default());
3641 },
3642 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
3643 };
3644 Ok(())
3645 }
3646
3647 fn InsertBefore(
3649 &self,
3650 cx: &mut JSContext,
3651 node: &Node,
3652 child: Option<&Node>,
3653 ) -> Fallible<DomRoot<Node>> {
3654 Node::pre_insert(cx, node, self, child)
3655 }
3656
3657 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3659 Node::pre_insert(cx, node, self, None)
3660 }
3661
3662 fn ReplaceChild(
3664 &self,
3665 cx: &mut JSContext,
3666 node: &Node,
3667 child: &Node,
3668 ) -> Fallible<DomRoot<Node>> {
3669 match self.type_id() {
3672 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3673 },
3674 _ => return Err(Error::HierarchyRequest(None)),
3675 }
3676
3677 if node.is_inclusive_ancestor_of(self) {
3680 return Err(Error::HierarchyRequest(None));
3681 }
3682
3683 if !self.is_parent_of(child) {
3685 return Err(Error::NotFound(None));
3686 }
3687
3688 match node.type_id() {
3693 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
3694 return Err(Error::HierarchyRequest(None));
3695 },
3696 NodeTypeId::DocumentType if !self.is::<Document>() => {
3697 return Err(Error::HierarchyRequest(None));
3698 },
3699 NodeTypeId::Document(_) | NodeTypeId::Attr => {
3700 return Err(Error::HierarchyRequest(None));
3701 },
3702 _ => (),
3703 }
3704
3705 if self.is::<Document>() {
3708 match node.type_id() {
3709 NodeTypeId::DocumentFragment(_) => {
3711 if node.children_unrooted(cx.no_gc()).any(|c| c.is::<Text>()) {
3713 return Err(Error::HierarchyRequest(None));
3714 }
3715 match node.child_elements_unrooted(cx.no_gc()).count() {
3716 0 => (),
3717 1 => {
3719 if self
3720 .child_elements_unrooted(cx.no_gc())
3721 .any(|c| c.upcast::<Node>() != child)
3722 {
3723 return Err(Error::HierarchyRequest(None));
3724 }
3725 if child.following_siblings().any(|child| child.is_doctype()) {
3726 return Err(Error::HierarchyRequest(None));
3727 }
3728 },
3729 _ => return Err(Error::HierarchyRequest(None)),
3731 }
3732 },
3733 NodeTypeId::Element(..) => {
3735 if self
3736 .child_elements_unrooted(cx.no_gc())
3737 .any(|c| c.upcast::<Node>() != child)
3738 {
3739 return Err(Error::HierarchyRequest(None));
3740 }
3741 if child.following_siblings().any(|child| child.is_doctype()) {
3742 return Err(Error::HierarchyRequest(None));
3743 }
3744 },
3745 NodeTypeId::DocumentType => {
3747 if self
3748 .children_unrooted(cx.no_gc())
3749 .any(|c| c.is_doctype() && *c != child)
3750 {
3751 return Err(Error::HierarchyRequest(None));
3752 }
3753 if self
3754 .children_unrooted(cx.no_gc())
3755 .take_while(|c| **c != child)
3756 .any(|c| c.is::<Element>())
3757 {
3758 return Err(Error::HierarchyRequest(None));
3759 }
3760 },
3761 NodeTypeId::CharacterData(..) => (),
3762 NodeTypeId::Document(_) => unreachable!(),
3765 NodeTypeId::Attr => unreachable!(),
3766 }
3767 }
3768
3769 let child_next_sibling = child.GetNextSibling();
3772 let node_next_sibling = node.GetNextSibling();
3773 let reference_child = if child_next_sibling.as_deref() == Some(node) {
3774 node_next_sibling.as_deref()
3775 } else {
3776 child_next_sibling.as_deref()
3777 };
3778
3779 let previous_sibling = child.GetPreviousSibling();
3781
3782 let document = self.owner_document();
3786 Node::adopt(cx, node, &document);
3787
3788 let removed_child = if node != child {
3793 Node::remove(cx, child, self, SuppressObserver::Suppressed);
3795 Some(child)
3796 } else {
3797 None
3798 };
3799
3800 rooted_vec!(let mut nodes);
3802 let nodes = if node.type_id() ==
3803 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
3804 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
3805 {
3806 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
3807 nodes.r()
3808 } else {
3809 from_ref(&node)
3810 };
3811
3812 Node::insert(
3814 cx,
3815 node,
3816 self,
3817 reference_child,
3818 SuppressObserver::Suppressed,
3819 );
3820
3821 vtable_for(self).children_changed(
3822 cx,
3823 &ChildrenMutation::replace(
3824 previous_sibling.as_deref(),
3825 &removed_child,
3826 reference_child,
3827 ),
3828 );
3829
3830 let removed = removed_child.map(|r| [r]);
3833 let mutation = LazyCell::new(|| Mutation::ChildList {
3834 added: Some(nodes),
3835 removed: removed.as_ref().map(|r| &r[..]),
3836 prev: previous_sibling.as_deref(),
3837 next: reference_child,
3838 });
3839
3840 MutationObserver::queue_a_mutation_record(cx, self, mutation);
3841
3842 Ok(DomRoot::from_ref(child))
3844 }
3845
3846 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3848 Node::pre_remove(cx, node, self)
3849 }
3850
3851 fn Normalize(&self, cx: &mut JSContext) {
3853 let mut children = self.children().enumerate().peekable();
3854 while let Some((_, node)) = children.next() {
3855 if let Some(text) = node.downcast::<Text>() {
3856 if text.is::<CDATASection>() {
3857 continue;
3858 }
3859 let cdata = text.upcast::<CharacterData>();
3860 let mut length = cdata.Length();
3861 if length == 0 {
3862 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
3863 continue;
3864 }
3865 while children.peek().is_some_and(|(_, sibling)| {
3866 sibling.is::<Text>() && !sibling.is::<CDATASection>()
3867 }) {
3868 let (index, sibling) = children.next().unwrap();
3869 if let Some(sibling_weak_ranges) = sibling.weak_ranges_mut() {
3870 sibling_weak_ranges
3871 .drain_to_preceding_text_sibling(&sibling, &node, length);
3872 }
3873 if let Some(weak_ranges) = self.weak_ranges_mut() {
3874 weak_ranges.move_to_text_child_at(self, index as u32, &node, length);
3875 }
3876 let sibling_cdata = sibling.downcast::<CharacterData>().unwrap();
3877 length += sibling_cdata.Length();
3878 cdata.append_data(cx, &sibling_cdata.data());
3879 Node::remove(cx, &sibling, self, SuppressObserver::Unsuppressed);
3880 }
3881 } else {
3882 node.Normalize(cx);
3883 }
3884 }
3885 }
3886
3887 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
3889 if self.is::<ShadowRoot>() {
3891 return Err(Error::NotSupported(None));
3892 }
3893
3894 let result = Node::clone(
3896 cx,
3897 self,
3898 None,
3899 if subtree {
3900 CloneChildrenFlag::CloneChildren
3901 } else {
3902 CloneChildrenFlag::DoNotCloneChildren
3903 },
3904 None,
3905 );
3906 Ok(result)
3907 }
3908
3909 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
3911 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
3912 let doctype = node.downcast::<DocumentType>().unwrap();
3913 let other_doctype = other.downcast::<DocumentType>().unwrap();
3914 (*doctype.name() == *other_doctype.name()) &&
3915 (*doctype.public_id() == *other_doctype.public_id()) &&
3916 (*doctype.system_id() == *other_doctype.system_id())
3917 }
3918 fn is_equal_element(node: &Node, other: &Node) -> bool {
3919 let element = node.downcast::<Element>().unwrap();
3920 let other_element = other.downcast::<Element>().unwrap();
3921 (*element.namespace() == *other_element.namespace()) &&
3922 (*element.prefix() == *other_element.prefix()) &&
3923 (*element.local_name() == *other_element.local_name()) &&
3924 (element.attrs().borrow().len() == other_element.attrs().borrow().len())
3925 }
3926 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
3927 let pi = node.downcast::<ProcessingInstruction>().unwrap();
3928 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
3929 (*pi.target() == *other_pi.target()) &&
3930 (*pi.upcast::<CharacterData>().data() ==
3931 *other_pi.upcast::<CharacterData>().data())
3932 }
3933 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
3934 let characterdata = node.downcast::<CharacterData>().unwrap();
3935 let other_characterdata = other.downcast::<CharacterData>().unwrap();
3936 *characterdata.data() == *other_characterdata.data()
3937 }
3938 fn is_equal_attr(node: &Node, other: &Node) -> bool {
3939 let attr = node.downcast::<Attr>().unwrap();
3940 let other_attr = other.downcast::<Attr>().unwrap();
3941 (*attr.namespace() == *other_attr.namespace()) &&
3942 (attr.local_name() == other_attr.local_name()) &&
3943 (**attr.value() == **other_attr.value())
3944 }
3945 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
3946 let element = node.downcast::<Element>().unwrap();
3947 let other_element = other.downcast::<Element>().unwrap();
3948 assert!(element.attrs().borrow().len() == other_element.attrs().borrow().len());
3949 element.attrs().borrow().iter().all(|attr| {
3950 other_element.attrs().borrow().iter().any(|other_attr| {
3951 (*attr.namespace() == *other_attr.namespace()) &&
3952 (attr.local_name() == other_attr.local_name()) &&
3953 (**attr.value() == **other_attr.value())
3954 })
3955 })
3956 }
3957
3958 fn is_equal_node(this: &Node, node: &Node) -> bool {
3959 if this.NodeType() != node.NodeType() {
3961 return false;
3962 }
3963
3964 match node.type_id() {
3965 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
3967 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
3968 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
3969 if !is_equal_processinginstruction(this, node) =>
3970 {
3971 return false;
3972 },
3973 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
3974 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
3975 if !is_equal_characterdata(this, node) =>
3976 {
3977 return false;
3978 },
3979 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
3981 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
3982
3983 _ => (),
3984 }
3985
3986 if this.children_count() != node.children_count() {
3988 return false;
3989 }
3990
3991 this.children()
3993 .zip(node.children())
3994 .all(|(child, other_child)| is_equal_node(&child, &other_child))
3995 }
3996 match maybe_node {
3997 None => false,
3999 Some(node) => is_equal_node(self, node),
4001 }
4002 }
4003
4004 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
4006 match other_node {
4007 Some(node) => self == node,
4008 None => false,
4009 }
4010 }
4011
4012 fn CompareDocumentPosition(&self, other: &Node) -> u16 {
4014 if self == other {
4016 return 0;
4017 }
4018
4019 let mut node1 = Some(other);
4021 let mut node2 = Some(self);
4022
4023 let mut attr1: Option<&Attr> = None;
4025 let mut attr2: Option<&Attr> = None;
4026
4027 let attr1owner;
4032 if let Some(a) = other.downcast::<Attr>() {
4033 attr1 = Some(a);
4034 attr1owner = a.GetOwnerElement();
4035 node1 = match attr1owner {
4036 Some(ref e) => Some(e.upcast()),
4037 None => None,
4038 }
4039 }
4040
4041 let attr2owner;
4044 if let Some(a) = self.downcast::<Attr>() {
4045 attr2 = Some(a);
4046 attr2owner = a.GetOwnerElement();
4047 node2 = match attr2owner {
4048 Some(ref e) => Some(e.upcast()),
4049 None => None,
4050 }
4051 }
4052
4053 if let Some(node2) = node2 &&
4058 Some(node2) == node1 &&
4059 let (Some(a1), Some(a2)) = (attr1, attr2)
4060 {
4061 let attrs = node2.downcast::<Element>().unwrap().attrs();
4062 for attr in attrs.borrow().iter() {
4066 if (*attr.namespace() == *a1.namespace()) &&
4067 (attr.local_name() == a1.local_name()) &&
4068 (**attr.value() == **a1.value())
4069 {
4070 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4071 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4072 }
4073 if (*attr.namespace() == *a2.namespace()) &&
4074 (attr.local_name() == a2.local_name()) &&
4075 (**attr.value() == **a2.value())
4076 {
4077 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4078 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4079 }
4080 }
4081 unreachable!();
4084 }
4085
4086 match (node1, node2) {
4088 (None, _) => {
4089 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4091 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4092 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4093 },
4094 (_, None) => {
4095 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4097 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4098 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4099 },
4100 (Some(node1), Some(node2)) => {
4101 let mut self_and_ancestors = node2
4103 .inclusive_ancestors(ShadowIncluding::No)
4104 .collect::<SmallVec<[_; 20]>>();
4105 let mut other_and_ancestors = node1
4106 .inclusive_ancestors(ShadowIncluding::No)
4107 .collect::<SmallVec<[_; 20]>>();
4108
4109 if self_and_ancestors.last() != other_and_ancestors.last() {
4110 let random = as_uintptr(self_and_ancestors.last().unwrap()) <
4111 as_uintptr(other_and_ancestors.last().unwrap());
4112 let random = if random {
4113 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4114 } else {
4115 NodeConstants::DOCUMENT_POSITION_PRECEDING
4116 };
4117
4118 return random +
4120 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4121 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4122 }
4123 let mut parent = self_and_ancestors.pop().unwrap();
4125 other_and_ancestors.pop().unwrap();
4126
4127 let mut current_position =
4128 cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
4129
4130 while current_position > 0 {
4131 current_position -= 1;
4132 let child_1 = self_and_ancestors.pop().unwrap();
4133 let child_2 = other_and_ancestors.pop().unwrap();
4134
4135 if child_1 != child_2 {
4136 for child in parent.children() {
4137 if child == child_1 {
4138 return NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4140 }
4141 if child == child_2 {
4142 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4144 }
4145 }
4146 }
4147
4148 parent = child_1;
4149 }
4150
4151 if self_and_ancestors.len() < other_and_ancestors.len() {
4156 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4157 NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
4158 } else {
4159 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4160 NodeConstants::DOCUMENT_POSITION_CONTAINS
4161 }
4162 },
4163 }
4164 }
4165
4166 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4168 match maybe_other {
4169 None => false,
4170 Some(other) => self.is_inclusive_ancestor_of(other),
4171 }
4172 }
4173
4174 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4176 let namespace = namespace_from_domstring(namespace);
4177
4178 if namespace == ns!() {
4180 return None;
4181 }
4182
4183 match self.type_id() {
4185 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4186 NodeTypeId::Document(_) => self
4187 .downcast::<Document>()
4188 .unwrap()
4189 .GetDocumentElement()
4190 .and_then(|element| element.lookup_prefix(namespace)),
4191 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4192 NodeTypeId::Attr => self
4193 .downcast::<Attr>()
4194 .unwrap()
4195 .GetOwnerElement()
4196 .and_then(|element| element.lookup_prefix(namespace)),
4197 _ => self
4198 .GetParentElement()
4199 .and_then(|element| element.lookup_prefix(namespace)),
4200 }
4201 }
4202
4203 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4205 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4207
4208 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4210 }
4211
4212 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4214 let namespace = namespace_from_domstring(namespace);
4216 Node::locate_namespace(self, None) == namespace
4218 }
4219}
4220
4221pub(crate) trait NodeTraits {
4222 fn owner_document(&self) -> DomRoot<Document>;
4226 fn owner_window(&self) -> DomRoot<Window>;
4230 fn owner_global(&self) -> DomRoot<GlobalScope>;
4234 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4236 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4239}
4240
4241impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4242 fn owner_document(&self) -> DomRoot<Document> {
4243 self.upcast().owner_doc()
4244 }
4245
4246 fn owner_window(&self) -> DomRoot<Window> {
4247 DomRoot::from_ref(self.owner_document().window())
4248 }
4249
4250 fn owner_global(&self) -> DomRoot<GlobalScope> {
4251 DomRoot::from_ref(self.owner_window().upcast())
4252 }
4253
4254 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4255 Node::containing_shadow_root(self.upcast())
4256 }
4257
4258 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4259 self.containing_shadow_root()
4260 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4261 .unwrap_or_else(|| {
4262 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4263 })
4264 }
4265}
4266
4267impl VirtualMethods for Node {
4268 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4269 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4270 }
4271
4272 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4273 if let Some(s) = self.super_type() {
4274 s.children_changed(cx, mutation);
4275 }
4276
4277 if let Some(data) = self.rare_data.borrow().as_ref() &&
4278 let Some(list) = data.child_list.get()
4279 {
4280 list.as_children_list().children_changed(mutation);
4281 }
4282
4283 self.owner_doc_unrooted(cx.no_gc())
4284 .content_and_heritage_changed(cx.no_gc(), self);
4285 }
4286
4287 fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
4290 self.super_type().unwrap().unbind_from_tree(cx, context);
4291
4292 if !self.is_in_a_shadow_tree() &&
4297 let Some(weak_ranges) = self.weak_ranges_mut() &&
4298 !weak_ranges.is_empty()
4299 {
4300 weak_ranges.drain_to_parent(context.parent, context.index(), self);
4301 }
4302 }
4303
4304 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
4305 if let Some(super_type) = self.super_type() {
4306 super_type.moving_steps(cx, context);
4307 }
4308
4309 if let Some(old_parent) = context.old_parent &&
4314 !self.is_in_a_shadow_tree() &&
4315 let Some(weak_ranges) = self.weak_ranges_mut() &&
4316 !weak_ranges.is_empty()
4317 {
4318 weak_ranges.drain_to_parent(old_parent, context.index(), self);
4319 }
4320
4321 self.owner_doc_unrooted(cx.no_gc())
4322 .content_and_heritage_changed(cx.no_gc(), self);
4323 }
4324
4325 fn handle_event(&self, cx: &mut JSContext, event: &Event) {
4326 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4327 return;
4328 }
4329
4330 if let Some(event) = event.downcast::<KeyboardEvent>() {
4331 self.owner_document()
4332 .event_handler()
4333 .run_default_keyboard_event_handler(cx, self, event);
4334 }
4335 }
4336}
4337
4338#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4340pub(crate) enum NodeDamage {
4341 Style,
4343 ContentOrHeritage,
4346 Other,
4348}
4349
4350pub(crate) struct UniqueId {
4352 cell: UnsafeCell<Option<Box<Uuid>>>,
4353}
4354
4355unsafe_no_jsmanaged_fields!(UniqueId);
4356
4357impl MallocSizeOf for UniqueId {
4358 #[expect(unsafe_code)]
4359 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
4360 if let Some(uuid) = unsafe { &*self.cell.get() } {
4361 unsafe { ops.malloc_size_of(&**uuid) }
4362 } else {
4363 0
4364 }
4365 }
4366}
4367
4368impl UniqueId {
4369 pub(super) fn new() -> UniqueId {
4371 UniqueId {
4372 cell: UnsafeCell::new(None),
4373 }
4374 }
4375
4376 #[expect(unsafe_code)]
4378 pub(super) fn borrow(&self) -> &Uuid {
4379 unsafe {
4380 let ptr = self.cell.get();
4381 if (*ptr).is_none() {
4382 *ptr = Some(Box::new(Uuid::new_v4()));
4383 }
4384 (*ptr).as_ref().unwrap()
4385 }
4386 }
4387}
4388
4389pub(crate) trait VecPreOrderInsertionHelper<T> {
4392 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
4393}
4394
4395impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
4396where
4397 T: DerivedFrom<Node> + DomObject,
4398{
4399 fn insert_pre_order(&mut self, node: &T, tree_root: &Node) {
4404 let Err(insertion_index) = self.binary_search_by(|candidate| {
4405 candidate.upcast().compare_dom_tree_position(
4406 node.upcast(),
4407 tree_root,
4408 ShadowIncluding::No,
4409 )
4410 }) else {
4411 return;
4414 };
4415
4416 self.insert(insertion_index, Dom::from_ref(node));
4417 }
4418}
4419
4420pub(crate) enum FlatTreeParent {
4422 Parent(DomRoot<Node>),
4424 NotInFlatTree,
4427 RootNode,
4429}