1use std::cell::{Cell, LazyCell};
8use std::cmp::Ordering;
9use std::default::Default;
10use std::f64::consts::PI;
11use std::ops::Deref;
12use std::rc::Rc;
13use std::slice::from_ref;
14use std::{cmp, fmt, iter};
15
16use app_units::Au;
17use bitflags::bitflags;
18use dom_struct::dom_struct;
19use embedder_traits::{MouseButton, 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 AccessibilityDamage, AxesOverflow, BoxAreaType, CSSPixelRectVec, GenericLayoutData,
30 NodeRenderingType, PhysicalSides, TrustedNodeAddress, with_layout_state,
31};
32use libc::{self, uintptr_t};
33use script_bindings::cell::{DomRefCell, Ref, RefMut};
34use script_bindings::codegen::GenericBindings::DocumentTypeBinding::DocumentTypeMethods;
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::domstring::TracedDOMString;
40use script_bindings::reflector::{
41 DomObject, DomObjectWrap, WeakReferenceableDomObjectWrap, reflect_dom_object_with_proto,
42 reflect_weak_referenceable_dom_object_with_proto,
43};
44use script_bindings::trace::{RootedTraceableBox, TraceableSmallVec};
45use script_traits::{DocumentActivity, MouseButtons};
46use servo_base::id::PipelineId;
47use smallvec::SmallVec;
48use style::Atom;
49use style::context::QuirksMode;
50use style::dom::OpaqueNode;
51use style::dom_apis::{QueryAll, QueryFirst};
52use style::selector_parser::PseudoElement;
53use style::values::computed::{Inert, Interactivity};
54use style_traits::CSSPixel;
55use uuid::Uuid;
56use xml5ever::{local_name, serialize as xml_serialize};
57
58use crate::dom::ChildrenMutation;
59use crate::dom::attr::Attr;
60use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
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::comparator::{DomPositionContainment, compare_dom_positions};
87use crate::dom::context::{BindContext, IsShadowTree, MoveContext, UnbindContext};
88use crate::dom::css::cssstylesheet::CSSStyleSheet;
89use crate::dom::css::stylesheetlist::StyleSheetListOwner;
90use crate::dom::customelementregistry::{
91 CallbackReaction, CustomElementRegistry, try_upgrade_element,
92};
93use crate::dom::document::{Document, HasBrowsingContext, IsHTMLDocument};
94use crate::dom::documentfragment::DocumentFragment;
95use crate::dom::documenttype::DocumentType;
96use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
97use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
98use crate::dom::eventtarget::EventTarget;
99use crate::dom::globalscope::GlobalScope;
100use crate::dom::html::htmlcollection::HTMLCollection;
101use crate::dom::html::htmlelement::HTMLElement;
102use crate::dom::html::htmllinkelement::HTMLLinkElement;
103use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
104use crate::dom::html::htmlstyleelement::HTMLStyleElement;
105use crate::dom::iterators::{
106 ShadowIncluding, UnrootedAncestorIterator, UnrootedFollowingFlatTreeNodesTraversal,
107 UnrootedFollowingNodeIterator, UnrootedPrecedingNodeIterator,
108};
109use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
110use crate::dom::node::iterators::{
111 FollowingNodeIterator, PrecedingNodeIterator, SimpleNodeIterator, TreeIterator,
112 UnrootedSimpleNodeIterator, UnrootedTreeIterator,
113};
114use crate::dom::node::nodelist::NodeList;
115use crate::dom::node::virtualmethods::{VirtualMethods, vtable_for};
116use crate::dom::pointerevent::{PointerEvent, PointerId};
117use crate::dom::raredata::NodeRareData;
118use crate::dom::servoparser::html::HtmlSerialize;
119use crate::dom::servoparser::serialize_html_fragment;
120use crate::dom::shadowroot::shadowroot::{IsUserAgentWidget, ShadowRoot};
121use crate::dom::text::Text;
122use crate::dom::traversal::LightDomNoGcTraversal;
123use crate::dom::types::{CDATASection, KeyboardEvent, ProcessingInstruction};
124use crate::dom::window::Window;
125use crate::event_loop::document_loader::DocumentLoader;
126use crate::event_loop::script_thread::ScriptThread;
127use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode};
128
129#[dom_struct]
131pub struct Node {
132 eventtarget: EventTarget,
134
135 parent_node: MutNullableDom<Node>,
137
138 first_child: MutNullableDom<Node>,
140
141 last_child: MutNullableDom<Node>,
143
144 next_sibling: MutNullableDom<Node>,
146
147 prev_sibling: MutNullableDom<Node>,
149
150 owner_doc: MutNullableDom<Document>,
152
153 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
155
156 children_count: Cell<u32>,
158
159 flags: Cell<NodeFlags>,
161
162 inclusive_descendants_version: Cell<u64>,
164
165 #[no_trace]
168 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
169}
170
171impl fmt::Debug for Node {
172 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
173 if let Some(element) = self.downcast::<Element>() {
174 element.fmt(f)
175 } else if let Some(character_data) = self.downcast::<CharacterData>() {
176 write!(f, "[Text({})]", *character_data.data())
177 } else {
178 write!(f, "[Node({:?})]", self.type_id())
179 }
180 }
181}
182
183#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
185pub(crate) struct NodeFlags(u16);
186
187bitflags! {
188 impl NodeFlags: u16 {
189 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
193
194 const HAS_DIRTY_DESCENDANTS = 1 << 1;
196
197 const CLICK_IN_PROGRESS = 1 << 2;
200
201 const HAS_EVER_ANIMATED = 1 << 3;
204
205 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
210
211 const HAS_SNAPSHOT = 1 << 7;
216
217 const HANDLED_SNAPSHOT = 1 << 8;
219
220 const IS_IN_SHADOW_TREE = 1 << 9;
222
223 const IS_CONNECTED = 1 << 10;
227
228 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
231
232 const IS_IN_UA_WIDGET = 1 << 12;
235
236 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
238
239 const OVERLAPS_DOCUMENT_SELECTION = 1 << 14;
246
247 const SELECTION_INHIBITED = 1 << 15;
250 }
251}
252
253#[derive(Clone, Copy, MallocSizeOf)]
257pub(crate) enum SuppressObserver {
258 Suppressed,
259 Unsuppressed,
260}
261
262pub(crate) enum ForceSlottableNodeReconciliation {
263 Force,
264 Skip,
265}
266
267impl Node {
268 pub(super) fn parent_node(&self) -> &MutNullableDom<Node> {
270 &self.parent_node
271 }
272
273 pub(super) fn first_child(&self) -> &MutNullableDom<Node> {
274 &self.first_child
275 }
276
277 pub(super) fn last_child(&self) -> &MutNullableDom<Node> {
278 &self.last_child
279 }
280
281 pub(super) fn next_sibling(&self) -> &MutNullableDom<Node> {
282 &self.next_sibling
283 }
284
285 pub(super) fn prev_sibling(&self) -> &MutNullableDom<Node> {
286 &self.prev_sibling
287 }
288
289 pub(super) fn get_owner_doc(&self) -> &MutNullableDom<Document> {
290 &self.owner_doc
291 }
292
293 pub(super) fn get_rare_data(&self) -> &DomRefCell<Option<Box<NodeRareData>>> {
294 &self.rare_data
295 }
296
297 pub(super) fn flags(&self) -> &Cell<NodeFlags> {
298 &self.flags
299 }
300
301 pub(crate) fn layout_data(&self) -> &DomRefCell<Option<Box<GenericLayoutData>>> {
302 &self.layout_data
303 }
304
305 fn add_child(
309 &self,
310 cx: &mut JSContext,
311 operation: MoveOrInsert,
312 new_child: &Node,
313 before: Option<&Node>,
314 ) {
315 assert!(new_child.parent_node.get().is_none());
316 assert!(new_child.prev_sibling.get().is_none());
317 assert!(new_child.next_sibling.get().is_none());
318
319 self.add_pending_accessibility_damage(cx.no_gc(), AccessibilityDamage::Children);
320
321 match before {
322 Some(before) => {
323 assert!(before.parent_node.get().as_deref() == Some(self));
324 let prev_sibling = before.GetPreviousSibling();
325 match prev_sibling {
326 None => {
327 assert!(self.first_child.get().as_deref() == Some(before));
328 self.first_child.set(Some(new_child));
329 },
330 Some(ref prev_sibling) => {
331 prev_sibling.next_sibling.set(Some(new_child));
332 new_child.prev_sibling.set(Some(prev_sibling));
333 },
334 }
335 before.prev_sibling.set(Some(new_child));
336 new_child.next_sibling.set(Some(before));
337 },
338 None => {
339 let last_child = self.GetLastChild();
340 match last_child {
341 None => self.first_child.set(Some(new_child)),
342 Some(ref last_child) => {
343 assert!(last_child.next_sibling.get().is_none());
344 last_child.next_sibling.set(Some(new_child));
345 new_child.prev_sibling.set(Some(last_child));
346 },
347 }
348
349 self.last_child.set(Some(new_child));
350 },
351 }
352
353 new_child.parent_node.set(Some(self));
354 self.children_count.set(self.children_count.get() + 1);
355
356 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
357 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
358 let parent_is_connected = self.is_connected();
359 let parent_is_in_ua_widget = self.is_in_ua_widget();
360 let context = LazyCell::new(|| BindContext::new(self, IsShadowTree::No));
361
362 for node in new_child.traverse_preorder(ShadowIncluding::No) {
363 if parent_in_shadow_tree {
364 if let Some(shadow_root) = self.containing_shadow_root() {
365 node.set_containing_shadow_root(Some(&*shadow_root));
366 }
367 debug_assert!(node.containing_shadow_root().is_some());
368 }
369 node.set_flag(
370 NodeFlags::IS_IN_A_DOCUMENT_TREE,
371 parent_is_in_a_document_tree,
372 );
373 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
374 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
375 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
376
377 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
379
380 match operation {
381 MoveOrInsert::Move => {
382 if (parent_is_in_a_document_tree || parent_in_shadow_tree) &&
383 let Some(element) = node.downcast::<Element>()
384 {
385 element.register_current_id_and_name_attribute(cx);
386 }
387 },
388 MoveOrInsert::Insert => vtable_for(&node).bind_to_tree(cx, &context),
389 }
390 }
391 }
392
393 pub(crate) fn complete_remove_subtree(
396 cx: &mut JSContext,
397 root: &Node,
398 context: &UnbindContext,
399 ) {
400 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
402 .union(NodeFlags::IS_CONNECTED)
403 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
404 .union(NodeFlags::HAS_SNAPSHOT)
405 .union(NodeFlags::HANDLED_SNAPSHOT)
406 .union(NodeFlags::OVERLAPS_DOCUMENT_SELECTION)
407 .union(NodeFlags::SELECTION_INHIBITED);
408
409 for node in root.traverse_preorder_unrooted(cx.no_gc(), ShadowIncluding::No) {
410 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
411
412 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
415 for node in shadow_root
416 .upcast::<Node>()
417 .traverse_preorder_unrooted(cx.no_gc(), ShadowIncluding::Yes)
418 {
419 node.set_flag(RESET_FLAGS, false);
420 }
421 }
422 }
423
424 let is_parent_connected = context.parent.is_connected();
426 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
427
428 let cleanup_node = |cx: &mut JSContext, node: &Node| {
431 let document = node.owner_document_unrooted(cx.no_gc());
432 document.cancel_animations_for_node(node);
433 document.clean_up_style_and_layout_data_for_node(node);
434
435 vtable_for(node).unbind_from_tree(cx, context);
440
441 if is_parent_connected && let Some(element) = node.as_custom_element() {
443 custom_element_reaction_stack.enqueue_callback_reaction(
444 cx,
445 &element,
446 CallbackReaction::Disconnected,
447 None,
448 );
449 }
450 };
451
452 for node in root.traverse_preorder(ShadowIncluding::No) {
453 cleanup_node(cx, &node);
454
455 if node.containing_shadow_root().is_some() {
458 node.set_containing_shadow_root(None);
461 }
462
463 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
466 for node in shadow_root
467 .upcast::<Node>()
468 .traverse_preorder(ShadowIncluding::Yes)
469 {
470 cleanup_node(cx, &node);
471 }
472 }
473 }
474
475 let no_gc = cx.no_gc();
478 let document = root.owner_document_unrooted(no_gc);
479 if document.accessibility_active() {
480 document
481 .accessibility_data_mut()
482 .root_removed_node(no_gc, root);
483 }
484 }
485
486 pub(crate) fn complete_move_subtree(cx: &mut JSContext, root: &Node) {
487 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
489 .union(NodeFlags::IS_CONNECTED)
490 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
491 .union(NodeFlags::HAS_SNAPSHOT)
492 .union(NodeFlags::HANDLED_SNAPSHOT)
493 .union(NodeFlags::OVERLAPS_DOCUMENT_SELECTION)
494 .union(NodeFlags::SELECTION_INHIBITED);
495
496 let document = root.owner_document();
497 for node in root.traverse_preorder(ShadowIncluding::No) {
498 let node_was_in_tree = node.is_in_a_document_tree() || node.is_in_a_shadow_tree();
499
500 node.set_flag(
503 (RESET_FLAGS - NodeFlags::IS_CONNECTED) | NodeFlags::IS_IN_SHADOW_TREE,
504 false,
505 );
506 document.clean_up_style_and_layout_data_for_node(&node);
507
508 if node_was_in_tree && let Some(element) = node.downcast::<Element>() {
511 element.unregister_current_id_and_name_attribute(cx);
512 }
513
514 if node.containing_shadow_root().is_some() {
517 node.set_containing_shadow_root(None);
520 }
521
522 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
526 for node in shadow_root
527 .upcast::<Node>()
528 .traverse_preorder(ShadowIncluding::Yes)
529 {
530 node.set_flag(RESET_FLAGS - NodeFlags::IS_CONNECTED, false);
533 document.clean_up_style_and_layout_data_for_node(&node);
534 }
535 }
536 }
537 }
538
539 fn remove_child(&self, cx: &mut JSContext, child: &Node) {
543 assert!(child.parent_node.get().as_deref() == Some(self));
544
545 if let Some(element) = self.downcast::<Element>() {
546 element.note_dirty_descendants(cx.no_gc());
547 }
548 self.add_pending_accessibility_damage(cx.no_gc(), AccessibilityDamage::Children);
549
550 let prev_sibling = child.GetPreviousSibling();
551 match prev_sibling {
552 None => {
553 self.first_child.set(child.next_sibling.get().as_deref());
554 },
555 Some(ref prev_sibling) => {
556 prev_sibling
557 .next_sibling
558 .set(child.next_sibling.get().as_deref());
559 },
560 }
561 let next_sibling = child.GetNextSibling();
562 match next_sibling {
563 None => {
564 self.last_child.set(child.prev_sibling.get().as_deref());
565 },
566 Some(ref next_sibling) => {
567 next_sibling
568 .prev_sibling
569 .set(child.prev_sibling.get().as_deref());
570 },
571 }
572
573 let context = UnbindContext::new(self, next_sibling.as_deref());
574
575 child.prev_sibling.set(None);
576 child.next_sibling.set(None);
577 child.parent_node.set(None);
578 self.children_count.set(self.children_count.get() - 1);
579
580 Self::complete_remove_subtree(cx, child, &context);
581 }
582
583 fn move_child(&self, cx: &mut JSContext, child: &Node) {
584 assert!(child.parent_node.get().as_deref() == Some(self));
585 self.dirty(cx.no_gc(), NodeDamage::ContentOrHeritage);
586 if let Some(element) = self.downcast::<Element>() {
587 element.note_dirty_descendants(cx.no_gc());
588 }
589
590 self.add_pending_accessibility_damage(cx.no_gc(), AccessibilityDamage::Children);
591
592 child.prev_sibling.set(None);
593 child.next_sibling.set(None);
594 child.parent_node.set(None);
595 self.children_count.set(self.children_count.get() - 1);
596 Self::complete_move_subtree(cx, child)
597 }
598
599 pub(crate) fn to_opaque(&self) -> OpaqueNode {
600 OpaqueNode(self.reflector().get_jsobject().get() as usize)
601 }
602
603 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
604 self.downcast::<Element>().and_then(|element| {
605 if element.is_custom() {
606 assert!(element.get_custom_element_definition().is_some());
607 Some(DomRoot::from_ref(element))
608 } else {
609 None
610 }
611 })
612 }
613
614 pub(crate) fn fire_synthetic_pointer_event_not_trusted(
616 &self,
617 cx: &mut JSContext,
618 event_type: Atom,
619 ) {
620 let window = self.owner_window();
624
625 let pointer_event = PointerEvent::new(
627 cx,
628 &window, event_type,
630 EventBubbles::Bubbles, EventCancelable::Cancelable, Some(&window), 0, Point2D::zero(), Point2D::zero(), Point2D::zero(), Modifiers::empty(), MouseButton::Primary, MouseButtons::empty(), None, None, PointerId::NonPointerDevice as i32, 1, 1, 0.5, 0.0, 0, 0, 0, PI / 2.0, 0.0, DOMString::new(), false, vec![], vec![], );
657
658 pointer_event.upcast::<Event>().set_composed(true);
660
661 pointer_event.upcast::<Event>().set_trusted(false);
663
664 pointer_event
667 .upcast::<Event>()
668 .dispatch(cx, self.upcast::<EventTarget>(), false);
669 }
670
671 pub(crate) fn parent_directionality(&self) -> String {
672 let mut current = self.GetParentNode();
673
674 loop {
675 match current {
676 Some(node) => {
677 if let Some(directionality) = node
678 .downcast::<HTMLElement>()
679 .and_then(|html_element| html_element.directionality())
680 {
681 return directionality;
682 } else {
683 current = node.GetParentNode();
684 }
685 },
686 None => return "ltr".to_owned(),
687 }
688 }
689 }
690
691 pub(crate) fn is_being_rendered_or_delegates_rendering(
695 &self,
696 pseudo_element: Option<PseudoElement>,
697 ) -> bool {
698 matches!(
699 self.owner_window()
700 .layout()
701 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
702 NodeRenderingType::Rendered | NodeRenderingType::DelegatesRendering
703 )
704 }
705
706 pub(crate) fn is_being_rendered(&self, pseudo_element: Option<PseudoElement>) -> bool {
708 matches!(
709 self.owner_window()
710 .layout()
711 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
712 NodeRenderingType::Rendered
713 )
714 }
715
716 pub(crate) fn add_pending_accessibility_damage(
717 &self,
718 no_gc: &NoGC,
719 damage: AccessibilityDamage,
720 ) {
721 let document = self.owner_document_unrooted(no_gc);
722 if document.accessibility_active() {
723 document
724 .accessibility_data_mut()
725 .add_pending_accessibility_damage_for_node(self, damage);
726 }
727 }
728
729 pub(crate) fn set_element_selection(&self, selected: bool) -> bool {
732 debug_assert!(
733 self.downcast::<CharacterData>().is_none(),
734 "Should never be called on CharacterData"
735 );
736 self.layout_data()
737 .borrow()
738 .as_ref()
739 .is_some_and(|layout_data| layout_data.set_element_selection(selected))
740 }
741}
742
743impl Node {
744 fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
745 let mut rare_data = self.rare_data.borrow_mut();
746 if rare_data.is_none() {
747 *rare_data = Some(Default::default());
748 }
749 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
750 }
751
752 pub(crate) fn is_before(&self, no_gc: &NoGC, other: &Node) -> bool {
755 let cmp = other.CompareDocumentPosition(no_gc, self);
756 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
757 return false;
758 }
759
760 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
761 }
762
763 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
766 RefMut::map(self.ensure_rare_data(), |rare_data| {
767 &mut rare_data.mutation_observers
768 })
769 }
770
771 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
772 let rare_data = self.rare_data.borrow();
773 if rare_data.is_none() {
774 return None;
775 }
776 Some(Ref::map(rare_data, |rare_data| {
777 &rare_data.as_ref().unwrap().mutation_observers
778 }))
779 }
780
781 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
783 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
784 self.ensure_rare_data().mutation_observers.push(observer);
785 }
786
787 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
789 let mut rare_data = self.rare_data.borrow_mut();
790 let Some(rare_data) = rare_data.as_mut() else {
791 return;
792 };
793 rare_data
794 .mutation_observers
795 .retain(|registered_observer| &*registered_observer.observer != observer)
796 }
797
798 pub(crate) fn debug_str(&self) -> String {
800 format!("{:?}", self.type_id())
801 }
802
803 pub(crate) fn is_in_a_document_tree(&self) -> bool {
805 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
806 }
807
808 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
810 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
811 }
812
813 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
814 self.flags
815 .get()
816 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
817 }
818
819 pub(crate) fn set_weird_parser_insertion_mode(&self) {
820 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
821 }
822
823 pub(crate) fn is_connected(&self) -> bool {
825 self.flags.get().contains(NodeFlags::IS_CONNECTED)
826 }
827
828 pub(crate) fn is_in_flat_tree(&self, no_gc: &NoGC) -> bool {
833 if !self.is_connected() {
834 return false;
835 }
836
837 let mut node = UnrootedDom::from_ref(self, no_gc);
838 loop {
839 match node.parent_in_flat_tree(no_gc) {
840 FlatTreeParent::Parent(parent) => node = parent,
841 FlatTreeParent::NotInFlatTree => return false,
842 FlatTreeParent::RootNode => return true,
843 }
844 }
845 }
846
847 pub(crate) fn mark_in_ua_widget(&self) {
848 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, true)
849 }
850
851 pub(crate) fn is_in_ua_widget(&self) -> bool {
852 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
853 }
854
855 pub(crate) fn type_id(&self) -> NodeTypeId {
857 match *self.eventtarget.type_id() {
858 EventTargetTypeId::Node(type_id) => type_id,
859 _ => unreachable!(),
860 }
861 }
862
863 pub(crate) fn len(&self) -> u32 {
865 match self.type_id() {
866 NodeTypeId::DocumentType => 0,
867 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
868 _ => self.children_count(),
869 }
870 }
871
872 pub(crate) fn is_empty(&self) -> bool {
873 self.len() == 0
875 }
876
877 pub(crate) fn index(&self) -> u32 {
879 self.preceding_siblings().count() as u32
880 }
881
882 pub(crate) fn has_parent(&self) -> bool {
884 self.parent_node.get().is_some()
885 }
886
887 pub(crate) fn children_count(&self) -> u32 {
888 self.children_count.get()
889 }
890
891 #[inline]
892 pub(crate) fn is_doctype(&self) -> bool {
893 self.type_id() == NodeTypeId::DocumentType
894 }
895
896 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
897 self.flags.get().contains(flag)
898 }
899
900 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
901 let mut flags = self.flags.get();
902
903 if value {
904 flags.insert(flag);
905 } else {
906 flags.remove(flag);
907 }
908
909 self.flags.set(flags);
910 }
911
912 pub(crate) fn rev_version(&self, no_gc: &NoGC) {
913 let document = UnrootedDom::upcast::<Node>(self.owner_doc_unrooted(no_gc));
918 let version = cmp::max(
919 self.inclusive_descendants_version(),
920 document.inclusive_descendants_version(),
921 ) + 1;
922
923 for node in self.inclusive_ancestors_unrooted(no_gc, ShadowIncluding::No) {
924 node.inclusive_descendants_version.set(version);
925 }
926 document.inclusive_descendants_version.set(version);
927 }
928
929 pub(crate) fn clear_layout_data(&self) {
930 self.layout_data.take();
931 }
932
933 pub(crate) fn dirty(&self, no_gc: &NoGC, damage: NodeDamage) {
934 self.rev_version(no_gc);
935 if !self.is_connected() {
936 return;
937 }
938
939 match self.type_id() {
940 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..)) => {
941 *self.layout_data.borrow_mut() = None;
944
945 if let Some(parent) = self.parent_node.get() {
951 parent.dirty(no_gc, NodeDamage::ContentOrHeritage);
952 }
953
954 if damage == NodeDamage::Other {
955 self.add_pending_accessibility_damage(no_gc, AccessibilityDamage::Node);
956 }
957 },
958 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(no_gc, damage),
959 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
960 .downcast::<ShadowRoot>()
961 .unwrap()
962 .Host()
963 .upcast::<Element>()
964 .restyle(no_gc, damage),
965 _ => {},
966 };
967 }
968
969 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
971 self.inclusive_descendants_version.get()
972 }
973
974 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
976 TreeIterator::new(self, shadow_including)
977 }
978
979 pub(crate) fn traverse_preorder_unrooted<'b>(
982 &self,
983 no_gc: &'b NoGC,
984 shadow_including: ShadowIncluding,
985 ) -> UnrootedTreeIterator<'b> {
986 UnrootedTreeIterator::new(self, shadow_including, no_gc)
987 }
988
989 pub(crate) fn inclusively_following_siblings(
990 &self,
991 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
992 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), |n| n.GetNextSibling())
993 }
994
995 pub(crate) fn inclusively_following_siblings_unrooted<'b>(
996 &self,
997 no_gc: &'b NoGC,
998 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
999 UnrootedSimpleNodeIterator::new(
1000 Some(UnrootedDom::from_ref(self, no_gc)),
1001 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1002 no_gc,
1003 )
1004 }
1005
1006 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
1007 &self,
1008 no_gc: &'b NoGC,
1009 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
1010 UnrootedSimpleNodeIterator::new(
1011 Some(UnrootedDom::from_ref(self, no_gc)),
1012 |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
1013 no_gc,
1014 )
1015 }
1016
1017 pub(crate) fn common_ancestor(
1018 &self,
1019 other: &Node,
1020 shadow_including: ShadowIncluding,
1021 ) -> Option<DomRoot<Node>> {
1022 self.inclusive_ancestors(shadow_including).find(|ancestor| {
1023 other
1024 .inclusive_ancestors(shadow_including)
1025 .any(|node| node == *ancestor)
1026 })
1027 }
1028
1029 pub(crate) fn common_ancestor_in_flat_tree(
1030 &self,
1031 no_gc: &NoGC,
1032 other: &Node,
1033 ) -> Option<DomRoot<Node>> {
1034 self.inclusive_ancestors_in_flat_tree_unrooted(no_gc)
1035 .find(|ancestor| {
1036 other
1037 .inclusive_ancestors_in_flat_tree_unrooted(no_gc)
1038 .any(|node| node == *ancestor)
1039 })
1040 .map(|node| node.as_rooted())
1041 }
1042
1043 pub(crate) fn following_flat_tree_nodes_unrooted<'no_gc>(
1044 &self,
1045 no_gc: &'no_gc NoGC,
1046 ) -> UnrootedFollowingFlatTreeNodesTraversal<'no_gc> {
1047 UnrootedFollowingFlatTreeNodesTraversal::new(self, no_gc)
1048 }
1049
1050 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
1052 self == child || self.is_ancestor_of(child)
1054 }
1055
1056 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
1058 let mut current = &possible_descendant.parent_node;
1060 let mut done = false;
1061
1062 while let Some(node) = current.if_is_some(|node| {
1063 done = node == self;
1064 &node.parent_node
1065 }) {
1066 if done {
1067 break;
1068 }
1069 current = node
1070 }
1071 done
1072 }
1073
1074 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
1076 self.is_inclusive_ancestor_of(child) ||
1079 child
1080 .GetRootNode(&GetRootNodeOptions::empty())
1081 .downcast::<DocumentFragment>()
1082 .and_then(|fragment| fragment.host())
1083 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1084 }
1085
1086 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1088 node.inclusive_ancestors(ShadowIncluding::Yes)
1089 .any(|ancestor| &*ancestor == self)
1090 }
1091
1092 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1093 SimpleNodeIterator::new(self.GetNextSibling(), |n| n.GetNextSibling())
1094 }
1095
1096 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1097 SimpleNodeIterator::new(self.GetPreviousSibling(), |n| n.GetPreviousSibling())
1098 }
1099
1100 pub(crate) fn following_nodes(
1101 &self,
1102 root: &Node,
1103 shadow_including: ShadowIncluding,
1104 ) -> FollowingNodeIterator {
1105 FollowingNodeIterator::new(
1106 Some(DomRoot::from_ref(self)),
1107 DomRoot::from_ref(root),
1108 shadow_including,
1109 )
1110 }
1111
1112 pub(crate) fn following_nodes_unrooted<'b>(
1113 &self,
1114 no_gc: &'b NoGC,
1115 root: &Node,
1116 shadow_including: ShadowIncluding,
1117 ) -> UnrootedFollowingNodeIterator<'b> {
1118 UnrootedFollowingNodeIterator::new(
1119 Some(UnrootedDom::from_ref(self, no_gc)),
1120 UnrootedDom::from_ref(root, no_gc),
1121 shadow_including,
1122 no_gc,
1123 )
1124 }
1125
1126 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1127 PrecedingNodeIterator::new(Some(DomRoot::from_ref(self)), DomRoot::from_ref(root))
1128 }
1129
1130 pub(crate) fn preceding_nodes_unrooted<'b>(
1131 &self,
1132 no_gc: &'b NoGC,
1133 root: &Node,
1134 ) -> UnrootedPrecedingNodeIterator<'b> {
1135 UnrootedPrecedingNodeIterator::new(
1136 Some(UnrootedDom::from_ref(self, no_gc)),
1137 UnrootedDom::from_ref(root, no_gc),
1138 no_gc,
1139 )
1140 }
1141
1142 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1145 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetLastChild())
1146 }
1147
1148 pub(crate) fn descending_last_children_unrooted<'b>(
1149 &self,
1150 no_gc: &'b NoGC,
1151 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> {
1152 UnrootedSimpleNodeIterator::new(
1153 self.get_last_child_unrooted(no_gc),
1154 |n, no_gc| n.get_last_child_unrooted(no_gc),
1155 no_gc,
1156 )
1157 }
1158
1159 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1160 child
1161 .parent_node
1162 .get()
1163 .is_some_and(|parent| &*parent == self)
1164 }
1165
1166 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1167 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1168 }
1169
1170 pub(crate) fn containing_block_node_without_reflow(&self) -> Option<DomRoot<Node>> {
1172 self.owner_window()
1173 .containing_block_node_query_without_reflow(self)
1174 }
1175
1176 pub(crate) fn padding(&self) -> Option<PhysicalSides<Au>> {
1177 self.owner_window().padding_query_without_reflow(self)
1178 }
1179
1180 pub(crate) fn content_box(&self, cx: &mut JSContext) -> Option<Rect<Au, CSSPixel>> {
1181 self.owner_window()
1182 .box_area_query(cx, self, BoxAreaType::Content, false)
1183 }
1184
1185 pub(crate) fn border_box(&self, cx: &mut JSContext) -> Option<Rect<Au, CSSPixel>> {
1186 self.owner_window()
1187 .box_area_query(cx, self, BoxAreaType::Border, false)
1188 }
1189
1190 pub(crate) fn border_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1191 self.owner_window()
1192 .box_area_query_without_reflow(self, BoxAreaType::Border, false)
1193 }
1194
1195 pub(crate) fn padding_box(&self, cx: &mut JSContext) -> Option<Rect<Au, CSSPixel>> {
1196 self.owner_window()
1197 .box_area_query(cx, self, BoxAreaType::Padding, false)
1198 }
1199
1200 pub(crate) fn padding_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1201 self.owner_window()
1202 .box_area_query_without_reflow(self, BoxAreaType::Padding, false)
1203 }
1204
1205 pub(crate) fn border_boxes(&self, cx: &mut JSContext) -> CSSPixelRectVec {
1206 self.owner_window()
1207 .box_areas_query(cx, self, BoxAreaType::Border)
1208 }
1209
1210 pub(crate) fn client_rect(&self, cx: &mut JSContext) -> Rect<i32, CSSPixel> {
1211 self.owner_window().client_rect_query(cx, self)
1212 }
1213
1214 pub(crate) fn scroll_area(&self, cx: &mut JSContext) -> Rect<i32, CSSPixel> {
1217 let document = self.owner_doc();
1219
1220 if !document.is_active() {
1222 return Rect::zero();
1223 }
1224
1225 let window = document.window();
1228 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1229
1230 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1231 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1232 let is_body_element = self
1233 .downcast::<HTMLElement>()
1234 .is_some_and(|e| e.is_body_element());
1235
1236 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1242 let viewport_scrolling_area = window.scrolling_area_query(cx, None);
1243 return Rect::new(
1244 viewport_scrolling_area.origin,
1245 viewport_scrolling_area.size.max(viewport),
1246 );
1247 }
1248
1249 window.scrolling_area_query(cx, Some(self))
1253 }
1254
1255 pub(crate) fn effective_overflow(&self, cx: &mut JSContext) -> Option<AxesOverflow> {
1256 self.owner_window().query_effective_overflow(cx, self)
1257 }
1258
1259 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1260 self.owner_window()
1261 .query_effective_overflow_without_reflow(self)
1262 }
1263
1264 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1266 let parent = &self.parent_node;
1268
1269 let parent = match parent.get() {
1271 None => return Ok(()),
1272 Some(parent) => parent,
1273 };
1274
1275 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1277
1278 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1280
1281 let viable_previous_sibling = match viable_previous_sibling {
1283 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1284 None => parent.first_child.get(),
1285 };
1286
1287 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1289
1290 Ok(())
1291 }
1292
1293 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1295 let parent = &self.parent_node;
1297
1298 let parent = match parent.get() {
1300 None => return Ok(()),
1301 Some(parent) => parent,
1302 };
1303
1304 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1306
1307 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1309
1310 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1312
1313 Ok(())
1314 }
1315
1316 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1318 let Some(parent) = self.GetParentNode() else {
1320 return Ok(());
1322 };
1323
1324 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1326
1327 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1329
1330 if self.parent_node == Some(&*parent) {
1331 parent.ReplaceChild(cx, &node, self)?;
1333 } else {
1334 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1336 }
1337 Ok(())
1338 }
1339
1340 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1342 let doc = self.owner_doc();
1344 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1345 let first_child = self.first_child.get();
1347 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1348 }
1349
1350 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1352 let doc = self.owner_doc();
1354 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1355 self.AppendChild(cx, &node).map(|_| ())
1357 }
1358
1359 pub(crate) fn replace_children(
1361 &self,
1362 cx: &mut JSContext,
1363 nodes: Vec<NodeOrString>,
1364 ) -> ErrorResult {
1365 let doc = self.owner_doc();
1368 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1369
1370 Node::ensure_pre_insertion_validity(cx.no_gc(), &node, self, None, &[])?;
1372
1373 Node::replace_all(cx, Some(&node), self);
1375 Ok(())
1376 }
1377
1378 pub(crate) fn move_before(
1380 &self,
1381 cx: &mut JSContext,
1382 node: &Node,
1383 child: Option<&Node>,
1384 ) -> ErrorResult {
1385 let reference_child_root;
1388 let reference_child = match child {
1389 Some(child) if child == node => {
1390 reference_child_root = node.GetNextSibling();
1391 reference_child_root.as_deref()
1392 },
1393 _ => child,
1394 };
1395
1396 Node::move_fn(cx, node, self, reference_child)
1398 }
1399
1400 fn move_fn(
1402 cx: &mut JSContext,
1403 node: &Node,
1404 new_parent: &Node,
1405 child: Option<&Node>,
1406 ) -> ErrorResult {
1407 let mut options = GetRootNodeOptions::empty();
1412 options.composed = true;
1413 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1414 return Err(Error::HierarchyRequest(Some(
1415 "The `newParent` node's shadow root is not the same as the `node`'s shadow root"
1416 .into(),
1417 )));
1418 }
1419
1420 if node.is_host_including_inclusive_ancestor(new_parent) {
1423 return Err(Error::HierarchyRequest(Some(
1424 "`node` node cannot be the inclusive ancestor of the `newParent` node".into(),
1425 )));
1426 }
1427
1428 if let Some(child) = child &&
1431 !new_parent.is_parent_of(child)
1432 {
1433 return Err(Error::NotFound(Some(
1434 "`child` node's parent node is not `newParent`".into(),
1435 )));
1436 }
1437
1438 match node.type_id() {
1443 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1444 if new_parent.is::<Document>() {
1445 return Err(Error::HierarchyRequest(Some(
1446 "`node` cannot be a text node when `newParent` is a document".into(),
1447 )));
1448 }
1449 },
1450 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1451 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1452 NodeTypeId::Element(_) => (),
1453 NodeTypeId::DocumentFragment(_) |
1454 NodeTypeId::DocumentType |
1455 NodeTypeId::Document(_) |
1456 NodeTypeId::Attr => {
1457 return Err(Error::HierarchyRequest(Some(
1458 "To move `node` into a `newParent`, it must be an Element".into(),
1459 )));
1460 },
1461 }
1462
1463 if new_parent.is::<Document>() && node.is::<Element>() {
1467 if new_parent.child_elements().next().is_some() {
1469 return Err(Error::HierarchyRequest(Some(
1470 "`newParent` document cannot have an element child".into(),
1471 )));
1472 }
1473
1474 if child.is_some_and(|child| {
1477 child
1478 .inclusively_following_siblings_unrooted(cx.no_gc())
1479 .any(|child| child.is_doctype())
1480 }) {
1481 return Err(Error::HierarchyRequest(Some(
1482 "`child` node has a document node following it".into(),
1483 )));
1484 }
1485 }
1486
1487 let old_parent = node
1490 .parent_node
1491 .get()
1492 .expect("old_parent should always be initialized");
1493
1494 let document = node.owner_doc_unrooted(cx.no_gc());
1496 let mut cached_index = None;
1497 let mut lazy_index = || *cached_index.get_or_insert_with(|| node.index());
1498 if let Some(selection) = document.selection() {
1499 selection.pre_remove_steps(node, &old_parent, &mut lazy_index);
1500 }
1501 document.live_range_pre_remove_steps(cx.no_gc(), node, &old_parent, &mut lazy_index);
1502
1503 let old_previous_sibling = node.prev_sibling.get();
1508
1509 let old_next_sibling = node.next_sibling.get();
1511
1512 let prev_sibling = node.GetPreviousSibling();
1513 match prev_sibling {
1514 None => {
1515 old_parent
1516 .first_child
1517 .set(node.next_sibling.get().as_deref());
1518 },
1519 Some(ref prev_sibling) => {
1520 prev_sibling
1521 .next_sibling
1522 .set(node.next_sibling.get().as_deref());
1523 },
1524 }
1525 let next_sibling = node.GetNextSibling();
1526 match next_sibling {
1527 None => {
1528 old_parent
1529 .last_child
1530 .set(node.prev_sibling.get().as_deref());
1531 },
1532 Some(ref next_sibling) => {
1533 next_sibling
1534 .prev_sibling
1535 .set(node.prev_sibling.get().as_deref());
1536 },
1537 }
1538
1539 old_parent.move_child(cx, node);
1541
1542 if let Some(slot) = node.assigned_slot() {
1544 slot.assign_slottables(cx);
1545 }
1546
1547 if old_parent.is_in_a_shadow_tree() &&
1550 let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() &&
1551 !slot_element.has_assigned_nodes()
1552 {
1553 slot_element.signal_a_slot_change(cx);
1554 }
1555
1556 let has_slot_descendant = node
1558 .traverse_preorder_unrooted(cx.no_gc(), ShadowIncluding::No)
1559 .any(|element| element.is::<HTMLSlotElement>());
1560 if has_slot_descendant {
1561 old_parent
1563 .GetRootNode(&GetRootNodeOptions::empty())
1564 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1565
1566 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1568 }
1569
1570 if let Some(child) = child {
1575 let document = new_parent.owner_doc_unrooted(cx.no_gc());
1577 if let Some(selection) = document.selection() {
1578 selection.insert_steps(new_parent, child, 1);
1579 }
1580 document.live_range_insert_steps(cx.no_gc(), new_parent, child, 1);
1581 }
1582
1583 let new_previous_sibling = child.map_or_else(
1586 || new_parent.last_child.get(),
1587 |child| child.prev_sibling.get(),
1588 );
1589
1590 new_parent.add_child(cx, MoveOrInsert::Move, node, child);
1593
1594 if let Some(shadow_root) = new_parent
1597 .downcast::<Element>()
1598 .and_then(Element::shadow_root) &&
1599 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1600 (node.is::<Element>() || node.is::<Text>())
1601 {
1602 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1603 slottable.assign_a_slot(cx);
1604 }
1605
1606 if new_parent.is_in_a_shadow_tree() &&
1609 let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() &&
1610 !slot_element.has_assigned_nodes()
1611 {
1612 slot_element.signal_a_slot_change(cx);
1613 }
1614
1615 node.GetRootNode(&GetRootNodeOptions::empty())
1617 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1618
1619 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1622 let is_subtree_root = descendant.deref() == node;
1624 vtable_for(&descendant)
1626 .moving_steps(cx, &MoveContext::new(&old_parent, is_subtree_root));
1627
1628 if let Some(descendant) = descendant.downcast::<Element>() &&
1630 descendant.is_custom() &&
1631 new_parent.is_connected()
1632 {
1633 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
1636 custom_element_reaction_stack.enqueue_callback_reaction(
1637 cx,
1638 descendant,
1639 CallbackReaction::ConnectedMove,
1640 None,
1641 );
1642 }
1643 }
1644
1645 let moved = [node];
1648 let mutation = LazyCell::new(|| Mutation::ChildList {
1649 added: None,
1650 removed: Some(&moved),
1651 prev: old_previous_sibling.as_deref(),
1652 next: old_next_sibling.as_deref(),
1653 });
1654 MutationObserver::queue_a_mutation_record(cx, &old_parent, mutation);
1655
1656 let mutation = LazyCell::new(|| Mutation::ChildList {
1659 added: Some(&moved),
1660 removed: None,
1661 prev: new_previous_sibling.as_deref(),
1662 next: child,
1663 });
1664 MutationObserver::queue_a_mutation_record(cx, new_parent, mutation);
1665
1666 Ok(())
1667 }
1668
1669 #[allow(unsafe_code)]
1671 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1672 pub(crate) fn query_selector(
1673 &self,
1674 no_gc: &NoGC,
1675 selectors: DOMString,
1676 ) -> Fallible<Option<DomRoot<Element>>> {
1677 let document_url = self.owner_document().url().get_arc();
1680
1681 self.owner_document()
1684 .id_map()
1685 .resolve_all(no_gc, self.owner_doc().upcast());
1686
1687 let traced_node = Dom::from_ref(self);
1689
1690 let first_matching_element = with_layout_state(|| {
1691 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1692 ServoDangerousStyleNode::from(layout_node)
1693 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1694 })?;
1695
1696 Ok(first_matching_element.map(ServoDangerousStyleElement::rooted))
1697 }
1698
1699 #[allow(unsafe_code)]
1701 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1702 pub(crate) fn query_selector_all(
1703 &self,
1704 cx: &mut JSContext,
1705 selectors: DOMString,
1706 ) -> Fallible<DomRoot<NodeList>> {
1707 let document_url = self.owner_document().url().get_arc();
1710
1711 self.owner_document()
1714 .id_map()
1715 .resolve_all(cx.no_gc(), self.owner_doc().upcast());
1716
1717 let unrooted_node = UnrootedDom::from_ref(self, cx.no_gc());
1718 let matching_elements = with_layout_state(|| {
1719 let layout_node: LayoutDom<'_, _> = unsafe { unrooted_node.to_layout() };
1720 ServoDangerousStyleNode::from(layout_node)
1721 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1722 })?;
1723 let iter = matching_elements
1724 .into_iter()
1725 .map(ServoDangerousStyleElement::rooted)
1726 .map(DomRoot::upcast::<Node>);
1727
1728 Ok(NodeList::new_simple_list(cx, &self.owner_window(), iter))
1731 }
1732
1733 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1734 SimpleNodeIterator::new(self.GetParentNode(), |n| n.GetParentNode())
1735 }
1736
1737 pub(crate) fn ancestors_unrooted<'a>(&self, no_gc: &'a NoGC) -> UnrootedAncestorIterator<'a> {
1738 UnrootedSimpleNodeIterator::new(
1739 self.get_parent_node_unrooted(no_gc),
1740 |node, no_gc| node.get_parent_node_unrooted(no_gc),
1741 no_gc,
1742 )
1743 }
1744
1745 pub(crate) fn inclusive_ancestors(
1747 &self,
1748 shadow_including: ShadowIncluding,
1749 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1750 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |n| {
1751 if shadow_including == ShadowIncluding::Yes &&
1752 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1753 {
1754 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1755 }
1756 n.GetParentNode()
1757 })
1758 }
1759
1760 pub(crate) fn inclusive_ancestors_unrooted<'a>(
1761 &self,
1762 no_gc: &'a NoGC,
1763 shadow_including: ShadowIncluding,
1764 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1765 UnrootedSimpleNodeIterator::new(
1766 Some(UnrootedDom::from_ref(self, no_gc)),
1767 move |node, no_gc| {
1768 if shadow_including == ShadowIncluding::Yes &&
1769 let Some(shadow_root) = node.downcast::<ShadowRoot>()
1770 {
1771 return Some(UnrootedDom::upcast(shadow_root.host_unrooted(no_gc)));
1772 }
1773 node.get_parent_node_unrooted(no_gc)
1774 },
1775 no_gc,
1776 )
1777 }
1778
1779 pub(crate) fn ancestors_in_flat_tree_unrooted<'a>(
1780 &self,
1781 no_gc: &'a NoGC,
1782 ) -> UnrootedAncestorIterator<'a> {
1783 UnrootedSimpleNodeIterator::new(
1784 self.parent_in_flat_tree(no_gc).into_parent(),
1785 |node, no_gc| node.parent_in_flat_tree(no_gc).into_parent(),
1786 no_gc,
1787 )
1788 }
1789
1790 pub(crate) fn inclusive_ancestors_in_flat_tree_unrooted<'a>(
1791 &self,
1792 no_gc: &'a NoGC,
1793 ) -> UnrootedAncestorIterator<'a> {
1794 UnrootedSimpleNodeIterator::new(
1795 Some(UnrootedDom::from_ref(self, no_gc)),
1796 |node, no_gc| node.parent_in_flat_tree(no_gc).into_parent(),
1797 no_gc,
1798 )
1799 }
1800
1801 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1802 self.owner_doc.get().unwrap()
1803 }
1804
1805 pub(crate) fn owner_doc_unrooted<'a>(&self, no_gc: &'a NoGC) -> UnrootedDom<'a, Document> {
1806 self.owner_doc.get_unrooted(no_gc).unwrap()
1807 }
1808
1809 pub(crate) fn set_owner_doc(&self, document: &Document) {
1810 self.owner_doc.set(Some(document));
1811 }
1812
1813 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1814 self.rare_data
1815 .borrow()
1816 .as_ref()?
1817 .containing_shadow_root
1818 .as_ref()
1819 .map(|shadow_root| DomRoot::from_ref(&**shadow_root))
1820 }
1821
1822 pub(crate) fn containing_shadow_root_unrooted<'a>(
1823 &self,
1824 no_gc: &'a NoGC,
1825 ) -> Option<UnrootedDom<'a, ShadowRoot>> {
1826 self.rare_data
1827 .borrow()
1828 .as_ref()?
1829 .containing_shadow_root
1830 .as_ref()
1831 .map(|shadow_root| shadow_root.as_unrooted(no_gc))
1832 }
1833
1834 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1835 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1836 }
1837
1838 pub(crate) fn is_in_html_doc(&self) -> bool {
1839 self.owner_doc().is_html_document()
1840 }
1841
1842 pub(crate) fn is_connected_with_browsing_context(&self, no_gc: &NoGC) -> bool {
1843 self.is_connected() &&
1844 self.owner_document_unrooted(no_gc)
1845 .browsing_context()
1846 .is_some()
1847 }
1848
1849 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1850 SimpleNodeIterator::new(self.GetFirstChild(), |n| n.GetNextSibling())
1851 }
1852
1853 pub(crate) fn children_unrooted<'a>(
1854 &self,
1855 no_gc: &'a NoGC,
1856 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1857 UnrootedSimpleNodeIterator::new(
1858 self.get_first_child_unrooted(no_gc),
1859 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1860 no_gc,
1861 )
1862 }
1863
1864 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1865 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetPreviousSibling())
1866 }
1867
1868 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1870 self.children()
1871 .filter_map(DomRoot::downcast as fn(_) -> _)
1872 .peekable()
1873 }
1874
1875 pub(crate) fn child_elements_unrooted<'a>(
1876 &self,
1877 no_gc: &'a NoGC,
1878 ) -> impl Iterator<Item = UnrootedDom<'a, Element>> + use<'a> {
1879 self.children_unrooted(no_gc)
1880 .filter_map(UnrootedDom::downcast)
1881 .peekable()
1882 }
1883
1884 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1885 if let Some(ref parent) = self.GetParentNode() {
1886 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1887 }
1888 }
1889
1890 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1892 Ref::filter_map(self.rare_data.borrow(), |rare_data| {
1893 rare_data
1894 .as_ref()
1895 .and_then(|rare_data| rare_data.unique_id.as_ref())
1896 })
1897 .ok()
1898 .map(|unique_id| unique_id.simple().to_string())
1899 }
1900
1901 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1902 let mut rare_data = self.ensure_rare_data();
1903
1904 if rare_data.unique_id.is_none() {
1905 let node_id = Uuid::new_v4();
1906 ScriptThread::save_node_id(pipeline, node_id.simple().to_string());
1907 rare_data.unique_id = Some(node_id);
1908 }
1909 rare_data.unique_id.as_ref().unwrap().simple().to_string()
1910 }
1911
1912 #[cfg(feature = "devtools")]
1913 pub(crate) fn summarize(&self, cx: &mut JSContext) -> devtools_traits::NodeInfo {
1914 use crate::conversions::Convert;
1915 use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
1916 let USVString(base_uri) = self.BaseURI();
1917 let node_type = self.NodeType();
1918 let pipeline = self.owner_window().pipeline_id();
1919
1920 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1921 let shadow_root_mode = maybe_shadow_root
1922 .map(ShadowRoot::Mode)
1923 .map(ShadowRootMode::convert);
1924 let host = maybe_shadow_root
1925 .map(ShadowRoot::Host)
1926 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1927 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1928 let Some(root) = potential_host.shadow_root() else {
1929 return false;
1930 };
1931 !root.is_user_agent_widget() ||
1932 servo_config::pref!(inspector_show_servo_internal_shadow_roots)
1933 });
1934
1935 let num_children = if is_shadow_host {
1936 self.ChildNodes(cx).Length(cx.no_gc()) as usize + 1
1938 } else {
1939 self.ChildNodes(cx).Length(cx.no_gc()) as usize
1940 };
1941
1942 let window = self.owner_window();
1943 let element = self.downcast::<Element>();
1944 let display = element
1945 .map(|elem| window.GetComputedStyle(cx, elem, None))
1946 .map(|style| style.Display().into());
1947
1948 let is_displayed =
1954 element.is_none_or(|element| !element.is_display_none()) || self.is::<DocumentType>();
1955 let attrs = element.map(Element::summarize).unwrap_or_default();
1956
1957 devtools_traits::NodeInfo {
1958 unique_id: self.unique_id(pipeline),
1959 host,
1960 base_uri,
1961 parent: self
1962 .GetParentNode()
1963 .map_or(String::new(), |node| node.unique_id(pipeline)),
1964 node_type,
1965 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1966 node_name: String::from(self.NodeName()),
1967 node_value: self.GetNodeValue().map(|v| v.into()),
1968 num_children,
1969 attrs,
1970 is_shadow_host,
1971 shadow_root_mode,
1972 display,
1973 is_displayed,
1974 doctype_name: self
1975 .downcast::<DocumentType>()
1976 .map(DocumentType::name)
1977 .cloned()
1978 .map(String::from),
1979 doctype_public_identifier: self
1980 .downcast::<DocumentType>()
1981 .map(DocumentType::public_id)
1982 .cloned()
1983 .map(String::from),
1984 doctype_system_identifier: self
1985 .downcast::<DocumentType>()
1986 .map(DocumentType::system_id)
1987 .cloned()
1988 .map(String::from),
1989 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1990 }
1991 }
1992
1993 pub(crate) fn insert_cell_or_row<F, G, I>(
1995 &self,
1996 cx: &mut JSContext,
1997 index: i32,
1998 get_items: F,
1999 new_child: G,
2000 ) -> Fallible<DomRoot<HTMLElement>>
2001 where
2002 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
2003 G: Fn(&mut JSContext) -> DomRoot<I>,
2004 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
2005 {
2006 if index < -1 {
2007 return Err(Error::IndexSize(Some("Index is out of bounds".into())));
2008 }
2009
2010 let tr = new_child(cx);
2011
2012 {
2013 let tr_node = tr.upcast::<Node>();
2014 if index == -1 {
2015 self.InsertBefore(cx, tr_node, None)?;
2016 } else {
2017 let items = get_items(cx);
2018 let node = match items
2019 .elements_iter(cx.no_gc())
2020 .map(UnrootedDom::upcast::<Node>)
2021 .map(Some)
2022 .chain(iter::once(None))
2023 .nth(index as usize)
2024 {
2025 None => return Err(Error::IndexSize(Some("Index is out of bounds".into()))),
2026 Some(node) => node,
2027 };
2028 self.InsertBefore(cx, tr_node, node.map(|node| node.as_rooted()).as_deref())?;
2029 }
2030 }
2031
2032 Ok(DomRoot::upcast::<HTMLElement>(tr))
2033 }
2034
2035 pub(crate) fn delete_cell_or_row<F, G>(
2037 &self,
2038 cx: &mut JSContext,
2039 index: i32,
2040 get_items: F,
2041 is_delete_type: G,
2042 ) -> ErrorResult
2043 where
2044 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
2045 G: Fn(&Element) -> bool,
2046 {
2047 let element = match index {
2048 index if index < -1 => {
2049 return Err(Error::IndexSize(Some("Index is out of bounds".into())));
2050 },
2051 -1 => {
2052 let last_child = self.upcast::<Node>().GetLastChild();
2053 match last_child.and_then(|node| {
2054 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
2055 .filter_map(UnrootedDom::downcast::<Element>)
2056 .find(|elem| is_delete_type(elem))
2057 .map(|elem| elem.as_rooted())
2058 }) {
2059 Some(element) => element,
2060 None => return Ok(()),
2061 }
2062 },
2063 index => match get_items(cx).Item(cx, index as u32) {
2064 Some(element) => element,
2065 None => return Err(Error::IndexSize(Some("Index is out of bounds".into()))),
2066 },
2067 };
2068
2069 element.upcast::<Node>().remove_self(cx);
2070 Ok(())
2071 }
2072
2073 pub(crate) fn get_cssom_stylesheet(
2074 &self,
2075 cx: &mut JSContext,
2076 ) -> Option<DomRoot<CSSStyleSheet>> {
2077 if let Some(node) = self.downcast::<HTMLStyleElement>() {
2078 node.get_cssom_stylesheet(cx)
2079 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
2080 node.get_cssom_stylesheet(cx)
2081 } else {
2082 None
2083 }
2084 }
2085
2086 pub(crate) fn get_lang(&self) -> Option<String> {
2088 self.inclusive_ancestors(ShadowIncluding::Yes)
2096 .find_map(|node| {
2097 node.downcast::<Element>().and_then(|element| {
2098 element
2101 .get_attribute_string_value_with_namespace(&ns!(xml), &local_name!("lang"))
2102 .or_else(|| {
2106 if element.namespace() == &ns!() || element.namespace() == &ns!(svg) {
2107 element.get_attribute_string_value(&local_name!("lang"))
2108 } else {
2109 None
2110 }
2111 })
2112 })
2113 })
2114 .or_else(|| self.owner_document().default_language())
2129 }
2130
2131 pub(crate) fn assign_slottables_for_a_tree(
2133 &self,
2134 cx: &JSContext,
2135 force: ForceSlottableNodeReconciliation,
2136 ) {
2137 let is_shadow_root_with_slots = self
2144 .downcast::<ShadowRoot>()
2145 .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
2146 if !is_shadow_root_with_slots &&
2147 !self.is::<HTMLSlotElement>() &&
2148 matches!(force, ForceSlottableNodeReconciliation::Skip)
2149 {
2150 return;
2151 }
2152
2153 for node in self.traverse_preorder_unrooted(cx, ShadowIncluding::No) {
2156 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
2157 slot.assign_slottables(cx);
2158 }
2159 }
2160 }
2161
2162 pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
2163 let assigned_slot = self
2164 .rare_data
2165 .borrow()
2166 .as_ref()?
2167 .slottable_data
2168 .assigned_slot
2169 .as_ref()?
2170 .as_rooted();
2171 Some(assigned_slot)
2172 }
2173
2174 pub(crate) fn assigned_slot_unrooted<'a>(
2175 &self,
2176 no_gc: &'a NoGC,
2177 ) -> Option<UnrootedDom<'a, HTMLSlotElement>> {
2178 let rare_data = self.rare_data.borrow();
2179 let assigned_slot = rare_data.as_ref()?.slottable_data.assigned_slot.as_ref()?;
2180 Some(UnrootedDom::from_ref(assigned_slot, no_gc))
2181 }
2182
2183 pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
2184 self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
2185 }
2186
2187 pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
2188 let manually_assigned_slot = self
2189 .rare_data
2190 .borrow()
2191 .as_ref()?
2192 .slottable_data
2193 .manual_slot_assignment
2194 .as_ref()?
2195 .as_rooted();
2196 Some(manually_assigned_slot)
2197 }
2198
2199 pub(crate) fn set_manual_slot_assignment(
2200 &self,
2201 manually_assigned_slot: Option<&HTMLSlotElement>,
2202 ) {
2203 self.ensure_rare_data()
2204 .slottable_data
2205 .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
2206 }
2207
2208 pub(crate) fn parent_in_flat_tree<'b>(&self, no_gc: &'b NoGC) -> FlatTreeParent<'b> {
2219 if let Some(assigned_slot) = self.assigned_slot_unrooted(no_gc) {
2220 return FlatTreeParent::Parent(UnrootedDom::upcast::<Node>(assigned_slot));
2221 }
2222
2223 let Some(parent) = self.get_parent_node_unrooted(no_gc) else {
2224 return FlatTreeParent::RootNode;
2225 };
2226
2227 if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
2228 return FlatTreeParent::Parent(UnrootedDom::upcast(shadow_root.host_unrooted(no_gc)));
2229 }
2230
2231 if parent
2232 .downcast::<Element>()
2233 .is_some_and(|element| element.is_shadow_host())
2234 {
2235 return FlatTreeParent::NotInFlatTree;
2236 }
2237
2238 if parent
2239 .downcast::<HTMLSlotElement>()
2240 .is_some_and(|slot| slot.has_assigned_nodes())
2241 {
2242 return FlatTreeParent::NotInFlatTree;
2243 }
2244
2245 FlatTreeParent::Parent(parent)
2246 }
2247
2248 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2250 debug_assert!(self.is_in_ua_widget());
2252 debug_assert!(pseudo_element.is_element_backed());
2253 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2254 }
2255
2256 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2257 self.rare_data
2258 .borrow()
2259 .as_ref()
2260 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2261 }
2262
2263 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2265 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2269 if ancestor.is_editing_host() {
2270 return Some(ancestor);
2271 }
2272 if ancestor
2273 .downcast::<HTMLElement>()
2274 .is_some_and(|el| el.ContentEditable().str() == "false")
2275 {
2276 return None;
2277 }
2278 }
2279 None
2280 }
2281
2282 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2283 self.editing_host_of().is_some()
2284 }
2285
2286 pub(crate) fn is_editing_host(&self) -> bool {
2288 self.downcast::<HTMLElement>()
2289 .is_some_and(HTMLElement::is_editing_host)
2290 }
2291
2292 pub(crate) fn is_editable(&self) -> bool {
2294 if self.is_inert() {
2297 return false;
2298 }
2299
2300 if self.is_editing_host() {
2302 return false;
2303 }
2304 let html_element = self.downcast::<HTMLElement>();
2306 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2307 return false;
2308 }
2309 let Some(parent) = self.GetParentNode() else {
2311 return false;
2312 };
2313 if !parent.is_editable_or_editing_host() {
2314 return false;
2315 }
2316 html_element.is_some() || (!self.is::<Element>() && parent.is::<HTMLElement>())
2318 }
2319
2320 pub(crate) fn is_inert(&self) -> bool {
2325 self.downcast::<Element>()
2326 .and_then(Element::style)
2327 .is_some_and(|style| {
2328 *style.get__moz_inert() == Inert::Inert ||
2329 *style.get_interactivity() == Interactivity::Inert
2330 })
2331 }
2332}
2333
2334fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2336where
2337 I: Iterator<Item = DomRoot<Node>>,
2338{
2339 nodes.find(|node| {
2340 not_in.iter().all(|n| match *n {
2341 NodeOrString::Node(ref n) => n != node,
2342 _ => true,
2343 })
2344 })
2345}
2346
2347#[expect(unsafe_code)]
2350pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2351 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2352 DomRoot::from_ref(node)
2353}
2354
2355#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2357pub(crate) enum CloneChildrenFlag {
2358 CloneChildren,
2359 DoNotCloneChildren,
2360}
2361
2362impl From<bool> for CloneChildrenFlag {
2363 fn from(boolean: bool) -> Self {
2364 if boolean {
2365 CloneChildrenFlag::CloneChildren
2366 } else {
2367 CloneChildrenFlag::DoNotCloneChildren
2368 }
2369 }
2370}
2371
2372pub(super) fn as_uintptr<T>(t: &T) -> uintptr_t {
2373 t as *const T as uintptr_t
2374}
2375
2376impl Node {
2377 pub(crate) fn reflect_node<N>(
2378 cx: &mut JSContext,
2379 node: Box<N>,
2380 document: &Document,
2381 ) -> DomRoot<N>
2382 where
2383 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2384 {
2385 Self::reflect_node_with_proto(cx, node, document, None)
2386 }
2387
2388 pub(crate) fn reflect_node_with_proto<N>(
2389 cx: &mut JSContext,
2390 node: Box<N>,
2391 document: &Document,
2392 proto: Option<HandleObject>,
2393 ) -> DomRoot<N>
2394 where
2395 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2396 {
2397 let window = document.window();
2398 reflect_dom_object_with_proto(cx, node, window, proto)
2399 }
2400
2401 pub(crate) fn reflect_weak_referenceable_node_with_proto<N>(
2402 cx: &mut JSContext,
2403 node: Rc<N>,
2404 document: &Document,
2405 proto: Option<HandleObject>,
2406 ) -> DomRoot<N>
2407 where
2408 N: DerivedFrom<Node> + DomObject + WeakReferenceableDomObjectWrap<crate::DomTypeHolder>,
2409 {
2410 let window = document.window();
2411 reflect_weak_referenceable_dom_object_with_proto(cx, node, window, proto)
2412 }
2413
2414 pub(crate) fn new_inherited(doc: &Document) -> Node {
2415 Node::new_(NodeFlags::empty(), Some(doc))
2416 }
2417
2418 pub(crate) fn new_document_node() -> Node {
2419 Node::new_(
2420 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2421 None,
2422 )
2423 }
2424
2425 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2426 Node {
2427 eventtarget: EventTarget::new_inherited(),
2428 parent_node: Default::default(),
2429 first_child: Default::default(),
2430 last_child: Default::default(),
2431 next_sibling: Default::default(),
2432 prev_sibling: Default::default(),
2433 owner_doc: MutNullableDom::new(doc),
2434 rare_data: Default::default(),
2435 children_count: Cell::new(0u32),
2436 flags: Cell::new(flags),
2437 inclusive_descendants_version: Cell::new(0),
2438 layout_data: Default::default(),
2439 }
2440 }
2441
2442 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2444 document.add_script_and_layout_blocker();
2445
2446 let old_doc = node.owner_doc();
2448 old_doc.add_script_and_layout_blocker();
2449
2450 node.remove_self(cx);
2452
2453 if &*old_doc != document {
2457 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2458 descendant.set_owner_doc(document);
2460
2461 if let Some(shadow_root) = descendant.downcast::<ShadowRoot>() {
2472 if shadow_root
2473 .custom_element_registry()
2474 .is_none_or(|registry| {
2475 CustomElementRegistry::is_a_global_element_registry(Some(&*registry))
2476 })
2477 {
2478 shadow_root.set_custom_element_registry(
2479 document
2480 .effective_global_custom_element_registry()
2481 .as_deref(),
2482 );
2483 }
2484 }
2485 else if let Some(element) = descendant.downcast::<Element>() {
2487 for attribute in element.attrs().borrow().iter() {
2490 if let Some(attr) = attribute.as_attr() {
2491 attr.upcast::<Node>().set_owner_doc(document);
2492 }
2493 }
2494
2495 if element
2501 .custom_element_registry()
2502 .is_none_or(|registry| !registry.is_scoped())
2503 {
2504 element.set_custom_element_registry(
2505 document
2506 .effective_global_custom_element_registry()
2507 .as_deref(),
2508 cx.no_gc(),
2509 );
2510 }
2511
2512 if element.is_custom() {
2516 ScriptThread::custom_element_reaction_stack().enqueue_callback_reaction(
2517 cx,
2518 element,
2519 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2520 None,
2521 );
2522 }
2523 }
2524
2525 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2527 }
2528
2529 for range in old_doc.live_ranges().as_vec() {
2533 range.maybe_update_document();
2534 }
2535 }
2536
2537 old_doc.remove_script_and_layout_blocker(cx);
2538 document.remove_script_and_layout_blocker(cx);
2539 }
2540
2541 pub(crate) fn ensure_pre_insertion_validity(
2543 no_gc: &NoGC,
2544 node: &Node,
2545 parent: &Node,
2546 child: Option<&Node>,
2547 children_to_exclude: &[&Node],
2548 ) -> ErrorResult {
2549 let excluded = |node: &Node| children_to_exclude.contains(&node);
2550
2551 match parent.type_id() {
2553 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2554 },
2555 _ => {
2556 return Err(Error::HierarchyRequest(Some(
2557 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2558 )));
2559 },
2560 }
2561
2562 if node.is_host_including_inclusive_ancestor(parent) {
2564 return Err(Error::HierarchyRequest(Some(
2565 "Node is a host-including inclusive ancestor of parent".to_owned(),
2566 )));
2567 }
2568
2569 if let Some(child) = child &&
2571 !parent.is_parent_of(child)
2572 {
2573 return Err(Error::NotFound(Some(
2574 "Child is non-null and its parent is not parent".to_owned(),
2575 )));
2576 }
2577
2578 match node.type_id() {
2579 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2583 if parent.is::<Document>() {
2584 return Err(Error::HierarchyRequest(Some(
2585 "Node is a Text node and parent is a document".to_owned(),
2586 )));
2587 }
2588 },
2589 NodeTypeId::DocumentType => {
2590 if !parent.is::<Document>() {
2591 return Err(Error::HierarchyRequest(Some(
2592 "Node is a doctype and parent is not a document".to_owned(),
2593 )));
2594 }
2595 },
2596 NodeTypeId::DocumentFragment(_) |
2597 NodeTypeId::Element(_) |
2598 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2599 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2600 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2603 return Err(Error::HierarchyRequest(Some(
2604 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2605 .to_owned(),
2606 )));
2607 },
2608 }
2609
2610 if parent.is::<Document>() {
2613 match node.type_id() {
2614 NodeTypeId::DocumentFragment(_) => {
2615 if node.children_unrooted(no_gc).any(|c| c.is::<Text>()) {
2617 return Err(Error::HierarchyRequest(Some(
2618 "Parent is a document and node has a Text node child".into(),
2619 )));
2620 }
2621 match node.child_elements_unrooted(no_gc).count() {
2622 0 => (),
2623 1 => {
2627 if parent
2628 .child_elements_unrooted(no_gc)
2629 .any(|c| !excluded(c.upcast()))
2630 {
2631 return Err(Error::HierarchyRequest(Some(
2632 "Node has one element child and parent has an element child"
2633 .into(),
2634 )));
2635 }
2636 if let Some(child) = child &&
2637 child
2638 .inclusively_following_siblings_unrooted(no_gc)
2639 .any(|sibling| sibling.is_doctype() && !excluded(&sibling))
2640 {
2641 return Err(Error::HierarchyRequest(Some(
2642 "Node has one element child and child is a doctype".into(),
2643 )));
2644 }
2645 },
2646 _ => {
2647 return Err(Error::HierarchyRequest(Some(
2648 "Node cannot have more than one child element".into(),
2649 )));
2650 },
2651 }
2652 },
2653 NodeTypeId::Element(_) => {
2654 if parent
2657 .child_elements_unrooted(no_gc)
2658 .any(|c| !excluded(c.upcast()))
2659 {
2660 return Err(Error::HierarchyRequest(Some(
2661 "Parent has an element child".to_owned(),
2662 )));
2663 }
2664 if let Some(child) = child &&
2665 child
2666 .inclusively_following_siblings_unrooted(no_gc)
2667 .any(|following| following.is_doctype() && !excluded(&following))
2668 {
2669 return Err(Error::HierarchyRequest(Some(
2670 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
2671 )));
2672 }
2673 },
2674 NodeTypeId::DocumentType => {
2675 if parent
2679 .children_unrooted(no_gc)
2680 .any(|c| c.is_doctype() && !excluded(&c))
2681 {
2682 return Err(Error::HierarchyRequest(Some(
2683 "Parent cannot have a doctype child".into(),
2684 )));
2685 }
2686 match child {
2687 Some(child) => {
2688 if parent
2689 .children_unrooted(no_gc)
2690 .take_while(|c| **c != child)
2691 .any(|c| c.is::<Element>())
2692 {
2693 return Err(Error::HierarchyRequest(Some(
2694 "Child is non-null and an element is preceding child".into(),
2695 )));
2696 }
2697 },
2698 None => {
2699 if parent
2700 .child_elements_unrooted(no_gc)
2701 .any(|c| !excluded(c.upcast()))
2702 {
2703 return Err(Error::HierarchyRequest(Some(
2704 "Child is null and parent has an element child".into(),
2705 )));
2706 }
2707 },
2708 }
2709 },
2710 NodeTypeId::CharacterData(_) => (),
2711 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
2714 }
2715 }
2716 Ok(())
2717 }
2718
2719 pub(crate) fn pre_insert(
2721 cx: &mut JSContext,
2722 node: &Node,
2723 parent: &Node,
2724 child: Option<&Node>,
2725 ) -> Fallible<DomRoot<Node>> {
2726 Node::ensure_pre_insertion_validity(cx.no_gc(), node, parent, child, &[])?;
2728
2729 let reference_child_root;
2731 let reference_child = match child {
2732 Some(child) if child == node => {
2734 reference_child_root = node.GetNextSibling();
2735 reference_child_root.as_deref()
2736 },
2737 _ => child,
2738 };
2739
2740 Node::insert(
2742 cx,
2743 node,
2744 parent,
2745 reference_child,
2746 SuppressObserver::Unsuppressed,
2747 );
2748
2749 Ok(DomRoot::from_ref(node))
2751 }
2752
2753 pub(crate) fn insert(
2755 cx: &mut JSContext,
2756 node: &Node,
2757 parent: &Node,
2758 child: Option<&Node>,
2759 suppress_observers: SuppressObserver,
2760 ) {
2761 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
2762
2763 rooted_vec!(let mut new_nodes);
2765 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2766 new_nodes.extend(
2767 node.children_unrooted(cx.no_gc())
2768 .map(|node| Dom::from_ref(&**node)),
2769 );
2770 new_nodes.r()
2771 } else {
2772 from_ref(&node)
2773 };
2774
2775 let count = new_nodes.len();
2777
2778 if count == 0 {
2780 return;
2781 }
2782
2783 let parent_document = parent.owner_document();
2786 let from_document = node.owner_document();
2787 parent_document.add_script_and_layout_blocker();
2788 from_document.add_script_and_layout_blocker();
2789
2790 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2792 for kid in new_nodes {
2794 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
2795 }
2796 vtable_for(node).children_changed(cx, &ChildrenMutation::ReplaceAll);
2797
2798 let mutation = LazyCell::new(|| Mutation::ChildList {
2800 added: None,
2801 removed: Some(new_nodes),
2802 prev: None,
2803 next: None,
2804 });
2805 MutationObserver::queue_a_mutation_record(cx, node, mutation);
2806 }
2807
2808 if let Some(child) = child {
2810 let count = count.try_into().unwrap();
2812 if let Some(selection) = parent_document.selection() {
2813 selection.insert_steps(parent, child, count);
2814 }
2815 parent_document.live_range_insert_steps(cx.no_gc(), parent, child, count);
2816 }
2817
2818 let previous_sibling = match suppress_observers {
2820 SuppressObserver::Unsuppressed => match child {
2821 Some(child) => child.GetPreviousSibling(),
2822 None => parent.GetLastChild(),
2823 },
2824 SuppressObserver::Suppressed => None,
2825 };
2826
2827 let mut static_node_list: Option<RootedTraceableBox<TraceableSmallVec<[Dom<Node>; 4]>>> =
2832 None;
2833
2834 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
2835 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
2836 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
2837
2838 for kid in new_nodes {
2840 Node::adopt(cx, kid, &parent_document);
2842
2843 parent.add_child(cx, MoveOrInsert::Insert, kid, child);
2846
2847 if let Some(ref shadow_root) = parent_shadow_root &&
2850 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
2851 (kid.is::<Element>() || kid.is::<Text>())
2852 {
2853 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(kid)));
2854 slottable.assign_a_slot(cx);
2855 }
2856
2857 if parent_in_shadow_tree &&
2860 let Some(slot_element) = parent_as_slot &&
2861 !slot_element.has_assigned_nodes()
2862 {
2863 slot_element.signal_a_slot_change(cx);
2864 }
2865
2866 kid.GetRootNode(&GetRootNodeOptions::empty())
2868 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
2869
2870 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
2873 if let Some(element) = descendant.downcast::<Element>() &&
2879 !element.is_custom()
2880 {
2881 try_upgrade_element(cx, element);
2882 }
2883
2884 if !descendant.is_connected() {
2886 continue;
2887 }
2888
2889 if let Some(element) = descendant.downcast::<Element>() {
2891 if let Some(registry) = element.custom_element_registry() {
2893 if registry.is_scoped() {
2898 registry
2899 .add_scoped_document(&element.owner_document_unrooted(cx.no_gc()));
2900 }
2901 }
2902 if element.is_custom() {
2910 ScriptThread::custom_element_reaction_stack().enqueue_callback_reaction(
2911 cx,
2912 element,
2913 CallbackReaction::Connected,
2914 None,
2915 );
2916 }
2917 else {
2919 try_upgrade_element(cx, element);
2920 }
2921 }
2922 else if let Some(shadow_root) =
2929 DomRoot::downcast::<ShadowRoot>(descendant.clone()) &&
2930 let Some(custom_element_registry) = shadow_root.custom_element_registry() &&
2931 custom_element_registry.is_scoped()
2932 {
2933 custom_element_registry.add_scoped_document(shadow_root.owner_doc());
2934 }
2935
2936 static_node_list
2939 .get_or_insert_default()
2940 .push(descendant.as_traced());
2941 }
2942 }
2943
2944 Self::maybe_dirty_visible_selection_for_newly_inserted_nodes(cx.no_gc(), parent, new_nodes);
2945
2946 if let SuppressObserver::Unsuppressed = suppress_observers {
2947 vtable_for(parent).children_changed(
2950 cx,
2951 &ChildrenMutation::insert(previous_sibling.as_deref(), child),
2952 );
2953
2954 let mutation = LazyCell::new(|| Mutation::ChildList {
2957 added: Some(new_nodes),
2958 removed: None,
2959 prev: previous_sibling.as_deref(),
2960 next: child,
2961 });
2962 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2963 }
2964
2965 if let Some(static_node_list) = static_node_list {
2976 parent_document.add_delayed_task(
2977 task!(PostConnectionSteps: |cx, static_node_list: RootedTraceableBox<TraceableSmallVec<[Dom<Node>; 4]>>| {
2978 for node in static_node_list.iter() {
2983 vtable_for(node).post_connection_steps(cx);
2984 }
2985 }),
2986 );
2987 }
2988
2989 parent_document.remove_script_and_layout_blocker(cx);
2990 from_document.remove_script_and_layout_blocker(cx);
2991 }
2992
2993 pub(crate) fn maybe_dirty_visible_selection_for_newly_inserted_nodes(
2996 no_gc: &NoGC,
2997 parent: &Node,
2998 inserted_nodes: &[&Node],
2999 ) {
3000 let Some(selection) = parent.owner_document_unrooted(no_gc).selection() else {
3001 return;
3002 };
3003
3004 for node in inserted_nodes {
3005 match node.parent_in_flat_tree(no_gc) {
3006 FlatTreeParent::RootNode | FlatTreeParent::NotInFlatTree => {},
3007 FlatTreeParent::Parent(parent) => {
3008 if parent.get_flag(NodeFlags::OVERLAPS_DOCUMENT_SELECTION) {
3009 selection.set_visible_selection_dirty();
3010 return;
3011 }
3012 },
3013 }
3014 }
3015 }
3016
3017 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
3019 let document = parent.owner_document();
3020 document.add_script_and_layout_blocker();
3021
3022 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
3024
3025 rooted_vec!(let mut added_nodes);
3029 let added_nodes = if let Some(node) = node.as_ref() {
3030 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
3031 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
3032 added_nodes.r()
3033 } else {
3034 from_ref(node)
3035 }
3036 } else {
3037 &[] as &[&Node]
3038 };
3039
3040 for child in &*removed_nodes {
3042 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
3043 }
3044
3045 if let Some(node) = node {
3047 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
3048 }
3049
3050 vtable_for(parent).children_changed(cx, &ChildrenMutation::ReplaceAll);
3051
3052 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
3055 let mutation = LazyCell::new(|| Mutation::ChildList {
3056 added: Some(added_nodes),
3057 removed: Some(removed_nodes.r()),
3058 prev: None,
3059 next: None,
3060 });
3061 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
3062 }
3063 document.remove_script_and_layout_blocker(cx);
3064 }
3065
3066 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
3068 if string.is_empty() {
3069 Node::replace_all(cx, None, parent);
3070 } else {
3071 let text = Text::new(cx, string, &parent.owner_document());
3072 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
3073 };
3074 }
3075
3076 pub(super) fn pre_remove(
3078 cx: &mut JSContext,
3079 child: &Node,
3080 parent: &Node,
3081 ) -> Fallible<DomRoot<Node>> {
3082 match child.GetParentNode() {
3084 Some(ref node) if &**node != parent => {
3085 return Err(Error::NotFound(Some(
3086 "Child's parent does not match the parent node provided".into(),
3087 )));
3088 },
3089 None => {
3090 return Err(Error::NotFound(Some(
3091 "Child does not have a parent node".into(),
3092 )));
3093 },
3094 _ => (),
3095 }
3096
3097 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
3099
3100 Ok(DomRoot::from_ref(child))
3102 }
3103
3104 pub(super) fn remove(
3106 cx: &mut JSContext,
3107 node: &Node,
3108 parent: &Node,
3109 suppress_observers: SuppressObserver,
3110 ) {
3111 let document = parent.owner_document();
3112 document.add_script_and_layout_blocker();
3113
3114 assert!(
3118 node.GetParentNode()
3119 .is_some_and(|node_parent| &*node_parent == parent)
3120 );
3121
3122 let mut cached_index = None;
3124 {
3125 let mut lazy_index = || *cached_index.get_or_insert_with(|| node.index());
3126 let document = parent.owner_doc_unrooted(cx.no_gc());
3127 if let Some(selection) = document.selection() {
3128 selection.pre_remove_steps(node, parent, &mut lazy_index);
3129 }
3130 document.live_range_pre_remove_steps(cx.no_gc(), node, parent, &mut lazy_index);
3131 }
3132
3133 let old_previous_sibling = node.GetPreviousSibling();
3137
3138 let old_next_sibling = node.GetNextSibling();
3140
3141 parent.remove_child(cx, node);
3144
3145 if let Some(slot) = node.assigned_slot() {
3147 slot.assign_slottables(cx);
3148 }
3149
3150 if parent.is_in_a_shadow_tree() &&
3153 let Some(slot_element) = parent.downcast::<HTMLSlotElement>() &&
3154 !slot_element.has_assigned_nodes()
3155 {
3156 slot_element.signal_a_slot_change(cx);
3157 }
3158
3159 let has_slot_descendant = node
3161 .traverse_preorder_unrooted(cx.no_gc(), ShadowIncluding::No)
3162 .any(|elem| elem.is::<HTMLSlotElement>());
3163 if has_slot_descendant {
3164 parent
3166 .GetRootNode(&GetRootNodeOptions::empty())
3167 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
3168
3169 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Force);
3171 }
3172
3173 if let SuppressObserver::Unsuppressed = suppress_observers {
3177 vtable_for(parent).children_changed(
3178 cx,
3179 &ChildrenMutation::replace(
3180 old_previous_sibling.as_deref(),
3181 &Some(node),
3182 old_next_sibling.as_deref(),
3183 ),
3184 );
3185
3186 let removed = [node];
3187 let mutation = LazyCell::new(|| Mutation::ChildList {
3188 added: None,
3189 removed: Some(&removed),
3190 prev: old_previous_sibling.as_deref(),
3191 next: old_next_sibling.as_deref(),
3192 });
3193 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
3194 }
3195 document.remove_script_and_layout_blocker(cx);
3196 }
3197
3198 pub(crate) fn clone(
3200 cx: &mut JSContext,
3201 node: &Node,
3202 maybe_doc: Option<&Document>,
3203 clone_children: CloneChildrenFlag,
3204 registry: Option<DomRoot<CustomElementRegistry>>,
3205 ) -> DomRoot<Node> {
3206 let document = match maybe_doc {
3208 Some(doc) => DomRoot::from_ref(doc),
3209 None => node.owner_doc(),
3210 };
3211
3212 let copy: DomRoot<Node> = match node.type_id() {
3215 NodeTypeId::DocumentType => {
3216 let doctype = node.downcast::<DocumentType>().unwrap();
3217 let doctype = DocumentType::new(
3218 cx,
3219 doctype.Name(),
3220 Some(doctype.PublicId()),
3221 Some(doctype.SystemId()),
3222 &document,
3223 );
3224 DomRoot::upcast::<Node>(doctype)
3225 },
3226 NodeTypeId::Attr => {
3227 let attr = node.downcast::<Attr>().unwrap();
3228 let attr = Attr::new(
3229 cx,
3230 &document,
3231 attr.local_name().clone(),
3232 attr.value().clone(),
3233 attr.name().clone(),
3234 attr.namespace().clone(),
3235 attr.prefix().cloned(),
3236 None,
3237 );
3238 DomRoot::upcast::<Node>(attr)
3239 },
3240 NodeTypeId::DocumentFragment(_) => {
3241 let doc_fragment = DocumentFragment::new(cx, &document);
3242 DomRoot::upcast::<Node>(doc_fragment)
3243 },
3244 NodeTypeId::CharacterData(_) => {
3245 let cdata = node.downcast::<CharacterData>().unwrap();
3246 cdata.clone_with_data(cx, cdata.Data(), &document)
3247 },
3248 NodeTypeId::Document(_) => {
3249 let document = node.downcast::<Document>().unwrap();
3252 let is_html_doc = if document.is_html_document() {
3253 IsHTMLDocument::HTMLDocument
3254 } else {
3255 IsHTMLDocument::NonHTMLDocument
3256 };
3257 let window = document.window();
3258 let loader = DocumentLoader::new(&document.loader());
3259 let document = Document::new(
3260 cx,
3261 window,
3262 HasBrowsingContext::No,
3263 Some(document.url()),
3264 None,
3265 document.origin().clone(),
3267 is_html_doc,
3268 None,
3269 None,
3270 DocumentActivity::Inactive,
3271 loader,
3272 None,
3273 document.status_code(),
3274 false,
3275 document.allow_declarative_shadow_roots(),
3276 Some(document.insecure_requests_policy()),
3277 document.has_trustworthy_ancestor_or_current_origin(),
3278 document.custom_element_reaction_stack(),
3279 document.creation_sandboxing_flag_set(),
3280 document.pipeline_id(),
3281 document.image_cache(),
3282 );
3283 DomRoot::upcast::<Node>(document)
3287 },
3288 NodeTypeId::Element(..) => {
3290 let element = node.downcast::<Element>().unwrap();
3291 let registry = element.custom_element_registry().or(registry);
3294 let registry =
3297 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3298 document.effective_global_custom_element_registry()
3299 } else {
3300 registry
3301 };
3302 let name = QualName {
3306 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3307 ns: element.namespace().clone(),
3308 local: element.local_name().clone(),
3309 };
3310 let element = Element::create(
3311 cx,
3312 name,
3313 element.get_is(),
3314 &document,
3315 ElementCreator::ScriptCreated,
3316 CustomElementCreationMode::Asynchronous,
3317 None,
3318 );
3319 element.set_custom_element_registry(registry.as_deref(), cx.no_gc());
3321 DomRoot::upcast::<Node>(element)
3322 },
3323 };
3324
3325 let document = match copy.downcast::<Document>() {
3328 Some(doc) => DomRoot::from_ref(doc),
3329 None => DomRoot::from_ref(&*document),
3330 };
3331 assert!(copy.owner_doc() == document);
3332
3333 match node.type_id() {
3335 NodeTypeId::Document(_) => {
3336 let node_doc = node.downcast::<Document>().unwrap();
3337 let copy_doc = copy.downcast::<Document>().unwrap();
3338 copy_doc.set_encoding(node_doc.encoding());
3339 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3340 },
3341 NodeTypeId::Element(..) => {
3342 let node_elem = node.downcast::<Element>().unwrap();
3343 let copy_elem = copy.downcast::<Element>().unwrap();
3344
3345 node_elem.copy_all_attributes_to_other_element(cx, copy_elem);
3347 },
3348 _ => (),
3349 }
3350
3351 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3354
3355 if clone_children == CloneChildrenFlag::CloneChildren {
3358 for child in node.children() {
3359 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3360 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3361 }
3362 }
3363
3364 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3367 let node_elem = node.downcast::<Element>().unwrap();
3368 let copy_elem = copy.downcast::<Element>().unwrap();
3369
3370 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3371 assert!(!copy_elem.is_shadow_host());
3373
3374 let copy_shadow_root =
3378 copy_elem.attach_shadow(
3379 cx,
3380 IsUserAgentWidget::No,
3381 shadow_root.Mode(),
3382 shadow_root.Clonable(),
3383 shadow_root.Serializable(),
3384 shadow_root.DelegatesFocus(),
3385 shadow_root.SlotAssignment(),
3386 )
3387 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3388
3389 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3391
3392 for child in shadow_root.upcast::<Node>().children() {
3395 let child_copy = Node::clone(
3396 cx,
3397 &child,
3398 Some(&document),
3399 CloneChildrenFlag::CloneChildren,
3400 None,
3401 );
3402
3403 let _inserted_node =
3405 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3406 }
3407 }
3408 }
3409
3410 copy
3412 }
3413
3414 pub(crate) fn child_text_content(&self) -> DOMString {
3416 Node::collect_text_contents(self.children())
3417 }
3418
3419 pub(crate) fn descendant_text_content(&self) -> DOMString {
3421 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3422 }
3423
3424 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3425 iterator: T,
3426 ) -> DOMString {
3427 let mut content = String::new();
3428 for node in iterator {
3429 if let Some(text) = node.downcast::<Text>() {
3430 content.push_str(&text.upcast::<CharacterData>().data());
3431 }
3432 }
3433 DOMString::from(content)
3434 }
3435
3436 pub(crate) fn set_text_content_for_element(
3438 &self,
3439 cx: &mut JSContext,
3440 value: Option<DOMString>,
3441 ) {
3442 assert!(matches!(
3445 self.type_id(),
3446 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3447 ));
3448 let value = value.unwrap_or_default();
3449 let node = if value.is_empty() {
3450 None
3452 } else {
3453 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3456 };
3457
3458 Self::replace_all(cx, node.as_deref(), self);
3460 }
3461
3462 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3463 match namespace {
3464 ns!() => None,
3465 _ => Some(TracedDOMString::from(namespace).root()),
3466 }
3467 }
3468
3469 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3471 match node.type_id() {
3472 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3473 NodeTypeId::Attr => node
3474 .downcast::<Attr>()
3475 .unwrap()
3476 .GetOwnerElement()
3477 .as_ref()
3478 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3479 NodeTypeId::Document(_) => node
3480 .downcast::<Document>()
3481 .unwrap()
3482 .GetDocumentElement()
3483 .as_ref()
3484 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3485 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3486 _ => node
3487 .GetParentElement()
3488 .as_ref()
3489 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3490 }
3491 }
3492
3493 #[expect(unsafe_code)]
3501 pub(crate) unsafe fn from_untrusted_node_address(
3502 candidate: UntrustedNodeAddress,
3503 ) -> &'static Self {
3504 let candidate = candidate.0 as usize;
3506 let object = candidate as *mut JSObject;
3507 if object.is_null() {
3508 panic!("Attempted to create a `Node` from an invalid pointer!")
3509 }
3510
3511 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3512 }
3513
3514 pub(crate) fn html_serialize(
3515 &self,
3516 cx: &mut JSContext,
3517 traversal_scope: html_serialize::TraversalScope,
3518 serialize_shadow_roots: bool,
3519 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3520 ) -> DOMString {
3521 let mut writer = vec![];
3522 let mut serializer = HtmlSerializer::new(
3523 &mut writer,
3524 html_serialize::SerializeOpts {
3525 traversal_scope: traversal_scope.clone(),
3526 ..Default::default()
3527 },
3528 );
3529
3530 serialize_html_fragment(
3531 cx,
3532 self,
3533 &mut serializer,
3534 traversal_scope,
3535 serialize_shadow_roots,
3536 shadow_roots,
3537 )
3538 .expect("Serializing node failed");
3539
3540 DOMString::from(String::from_utf8(writer).unwrap())
3542 }
3543
3544 pub(crate) fn xml_serialize(
3546 &self,
3547 traversal_scope: xml_serialize::TraversalScope,
3548 ) -> Fallible<DOMString> {
3549 let mut writer = vec![];
3550 xml_serialize::serialize(
3551 &mut writer,
3552 &HtmlSerialize::new(self),
3553 xml_serialize::SerializeOpts { traversal_scope },
3554 )
3555 .map_err(|error| {
3556 error!("Cannot serialize node: {error}");
3557 Error::InvalidState(Some("Cannot serialize node".into()))
3558 })?;
3559
3560 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3562 error!("Cannot serialize node: {error}");
3563 Error::InvalidState(Some("Cannot serialize node".into()))
3564 })?);
3565
3566 Ok(string)
3567 }
3568
3569 pub(crate) fn fragment_serialization_algorithm(
3571 &self,
3572 cx: &mut JSContext,
3573 require_well_formed: bool,
3574 ) -> Fallible<DOMString> {
3575 let context_document = self.owner_document();
3577
3578 if context_document.is_html_document() {
3581 return Ok(self.html_serialize(
3582 cx,
3583 html_serialize::TraversalScope::ChildrenOnly(None),
3584 false,
3585 vec![],
3586 ));
3587 }
3588
3589 let _ = require_well_formed;
3592 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3593 }
3594
3595 pub(crate) fn get_next_sibling_unrooted<'a>(
3596 &self,
3597 no_gc: &'a NoGC,
3598 ) -> Option<UnrootedDom<'a, Node>> {
3599 self.next_sibling.get_unrooted(no_gc)
3600 }
3601
3602 pub(crate) fn next_flat_tree_sibling_unrooted<'a>(
3603 &self,
3604 no_gc: &'a NoGC,
3605 ) -> Option<UnrootedDom<'a, Node>> {
3606 if let Some(slot_element) = self.assigned_slot() {
3607 return slot_element
3611 .assigned_nodes()
3612 .iter()
3613 .skip_while(|slottable| &*slottable.0 != self)
3614 .nth(1)
3616 .map(|next_slottable| next_slottable.0.as_unrooted(no_gc));
3617 }
3618 self.get_next_sibling_unrooted(no_gc)
3619 }
3620
3621 pub(crate) fn get_previous_sibling_unrooted<'a>(
3622 &self,
3623 no_gc: &'a NoGC,
3624 ) -> Option<UnrootedDom<'a, Node>> {
3625 self.prev_sibling.get_unrooted(no_gc)
3626 }
3627
3628 pub(crate) fn get_first_child_unrooted<'a>(
3629 &self,
3630 no_gc: &'a NoGC,
3631 ) -> Option<UnrootedDom<'a, Node>> {
3632 self.first_child.get_unrooted(no_gc)
3633 }
3634
3635 pub(crate) fn first_flat_tree_child_unrooted<'a>(
3636 &self,
3637 no_gc: &'a NoGC,
3638 ) -> Option<UnrootedDom<'a, Node>> {
3639 let Some(element) = self.downcast::<Element>() else {
3640 return self.get_first_child_unrooted(no_gc);
3641 };
3642 if let Some(shadow_root) = element.shadow_root_unrooted(no_gc) {
3643 return shadow_root
3644 .upcast::<Node>()
3645 .first_flat_tree_child_unrooted(no_gc);
3646 };
3647
3648 if let Some(slot_element) = element.downcast::<HTMLSlotElement>() &&
3652 slot_element.has_assigned_nodes() &&
3653 let Some(assigned_node) = slot_element.assigned_nodes().first()
3654 {
3655 return Some(assigned_node.0.as_unrooted(no_gc));
3656 }
3657
3658 self.get_first_child_unrooted(no_gc)
3659 }
3660
3661 fn get_last_child_unrooted<'b>(&self, no_gc: &'b NoGC) -> Option<UnrootedDom<'b, Node>> {
3662 self.last_child.get_unrooted(no_gc)
3663 }
3664
3665 pub(crate) fn get_parent_node_unrooted<'a>(
3666 &self,
3667 no_gc: &'a NoGC,
3668 ) -> Option<UnrootedDom<'a, Node>> {
3669 self.parent_node.get_unrooted(no_gc)
3670 }
3671
3672 pub(crate) fn compare_dom_tree_position(
3674 &self,
3675 other: &Node,
3676 common_ancestor: &Node,
3677 shadow_including: ShadowIncluding,
3678 ) -> Ordering {
3679 debug_assert!(
3680 self.inclusive_ancestors(shadow_including)
3681 .any(|ancestor| &*ancestor == common_ancestor)
3682 );
3683 debug_assert!(
3684 other
3685 .inclusive_ancestors(shadow_including)
3686 .any(|ancestor| &*ancestor == common_ancestor)
3687 );
3688
3689 if self == other {
3690 return Ordering::Equal;
3691 }
3692
3693 if self == common_ancestor {
3694 return Ordering::Less;
3695 }
3696 if other == common_ancestor {
3697 return Ordering::Greater;
3698 }
3699
3700 let my_ancestors: Vec<_> = self
3701 .inclusive_ancestors(shadow_including)
3702 .take_while(|ancestor| &**ancestor != common_ancestor)
3703 .collect();
3704 let other_ancestors: Vec<_> = other
3705 .inclusive_ancestors(shadow_including)
3706 .take_while(|ancestor| &**ancestor != common_ancestor)
3707 .collect();
3708
3709 let mut i = my_ancestors.len() - 1;
3711 let mut j = other_ancestors.len() - 1;
3712
3713 while my_ancestors[i] == other_ancestors[j] {
3714 if i == 0 {
3715 debug_assert_ne!(j, 0, "Equal inclusive ancestors but nodes are not equal?");
3717 return Ordering::Less;
3718 }
3719 if j == 0 {
3720 return Ordering::Greater;
3722 }
3723
3724 i -= 1;
3725 j -= 1;
3726 }
3727
3728 if my_ancestors[i]
3731 .preceding_siblings()
3732 .any(|sibling| sibling == other_ancestors[j])
3733 {
3734 Ordering::Greater
3736 } else {
3737 debug_assert!(
3739 other_ancestors[j]
3740 .preceding_siblings()
3741 .any(|sibling| sibling == my_ancestors[i])
3742 );
3743 Ordering::Less
3744 }
3745 }
3746}
3747
3748impl NodeMethods<crate::DomTypeHolder> for Node {
3749 fn NodeType(&self) -> u16 {
3751 match self.type_id() {
3752 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3753 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3754 NodeConstants::TEXT_NODE
3755 },
3756 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3757 NodeConstants::CDATA_SECTION_NODE
3758 },
3759 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3760 NodeConstants::PROCESSING_INSTRUCTION_NODE
3761 },
3762 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3763 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3764 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3765 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3766 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3767 }
3768 }
3769
3770 fn NodeName(&self) -> DOMString {
3772 match self.type_id() {
3773 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3774 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3775 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3776 DOMString::from_static("#text")
3777 },
3778 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3779 DOMString::from_static("#cdata-section")
3780 },
3781 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3782 self.downcast::<ProcessingInstruction>().unwrap().Target()
3783 },
3784 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => {
3785 DOMString::from_static("#comment")
3786 },
3787 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().Name(),
3788 NodeTypeId::DocumentFragment(_) => DOMString::from_static("#document-fragment"),
3789 NodeTypeId::Document(_) => DOMString::from_static("#document"),
3790 }
3791 }
3792
3793 fn BaseURI(&self) -> USVString {
3795 USVString(String::from(self.owner_doc().base_url().as_str()))
3796 }
3797
3798 fn IsConnected(&self) -> bool {
3800 self.is_connected()
3801 }
3802
3803 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3805 match self.type_id() {
3806 NodeTypeId::Document(_) => None,
3807 _ => Some(self.owner_doc()),
3808 }
3809 }
3810
3811 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3813 if !options.composed &&
3814 let Some(shadow_root) = self.containing_shadow_root()
3815 {
3816 return DomRoot::upcast(shadow_root);
3817 }
3818
3819 if self.is_connected() {
3820 DomRoot::upcast(self.owner_document())
3821 } else {
3822 self.inclusive_ancestors(ShadowIncluding::Yes)
3823 .last()
3824 .unwrap()
3825 }
3826 }
3827
3828 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
3830 self.parent_node().get()
3831 }
3832
3833 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
3835 self.GetParentNode().and_then(DomRoot::downcast)
3836 }
3837
3838 fn HasChildNodes(&self) -> bool {
3840 self.first_child().get().is_some()
3841 }
3842
3843 fn ChildNodes(&self, cx: &mut JSContext) -> DomRoot<NodeList> {
3845 if let Some(list) = self.ensure_rare_data().child_list.get() {
3846 return list;
3847 }
3848
3849 let doc = self.owner_doc();
3850 let window = doc.window();
3851 let list = NodeList::new_child_list(cx, window, self);
3852 self.ensure_rare_data().child_list.set(Some(&list));
3853 list
3854 }
3855
3856 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
3858 self.first_child().get()
3859 }
3860
3861 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
3863 self.last_child().get()
3864 }
3865
3866 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
3868 self.prev_sibling().get()
3869 }
3870
3871 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
3873 self.next_sibling().get()
3874 }
3875
3876 fn GetNodeValue(&self) -> Option<DOMString> {
3878 match self.type_id() {
3879 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3880 NodeTypeId::CharacterData(_) => {
3881 self.downcast::<CharacterData>().map(CharacterData::Data)
3882 },
3883 _ => None,
3884 }
3885 }
3886
3887 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
3889 match self.type_id() {
3890 NodeTypeId::Attr => {
3891 let attr = self.downcast::<Attr>().unwrap();
3892 attr.SetValue(cx, val.unwrap_or_default())?;
3893 },
3894 NodeTypeId::CharacterData(_) => {
3895 let character_data = self.downcast::<CharacterData>().unwrap();
3896 character_data.SetData(cx, val.unwrap_or_default());
3897 },
3898 _ => {},
3899 };
3900 Ok(())
3901 }
3902
3903 fn GetTextContent(&self) -> Option<DOMString> {
3905 match self.type_id() {
3906 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3907 let content =
3908 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
3909 Some(content)
3910 },
3911 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3912 NodeTypeId::CharacterData(..) => {
3913 let characterdata = self.downcast::<CharacterData>().unwrap();
3914 Some(characterdata.Data())
3915 },
3916 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
3917 }
3918 }
3919
3920 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
3922 match self.type_id() {
3923 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3924 self.set_text_content_for_element(cx, value);
3925 },
3926 NodeTypeId::Attr => {
3927 let attr = self.downcast::<Attr>().unwrap();
3928 attr.SetValue(cx, value.unwrap_or_default())?;
3929 },
3930 NodeTypeId::CharacterData(..) => {
3931 let characterdata = self.downcast::<CharacterData>().unwrap();
3932 characterdata.SetData(cx, value.unwrap_or_default());
3933 },
3934 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
3935 };
3936 Ok(())
3937 }
3938
3939 fn InsertBefore(
3941 &self,
3942 cx: &mut JSContext,
3943 node: &Node,
3944 child: Option<&Node>,
3945 ) -> Fallible<DomRoot<Node>> {
3946 Node::pre_insert(cx, node, self, child)
3947 }
3948
3949 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3951 Node::pre_insert(cx, node, self, None)
3952 }
3953
3954 fn ReplaceChild(
3956 &self,
3957 cx: &mut JSContext,
3958 node: &Node,
3959 child: &Node,
3960 ) -> Fallible<DomRoot<Node>> {
3961 Node::ensure_pre_insertion_validity(cx.no_gc(), node, self, Some(child), &[child])?;
3963
3964 let child_next_sibling = child.GetNextSibling();
3967 let node_next_sibling = node.GetNextSibling();
3968 let reference_child = if child_next_sibling.as_deref() == Some(node) {
3969 node_next_sibling.as_deref()
3970 } else {
3971 child_next_sibling.as_deref()
3972 };
3973
3974 let previous_sibling = child.GetPreviousSibling();
3976
3977 let document = self.owner_document();
3980 Node::adopt(cx, node, &document);
3981
3982 let removed_child = if node != child {
3986 Node::remove(cx, child, self, SuppressObserver::Suppressed);
3987 Some(child)
3988 } else {
3989 None
3990 };
3991
3992 rooted_vec!(let mut nodes);
3994 let nodes = if node.type_id() ==
3995 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
3996 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
3997 {
3998 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
3999 nodes.r()
4000 } else {
4001 from_ref(&node)
4002 };
4003
4004 Node::insert(
4006 cx,
4007 node,
4008 self,
4009 reference_child,
4010 SuppressObserver::Suppressed,
4011 );
4012
4013 vtable_for(self).children_changed(
4014 cx,
4015 &ChildrenMutation::replace(
4016 previous_sibling.as_deref(),
4017 &removed_child,
4018 reference_child,
4019 ),
4020 );
4021
4022 let removed = removed_child.map(|r| [r]);
4025 let mutation = LazyCell::new(|| Mutation::ChildList {
4026 added: Some(nodes),
4027 removed: removed.as_ref().map(|r| &r[..]),
4028 prev: previous_sibling.as_deref(),
4029 next: reference_child,
4030 });
4031
4032 MutationObserver::queue_a_mutation_record(cx, self, mutation);
4033
4034 Ok(DomRoot::from_ref(child))
4036 }
4037
4038 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
4040 Node::pre_remove(cx, node, self)
4041 }
4042
4043 fn Normalize(&self, cx: &mut JSContext) {
4045 let mut children = self.children().peekable();
4046
4047 let document = self.owner_document();
4048 let selection = document.selection();
4049 while let Some(node) = children.next() {
4050 let Some(text) = node.downcast::<Text>() else {
4053 node.Normalize(cx);
4054 continue;
4055 };
4056 if text.is::<CDATASection>() {
4057 continue;
4058 }
4059
4060 let cdata = text.upcast::<CharacterData>();
4062 let mut length = cdata.Length();
4063
4064 if length == 0 {
4067 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
4068 continue;
4069 }
4070
4071 let mut siblings_to_merge: SmallVec<[DomRoot<CharacterData>; 4]> = SmallVec::new();
4074 let mut new_data_length = 0;
4075 while let Some(sibling) = children.peek() {
4076 if !sibling.is::<Text>() || sibling.is::<CDATASection>() {
4077 break;
4078 }
4079
4080 let sibling: DomRoot<CharacterData> =
4081 DomRoot::downcast(children.next().expect("Guaranteed by the peek above"))
4082 .expect("Guaranteed by check above");
4083 new_data_length += sibling.data().len();
4084 siblings_to_merge.push(sibling);
4085 }
4086
4087 if siblings_to_merge.is_empty() {
4088 continue;
4089 }
4090
4091 let mut data = String::with_capacity(new_data_length);
4094 for sibling in &siblings_to_merge {
4095 data.push_str(sibling.data().as_str());
4096 }
4097
4098 cdata.append_data(cx, &data);
4100
4101 let first_sibling_index = LazyCell::new(|| node.index() + 1);
4105 for (current_node_index, current_node) in siblings_to_merge.iter().enumerate() {
4106 let index = &|| *first_sibling_index + current_node_index as u32;
4107 if let Some(selection) = &selection {
4109 selection.normalization_steps(
4110 self,
4111 &node,
4112 current_node.upcast(),
4113 &index,
4114 length,
4115 );
4116 }
4117 document.live_range_normalization_steps(
4118 cx.no_gc(),
4119 self,
4120 &node,
4121 current_node.upcast(),
4122 &index,
4123 length,
4124 );
4125 length += current_node.Length();
4127 }
4130
4131 for current_node in siblings_to_merge.into_iter() {
4134 Node::remove(
4135 cx,
4136 current_node.upcast(),
4137 self,
4138 SuppressObserver::Unsuppressed,
4139 );
4140 }
4141 }
4142 }
4143
4144 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
4146 if self.is::<ShadowRoot>() {
4148 return Err(Error::NotSupported(Some(
4149 "Cannot clone a shadow root".into(),
4150 )));
4151 }
4152
4153 let result = Node::clone(
4155 cx,
4156 self,
4157 None,
4158 if subtree {
4159 CloneChildrenFlag::CloneChildren
4160 } else {
4161 CloneChildrenFlag::DoNotCloneChildren
4162 },
4163 None,
4164 );
4165 Ok(result)
4166 }
4167
4168 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
4170 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
4171 let doctype = node.downcast::<DocumentType>().unwrap();
4172 let other_doctype = other.downcast::<DocumentType>().unwrap();
4173 (*doctype.name() == *other_doctype.name()) &&
4174 (*doctype.public_id() == *other_doctype.public_id()) &&
4175 (*doctype.system_id() == *other_doctype.system_id())
4176 }
4177 fn is_equal_element(node: &Node, other: &Node) -> bool {
4178 let element = node.downcast::<Element>().unwrap();
4179 let other_element = other.downcast::<Element>().unwrap();
4180 (*element.namespace() == *other_element.namespace()) &&
4181 (*element.prefix() == *other_element.prefix()) &&
4182 (*element.local_name() == *other_element.local_name()) &&
4183 (element.attrs().borrow().len() == other_element.attrs().borrow().len())
4184 }
4185 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
4186 let pi = node.downcast::<ProcessingInstruction>().unwrap();
4187 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
4188 (*pi.target() == *other_pi.target()) &&
4189 (*pi.upcast::<CharacterData>().data() ==
4190 *other_pi.upcast::<CharacterData>().data())
4191 }
4192 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
4193 let characterdata = node.downcast::<CharacterData>().unwrap();
4194 let other_characterdata = other.downcast::<CharacterData>().unwrap();
4195 *characterdata.data() == *other_characterdata.data()
4196 }
4197 fn is_equal_attr(node: &Node, other: &Node) -> bool {
4198 let attr = node.downcast::<Attr>().unwrap();
4199 let other_attr = other.downcast::<Attr>().unwrap();
4200 (*attr.namespace() == *other_attr.namespace()) &&
4201 (attr.local_name() == other_attr.local_name()) &&
4202 (**attr.value() == **other_attr.value())
4203 }
4204 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
4205 let element = node.downcast::<Element>().unwrap();
4206 let other_element = other.downcast::<Element>().unwrap();
4207 assert!(element.attrs().borrow().len() == other_element.attrs().borrow().len());
4208 element.attrs().borrow().iter().all(|attr| {
4209 other_element.attrs().borrow().iter().any(|other_attr| {
4210 (*attr.namespace() == *other_attr.namespace()) &&
4211 (attr.local_name() == other_attr.local_name()) &&
4212 (**attr.value() == **other_attr.value())
4213 })
4214 })
4215 }
4216
4217 fn is_equal_node(this: &Node, node: &Node) -> bool {
4218 if this.NodeType() != node.NodeType() {
4220 return false;
4221 }
4222
4223 match node.type_id() {
4224 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
4226 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
4227 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
4228 if !is_equal_processinginstruction(this, node) =>
4229 {
4230 return false;
4231 },
4232 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
4233 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
4234 if !is_equal_characterdata(this, node) =>
4235 {
4236 return false;
4237 },
4238 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
4240 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
4241
4242 _ => (),
4243 }
4244
4245 if this.children_count() != node.children_count() {
4247 return false;
4248 }
4249
4250 this.children()
4252 .zip(node.children())
4253 .all(|(child, other_child)| is_equal_node(&child, &other_child))
4254 }
4255 match maybe_node {
4256 None => false,
4258 Some(node) => is_equal_node(self, node),
4260 }
4261 }
4262
4263 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
4265 match other_node {
4266 Some(node) => self == node,
4267 None => false,
4268 }
4269 }
4270
4271 fn CompareDocumentPosition(&self, no_gc: &NoGC, other: &Node) -> u16 {
4273 if self == other {
4275 return 0;
4276 }
4277
4278 let mut node1 = Some(other);
4280 let mut node2 = Some(self);
4281
4282 let mut attr1: Option<&Attr> = None;
4284 let mut attr2: Option<&Attr> = None;
4285
4286 let attr1owner;
4291 if let Some(a) = other.downcast::<Attr>() {
4292 attr1 = Some(a);
4293 attr1owner = a.GetOwnerElement();
4294 node1 = match attr1owner {
4295 Some(ref e) => Some(e.upcast()),
4296 None => None,
4297 }
4298 }
4299
4300 let attr2owner;
4303 if let Some(a) = self.downcast::<Attr>() {
4304 attr2 = Some(a);
4305 attr2owner = a.GetOwnerElement();
4306 node2 = match attr2owner {
4307 Some(ref e) => Some(e.upcast()),
4308 None => None,
4309 }
4310 }
4311
4312 if let Some(node2) = node2 &&
4317 Some(node2) == node1 &&
4318 let (Some(a1), Some(a2)) = (attr1, attr2)
4319 {
4320 let attrs = node2.downcast::<Element>().unwrap().attrs();
4321 for attr in attrs.borrow().iter() {
4325 if (*attr.namespace() == *a1.namespace()) &&
4326 (attr.local_name() == a1.local_name()) &&
4327 (**attr.value() == **a1.value())
4328 {
4329 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4330 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4331 }
4332 if (*attr.namespace() == *a2.namespace()) &&
4333 (attr.local_name() == a2.local_name()) &&
4334 (**attr.value() == **a2.value())
4335 {
4336 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4337 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4338 }
4339 }
4340 unreachable!();
4343 }
4344
4345 let options = GetRootNodeOptions { composed: false };
4351 let node1_root = node1.map(|node| node.GetRootNode(&options));
4352 let node2_root = node2.map(|node| node.GetRootNode(&options));
4353 if node1_root.is_none() || node2_root.is_none() || node1_root != node2_root {
4354 let pointer1 = node1.map(as_uintptr::<Node>).unwrap_or_default();
4357 let pointer2 = node2.map(as_uintptr::<Node>).unwrap_or_default();
4358 let arbitrary_order = if pointer1 < pointer2 {
4359 NodeConstants::DOCUMENT_POSITION_PRECEDING
4360 } else {
4361 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4362 };
4363
4364 return arbitrary_order +
4365 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4366 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4367 }
4368
4369 let (ordering, containment_flags) = match (node1, node2) {
4371 (Some(node1), Some(node2)) => {
4372 compare_dom_positions::<LightDomNoGcTraversal>(no_gc, node1, 0, node2, 0)
4373 },
4374 _ => (None, DomPositionContainment::empty()),
4375 };
4376
4377 if (containment_flags.contains(DomPositionContainment::AContainsB) && attr1.is_none()) ||
4381 (node1 == node2 && attr2.is_some())
4382 {
4383 return NodeConstants::DOCUMENT_POSITION_CONTAINS +
4384 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4385 }
4386
4387 if (containment_flags.contains(DomPositionContainment::BContainsA) && attr2.is_none()) ||
4391 (node1 == node2 && attr1.is_some())
4392 {
4393 return NodeConstants::DOCUMENT_POSITION_CONTAINED_BY +
4394 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4395 }
4396
4397 if ordering == Some(Ordering::Less) {
4399 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4400 }
4401
4402 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4404 }
4405
4406 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4408 match maybe_other {
4409 None => false,
4410 Some(other) => self.is_inclusive_ancestor_of(other),
4411 }
4412 }
4413
4414 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4416 let namespace = namespace_from_domstring(namespace);
4417
4418 if namespace == ns!() {
4420 return None;
4421 }
4422
4423 match self.type_id() {
4425 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4426 NodeTypeId::Document(_) => self
4427 .downcast::<Document>()
4428 .unwrap()
4429 .GetDocumentElement()
4430 .and_then(|element| element.lookup_prefix(namespace)),
4431 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4432 NodeTypeId::Attr => self
4433 .downcast::<Attr>()
4434 .unwrap()
4435 .GetOwnerElement()
4436 .and_then(|element| element.lookup_prefix(namespace)),
4437 _ => self
4438 .GetParentElement()
4439 .and_then(|element| element.lookup_prefix(namespace)),
4440 }
4441 }
4442
4443 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4445 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4447
4448 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4450 }
4451
4452 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4454 let namespace = namespace_from_domstring(namespace);
4456 Node::locate_namespace(self, None) == namespace
4458 }
4459}
4460
4461pub(crate) trait NodeTraits {
4462 fn owner_document(&self) -> DomRoot<Document>;
4466 fn owner_document_unrooted<'no_gc>(&self, no_gc: &'no_gc NoGC)
4470 -> UnrootedDom<'no_gc, Document>;
4471 fn owner_window(&self) -> DomRoot<Window>;
4475 fn owner_window_unrooted<'no_gc>(&self, no_gc: &'no_gc NoGC) -> UnrootedDom<'no_gc, Window>;
4479 fn owner_global(&self) -> DomRoot<GlobalScope>;
4483 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4485 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4488}
4489
4490impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4491 fn owner_document(&self) -> DomRoot<Document> {
4492 self.upcast().owner_doc()
4493 }
4494
4495 fn owner_document_unrooted<'no_gc>(
4496 &self,
4497 no_gc: &'no_gc NoGC,
4498 ) -> UnrootedDom<'no_gc, Document> {
4499 self.upcast().owner_doc_unrooted(no_gc)
4500 }
4501
4502 fn owner_window(&self) -> DomRoot<Window> {
4503 DomRoot::from_ref(self.owner_document().window())
4504 }
4505
4506 fn owner_window_unrooted<'no_gc>(&self, no_gc: &'no_gc NoGC) -> UnrootedDom<'no_gc, Window> {
4507 UnrootedDom::from_ref(self.owner_document_unrooted(no_gc).window(), no_gc)
4508 }
4509
4510 fn owner_global(&self) -> DomRoot<GlobalScope> {
4511 DomRoot::from_ref(self.owner_window().upcast())
4512 }
4513
4514 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4515 Node::containing_shadow_root(self.upcast())
4516 }
4517
4518 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4519 self.containing_shadow_root()
4520 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4521 .unwrap_or_else(|| {
4522 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4523 })
4524 }
4525}
4526
4527impl VirtualMethods for Node {
4528 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4529 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4530 }
4531
4532 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4533 if let Some(s) = self.super_type() {
4534 s.children_changed(cx, mutation);
4535 }
4536
4537 if let Some(data) = self.rare_data.borrow().as_ref() &&
4538 let Some(list) = data.child_list.get()
4539 {
4540 list.as_children_list().children_changed(mutation);
4541 }
4542
4543 self.owner_doc_unrooted(cx.no_gc())
4544 .content_and_heritage_changed(cx.no_gc(), self);
4545 }
4546
4547 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
4548 if let Some(super_type) = self.super_type() {
4549 super_type.moving_steps(cx, context);
4550 }
4551
4552 self.owner_doc_unrooted(cx.no_gc())
4553 .content_and_heritage_changed(cx.no_gc(), self);
4554
4555 if let Some(parent) = self.GetParentNode() {
4556 Self::maybe_dirty_visible_selection_for_newly_inserted_nodes(
4557 cx.no_gc(),
4558 &parent,
4559 &[self],
4560 );
4561 }
4562 }
4563
4564 fn handle_event(&self, cx: &mut JSContext, event: &Event) {
4565 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4566 return;
4567 }
4568
4569 if event.type_() == atom!("keydown") &&
4570 let Some(event) = event.downcast::<KeyboardEvent>()
4571 {
4572 self.owner_document()
4573 .event_handler()
4574 .maybe_dispatch_simulated_click(cx, self, event);
4575 }
4576 }
4577}
4578
4579#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4581pub(crate) enum NodeDamage {
4582 Style,
4584 ContentOrHeritage,
4587 Other,
4589}
4590
4591pub(crate) trait VecPreOrderInsertionHelper<T> {
4594 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
4595}
4596
4597impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
4598where
4599 T: DerivedFrom<Node> + DomObject,
4600{
4601 fn insert_pre_order(&mut self, node: &T, tree_root: &Node) {
4606 let Err(insertion_index) = self.binary_search_by(|candidate| {
4607 candidate.upcast().compare_dom_tree_position(
4608 node.upcast(),
4609 tree_root,
4610 ShadowIncluding::No,
4611 )
4612 }) else {
4613 return;
4616 };
4617
4618 self.insert(insertion_index, Dom::from_ref(node));
4619 }
4620}
4621
4622pub(crate) enum FlatTreeParent<'a> {
4624 Parent(UnrootedDom<'a, Node>),
4626 NotInFlatTree,
4629 RootNode,
4631}
4632
4633impl<'a> FlatTreeParent<'a> {
4634 pub(crate) fn into_parent(self) -> Option<UnrootedDom<'a, Node>> {
4635 match self {
4636 FlatTreeParent::Parent(parent) => Some(parent),
4637 FlatTreeParent::NotInFlatTree | FlatTreeParent::RootNode => None,
4638 }
4639 }
4640}
4641
4642enum MoveOrInsert {
4643 Move,
4644 Insert,
4645}