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::slice::from_ref;
13use std::{cmp, fmt, iter};
14
15use app_units::Au;
16use bitflags::bitflags;
17use devtools_traits::NodeInfo;
18use dom_struct::dom_struct;
19use embedder_traits::UntrustedNodeAddress;
20use euclid::default::Size2D;
21use euclid::{Point2D, Rect};
22use html5ever::serialize::HtmlSerializer;
23use html5ever::{Namespace, Prefix, QualName, ns, serialize as html_serialize};
24use js::context::{JSContext, NoGC};
25use js::jsapi::JSObject;
26use js::rust::HandleObject;
27use keyboard_types::Modifiers;
28use layout_api::{
29 AxesOverflow, BoxAreaType, CSSPixelRectVec, GenericLayoutData, NodeRenderingType,
30 PhysicalSides, TrustedNodeAddress, with_layout_state,
31};
32use libc::{self, c_void, uintptr_t};
33use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
34use script_bindings::cell::{DomRefCell, Ref, RefMut};
35use script_bindings::codegen::GenericBindings::ElementBinding::ElementMethods;
36use script_bindings::codegen::GenericBindings::EventBinding::EventMethods;
37use script_bindings::codegen::GenericBindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
38use script_bindings::codegen::InheritTypes::{DocumentFragmentTypeId, TextTypeId};
39use script_bindings::reflector::{DomObject, DomObjectWrap, reflect_dom_object_with_proto_and_cx};
40use script_traits::DocumentActivity;
41use servo_arc::Arc as ServoArc;
42use servo_base::id::PipelineId;
43use servo_config::pref;
44use smallvec::SmallVec;
45use style::Atom;
46use style::context::QuirksMode;
47use style::dom::OpaqueNode;
48use style::dom_apis::{QueryAll, QueryFirst};
49use style::selector_parser::PseudoElement;
50use style::stylesheets::Stylesheet;
51use style_traits::CSSPixel;
52use uuid::Uuid;
53use xml5ever::{local_name, serialize as xml_serialize};
54
55use crate::conversions::Convert;
56use crate::document_loader::DocumentLoader;
57use crate::dom::ChildrenMutation;
58use crate::dom::attr::Attr;
59use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
60use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
61use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
62use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
63use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
64use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
65use crate::dom::bindings::codegen::Bindings::NodeBinding::{
66 GetRootNodeOptions, NodeConstants, NodeMethods,
67};
68use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
69use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
70use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
71 ShadowRootMode, SlotAssignmentMode,
72};
73use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
74use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
75use crate::dom::bindings::conversions::{self, DerivedFrom};
76use crate::dom::bindings::domname::namespace_from_domstring;
77use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
78use crate::dom::bindings::inheritance::{
79 Castable, CharacterDataTypeId, EventTargetTypeId, NodeTypeId,
80};
81use crate::dom::bindings::root::{
82 Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout, UnrootedDom,
83};
84use crate::dom::bindings::str::{DOMString, USVString};
85use crate::dom::characterdata::CharacterData;
86use crate::dom::context::{BindContext, IsShadowTree, MoveContext, UnbindContext};
87use crate::dom::css::cssstylesheet::CSSStyleSheet;
88use crate::dom::css::stylesheetlist::StyleSheetListOwner;
89use crate::dom::customelementregistry::{
90 CallbackReaction, CustomElementRegistry, try_upgrade_element,
91};
92use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
93use crate::dom::documentfragment::DocumentFragment;
94use crate::dom::documenttype::DocumentType;
95use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
96use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
97use crate::dom::eventtarget::EventTarget;
98use crate::dom::globalscope::GlobalScope;
99use crate::dom::html::htmlcollection::HTMLCollection;
100use crate::dom::html::htmlelement::HTMLElement;
101use crate::dom::html::htmllinkelement::HTMLLinkElement;
102use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
103use crate::dom::html::htmlstyleelement::HTMLStyleElement;
104use crate::dom::iterators::{
105 ShadowIncluding, UnrootedFollowingNodeIterator, UnrootedPrecedingNodeIterator,
106};
107use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
108use crate::dom::node::iterators::{
109 FollowingNodeIterator, PrecedingNodeIterator, SimpleNodeIterator, TreeIterator,
110 UnrootedSimpleNodeIterator, UnrootedTreeIterator,
111};
112use crate::dom::node::nodelist::NodeList;
113use crate::dom::node::virtualmethods::{VirtualMethods, vtable_for};
114use crate::dom::pointerevent::{PointerEvent, PointerId};
115use crate::dom::range::WeakRangeVec;
116use crate::dom::raredata::NodeRareData;
117use crate::dom::servoparser::html::HtmlSerialize;
118use crate::dom::servoparser::serialize_html_fragment;
119use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
120use crate::dom::text::Text;
121use crate::dom::types::{CDATASection, KeyboardEvent, ProcessingInstruction};
122use crate::dom::window::Window;
123use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode};
124use crate::script_runtime::CanGc;
125use crate::script_thread::ScriptThread;
126
127#[dom_struct]
133pub struct Node {
134 eventtarget: EventTarget,
136
137 parent_node: MutNullableDom<Node>,
139
140 first_child: MutNullableDom<Node>,
142
143 last_child: MutNullableDom<Node>,
145
146 next_sibling: MutNullableDom<Node>,
148
149 prev_sibling: MutNullableDom<Node>,
151
152 owner_doc: MutNullableDom<Document>,
154
155 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
157
158 children_count: Cell<u32>,
160
161 flags: Cell<NodeFlags>,
163
164 inclusive_descendants_version: Cell<u64>,
166
167 #[no_trace]
170 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
171}
172
173impl fmt::Debug for Node {
174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175 if let Some(element) = self.downcast::<Element>() {
176 element.fmt(f)
177 } else if let Some(character_data) = self.downcast::<CharacterData>() {
178 write!(f, "[Text({})]", character_data.data())
179 } else {
180 write!(f, "[Node({:?})]", self.type_id())
181 }
182 }
183}
184
185#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
187pub(crate) struct NodeFlags(u16);
188
189bitflags! {
190 impl NodeFlags: u16 {
191 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
195
196 const HAS_DIRTY_DESCENDANTS = 1 << 1;
198
199 const CLICK_IN_PROGRESS = 1 << 2;
202
203 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
208
209 const HAS_SNAPSHOT = 1 << 7;
214
215 const HANDLED_SNAPSHOT = 1 << 8;
217
218 const IS_IN_SHADOW_TREE = 1 << 9;
220
221 const IS_CONNECTED = 1 << 10;
225
226 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
229
230 const IS_IN_UA_WIDGET = 1 << 12;
233
234 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
236 }
237}
238
239#[derive(Clone, Copy, MallocSizeOf)]
243pub(crate) enum SuppressObserver {
244 Suppressed,
245 Unsuppressed,
246}
247
248pub(crate) enum ForceSlottableNodeReconciliation {
249 Force,
250 Skip,
251}
252
253impl Node {
254 pub(super) fn parent_node(&self) -> &MutNullableDom<Node> {
256 &self.parent_node
257 }
258
259 pub(super) fn first_child(&self) -> &MutNullableDom<Node> {
260 &self.first_child
261 }
262
263 pub(super) fn last_child(&self) -> &MutNullableDom<Node> {
264 &self.last_child
265 }
266
267 pub(super) fn next_sibling(&self) -> &MutNullableDom<Node> {
268 &self.next_sibling
269 }
270
271 pub(super) fn prev_sibling(&self) -> &MutNullableDom<Node> {
272 &self.prev_sibling
273 }
274
275 pub(super) fn get_owner_doc(&self) -> &MutNullableDom<Document> {
276 &self.owner_doc
277 }
278
279 pub(super) fn get_rare_data(&self) -> &DomRefCell<Option<Box<NodeRareData>>> {
280 &self.rare_data
281 }
282
283 pub(super) fn flags(&self) -> &Cell<NodeFlags> {
284 &self.flags
285 }
286
287 pub(super) fn layout_data(&self) -> &DomRefCell<Option<Box<GenericLayoutData>>> {
288 &self.layout_data
289 }
290
291 fn add_child(&self, cx: &mut JSContext, new_child: &Node, before: Option<&Node>) {
295 assert!(new_child.parent_node.get().is_none());
296 assert!(new_child.prev_sibling.get().is_none());
297 assert!(new_child.next_sibling.get().is_none());
298 match before {
299 Some(before) => {
300 assert!(before.parent_node.get().as_deref() == Some(self));
301 let prev_sibling = before.GetPreviousSibling();
302 match prev_sibling {
303 None => {
304 assert!(self.first_child.get().as_deref() == Some(before));
305 self.first_child.set(Some(new_child));
306 },
307 Some(ref prev_sibling) => {
308 prev_sibling.next_sibling.set(Some(new_child));
309 new_child.prev_sibling.set(Some(prev_sibling));
310 },
311 }
312 before.prev_sibling.set(Some(new_child));
313 new_child.next_sibling.set(Some(before));
314 },
315 None => {
316 let last_child = self.GetLastChild();
317 match last_child {
318 None => self.first_child.set(Some(new_child)),
319 Some(ref last_child) => {
320 assert!(last_child.next_sibling.get().is_none());
321 last_child.next_sibling.set(Some(new_child));
322 new_child.prev_sibling.set(Some(last_child));
323 },
324 }
325
326 self.last_child.set(Some(new_child));
327 },
328 }
329
330 new_child.parent_node.set(Some(self));
331 self.children_count.set(self.children_count.get() + 1);
332
333 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
334 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
335 let parent_is_connected = self.is_connected();
336 let parent_is_in_ua_widget = self.is_in_ua_widget();
337
338 let context = BindContext::new(self, IsShadowTree::No);
339
340 for node in new_child.traverse_preorder(ShadowIncluding::No) {
341 if parent_in_shadow_tree {
342 if let Some(shadow_root) = self.containing_shadow_root() {
343 node.set_containing_shadow_root(Some(&*shadow_root));
344 }
345 debug_assert!(node.containing_shadow_root().is_some());
346 }
347 node.set_flag(
348 NodeFlags::IS_IN_A_DOCUMENT_TREE,
349 parent_is_in_a_document_tree,
350 );
351 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
352 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
353 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
354
355 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
357 vtable_for(&node).bind_to_tree(cx, &context);
358 }
359 }
360
361 pub(crate) fn remove_style_and_layout_data_from_subtree(&self, no_gc: &NoGC) {
365 for node in self.traverse_preorder_non_rooting(no_gc, ShadowIncluding::Yes) {
366 node.clean_up_style_and_layout_data();
367 }
368 }
369
370 fn clean_up_style_and_layout_data(&self) {
371 self.layout_data.borrow_mut().take();
372 if let Some(element) = self.downcast::<Element>() {
373 element.clean_up_style_data();
374 }
375 }
376
377 pub(crate) fn complete_remove_subtree(
380 cx: &mut JSContext,
381 root: &Node,
382 context: &UnbindContext,
383 ) {
384 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
386 .union(NodeFlags::IS_CONNECTED)
387 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
388 .union(NodeFlags::HAS_SNAPSHOT)
389 .union(NodeFlags::HANDLED_SNAPSHOT);
390
391 for node in root.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No) {
392 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
393
394 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
397 for node in shadow_root
398 .upcast::<Node>()
399 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
400 {
401 node.set_flag(RESET_FLAGS, false);
402 }
403 }
404 }
405
406 let is_parent_connected = context.parent.is_connected();
408 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
409
410 let cleanup_node = |cx: &mut JSContext, node: &Node| {
413 node.owner_doc().cancel_animations_for_node(node);
414 node.clean_up_style_and_layout_data();
415
416 vtable_for(node).unbind_from_tree(cx, context);
421
422 if is_parent_connected && let Some(element) = node.as_custom_element() {
424 custom_element_reaction_stack.enqueue_callback_reaction(
425 cx,
426 &element,
427 CallbackReaction::Disconnected,
428 None,
429 );
430 }
431 };
432
433 for node in root.traverse_preorder(ShadowIncluding::No) {
434 cleanup_node(cx, &node);
435
436 if node.containing_shadow_root().is_some() {
439 node.set_containing_shadow_root(None);
442 }
443
444 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
447 for node in shadow_root
448 .upcast::<Node>()
449 .traverse_preorder(ShadowIncluding::Yes)
450 {
451 cleanup_node(cx, &node);
452 }
453 }
454 }
455 }
456
457 pub(crate) fn complete_move_subtree(cx: &mut JSContext, root: &Node) {
458 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
460 .union(NodeFlags::IS_CONNECTED)
461 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
462 .union(NodeFlags::HAS_SNAPSHOT)
463 .union(NodeFlags::HANDLED_SNAPSHOT);
464
465 for node in root.traverse_preorder(ShadowIncluding::No) {
466 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
467 node.clean_up_style_and_layout_data();
468
469 if let Some(element) = node.downcast::<Element>() {
472 element.unregister_current_id_and_name_attribute(cx);
473 }
474
475 if node.containing_shadow_root().is_some() {
478 node.set_containing_shadow_root(None);
481 }
482
483 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
487 for node in shadow_root
488 .upcast::<Node>()
489 .traverse_preorder(ShadowIncluding::Yes)
490 {
491 node.set_flag(RESET_FLAGS, false);
492 node.clean_up_style_and_layout_data();
493 }
494 }
495 }
496 }
497
498 fn remove_child(&self, cx: &mut JSContext, child: &Node, cached_index: Option<u32>) {
502 assert!(child.parent_node.get().as_deref() == Some(self));
503 self.note_dirty_descendants();
504
505 let prev_sibling = child.GetPreviousSibling();
506 match prev_sibling {
507 None => {
508 self.first_child.set(child.next_sibling.get().as_deref());
509 },
510 Some(ref prev_sibling) => {
511 prev_sibling
512 .next_sibling
513 .set(child.next_sibling.get().as_deref());
514 },
515 }
516 let next_sibling = child.GetNextSibling();
517 match next_sibling {
518 None => {
519 self.last_child.set(child.prev_sibling.get().as_deref());
520 },
521 Some(ref next_sibling) => {
522 next_sibling
523 .prev_sibling
524 .set(child.prev_sibling.get().as_deref());
525 },
526 }
527
528 let context = UnbindContext::new(
529 self,
530 prev_sibling.as_deref(),
531 next_sibling.as_deref(),
532 cached_index,
533 );
534
535 child.prev_sibling.set(None);
536 child.next_sibling.set(None);
537 child.parent_node.set(None);
538 self.children_count.set(self.children_count.get() - 1);
539
540 Self::complete_remove_subtree(cx, child, &context);
541 }
542
543 fn move_child(&self, cx: &mut JSContext, child: &Node) {
544 assert!(child.parent_node.get().as_deref() == Some(self));
545 self.note_dirty_descendants();
546
547 child.prev_sibling.set(None);
548 child.next_sibling.set(None);
549 child.parent_node.set(None);
550 self.children_count.set(self.children_count.get() - 1);
551 Self::complete_move_subtree(cx, child)
552 }
553
554 pub(crate) fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
555 UntrustedNodeAddress(self.reflector().get_jsobject().get() as *const c_void)
556 }
557
558 pub(crate) fn to_opaque(&self) -> OpaqueNode {
559 OpaqueNode(self.reflector().get_jsobject().get() as usize)
560 }
561
562 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
563 self.downcast::<Element>().and_then(|element| {
564 if element.is_custom() {
565 assert!(element.get_custom_element_definition().is_some());
566 Some(DomRoot::from_ref(element))
567 } else {
568 None
569 }
570 })
571 }
572
573 pub(crate) fn fire_synthetic_pointer_event_not_trusted(
575 &self,
576 cx: &mut JSContext,
577 event_type: Atom,
578 ) {
579 let window = self.owner_window();
583
584 let pointer_event = PointerEvent::new(
586 cx,
587 &window, event_type,
589 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![], );
616
617 pointer_event.upcast::<Event>().set_composed(true);
619
620 pointer_event.upcast::<Event>().set_trusted(false);
622
623 pointer_event
626 .upcast::<Event>()
627 .dispatch(cx, self.upcast::<EventTarget>(), false);
628 }
629
630 pub(crate) fn parent_directionality(&self) -> String {
631 let mut current = self.GetParentNode();
632
633 loop {
634 match current {
635 Some(node) => {
636 if let Some(directionality) = node
637 .downcast::<HTMLElement>()
638 .and_then(|html_element| html_element.directionality())
639 {
640 return directionality;
641 } else {
642 current = node.GetParentNode();
643 }
644 },
645 None => return "ltr".to_owned(),
646 }
647 }
648 }
649
650 pub(crate) fn is_being_rendered_or_delegates_rendering(
654 &self,
655 pseudo_element: Option<PseudoElement>,
656 ) -> bool {
657 matches!(
658 self.owner_window()
659 .layout()
660 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
661 NodeRenderingType::Rendered | NodeRenderingType::DelegatesRendering
662 )
663 }
664
665 pub(crate) fn is_being_rendered(&self, pseudo_element: Option<PseudoElement>) -> bool {
667 matches!(
668 self.owner_window()
669 .layout()
670 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
671 NodeRenderingType::Rendered
672 )
673 }
674
675 pub(super) fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
676 let mut rare_data = self.rare_data.borrow_mut();
677 if rare_data.is_none() {
678 *rare_data = Some(Default::default());
679 }
680 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
681 }
682
683 pub(crate) fn is_before(&self, other: &Node) -> bool {
686 let cmp = other.CompareDocumentPosition(self);
687 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
688 return false;
689 }
690
691 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
692 }
693
694 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
697 RefMut::map(self.ensure_rare_data(), |rare_data| {
698 &mut rare_data.mutation_observers
699 })
700 }
701
702 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
703 let rare_data: Ref<'_, _> = self.rare_data.borrow();
704
705 if rare_data.is_none() {
706 return None;
707 }
708 Some(Ref::map(rare_data, |rare_data| {
709 &rare_data.as_ref().unwrap().mutation_observers
710 }))
711 }
712
713 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
715 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
716 self.ensure_rare_data().mutation_observers.push(observer);
717 }
718
719 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
721 self.ensure_rare_data()
722 .mutation_observers
723 .retain(|reg_obs| &*reg_obs.observer != observer)
724 }
725
726 pub(crate) fn dump(&self) {
728 self.dump_indent(0);
729 }
730
731 pub(crate) fn dump_indent(&self, indent: u32) {
733 let mut s = String::new();
734 for _ in 0..indent {
735 s.push_str(" ");
736 }
737
738 s.push_str(&self.debug_str());
739 debug!("{:?}", s);
740
741 for kid in self.children() {
743 kid.dump_indent(indent + 1)
744 }
745 }
746
747 pub(crate) fn debug_str(&self) -> String {
749 format!("{:?}", self.type_id())
750 }
751
752 pub(crate) fn is_in_a_document_tree(&self) -> bool {
754 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
755 }
756
757 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
759 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
760 }
761
762 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
763 self.flags
764 .get()
765 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
766 }
767
768 pub(crate) fn set_weird_parser_insertion_mode(&self) {
769 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
770 }
771
772 pub(crate) fn is_connected(&self) -> bool {
774 self.flags.get().contains(NodeFlags::IS_CONNECTED)
775 }
776
777 pub(crate) fn set_in_ua_widget(&self, in_ua_widget: bool) {
778 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, in_ua_widget)
779 }
780
781 pub(crate) fn is_in_ua_widget(&self) -> bool {
782 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
783 }
784
785 pub(crate) fn type_id(&self) -> NodeTypeId {
787 match *self.eventtarget.type_id() {
788 EventTargetTypeId::Node(type_id) => type_id,
789 _ => unreachable!(),
790 }
791 }
792
793 pub(crate) fn len(&self) -> u32 {
795 match self.type_id() {
796 NodeTypeId::DocumentType => 0,
797 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
798 _ => self.children_count(),
799 }
800 }
801
802 pub(crate) fn is_empty(&self) -> bool {
803 self.len() == 0
805 }
806
807 pub(crate) fn index(&self) -> u32 {
809 self.preceding_siblings().count() as u32
810 }
811
812 pub(crate) fn has_parent(&self) -> bool {
814 self.parent_node.get().is_some()
815 }
816
817 pub(crate) fn children_count(&self) -> u32 {
818 self.children_count.get()
819 }
820
821 pub(crate) fn ranges(&self) -> RefMut<'_, WeakRangeVec> {
822 RefMut::map(self.ensure_rare_data(), |rare_data| &mut rare_data.ranges)
823 }
824
825 pub(crate) fn ranges_is_empty(&self) -> bool {
826 self.rare_data
827 .borrow()
828 .as_ref()
829 .is_none_or(|data| data.ranges.is_empty())
830 }
831
832 #[inline]
833 pub(crate) fn is_doctype(&self) -> bool {
834 self.type_id() == NodeTypeId::DocumentType
835 }
836
837 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
838 self.flags.get().contains(flag)
839 }
840
841 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
842 let mut flags = self.flags.get();
843
844 if value {
845 flags.insert(flag);
846 } else {
847 flags.remove(flag);
848 }
849
850 self.flags.set(flags);
851 }
852
853 pub(crate) fn note_dirty_descendants(&self) {
855 self.owner_doc().note_node_with_dirty_descendants(self);
856 }
857
858 pub(crate) fn has_dirty_descendants(&self) -> bool {
859 self.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)
860 }
861
862 pub(crate) fn rev_version(&self) {
863 let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
868 let version = cmp::max(
869 self.inclusive_descendants_version(),
870 doc.inclusive_descendants_version(),
871 ) + 1;
872
873 let mut node = &MutNullableDom::new(Some(self));
876 while let Some(p) = node.if_is_some(|p| {
877 p.inclusive_descendants_version.set(version);
878 &p.parent_node
879 }) {
880 node = p
881 }
882 doc.inclusive_descendants_version.set(version);
883 }
884
885 pub(crate) fn dirty(&self, damage: NodeDamage) {
886 self.rev_version();
887 if !self.is_connected() {
888 return;
889 }
890
891 match self.type_id() {
892 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..)) => {
893 *self.layout_data.borrow_mut() = None;
896
897 self.parent_node
901 .get()
902 .unwrap()
903 .dirty(NodeDamage::ContentOrHeritage)
904 },
905 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(damage),
906 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
907 .downcast::<ShadowRoot>()
908 .unwrap()
909 .Host()
910 .upcast::<Element>()
911 .restyle(damage),
912 _ => {},
913 };
914 }
915
916 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
918 self.inclusive_descendants_version.get()
919 }
920
921 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
923 TreeIterator::new(self, shadow_including)
924 }
925
926 pub(crate) fn traverse_preorder_non_rooting<'a, 'b>(
928 &'a self,
929 no_gc: &'b NoGC,
930 shadow_including: ShadowIncluding,
931 ) -> UnrootedTreeIterator<'a, 'b>
932 where
933 'b: 'a,
934 {
935 UnrootedTreeIterator::new(self, shadow_including, no_gc)
936 }
937
938 pub(crate) fn inclusively_following_siblings(
939 &self,
940 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
941 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), |n| n.GetNextSibling())
942 }
943
944 pub(crate) fn inclusively_following_siblings_unrooted<'b>(
945 &self,
946 no_gc: &'b NoGC,
947 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
948 UnrootedSimpleNodeIterator::new(
949 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
950 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
951 no_gc,
952 )
953 }
954
955 pub(crate) fn inclusively_preceding_siblings(
956 &self,
957 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
958 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), |n| n.GetPreviousSibling())
959 }
960
961 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
962 &self,
963 no_gc: &'b NoGC,
964 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
965 UnrootedSimpleNodeIterator::new(
966 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
967 |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
968 no_gc,
969 )
970 }
971
972 pub(crate) fn common_ancestor(
973 &self,
974 other: &Node,
975 shadow_including: ShadowIncluding,
976 ) -> Option<DomRoot<Node>> {
977 self.inclusive_ancestors(shadow_including).find(|ancestor| {
978 other
979 .inclusive_ancestors(shadow_including)
980 .any(|node| node == *ancestor)
981 })
982 }
983
984 pub(crate) fn common_ancestor_in_flat_tree(&self, other: &Node) -> Option<DomRoot<Node>> {
985 self.inclusive_ancestors_in_flat_tree().find(|ancestor| {
986 other
987 .inclusive_ancestors_in_flat_tree()
988 .any(|node| node == *ancestor)
989 })
990 }
991
992 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
994 self == child || self.is_ancestor_of(child)
996 }
997
998 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
1000 let mut current = &possible_descendant.parent_node;
1002 let mut done = false;
1003
1004 while let Some(node) = current.if_is_some(|node| {
1005 done = node == self;
1006 &node.parent_node
1007 }) {
1008 if done {
1009 break;
1010 }
1011 current = node
1012 }
1013 done
1014 }
1015
1016 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
1018 self.is_inclusive_ancestor_of(child) ||
1021 child
1022 .GetRootNode(&GetRootNodeOptions::empty())
1023 .downcast::<DocumentFragment>()
1024 .and_then(|fragment| fragment.host())
1025 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1026 }
1027
1028 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1030 node.inclusive_ancestors(ShadowIncluding::Yes)
1031 .any(|ancestor| &*ancestor == self)
1032 }
1033
1034 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1035 SimpleNodeIterator::new(self.GetNextSibling(), |n| n.GetNextSibling())
1036 }
1037
1038 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1039 SimpleNodeIterator::new(self.GetPreviousSibling(), |n| n.GetPreviousSibling())
1040 }
1041
1042 pub(crate) fn following_nodes(
1043 &self,
1044 root: &Node,
1045 shadow_including: ShadowIncluding,
1046 ) -> FollowingNodeIterator {
1047 FollowingNodeIterator::new(
1048 Some(DomRoot::from_ref(self)),
1049 DomRoot::from_ref(root),
1050 shadow_including,
1051 )
1052 }
1053
1054 pub(crate) fn following_nodes_unrooted<'a, 'b>(
1055 &'a self,
1056 no_gc: &'b NoGC,
1057 root: &Node,
1058 shadow_including: ShadowIncluding,
1059 ) -> UnrootedFollowingNodeIterator<'a, 'b>
1060 where
1061 'b: 'a,
1062 {
1063 UnrootedFollowingNodeIterator::new(
1064 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1065 UnrootedDom::from_dom(Dom::from_ref(root), no_gc),
1066 shadow_including,
1067 no_gc,
1068 )
1069 }
1070
1071 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1072 PrecedingNodeIterator::new(Some(DomRoot::from_ref(self)), DomRoot::from_ref(root))
1073 }
1074
1075 pub(crate) fn preceding_nodes_unrooted<'a, 'b>(
1076 &self,
1077 no_gc: &'b NoGC,
1078 root: &'a Node,
1079 ) -> UnrootedPrecedingNodeIterator<'a, 'b>
1080 where
1081 'b: 'a,
1082 {
1083 UnrootedPrecedingNodeIterator::new(
1084 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1085 UnrootedDom::from_dom(Dom::from_ref(root), no_gc),
1086 no_gc,
1087 )
1088 }
1089
1090 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1093 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetLastChild())
1094 }
1095
1096 pub(crate) fn descending_last_children_unrooted<'b>(
1097 &self,
1098 no_gc: &'b NoGC,
1099 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> {
1100 UnrootedSimpleNodeIterator::new(
1101 self.get_last_child_unrooted(no_gc),
1102 |n, no_gc| n.get_last_child_unrooted(no_gc),
1103 no_gc,
1104 )
1105 }
1106
1107 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1108 child
1109 .parent_node
1110 .get()
1111 .is_some_and(|parent| &*parent == self)
1112 }
1113
1114 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1115 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1116 }
1117
1118 pub(crate) fn containing_block_node_without_reflow(&self) -> Option<DomRoot<Node>> {
1120 self.owner_window()
1121 .containing_block_node_query_without_reflow(self)
1122 }
1123
1124 pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1125 self.owner_window().padding_query_without_reflow(self)
1126 }
1127
1128 pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1129 self.owner_window()
1130 .box_area_query(self, BoxAreaType::Content, false)
1131 }
1132
1133 pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1134 self.owner_window()
1135 .box_area_query(self, BoxAreaType::Border, false)
1136 }
1137
1138 pub(crate) fn border_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1139 self.owner_window()
1140 .box_area_query_without_reflow(self, BoxAreaType::Border, false)
1141 }
1142
1143 pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1144 self.owner_window()
1145 .box_area_query(self, BoxAreaType::Padding, false)
1146 }
1147
1148 pub(crate) fn padding_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1149 self.owner_window()
1150 .box_area_query_without_reflow(self, BoxAreaType::Padding, false)
1151 }
1152
1153 pub(crate) fn border_boxes(&self) -> CSSPixelRectVec {
1154 self.owner_window()
1155 .box_areas_query(self, BoxAreaType::Border)
1156 }
1157
1158 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1159 self.owner_window().client_rect_query(self)
1160 }
1161
1162 pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1165 let document = self.owner_doc();
1167
1168 if !document.is_active() {
1170 return Rect::zero();
1171 }
1172
1173 let window = document.window();
1176 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1177
1178 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1179 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1180 let is_body_element = self
1181 .downcast::<HTMLElement>()
1182 .is_some_and(|e| e.is_body_element());
1183
1184 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1190 let viewport_scrolling_area = window.scrolling_area_query(None);
1191 return Rect::new(
1192 viewport_scrolling_area.origin,
1193 viewport_scrolling_area.size.max(viewport),
1194 );
1195 }
1196
1197 window.scrolling_area_query(Some(self))
1201 }
1202
1203 pub(crate) fn effective_overflow(&self) -> Option<AxesOverflow> {
1204 self.owner_window().query_effective_overflow(self)
1205 }
1206
1207 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1208 self.owner_window()
1209 .query_effective_overflow_without_reflow(self)
1210 }
1211
1212 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1214 let parent = &self.parent_node;
1216
1217 let parent = match parent.get() {
1219 None => return Ok(()),
1220 Some(parent) => parent,
1221 };
1222
1223 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1225
1226 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1228
1229 let viable_previous_sibling = match viable_previous_sibling {
1231 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1232 None => parent.first_child.get(),
1233 };
1234
1235 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1237
1238 Ok(())
1239 }
1240
1241 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1243 let parent = &self.parent_node;
1245
1246 let parent = match parent.get() {
1248 None => return Ok(()),
1249 Some(parent) => parent,
1250 };
1251
1252 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1254
1255 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1257
1258 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1260
1261 Ok(())
1262 }
1263
1264 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1266 let Some(parent) = self.GetParentNode() else {
1268 return Ok(());
1270 };
1271
1272 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1274
1275 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1277
1278 if self.parent_node == Some(&*parent) {
1279 parent.ReplaceChild(cx, &node, self)?;
1281 } else {
1282 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1284 }
1285 Ok(())
1286 }
1287
1288 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1290 let doc = self.owner_doc();
1292 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1293 let first_child = self.first_child.get();
1295 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1296 }
1297
1298 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1300 let doc = self.owner_doc();
1302 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1303 self.AppendChild(cx, &node).map(|_| ())
1305 }
1306
1307 pub(crate) fn replace_children(
1309 &self,
1310 cx: &mut JSContext,
1311 nodes: Vec<NodeOrString>,
1312 ) -> ErrorResult {
1313 let doc = self.owner_doc();
1316 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1317
1318 Node::ensure_pre_insertion_validity(cx.no_gc(), &node, self, None)?;
1320
1321 Node::replace_all(cx, Some(&node), self);
1323 Ok(())
1324 }
1325
1326 pub(crate) fn move_before(
1328 &self,
1329 cx: &mut JSContext,
1330 node: &Node,
1331 child: Option<&Node>,
1332 ) -> ErrorResult {
1333 let reference_child_root;
1336 let reference_child = match child {
1337 Some(child) if child == node => {
1338 reference_child_root = node.GetNextSibling();
1339 reference_child_root.as_deref()
1340 },
1341 _ => child,
1342 };
1343
1344 Node::move_fn(cx, node, self, reference_child)
1346 }
1347
1348 fn move_fn(
1350 cx: &mut JSContext,
1351 node: &Node,
1352 new_parent: &Node,
1353 child: Option<&Node>,
1354 ) -> ErrorResult {
1355 let mut options = GetRootNodeOptions::empty();
1360 options.composed = true;
1361 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1362 return Err(Error::HierarchyRequest(None));
1363 }
1364
1365 if node.is_inclusive_ancestor_of(new_parent) {
1368 return Err(Error::HierarchyRequest(None));
1369 }
1370
1371 if let Some(child) = child &&
1374 !new_parent.is_parent_of(child)
1375 {
1376 return Err(Error::NotFound(None));
1377 }
1378
1379 match node.type_id() {
1384 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1385 if new_parent.is::<Document>() {
1386 return Err(Error::HierarchyRequest(None));
1387 }
1388 },
1389 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1390 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1391 NodeTypeId::Element(_) => (),
1392 NodeTypeId::DocumentFragment(_) |
1393 NodeTypeId::DocumentType |
1394 NodeTypeId::Document(_) |
1395 NodeTypeId::Attr => {
1396 return Err(Error::HierarchyRequest(None));
1397 },
1398 }
1399
1400 if new_parent.is::<Document>() && node.is::<Element>() {
1404 if new_parent.child_elements().next().is_some() {
1406 return Err(Error::HierarchyRequest(None));
1407 }
1408
1409 if child.is_some_and(|child| {
1412 child
1413 .inclusively_following_siblings_unrooted(cx.no_gc())
1414 .any(|child| child.is_doctype())
1415 }) {
1416 return Err(Error::HierarchyRequest(None));
1417 }
1418 }
1419
1420 let old_parent = node
1423 .parent_node
1424 .get()
1425 .expect("old_parent should always be initialized");
1426
1427 let cached_index = Node::live_range_pre_remove_steps(node, &old_parent);
1429
1430 let old_previous_sibling = node.prev_sibling.get();
1435
1436 let old_next_sibling = node.next_sibling.get();
1438
1439 let prev_sibling = node.GetPreviousSibling();
1440 match prev_sibling {
1441 None => {
1442 old_parent
1443 .first_child
1444 .set(node.next_sibling.get().as_deref());
1445 },
1446 Some(ref prev_sibling) => {
1447 prev_sibling
1448 .next_sibling
1449 .set(node.next_sibling.get().as_deref());
1450 },
1451 }
1452 let next_sibling = node.GetNextSibling();
1453 match next_sibling {
1454 None => {
1455 old_parent
1456 .last_child
1457 .set(node.prev_sibling.get().as_deref());
1458 },
1459 Some(ref next_sibling) => {
1460 next_sibling
1461 .prev_sibling
1462 .set(node.prev_sibling.get().as_deref());
1463 },
1464 }
1465
1466 let mut context = MoveContext::new(
1467 Some(&old_parent),
1468 prev_sibling.as_deref(),
1469 next_sibling.as_deref(),
1470 cached_index,
1471 );
1472
1473 old_parent.move_child(cx, node);
1475
1476 if let Some(slot) = node.assigned_slot() {
1478 slot.assign_slottables(cx);
1479 }
1480
1481 if old_parent.is_in_a_shadow_tree() &&
1484 let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() &&
1485 !slot_element.has_assigned_nodes()
1486 {
1487 slot_element.signal_a_slot_change();
1488 }
1489
1490 let has_slot_descendant = node
1492 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
1493 .any(|element| element.is::<HTMLSlotElement>());
1494 if has_slot_descendant {
1495 old_parent
1497 .GetRootNode(&GetRootNodeOptions::empty())
1498 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1499
1500 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1502 }
1503
1504 if let Some(child) = child {
1506 new_parent
1511 .ranges()
1512 .increase_above(new_parent, child.index(), 1)
1513 }
1514
1515 let new_previous_sibling = child.map_or_else(
1518 || new_parent.last_child.get(),
1519 |child| child.prev_sibling.get(),
1520 );
1521
1522 new_parent.add_child(cx, node, child);
1525
1526 if let Some(shadow_root) = new_parent
1529 .downcast::<Element>()
1530 .and_then(Element::shadow_root) &&
1531 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1532 (node.is::<Element>() || node.is::<Text>())
1533 {
1534 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1535 slottable.assign_a_slot(cx);
1536 }
1537
1538 if new_parent.is_in_a_shadow_tree() &&
1541 let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() &&
1542 !slot_element.has_assigned_nodes()
1543 {
1544 slot_element.signal_a_slot_change();
1545 }
1546
1547 node.GetRootNode(&GetRootNodeOptions::empty())
1549 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1550
1551 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1554 if descendant.deref() == node {
1558 vtable_for(&descendant).moving_steps(cx, &context);
1559 } else {
1560 context.old_parent = None;
1561 vtable_for(&descendant).moving_steps(cx, &context);
1562 }
1563
1564 if let Some(descendant) = descendant.downcast::<Element>() &&
1566 descendant.is_custom() &&
1567 new_parent.is_connected()
1568 {
1569 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
1572 custom_element_reaction_stack.enqueue_callback_reaction(
1573 cx,
1574 descendant,
1575 CallbackReaction::ConnectedMove,
1576 None,
1577 );
1578 }
1579 }
1580
1581 let moved = [node];
1584 let mutation = LazyCell::new(|| Mutation::ChildList {
1585 added: None,
1586 removed: Some(&moved),
1587 prev: old_previous_sibling.as_deref(),
1588 next: old_next_sibling.as_deref(),
1589 });
1590 MutationObserver::queue_a_mutation_record(&old_parent, mutation);
1591
1592 let mutation = LazyCell::new(|| Mutation::ChildList {
1595 added: Some(&moved),
1596 removed: None,
1597 prev: new_previous_sibling.as_deref(),
1598 next: child,
1599 });
1600 MutationObserver::queue_a_mutation_record(new_parent, mutation);
1601
1602 Ok(())
1603 }
1604
1605 #[allow(unsafe_code)]
1607 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1608 pub(crate) fn query_selector(
1609 &self,
1610 no_gc: &NoGC,
1611 selectors: DOMString,
1612 ) -> Fallible<Option<DomRoot<Element>>> {
1613 let document_url = self.owner_document().url().get_arc();
1616
1617 self.owner_document()
1620 .id_map()
1621 .resolve_all(no_gc, self.owner_doc().upcast());
1622
1623 let traced_node = Dom::from_ref(self);
1625
1626 let first_matching_element = with_layout_state(|| {
1627 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1628 ServoDangerousStyleNode::from(layout_node)
1629 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1630 })?;
1631
1632 Ok(first_matching_element.map(ServoDangerousStyleElement::rooted))
1633 }
1634
1635 #[allow(unsafe_code)]
1637 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1638 pub(crate) fn query_selector_all(
1639 &self,
1640 no_gc: &NoGC,
1641 selectors: DOMString,
1642 ) -> Fallible<DomRoot<NodeList>> {
1643 let document_url = self.owner_document().url().get_arc();
1646
1647 self.owner_document()
1650 .id_map()
1651 .resolve_all(no_gc, self.owner_doc().upcast());
1652
1653 let traced_node = Dom::from_ref(self);
1655 let matching_elements = with_layout_state(|| {
1656 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1657 ServoDangerousStyleNode::from(layout_node)
1658 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1659 })?;
1660 let iter = matching_elements
1661 .into_iter()
1662 .map(ServoDangerousStyleElement::rooted)
1663 .map(DomRoot::upcast::<Node>);
1664
1665 Ok(NodeList::new_simple_list(
1668 &self.owner_window(),
1669 iter,
1670 CanGc::deprecated_note(),
1671 ))
1672 }
1673
1674 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1675 SimpleNodeIterator::new(self.GetParentNode(), |n| n.GetParentNode())
1676 }
1677
1678 pub(crate) fn inclusive_ancestors(
1680 &self,
1681 shadow_including: ShadowIncluding,
1682 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1683 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |n| {
1684 if shadow_including == ShadowIncluding::Yes &&
1685 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1686 {
1687 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1688 }
1689 n.GetParentNode()
1690 })
1691 }
1692
1693 pub(crate) fn inclusive_ancestors_unrooted<'a>(
1694 &self,
1695 no_gc: &'a NoGC,
1696 shadow_including: ShadowIncluding,
1697 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1698 UnrootedSimpleNodeIterator::new(
1699 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1700 move |n, no_gc| {
1701 if shadow_including == ShadowIncluding::Yes &&
1702 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1703 {
1704 return Some(UnrootedDom::from_dom(
1705 Dom::from_ref(shadow_root.Host().upcast::<Node>()),
1706 no_gc,
1707 ));
1708 }
1709 n.get_parent_node_unrooted(no_gc)
1710 },
1711 no_gc,
1712 )
1713 }
1714
1715 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1716 self.owner_doc.get().unwrap()
1717 }
1718
1719 pub(crate) fn set_owner_doc(&self, document: &Document) {
1720 self.owner_doc.set(Some(document));
1721 }
1722
1723 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1724 self.rare_data
1725 .borrow()
1726 .as_ref()?
1727 .containing_shadow_root
1728 .as_ref()
1729 .map(|sr| DomRoot::from_ref(&**sr))
1730 }
1731
1732 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1733 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1734 }
1735
1736 pub(crate) fn is_in_html_doc(&self) -> bool {
1737 self.owner_doc().is_html_document()
1738 }
1739
1740 pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1741 self.is_connected() && self.owner_doc().browsing_context().is_some()
1742 }
1743
1744 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1745 SimpleNodeIterator::new(self.GetFirstChild(), |n| n.GetNextSibling())
1746 }
1747
1748 pub(crate) fn children_unrooted<'a>(
1749 &self,
1750 no_gc: &'a NoGC,
1751 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1752 UnrootedSimpleNodeIterator::new(
1753 self.get_first_child_unrooted(no_gc),
1754 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1755 no_gc,
1756 )
1757 }
1758
1759 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1760 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetPreviousSibling())
1761 }
1762
1763 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1765 self.children()
1766 .filter_map(DomRoot::downcast as fn(_) -> _)
1767 .peekable()
1768 }
1769
1770 pub(crate) fn child_elements_unrooted<'a>(
1771 &self,
1772 no_gc: &'a NoGC,
1773 ) -> impl Iterator<Item = UnrootedDom<'a, Element>> + use<'a> {
1774 self.children_unrooted(no_gc)
1775 .filter_map(UnrootedDom::downcast)
1776 .peekable()
1777 }
1778
1779 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1780 if let Some(ref parent) = self.GetParentNode() {
1781 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1782 }
1783 }
1784
1785 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1787 Ref::filter_map(self.rare_data.borrow(), |rare_data| {
1788 rare_data
1789 .as_ref()
1790 .and_then(|rare_data| rare_data.unique_id.as_ref())
1791 })
1792 .ok()
1793 .map(|unique_id| unique_id.borrow().simple().to_string())
1794 }
1795
1796 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1797 let mut rare_data = self.ensure_rare_data();
1798
1799 if rare_data.unique_id.is_none() {
1800 let node_id = UniqueId::new();
1801 ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string());
1802 rare_data.unique_id = Some(node_id);
1803 }
1804 rare_data
1805 .unique_id
1806 .as_ref()
1807 .unwrap()
1808 .borrow()
1809 .simple()
1810 .to_string()
1811 }
1812
1813 pub(crate) fn summarize(&self, cx: &mut JSContext) -> NodeInfo {
1814 let USVString(base_uri) = self.BaseURI();
1815 let node_type = self.NodeType();
1816 let pipeline = self.owner_window().pipeline_id();
1817
1818 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1819 let shadow_root_mode = maybe_shadow_root
1820 .map(ShadowRoot::Mode)
1821 .map(ShadowRootMode::convert);
1822 let host = maybe_shadow_root
1823 .map(ShadowRoot::Host)
1824 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1825 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1826 let Some(root) = potential_host.shadow_root() else {
1827 return false;
1828 };
1829 !root.is_user_agent_widget() || pref!(inspector_show_servo_internal_shadow_roots)
1830 });
1831
1832 let num_children = if is_shadow_host {
1833 self.ChildNodes(cx).Length() as usize + 1
1835 } else {
1836 self.ChildNodes(cx).Length() as usize
1837 };
1838
1839 let window = self.owner_window();
1840 let element = self.downcast::<Element>();
1841 let display = element
1842 .map(|elem| window.GetComputedStyle(cx, elem, None))
1843 .map(|style| style.Display().into());
1844
1845 let is_displayed =
1851 element.is_none_or(|element| !element.is_display_none()) || self.is::<DocumentType>();
1852 let attrs = element.map(Element::summarize).unwrap_or_default();
1853
1854 NodeInfo {
1855 unique_id: self.unique_id(pipeline),
1856 host,
1857 base_uri,
1858 parent: self
1859 .GetParentNode()
1860 .map_or("".to_owned(), |node| node.unique_id(pipeline)),
1861 node_type,
1862 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1863 node_name: String::from(self.NodeName()),
1864 node_value: self.GetNodeValue().map(|v| v.into()),
1865 num_children,
1866 attrs,
1867 is_shadow_host,
1868 shadow_root_mode,
1869 display,
1870 is_displayed,
1871 doctype_name: self
1872 .downcast::<DocumentType>()
1873 .map(DocumentType::name)
1874 .cloned()
1875 .map(String::from),
1876 doctype_public_identifier: self
1877 .downcast::<DocumentType>()
1878 .map(DocumentType::public_id)
1879 .cloned()
1880 .map(String::from),
1881 doctype_system_identifier: self
1882 .downcast::<DocumentType>()
1883 .map(DocumentType::system_id)
1884 .cloned()
1885 .map(String::from),
1886 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1887 }
1888 }
1889
1890 pub(crate) fn insert_cell_or_row<F, G, I>(
1892 &self,
1893 cx: &mut JSContext,
1894 index: i32,
1895 get_items: F,
1896 new_child: G,
1897 ) -> Fallible<DomRoot<HTMLElement>>
1898 where
1899 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1900 G: Fn(&mut JSContext) -> DomRoot<I>,
1901 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1902 {
1903 if index < -1 {
1904 return Err(Error::IndexSize(None));
1905 }
1906
1907 let tr = new_child(cx);
1908
1909 {
1910 let tr_node = tr.upcast::<Node>();
1911 if index == -1 {
1912 self.InsertBefore(cx, tr_node, None)?;
1913 } else {
1914 let items = get_items(cx);
1915 let node = match items
1916 .elements_iter(cx.no_gc())
1917 .map(UnrootedDom::upcast::<Node>)
1918 .map(Some)
1919 .chain(iter::once(None))
1920 .nth(index as usize)
1921 {
1922 None => return Err(Error::IndexSize(None)),
1923 Some(node) => node,
1924 };
1925 self.InsertBefore(cx, tr_node, node.map(|node| node.as_rooted()).as_deref())?;
1926 }
1927 }
1928
1929 Ok(DomRoot::upcast::<HTMLElement>(tr))
1930 }
1931
1932 pub(crate) fn delete_cell_or_row<F, G>(
1934 &self,
1935 cx: &mut JSContext,
1936 index: i32,
1937 get_items: F,
1938 is_delete_type: G,
1939 ) -> ErrorResult
1940 where
1941 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1942 G: Fn(&Element) -> bool,
1943 {
1944 let element = match index {
1945 index if index < -1 => return Err(Error::IndexSize(None)),
1946 -1 => {
1947 let last_child = self.upcast::<Node>().GetLastChild();
1948 match last_child.and_then(|node| {
1949 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
1950 .filter_map(UnrootedDom::downcast::<Element>)
1951 .find(|elem| is_delete_type(elem))
1952 .map(|elem| elem.as_rooted())
1953 }) {
1954 Some(element) => element,
1955 None => return Ok(()),
1956 }
1957 },
1958 index => match get_items(cx).Item(cx, index as u32) {
1959 Some(element) => element,
1960 None => return Err(Error::IndexSize(None)),
1961 },
1962 };
1963
1964 element.upcast::<Node>().remove_self(cx);
1965 Ok(())
1966 }
1967
1968 pub(crate) fn get_stylesheet(&self) -> Option<ServoArc<Stylesheet>> {
1969 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1970 node.get_stylesheet()
1971 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1972 node.get_stylesheet()
1973 } else {
1974 None
1975 }
1976 }
1977
1978 pub(crate) fn get_cssom_stylesheet(&self) -> Option<DomRoot<CSSStyleSheet>> {
1979 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1980 node.get_cssom_stylesheet()
1981 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1982 node.get_cssom_stylesheet(CanGc::deprecated_note())
1983 } else {
1984 None
1985 }
1986 }
1987
1988 pub(crate) fn get_lang(&self) -> Option<String> {
1990 self.inclusive_ancestors(ShadowIncluding::Yes)
1991 .find_map(|node| {
1992 node.downcast::<Element>().and_then(|el| {
1993 el.get_attribute_string_value_with_namespace(&ns!(xml), &local_name!("lang"))
1994 .or_else(|| el.get_attribute_string_value(&local_name!("lang")))
1995 })
1996 })
1999 }
2000
2001 pub(crate) fn assign_slottables_for_a_tree(
2003 &self,
2004 cx: &JSContext,
2005 force: ForceSlottableNodeReconciliation,
2006 ) {
2007 let is_shadow_root_with_slots = self
2014 .downcast::<ShadowRoot>()
2015 .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
2016 if !is_shadow_root_with_slots &&
2017 !self.is::<HTMLSlotElement>() &&
2018 matches!(force, ForceSlottableNodeReconciliation::Skip)
2019 {
2020 return;
2021 }
2022
2023 for node in self.traverse_preorder_non_rooting(cx, ShadowIncluding::No) {
2026 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
2027 slot.assign_slottables(cx);
2028 }
2029 }
2030 }
2031
2032 pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
2033 let assigned_slot = self
2034 .rare_data
2035 .borrow()
2036 .as_ref()?
2037 .slottable_data
2038 .assigned_slot
2039 .as_ref()?
2040 .as_rooted();
2041 Some(assigned_slot)
2042 }
2043
2044 pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
2045 self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
2046 }
2047
2048 pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
2049 let manually_assigned_slot = self
2050 .rare_data
2051 .borrow()
2052 .as_ref()?
2053 .slottable_data
2054 .manual_slot_assignment
2055 .as_ref()?
2056 .as_rooted();
2057 Some(manually_assigned_slot)
2058 }
2059
2060 pub(crate) fn set_manual_slot_assignment(
2061 &self,
2062 manually_assigned_slot: Option<&HTMLSlotElement>,
2063 ) {
2064 self.ensure_rare_data()
2065 .slottable_data
2066 .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
2067 }
2068
2069 pub(crate) fn parent_in_flat_tree(&self) -> Option<DomRoot<Node>> {
2075 if let Some(assigned_slot) = self.assigned_slot() {
2076 return Some(DomRoot::upcast(assigned_slot));
2077 }
2078
2079 let parent_or_none = self.GetParentNode();
2080 if let Some(parent) = parent_or_none.as_deref() &&
2081 let Some(shadow_root) = parent.downcast::<ShadowRoot>()
2082 {
2083 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
2084 }
2085
2086 parent_or_none
2087 }
2088
2089 pub(crate) fn inclusive_ancestors_in_flat_tree(
2090 &self,
2091 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
2092 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |n| {
2093 n.parent_in_flat_tree()
2094 })
2095 }
2096
2097 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2099 debug_assert!(self.is_in_ua_widget());
2101 debug_assert!(pseudo_element.is_element_backed());
2102 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2103 }
2104
2105 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2106 self.rare_data
2107 .borrow()
2108 .as_ref()
2109 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2110 }
2111
2112 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2114 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2118 if ancestor.is_editing_host() {
2119 return Some(ancestor);
2120 }
2121 if ancestor
2122 .downcast::<HTMLElement>()
2123 .is_some_and(|el| el.ContentEditable().str() == "false")
2124 {
2125 return None;
2126 }
2127 }
2128 None
2129 }
2130
2131 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2132 self.editing_host_of().is_some()
2133 }
2134
2135 pub(crate) fn is_editing_host(&self) -> bool {
2137 self.downcast::<HTMLElement>()
2138 .is_some_and(HTMLElement::is_editing_host)
2139 }
2140
2141 pub(crate) fn is_editable(&self) -> bool {
2143 if self.is_editing_host() {
2145 return false;
2146 }
2147 let html_element = self.downcast::<HTMLElement>();
2149 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2150 return false;
2151 }
2152 let Some(parent) = self.GetParentNode() else {
2154 return false;
2155 };
2156 if !parent.is_editable_or_editing_host() {
2157 return false;
2158 }
2159 html_element.is_some() || (!self.is::<Element>() && parent.is::<HTMLElement>())
2161 }
2162}
2163
2164fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2166where
2167 I: Iterator<Item = DomRoot<Node>>,
2168{
2169 nodes.find(|node| {
2170 not_in.iter().all(|n| match *n {
2171 NodeOrString::Node(ref n) => n != node,
2172 _ => true,
2173 })
2174 })
2175}
2176
2177#[expect(unsafe_code)]
2180pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2181 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2182 DomRoot::from_ref(node)
2183}
2184
2185#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2187pub(crate) enum CloneChildrenFlag {
2188 CloneChildren,
2189 DoNotCloneChildren,
2190}
2191
2192impl From<bool> for CloneChildrenFlag {
2193 fn from(boolean: bool) -> Self {
2194 if boolean {
2195 CloneChildrenFlag::CloneChildren
2196 } else {
2197 CloneChildrenFlag::DoNotCloneChildren
2198 }
2199 }
2200}
2201
2202pub(super) fn as_uintptr<T>(t: &T) -> uintptr_t {
2203 t as *const T as uintptr_t
2204}
2205
2206impl Node {
2207 pub(crate) fn reflect_node<N>(
2208 cx: &mut JSContext,
2209 node: Box<N>,
2210 document: &Document,
2211 ) -> DomRoot<N>
2212 where
2213 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2214 {
2215 Self::reflect_node_with_proto(cx, node, document, None)
2216 }
2217
2218 pub(crate) fn reflect_node_with_proto<N>(
2219 cx: &mut JSContext,
2220 node: Box<N>,
2221 document: &Document,
2222 proto: Option<HandleObject>,
2223 ) -> DomRoot<N>
2224 where
2225 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2226 {
2227 let window = document.window();
2228 reflect_dom_object_with_proto_and_cx(node, window, proto, cx)
2229 }
2230
2231 pub(crate) fn new_inherited(doc: &Document) -> Node {
2232 Node::new_(NodeFlags::empty(), Some(doc))
2233 }
2234
2235 pub(crate) fn new_document_node() -> Node {
2236 Node::new_(
2237 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2238 None,
2239 )
2240 }
2241
2242 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2243 Node {
2244 eventtarget: EventTarget::new_inherited(),
2245 parent_node: Default::default(),
2246 first_child: Default::default(),
2247 last_child: Default::default(),
2248 next_sibling: Default::default(),
2249 prev_sibling: Default::default(),
2250 owner_doc: MutNullableDom::new(doc),
2251 rare_data: Default::default(),
2252 children_count: Cell::new(0u32),
2253 flags: Cell::new(flags),
2254 inclusive_descendants_version: Cell::new(0),
2255 layout_data: Default::default(),
2256 }
2257 }
2258
2259 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2261 document.add_script_and_layout_blocker();
2262
2263 let old_doc = node.owner_doc();
2265 old_doc.add_script_and_layout_blocker();
2266
2267 node.remove_self(cx);
2269
2270 if &*old_doc != document {
2272 for descendant in node.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes) {
2274 descendant.set_owner_doc(document);
2276
2277 if let Some(element) = descendant.downcast::<Element>() {
2280 for attribute in element.attrs().borrow().iter() {
2281 if let Some(attr) = attribute.as_attr() {
2282 attr.upcast::<Node>().set_owner_doc(document);
2283 }
2284 }
2285 }
2286 }
2287
2288 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2292 for descendant in node
2293 .traverse_preorder(ShadowIncluding::Yes)
2294 .filter_map(|d| d.as_custom_element())
2295 {
2296 custom_element_reaction_stack.enqueue_callback_reaction(
2297 cx,
2298 &descendant,
2299 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2300 None,
2301 );
2302 }
2303
2304 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2307 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2308 }
2309 }
2310
2311 old_doc.remove_script_and_layout_blocker(cx);
2312 document.remove_script_and_layout_blocker(cx);
2313 }
2314
2315 pub(crate) fn ensure_pre_insertion_validity(
2317 no_gc: &NoGC,
2318 node: &Node,
2319 parent: &Node,
2320 child: Option<&Node>,
2321 ) -> ErrorResult {
2322 match parent.type_id() {
2324 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2325 },
2326 _ => {
2327 return Err(Error::HierarchyRequest(Some(
2328 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2329 )));
2330 },
2331 }
2332
2333 if node.is_host_including_inclusive_ancestor(parent) {
2335 return Err(Error::HierarchyRequest(Some(
2336 "Node is a host-including inclusive ancestor of parent".to_owned(),
2337 )));
2338 }
2339
2340 if let Some(child) = child &&
2342 !parent.is_parent_of(child)
2343 {
2344 return Err(Error::NotFound(Some(
2345 "Child is non-null and its parent is not parent".to_owned(),
2346 )));
2347 }
2348
2349 match node.type_id() {
2350 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2354 if parent.is::<Document>() {
2355 return Err(Error::HierarchyRequest(Some(
2356 "Node is a Text node and parent is a document".to_owned(),
2357 )));
2358 }
2359 },
2360 NodeTypeId::DocumentType => {
2361 if !parent.is::<Document>() {
2362 return Err(Error::HierarchyRequest(Some(
2363 "Node is a doctype and parent is not a document".to_owned(),
2364 )));
2365 }
2366 },
2367 NodeTypeId::DocumentFragment(_) |
2368 NodeTypeId::Element(_) |
2369 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2370 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2371 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2374 return Err(Error::HierarchyRequest(Some(
2375 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2376 .to_owned(),
2377 )));
2378 },
2379 }
2380
2381 if parent.is::<Document>() {
2384 match node.type_id() {
2385 NodeTypeId::DocumentFragment(_) => {
2386 if node.children_unrooted(no_gc).any(|c| c.is::<Text>()) {
2388 return Err(Error::HierarchyRequest(None));
2389 }
2390 match node.child_elements_unrooted(no_gc).count() {
2391 0 => (),
2392 1 => {
2395 if parent.child_elements_unrooted(no_gc).next().is_some() {
2396 return Err(Error::HierarchyRequest(None));
2397 }
2398 if let Some(child) = child &&
2399 child
2400 .inclusively_following_siblings_unrooted(no_gc)
2401 .any(|child| child.is_doctype())
2402 {
2403 return Err(Error::HierarchyRequest(None));
2404 }
2405 },
2406 _ => return Err(Error::HierarchyRequest(None)),
2407 }
2408 },
2409 NodeTypeId::Element(_) => {
2410 if parent.child_elements_unrooted(no_gc).next().is_some() {
2412 return Err(Error::HierarchyRequest(Some(
2413 "Parent has an element child".to_owned(),
2414 )));
2415 }
2416 if let Some(child) = child &&
2417 child
2418 .inclusively_following_siblings_unrooted(no_gc)
2419 .any(|following| following.is_doctype())
2420 {
2421 return Err(Error::HierarchyRequest(Some(
2422 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
2423 )));
2424 }
2425 },
2426 NodeTypeId::DocumentType => {
2427 if parent.children_unrooted(no_gc).any(|c| c.is_doctype()) {
2430 return Err(Error::HierarchyRequest(None));
2431 }
2432 match child {
2433 Some(child) => {
2434 if parent
2435 .children_unrooted(no_gc)
2436 .take_while(|c| **c != child)
2437 .any(|c| c.is::<Element>())
2438 {
2439 return Err(Error::HierarchyRequest(None));
2440 }
2441 },
2442 None => {
2443 if parent.child_elements_unrooted(no_gc).next().is_some() {
2444 return Err(Error::HierarchyRequest(None));
2445 }
2446 },
2447 }
2448 },
2449 NodeTypeId::CharacterData(_) => (),
2450 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
2453 }
2454 }
2455 Ok(())
2456 }
2457
2458 pub(crate) fn pre_insert(
2460 cx: &mut JSContext,
2461 node: &Node,
2462 parent: &Node,
2463 child: Option<&Node>,
2464 ) -> Fallible<DomRoot<Node>> {
2465 Node::ensure_pre_insertion_validity(cx.no_gc(), node, parent, child)?;
2467
2468 let reference_child_root;
2470 let reference_child = match child {
2471 Some(child) if child == node => {
2473 reference_child_root = node.GetNextSibling();
2474 reference_child_root.as_deref()
2475 },
2476 _ => child,
2477 };
2478
2479 Node::insert(
2481 cx,
2482 node,
2483 parent,
2484 reference_child,
2485 SuppressObserver::Unsuppressed,
2486 );
2487
2488 Ok(DomRoot::from_ref(node))
2490 }
2491
2492 pub(crate) fn insert(
2494 cx: &mut JSContext,
2495 node: &Node,
2496 parent: &Node,
2497 child: Option<&Node>,
2498 suppress_observers: SuppressObserver,
2499 ) {
2500 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
2501
2502 rooted_vec!(let mut new_nodes);
2504 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2505 new_nodes.extend(
2506 node.children_unrooted(cx.no_gc())
2507 .map(|node| Dom::from_ref(&**node)),
2508 );
2509 new_nodes.r()
2510 } else {
2511 from_ref(&node)
2512 };
2513
2514 let count = new_nodes.len();
2516
2517 if count == 0 {
2519 return;
2520 }
2521
2522 let parent_document = parent.owner_doc();
2525 let from_document = node.owner_doc();
2526 from_document.add_script_and_layout_blocker();
2527 parent_document.add_script_and_layout_blocker();
2528
2529 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2531 for kid in new_nodes {
2533 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
2534 }
2535 vtable_for(node).children_changed(cx, &ChildrenMutation::replace_all(new_nodes, &[]));
2536
2537 let mutation = LazyCell::new(|| Mutation::ChildList {
2539 added: None,
2540 removed: Some(new_nodes),
2541 prev: None,
2542 next: None,
2543 });
2544 MutationObserver::queue_a_mutation_record(node, mutation);
2545 }
2546
2547 if let Some(child) = child &&
2553 !parent.ranges_is_empty()
2554 {
2555 parent
2556 .ranges()
2557 .increase_above(parent, child.index(), count.try_into().unwrap());
2558 }
2559
2560 let previous_sibling = match suppress_observers {
2562 SuppressObserver::Unsuppressed => match child {
2563 Some(child) => child.GetPreviousSibling(),
2564 None => parent.GetLastChild(),
2565 },
2566 SuppressObserver::Suppressed => None,
2567 };
2568
2569 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2570
2571 let mut static_node_list: SmallVec<[_; 4]> = Default::default();
2573
2574 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
2575 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
2576 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
2577
2578 for kid in new_nodes {
2580 Node::adopt(cx, kid, &parent.owner_document());
2582
2583 parent.add_child(cx, kid, child);
2586
2587 if let Some(ref shadow_root) = parent_shadow_root &&
2590 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
2591 (kid.is::<Element>() || kid.is::<Text>())
2592 {
2593 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(kid)));
2594 slottable.assign_a_slot(cx);
2595 }
2596
2597 if parent_in_shadow_tree &&
2600 let Some(slot_element) = parent_as_slot &&
2601 !slot_element.has_assigned_nodes()
2602 {
2603 slot_element.signal_a_slot_change();
2604 }
2605
2606 kid.GetRootNode(&GetRootNodeOptions::empty())
2608 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
2609
2610 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
2613 if descendant.is_connected() {
2616 static_node_list.push(descendant.clone());
2617 }
2618
2619 if let Some(descendant) = DomRoot::downcast::<Element>(descendant) {
2625 if descendant.is_custom() {
2626 if descendant.is_connected() {
2627 custom_element_reaction_stack.enqueue_callback_reaction(
2628 cx,
2629 &descendant,
2630 CallbackReaction::Connected,
2631 None,
2632 );
2633 }
2634 } else {
2635 try_upgrade_element(&descendant);
2636 }
2637 }
2638 }
2639 }
2640
2641 if let SuppressObserver::Unsuppressed = suppress_observers {
2642 vtable_for(parent).children_changed(
2645 cx,
2646 &ChildrenMutation::insert(previous_sibling.as_deref(), new_nodes, child),
2647 );
2648
2649 let mutation = LazyCell::new(|| Mutation::ChildList {
2652 added: Some(new_nodes),
2653 removed: None,
2654 prev: previous_sibling.as_deref(),
2655 next: child,
2656 });
2657 MutationObserver::queue_a_mutation_record(parent, mutation);
2658 }
2659
2660 parent_document.add_delayed_task(
2671 task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
2672 for node in static_node_list {
2675 vtable_for(&node).post_connection_steps(cx);
2676 }
2677 }),
2678 );
2679
2680 parent_document.remove_script_and_layout_blocker(cx);
2681 from_document.remove_script_and_layout_blocker(cx);
2682 }
2683
2684 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
2686 parent.owner_doc().add_script_and_layout_blocker();
2687
2688 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
2690
2691 rooted_vec!(let mut added_nodes);
2695 let added_nodes = if let Some(node) = node.as_ref() {
2696 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2697 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
2698 added_nodes.r()
2699 } else {
2700 from_ref(node)
2701 }
2702 } else {
2703 &[] as &[&Node]
2704 };
2705
2706 for child in &*removed_nodes {
2708 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
2709 }
2710
2711 if let Some(node) = node {
2713 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
2714 }
2715
2716 vtable_for(parent).children_changed(
2717 cx,
2718 &ChildrenMutation::replace_all(removed_nodes.r(), added_nodes),
2719 );
2720
2721 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
2724 let mutation = LazyCell::new(|| Mutation::ChildList {
2725 added: Some(added_nodes),
2726 removed: Some(removed_nodes.r()),
2727 prev: None,
2728 next: None,
2729 });
2730 MutationObserver::queue_a_mutation_record(parent, mutation);
2731 }
2732 parent.owner_doc().remove_script_and_layout_blocker(cx);
2733 }
2734
2735 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
2737 if string.is_empty() {
2738 Node::replace_all(cx, None, parent);
2739 } else {
2740 let text = Text::new(cx, string, &parent.owner_document());
2741 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
2742 };
2743 }
2744
2745 pub(super) fn pre_remove(
2747 cx: &mut JSContext,
2748 child: &Node,
2749 parent: &Node,
2750 ) -> Fallible<DomRoot<Node>> {
2751 match child.GetParentNode() {
2753 Some(ref node) if &**node != parent => return Err(Error::NotFound(None)),
2754 None => return Err(Error::NotFound(None)),
2755 _ => (),
2756 }
2757
2758 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
2760
2761 Ok(DomRoot::from_ref(child))
2763 }
2764
2765 pub(super) fn remove(
2767 cx: &mut JSContext,
2768 node: &Node,
2769 parent: &Node,
2770 suppress_observers: SuppressObserver,
2771 ) {
2772 parent.owner_doc().add_script_and_layout_blocker();
2773
2774 assert!(
2778 node.GetParentNode()
2779 .is_some_and(|node_parent| &*node_parent == parent)
2780 );
2781
2782 let cached_index = Node::live_range_pre_remove_steps(node, parent);
2785
2786 let old_previous_sibling = node.GetPreviousSibling();
2790
2791 let old_next_sibling = node.GetNextSibling();
2793
2794 parent.remove_child(cx, node, cached_index);
2797
2798 if let Some(slot) = node.assigned_slot() {
2800 slot.assign_slottables(cx);
2801 }
2802
2803 if parent.is_in_a_shadow_tree() &&
2806 let Some(slot_element) = parent.downcast::<HTMLSlotElement>() &&
2807 !slot_element.has_assigned_nodes()
2808 {
2809 slot_element.signal_a_slot_change();
2810 }
2811
2812 let has_slot_descendant = node
2814 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
2815 .any(|elem| elem.is::<HTMLSlotElement>());
2816 if has_slot_descendant {
2817 parent
2819 .GetRootNode(&GetRootNodeOptions::empty())
2820 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
2821
2822 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Force);
2824 }
2825
2826 if let SuppressObserver::Unsuppressed = suppress_observers {
2830 vtable_for(parent).children_changed(
2831 cx,
2832 &ChildrenMutation::replace(
2833 old_previous_sibling.as_deref(),
2834 &Some(node),
2835 &[],
2836 old_next_sibling.as_deref(),
2837 ),
2838 );
2839
2840 let removed = [node];
2841 let mutation = LazyCell::new(|| Mutation::ChildList {
2842 added: None,
2843 removed: Some(&removed),
2844 prev: old_previous_sibling.as_deref(),
2845 next: old_next_sibling.as_deref(),
2846 });
2847 MutationObserver::queue_a_mutation_record(parent, mutation);
2848 }
2849 parent.owner_doc().remove_script_and_layout_blocker(cx);
2850 }
2851
2852 fn live_range_pre_remove_steps(node: &Node, parent: &Node) -> Option<u32> {
2854 if parent.ranges_is_empty() {
2855 return None;
2856 }
2857
2858 let index = node.index();
2864
2865 parent.ranges().decrease_above(parent, index, 1);
2872
2873 Some(index)
2877 }
2878
2879 pub(crate) fn clone(
2881 cx: &mut JSContext,
2882 node: &Node,
2883 maybe_doc: Option<&Document>,
2884 clone_children: CloneChildrenFlag,
2885 registry: Option<DomRoot<CustomElementRegistry>>,
2886 ) -> DomRoot<Node> {
2887 let document = match maybe_doc {
2889 Some(doc) => DomRoot::from_ref(doc),
2890 None => node.owner_doc(),
2891 };
2892
2893 let copy: DomRoot<Node> = match node.type_id() {
2896 NodeTypeId::DocumentType => {
2897 let doctype = node.downcast::<DocumentType>().unwrap();
2898 let doctype = DocumentType::new(
2899 cx,
2900 doctype.name().clone(),
2901 Some(doctype.public_id().clone()),
2902 Some(doctype.system_id().clone()),
2903 &document,
2904 );
2905 DomRoot::upcast::<Node>(doctype)
2906 },
2907 NodeTypeId::Attr => {
2908 let attr = node.downcast::<Attr>().unwrap();
2909 let attr = Attr::new(
2910 cx,
2911 &document,
2912 attr.local_name().clone(),
2913 attr.value().clone(),
2914 attr.name().clone(),
2915 attr.namespace().clone(),
2916 attr.prefix().cloned(),
2917 None,
2918 );
2919 DomRoot::upcast::<Node>(attr)
2920 },
2921 NodeTypeId::DocumentFragment(_) => {
2922 let doc_fragment = DocumentFragment::new(cx, &document);
2923 DomRoot::upcast::<Node>(doc_fragment)
2924 },
2925 NodeTypeId::CharacterData(_) => {
2926 let cdata = node.downcast::<CharacterData>().unwrap();
2927 cdata.clone_with_data(cx, cdata.Data(), &document)
2928 },
2929 NodeTypeId::Document(_) => {
2930 let document = node.downcast::<Document>().unwrap();
2933 let is_html_doc = if document.is_html_document() {
2934 IsHTMLDocument::HTMLDocument
2935 } else {
2936 IsHTMLDocument::NonHTMLDocument
2937 };
2938 let window = document.window();
2939 let loader = DocumentLoader::new(&document.loader());
2940 let document = Document::new(
2941 window,
2942 HasBrowsingContext::No,
2943 Some(document.url()),
2944 None,
2945 document.origin().clone(),
2947 is_html_doc,
2948 None,
2949 None,
2950 DocumentActivity::Inactive,
2951 DocumentSource::NotFromParser,
2952 loader,
2953 None,
2954 document.status_code(),
2955 Default::default(),
2956 false,
2957 document.allow_declarative_shadow_roots(),
2958 Some(document.insecure_requests_policy()),
2959 document.has_trustworthy_ancestor_or_current_origin(),
2960 document.custom_element_reaction_stack(),
2961 document.creation_sandboxing_flag_set(),
2962 document.pipeline_id(),
2963 document.image_cache(),
2964 CanGc::from_cx(cx),
2965 );
2966 DomRoot::upcast::<Node>(document)
2970 },
2971 NodeTypeId::Element(..) => {
2973 let element = node.downcast::<Element>().unwrap();
2974 let registry = element.custom_element_registry().or(registry);
2977 let registry =
2980 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
2981 document.custom_element_registry()
2982 } else {
2983 registry
2984 };
2985 let name = QualName {
2989 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
2990 ns: element.namespace().clone(),
2991 local: element.local_name().clone(),
2992 };
2993 let element = Element::create(
2994 cx,
2995 name,
2996 element.get_is(),
2997 &document,
2998 ElementCreator::ScriptCreated,
2999 CustomElementCreationMode::Asynchronous,
3000 None,
3001 );
3002 element.set_custom_element_registry(registry.as_deref());
3004 DomRoot::upcast::<Node>(element)
3005 },
3006 };
3007
3008 let document = match copy.downcast::<Document>() {
3011 Some(doc) => DomRoot::from_ref(doc),
3012 None => DomRoot::from_ref(&*document),
3013 };
3014 assert!(copy.owner_doc() == document);
3015
3016 match node.type_id() {
3018 NodeTypeId::Document(_) => {
3019 let node_doc = node.downcast::<Document>().unwrap();
3020 let copy_doc = copy.downcast::<Document>().unwrap();
3021 copy_doc.set_encoding(node_doc.encoding());
3022 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3023 },
3024 NodeTypeId::Element(..) => {
3025 let node_elem = node.downcast::<Element>().unwrap();
3026 let copy_elem = copy.downcast::<Element>().unwrap();
3027
3028 node_elem.copy_all_attributes_to_other_element(cx, copy_elem);
3030 },
3031 _ => (),
3032 }
3033
3034 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3037
3038 if clone_children == CloneChildrenFlag::CloneChildren {
3041 for child in node.children() {
3042 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3043 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3044 }
3045 }
3046
3047 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3050 let node_elem = node.downcast::<Element>().unwrap();
3051 let copy_elem = copy.downcast::<Element>().unwrap();
3052
3053 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3054 assert!(!copy_elem.is_shadow_host());
3056
3057 let copy_shadow_root =
3061 copy_elem.attach_shadow(
3062 cx,
3063 IsUserAgentWidget::No,
3064 shadow_root.Mode(),
3065 shadow_root.Clonable(),
3066 shadow_root.Serializable(),
3067 shadow_root.DelegatesFocus(),
3068 shadow_root.SlotAssignment(),
3069 )
3070 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3071
3072 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3074
3075 for child in shadow_root.upcast::<Node>().children() {
3078 let child_copy = Node::clone(
3079 cx,
3080 &child,
3081 Some(&document),
3082 CloneChildrenFlag::CloneChildren,
3083 None,
3084 );
3085
3086 let _inserted_node =
3088 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3089 }
3090 }
3091 }
3092
3093 copy
3095 }
3096
3097 pub(crate) fn child_text_content(&self) -> DOMString {
3099 Node::collect_text_contents(self.children())
3100 }
3101
3102 pub(crate) fn descendant_text_content(&self) -> DOMString {
3104 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3105 }
3106
3107 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3108 iterator: T,
3109 ) -> DOMString {
3110 let mut content = String::new();
3111 for node in iterator {
3112 if let Some(text) = node.downcast::<Text>() {
3113 content.push_str(&text.upcast::<CharacterData>().data());
3114 }
3115 }
3116 DOMString::from(content)
3117 }
3118
3119 pub(crate) fn set_text_content_for_element(
3121 &self,
3122 cx: &mut JSContext,
3123 value: Option<DOMString>,
3124 ) {
3125 assert!(matches!(
3128 self.type_id(),
3129 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3130 ));
3131 let value = value.unwrap_or_default();
3132 let node = if value.is_empty() {
3133 None
3135 } else {
3136 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3139 };
3140
3141 Self::replace_all(cx, node.as_deref(), self);
3143 }
3144
3145 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3146 match namespace {
3147 ns!() => None,
3148 _ => Some(DOMString::from(&*namespace)),
3150 }
3151 }
3152
3153 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3155 match node.type_id() {
3156 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3157 NodeTypeId::Attr => node
3158 .downcast::<Attr>()
3159 .unwrap()
3160 .GetOwnerElement()
3161 .as_ref()
3162 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3163 NodeTypeId::Document(_) => node
3164 .downcast::<Document>()
3165 .unwrap()
3166 .GetDocumentElement()
3167 .as_ref()
3168 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3169 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3170 _ => node
3171 .GetParentElement()
3172 .as_ref()
3173 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3174 }
3175 }
3176
3177 #[expect(unsafe_code)]
3185 pub(crate) unsafe fn from_untrusted_node_address(
3186 candidate: UntrustedNodeAddress,
3187 ) -> &'static Self {
3188 let candidate = candidate.0 as usize;
3190 let object = candidate as *mut JSObject;
3191 if object.is_null() {
3192 panic!("Attempted to create a `Node` from an invalid pointer!")
3193 }
3194
3195 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3196 }
3197
3198 pub(crate) fn html_serialize(
3199 &self,
3200 cx: &mut JSContext,
3201 traversal_scope: html_serialize::TraversalScope,
3202 serialize_shadow_roots: bool,
3203 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3204 ) -> DOMString {
3205 let mut writer = vec![];
3206 let mut serializer = HtmlSerializer::new(
3207 &mut writer,
3208 html_serialize::SerializeOpts {
3209 traversal_scope: traversal_scope.clone(),
3210 ..Default::default()
3211 },
3212 );
3213
3214 serialize_html_fragment(
3215 cx,
3216 self,
3217 &mut serializer,
3218 traversal_scope,
3219 serialize_shadow_roots,
3220 shadow_roots,
3221 )
3222 .expect("Serializing node failed");
3223
3224 DOMString::from(String::from_utf8(writer).unwrap())
3226 }
3227
3228 pub(crate) fn xml_serialize(
3230 &self,
3231 traversal_scope: xml_serialize::TraversalScope,
3232 ) -> Fallible<DOMString> {
3233 let mut writer = vec![];
3234 xml_serialize::serialize(
3235 &mut writer,
3236 &HtmlSerialize::new(self),
3237 xml_serialize::SerializeOpts { traversal_scope },
3238 )
3239 .map_err(|error| {
3240 error!("Cannot serialize node: {error}");
3241 Error::InvalidState(None)
3242 })?;
3243
3244 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3246 error!("Cannot serialize node: {error}");
3247 Error::InvalidState(None)
3248 })?);
3249
3250 Ok(string)
3251 }
3252
3253 pub(crate) fn fragment_serialization_algorithm(
3255 &self,
3256 cx: &mut JSContext,
3257 require_well_formed: bool,
3258 ) -> Fallible<DOMString> {
3259 let context_document = self.owner_document();
3261
3262 if context_document.is_html_document() {
3265 return Ok(self.html_serialize(
3266 cx,
3267 html_serialize::TraversalScope::ChildrenOnly(None),
3268 false,
3269 vec![],
3270 ));
3271 }
3272
3273 let _ = require_well_formed;
3276 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3277 }
3278
3279 pub(crate) fn get_next_sibling_unrooted<'a>(
3280 &self,
3281 no_gc: &'a NoGC,
3282 ) -> Option<UnrootedDom<'a, Node>> {
3283 self.next_sibling.get_unrooted(no_gc)
3284 }
3285
3286 pub(crate) fn get_previous_sibling_unrooted<'a>(
3287 &self,
3288 no_gc: &'a NoGC,
3289 ) -> Option<UnrootedDom<'a, Node>> {
3290 self.prev_sibling.get_unrooted(no_gc)
3291 }
3292
3293 pub(crate) fn get_first_child_unrooted<'a>(
3294 &self,
3295 no_gc: &'a NoGC,
3296 ) -> Option<UnrootedDom<'a, Node>> {
3297 self.first_child.get_unrooted(no_gc)
3298 }
3299
3300 fn get_last_child_unrooted<'b>(&self, no_gc: &'b NoGC) -> Option<UnrootedDom<'b, Node>> {
3301 self.last_child.get_unrooted(no_gc)
3302 }
3303
3304 pub(crate) fn get_parent_node_unrooted<'a>(
3305 &self,
3306 no_gc: &'a NoGC,
3307 ) -> Option<UnrootedDom<'a, Node>> {
3308 self.parent_node.get_unrooted(no_gc)
3309 }
3310
3311 pub(crate) fn compare_dom_tree_position(
3313 &self,
3314 other: &Node,
3315 common_ancestor: &Node,
3316 shadow_including: ShadowIncluding,
3317 ) -> Ordering {
3318 debug_assert!(
3319 self.inclusive_ancestors(shadow_including)
3320 .any(|ancestor| &*ancestor == common_ancestor)
3321 );
3322 debug_assert!(
3323 other
3324 .inclusive_ancestors(shadow_including)
3325 .any(|ancestor| &*ancestor == common_ancestor)
3326 );
3327
3328 if self == other {
3329 return Ordering::Equal;
3330 }
3331
3332 if self == common_ancestor {
3333 return Ordering::Less;
3334 }
3335 if other == common_ancestor {
3336 return Ordering::Greater;
3337 }
3338
3339 let my_ancestors: Vec<_> = self
3340 .inclusive_ancestors(shadow_including)
3341 .take_while(|ancestor| &**ancestor != common_ancestor)
3342 .collect();
3343 let other_ancestors: Vec<_> = other
3344 .inclusive_ancestors(shadow_including)
3345 .take_while(|ancestor| &**ancestor != common_ancestor)
3346 .collect();
3347
3348 let mut i = my_ancestors.len() - 1;
3350 let mut j = other_ancestors.len() - 1;
3351
3352 while my_ancestors[i] == other_ancestors[j] {
3353 if i == 0 {
3354 debug_assert_ne!(j, 0, "Equal inclusive ancestors but nodes are not equal?");
3356 return Ordering::Less;
3357 }
3358 if j == 0 {
3359 return Ordering::Greater;
3361 }
3362
3363 i -= 1;
3364 j -= 1;
3365 }
3366
3367 if my_ancestors[i]
3370 .preceding_siblings()
3371 .any(|sibling| sibling == other_ancestors[j])
3372 {
3373 Ordering::Greater
3375 } else {
3376 debug_assert!(
3378 other_ancestors[j]
3379 .preceding_siblings()
3380 .any(|sibling| sibling == my_ancestors[i])
3381 );
3382 Ordering::Less
3383 }
3384 }
3385}
3386
3387impl NodeMethods<crate::DomTypeHolder> for Node {
3388 fn NodeType(&self) -> u16 {
3390 match self.type_id() {
3391 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3392 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3393 NodeConstants::TEXT_NODE
3394 },
3395 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3396 NodeConstants::CDATA_SECTION_NODE
3397 },
3398 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3399 NodeConstants::PROCESSING_INSTRUCTION_NODE
3400 },
3401 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3402 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3403 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3404 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3405 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3406 }
3407 }
3408
3409 fn NodeName(&self) -> DOMString {
3411 match self.type_id() {
3412 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3413 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3414 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3415 DOMString::from("#text")
3416 },
3417 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3418 DOMString::from("#cdata-section")
3419 },
3420 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3421 self.downcast::<ProcessingInstruction>().unwrap().Target()
3422 },
3423 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => DOMString::from("#comment"),
3424 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3425 NodeTypeId::DocumentFragment(_) => DOMString::from("#document-fragment"),
3426 NodeTypeId::Document(_) => DOMString::from("#document"),
3427 }
3428 }
3429
3430 fn BaseURI(&self) -> USVString {
3432 USVString(String::from(self.owner_doc().base_url().as_str()))
3433 }
3434
3435 fn IsConnected(&self) -> bool {
3437 self.is_connected()
3438 }
3439
3440 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3442 match self.type_id() {
3443 NodeTypeId::Document(_) => None,
3444 _ => Some(self.owner_doc()),
3445 }
3446 }
3447
3448 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3450 if !options.composed &&
3451 let Some(shadow_root) = self.containing_shadow_root()
3452 {
3453 return DomRoot::upcast(shadow_root);
3454 }
3455
3456 if self.is_connected() {
3457 DomRoot::from_ref(self.owner_doc().upcast::<Node>())
3458 } else {
3459 self.inclusive_ancestors(ShadowIncluding::Yes)
3460 .last()
3461 .unwrap()
3462 }
3463 }
3464
3465 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
3467 self.parent_node().get()
3468 }
3469
3470 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
3472 self.GetParentNode().and_then(DomRoot::downcast)
3473 }
3474
3475 fn HasChildNodes(&self) -> bool {
3477 self.first_child().get().is_some()
3478 }
3479
3480 fn ChildNodes(&self, cx: &mut JSContext) -> DomRoot<NodeList> {
3482 if let Some(list) = self.ensure_rare_data().child_list.get() {
3483 return list;
3484 }
3485
3486 let doc = self.owner_doc();
3487 let window = doc.window();
3488 let list = NodeList::new_child_list(window, self, CanGc::from_cx(cx));
3489 self.ensure_rare_data().child_list.set(Some(&list));
3490 list
3491 }
3492
3493 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
3495 self.first_child().get()
3496 }
3497
3498 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
3500 self.last_child().get()
3501 }
3502
3503 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
3505 self.prev_sibling().get()
3506 }
3507
3508 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
3510 self.next_sibling().get()
3511 }
3512
3513 fn GetNodeValue(&self) -> Option<DOMString> {
3515 match self.type_id() {
3516 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3517 NodeTypeId::CharacterData(_) => {
3518 self.downcast::<CharacterData>().map(CharacterData::Data)
3519 },
3520 _ => None,
3521 }
3522 }
3523
3524 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
3526 match self.type_id() {
3527 NodeTypeId::Attr => {
3528 let attr = self.downcast::<Attr>().unwrap();
3529 attr.SetValue(cx, val.unwrap_or_default())?;
3530 },
3531 NodeTypeId::CharacterData(_) => {
3532 let character_data = self.downcast::<CharacterData>().unwrap();
3533 character_data.SetData(cx, val.unwrap_or_default());
3534 },
3535 _ => {},
3536 };
3537 Ok(())
3538 }
3539
3540 fn GetTextContent(&self) -> Option<DOMString> {
3542 match self.type_id() {
3543 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3544 let content =
3545 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
3546 Some(content)
3547 },
3548 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3549 NodeTypeId::CharacterData(..) => {
3550 let characterdata = self.downcast::<CharacterData>().unwrap();
3551 Some(characterdata.Data())
3552 },
3553 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
3554 }
3555 }
3556
3557 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
3559 match self.type_id() {
3560 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3561 self.set_text_content_for_element(cx, value);
3562 },
3563 NodeTypeId::Attr => {
3564 let attr = self.downcast::<Attr>().unwrap();
3565 attr.SetValue(cx, value.unwrap_or_default())?;
3566 },
3567 NodeTypeId::CharacterData(..) => {
3568 let characterdata = self.downcast::<CharacterData>().unwrap();
3569 characterdata.SetData(cx, value.unwrap_or_default());
3570 },
3571 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
3572 };
3573 Ok(())
3574 }
3575
3576 fn InsertBefore(
3578 &self,
3579 cx: &mut JSContext,
3580 node: &Node,
3581 child: Option<&Node>,
3582 ) -> Fallible<DomRoot<Node>> {
3583 Node::pre_insert(cx, node, self, child)
3584 }
3585
3586 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3588 Node::pre_insert(cx, node, self, None)
3589 }
3590
3591 fn ReplaceChild(
3593 &self,
3594 cx: &mut JSContext,
3595 node: &Node,
3596 child: &Node,
3597 ) -> Fallible<DomRoot<Node>> {
3598 match self.type_id() {
3601 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3602 },
3603 _ => return Err(Error::HierarchyRequest(None)),
3604 }
3605
3606 if node.is_inclusive_ancestor_of(self) {
3609 return Err(Error::HierarchyRequest(None));
3610 }
3611
3612 if !self.is_parent_of(child) {
3614 return Err(Error::NotFound(None));
3615 }
3616
3617 match node.type_id() {
3622 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
3623 return Err(Error::HierarchyRequest(None));
3624 },
3625 NodeTypeId::DocumentType if !self.is::<Document>() => {
3626 return Err(Error::HierarchyRequest(None));
3627 },
3628 NodeTypeId::Document(_) | NodeTypeId::Attr => {
3629 return Err(Error::HierarchyRequest(None));
3630 },
3631 _ => (),
3632 }
3633
3634 if self.is::<Document>() {
3637 match node.type_id() {
3638 NodeTypeId::DocumentFragment(_) => {
3640 if node.children_unrooted(cx.no_gc()).any(|c| c.is::<Text>()) {
3642 return Err(Error::HierarchyRequest(None));
3643 }
3644 match node.child_elements_unrooted(cx.no_gc()).count() {
3645 0 => (),
3646 1 => {
3648 if self
3649 .child_elements_unrooted(cx.no_gc())
3650 .any(|c| c.upcast::<Node>() != child)
3651 {
3652 return Err(Error::HierarchyRequest(None));
3653 }
3654 if child.following_siblings().any(|child| child.is_doctype()) {
3655 return Err(Error::HierarchyRequest(None));
3656 }
3657 },
3658 _ => return Err(Error::HierarchyRequest(None)),
3660 }
3661 },
3662 NodeTypeId::Element(..) => {
3664 if self
3665 .child_elements_unrooted(cx.no_gc())
3666 .any(|c| c.upcast::<Node>() != child)
3667 {
3668 return Err(Error::HierarchyRequest(None));
3669 }
3670 if child.following_siblings().any(|child| child.is_doctype()) {
3671 return Err(Error::HierarchyRequest(None));
3672 }
3673 },
3674 NodeTypeId::DocumentType => {
3676 if self
3677 .children_unrooted(cx.no_gc())
3678 .any(|c| c.is_doctype() && *c != child)
3679 {
3680 return Err(Error::HierarchyRequest(None));
3681 }
3682 if self
3683 .children_unrooted(cx.no_gc())
3684 .take_while(|c| **c != child)
3685 .any(|c| c.is::<Element>())
3686 {
3687 return Err(Error::HierarchyRequest(None));
3688 }
3689 },
3690 NodeTypeId::CharacterData(..) => (),
3691 NodeTypeId::Document(_) => unreachable!(),
3694 NodeTypeId::Attr => unreachable!(),
3695 }
3696 }
3697
3698 let child_next_sibling = child.GetNextSibling();
3701 let node_next_sibling = node.GetNextSibling();
3702 let reference_child = if child_next_sibling.as_deref() == Some(node) {
3703 node_next_sibling.as_deref()
3704 } else {
3705 child_next_sibling.as_deref()
3706 };
3707
3708 let previous_sibling = child.GetPreviousSibling();
3710
3711 let document = self.owner_document();
3715 Node::adopt(cx, node, &document);
3716
3717 let removed_child = if node != child {
3722 Node::remove(cx, child, self, SuppressObserver::Suppressed);
3724 Some(child)
3725 } else {
3726 None
3727 };
3728
3729 rooted_vec!(let mut nodes);
3731 let nodes = if node.type_id() ==
3732 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
3733 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
3734 {
3735 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
3736 nodes.r()
3737 } else {
3738 from_ref(&node)
3739 };
3740
3741 Node::insert(
3743 cx,
3744 node,
3745 self,
3746 reference_child,
3747 SuppressObserver::Suppressed,
3748 );
3749
3750 vtable_for(self).children_changed(
3751 cx,
3752 &ChildrenMutation::replace(
3753 previous_sibling.as_deref(),
3754 &removed_child,
3755 nodes,
3756 reference_child,
3757 ),
3758 );
3759
3760 let removed = removed_child.map(|r| [r]);
3763 let mutation = LazyCell::new(|| Mutation::ChildList {
3764 added: Some(nodes),
3765 removed: removed.as_ref().map(|r| &r[..]),
3766 prev: previous_sibling.as_deref(),
3767 next: reference_child,
3768 });
3769
3770 MutationObserver::queue_a_mutation_record(self, mutation);
3771
3772 Ok(DomRoot::from_ref(child))
3774 }
3775
3776 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3778 Node::pre_remove(cx, node, self)
3779 }
3780
3781 fn Normalize(&self, cx: &mut JSContext) {
3783 let mut children = self.children().enumerate().peekable();
3784 while let Some((_, node)) = children.next() {
3785 if let Some(text) = node.downcast::<Text>() {
3786 if text.is::<CDATASection>() {
3787 continue;
3788 }
3789 let cdata = text.upcast::<CharacterData>();
3790 let mut length = cdata.Length();
3791 if length == 0 {
3792 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
3793 continue;
3794 }
3795 while children.peek().is_some_and(|(_, sibling)| {
3796 sibling.is::<Text>() && !sibling.is::<CDATASection>()
3797 }) {
3798 let (index, sibling) = children.next().unwrap();
3799 sibling
3800 .ranges()
3801 .drain_to_preceding_text_sibling(&sibling, &node, length);
3802 self.ranges()
3803 .move_to_text_child_at(self, index as u32, &node, length);
3804 let sibling_cdata = sibling.downcast::<CharacterData>().unwrap();
3805 length += sibling_cdata.Length();
3806 cdata.append_data(cx, &sibling_cdata.data());
3807 Node::remove(cx, &sibling, self, SuppressObserver::Unsuppressed);
3808 }
3809 } else {
3810 node.Normalize(cx);
3811 }
3812 }
3813 }
3814
3815 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
3817 if self.is::<ShadowRoot>() {
3819 return Err(Error::NotSupported(None));
3820 }
3821
3822 let result = Node::clone(
3824 cx,
3825 self,
3826 None,
3827 if subtree {
3828 CloneChildrenFlag::CloneChildren
3829 } else {
3830 CloneChildrenFlag::DoNotCloneChildren
3831 },
3832 None,
3833 );
3834 Ok(result)
3835 }
3836
3837 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
3839 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
3840 let doctype = node.downcast::<DocumentType>().unwrap();
3841 let other_doctype = other.downcast::<DocumentType>().unwrap();
3842 (*doctype.name() == *other_doctype.name()) &&
3843 (*doctype.public_id() == *other_doctype.public_id()) &&
3844 (*doctype.system_id() == *other_doctype.system_id())
3845 }
3846 fn is_equal_element(node: &Node, other: &Node) -> bool {
3847 let element = node.downcast::<Element>().unwrap();
3848 let other_element = other.downcast::<Element>().unwrap();
3849 (*element.namespace() == *other_element.namespace()) &&
3850 (*element.prefix() == *other_element.prefix()) &&
3851 (*element.local_name() == *other_element.local_name()) &&
3852 (element.attrs().borrow().len() == other_element.attrs().borrow().len())
3853 }
3854 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
3855 let pi = node.downcast::<ProcessingInstruction>().unwrap();
3856 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
3857 (*pi.target() == *other_pi.target()) &&
3858 (*pi.upcast::<CharacterData>().data() ==
3859 *other_pi.upcast::<CharacterData>().data())
3860 }
3861 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
3862 let characterdata = node.downcast::<CharacterData>().unwrap();
3863 let other_characterdata = other.downcast::<CharacterData>().unwrap();
3864 *characterdata.data() == *other_characterdata.data()
3865 }
3866 fn is_equal_attr(node: &Node, other: &Node) -> bool {
3867 let attr = node.downcast::<Attr>().unwrap();
3868 let other_attr = other.downcast::<Attr>().unwrap();
3869 (*attr.namespace() == *other_attr.namespace()) &&
3870 (attr.local_name() == other_attr.local_name()) &&
3871 (**attr.value() == **other_attr.value())
3872 }
3873 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
3874 let element = node.downcast::<Element>().unwrap();
3875 let other_element = other.downcast::<Element>().unwrap();
3876 assert!(element.attrs().borrow().len() == other_element.attrs().borrow().len());
3877 element.attrs().borrow().iter().all(|attr| {
3878 other_element.attrs().borrow().iter().any(|other_attr| {
3879 (*attr.namespace() == *other_attr.namespace()) &&
3880 (attr.local_name() == other_attr.local_name()) &&
3881 (**attr.value() == **other_attr.value())
3882 })
3883 })
3884 }
3885
3886 fn is_equal_node(this: &Node, node: &Node) -> bool {
3887 if this.NodeType() != node.NodeType() {
3889 return false;
3890 }
3891
3892 match node.type_id() {
3893 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
3895 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
3896 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
3897 if !is_equal_processinginstruction(this, node) =>
3898 {
3899 return false;
3900 },
3901 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
3902 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
3903 if !is_equal_characterdata(this, node) =>
3904 {
3905 return false;
3906 },
3907 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
3909 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
3910
3911 _ => (),
3912 }
3913
3914 if this.children_count() != node.children_count() {
3916 return false;
3917 }
3918
3919 this.children()
3921 .zip(node.children())
3922 .all(|(child, other_child)| is_equal_node(&child, &other_child))
3923 }
3924 match maybe_node {
3925 None => false,
3927 Some(node) => is_equal_node(self, node),
3929 }
3930 }
3931
3932 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
3934 match other_node {
3935 Some(node) => self == node,
3936 None => false,
3937 }
3938 }
3939
3940 fn CompareDocumentPosition(&self, other: &Node) -> u16 {
3942 if self == other {
3944 return 0;
3945 }
3946
3947 let mut node1 = Some(other);
3949 let mut node2 = Some(self);
3950
3951 let mut attr1: Option<&Attr> = None;
3953 let mut attr2: Option<&Attr> = None;
3954
3955 let attr1owner;
3960 if let Some(a) = other.downcast::<Attr>() {
3961 attr1 = Some(a);
3962 attr1owner = a.GetOwnerElement();
3963 node1 = match attr1owner {
3964 Some(ref e) => Some(e.upcast()),
3965 None => None,
3966 }
3967 }
3968
3969 let attr2owner;
3972 if let Some(a) = self.downcast::<Attr>() {
3973 attr2 = Some(a);
3974 attr2owner = a.GetOwnerElement();
3975 node2 = match attr2owner {
3976 Some(ref e) => Some(e.upcast()),
3977 None => None,
3978 }
3979 }
3980
3981 if let Some(node2) = node2 &&
3986 Some(node2) == node1 &&
3987 let (Some(a1), Some(a2)) = (attr1, attr2)
3988 {
3989 let attrs = node2.downcast::<Element>().unwrap().attrs();
3990 for attr in attrs.borrow().iter() {
3994 if (*attr.namespace() == *a1.namespace()) &&
3995 (attr.local_name() == a1.local_name()) &&
3996 (**attr.value() == **a1.value())
3997 {
3998 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
3999 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4000 }
4001 if (*attr.namespace() == *a2.namespace()) &&
4002 (attr.local_name() == a2.local_name()) &&
4003 (**attr.value() == **a2.value())
4004 {
4005 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4006 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4007 }
4008 }
4009 unreachable!();
4012 }
4013
4014 match (node1, node2) {
4016 (None, _) => {
4017 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4019 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4020 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4021 },
4022 (_, None) => {
4023 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4025 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4026 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4027 },
4028 (Some(node1), Some(node2)) => {
4029 let mut self_and_ancestors = node2
4031 .inclusive_ancestors(ShadowIncluding::No)
4032 .collect::<SmallVec<[_; 20]>>();
4033 let mut other_and_ancestors = node1
4034 .inclusive_ancestors(ShadowIncluding::No)
4035 .collect::<SmallVec<[_; 20]>>();
4036
4037 if self_and_ancestors.last() != other_and_ancestors.last() {
4038 let random = as_uintptr(self_and_ancestors.last().unwrap()) <
4039 as_uintptr(other_and_ancestors.last().unwrap());
4040 let random = if random {
4041 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4042 } else {
4043 NodeConstants::DOCUMENT_POSITION_PRECEDING
4044 };
4045
4046 return random +
4048 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4049 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4050 }
4051 let mut parent = self_and_ancestors.pop().unwrap();
4053 other_and_ancestors.pop().unwrap();
4054
4055 let mut current_position =
4056 cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
4057
4058 while current_position > 0 {
4059 current_position -= 1;
4060 let child_1 = self_and_ancestors.pop().unwrap();
4061 let child_2 = other_and_ancestors.pop().unwrap();
4062
4063 if child_1 != child_2 {
4064 for child in parent.children() {
4065 if child == child_1 {
4066 return NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4068 }
4069 if child == child_2 {
4070 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4072 }
4073 }
4074 }
4075
4076 parent = child_1;
4077 }
4078
4079 if self_and_ancestors.len() < other_and_ancestors.len() {
4084 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4085 NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
4086 } else {
4087 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4088 NodeConstants::DOCUMENT_POSITION_CONTAINS
4089 }
4090 },
4091 }
4092 }
4093
4094 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4096 match maybe_other {
4097 None => false,
4098 Some(other) => self.is_inclusive_ancestor_of(other),
4099 }
4100 }
4101
4102 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4104 let namespace = namespace_from_domstring(namespace);
4105
4106 if namespace == ns!() {
4108 return None;
4109 }
4110
4111 match self.type_id() {
4113 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4114 NodeTypeId::Document(_) => self
4115 .downcast::<Document>()
4116 .unwrap()
4117 .GetDocumentElement()
4118 .and_then(|element| element.lookup_prefix(namespace)),
4119 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4120 NodeTypeId::Attr => self
4121 .downcast::<Attr>()
4122 .unwrap()
4123 .GetOwnerElement()
4124 .and_then(|element| element.lookup_prefix(namespace)),
4125 _ => self
4126 .GetParentElement()
4127 .and_then(|element| element.lookup_prefix(namespace)),
4128 }
4129 }
4130
4131 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4133 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4135
4136 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4138 }
4139
4140 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4142 let namespace = namespace_from_domstring(namespace);
4144 Node::locate_namespace(self, None) == namespace
4146 }
4147}
4148
4149pub(crate) trait NodeTraits {
4150 fn owner_document(&self) -> DomRoot<Document>;
4154 fn owner_window(&self) -> DomRoot<Window>;
4158 fn owner_global(&self) -> DomRoot<GlobalScope>;
4162 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4164 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4167}
4168
4169impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4170 fn owner_document(&self) -> DomRoot<Document> {
4171 self.upcast().owner_doc()
4172 }
4173
4174 fn owner_window(&self) -> DomRoot<Window> {
4175 DomRoot::from_ref(self.owner_document().window())
4176 }
4177
4178 fn owner_global(&self) -> DomRoot<GlobalScope> {
4179 DomRoot::from_ref(self.owner_window().upcast())
4180 }
4181
4182 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4183 Node::containing_shadow_root(self.upcast())
4184 }
4185
4186 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4187 self.containing_shadow_root()
4188 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4189 .unwrap_or_else(|| {
4190 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4191 })
4192 }
4193}
4194
4195impl VirtualMethods for Node {
4196 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4197 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4198 }
4199
4200 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4201 if let Some(s) = self.super_type() {
4202 s.children_changed(cx, mutation);
4203 }
4204
4205 if let Some(data) = self.rare_data.borrow().as_ref() &&
4206 let Some(list) = data.child_list.get()
4207 {
4208 list.as_children_list().children_changed(mutation);
4209 }
4210
4211 self.owner_doc().content_and_heritage_changed(self);
4212 }
4213
4214 fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
4217 self.super_type().unwrap().unbind_from_tree(cx, context);
4218
4219 if !self.is_in_a_shadow_tree() && !self.ranges_is_empty() {
4224 self.ranges()
4225 .drain_to_parent(context.parent, context.index(), self);
4226 }
4227
4228 if self.owner_document().accessibility_active() {
4229 self.owner_document()
4230 .accessibility_data_mut()
4231 .root_removed_node(cx.no_gc(), self);
4232 }
4233 }
4234
4235 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
4236 if let Some(super_type) = self.super_type() {
4237 super_type.moving_steps(cx, context);
4238 }
4239
4240 if let Some(old_parent) = context.old_parent &&
4245 !self.is_in_a_shadow_tree() &&
4246 !self.ranges_is_empty()
4247 {
4248 self.ranges()
4249 .drain_to_parent(old_parent, context.index(), self);
4250 }
4251
4252 self.owner_doc().content_and_heritage_changed(self);
4253 }
4254
4255 fn handle_event(&self, cx: &mut JSContext, event: &Event) {
4256 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4257 return;
4258 }
4259
4260 if let Some(event) = event.downcast::<KeyboardEvent>() {
4261 self.owner_document()
4262 .event_handler()
4263 .run_default_keyboard_event_handler(cx, self, event);
4264 }
4265 }
4266}
4267
4268#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4270pub(crate) enum NodeDamage {
4271 Style,
4273 ContentOrHeritage,
4276 Other,
4278}
4279
4280pub(crate) struct UniqueId {
4282 cell: UnsafeCell<Option<Box<Uuid>>>,
4283}
4284
4285unsafe_no_jsmanaged_fields!(UniqueId);
4286
4287impl MallocSizeOf for UniqueId {
4288 #[expect(unsafe_code)]
4289 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
4290 if let Some(uuid) = unsafe { &*self.cell.get() } {
4291 unsafe { ops.malloc_size_of(&**uuid) }
4292 } else {
4293 0
4294 }
4295 }
4296}
4297
4298impl UniqueId {
4299 pub(super) fn new() -> UniqueId {
4301 UniqueId {
4302 cell: UnsafeCell::new(None),
4303 }
4304 }
4305
4306 #[expect(unsafe_code)]
4308 pub(super) fn borrow(&self) -> &Uuid {
4309 unsafe {
4310 let ptr = self.cell.get();
4311 if (*ptr).is_none() {
4312 *ptr = Some(Box::new(Uuid::new_v4()));
4313 }
4314 (*ptr).as_ref().unwrap()
4315 }
4316 }
4317}
4318
4319pub(crate) trait VecPreOrderInsertionHelper<T> {
4322 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
4323}
4324
4325impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
4326where
4327 T: DerivedFrom<Node> + DomObject,
4328{
4329 fn insert_pre_order(&mut self, node: &T, tree_root: &Node) {
4334 let Err(insertion_index) = self.binary_search_by(|candidate| {
4335 candidate.upcast().compare_dom_tree_position(
4336 node.upcast(),
4337 tree_root,
4338 ShadowIncluding::No,
4339 )
4340 }) else {
4341 return;
4344 };
4345
4346 self.insert(insertion_index, Dom::from_ref(node));
4347 }
4348}