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::ElementBinding::ElementMethods;
35use script_bindings::codegen::GenericBindings::EventBinding::EventMethods;
36use script_bindings::codegen::GenericBindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
37use script_bindings::codegen::InheritTypes::{DocumentFragmentTypeId, TextTypeId};
38use script_bindings::reflector::{
39 DomObject, DomObjectWrap, WeakReferenceableDomObjectWrap, reflect_dom_object_with_proto,
40 reflect_weak_referenceable_dom_object_with_proto,
41};
42use script_traits::{DocumentActivity, MouseButtons};
43use servo_base::id::PipelineId;
44use smallvec::SmallVec;
45use style::Atom;
46use style::context::QuirksMode;
47use style::dom::OpaqueNode;
48use style::dom_apis::{QueryAll, QueryFirst};
49use style::selector_parser::PseudoElement;
50use style_traits::CSSPixel;
51use uuid::Uuid;
52use xml5ever::{local_name, serialize as xml_serialize};
53
54use crate::dom::ChildrenMutation;
55use crate::dom::attr::Attr;
56use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
57use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
58use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
59use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
60use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
61use crate::dom::bindings::codegen::Bindings::NodeBinding::{
62 GetRootNodeOptions, NodeConstants, NodeMethods,
63};
64use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
65use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
66use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
67 ShadowRootMode, SlotAssignmentMode,
68};
69use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
70use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
71use crate::dom::bindings::conversions::{self, DerivedFrom};
72use crate::dom::bindings::domname::namespace_from_domstring;
73use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
74use crate::dom::bindings::inheritance::{
75 Castable, CharacterDataTypeId, EventTargetTypeId, NodeTypeId,
76};
77use crate::dom::bindings::root::{
78 Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout, UnrootedDom,
79};
80use crate::dom::bindings::str::{DOMString, USVString};
81use crate::dom::characterdata::CharacterData;
82use crate::dom::comparator::{DomPositionContainment, compare_dom_positions};
83use crate::dom::context::{BindContext, IsShadowTree, MoveContext, UnbindContext};
84use crate::dom::css::cssstylesheet::CSSStyleSheet;
85use crate::dom::css::stylesheetlist::StyleSheetListOwner;
86use crate::dom::customelementregistry::{
87 CallbackReaction, CustomElementRegistry, try_upgrade_element,
88};
89use crate::dom::document::{Document, HasBrowsingContext, IsHTMLDocument};
90use crate::dom::documentfragment::DocumentFragment;
91use crate::dom::documenttype::DocumentType;
92use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
93use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
94use crate::dom::eventtarget::EventTarget;
95use crate::dom::globalscope::GlobalScope;
96use crate::dom::html::htmlcollection::HTMLCollection;
97use crate::dom::html::htmlelement::HTMLElement;
98use crate::dom::html::htmllinkelement::HTMLLinkElement;
99use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
100use crate::dom::html::htmlstyleelement::HTMLStyleElement;
101use crate::dom::iterators::{
102 ShadowIncluding, UnrootedAncestorIterator, UnrootedFollowingFlatTreeNodesTraversal,
103 UnrootedFollowingNodeIterator, UnrootedPrecedingNodeIterator,
104};
105use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
106use crate::dom::node::iterators::{
107 FollowingNodeIterator, PrecedingNodeIterator, SimpleNodeIterator, TreeIterator,
108 UnrootedSimpleNodeIterator, UnrootedTreeIterator,
109};
110use crate::dom::node::nodelist::NodeList;
111use crate::dom::node::virtualmethods::{VirtualMethods, vtable_for};
112use crate::dom::pointerevent::{PointerEvent, PointerId};
113use crate::dom::raredata::NodeRareData;
114use crate::dom::servoparser::html::HtmlSerialize;
115use crate::dom::servoparser::serialize_html_fragment;
116use crate::dom::shadowroot::shadowroot::{IsUserAgentWidget, ShadowRoot};
117use crate::dom::text::Text;
118use crate::dom::traversal::LightDomNoGcTraversal;
119use crate::dom::types::{CDATASection, KeyboardEvent, ProcessingInstruction};
120use crate::dom::window::Window;
121use crate::event_loop::document_loader::DocumentLoader;
122use crate::event_loop::script_thread::ScriptThread;
123use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode};
124
125#[dom_struct]
127pub struct Node {
128 eventtarget: EventTarget,
130
131 parent_node: MutNullableDom<Node>,
133
134 first_child: MutNullableDom<Node>,
136
137 last_child: MutNullableDom<Node>,
139
140 next_sibling: MutNullableDom<Node>,
142
143 prev_sibling: MutNullableDom<Node>,
145
146 owner_doc: MutNullableDom<Document>,
148
149 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
151
152 children_count: Cell<u32>,
154
155 flags: Cell<NodeFlags>,
157
158 inclusive_descendants_version: Cell<u64>,
160
161 #[no_trace]
164 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
165}
166
167impl fmt::Debug for Node {
168 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169 if let Some(element) = self.downcast::<Element>() {
170 element.fmt(f)
171 } else if let Some(character_data) = self.downcast::<CharacterData>() {
172 write!(f, "[Text({})]", *character_data.data())
173 } else {
174 write!(f, "[Node({:?})]", self.type_id())
175 }
176 }
177}
178
179#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
181pub(crate) struct NodeFlags(u16);
182
183bitflags! {
184 impl NodeFlags: u16 {
185 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
189
190 const HAS_DIRTY_DESCENDANTS = 1 << 1;
192
193 const CLICK_IN_PROGRESS = 1 << 2;
196
197 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
202
203 const HAS_SNAPSHOT = 1 << 7;
208
209 const HANDLED_SNAPSHOT = 1 << 8;
211
212 const IS_IN_SHADOW_TREE = 1 << 9;
214
215 const IS_CONNECTED = 1 << 10;
219
220 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
223
224 const IS_IN_UA_WIDGET = 1 << 12;
227
228 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
230
231 const OVERLAPS_DOCUMENT_SELECTION = 1 << 14;
238
239 const SELECTION_INHIBITED = 1 << 15;
242 }
243}
244
245#[derive(Clone, Copy, MallocSizeOf)]
249pub(crate) enum SuppressObserver {
250 Suppressed,
251 Unsuppressed,
252}
253
254pub(crate) enum ForceSlottableNodeReconciliation {
255 Force,
256 Skip,
257}
258
259impl Node {
260 pub(super) fn parent_node(&self) -> &MutNullableDom<Node> {
262 &self.parent_node
263 }
264
265 pub(super) fn first_child(&self) -> &MutNullableDom<Node> {
266 &self.first_child
267 }
268
269 pub(super) fn last_child(&self) -> &MutNullableDom<Node> {
270 &self.last_child
271 }
272
273 pub(super) fn next_sibling(&self) -> &MutNullableDom<Node> {
274 &self.next_sibling
275 }
276
277 pub(super) fn prev_sibling(&self) -> &MutNullableDom<Node> {
278 &self.prev_sibling
279 }
280
281 pub(super) fn get_owner_doc(&self) -> &MutNullableDom<Document> {
282 &self.owner_doc
283 }
284
285 pub(super) fn get_rare_data(&self) -> &DomRefCell<Option<Box<NodeRareData>>> {
286 &self.rare_data
287 }
288
289 pub(super) fn flags(&self) -> &Cell<NodeFlags> {
290 &self.flags
291 }
292
293 pub(crate) fn layout_data(&self) -> &DomRefCell<Option<Box<GenericLayoutData>>> {
294 &self.layout_data
295 }
296
297 fn add_child(&self, cx: &mut JSContext, new_child: &Node, before: Option<&Node>) {
301 assert!(new_child.parent_node.get().is_none());
302 assert!(new_child.prev_sibling.get().is_none());
303 assert!(new_child.next_sibling.get().is_none());
304
305 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
306
307 match before {
308 Some(before) => {
309 assert!(before.parent_node.get().as_deref() == Some(self));
310 let prev_sibling = before.GetPreviousSibling();
311 match prev_sibling {
312 None => {
313 assert!(self.first_child.get().as_deref() == Some(before));
314 self.first_child.set(Some(new_child));
315 },
316 Some(ref prev_sibling) => {
317 prev_sibling.next_sibling.set(Some(new_child));
318 new_child.prev_sibling.set(Some(prev_sibling));
319 },
320 }
321 before.prev_sibling.set(Some(new_child));
322 new_child.next_sibling.set(Some(before));
323 },
324 None => {
325 let last_child = self.GetLastChild();
326 match last_child {
327 None => self.first_child.set(Some(new_child)),
328 Some(ref last_child) => {
329 assert!(last_child.next_sibling.get().is_none());
330 last_child.next_sibling.set(Some(new_child));
331 new_child.prev_sibling.set(Some(last_child));
332 },
333 }
334
335 self.last_child.set(Some(new_child));
336 },
337 }
338
339 new_child.parent_node.set(Some(self));
340 self.children_count.set(self.children_count.get() + 1);
341
342 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
343 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
344 let parent_is_connected = self.is_connected();
345 let parent_is_in_ua_widget = self.is_in_ua_widget();
346
347 let context = BindContext::new(self, IsShadowTree::No);
348
349 for node in new_child.traverse_preorder(ShadowIncluding::No) {
350 if parent_in_shadow_tree {
351 if let Some(shadow_root) = self.containing_shadow_root() {
352 node.set_containing_shadow_root(Some(&*shadow_root));
353 }
354 debug_assert!(node.containing_shadow_root().is_some());
355 }
356 node.set_flag(
357 NodeFlags::IS_IN_A_DOCUMENT_TREE,
358 parent_is_in_a_document_tree,
359 );
360 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
361 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
362 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
363
364 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
366 vtable_for(&node).bind_to_tree(cx, &context);
367 }
368 }
369
370 pub(crate) fn complete_remove_subtree(
373 cx: &mut JSContext,
374 root: &Node,
375 context: &UnbindContext,
376 ) {
377 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
379 .union(NodeFlags::IS_CONNECTED)
380 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
381 .union(NodeFlags::HAS_SNAPSHOT)
382 .union(NodeFlags::HANDLED_SNAPSHOT)
383 .union(NodeFlags::OVERLAPS_DOCUMENT_SELECTION)
384 .union(NodeFlags::SELECTION_INHIBITED);
385
386 for node in root.traverse_preorder_unrooted(cx.no_gc(), ShadowIncluding::No) {
387 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
388
389 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
392 for node in shadow_root
393 .upcast::<Node>()
394 .traverse_preorder_unrooted(cx.no_gc(), ShadowIncluding::Yes)
395 {
396 node.set_flag(RESET_FLAGS, false);
397 }
398 }
399 }
400
401 let is_parent_connected = context.parent.is_connected();
403 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
404
405 let document = root.owner_doc();
408 let cleanup_node = |cx: &mut JSContext, node: &Node| {
409 document.cancel_animations_for_node(node);
410 document.clean_up_style_and_layout_data_for_node(node);
411
412 vtable_for(node).unbind_from_tree(cx, context);
417
418 if is_parent_connected && let Some(element) = node.as_custom_element() {
420 custom_element_reaction_stack.enqueue_callback_reaction(
421 cx,
422 &element,
423 CallbackReaction::Disconnected,
424 None,
425 );
426 }
427 };
428
429 for node in root.traverse_preorder(ShadowIncluding::No) {
430 cleanup_node(cx, &node);
431
432 if node.containing_shadow_root().is_some() {
435 node.set_containing_shadow_root(None);
438 }
439
440 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
443 for node in shadow_root
444 .upcast::<Node>()
445 .traverse_preorder(ShadowIncluding::Yes)
446 {
447 cleanup_node(cx, &node);
448 }
449 }
450 }
451
452 if root.owner_document().accessibility_active() {
455 root.owner_document()
456 .accessibility_data_mut()
457 .root_removed_node(cx.no_gc(), root);
458 }
459 }
460
461 pub(crate) fn complete_move_subtree(cx: &mut JSContext, root: &Node) {
462 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
464 .union(NodeFlags::IS_CONNECTED)
465 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
466 .union(NodeFlags::HAS_SNAPSHOT)
467 .union(NodeFlags::HANDLED_SNAPSHOT)
468 .union(NodeFlags::OVERLAPS_DOCUMENT_SELECTION)
469 .union(NodeFlags::SELECTION_INHIBITED);
470
471 let document = root.owner_document();
472 for node in root.traverse_preorder(ShadowIncluding::No) {
473 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
474 document.clean_up_style_and_layout_data_for_node(&node);
475
476 if let Some(element) = node.downcast::<Element>() {
479 element.unregister_current_id_and_name_attribute(cx);
480 }
481
482 if node.containing_shadow_root().is_some() {
485 node.set_containing_shadow_root(None);
488 }
489
490 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
494 for node in shadow_root
495 .upcast::<Node>()
496 .traverse_preorder(ShadowIncluding::Yes)
497 {
498 node.set_flag(RESET_FLAGS, false);
499 document.clean_up_style_and_layout_data_for_node(&node);
500 }
501 }
502 }
503 }
504
505 fn remove_child(&self, cx: &mut JSContext, child: &Node) {
509 assert!(child.parent_node.get().as_deref() == Some(self));
510
511 if let Some(element) = self.downcast::<Element>() {
512 element.note_dirty_descendants(cx.no_gc());
513 }
514 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
515
516 let prev_sibling = child.GetPreviousSibling();
517 match prev_sibling {
518 None => {
519 self.first_child.set(child.next_sibling.get().as_deref());
520 },
521 Some(ref prev_sibling) => {
522 prev_sibling
523 .next_sibling
524 .set(child.next_sibling.get().as_deref());
525 },
526 }
527 let next_sibling = child.GetNextSibling();
528 match next_sibling {
529 None => {
530 self.last_child.set(child.prev_sibling.get().as_deref());
531 },
532 Some(ref next_sibling) => {
533 next_sibling
534 .prev_sibling
535 .set(child.prev_sibling.get().as_deref());
536 },
537 }
538
539 let context = UnbindContext::new(self, next_sibling.as_deref());
540
541 child.prev_sibling.set(None);
542 child.next_sibling.set(None);
543 child.parent_node.set(None);
544 self.children_count.set(self.children_count.get() - 1);
545
546 Self::complete_remove_subtree(cx, child, &context);
547 }
548
549 fn move_child(&self, cx: &mut JSContext, child: &Node) {
550 assert!(child.parent_node.get().as_deref() == Some(self));
551 self.dirty(cx.no_gc(), NodeDamage::ContentOrHeritage);
552 if let Some(element) = self.downcast::<Element>() {
553 element.note_dirty_descendants(cx.no_gc());
554 }
555
556 self.add_pending_accessibility_damage(AccessibilityDamage::Children);
557
558 child.prev_sibling.set(None);
559 child.next_sibling.set(None);
560 child.parent_node.set(None);
561 self.children_count.set(self.children_count.get() - 1);
562 Self::complete_move_subtree(cx, child)
563 }
564
565 pub(crate) fn to_opaque(&self) -> OpaqueNode {
566 OpaqueNode(self.reflector().get_jsobject().get() as usize)
567 }
568
569 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
570 self.downcast::<Element>().and_then(|element| {
571 if element.is_custom() {
572 assert!(element.get_custom_element_definition().is_some());
573 Some(DomRoot::from_ref(element))
574 } else {
575 None
576 }
577 })
578 }
579
580 pub(crate) fn fire_synthetic_pointer_event_not_trusted(
582 &self,
583 cx: &mut JSContext,
584 event_type: Atom,
585 ) {
586 let window = self.owner_window();
590
591 let pointer_event = PointerEvent::new(
593 cx,
594 &window, event_type,
596 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![], );
623
624 pointer_event.upcast::<Event>().set_composed(true);
626
627 pointer_event.upcast::<Event>().set_trusted(false);
629
630 pointer_event
633 .upcast::<Event>()
634 .dispatch(cx, self.upcast::<EventTarget>(), false);
635 }
636
637 pub(crate) fn parent_directionality(&self) -> String {
638 let mut current = self.GetParentNode();
639
640 loop {
641 match current {
642 Some(node) => {
643 if let Some(directionality) = node
644 .downcast::<HTMLElement>()
645 .and_then(|html_element| html_element.directionality())
646 {
647 return directionality;
648 } else {
649 current = node.GetParentNode();
650 }
651 },
652 None => return "ltr".to_owned(),
653 }
654 }
655 }
656
657 pub(crate) fn is_being_rendered_or_delegates_rendering(
661 &self,
662 pseudo_element: Option<PseudoElement>,
663 ) -> bool {
664 matches!(
665 self.owner_window()
666 .layout()
667 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
668 NodeRenderingType::Rendered | NodeRenderingType::DelegatesRendering
669 )
670 }
671
672 pub(crate) fn is_being_rendered(&self, pseudo_element: Option<PseudoElement>) -> bool {
674 matches!(
675 self.owner_window()
676 .layout()
677 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
678 NodeRenderingType::Rendered
679 )
680 }
681
682 pub(crate) fn add_pending_accessibility_damage(&self, damage: AccessibilityDamage) {
683 if !self.owner_doc().accessibility_active() {
684 return;
685 }
686
687 self.owner_doc()
688 .accessibility_data_mut()
689 .add_pending_accessibility_damage_for_node(self, damage);
690 }
691
692 pub(crate) fn set_element_selection(&self, selected: bool) -> bool {
695 debug_assert!(
696 self.downcast::<CharacterData>().is_none(),
697 "Should never be called on CharacterData"
698 );
699 self.layout_data()
700 .borrow()
701 .as_ref()
702 .is_some_and(|layout_data| layout_data.set_element_selection(selected))
703 }
704}
705
706impl Node {
707 fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
708 let mut rare_data = self.rare_data.borrow_mut();
709 if rare_data.is_none() {
710 *rare_data = Some(Default::default());
711 }
712 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
713 }
714
715 pub(crate) fn is_before(&self, no_gc: &NoGC, other: &Node) -> bool {
718 let cmp = other.CompareDocumentPosition(no_gc, self);
719 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
720 return false;
721 }
722
723 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
724 }
725
726 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
729 RefMut::map(self.ensure_rare_data(), |rare_data| {
730 &mut rare_data.mutation_observers
731 })
732 }
733
734 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
735 let rare_data = self.rare_data.borrow();
736 if rare_data.is_none() {
737 return None;
738 }
739 Some(Ref::map(rare_data, |rare_data| {
740 &rare_data.as_ref().unwrap().mutation_observers
741 }))
742 }
743
744 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
746 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
747 self.ensure_rare_data().mutation_observers.push(observer);
748 }
749
750 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
752 let mut rare_data = self.rare_data.borrow_mut();
753 let Some(rare_data) = rare_data.as_mut() else {
754 return;
755 };
756 rare_data
757 .mutation_observers
758 .retain(|registered_observer| &*registered_observer.observer != observer)
759 }
760
761 pub(crate) fn debug_str(&self) -> String {
763 format!("{:?}", self.type_id())
764 }
765
766 pub(crate) fn is_in_a_document_tree(&self) -> bool {
768 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
769 }
770
771 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
773 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
774 }
775
776 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
777 self.flags
778 .get()
779 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
780 }
781
782 pub(crate) fn set_weird_parser_insertion_mode(&self) {
783 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
784 }
785
786 pub(crate) fn is_connected(&self) -> bool {
788 self.flags.get().contains(NodeFlags::IS_CONNECTED)
789 }
790
791 pub(crate) fn is_in_flat_tree(&self, no_gc: &NoGC) -> bool {
796 if !self.is_connected() {
797 return false;
798 }
799
800 let mut node = UnrootedDom::from_ref(self, no_gc);
801 loop {
802 match node.parent_in_flat_tree(no_gc) {
803 FlatTreeParent::Parent(parent) => node = parent,
804 FlatTreeParent::NotInFlatTree => return false,
805 FlatTreeParent::RootNode => return true,
806 }
807 }
808 }
809
810 pub(crate) fn mark_in_ua_widget(&self) {
811 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, true)
812 }
813
814 pub(crate) fn is_in_ua_widget(&self) -> bool {
815 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
816 }
817
818 pub(crate) fn type_id(&self) -> NodeTypeId {
820 match *self.eventtarget.type_id() {
821 EventTargetTypeId::Node(type_id) => type_id,
822 _ => unreachable!(),
823 }
824 }
825
826 pub(crate) fn len(&self) -> u32 {
828 match self.type_id() {
829 NodeTypeId::DocumentType => 0,
830 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
831 _ => self.children_count(),
832 }
833 }
834
835 pub(crate) fn is_empty(&self) -> bool {
836 self.len() == 0
838 }
839
840 pub(crate) fn index(&self) -> u32 {
842 self.preceding_siblings().count() as u32
843 }
844
845 pub(crate) fn has_parent(&self) -> bool {
847 self.parent_node.get().is_some()
848 }
849
850 pub(crate) fn children_count(&self) -> u32 {
851 self.children_count.get()
852 }
853
854 #[inline]
855 pub(crate) fn is_doctype(&self) -> bool {
856 self.type_id() == NodeTypeId::DocumentType
857 }
858
859 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
860 self.flags.get().contains(flag)
861 }
862
863 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
864 let mut flags = self.flags.get();
865
866 if value {
867 flags.insert(flag);
868 } else {
869 flags.remove(flag);
870 }
871
872 self.flags.set(flags);
873 }
874
875 pub(crate) fn rev_version(&self, no_gc: &NoGC) {
876 let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
881 let version = cmp::max(
882 self.inclusive_descendants_version(),
883 doc.inclusive_descendants_version(),
884 ) + 1;
885
886 for node in self.inclusive_ancestors_unrooted(no_gc, ShadowIncluding::No) {
887 node.inclusive_descendants_version.set(version);
888 }
889 doc.inclusive_descendants_version.set(version);
890 }
891
892 pub(crate) fn clear_layout_data(&self) {
893 self.layout_data.take();
894 }
895
896 pub(crate) fn dirty(&self, no_gc: &NoGC, damage: NodeDamage) {
897 self.rev_version(no_gc);
898 if !self.is_connected() {
899 return;
900 }
901
902 match self.type_id() {
903 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..)) => {
904 *self.layout_data.borrow_mut() = None;
907
908 self.parent_node
912 .get()
913 .unwrap()
914 .dirty(no_gc, NodeDamage::ContentOrHeritage);
915
916 if damage == NodeDamage::Other {
917 self.add_pending_accessibility_damage(AccessibilityDamage::Node);
918 }
919 },
920 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(no_gc, damage),
921 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
922 .downcast::<ShadowRoot>()
923 .unwrap()
924 .Host()
925 .upcast::<Element>()
926 .restyle(no_gc, damage),
927 _ => {},
928 };
929 }
930
931 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
933 self.inclusive_descendants_version.get()
934 }
935
936 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
938 TreeIterator::new(self, shadow_including)
939 }
940
941 pub(crate) fn traverse_preorder_unrooted<'b>(
944 &self,
945 no_gc: &'b NoGC,
946 shadow_including: ShadowIncluding,
947 ) -> UnrootedTreeIterator<'b> {
948 UnrootedTreeIterator::new(self, shadow_including, no_gc)
949 }
950
951 pub(crate) fn inclusively_following_siblings(
952 &self,
953 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
954 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), |n| n.GetNextSibling())
955 }
956
957 pub(crate) fn inclusively_following_siblings_unrooted<'b>(
958 &self,
959 no_gc: &'b NoGC,
960 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
961 UnrootedSimpleNodeIterator::new(
962 Some(UnrootedDom::from_ref(self, no_gc)),
963 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
964 no_gc,
965 )
966 }
967
968 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
969 &self,
970 no_gc: &'b NoGC,
971 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
972 UnrootedSimpleNodeIterator::new(
973 Some(UnrootedDom::from_ref(self, no_gc)),
974 |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
975 no_gc,
976 )
977 }
978
979 pub(crate) fn common_ancestor(
980 &self,
981 other: &Node,
982 shadow_including: ShadowIncluding,
983 ) -> Option<DomRoot<Node>> {
984 self.inclusive_ancestors(shadow_including).find(|ancestor| {
985 other
986 .inclusive_ancestors(shadow_including)
987 .any(|node| node == *ancestor)
988 })
989 }
990
991 pub(crate) fn common_ancestor_in_flat_tree(
992 &self,
993 no_gc: &NoGC,
994 other: &Node,
995 ) -> Option<DomRoot<Node>> {
996 self.inclusive_ancestors_in_flat_tree_unrooted(no_gc)
997 .find(|ancestor| {
998 other
999 .inclusive_ancestors_in_flat_tree_unrooted(no_gc)
1000 .any(|node| node == *ancestor)
1001 })
1002 .map(|node| node.as_rooted())
1003 }
1004
1005 pub(crate) fn following_flat_tree_nodes_unrooted<'no_gc>(
1006 &self,
1007 no_gc: &'no_gc NoGC,
1008 ) -> UnrootedFollowingFlatTreeNodesTraversal<'no_gc> {
1009 UnrootedFollowingFlatTreeNodesTraversal::new(self, no_gc)
1010 }
1011
1012 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
1014 self == child || self.is_ancestor_of(child)
1016 }
1017
1018 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
1020 let mut current = &possible_descendant.parent_node;
1022 let mut done = false;
1023
1024 while let Some(node) = current.if_is_some(|node| {
1025 done = node == self;
1026 &node.parent_node
1027 }) {
1028 if done {
1029 break;
1030 }
1031 current = node
1032 }
1033 done
1034 }
1035
1036 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
1038 self.is_inclusive_ancestor_of(child) ||
1041 child
1042 .GetRootNode(&GetRootNodeOptions::empty())
1043 .downcast::<DocumentFragment>()
1044 .and_then(|fragment| fragment.host())
1045 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1046 }
1047
1048 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1050 node.inclusive_ancestors(ShadowIncluding::Yes)
1051 .any(|ancestor| &*ancestor == self)
1052 }
1053
1054 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1055 SimpleNodeIterator::new(self.GetNextSibling(), |n| n.GetNextSibling())
1056 }
1057
1058 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1059 SimpleNodeIterator::new(self.GetPreviousSibling(), |n| n.GetPreviousSibling())
1060 }
1061
1062 pub(crate) fn following_nodes(
1063 &self,
1064 root: &Node,
1065 shadow_including: ShadowIncluding,
1066 ) -> FollowingNodeIterator {
1067 FollowingNodeIterator::new(
1068 Some(DomRoot::from_ref(self)),
1069 DomRoot::from_ref(root),
1070 shadow_including,
1071 )
1072 }
1073
1074 pub(crate) fn following_nodes_unrooted<'b>(
1075 &self,
1076 no_gc: &'b NoGC,
1077 root: &Node,
1078 shadow_including: ShadowIncluding,
1079 ) -> UnrootedFollowingNodeIterator<'b> {
1080 UnrootedFollowingNodeIterator::new(
1081 Some(UnrootedDom::from_ref(self, no_gc)),
1082 UnrootedDom::from_ref(root, no_gc),
1083 shadow_including,
1084 no_gc,
1085 )
1086 }
1087
1088 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1089 PrecedingNodeIterator::new(Some(DomRoot::from_ref(self)), DomRoot::from_ref(root))
1090 }
1091
1092 pub(crate) fn preceding_nodes_unrooted<'b>(
1093 &self,
1094 no_gc: &'b NoGC,
1095 root: &Node,
1096 ) -> UnrootedPrecedingNodeIterator<'b> {
1097 UnrootedPrecedingNodeIterator::new(
1098 Some(UnrootedDom::from_ref(self, no_gc)),
1099 UnrootedDom::from_ref(root, no_gc),
1100 no_gc,
1101 )
1102 }
1103
1104 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1107 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetLastChild())
1108 }
1109
1110 pub(crate) fn descending_last_children_unrooted<'b>(
1111 &self,
1112 no_gc: &'b NoGC,
1113 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> {
1114 UnrootedSimpleNodeIterator::new(
1115 self.get_last_child_unrooted(no_gc),
1116 |n, no_gc| n.get_last_child_unrooted(no_gc),
1117 no_gc,
1118 )
1119 }
1120
1121 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1122 child
1123 .parent_node
1124 .get()
1125 .is_some_and(|parent| &*parent == self)
1126 }
1127
1128 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1129 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1130 }
1131
1132 pub(crate) fn containing_block_node_without_reflow(&self) -> Option<DomRoot<Node>> {
1134 self.owner_window()
1135 .containing_block_node_query_without_reflow(self)
1136 }
1137
1138 pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1139 self.owner_window().padding_query_without_reflow(self)
1140 }
1141
1142 pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1143 self.owner_window()
1144 .box_area_query(self, BoxAreaType::Content, false)
1145 }
1146
1147 pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1148 self.owner_window()
1149 .box_area_query(self, BoxAreaType::Border, false)
1150 }
1151
1152 pub(crate) fn border_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1153 self.owner_window()
1154 .box_area_query_without_reflow(self, BoxAreaType::Border, false)
1155 }
1156
1157 pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1158 self.owner_window()
1159 .box_area_query(self, BoxAreaType::Padding, false)
1160 }
1161
1162 pub(crate) fn padding_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1163 self.owner_window()
1164 .box_area_query_without_reflow(self, BoxAreaType::Padding, false)
1165 }
1166
1167 pub(crate) fn border_boxes(&self) -> CSSPixelRectVec {
1168 self.owner_window()
1169 .box_areas_query(self, BoxAreaType::Border)
1170 }
1171
1172 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1173 self.owner_window().client_rect_query(self)
1174 }
1175
1176 pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1179 let document = self.owner_doc();
1181
1182 if !document.is_active() {
1184 return Rect::zero();
1185 }
1186
1187 let window = document.window();
1190 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1191
1192 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1193 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1194 let is_body_element = self
1195 .downcast::<HTMLElement>()
1196 .is_some_and(|e| e.is_body_element());
1197
1198 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1204 let viewport_scrolling_area = window.scrolling_area_query(None);
1205 return Rect::new(
1206 viewport_scrolling_area.origin,
1207 viewport_scrolling_area.size.max(viewport),
1208 );
1209 }
1210
1211 window.scrolling_area_query(Some(self))
1215 }
1216
1217 pub(crate) fn effective_overflow(&self) -> Option<AxesOverflow> {
1218 self.owner_window().query_effective_overflow(self)
1219 }
1220
1221 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1222 self.owner_window()
1223 .query_effective_overflow_without_reflow(self)
1224 }
1225
1226 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1228 let parent = &self.parent_node;
1230
1231 let parent = match parent.get() {
1233 None => return Ok(()),
1234 Some(parent) => parent,
1235 };
1236
1237 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1239
1240 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1242
1243 let viable_previous_sibling = match viable_previous_sibling {
1245 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1246 None => parent.first_child.get(),
1247 };
1248
1249 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1251
1252 Ok(())
1253 }
1254
1255 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1257 let parent = &self.parent_node;
1259
1260 let parent = match parent.get() {
1262 None => return Ok(()),
1263 Some(parent) => parent,
1264 };
1265
1266 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1268
1269 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1271
1272 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1274
1275 Ok(())
1276 }
1277
1278 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1280 let Some(parent) = self.GetParentNode() else {
1282 return Ok(());
1284 };
1285
1286 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1288
1289 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1291
1292 if self.parent_node == Some(&*parent) {
1293 parent.ReplaceChild(cx, &node, self)?;
1295 } else {
1296 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1298 }
1299 Ok(())
1300 }
1301
1302 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1304 let doc = self.owner_doc();
1306 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1307 let first_child = self.first_child.get();
1309 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1310 }
1311
1312 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1314 let doc = self.owner_doc();
1316 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1317 self.AppendChild(cx, &node).map(|_| ())
1319 }
1320
1321 pub(crate) fn replace_children(
1323 &self,
1324 cx: &mut JSContext,
1325 nodes: Vec<NodeOrString>,
1326 ) -> ErrorResult {
1327 let doc = self.owner_doc();
1330 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1331
1332 Node::ensure_pre_insertion_validity(cx.no_gc(), &node, self, None)?;
1334
1335 Node::replace_all(cx, Some(&node), self);
1337 Ok(())
1338 }
1339
1340 pub(crate) fn move_before(
1342 &self,
1343 cx: &mut JSContext,
1344 node: &Node,
1345 child: Option<&Node>,
1346 ) -> ErrorResult {
1347 let reference_child_root;
1350 let reference_child = match child {
1351 Some(child) if child == node => {
1352 reference_child_root = node.GetNextSibling();
1353 reference_child_root.as_deref()
1354 },
1355 _ => child,
1356 };
1357
1358 Node::move_fn(cx, node, self, reference_child)
1360 }
1361
1362 fn move_fn(
1364 cx: &mut JSContext,
1365 node: &Node,
1366 new_parent: &Node,
1367 child: Option<&Node>,
1368 ) -> ErrorResult {
1369 let mut options = GetRootNodeOptions::empty();
1374 options.composed = true;
1375 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1376 return Err(Error::HierarchyRequest(Some(
1377 "The `newParent` node's shadow root is not the same as the `node`'s shadow root"
1378 .into(),
1379 )));
1380 }
1381
1382 if node.is_inclusive_ancestor_of(new_parent) {
1385 return Err(Error::HierarchyRequest(Some(
1386 "`node` node cannot be the inclusive ancestor of the `newParent` node".into(),
1387 )));
1388 }
1389
1390 if let Some(child) = child &&
1393 !new_parent.is_parent_of(child)
1394 {
1395 return Err(Error::NotFound(Some(
1396 "`child` node's parent node is not `newParent`".into(),
1397 )));
1398 }
1399
1400 match node.type_id() {
1405 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1406 if new_parent.is::<Document>() {
1407 return Err(Error::HierarchyRequest(Some(
1408 "`node` cannot be a text node when `newParent` is a document".into(),
1409 )));
1410 }
1411 },
1412 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1413 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1414 NodeTypeId::Element(_) => (),
1415 NodeTypeId::DocumentFragment(_) |
1416 NodeTypeId::DocumentType |
1417 NodeTypeId::Document(_) |
1418 NodeTypeId::Attr => {
1419 return Err(Error::HierarchyRequest(Some(
1420 "To move `node` into a `newParent`, it must be an Element".into(),
1421 )));
1422 },
1423 }
1424
1425 if new_parent.is::<Document>() && node.is::<Element>() {
1429 if new_parent.child_elements().next().is_some() {
1431 return Err(Error::HierarchyRequest(Some(
1432 "`newParent` document cannot have an element child".into(),
1433 )));
1434 }
1435
1436 if child.is_some_and(|child| {
1439 child
1440 .inclusively_following_siblings_unrooted(cx.no_gc())
1441 .any(|child| child.is_doctype())
1442 }) {
1443 return Err(Error::HierarchyRequest(Some(
1444 "`child` node has a document node following it".into(),
1445 )));
1446 }
1447 }
1448
1449 let old_parent = node
1452 .parent_node
1453 .get()
1454 .expect("old_parent should always be initialized");
1455
1456 let document = node.owner_doc_unrooted(cx.no_gc());
1458 let mut cached_index = None;
1459 let mut lazy_index = || *cached_index.get_or_insert_with(|| node.index());
1460 if let Some(selection) = document.selection() {
1461 selection.pre_remove_steps(node, &old_parent, &mut lazy_index);
1462 }
1463 document.live_range_pre_remove_steps(cx.no_gc(), node, &old_parent, &mut lazy_index);
1464
1465 let old_previous_sibling = node.prev_sibling.get();
1470
1471 let old_next_sibling = node.next_sibling.get();
1473
1474 let prev_sibling = node.GetPreviousSibling();
1475 match prev_sibling {
1476 None => {
1477 old_parent
1478 .first_child
1479 .set(node.next_sibling.get().as_deref());
1480 },
1481 Some(ref prev_sibling) => {
1482 prev_sibling
1483 .next_sibling
1484 .set(node.next_sibling.get().as_deref());
1485 },
1486 }
1487 let next_sibling = node.GetNextSibling();
1488 match next_sibling {
1489 None => {
1490 old_parent
1491 .last_child
1492 .set(node.prev_sibling.get().as_deref());
1493 },
1494 Some(ref next_sibling) => {
1495 next_sibling
1496 .prev_sibling
1497 .set(node.prev_sibling.get().as_deref());
1498 },
1499 }
1500
1501 old_parent.move_child(cx, node);
1503
1504 if let Some(slot) = node.assigned_slot() {
1506 slot.assign_slottables(cx);
1507 }
1508
1509 if old_parent.is_in_a_shadow_tree() &&
1512 let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() &&
1513 !slot_element.has_assigned_nodes()
1514 {
1515 slot_element.signal_a_slot_change(cx);
1516 }
1517
1518 let has_slot_descendant = node
1520 .traverse_preorder_unrooted(cx.no_gc(), ShadowIncluding::No)
1521 .any(|element| element.is::<HTMLSlotElement>());
1522 if has_slot_descendant {
1523 old_parent
1525 .GetRootNode(&GetRootNodeOptions::empty())
1526 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1527
1528 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1530 }
1531
1532 if let Some(child) = child {
1534 let document = new_parent.owner_doc_unrooted(cx.no_gc());
1536 if let Some(selection) = document.selection() {
1537 selection.insert_steps(new_parent, child, 1);
1538 }
1539 document.live_range_insert_steps(cx.no_gc(), new_parent, child, 1);
1540 }
1541
1542 let new_previous_sibling = child.map_or_else(
1545 || new_parent.last_child.get(),
1546 |child| child.prev_sibling.get(),
1547 );
1548
1549 new_parent.add_child(cx, node, child);
1552
1553 if let Some(shadow_root) = new_parent
1556 .downcast::<Element>()
1557 .and_then(Element::shadow_root) &&
1558 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1559 (node.is::<Element>() || node.is::<Text>())
1560 {
1561 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1562 slottable.assign_a_slot(cx);
1563 }
1564
1565 if new_parent.is_in_a_shadow_tree() &&
1568 let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() &&
1569 !slot_element.has_assigned_nodes()
1570 {
1571 slot_element.signal_a_slot_change(cx);
1572 }
1573
1574 node.GetRootNode(&GetRootNodeOptions::empty())
1576 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
1577
1578 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1581 if descendant.deref() == node {
1585 vtable_for(&descendant).moving_steps(cx, &MoveContext::new(Some(&old_parent)));
1586 } else {
1587 vtable_for(&descendant).moving_steps(cx, &MoveContext::new(None));
1588 }
1589
1590 if let Some(descendant) = descendant.downcast::<Element>() &&
1592 descendant.is_custom() &&
1593 new_parent.is_connected()
1594 {
1595 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
1598 custom_element_reaction_stack.enqueue_callback_reaction(
1599 cx,
1600 descendant,
1601 CallbackReaction::ConnectedMove,
1602 None,
1603 );
1604 }
1605 }
1606
1607 let moved = [node];
1610 let mutation = LazyCell::new(|| Mutation::ChildList {
1611 added: None,
1612 removed: Some(&moved),
1613 prev: old_previous_sibling.as_deref(),
1614 next: old_next_sibling.as_deref(),
1615 });
1616 MutationObserver::queue_a_mutation_record(cx, &old_parent, mutation);
1617
1618 let mutation = LazyCell::new(|| Mutation::ChildList {
1621 added: Some(&moved),
1622 removed: None,
1623 prev: new_previous_sibling.as_deref(),
1624 next: child,
1625 });
1626 MutationObserver::queue_a_mutation_record(cx, new_parent, mutation);
1627
1628 Ok(())
1629 }
1630
1631 #[allow(unsafe_code)]
1633 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1634 pub(crate) fn query_selector(
1635 &self,
1636 no_gc: &NoGC,
1637 selectors: DOMString,
1638 ) -> Fallible<Option<DomRoot<Element>>> {
1639 let document_url = self.owner_document().url().get_arc();
1642
1643 self.owner_document()
1646 .id_map()
1647 .resolve_all(no_gc, self.owner_doc().upcast());
1648
1649 let traced_node = Dom::from_ref(self);
1651
1652 let first_matching_element = with_layout_state(|| {
1653 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1654 ServoDangerousStyleNode::from(layout_node)
1655 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1656 })?;
1657
1658 Ok(first_matching_element.map(ServoDangerousStyleElement::rooted))
1659 }
1660
1661 #[allow(unsafe_code)]
1663 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1664 pub(crate) fn query_selector_all(
1665 &self,
1666 cx: &mut JSContext,
1667 selectors: DOMString,
1668 ) -> Fallible<DomRoot<NodeList>> {
1669 let document_url = self.owner_document().url().get_arc();
1672
1673 self.owner_document()
1676 .id_map()
1677 .resolve_all(cx.no_gc(), self.owner_doc().upcast());
1678
1679 let unrooted_node = UnrootedDom::from_ref(self, cx.no_gc());
1680 let matching_elements = with_layout_state(|| {
1681 let layout_node: LayoutDom<'_, _> = unsafe { unrooted_node.to_layout() };
1682 ServoDangerousStyleNode::from(layout_node)
1683 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1684 })?;
1685 let iter = matching_elements
1686 .into_iter()
1687 .map(ServoDangerousStyleElement::rooted)
1688 .map(DomRoot::upcast::<Node>);
1689
1690 Ok(NodeList::new_simple_list(cx, &self.owner_window(), iter))
1693 }
1694
1695 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1696 SimpleNodeIterator::new(self.GetParentNode(), |n| n.GetParentNode())
1697 }
1698
1699 pub(crate) fn ancestors_unrooted<'a>(&self, no_gc: &'a NoGC) -> UnrootedAncestorIterator<'a> {
1700 UnrootedSimpleNodeIterator::new(
1701 self.get_parent_node_unrooted(no_gc),
1702 |node, no_gc| node.get_parent_node_unrooted(no_gc),
1703 no_gc,
1704 )
1705 }
1706
1707 pub(crate) fn inclusive_ancestors(
1709 &self,
1710 shadow_including: ShadowIncluding,
1711 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1712 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |n| {
1713 if shadow_including == ShadowIncluding::Yes &&
1714 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1715 {
1716 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1717 }
1718 n.GetParentNode()
1719 })
1720 }
1721
1722 pub(crate) fn inclusive_ancestors_unrooted<'a>(
1723 &self,
1724 no_gc: &'a NoGC,
1725 shadow_including: ShadowIncluding,
1726 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1727 UnrootedSimpleNodeIterator::new(
1728 Some(UnrootedDom::from_ref(self, no_gc)),
1729 move |node, no_gc| {
1730 if shadow_including == ShadowIncluding::Yes &&
1731 let Some(shadow_root) = node.downcast::<ShadowRoot>()
1732 {
1733 return Some(UnrootedDom::upcast(shadow_root.host_unrooted(no_gc)));
1734 }
1735 node.get_parent_node_unrooted(no_gc)
1736 },
1737 no_gc,
1738 )
1739 }
1740
1741 pub(crate) fn ancestors_in_flat_tree_unrooted<'a>(
1742 &self,
1743 no_gc: &'a NoGC,
1744 ) -> UnrootedAncestorIterator<'a> {
1745 UnrootedSimpleNodeIterator::new(
1746 self.parent_in_flat_tree(no_gc).into_parent(),
1747 |node, no_gc| node.parent_in_flat_tree(no_gc).into_parent(),
1748 no_gc,
1749 )
1750 }
1751
1752 pub(crate) fn inclusive_ancestors_in_flat_tree_unrooted<'a>(
1753 &self,
1754 no_gc: &'a NoGC,
1755 ) -> UnrootedAncestorIterator<'a> {
1756 UnrootedSimpleNodeIterator::new(
1757 Some(UnrootedDom::from_ref(self, no_gc)),
1758 |node, no_gc| node.parent_in_flat_tree(no_gc).into_parent(),
1759 no_gc,
1760 )
1761 }
1762
1763 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1764 self.owner_doc.get().unwrap()
1765 }
1766
1767 pub(crate) fn owner_doc_unrooted<'a>(&self, no_gc: &'a NoGC) -> UnrootedDom<'a, Document> {
1768 self.owner_doc.get_unrooted(no_gc).unwrap()
1769 }
1770
1771 pub(crate) fn set_owner_doc(&self, document: &Document) {
1772 self.owner_doc.set(Some(document));
1773 }
1774
1775 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1776 self.rare_data
1777 .borrow()
1778 .as_ref()?
1779 .containing_shadow_root
1780 .as_ref()
1781 .map(|shadow_root| DomRoot::from_ref(&**shadow_root))
1782 }
1783
1784 pub(crate) fn containing_shadow_root_unrooted<'a>(
1785 &self,
1786 no_gc: &'a NoGC,
1787 ) -> Option<UnrootedDom<'a, ShadowRoot>> {
1788 self.rare_data
1789 .borrow()
1790 .as_ref()?
1791 .containing_shadow_root
1792 .as_ref()
1793 .map(|shadow_root| shadow_root.as_unrooted(no_gc))
1794 }
1795
1796 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1797 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1798 }
1799
1800 pub(crate) fn is_in_html_doc(&self) -> bool {
1801 self.owner_doc().is_html_document()
1802 }
1803
1804 pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1805 self.is_connected() && self.owner_doc().browsing_context().is_some()
1806 }
1807
1808 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1809 SimpleNodeIterator::new(self.GetFirstChild(), |n| n.GetNextSibling())
1810 }
1811
1812 pub(crate) fn children_unrooted<'a>(
1813 &self,
1814 no_gc: &'a NoGC,
1815 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1816 UnrootedSimpleNodeIterator::new(
1817 self.get_first_child_unrooted(no_gc),
1818 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1819 no_gc,
1820 )
1821 }
1822
1823 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1824 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetPreviousSibling())
1825 }
1826
1827 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1829 self.children()
1830 .filter_map(DomRoot::downcast as fn(_) -> _)
1831 .peekable()
1832 }
1833
1834 pub(crate) fn child_elements_unrooted<'a>(
1835 &self,
1836 no_gc: &'a NoGC,
1837 ) -> impl Iterator<Item = UnrootedDom<'a, Element>> + use<'a> {
1838 self.children_unrooted(no_gc)
1839 .filter_map(UnrootedDom::downcast)
1840 .peekable()
1841 }
1842
1843 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1844 if let Some(ref parent) = self.GetParentNode() {
1845 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1846 }
1847 }
1848
1849 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1851 Ref::filter_map(self.rare_data.borrow(), |rare_data| {
1852 rare_data
1853 .as_ref()
1854 .and_then(|rare_data| rare_data.unique_id.as_ref())
1855 })
1856 .ok()
1857 .map(|unique_id| unique_id.simple().to_string())
1858 }
1859
1860 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1861 let mut rare_data = self.ensure_rare_data();
1862
1863 if rare_data.unique_id.is_none() {
1864 let node_id = Uuid::new_v4();
1865 ScriptThread::save_node_id(pipeline, node_id.simple().to_string());
1866 rare_data.unique_id = Some(node_id);
1867 }
1868 rare_data.unique_id.as_ref().unwrap().simple().to_string()
1869 }
1870
1871 #[cfg(feature = "devtools")]
1872 pub(crate) fn summarize(&self, cx: &mut JSContext) -> devtools_traits::NodeInfo {
1873 use crate::conversions::Convert;
1874 use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
1875 let USVString(base_uri) = self.BaseURI();
1876 let node_type = self.NodeType();
1877 let pipeline = self.owner_window().pipeline_id();
1878
1879 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1880 let shadow_root_mode = maybe_shadow_root
1881 .map(ShadowRoot::Mode)
1882 .map(ShadowRootMode::convert);
1883 let host = maybe_shadow_root
1884 .map(ShadowRoot::Host)
1885 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1886 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1887 let Some(root) = potential_host.shadow_root() else {
1888 return false;
1889 };
1890 !root.is_user_agent_widget() ||
1891 servo_config::pref!(inspector_show_servo_internal_shadow_roots)
1892 });
1893
1894 let num_children = if is_shadow_host {
1895 self.ChildNodes(cx).Length(cx.no_gc()) as usize + 1
1897 } else {
1898 self.ChildNodes(cx).Length(cx.no_gc()) as usize
1899 };
1900
1901 let window = self.owner_window();
1902 let element = self.downcast::<Element>();
1903 let display = element
1904 .map(|elem| window.GetComputedStyle(cx, elem, None))
1905 .map(|style| style.Display().into());
1906
1907 let is_displayed =
1913 element.is_none_or(|element| !element.is_display_none()) || self.is::<DocumentType>();
1914 let attrs = element.map(Element::summarize).unwrap_or_default();
1915
1916 devtools_traits::NodeInfo {
1917 unique_id: self.unique_id(pipeline),
1918 host,
1919 base_uri,
1920 parent: self
1921 .GetParentNode()
1922 .map_or(String::new(), |node| node.unique_id(pipeline)),
1923 node_type,
1924 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1925 node_name: String::from(self.NodeName()),
1926 node_value: self.GetNodeValue().map(|v| v.into()),
1927 num_children,
1928 attrs,
1929 is_shadow_host,
1930 shadow_root_mode,
1931 display,
1932 is_displayed,
1933 doctype_name: self
1934 .downcast::<DocumentType>()
1935 .map(DocumentType::name)
1936 .cloned()
1937 .map(String::from),
1938 doctype_public_identifier: self
1939 .downcast::<DocumentType>()
1940 .map(DocumentType::public_id)
1941 .cloned()
1942 .map(String::from),
1943 doctype_system_identifier: self
1944 .downcast::<DocumentType>()
1945 .map(DocumentType::system_id)
1946 .cloned()
1947 .map(String::from),
1948 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1949 }
1950 }
1951
1952 pub(crate) fn insert_cell_or_row<F, G, I>(
1954 &self,
1955 cx: &mut JSContext,
1956 index: i32,
1957 get_items: F,
1958 new_child: G,
1959 ) -> Fallible<DomRoot<HTMLElement>>
1960 where
1961 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1962 G: Fn(&mut JSContext) -> DomRoot<I>,
1963 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1964 {
1965 if index < -1 {
1966 return Err(Error::IndexSize(Some("Index is out of bounds".into())));
1967 }
1968
1969 let tr = new_child(cx);
1970
1971 {
1972 let tr_node = tr.upcast::<Node>();
1973 if index == -1 {
1974 self.InsertBefore(cx, tr_node, None)?;
1975 } else {
1976 let items = get_items(cx);
1977 let node = match items
1978 .elements_iter(cx.no_gc())
1979 .map(UnrootedDom::upcast::<Node>)
1980 .map(Some)
1981 .chain(iter::once(None))
1982 .nth(index as usize)
1983 {
1984 None => return Err(Error::IndexSize(Some("Index is out of bounds".into()))),
1985 Some(node) => node,
1986 };
1987 self.InsertBefore(cx, tr_node, node.map(|node| node.as_rooted()).as_deref())?;
1988 }
1989 }
1990
1991 Ok(DomRoot::upcast::<HTMLElement>(tr))
1992 }
1993
1994 pub(crate) fn delete_cell_or_row<F, G>(
1996 &self,
1997 cx: &mut JSContext,
1998 index: i32,
1999 get_items: F,
2000 is_delete_type: G,
2001 ) -> ErrorResult
2002 where
2003 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
2004 G: Fn(&Element) -> bool,
2005 {
2006 let element = match index {
2007 index if index < -1 => {
2008 return Err(Error::IndexSize(Some("Index is out of bounds".into())));
2009 },
2010 -1 => {
2011 let last_child = self.upcast::<Node>().GetLastChild();
2012 match last_child.and_then(|node| {
2013 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
2014 .filter_map(UnrootedDom::downcast::<Element>)
2015 .find(|elem| is_delete_type(elem))
2016 .map(|elem| elem.as_rooted())
2017 }) {
2018 Some(element) => element,
2019 None => return Ok(()),
2020 }
2021 },
2022 index => match get_items(cx).Item(cx, index as u32) {
2023 Some(element) => element,
2024 None => return Err(Error::IndexSize(Some("Index is out of bounds".into()))),
2025 },
2026 };
2027
2028 element.upcast::<Node>().remove_self(cx);
2029 Ok(())
2030 }
2031
2032 pub(crate) fn get_cssom_stylesheet(
2033 &self,
2034 cx: &mut JSContext,
2035 ) -> Option<DomRoot<CSSStyleSheet>> {
2036 if let Some(node) = self.downcast::<HTMLStyleElement>() {
2037 node.get_cssom_stylesheet(cx)
2038 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
2039 node.get_cssom_stylesheet(cx)
2040 } else {
2041 None
2042 }
2043 }
2044
2045 pub(crate) fn get_lang(&self) -> Option<String> {
2047 self.inclusive_ancestors(ShadowIncluding::Yes)
2055 .find_map(|node| {
2056 node.downcast::<Element>().and_then(|element| {
2057 element
2060 .get_attribute_string_value_with_namespace(&ns!(xml), &local_name!("lang"))
2061 .or_else(|| {
2065 if element.namespace() == &ns!() || element.namespace() == &ns!(svg) {
2066 element.get_attribute_string_value(&local_name!("lang"))
2067 } else {
2068 None
2069 }
2070 })
2071 })
2072 })
2073 .or_else(|| self.owner_document().default_language())
2088 }
2089
2090 pub(crate) fn assign_slottables_for_a_tree(
2092 &self,
2093 cx: &JSContext,
2094 force: ForceSlottableNodeReconciliation,
2095 ) {
2096 let is_shadow_root_with_slots = self
2103 .downcast::<ShadowRoot>()
2104 .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
2105 if !is_shadow_root_with_slots &&
2106 !self.is::<HTMLSlotElement>() &&
2107 matches!(force, ForceSlottableNodeReconciliation::Skip)
2108 {
2109 return;
2110 }
2111
2112 for node in self.traverse_preorder_unrooted(cx, ShadowIncluding::No) {
2115 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
2116 slot.assign_slottables(cx);
2117 }
2118 }
2119 }
2120
2121 pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
2122 let assigned_slot = self
2123 .rare_data
2124 .borrow()
2125 .as_ref()?
2126 .slottable_data
2127 .assigned_slot
2128 .as_ref()?
2129 .as_rooted();
2130 Some(assigned_slot)
2131 }
2132
2133 pub(crate) fn assigned_slot_unrooted<'a>(
2134 &self,
2135 no_gc: &'a NoGC,
2136 ) -> Option<UnrootedDom<'a, HTMLSlotElement>> {
2137 let rare_data = self.rare_data.borrow();
2138 let assigned_slot = rare_data.as_ref()?.slottable_data.assigned_slot.as_ref()?;
2139 Some(UnrootedDom::from_ref(assigned_slot, no_gc))
2140 }
2141
2142 pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
2143 self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
2144 }
2145
2146 pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
2147 let manually_assigned_slot = self
2148 .rare_data
2149 .borrow()
2150 .as_ref()?
2151 .slottable_data
2152 .manual_slot_assignment
2153 .as_ref()?
2154 .as_rooted();
2155 Some(manually_assigned_slot)
2156 }
2157
2158 pub(crate) fn set_manual_slot_assignment(
2159 &self,
2160 manually_assigned_slot: Option<&HTMLSlotElement>,
2161 ) {
2162 self.ensure_rare_data()
2163 .slottable_data
2164 .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
2165 }
2166
2167 pub(crate) fn parent_in_flat_tree<'b>(&self, no_gc: &'b NoGC) -> FlatTreeParent<'b> {
2178 if let Some(assigned_slot) = self.assigned_slot_unrooted(no_gc) {
2179 return FlatTreeParent::Parent(UnrootedDom::upcast::<Node>(assigned_slot));
2180 }
2181
2182 let Some(parent) = self.get_parent_node_unrooted(no_gc) else {
2183 return FlatTreeParent::RootNode;
2184 };
2185
2186 if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
2187 return FlatTreeParent::Parent(UnrootedDom::upcast(shadow_root.host_unrooted(no_gc)));
2188 }
2189
2190 if parent
2191 .downcast::<Element>()
2192 .is_some_and(|element| element.is_shadow_host())
2193 {
2194 return FlatTreeParent::NotInFlatTree;
2195 }
2196
2197 if parent
2198 .downcast::<HTMLSlotElement>()
2199 .is_some_and(|slot| slot.has_assigned_nodes())
2200 {
2201 return FlatTreeParent::NotInFlatTree;
2202 }
2203
2204 FlatTreeParent::Parent(parent)
2205 }
2206
2207 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2209 debug_assert!(self.is_in_ua_widget());
2211 debug_assert!(pseudo_element.is_element_backed());
2212 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2213 }
2214
2215 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2216 self.rare_data
2217 .borrow()
2218 .as_ref()
2219 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2220 }
2221
2222 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2224 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2228 if ancestor.is_editing_host() {
2229 return Some(ancestor);
2230 }
2231 if ancestor
2232 .downcast::<HTMLElement>()
2233 .is_some_and(|el| el.ContentEditable().str() == "false")
2234 {
2235 return None;
2236 }
2237 }
2238 None
2239 }
2240
2241 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2242 self.editing_host_of().is_some()
2243 }
2244
2245 pub(crate) fn is_editing_host(&self) -> bool {
2247 self.downcast::<HTMLElement>()
2248 .is_some_and(HTMLElement::is_editing_host)
2249 }
2250
2251 pub(crate) fn is_editable(&self) -> bool {
2253 if self.is_editing_host() {
2255 return false;
2256 }
2257 let html_element = self.downcast::<HTMLElement>();
2259 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2260 return false;
2261 }
2262 let Some(parent) = self.GetParentNode() else {
2264 return false;
2265 };
2266 if !parent.is_editable_or_editing_host() {
2267 return false;
2268 }
2269 html_element.is_some() || (!self.is::<Element>() && parent.is::<HTMLElement>())
2271 }
2272}
2273
2274fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2276where
2277 I: Iterator<Item = DomRoot<Node>>,
2278{
2279 nodes.find(|node| {
2280 not_in.iter().all(|n| match *n {
2281 NodeOrString::Node(ref n) => n != node,
2282 _ => true,
2283 })
2284 })
2285}
2286
2287#[expect(unsafe_code)]
2290pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2291 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2292 DomRoot::from_ref(node)
2293}
2294
2295#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2297pub(crate) enum CloneChildrenFlag {
2298 CloneChildren,
2299 DoNotCloneChildren,
2300}
2301
2302impl From<bool> for CloneChildrenFlag {
2303 fn from(boolean: bool) -> Self {
2304 if boolean {
2305 CloneChildrenFlag::CloneChildren
2306 } else {
2307 CloneChildrenFlag::DoNotCloneChildren
2308 }
2309 }
2310}
2311
2312pub(super) fn as_uintptr<T>(t: &T) -> uintptr_t {
2313 t as *const T as uintptr_t
2314}
2315
2316impl Node {
2317 pub(crate) fn reflect_node<N>(
2318 cx: &mut JSContext,
2319 node: Box<N>,
2320 document: &Document,
2321 ) -> DomRoot<N>
2322 where
2323 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2324 {
2325 Self::reflect_node_with_proto(cx, node, document, None)
2326 }
2327
2328 pub(crate) fn reflect_node_with_proto<N>(
2329 cx: &mut JSContext,
2330 node: Box<N>,
2331 document: &Document,
2332 proto: Option<HandleObject>,
2333 ) -> DomRoot<N>
2334 where
2335 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2336 {
2337 let window = document.window();
2338 reflect_dom_object_with_proto(cx, node, window, proto)
2339 }
2340
2341 pub(crate) fn reflect_weak_referenceable_node_with_proto<N>(
2342 cx: &mut JSContext,
2343 node: Rc<N>,
2344 document: &Document,
2345 proto: Option<HandleObject>,
2346 ) -> DomRoot<N>
2347 where
2348 N: DerivedFrom<Node> + DomObject + WeakReferenceableDomObjectWrap<crate::DomTypeHolder>,
2349 {
2350 let window = document.window();
2351 reflect_weak_referenceable_dom_object_with_proto(cx, node, window, proto)
2352 }
2353
2354 pub(crate) fn new_inherited(doc: &Document) -> Node {
2355 Node::new_(NodeFlags::empty(), Some(doc))
2356 }
2357
2358 pub(crate) fn new_document_node() -> Node {
2359 Node::new_(
2360 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2361 None,
2362 )
2363 }
2364
2365 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2366 Node {
2367 eventtarget: EventTarget::new_inherited(),
2368 parent_node: Default::default(),
2369 first_child: Default::default(),
2370 last_child: Default::default(),
2371 next_sibling: Default::default(),
2372 prev_sibling: Default::default(),
2373 owner_doc: MutNullableDom::new(doc),
2374 rare_data: Default::default(),
2375 children_count: Cell::new(0u32),
2376 flags: Cell::new(flags),
2377 inclusive_descendants_version: Cell::new(0),
2378 layout_data: Default::default(),
2379 }
2380 }
2381
2382 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2384 document.add_script_and_layout_blocker();
2385
2386 let old_doc = node.owner_doc();
2388 old_doc.add_script_and_layout_blocker();
2389
2390 node.remove_self(cx);
2392
2393 if &*old_doc != document {
2397 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2398 descendant.set_owner_doc(document);
2400
2401 if let Some(shadow_root) = descendant.downcast::<ShadowRoot>() {
2412 if shadow_root
2413 .custom_element_registry()
2414 .is_none_or(|registry| {
2415 CustomElementRegistry::is_a_global_element_registry(Some(&*registry))
2416 })
2417 {
2418 shadow_root.set_custom_element_registry(
2419 document
2420 .effective_global_custom_element_registry()
2421 .as_deref(),
2422 );
2423 }
2424 }
2425 else if let Some(element) = descendant.downcast::<Element>() {
2427 for attribute in element.attrs().borrow().iter() {
2430 if let Some(attr) = attribute.as_attr() {
2431 attr.upcast::<Node>().set_owner_doc(document);
2432 }
2433 }
2434
2435 if element
2441 .custom_element_registry()
2442 .is_none_or(|registry| !registry.is_scoped())
2443 {
2444 element.set_custom_element_registry(
2445 document
2446 .effective_global_custom_element_registry()
2447 .as_deref(),
2448 cx.no_gc(),
2449 );
2450 }
2451
2452 if element.is_custom() {
2456 ScriptThread::custom_element_reaction_stack().enqueue_callback_reaction(
2457 cx,
2458 element,
2459 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2460 None,
2461 );
2462 }
2463 }
2464
2465 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2467 }
2468
2469 for range in old_doc.live_ranges().as_vec() {
2473 range.maybe_update_document();
2474 }
2475 }
2476
2477 old_doc.remove_script_and_layout_blocker(cx);
2478 document.remove_script_and_layout_blocker(cx);
2479 }
2480
2481 pub(crate) fn ensure_pre_insertion_validity(
2483 no_gc: &NoGC,
2484 node: &Node,
2485 parent: &Node,
2486 child: Option<&Node>,
2487 ) -> ErrorResult {
2488 match parent.type_id() {
2490 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2491 },
2492 _ => {
2493 return Err(Error::HierarchyRequest(Some(
2494 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2495 )));
2496 },
2497 }
2498
2499 if node.is_host_including_inclusive_ancestor(parent) {
2501 return Err(Error::HierarchyRequest(Some(
2502 "Node is a host-including inclusive ancestor of parent".to_owned(),
2503 )));
2504 }
2505
2506 if let Some(child) = child &&
2508 !parent.is_parent_of(child)
2509 {
2510 return Err(Error::NotFound(Some(
2511 "Child is non-null and its parent is not parent".to_owned(),
2512 )));
2513 }
2514
2515 match node.type_id() {
2516 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2520 if parent.is::<Document>() {
2521 return Err(Error::HierarchyRequest(Some(
2522 "Node is a Text node and parent is a document".to_owned(),
2523 )));
2524 }
2525 },
2526 NodeTypeId::DocumentType => {
2527 if !parent.is::<Document>() {
2528 return Err(Error::HierarchyRequest(Some(
2529 "Node is a doctype and parent is not a document".to_owned(),
2530 )));
2531 }
2532 },
2533 NodeTypeId::DocumentFragment(_) |
2534 NodeTypeId::Element(_) |
2535 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2536 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2537 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2540 return Err(Error::HierarchyRequest(Some(
2541 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2542 .to_owned(),
2543 )));
2544 },
2545 }
2546
2547 if parent.is::<Document>() {
2550 match node.type_id() {
2551 NodeTypeId::DocumentFragment(_) => {
2552 if node.children_unrooted(no_gc).any(|c| c.is::<Text>()) {
2554 return Err(Error::HierarchyRequest(Some(
2555 "Parent is a document and node has a Text node child".into(),
2556 )));
2557 }
2558 match node.child_elements_unrooted(no_gc).count() {
2559 0 => (),
2560 1 => {
2563 if parent.child_elements_unrooted(no_gc).next().is_some() {
2564 return Err(Error::HierarchyRequest(Some(
2565 "Node has one element child and parent has an element child"
2566 .into(),
2567 )));
2568 }
2569 if let Some(child) = child &&
2570 child
2571 .inclusively_following_siblings_unrooted(no_gc)
2572 .any(|child| child.is_doctype())
2573 {
2574 return Err(Error::HierarchyRequest(Some(
2575 "Node has one element child and child is a doctype".into(),
2576 )));
2577 }
2578 },
2579 _ => {
2580 return Err(Error::HierarchyRequest(Some(
2581 "Node cannot have more than one child element".into(),
2582 )));
2583 },
2584 }
2585 },
2586 NodeTypeId::Element(_) => {
2587 if parent.child_elements_unrooted(no_gc).next().is_some() {
2589 return Err(Error::HierarchyRequest(Some(
2590 "Parent has an element child".to_owned(),
2591 )));
2592 }
2593 if let Some(child) = child &&
2594 child
2595 .inclusively_following_siblings_unrooted(no_gc)
2596 .any(|following| following.is_doctype())
2597 {
2598 return Err(Error::HierarchyRequest(Some(
2599 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
2600 )));
2601 }
2602 },
2603 NodeTypeId::DocumentType => {
2604 if parent.children_unrooted(no_gc).any(|c| c.is_doctype()) {
2607 return Err(Error::HierarchyRequest(Some(
2608 "Parent cannot have a doctype child".into(),
2609 )));
2610 }
2611 match child {
2612 Some(child) => {
2613 if parent
2614 .children_unrooted(no_gc)
2615 .take_while(|c| **c != child)
2616 .any(|c| c.is::<Element>())
2617 {
2618 return Err(Error::HierarchyRequest(Some(
2619 "Child is non-null and an element is preceding child".into(),
2620 )));
2621 }
2622 },
2623 None => {
2624 if parent.child_elements_unrooted(no_gc).next().is_some() {
2625 return Err(Error::HierarchyRequest(Some(
2626 "Child is null and parent has an element child".into(),
2627 )));
2628 }
2629 },
2630 }
2631 },
2632 NodeTypeId::CharacterData(_) => (),
2633 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
2636 }
2637 }
2638 Ok(())
2639 }
2640
2641 pub(crate) fn pre_insert(
2643 cx: &mut JSContext,
2644 node: &Node,
2645 parent: &Node,
2646 child: Option<&Node>,
2647 ) -> Fallible<DomRoot<Node>> {
2648 Node::ensure_pre_insertion_validity(cx.no_gc(), node, parent, child)?;
2650
2651 let reference_child_root;
2653 let reference_child = match child {
2654 Some(child) if child == node => {
2656 reference_child_root = node.GetNextSibling();
2657 reference_child_root.as_deref()
2658 },
2659 _ => child,
2660 };
2661
2662 Node::insert(
2664 cx,
2665 node,
2666 parent,
2667 reference_child,
2668 SuppressObserver::Unsuppressed,
2669 );
2670
2671 Ok(DomRoot::from_ref(node))
2673 }
2674
2675 pub(crate) fn insert(
2677 cx: &mut JSContext,
2678 node: &Node,
2679 parent: &Node,
2680 child: Option<&Node>,
2681 suppress_observers: SuppressObserver,
2682 ) {
2683 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
2684
2685 rooted_vec!(let mut new_nodes);
2687 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2688 new_nodes.extend(
2689 node.children_unrooted(cx.no_gc())
2690 .map(|node| Dom::from_ref(&**node)),
2691 );
2692 new_nodes.r()
2693 } else {
2694 from_ref(&node)
2695 };
2696
2697 let count = new_nodes.len();
2699
2700 if count == 0 {
2702 return;
2703 }
2704
2705 let parent_document = parent.owner_doc();
2708 let from_document = node.owner_doc();
2709 from_document.add_script_and_layout_blocker();
2710 parent_document.add_script_and_layout_blocker();
2711
2712 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2714 for kid in new_nodes {
2716 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
2717 }
2718 vtable_for(node).children_changed(cx, &ChildrenMutation::ReplaceAll);
2719
2720 let mutation = LazyCell::new(|| Mutation::ChildList {
2722 added: None,
2723 removed: Some(new_nodes),
2724 prev: None,
2725 next: None,
2726 });
2727 MutationObserver::queue_a_mutation_record(cx, node, mutation);
2728 }
2729
2730 if let Some(child) = child {
2732 let count = count.try_into().unwrap();
2734 let document = parent.owner_doc_unrooted(cx.no_gc());
2735 if let Some(selection) = document.selection() {
2736 selection.insert_steps(parent, child, count);
2737 }
2738 document.live_range_insert_steps(cx.no_gc(), parent, child, count);
2739 }
2740
2741 let previous_sibling = match suppress_observers {
2743 SuppressObserver::Unsuppressed => match child {
2744 Some(child) => child.GetPreviousSibling(),
2745 None => parent.GetLastChild(),
2746 },
2747 SuppressObserver::Suppressed => None,
2748 };
2749
2750 let mut static_node_list: SmallVec<[_; 4]> = Default::default();
2752
2753 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
2754 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
2755 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
2756
2757 for kid in new_nodes {
2759 Node::adopt(cx, kid, &parent.owner_document());
2761
2762 parent.add_child(cx, kid, child);
2765
2766 if let Some(ref shadow_root) = parent_shadow_root &&
2769 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
2770 (kid.is::<Element>() || kid.is::<Text>())
2771 {
2772 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(kid)));
2773 slottable.assign_a_slot(cx);
2774 }
2775
2776 if parent_in_shadow_tree &&
2779 let Some(slot_element) = parent_as_slot &&
2780 !slot_element.has_assigned_nodes()
2781 {
2782 slot_element.signal_a_slot_change(cx);
2783 }
2784
2785 kid.GetRootNode(&GetRootNodeOptions::empty())
2787 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
2788
2789 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
2792 if let Some(element) = DomRoot::downcast::<Element>(descendant.clone()) &&
2798 !element.is_custom()
2799 {
2800 try_upgrade_element(cx, &element);
2801 }
2802
2803 if !descendant.is_connected() {
2805 continue;
2806 }
2807
2808 if let Some(element) = DomRoot::downcast::<Element>(descendant.clone()) {
2810 if let Some(registry) = element.custom_element_registry() {
2812 if registry.is_scoped() {
2817 registry.add_scoped_document(&element.owner_document());
2818 }
2819 }
2820 if element.is_custom() {
2828 ScriptThread::custom_element_reaction_stack().enqueue_callback_reaction(
2829 cx,
2830 &element,
2831 CallbackReaction::Connected,
2832 None,
2833 );
2834 }
2835 else {
2837 try_upgrade_element(cx, &element);
2838 }
2839 }
2840 else if let Some(shadow_root) =
2847 DomRoot::downcast::<ShadowRoot>(descendant.clone()) &&
2848 let Some(custom_element_registry) = shadow_root.custom_element_registry() &&
2849 custom_element_registry.is_scoped()
2850 {
2851 custom_element_registry.add_scoped_document(shadow_root.owner_doc());
2852 }
2853
2854 static_node_list.push(descendant.clone());
2857 }
2858 }
2859
2860 Self::maybe_dirty_visible_selection_for_newly_inserted_nodes(cx.no_gc(), parent, new_nodes);
2861
2862 if let SuppressObserver::Unsuppressed = suppress_observers {
2863 vtable_for(parent).children_changed(
2866 cx,
2867 &ChildrenMutation::insert(previous_sibling.as_deref(), child),
2868 );
2869
2870 let mutation = LazyCell::new(|| Mutation::ChildList {
2873 added: Some(new_nodes),
2874 removed: None,
2875 prev: previous_sibling.as_deref(),
2876 next: child,
2877 });
2878 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2879 }
2880
2881 if !static_node_list.is_empty() {
2892 parent_document.add_delayed_task(
2893 task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
2894 for node in static_node_list {
2899 vtable_for(&node).post_connection_steps(cx);
2900 }
2901 }),
2902 );
2903 }
2904
2905 parent_document.remove_script_and_layout_blocker(cx);
2906 from_document.remove_script_and_layout_blocker(cx);
2907 }
2908
2909 pub(crate) fn maybe_dirty_visible_selection_for_newly_inserted_nodes(
2912 no_gc: &NoGC,
2913 parent: &Node,
2914 inserted_nodes: &[&Node],
2915 ) {
2916 let Some(selection) = parent.owner_document().selection() else {
2917 return;
2918 };
2919
2920 for node in inserted_nodes {
2921 match node.parent_in_flat_tree(no_gc) {
2922 FlatTreeParent::RootNode | FlatTreeParent::NotInFlatTree => {},
2923 FlatTreeParent::Parent(parent) => {
2924 if parent.get_flag(NodeFlags::OVERLAPS_DOCUMENT_SELECTION) {
2925 selection.set_visible_selection_dirty();
2926 return;
2927 }
2928 },
2929 }
2930 }
2931 }
2932
2933 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
2935 parent.owner_doc().add_script_and_layout_blocker();
2936
2937 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
2939
2940 rooted_vec!(let mut added_nodes);
2944 let added_nodes = if let Some(node) = node.as_ref() {
2945 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2946 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
2947 added_nodes.r()
2948 } else {
2949 from_ref(node)
2950 }
2951 } else {
2952 &[] as &[&Node]
2953 };
2954
2955 for child in &*removed_nodes {
2957 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
2958 }
2959
2960 if let Some(node) = node {
2962 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
2963 }
2964
2965 vtable_for(parent).children_changed(cx, &ChildrenMutation::ReplaceAll);
2966
2967 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
2970 let mutation = LazyCell::new(|| Mutation::ChildList {
2971 added: Some(added_nodes),
2972 removed: Some(removed_nodes.r()),
2973 prev: None,
2974 next: None,
2975 });
2976 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
2977 }
2978 parent.owner_doc().remove_script_and_layout_blocker(cx);
2979 }
2980
2981 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
2983 if string.is_empty() {
2984 Node::replace_all(cx, None, parent);
2985 } else {
2986 let text = Text::new(cx, string, &parent.owner_document());
2987 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
2988 };
2989 }
2990
2991 pub(super) fn pre_remove(
2993 cx: &mut JSContext,
2994 child: &Node,
2995 parent: &Node,
2996 ) -> Fallible<DomRoot<Node>> {
2997 match child.GetParentNode() {
2999 Some(ref node) if &**node != parent => {
3000 return Err(Error::NotFound(Some(
3001 "Child's parent does not match the parent node provided".into(),
3002 )));
3003 },
3004 None => {
3005 return Err(Error::NotFound(Some(
3006 "Child does not have a parent node".into(),
3007 )));
3008 },
3009 _ => (),
3010 }
3011
3012 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
3014
3015 Ok(DomRoot::from_ref(child))
3017 }
3018
3019 pub(super) fn remove(
3021 cx: &mut JSContext,
3022 node: &Node,
3023 parent: &Node,
3024 suppress_observers: SuppressObserver,
3025 ) {
3026 parent.owner_doc().add_script_and_layout_blocker();
3027
3028 assert!(
3032 node.GetParentNode()
3033 .is_some_and(|node_parent| &*node_parent == parent)
3034 );
3035
3036 let mut cached_index = None;
3038 {
3039 let mut lazy_index = || *cached_index.get_or_insert_with(|| node.index());
3040 let document = parent.owner_doc_unrooted(cx.no_gc());
3041 if let Some(selection) = document.selection() {
3042 selection.pre_remove_steps(node, parent, &mut lazy_index);
3043 }
3044 document.live_range_pre_remove_steps(cx.no_gc(), node, parent, &mut lazy_index);
3045 }
3046
3047 let old_previous_sibling = node.GetPreviousSibling();
3051
3052 let old_next_sibling = node.GetNextSibling();
3054
3055 parent.remove_child(cx, node);
3058
3059 if let Some(slot) = node.assigned_slot() {
3061 slot.assign_slottables(cx);
3062 }
3063
3064 if parent.is_in_a_shadow_tree() &&
3067 let Some(slot_element) = parent.downcast::<HTMLSlotElement>() &&
3068 !slot_element.has_assigned_nodes()
3069 {
3070 slot_element.signal_a_slot_change(cx);
3071 }
3072
3073 let has_slot_descendant = node
3075 .traverse_preorder_unrooted(cx.no_gc(), ShadowIncluding::No)
3076 .any(|elem| elem.is::<HTMLSlotElement>());
3077 if has_slot_descendant {
3078 parent
3080 .GetRootNode(&GetRootNodeOptions::empty())
3081 .assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Skip);
3082
3083 node.assign_slottables_for_a_tree(cx, ForceSlottableNodeReconciliation::Force);
3085 }
3086
3087 if let SuppressObserver::Unsuppressed = suppress_observers {
3091 vtable_for(parent).children_changed(
3092 cx,
3093 &ChildrenMutation::replace(
3094 old_previous_sibling.as_deref(),
3095 &Some(node),
3096 old_next_sibling.as_deref(),
3097 ),
3098 );
3099
3100 let removed = [node];
3101 let mutation = LazyCell::new(|| Mutation::ChildList {
3102 added: None,
3103 removed: Some(&removed),
3104 prev: old_previous_sibling.as_deref(),
3105 next: old_next_sibling.as_deref(),
3106 });
3107 MutationObserver::queue_a_mutation_record(cx, parent, mutation);
3108 }
3109 parent.owner_doc().remove_script_and_layout_blocker(cx);
3110 }
3111
3112 pub(crate) fn clone(
3114 cx: &mut JSContext,
3115 node: &Node,
3116 maybe_doc: Option<&Document>,
3117 clone_children: CloneChildrenFlag,
3118 registry: Option<DomRoot<CustomElementRegistry>>,
3119 ) -> DomRoot<Node> {
3120 let document = match maybe_doc {
3122 Some(doc) => DomRoot::from_ref(doc),
3123 None => node.owner_doc(),
3124 };
3125
3126 let copy: DomRoot<Node> = match node.type_id() {
3129 NodeTypeId::DocumentType => {
3130 let doctype = node.downcast::<DocumentType>().unwrap();
3131 let doctype = DocumentType::new(
3132 cx,
3133 doctype.name().clone(),
3134 Some(doctype.public_id().clone()),
3135 Some(doctype.system_id().clone()),
3136 &document,
3137 );
3138 DomRoot::upcast::<Node>(doctype)
3139 },
3140 NodeTypeId::Attr => {
3141 let attr = node.downcast::<Attr>().unwrap();
3142 let attr = Attr::new(
3143 cx,
3144 &document,
3145 attr.local_name().clone(),
3146 attr.value().clone(),
3147 attr.name().clone(),
3148 attr.namespace().clone(),
3149 attr.prefix().cloned(),
3150 None,
3151 );
3152 DomRoot::upcast::<Node>(attr)
3153 },
3154 NodeTypeId::DocumentFragment(_) => {
3155 let doc_fragment = DocumentFragment::new(cx, &document);
3156 DomRoot::upcast::<Node>(doc_fragment)
3157 },
3158 NodeTypeId::CharacterData(_) => {
3159 let cdata = node.downcast::<CharacterData>().unwrap();
3160 cdata.clone_with_data(cx, cdata.Data(), &document)
3161 },
3162 NodeTypeId::Document(_) => {
3163 let document = node.downcast::<Document>().unwrap();
3166 let is_html_doc = if document.is_html_document() {
3167 IsHTMLDocument::HTMLDocument
3168 } else {
3169 IsHTMLDocument::NonHTMLDocument
3170 };
3171 let window = document.window();
3172 let loader = DocumentLoader::new(&document.loader());
3173 let document = Document::new(
3174 cx,
3175 window,
3176 HasBrowsingContext::No,
3177 Some(document.url()),
3178 None,
3179 document.origin().clone(),
3181 is_html_doc,
3182 None,
3183 None,
3184 DocumentActivity::Inactive,
3185 loader,
3186 None,
3187 document.status_code(),
3188 false,
3189 document.allow_declarative_shadow_roots(),
3190 Some(document.insecure_requests_policy()),
3191 document.has_trustworthy_ancestor_or_current_origin(),
3192 document.custom_element_reaction_stack(),
3193 document.creation_sandboxing_flag_set(),
3194 document.pipeline_id(),
3195 document.image_cache(),
3196 );
3197 DomRoot::upcast::<Node>(document)
3201 },
3202 NodeTypeId::Element(..) => {
3204 let element = node.downcast::<Element>().unwrap();
3205 let registry = element.custom_element_registry().or(registry);
3208 let registry =
3211 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3212 document.effective_global_custom_element_registry()
3213 } else {
3214 registry
3215 };
3216 let name = QualName {
3220 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3221 ns: element.namespace().clone(),
3222 local: element.local_name().clone(),
3223 };
3224 let element = Element::create(
3225 cx,
3226 name,
3227 element.get_is(),
3228 &document,
3229 ElementCreator::ScriptCreated,
3230 CustomElementCreationMode::Asynchronous,
3231 None,
3232 );
3233 element.set_custom_element_registry(registry.as_deref(), cx.no_gc());
3235 DomRoot::upcast::<Node>(element)
3236 },
3237 };
3238
3239 let document = match copy.downcast::<Document>() {
3242 Some(doc) => DomRoot::from_ref(doc),
3243 None => DomRoot::from_ref(&*document),
3244 };
3245 assert!(copy.owner_doc() == document);
3246
3247 match node.type_id() {
3249 NodeTypeId::Document(_) => {
3250 let node_doc = node.downcast::<Document>().unwrap();
3251 let copy_doc = copy.downcast::<Document>().unwrap();
3252 copy_doc.set_encoding(node_doc.encoding());
3253 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3254 },
3255 NodeTypeId::Element(..) => {
3256 let node_elem = node.downcast::<Element>().unwrap();
3257 let copy_elem = copy.downcast::<Element>().unwrap();
3258
3259 node_elem.copy_all_attributes_to_other_element(cx, copy_elem);
3261 },
3262 _ => (),
3263 }
3264
3265 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3268
3269 if clone_children == CloneChildrenFlag::CloneChildren {
3272 for child in node.children() {
3273 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3274 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3275 }
3276 }
3277
3278 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3281 let node_elem = node.downcast::<Element>().unwrap();
3282 let copy_elem = copy.downcast::<Element>().unwrap();
3283
3284 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3285 assert!(!copy_elem.is_shadow_host());
3287
3288 let copy_shadow_root =
3292 copy_elem.attach_shadow(
3293 cx,
3294 IsUserAgentWidget::No,
3295 shadow_root.Mode(),
3296 shadow_root.Clonable(),
3297 shadow_root.Serializable(),
3298 shadow_root.DelegatesFocus(),
3299 shadow_root.SlotAssignment(),
3300 )
3301 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3302
3303 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3305
3306 for child in shadow_root.upcast::<Node>().children() {
3309 let child_copy = Node::clone(
3310 cx,
3311 &child,
3312 Some(&document),
3313 CloneChildrenFlag::CloneChildren,
3314 None,
3315 );
3316
3317 let _inserted_node =
3319 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3320 }
3321 }
3322 }
3323
3324 copy
3326 }
3327
3328 pub(crate) fn child_text_content(&self) -> DOMString {
3330 Node::collect_text_contents(self.children())
3331 }
3332
3333 pub(crate) fn descendant_text_content(&self) -> DOMString {
3335 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3336 }
3337
3338 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3339 iterator: T,
3340 ) -> DOMString {
3341 let mut content = String::new();
3342 for node in iterator {
3343 if let Some(text) = node.downcast::<Text>() {
3344 content.push_str(&text.upcast::<CharacterData>().data());
3345 }
3346 }
3347 DOMString::from(content)
3348 }
3349
3350 pub(crate) fn set_text_content_for_element(
3352 &self,
3353 cx: &mut JSContext,
3354 value: Option<DOMString>,
3355 ) {
3356 assert!(matches!(
3359 self.type_id(),
3360 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3361 ));
3362 let value = value.unwrap_or_default();
3363 let node = if value.is_empty() {
3364 None
3366 } else {
3367 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3370 };
3371
3372 Self::replace_all(cx, node.as_deref(), self);
3374 }
3375
3376 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3377 match namespace {
3378 ns!() => None,
3379 _ => Some(DOMString::from(&*namespace)),
3381 }
3382 }
3383
3384 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3386 match node.type_id() {
3387 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3388 NodeTypeId::Attr => node
3389 .downcast::<Attr>()
3390 .unwrap()
3391 .GetOwnerElement()
3392 .as_ref()
3393 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3394 NodeTypeId::Document(_) => node
3395 .downcast::<Document>()
3396 .unwrap()
3397 .GetDocumentElement()
3398 .as_ref()
3399 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3400 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3401 _ => node
3402 .GetParentElement()
3403 .as_ref()
3404 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3405 }
3406 }
3407
3408 #[expect(unsafe_code)]
3416 pub(crate) unsafe fn from_untrusted_node_address(
3417 candidate: UntrustedNodeAddress,
3418 ) -> &'static Self {
3419 let candidate = candidate.0 as usize;
3421 let object = candidate as *mut JSObject;
3422 if object.is_null() {
3423 panic!("Attempted to create a `Node` from an invalid pointer!")
3424 }
3425
3426 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3427 }
3428
3429 pub(crate) fn html_serialize(
3430 &self,
3431 cx: &mut JSContext,
3432 traversal_scope: html_serialize::TraversalScope,
3433 serialize_shadow_roots: bool,
3434 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3435 ) -> DOMString {
3436 let mut writer = vec![];
3437 let mut serializer = HtmlSerializer::new(
3438 &mut writer,
3439 html_serialize::SerializeOpts {
3440 traversal_scope: traversal_scope.clone(),
3441 ..Default::default()
3442 },
3443 );
3444
3445 serialize_html_fragment(
3446 cx,
3447 self,
3448 &mut serializer,
3449 traversal_scope,
3450 serialize_shadow_roots,
3451 shadow_roots,
3452 )
3453 .expect("Serializing node failed");
3454
3455 DOMString::from(String::from_utf8(writer).unwrap())
3457 }
3458
3459 pub(crate) fn xml_serialize(
3461 &self,
3462 traversal_scope: xml_serialize::TraversalScope,
3463 ) -> Fallible<DOMString> {
3464 let mut writer = vec![];
3465 xml_serialize::serialize(
3466 &mut writer,
3467 &HtmlSerialize::new(self),
3468 xml_serialize::SerializeOpts { traversal_scope },
3469 )
3470 .map_err(|error| {
3471 error!("Cannot serialize node: {error}");
3472 Error::InvalidState(Some("Cannot serialize node".into()))
3473 })?;
3474
3475 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3477 error!("Cannot serialize node: {error}");
3478 Error::InvalidState(Some("Cannot serialize node".into()))
3479 })?);
3480
3481 Ok(string)
3482 }
3483
3484 pub(crate) fn fragment_serialization_algorithm(
3486 &self,
3487 cx: &mut JSContext,
3488 require_well_formed: bool,
3489 ) -> Fallible<DOMString> {
3490 let context_document = self.owner_document();
3492
3493 if context_document.is_html_document() {
3496 return Ok(self.html_serialize(
3497 cx,
3498 html_serialize::TraversalScope::ChildrenOnly(None),
3499 false,
3500 vec![],
3501 ));
3502 }
3503
3504 let _ = require_well_formed;
3507 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3508 }
3509
3510 pub(crate) fn get_next_sibling_unrooted<'a>(
3511 &self,
3512 no_gc: &'a NoGC,
3513 ) -> Option<UnrootedDom<'a, Node>> {
3514 self.next_sibling.get_unrooted(no_gc)
3515 }
3516
3517 pub(crate) fn next_flat_tree_sibling_unrooted<'a>(
3518 &self,
3519 no_gc: &'a NoGC,
3520 ) -> Option<UnrootedDom<'a, Node>> {
3521 if let Some(slot_element) = self.assigned_slot() {
3522 return slot_element
3526 .assigned_nodes()
3527 .iter()
3528 .skip_while(|slottable| &*slottable.0 != self)
3529 .nth(1)
3531 .map(|next_slottable| next_slottable.0.as_unrooted(no_gc));
3532 }
3533 self.get_next_sibling_unrooted(no_gc)
3534 }
3535
3536 pub(crate) fn get_previous_sibling_unrooted<'a>(
3537 &self,
3538 no_gc: &'a NoGC,
3539 ) -> Option<UnrootedDom<'a, Node>> {
3540 self.prev_sibling.get_unrooted(no_gc)
3541 }
3542
3543 pub(crate) fn get_first_child_unrooted<'a>(
3544 &self,
3545 no_gc: &'a NoGC,
3546 ) -> Option<UnrootedDom<'a, Node>> {
3547 self.first_child.get_unrooted(no_gc)
3548 }
3549
3550 pub(crate) fn first_flat_tree_child_unrooted<'a>(
3551 &self,
3552 no_gc: &'a NoGC,
3553 ) -> Option<UnrootedDom<'a, Node>> {
3554 let Some(element) = self.downcast::<Element>() else {
3555 return self.get_first_child_unrooted(no_gc);
3556 };
3557 if let Some(shadow_root) = element.shadow_root_unrooted(no_gc) {
3558 return shadow_root
3559 .upcast::<Node>()
3560 .first_flat_tree_child_unrooted(no_gc);
3561 };
3562
3563 if let Some(slot_element) = element.downcast::<HTMLSlotElement>() &&
3567 slot_element.has_assigned_nodes() &&
3568 let Some(assigned_node) = slot_element.assigned_nodes().first()
3569 {
3570 return Some(assigned_node.0.as_unrooted(no_gc));
3571 }
3572
3573 self.get_first_child_unrooted(no_gc)
3574 }
3575
3576 fn get_last_child_unrooted<'b>(&self, no_gc: &'b NoGC) -> Option<UnrootedDom<'b, Node>> {
3577 self.last_child.get_unrooted(no_gc)
3578 }
3579
3580 pub(crate) fn get_parent_node_unrooted<'a>(
3581 &self,
3582 no_gc: &'a NoGC,
3583 ) -> Option<UnrootedDom<'a, Node>> {
3584 self.parent_node.get_unrooted(no_gc)
3585 }
3586
3587 pub(crate) fn compare_dom_tree_position(
3589 &self,
3590 other: &Node,
3591 common_ancestor: &Node,
3592 shadow_including: ShadowIncluding,
3593 ) -> Ordering {
3594 debug_assert!(
3595 self.inclusive_ancestors(shadow_including)
3596 .any(|ancestor| &*ancestor == common_ancestor)
3597 );
3598 debug_assert!(
3599 other
3600 .inclusive_ancestors(shadow_including)
3601 .any(|ancestor| &*ancestor == common_ancestor)
3602 );
3603
3604 if self == other {
3605 return Ordering::Equal;
3606 }
3607
3608 if self == common_ancestor {
3609 return Ordering::Less;
3610 }
3611 if other == common_ancestor {
3612 return Ordering::Greater;
3613 }
3614
3615 let my_ancestors: Vec<_> = self
3616 .inclusive_ancestors(shadow_including)
3617 .take_while(|ancestor| &**ancestor != common_ancestor)
3618 .collect();
3619 let other_ancestors: Vec<_> = other
3620 .inclusive_ancestors(shadow_including)
3621 .take_while(|ancestor| &**ancestor != common_ancestor)
3622 .collect();
3623
3624 let mut i = my_ancestors.len() - 1;
3626 let mut j = other_ancestors.len() - 1;
3627
3628 while my_ancestors[i] == other_ancestors[j] {
3629 if i == 0 {
3630 debug_assert_ne!(j, 0, "Equal inclusive ancestors but nodes are not equal?");
3632 return Ordering::Less;
3633 }
3634 if j == 0 {
3635 return Ordering::Greater;
3637 }
3638
3639 i -= 1;
3640 j -= 1;
3641 }
3642
3643 if my_ancestors[i]
3646 .preceding_siblings()
3647 .any(|sibling| sibling == other_ancestors[j])
3648 {
3649 Ordering::Greater
3651 } else {
3652 debug_assert!(
3654 other_ancestors[j]
3655 .preceding_siblings()
3656 .any(|sibling| sibling == my_ancestors[i])
3657 );
3658 Ordering::Less
3659 }
3660 }
3661}
3662
3663impl NodeMethods<crate::DomTypeHolder> for Node {
3664 fn NodeType(&self) -> u16 {
3666 match self.type_id() {
3667 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3668 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3669 NodeConstants::TEXT_NODE
3670 },
3671 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3672 NodeConstants::CDATA_SECTION_NODE
3673 },
3674 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3675 NodeConstants::PROCESSING_INSTRUCTION_NODE
3676 },
3677 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3678 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3679 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3680 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3681 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3682 }
3683 }
3684
3685 fn NodeName(&self) -> DOMString {
3687 match self.type_id() {
3688 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3689 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3690 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3691 DOMString::from_static("#text")
3692 },
3693 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3694 DOMString::from_static("#cdata-section")
3695 },
3696 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3697 self.downcast::<ProcessingInstruction>().unwrap().Target()
3698 },
3699 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => {
3700 DOMString::from_static("#comment")
3701 },
3702 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3703 NodeTypeId::DocumentFragment(_) => DOMString::from_static("#document-fragment"),
3704 NodeTypeId::Document(_) => DOMString::from_static("#document"),
3705 }
3706 }
3707
3708 fn BaseURI(&self) -> USVString {
3710 USVString(String::from(self.owner_doc().base_url().as_str()))
3711 }
3712
3713 fn IsConnected(&self) -> bool {
3715 self.is_connected()
3716 }
3717
3718 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3720 match self.type_id() {
3721 NodeTypeId::Document(_) => None,
3722 _ => Some(self.owner_doc()),
3723 }
3724 }
3725
3726 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3728 if !options.composed &&
3729 let Some(shadow_root) = self.containing_shadow_root()
3730 {
3731 return DomRoot::upcast(shadow_root);
3732 }
3733
3734 if self.is_connected() {
3735 DomRoot::from_ref(self.owner_doc().upcast::<Node>())
3736 } else {
3737 self.inclusive_ancestors(ShadowIncluding::Yes)
3738 .last()
3739 .unwrap()
3740 }
3741 }
3742
3743 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
3745 self.parent_node().get()
3746 }
3747
3748 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
3750 self.GetParentNode().and_then(DomRoot::downcast)
3751 }
3752
3753 fn HasChildNodes(&self) -> bool {
3755 self.first_child().get().is_some()
3756 }
3757
3758 fn ChildNodes(&self, cx: &mut JSContext) -> DomRoot<NodeList> {
3760 if let Some(list) = self.ensure_rare_data().child_list.get() {
3761 return list;
3762 }
3763
3764 let doc = self.owner_doc();
3765 let window = doc.window();
3766 let list = NodeList::new_child_list(cx, window, self);
3767 self.ensure_rare_data().child_list.set(Some(&list));
3768 list
3769 }
3770
3771 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
3773 self.first_child().get()
3774 }
3775
3776 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
3778 self.last_child().get()
3779 }
3780
3781 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
3783 self.prev_sibling().get()
3784 }
3785
3786 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
3788 self.next_sibling().get()
3789 }
3790
3791 fn GetNodeValue(&self) -> Option<DOMString> {
3793 match self.type_id() {
3794 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3795 NodeTypeId::CharacterData(_) => {
3796 self.downcast::<CharacterData>().map(CharacterData::Data)
3797 },
3798 _ => None,
3799 }
3800 }
3801
3802 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
3804 match self.type_id() {
3805 NodeTypeId::Attr => {
3806 let attr = self.downcast::<Attr>().unwrap();
3807 attr.SetValue(cx, val.unwrap_or_default())?;
3808 },
3809 NodeTypeId::CharacterData(_) => {
3810 let character_data = self.downcast::<CharacterData>().unwrap();
3811 character_data.SetData(cx, val.unwrap_or_default());
3812 },
3813 _ => {},
3814 };
3815 Ok(())
3816 }
3817
3818 fn GetTextContent(&self) -> Option<DOMString> {
3820 match self.type_id() {
3821 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3822 let content =
3823 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
3824 Some(content)
3825 },
3826 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3827 NodeTypeId::CharacterData(..) => {
3828 let characterdata = self.downcast::<CharacterData>().unwrap();
3829 Some(characterdata.Data())
3830 },
3831 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
3832 }
3833 }
3834
3835 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
3837 match self.type_id() {
3838 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3839 self.set_text_content_for_element(cx, value);
3840 },
3841 NodeTypeId::Attr => {
3842 let attr = self.downcast::<Attr>().unwrap();
3843 attr.SetValue(cx, value.unwrap_or_default())?;
3844 },
3845 NodeTypeId::CharacterData(..) => {
3846 let characterdata = self.downcast::<CharacterData>().unwrap();
3847 characterdata.SetData(cx, value.unwrap_or_default());
3848 },
3849 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
3850 };
3851 Ok(())
3852 }
3853
3854 fn InsertBefore(
3856 &self,
3857 cx: &mut JSContext,
3858 node: &Node,
3859 child: Option<&Node>,
3860 ) -> Fallible<DomRoot<Node>> {
3861 Node::pre_insert(cx, node, self, child)
3862 }
3863
3864 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3866 Node::pre_insert(cx, node, self, None)
3867 }
3868
3869 fn ReplaceChild(
3871 &self,
3872 cx: &mut JSContext,
3873 node: &Node,
3874 child: &Node,
3875 ) -> Fallible<DomRoot<Node>> {
3876 match self.type_id() {
3879 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3880 },
3881 _ => {
3882 return Err(Error::HierarchyRequest(Some(
3883 "Parent is not a Document, DocumentFragment, or Element node".into(),
3884 )));
3885 },
3886 }
3887
3888 if node.is_inclusive_ancestor_of(self) {
3891 return Err(Error::HierarchyRequest(Some(
3892 "Node cannot be a host-including ancestor of parent".into(),
3893 )));
3894 }
3895
3896 if !self.is_parent_of(child) {
3898 return Err(Error::NotFound(Some(
3899 "Parent node provided does not match child's parent node".into(),
3900 )));
3901 }
3902
3903 match node.type_id() {
3908 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
3909 return Err(Error::HierarchyRequest(Some(
3910 "Node cannot be a Text node while parent is a document".into(),
3911 )));
3912 },
3913 NodeTypeId::DocumentType if !self.is::<Document>() => {
3914 return Err(Error::HierarchyRequest(Some(
3915 "Node cannot be a doctype when parent is not a document".into(),
3916 )));
3917 },
3918 NodeTypeId::Document(_) | NodeTypeId::Attr => {
3919 return Err(Error::HierarchyRequest(Some(
3920 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
3921 .into(),
3922 )));
3923 },
3924 _ => (),
3925 }
3926
3927 if self.is::<Document>() {
3930 match node.type_id() {
3931 NodeTypeId::DocumentFragment(_) => {
3933 if node.children_unrooted(cx.no_gc()).any(|c| c.is::<Text>()) {
3935 return Err(Error::HierarchyRequest(Some(
3936 "Parent is a document and node has a Text node child".into(),
3937 )));
3938 }
3939 match node.child_elements_unrooted(cx.no_gc()).count() {
3940 0 => (),
3941 1 => {
3943 if self
3944 .child_elements_unrooted(cx.no_gc())
3945 .any(|c| c.upcast::<Node>() != child)
3946 {
3947 return Err(Error::HierarchyRequest(Some(
3948 "Node has one element child and parent's children elements does not include child provided"
3949 .into(),
3950 )));
3951 }
3952 if child.following_siblings().any(|child| child.is_doctype()) {
3953 return Err(Error::HierarchyRequest(Some(
3954 "Node cannot have element child of type document".into(),
3955 )));
3956 }
3957 },
3958 _ => {
3960 return Err(Error::HierarchyRequest(Some(
3961 "Node cannot have more than one child element".into(),
3962 )));
3963 },
3964 }
3965 },
3966 NodeTypeId::Element(..) => {
3968 if self
3969 .child_elements_unrooted(cx.no_gc())
3970 .any(|c| c.upcast::<Node>() != child)
3971 {
3972 return Err(Error::HierarchyRequest(Some(
3973 "Parent's children elements does not include child provided".into(),
3974 )));
3975 }
3976 if child.following_siblings().any(|child| child.is_doctype()) {
3977 return Err(Error::HierarchyRequest(Some(
3978 "Node cannot have element child of type document".into(),
3979 )));
3980 }
3981 },
3982 NodeTypeId::DocumentType => {
3984 if self
3985 .children_unrooted(cx.no_gc())
3986 .any(|c| c.is_doctype() && *c != child)
3987 {
3988 return Err(Error::HierarchyRequest(Some(
3989 "Parent cannot have a doctype child".into(),
3990 )));
3991 }
3992 if self
3993 .children_unrooted(cx.no_gc())
3994 .take_while(|c| **c != child)
3995 .any(|c| c.is::<Element>())
3996 {
3997 return Err(Error::HierarchyRequest(Some(
3998 "An element cannot precede the child given".into(),
3999 )));
4000 }
4001 },
4002 NodeTypeId::CharacterData(..) => (),
4003 NodeTypeId::Document(_) => unreachable!(),
4006 NodeTypeId::Attr => unreachable!(),
4007 }
4008 }
4009
4010 let child_next_sibling = child.GetNextSibling();
4013 let node_next_sibling = node.GetNextSibling();
4014 let reference_child = if child_next_sibling.as_deref() == Some(node) {
4015 node_next_sibling.as_deref()
4016 } else {
4017 child_next_sibling.as_deref()
4018 };
4019
4020 let previous_sibling = child.GetPreviousSibling();
4022
4023 let document = self.owner_document();
4027 Node::adopt(cx, node, &document);
4028
4029 let removed_child = if node != child {
4034 Node::remove(cx, child, self, SuppressObserver::Suppressed);
4036 Some(child)
4037 } else {
4038 None
4039 };
4040
4041 rooted_vec!(let mut nodes);
4043 let nodes = if node.type_id() ==
4044 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
4045 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
4046 {
4047 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
4048 nodes.r()
4049 } else {
4050 from_ref(&node)
4051 };
4052
4053 Node::insert(
4055 cx,
4056 node,
4057 self,
4058 reference_child,
4059 SuppressObserver::Suppressed,
4060 );
4061
4062 vtable_for(self).children_changed(
4063 cx,
4064 &ChildrenMutation::replace(
4065 previous_sibling.as_deref(),
4066 &removed_child,
4067 reference_child,
4068 ),
4069 );
4070
4071 let removed = removed_child.map(|r| [r]);
4074 let mutation = LazyCell::new(|| Mutation::ChildList {
4075 added: Some(nodes),
4076 removed: removed.as_ref().map(|r| &r[..]),
4077 prev: previous_sibling.as_deref(),
4078 next: reference_child,
4079 });
4080
4081 MutationObserver::queue_a_mutation_record(cx, self, mutation);
4082
4083 Ok(DomRoot::from_ref(child))
4085 }
4086
4087 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
4089 Node::pre_remove(cx, node, self)
4090 }
4091
4092 fn Normalize(&self, cx: &mut JSContext) {
4094 let mut children = self.children().peekable();
4095
4096 let document = self.owner_document();
4097 let selection = document.selection();
4098 while let Some(node) = children.next() {
4099 let Some(text) = node.downcast::<Text>() else {
4102 node.Normalize(cx);
4103 continue;
4104 };
4105 if text.is::<CDATASection>() {
4106 continue;
4107 }
4108
4109 let cdata = text.upcast::<CharacterData>();
4111 let mut length = cdata.Length();
4112
4113 if length == 0 {
4116 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
4117 continue;
4118 }
4119
4120 let mut siblings_to_merge: SmallVec<[DomRoot<CharacterData>; 4]> = SmallVec::new();
4123 let mut new_data_length = 0;
4124 while let Some(sibling) = children.peek() {
4125 if !sibling.is::<Text>() || sibling.is::<CDATASection>() {
4126 break;
4127 }
4128
4129 let sibling: DomRoot<CharacterData> =
4130 DomRoot::downcast(children.next().expect("Guaranteed by the peek above"))
4131 .expect("Guaranteed by check above");
4132 new_data_length += sibling.data().len();
4133 siblings_to_merge.push(sibling);
4134 }
4135
4136 if siblings_to_merge.is_empty() {
4137 continue;
4138 }
4139
4140 let mut data = String::with_capacity(new_data_length);
4143 for sibling in &siblings_to_merge {
4144 data.push_str(sibling.data().as_str());
4145 }
4146
4147 cdata.append_data(cx, &data);
4149
4150 let first_sibling_index = LazyCell::new(|| node.index() + 1);
4154 for (current_node_index, current_node) in siblings_to_merge.iter().enumerate() {
4155 let index = &|| *first_sibling_index + current_node_index as u32;
4156 if let Some(selection) = &selection {
4158 selection.normalization_steps(
4159 self,
4160 &node,
4161 current_node.upcast(),
4162 &index,
4163 length,
4164 );
4165 }
4166 document.live_range_normalization_steps(
4167 cx.no_gc(),
4168 self,
4169 &node,
4170 current_node.upcast(),
4171 &index,
4172 length,
4173 );
4174 length += current_node.Length();
4176 }
4179
4180 for current_node in siblings_to_merge.into_iter() {
4183 Node::remove(
4184 cx,
4185 current_node.upcast(),
4186 self,
4187 SuppressObserver::Unsuppressed,
4188 );
4189 }
4190 }
4191 }
4192
4193 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
4195 if self.is::<ShadowRoot>() {
4197 return Err(Error::NotSupported(Some(
4198 "Cannot clone a shadow root".into(),
4199 )));
4200 }
4201
4202 let result = Node::clone(
4204 cx,
4205 self,
4206 None,
4207 if subtree {
4208 CloneChildrenFlag::CloneChildren
4209 } else {
4210 CloneChildrenFlag::DoNotCloneChildren
4211 },
4212 None,
4213 );
4214 Ok(result)
4215 }
4216
4217 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
4219 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
4220 let doctype = node.downcast::<DocumentType>().unwrap();
4221 let other_doctype = other.downcast::<DocumentType>().unwrap();
4222 (*doctype.name() == *other_doctype.name()) &&
4223 (*doctype.public_id() == *other_doctype.public_id()) &&
4224 (*doctype.system_id() == *other_doctype.system_id())
4225 }
4226 fn is_equal_element(node: &Node, other: &Node) -> bool {
4227 let element = node.downcast::<Element>().unwrap();
4228 let other_element = other.downcast::<Element>().unwrap();
4229 (*element.namespace() == *other_element.namespace()) &&
4230 (*element.prefix() == *other_element.prefix()) &&
4231 (*element.local_name() == *other_element.local_name()) &&
4232 (element.attrs().borrow().len() == other_element.attrs().borrow().len())
4233 }
4234 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
4235 let pi = node.downcast::<ProcessingInstruction>().unwrap();
4236 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
4237 (*pi.target() == *other_pi.target()) &&
4238 (*pi.upcast::<CharacterData>().data() ==
4239 *other_pi.upcast::<CharacterData>().data())
4240 }
4241 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
4242 let characterdata = node.downcast::<CharacterData>().unwrap();
4243 let other_characterdata = other.downcast::<CharacterData>().unwrap();
4244 *characterdata.data() == *other_characterdata.data()
4245 }
4246 fn is_equal_attr(node: &Node, other: &Node) -> bool {
4247 let attr = node.downcast::<Attr>().unwrap();
4248 let other_attr = other.downcast::<Attr>().unwrap();
4249 (*attr.namespace() == *other_attr.namespace()) &&
4250 (attr.local_name() == other_attr.local_name()) &&
4251 (**attr.value() == **other_attr.value())
4252 }
4253 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
4254 let element = node.downcast::<Element>().unwrap();
4255 let other_element = other.downcast::<Element>().unwrap();
4256 assert!(element.attrs().borrow().len() == other_element.attrs().borrow().len());
4257 element.attrs().borrow().iter().all(|attr| {
4258 other_element.attrs().borrow().iter().any(|other_attr| {
4259 (*attr.namespace() == *other_attr.namespace()) &&
4260 (attr.local_name() == other_attr.local_name()) &&
4261 (**attr.value() == **other_attr.value())
4262 })
4263 })
4264 }
4265
4266 fn is_equal_node(this: &Node, node: &Node) -> bool {
4267 if this.NodeType() != node.NodeType() {
4269 return false;
4270 }
4271
4272 match node.type_id() {
4273 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
4275 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
4276 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
4277 if !is_equal_processinginstruction(this, node) =>
4278 {
4279 return false;
4280 },
4281 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
4282 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
4283 if !is_equal_characterdata(this, node) =>
4284 {
4285 return false;
4286 },
4287 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
4289 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
4290
4291 _ => (),
4292 }
4293
4294 if this.children_count() != node.children_count() {
4296 return false;
4297 }
4298
4299 this.children()
4301 .zip(node.children())
4302 .all(|(child, other_child)| is_equal_node(&child, &other_child))
4303 }
4304 match maybe_node {
4305 None => false,
4307 Some(node) => is_equal_node(self, node),
4309 }
4310 }
4311
4312 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
4314 match other_node {
4315 Some(node) => self == node,
4316 None => false,
4317 }
4318 }
4319
4320 fn CompareDocumentPosition(&self, no_gc: &NoGC, other: &Node) -> u16 {
4322 if self == other {
4324 return 0;
4325 }
4326
4327 let mut node1 = Some(other);
4329 let mut node2 = Some(self);
4330
4331 let mut attr1: Option<&Attr> = None;
4333 let mut attr2: Option<&Attr> = None;
4334
4335 let attr1owner;
4340 if let Some(a) = other.downcast::<Attr>() {
4341 attr1 = Some(a);
4342 attr1owner = a.GetOwnerElement();
4343 node1 = match attr1owner {
4344 Some(ref e) => Some(e.upcast()),
4345 None => None,
4346 }
4347 }
4348
4349 let attr2owner;
4352 if let Some(a) = self.downcast::<Attr>() {
4353 attr2 = Some(a);
4354 attr2owner = a.GetOwnerElement();
4355 node2 = match attr2owner {
4356 Some(ref e) => Some(e.upcast()),
4357 None => None,
4358 }
4359 }
4360
4361 if let Some(node2) = node2 &&
4366 Some(node2) == node1 &&
4367 let (Some(a1), Some(a2)) = (attr1, attr2)
4368 {
4369 let attrs = node2.downcast::<Element>().unwrap().attrs();
4370 for attr in attrs.borrow().iter() {
4374 if (*attr.namespace() == *a1.namespace()) &&
4375 (attr.local_name() == a1.local_name()) &&
4376 (**attr.value() == **a1.value())
4377 {
4378 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4379 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4380 }
4381 if (*attr.namespace() == *a2.namespace()) &&
4382 (attr.local_name() == a2.local_name()) &&
4383 (**attr.value() == **a2.value())
4384 {
4385 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4386 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4387 }
4388 }
4389 unreachable!();
4392 }
4393
4394 let options = GetRootNodeOptions { composed: false };
4400 let node1_root = node1.map(|node| node.GetRootNode(&options));
4401 let node2_root = node2.map(|node| node.GetRootNode(&options));
4402 if node1_root.is_none() || node2_root.is_none() || node1_root != node2_root {
4403 let pointer1 = node1.map(as_uintptr::<Node>).unwrap_or_default();
4406 let pointer2 = node2.map(as_uintptr::<Node>).unwrap_or_default();
4407 let arbitrary_order = if pointer1 < pointer2 {
4408 NodeConstants::DOCUMENT_POSITION_PRECEDING
4409 } else {
4410 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4411 };
4412
4413 return arbitrary_order +
4414 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4415 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4416 }
4417
4418 let (ordering, containment_flags) = match (node1, node2) {
4420 (Some(node1), Some(node2)) => {
4421 compare_dom_positions::<LightDomNoGcTraversal>(no_gc, node1, 0, node2, 0)
4422 },
4423 _ => (None, DomPositionContainment::empty()),
4424 };
4425
4426 if (containment_flags.contains(DomPositionContainment::AContainsB) && attr1.is_none()) ||
4430 (node1 == node2 && attr2.is_some())
4431 {
4432 return NodeConstants::DOCUMENT_POSITION_CONTAINS +
4433 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4434 }
4435
4436 if (containment_flags.contains(DomPositionContainment::BContainsA) && attr2.is_none()) ||
4440 (node1 == node2 && attr1.is_some())
4441 {
4442 return NodeConstants::DOCUMENT_POSITION_CONTAINED_BY +
4443 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4444 }
4445
4446 if ordering == Some(Ordering::Less) {
4448 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4449 }
4450
4451 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4453 }
4454
4455 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4457 match maybe_other {
4458 None => false,
4459 Some(other) => self.is_inclusive_ancestor_of(other),
4460 }
4461 }
4462
4463 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4465 let namespace = namespace_from_domstring(namespace);
4466
4467 if namespace == ns!() {
4469 return None;
4470 }
4471
4472 match self.type_id() {
4474 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4475 NodeTypeId::Document(_) => self
4476 .downcast::<Document>()
4477 .unwrap()
4478 .GetDocumentElement()
4479 .and_then(|element| element.lookup_prefix(namespace)),
4480 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4481 NodeTypeId::Attr => self
4482 .downcast::<Attr>()
4483 .unwrap()
4484 .GetOwnerElement()
4485 .and_then(|element| element.lookup_prefix(namespace)),
4486 _ => self
4487 .GetParentElement()
4488 .and_then(|element| element.lookup_prefix(namespace)),
4489 }
4490 }
4491
4492 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4494 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4496
4497 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4499 }
4500
4501 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4503 let namespace = namespace_from_domstring(namespace);
4505 Node::locate_namespace(self, None) == namespace
4507 }
4508}
4509
4510pub(crate) trait NodeTraits {
4511 fn owner_document(&self) -> DomRoot<Document>;
4515 fn owner_window(&self) -> DomRoot<Window>;
4519 fn owner_global(&self) -> DomRoot<GlobalScope>;
4523 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4525 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4528}
4529
4530impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4531 fn owner_document(&self) -> DomRoot<Document> {
4532 self.upcast().owner_doc()
4533 }
4534
4535 fn owner_window(&self) -> DomRoot<Window> {
4536 DomRoot::from_ref(self.owner_document().window())
4537 }
4538
4539 fn owner_global(&self) -> DomRoot<GlobalScope> {
4540 DomRoot::from_ref(self.owner_window().upcast())
4541 }
4542
4543 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4544 Node::containing_shadow_root(self.upcast())
4545 }
4546
4547 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4548 self.containing_shadow_root()
4549 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4550 .unwrap_or_else(|| {
4551 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4552 })
4553 }
4554}
4555
4556impl VirtualMethods for Node {
4557 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4558 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4559 }
4560
4561 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4562 if let Some(s) = self.super_type() {
4563 s.children_changed(cx, mutation);
4564 }
4565
4566 if let Some(data) = self.rare_data.borrow().as_ref() &&
4567 let Some(list) = data.child_list.get()
4568 {
4569 list.as_children_list().children_changed(mutation);
4570 }
4571
4572 self.owner_doc_unrooted(cx.no_gc())
4573 .content_and_heritage_changed(cx.no_gc(), self);
4574 }
4575
4576 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
4577 if let Some(super_type) = self.super_type() {
4578 super_type.moving_steps(cx, context);
4579 }
4580
4581 self.owner_doc_unrooted(cx.no_gc())
4582 .content_and_heritage_changed(cx.no_gc(), self);
4583
4584 if let Some(parent) = self.GetParentNode() {
4585 Self::maybe_dirty_visible_selection_for_newly_inserted_nodes(
4586 cx.no_gc(),
4587 &parent,
4588 &[self],
4589 );
4590 }
4591 }
4592
4593 fn handle_event(&self, cx: &mut JSContext, event: &Event) {
4594 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4595 return;
4596 }
4597
4598 if event.type_() == atom!("keydown") &&
4599 let Some(event) = event.downcast::<KeyboardEvent>()
4600 {
4601 self.owner_document()
4602 .event_handler()
4603 .maybe_dispatch_simulated_click(cx, self, event);
4604 }
4605 }
4606}
4607
4608#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4610pub(crate) enum NodeDamage {
4611 Style,
4613 ContentOrHeritage,
4616 Other,
4618}
4619
4620pub(crate) trait VecPreOrderInsertionHelper<T> {
4623 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
4624}
4625
4626impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
4627where
4628 T: DerivedFrom<Node> + DomObject,
4629{
4630 fn insert_pre_order(&mut self, node: &T, tree_root: &Node) {
4635 let Err(insertion_index) = self.binary_search_by(|candidate| {
4636 candidate.upcast().compare_dom_tree_position(
4637 node.upcast(),
4638 tree_root,
4639 ShadowIncluding::No,
4640 )
4641 }) else {
4642 return;
4645 };
4646
4647 self.insert(insertion_index, Dom::from_ref(node));
4648 }
4649}
4650
4651pub(crate) enum FlatTreeParent<'a> {
4653 Parent(UnrootedDom<'a, Node>),
4655 NotInFlatTree,
4658 RootNode,
4660}
4661
4662impl<'a> FlatTreeParent<'a> {
4663 pub(crate) fn into_parent(self) -> Option<UnrootedDom<'a, Node>> {
4664 match self {
4665 FlatTreeParent::Parent(parent) => Some(parent),
4666 FlatTreeParent::NotInFlatTree | FlatTreeParent::RootNode => None,
4667 }
4668 }
4669}