1use std::borrow::Cow;
8use std::cell::{Cell, LazyCell, UnsafeCell};
9use std::cmp::Ordering;
10use std::default::Default;
11use std::f64::consts::PI;
12use std::marker::PhantomData;
13use std::ops::Deref;
14use std::slice::from_ref;
15use std::{cmp, fmt, iter};
16
17use app_units::Au;
18use bitflags::bitflags;
19use devtools_traits::NodeInfo;
20use dom_struct::dom_struct;
21use embedder_traits::UntrustedNodeAddress;
22use euclid::default::Size2D;
23use euclid::{Point2D, Rect};
24use html5ever::serialize::HtmlSerializer;
25use html5ever::{Namespace, Prefix, QualName, ns, serialize as html_serialize};
26use js::context::{JSContext, NoGC};
27use js::jsapi::JSObject;
28use js::rust::HandleObject;
29use keyboard_types::Modifiers;
30use layout_api::{
31 AxesOverflow, BoxAreaType, CSSPixelRectVec, GenericLayoutData, HTMLCanvasData, HTMLMediaData,
32 LayoutElementType, LayoutNodeType, NodeRenderingType, PhysicalSides, SVGElementData,
33 SharedSelection, TrustedNodeAddress, with_layout_state,
34};
35use libc::{self, c_void, uintptr_t};
36use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
37use net_traits::image_cache::Image;
38use pixels::ImageMetadata;
39use script_bindings::cell::{DomRefCell, Ref, RefMut};
40use script_bindings::codegen::GenericBindings::EventBinding::EventMethods;
41use script_bindings::codegen::InheritTypes::DocumentFragmentTypeId;
42use script_bindings::reflector::{DomObject, DomObjectWrap, reflect_dom_object_with_proto_and_cx};
43use script_traits::DocumentActivity;
44use servo_arc::Arc as ServoArc;
45use servo_base::id::{BrowsingContextId, PipelineId};
46use servo_config::pref;
47use servo_url::ServoUrl;
48use smallvec::SmallVec;
49use style::Atom;
50use style::context::QuirksMode;
51use style::dom::OpaqueNode;
52use style::dom_apis::{QueryAll, QueryFirst};
53use style::selector_parser::PseudoElement;
54use style::stylesheets::Stylesheet;
55use style_traits::CSSPixel;
56use uuid::Uuid;
57use xml5ever::{local_name, serialize as xml_serialize};
58
59use crate::conversions::Convert;
60use crate::document_loader::DocumentLoader;
61use crate::dom::attr::Attr;
62use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
63use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
64use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
65use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
66use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
67use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
68use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
69use crate::dom::bindings::codegen::Bindings::NodeBinding::{
70 GetRootNodeOptions, NodeConstants, NodeMethods,
71};
72use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
73use crate::dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
74use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
75use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
76 ShadowRootMode, SlotAssignmentMode,
77};
78use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
79use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
80use crate::dom::bindings::conversions::{self, DerivedFrom};
81use crate::dom::bindings::domname::namespace_from_domstring;
82use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
83use crate::dom::bindings::inheritance::{
84 Castable, CharacterDataTypeId, ElementTypeId, EventTargetTypeId, HTMLElementTypeId, NodeTypeId,
85 SVGElementTypeId, SVGGraphicsElementTypeId, TextTypeId,
86};
87use crate::dom::bindings::root::{
88 Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout, UnrootedDom,
89};
90use crate::dom::bindings::str::{DOMString, USVString};
91use crate::dom::characterdata::CharacterData;
92use crate::dom::css::cssstylesheet::CSSStyleSheet;
93use crate::dom::css::stylesheetlist::StyleSheetListOwner;
94use crate::dom::customelementregistry::{
95 CallbackReaction, CustomElementRegistry, try_upgrade_element,
96};
97use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
98use crate::dom::documentfragment::DocumentFragment;
99use crate::dom::documenttype::DocumentType;
100use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
101use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
102use crate::dom::eventtarget::EventTarget;
103use crate::dom::globalscope::GlobalScope;
104use crate::dom::html::htmlcanvaselement::HTMLCanvasElement;
105use crate::dom::html::htmlcollection::HTMLCollection;
106use crate::dom::html::htmlelement::HTMLElement;
107use crate::dom::html::htmliframeelement::HTMLIFrameElement;
108use crate::dom::html::htmlimageelement::HTMLImageElement;
109use crate::dom::html::htmllinkelement::HTMLLinkElement;
110use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
111use crate::dom::html::htmlstyleelement::HTMLStyleElement;
112use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
113use crate::dom::html::htmlvideoelement::HTMLVideoElement;
114use crate::dom::html::input_element::HTMLInputElement;
115use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
116use crate::dom::node::nodelist::NodeList;
117use crate::dom::pointerevent::{PointerEvent, PointerId};
118use crate::dom::processinginstruction::ProcessingInstruction;
119use crate::dom::range::WeakRangeVec;
120use crate::dom::raredata::NodeRareData;
121use crate::dom::servoparser::html::HtmlSerialize;
122use crate::dom::servoparser::{ServoParser, serialize_html_fragment};
123use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
124use crate::dom::svg::svgsvgelement::SVGSVGElement;
125use crate::dom::text::Text;
126use crate::dom::types::{CDATASection, KeyboardEvent};
127use crate::dom::virtualmethods::{VirtualMethods, vtable_for};
128use crate::dom::window::Window;
129use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode};
130use crate::script_runtime::CanGc;
131use crate::script_thread::ScriptThread;
132
133#[dom_struct]
139pub struct Node {
140 eventtarget: EventTarget,
142
143 parent_node: MutNullableDom<Node>,
145
146 first_child: MutNullableDom<Node>,
148
149 last_child: MutNullableDom<Node>,
151
152 next_sibling: MutNullableDom<Node>,
154
155 prev_sibling: MutNullableDom<Node>,
157
158 owner_doc: MutNullableDom<Document>,
160
161 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
163
164 children_count: Cell<u32>,
166
167 flags: Cell<NodeFlags>,
169
170 inclusive_descendants_version: Cell<u64>,
172
173 #[no_trace]
176 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
177}
178
179impl fmt::Debug for Node {
180 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181 if let Some(element) = self.downcast::<Element>() {
182 element.fmt(f)
183 } else if let Some(character_data) = self.downcast::<CharacterData>() {
184 write!(f, "[Text({})]", character_data.data())
185 } else {
186 write!(f, "[Node({:?})]", self.type_id())
187 }
188 }
189}
190
191#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
193pub(crate) struct NodeFlags(u16);
194
195bitflags! {
196 impl NodeFlags: u16 {
197 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
201
202 const HAS_DIRTY_DESCENDANTS = 1 << 1;
204
205 const CLICK_IN_PROGRESS = 1 << 2;
208
209 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
214
215 const HAS_SNAPSHOT = 1 << 7;
220
221 const HANDLED_SNAPSHOT = 1 << 8;
223
224 const IS_IN_SHADOW_TREE = 1 << 9;
226
227 const IS_CONNECTED = 1 << 10;
231
232 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
235
236 const IS_IN_UA_WIDGET = 1 << 12;
239
240 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
242 }
243}
244
245#[derive(Clone, Copy, MallocSizeOf)]
249enum SuppressObserver {
250 Suppressed,
251 Unsuppressed,
252}
253
254pub(crate) enum ForceSlottableNodeReconciliation {
255 Force,
256 Skip,
257}
258
259impl Node {
260 fn add_child(&self, cx: &mut JSContext, new_child: &Node, before: Option<&Node>) {
264 assert!(new_child.parent_node.get().is_none());
265 assert!(new_child.prev_sibling.get().is_none());
266 assert!(new_child.next_sibling.get().is_none());
267 match before {
268 Some(before) => {
269 assert!(before.parent_node.get().as_deref() == Some(self));
270 let prev_sibling = before.GetPreviousSibling();
271 match prev_sibling {
272 None => {
273 assert!(self.first_child.get().as_deref() == Some(before));
274 self.first_child.set(Some(new_child));
275 },
276 Some(ref prev_sibling) => {
277 prev_sibling.next_sibling.set(Some(new_child));
278 new_child.prev_sibling.set(Some(prev_sibling));
279 },
280 }
281 before.prev_sibling.set(Some(new_child));
282 new_child.next_sibling.set(Some(before));
283 },
284 None => {
285 let last_child = self.GetLastChild();
286 match last_child {
287 None => self.first_child.set(Some(new_child)),
288 Some(ref last_child) => {
289 assert!(last_child.next_sibling.get().is_none());
290 last_child.next_sibling.set(Some(new_child));
291 new_child.prev_sibling.set(Some(last_child));
292 },
293 }
294
295 self.last_child.set(Some(new_child));
296 },
297 }
298
299 new_child.parent_node.set(Some(self));
300 self.children_count.set(self.children_count.get() + 1);
301
302 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
303 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
304 let parent_is_connected = self.is_connected();
305 let parent_is_in_ua_widget = self.is_in_ua_widget();
306
307 let context = BindContext::new(self, IsShadowTree::No);
308
309 for node in new_child.traverse_preorder(ShadowIncluding::No) {
310 if parent_in_shadow_tree {
311 if let Some(shadow_root) = self.containing_shadow_root() {
312 node.set_containing_shadow_root(Some(&*shadow_root));
313 }
314 debug_assert!(node.containing_shadow_root().is_some());
315 }
316 node.set_flag(
317 NodeFlags::IS_IN_A_DOCUMENT_TREE,
318 parent_is_in_a_document_tree,
319 );
320 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
321 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
322 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
323
324 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
326 vtable_for(&node).bind_to_tree(cx, &context);
327 }
328 }
329
330 pub(crate) fn unsafely_set_html(
333 target: &Node,
334 context_element: &Element,
335 html: DOMString,
336 cx: &mut JSContext,
337 ) {
338 let new_children = ServoParser::parse_html_fragment(context_element, html, true, cx);
340
341 let context_document = context_element.owner_document();
344 let fragment = DocumentFragment::new(cx, &context_document);
345
346 for child in new_children {
348 fragment.upcast::<Node>().AppendChild(cx, &child).unwrap();
349 }
350
351 Node::replace_all(cx, Some(fragment.upcast()), target);
353 }
354
355 pub(crate) fn remove_style_and_layout_data_from_subtree(&self, no_gc: &NoGC) {
359 for node in self.traverse_preorder_non_rooting(no_gc, ShadowIncluding::Yes) {
360 node.clean_up_style_and_layout_data();
361 }
362 }
363
364 fn clean_up_style_and_layout_data(&self) {
365 self.layout_data.borrow_mut().take();
366 if let Some(element) = self.downcast::<Element>() {
367 element.clean_up_style_data();
368 }
369 }
370
371 pub(crate) fn complete_remove_subtree(
374 cx: &mut JSContext,
375 root: &Node,
376 context: &UnbindContext,
377 ) {
378 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
380 .union(NodeFlags::IS_CONNECTED)
381 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
382 .union(NodeFlags::HAS_SNAPSHOT)
383 .union(NodeFlags::HANDLED_SNAPSHOT);
384
385 for node in root.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No) {
386 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
387
388 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
391 for node in shadow_root
392 .upcast::<Node>()
393 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
394 {
395 node.set_flag(RESET_FLAGS, false);
396 }
397 }
398 }
399
400 let is_parent_connected = context.parent.is_connected();
402 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
403
404 let cleanup_node = |cx: &mut JSContext, node: &Node| {
407 node.owner_doc().cancel_animations_for_node(node);
408 node.clean_up_style_and_layout_data();
409
410 vtable_for(node).unbind_from_tree(cx, context);
415
416 if is_parent_connected && let Some(element) = node.as_custom_element() {
418 custom_element_reaction_stack.enqueue_callback_reaction(
419 &element,
420 CallbackReaction::Disconnected,
421 None,
422 );
423 }
424 };
425
426 for node in root.traverse_preorder(ShadowIncluding::No) {
427 cleanup_node(cx, &node);
428
429 if node.containing_shadow_root().is_some() {
432 node.set_containing_shadow_root(None);
435 }
436
437 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
440 for node in shadow_root
441 .upcast::<Node>()
442 .traverse_preorder(ShadowIncluding::Yes)
443 {
444 cleanup_node(cx, &node);
445 }
446 }
447 }
448 }
449
450 pub(crate) fn complete_move_subtree(root: &Node) {
451 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
453 .union(NodeFlags::IS_CONNECTED)
454 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
455 .union(NodeFlags::HAS_SNAPSHOT)
456 .union(NodeFlags::HANDLED_SNAPSHOT);
457
458 for node in root.traverse_preorder(ShadowIncluding::No) {
459 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
460 node.clean_up_style_and_layout_data();
461
462 if node.containing_shadow_root().is_some() {
465 node.set_containing_shadow_root(None);
468 }
469
470 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
474 for node in shadow_root
475 .upcast::<Node>()
476 .traverse_preorder(ShadowIncluding::Yes)
477 {
478 node.set_flag(RESET_FLAGS, false);
479 node.clean_up_style_and_layout_data();
480 }
481 }
482 }
483 }
484
485 fn remove_child(&self, cx: &mut JSContext, child: &Node, cached_index: Option<u32>) {
489 assert!(child.parent_node.get().as_deref() == Some(self));
490 self.note_dirty_descendants();
491
492 let prev_sibling = child.GetPreviousSibling();
493 match prev_sibling {
494 None => {
495 self.first_child.set(child.next_sibling.get().as_deref());
496 },
497 Some(ref prev_sibling) => {
498 prev_sibling
499 .next_sibling
500 .set(child.next_sibling.get().as_deref());
501 },
502 }
503 let next_sibling = child.GetNextSibling();
504 match next_sibling {
505 None => {
506 self.last_child.set(child.prev_sibling.get().as_deref());
507 },
508 Some(ref next_sibling) => {
509 next_sibling
510 .prev_sibling
511 .set(child.prev_sibling.get().as_deref());
512 },
513 }
514
515 let context = UnbindContext::new(
516 self,
517 prev_sibling.as_deref(),
518 next_sibling.as_deref(),
519 cached_index,
520 );
521
522 child.prev_sibling.set(None);
523 child.next_sibling.set(None);
524 child.parent_node.set(None);
525 self.children_count.set(self.children_count.get() - 1);
526
527 Self::complete_remove_subtree(cx, child, &context);
528 }
529
530 fn move_child(&self, child: &Node) {
531 assert!(child.parent_node.get().as_deref() == Some(self));
532 self.note_dirty_descendants();
533
534 child.prev_sibling.set(None);
535 child.next_sibling.set(None);
536 child.parent_node.set(None);
537 self.children_count.set(self.children_count.get() - 1);
538 Self::complete_move_subtree(child)
539 }
540
541 pub(crate) fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
542 UntrustedNodeAddress(self.reflector().get_jsobject().get() as *const c_void)
543 }
544
545 pub(crate) fn to_opaque(&self) -> OpaqueNode {
546 OpaqueNode(self.reflector().get_jsobject().get() as usize)
547 }
548
549 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
550 self.downcast::<Element>().and_then(|element| {
551 if element.is_custom() {
552 assert!(element.get_custom_element_definition().is_some());
553 Some(DomRoot::from_ref(element))
554 } else {
555 None
556 }
557 })
558 }
559
560 pub(crate) fn fire_synthetic_pointer_event_not_trusted(
562 &self,
563 cx: &mut JSContext,
564 event_type: Atom,
565 ) {
566 let window = self.owner_window();
570
571 let pointer_event = PointerEvent::new(
573 &window, event_type,
575 EventBubbles::Bubbles, EventCancelable::Cancelable, Some(&window), 0, Point2D::zero(), Point2D::zero(), Point2D::zero(), Modifiers::empty(), 0, 0, None, None, PointerId::NonPointerDevice as i32, 1, 1, 0.5, 0.0, 0, 0, 0, PI / 2.0, 0.0, DOMString::from(""), false, vec![], vec![], CanGc::from_cx(cx),
602 );
603
604 pointer_event.upcast::<Event>().set_composed(true);
606
607 pointer_event.upcast::<Event>().set_trusted(false);
609
610 pointer_event
613 .upcast::<Event>()
614 .dispatch(cx, self.upcast::<EventTarget>(), false);
615 }
616
617 pub(crate) fn parent_directionality(&self) -> String {
618 let mut current = self.GetParentNode();
619
620 loop {
621 match current {
622 Some(node) => {
623 if let Some(directionality) = node
624 .downcast::<HTMLElement>()
625 .and_then(|html_element| html_element.directionality())
626 {
627 return directionality;
628 } else {
629 current = node.GetParentNode();
630 }
631 },
632 None => return "ltr".to_owned(),
633 }
634 }
635 }
636
637 pub(crate) fn is_being_rendered_or_delegates_rendering(
641 &self,
642 pseudo_element: Option<PseudoElement>,
643 ) -> bool {
644 matches!(
645 self.owner_window()
646 .layout()
647 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
648 NodeRenderingType::Rendered | NodeRenderingType::DelegatesRendering
649 )
650 }
651
652 pub(crate) fn is_being_rendered(&self, pseudo_element: Option<PseudoElement>) -> bool {
654 matches!(
655 self.owner_window()
656 .layout()
657 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
658 NodeRenderingType::Rendered
659 )
660 }
661}
662
663impl Node {
664 fn rare_data(&self) -> Ref<'_, Option<Box<NodeRareData>>> {
665 self.rare_data.borrow()
666 }
667
668 fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
669 let mut rare_data = self.rare_data.borrow_mut();
670 if rare_data.is_none() {
671 *rare_data = Some(Default::default());
672 }
673 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
674 }
675
676 pub(crate) fn is_before(&self, other: &Node) -> bool {
679 let cmp = other.CompareDocumentPosition(self);
680 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
681 return false;
682 }
683
684 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
685 }
686
687 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
690 RefMut::map(self.ensure_rare_data(), |rare_data| {
691 &mut rare_data.mutation_observers
692 })
693 }
694
695 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
696 let rare_data: Ref<'_, _> = self.rare_data.borrow();
697
698 if rare_data.is_none() {
699 return None;
700 }
701 Some(Ref::map(rare_data, |rare_data| {
702 &rare_data.as_ref().unwrap().mutation_observers
703 }))
704 }
705
706 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
708 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
709 self.ensure_rare_data().mutation_observers.push(observer);
710 }
711
712 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
714 self.ensure_rare_data()
715 .mutation_observers
716 .retain(|reg_obs| &*reg_obs.observer != observer)
717 }
718
719 pub(crate) fn dump(&self) {
721 self.dump_indent(0);
722 }
723
724 pub(crate) fn dump_indent(&self, indent: u32) {
726 let mut s = String::new();
727 for _ in 0..indent {
728 s.push_str(" ");
729 }
730
731 s.push_str(&self.debug_str());
732 debug!("{:?}", s);
733
734 for kid in self.children() {
736 kid.dump_indent(indent + 1)
737 }
738 }
739
740 pub(crate) fn debug_str(&self) -> String {
742 format!("{:?}", self.type_id())
743 }
744
745 pub(crate) fn is_in_a_document_tree(&self) -> bool {
747 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
748 }
749
750 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
752 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
753 }
754
755 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
756 self.flags
757 .get()
758 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
759 }
760
761 pub(crate) fn set_weird_parser_insertion_mode(&self) {
762 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
763 }
764
765 pub(crate) fn is_connected(&self) -> bool {
767 self.flags.get().contains(NodeFlags::IS_CONNECTED)
768 }
769
770 pub(crate) fn set_in_ua_widget(&self, in_ua_widget: bool) {
771 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, in_ua_widget)
772 }
773
774 pub(crate) fn is_in_ua_widget(&self) -> bool {
775 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
776 }
777
778 pub(crate) fn type_id(&self) -> NodeTypeId {
780 match *self.eventtarget.type_id() {
781 EventTargetTypeId::Node(type_id) => type_id,
782 _ => unreachable!(),
783 }
784 }
785
786 pub(crate) fn len(&self) -> u32 {
788 match self.type_id() {
789 NodeTypeId::DocumentType => 0,
790 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
791 _ => self.children_count(),
792 }
793 }
794
795 pub(crate) fn is_empty(&self) -> bool {
796 self.len() == 0
798 }
799
800 pub(crate) fn index(&self) -> u32 {
802 self.preceding_siblings().count() as u32
803 }
804
805 pub(crate) fn has_parent(&self) -> bool {
807 self.parent_node.get().is_some()
808 }
809
810 pub(crate) fn children_count(&self) -> u32 {
811 self.children_count.get()
812 }
813
814 pub(crate) fn ranges(&self) -> RefMut<'_, WeakRangeVec> {
815 RefMut::map(self.ensure_rare_data(), |rare_data| &mut rare_data.ranges)
816 }
817
818 pub(crate) fn ranges_is_empty(&self) -> bool {
819 self.rare_data()
820 .as_ref()
821 .is_none_or(|data| data.ranges.is_empty())
822 }
823
824 #[inline]
825 pub(crate) fn is_doctype(&self) -> bool {
826 self.type_id() == NodeTypeId::DocumentType
827 }
828
829 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
830 self.flags.get().contains(flag)
831 }
832
833 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
834 let mut flags = self.flags.get();
835
836 if value {
837 flags.insert(flag);
838 } else {
839 flags.remove(flag);
840 }
841
842 self.flags.set(flags);
843 }
844
845 pub(crate) fn note_dirty_descendants(&self) {
847 self.owner_doc().note_node_with_dirty_descendants(self);
848 }
849
850 pub(crate) fn has_dirty_descendants(&self) -> bool {
851 self.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)
852 }
853
854 pub(crate) fn rev_version(&self) {
855 let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
860 let version = cmp::max(
861 self.inclusive_descendants_version(),
862 doc.inclusive_descendants_version(),
863 ) + 1;
864
865 let mut node = &MutNullableDom::new(Some(self));
868 while let Some(p) = node.if_is_some(|p| {
869 p.inclusive_descendants_version.set(version);
870 &p.parent_node
871 }) {
872 node = p
873 }
874 doc.inclusive_descendants_version.set(version);
875 }
876
877 pub(crate) fn dirty(&self, damage: NodeDamage) {
878 self.rev_version();
879 if !self.is_connected() {
880 return;
881 }
882
883 match self.type_id() {
884 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..)) => {
885 *self.layout_data.borrow_mut() = None;
888
889 self.parent_node
893 .get()
894 .unwrap()
895 .dirty(NodeDamage::ContentOrHeritage)
896 },
897 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(damage),
898 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
899 .downcast::<ShadowRoot>()
900 .unwrap()
901 .Host()
902 .upcast::<Element>()
903 .restyle(damage),
904 _ => {},
905 };
906 }
907
908 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
910 self.inclusive_descendants_version.get()
911 }
912
913 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
915 TreeIterator::new(self, shadow_including)
916 }
917
918 pub(crate) fn traverse_preorder_non_rooting<'a, 'b>(
920 &'a self,
921 no_gc: &'b NoGC,
922 shadow_including: ShadowIncluding,
923 ) -> UnrootedTreeIterator<'a, 'b>
924 where
925 'b: 'a,
926 {
927 UnrootedTreeIterator::new(self, shadow_including, no_gc)
928 }
929
930 pub(crate) fn inclusively_following_siblings(
931 &self,
932 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
933 SimpleNodeIterator {
934 current: Some(DomRoot::from_ref(self)),
935 next_node: |n| n.GetNextSibling(),
936 }
937 }
938
939 pub(crate) fn inclusively_following_siblings_unrooted<'b>(
940 &self,
941 no_gc: &'b NoGC,
942 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
943 UnrootedSimpleNodeIterator {
944 current: Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
945 next_node: |n, no_gc| n.get_next_sibling_unrooted(no_gc),
946 no_gc,
947 phantom: PhantomData,
948 }
949 }
950
951 pub(crate) fn inclusively_preceding_siblings(
952 &self,
953 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
954 SimpleNodeIterator {
955 current: Some(DomRoot::from_ref(self)),
956 next_node: |n| n.GetPreviousSibling(),
957 }
958 }
959
960 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
961 &self,
962 no_gc: &'b NoGC,
963 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
964 UnrootedSimpleNodeIterator {
965 current: Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
966 next_node: |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
967 no_gc,
968 phantom: PhantomData,
969 }
970 }
971
972 pub(crate) fn common_ancestor(
973 &self,
974 other: &Node,
975 shadow_including: ShadowIncluding,
976 ) -> Option<DomRoot<Node>> {
977 self.inclusive_ancestors(shadow_including).find(|ancestor| {
978 other
979 .inclusive_ancestors(shadow_including)
980 .any(|node| node == *ancestor)
981 })
982 }
983
984 pub(crate) fn common_ancestor_in_flat_tree(&self, other: &Node) -> Option<DomRoot<Node>> {
985 self.inclusive_ancestors_in_flat_tree().find(|ancestor| {
986 other
987 .inclusive_ancestors_in_flat_tree()
988 .any(|node| node == *ancestor)
989 })
990 }
991
992 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
994 self == child || self.is_ancestor_of(child)
996 }
997
998 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
1000 let mut current = &possible_descendant.parent_node;
1002 let mut done = false;
1003
1004 while let Some(node) = current.if_is_some(|node| {
1005 done = node == self;
1006 &node.parent_node
1007 }) {
1008 if done {
1009 break;
1010 }
1011 current = node
1012 }
1013 done
1014 }
1015
1016 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
1018 self.is_inclusive_ancestor_of(child) ||
1021 child
1022 .GetRootNode(&GetRootNodeOptions::empty())
1023 .downcast::<DocumentFragment>()
1024 .and_then(|fragment| fragment.host())
1025 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1026 }
1027
1028 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1030 node.inclusive_ancestors(ShadowIncluding::Yes)
1031 .any(|ancestor| &*ancestor == self)
1032 }
1033
1034 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1035 SimpleNodeIterator {
1036 current: self.GetNextSibling(),
1037 next_node: |n| n.GetNextSibling(),
1038 }
1039 }
1040
1041 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1042 SimpleNodeIterator {
1043 current: self.GetPreviousSibling(),
1044 next_node: |n| n.GetPreviousSibling(),
1045 }
1046 }
1047
1048 pub(crate) fn following_nodes(&self, root: &Node) -> FollowingNodeIterator {
1049 FollowingNodeIterator {
1050 current: Some(DomRoot::from_ref(self)),
1051 root: DomRoot::from_ref(root),
1052 }
1053 }
1054
1055 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1056 PrecedingNodeIterator {
1057 current: Some(DomRoot::from_ref(self)),
1058 root: DomRoot::from_ref(root),
1059 }
1060 }
1061
1062 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1065 SimpleNodeIterator {
1066 current: self.GetLastChild(),
1067 next_node: |n| n.GetLastChild(),
1068 }
1069 }
1070
1071 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1072 child
1073 .parent_node
1074 .get()
1075 .is_some_and(|parent| &*parent == self)
1076 }
1077
1078 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1079 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1080 }
1081
1082 pub(crate) fn containing_block_node_without_reflow(&self) -> Option<DomRoot<Node>> {
1084 self.owner_window()
1085 .containing_block_node_query_without_reflow(self)
1086 }
1087
1088 pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1089 self.owner_window().padding_query_without_reflow(self)
1090 }
1091
1092 pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1093 self.owner_window()
1094 .box_area_query(self, BoxAreaType::Content, false)
1095 }
1096
1097 pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1098 self.owner_window()
1099 .box_area_query(self, BoxAreaType::Border, false)
1100 }
1101
1102 pub(crate) fn border_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1103 self.owner_window()
1104 .box_area_query_without_reflow(self, BoxAreaType::Border, false)
1105 }
1106
1107 pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1108 self.owner_window()
1109 .box_area_query(self, BoxAreaType::Padding, false)
1110 }
1111
1112 pub(crate) fn padding_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1113 self.owner_window()
1114 .box_area_query_without_reflow(self, BoxAreaType::Padding, false)
1115 }
1116
1117 pub(crate) fn border_boxes(&self) -> CSSPixelRectVec {
1118 self.owner_window()
1119 .box_areas_query(self, BoxAreaType::Border)
1120 }
1121
1122 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1123 self.owner_window().client_rect_query(self)
1124 }
1125
1126 pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1129 let document = self.owner_doc();
1131
1132 if !document.is_active() {
1134 return Rect::zero();
1135 }
1136
1137 let window = document.window();
1140 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1141
1142 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1143 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1144 let is_body_element = self
1145 .downcast::<HTMLElement>()
1146 .is_some_and(|e| e.is_body_element());
1147
1148 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1154 let viewport_scrolling_area = window.scrolling_area_query(None);
1155 return Rect::new(
1156 viewport_scrolling_area.origin,
1157 viewport_scrolling_area.size.max(viewport),
1158 );
1159 }
1160
1161 window.scrolling_area_query(Some(self))
1165 }
1166
1167 pub(crate) fn effective_overflow(&self) -> Option<AxesOverflow> {
1168 self.owner_window().query_effective_overflow(self)
1169 }
1170
1171 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1172 self.owner_window()
1173 .query_effective_overflow_without_reflow(self)
1174 }
1175
1176 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1178 let parent = &self.parent_node;
1180
1181 let parent = match parent.get() {
1183 None => return Ok(()),
1184 Some(parent) => parent,
1185 };
1186
1187 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1189
1190 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1192
1193 let viable_previous_sibling = match viable_previous_sibling {
1195 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1196 None => parent.first_child.get(),
1197 };
1198
1199 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1201
1202 Ok(())
1203 }
1204
1205 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1207 let parent = &self.parent_node;
1209
1210 let parent = match parent.get() {
1212 None => return Ok(()),
1213 Some(parent) => parent,
1214 };
1215
1216 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1218
1219 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1221
1222 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1224
1225 Ok(())
1226 }
1227
1228 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1230 let Some(parent) = self.GetParentNode() else {
1232 return Ok(());
1234 };
1235
1236 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1238
1239 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1241
1242 if self.parent_node == Some(&*parent) {
1243 parent.ReplaceChild(cx, &node, self)?;
1245 } else {
1246 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1248 }
1249 Ok(())
1250 }
1251
1252 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1254 let doc = self.owner_doc();
1256 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1257 let first_child = self.first_child.get();
1259 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1260 }
1261
1262 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1264 let doc = self.owner_doc();
1266 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1267 self.AppendChild(cx, &node).map(|_| ())
1269 }
1270
1271 pub(crate) fn replace_children(
1273 &self,
1274 cx: &mut JSContext,
1275 nodes: Vec<NodeOrString>,
1276 ) -> ErrorResult {
1277 let doc = self.owner_doc();
1280 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1281
1282 Node::ensure_pre_insertion_validity(cx.no_gc(), &node, self, None)?;
1284
1285 Node::replace_all(cx, Some(&node), self);
1287 Ok(())
1288 }
1289
1290 pub(crate) fn move_before(
1292 &self,
1293 cx: &mut JSContext,
1294 node: &Node,
1295 child: Option<&Node>,
1296 ) -> ErrorResult {
1297 let reference_child_root;
1300 let reference_child = match child {
1301 Some(child) if child == node => {
1302 reference_child_root = node.GetNextSibling();
1303 reference_child_root.as_deref()
1304 },
1305 _ => child,
1306 };
1307
1308 Node::move_fn(cx, node, self, reference_child)
1310 }
1311
1312 fn move_fn(
1314 cx: &mut JSContext,
1315 node: &Node,
1316 new_parent: &Node,
1317 child: Option<&Node>,
1318 ) -> ErrorResult {
1319 let mut options = GetRootNodeOptions::empty();
1324 options.composed = true;
1325 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1326 return Err(Error::HierarchyRequest(None));
1327 }
1328
1329 if node.is_inclusive_ancestor_of(new_parent) {
1332 return Err(Error::HierarchyRequest(None));
1333 }
1334
1335 if let Some(child) = child &&
1338 !new_parent.is_parent_of(child)
1339 {
1340 return Err(Error::NotFound(None));
1341 }
1342
1343 match node.type_id() {
1348 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1349 if new_parent.is::<Document>() {
1350 return Err(Error::HierarchyRequest(None));
1351 }
1352 },
1353 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1354 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1355 NodeTypeId::Element(_) => (),
1356 NodeTypeId::DocumentFragment(_) |
1357 NodeTypeId::DocumentType |
1358 NodeTypeId::Document(_) |
1359 NodeTypeId::Attr => {
1360 return Err(Error::HierarchyRequest(None));
1361 },
1362 }
1363
1364 if new_parent.is::<Document>() && node.is::<Element>() {
1368 if new_parent.child_elements().next().is_some() {
1370 return Err(Error::HierarchyRequest(None));
1371 }
1372
1373 if child.is_some_and(|child| {
1376 child
1377 .inclusively_following_siblings_unrooted(cx.no_gc())
1378 .any(|child| child.is_doctype())
1379 }) {
1380 return Err(Error::HierarchyRequest(None));
1381 }
1382 }
1383
1384 let old_parent = node
1387 .parent_node
1388 .get()
1389 .expect("old_parent should always be initialized");
1390
1391 let cached_index = Node::live_range_pre_remove_steps(node, &old_parent);
1393
1394 let old_previous_sibling = node.prev_sibling.get();
1399
1400 let old_next_sibling = node.next_sibling.get();
1402
1403 let prev_sibling = node.GetPreviousSibling();
1404 match prev_sibling {
1405 None => {
1406 old_parent
1407 .first_child
1408 .set(node.next_sibling.get().as_deref());
1409 },
1410 Some(ref prev_sibling) => {
1411 prev_sibling
1412 .next_sibling
1413 .set(node.next_sibling.get().as_deref());
1414 },
1415 }
1416 let next_sibling = node.GetNextSibling();
1417 match next_sibling {
1418 None => {
1419 old_parent
1420 .last_child
1421 .set(node.prev_sibling.get().as_deref());
1422 },
1423 Some(ref next_sibling) => {
1424 next_sibling
1425 .prev_sibling
1426 .set(node.prev_sibling.get().as_deref());
1427 },
1428 }
1429
1430 let mut context = MoveContext::new(
1431 Some(&old_parent),
1432 prev_sibling.as_deref(),
1433 next_sibling.as_deref(),
1434 cached_index,
1435 );
1436
1437 old_parent.move_child(node);
1439
1440 if let Some(slot) = node.assigned_slot() {
1442 slot.assign_slottables(cx.no_gc());
1443 }
1444
1445 if old_parent.is_in_a_shadow_tree() &&
1448 let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() &&
1449 !slot_element.has_assigned_nodes()
1450 {
1451 slot_element.signal_a_slot_change();
1452 }
1453
1454 let has_slot_descendant = node
1456 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
1457 .any(|element| element.is::<HTMLSlotElement>());
1458 if has_slot_descendant {
1459 old_parent
1461 .GetRootNode(&GetRootNodeOptions::empty())
1462 .assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Skip);
1463
1464 node.assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Skip);
1466 }
1467
1468 if let Some(child) = child {
1470 new_parent
1475 .ranges()
1476 .increase_above(new_parent, child.index(), 1)
1477 }
1478
1479 let new_previous_sibling = child.map_or_else(
1482 || new_parent.last_child.get(),
1483 |child| child.prev_sibling.get(),
1484 );
1485
1486 new_parent.add_child(cx, node, child);
1489
1490 if let Some(shadow_root) = new_parent
1493 .downcast::<Element>()
1494 .and_then(Element::shadow_root) &&
1495 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1496 (node.is::<Element>() || node.is::<Text>())
1497 {
1498 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1499 slottable.assign_a_slot(cx.no_gc());
1500 }
1501
1502 if new_parent.is_in_a_shadow_tree() &&
1505 let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() &&
1506 !slot_element.has_assigned_nodes()
1507 {
1508 slot_element.signal_a_slot_change();
1509 }
1510
1511 node.GetRootNode(&GetRootNodeOptions::empty())
1513 .assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Skip);
1514
1515 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1518 if descendant.deref() == node {
1522 vtable_for(&descendant).moving_steps(cx, &context);
1523 } else {
1524 context.old_parent = None;
1525 vtable_for(&descendant).moving_steps(cx, &context);
1526 }
1527
1528 if let Some(descendant) = descendant.downcast::<Element>() &&
1530 descendant.is_custom() &&
1531 new_parent.is_connected()
1532 {
1533 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
1536 custom_element_reaction_stack.enqueue_callback_reaction(
1537 descendant,
1538 CallbackReaction::ConnectedMove,
1539 None,
1540 );
1541 }
1542 }
1543
1544 let moved = [node];
1547 let mutation = LazyCell::new(|| Mutation::ChildList {
1548 added: None,
1549 removed: Some(&moved),
1550 prev: old_previous_sibling.as_deref(),
1551 next: old_next_sibling.as_deref(),
1552 });
1553 MutationObserver::queue_a_mutation_record(&old_parent, mutation);
1554
1555 let mutation = LazyCell::new(|| Mutation::ChildList {
1558 added: Some(&moved),
1559 removed: None,
1560 prev: new_previous_sibling.as_deref(),
1561 next: child,
1562 });
1563 MutationObserver::queue_a_mutation_record(new_parent, mutation);
1564
1565 Ok(())
1566 }
1567
1568 #[allow(unsafe_code)]
1570 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1571 pub(crate) fn query_selector(
1572 &self,
1573 selectors: DOMString,
1574 ) -> Fallible<Option<DomRoot<Element>>> {
1575 let document_url = self.owner_document().url().get_arc();
1578
1579 let traced_node = Dom::from_ref(self);
1581
1582 let first_matching_element = with_layout_state(|| {
1583 let layout_node = unsafe { traced_node.to_layout() };
1584 ServoDangerousStyleNode::from(layout_node)
1585 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1586 })?;
1587
1588 Ok(first_matching_element.map(ServoDangerousStyleElement::rooted))
1589 }
1590
1591 #[allow(unsafe_code)]
1593 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1594 pub(crate) fn query_selector_all(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
1595 let document_url = self.owner_document().url().get_arc();
1598
1599 let traced_node = Dom::from_ref(self);
1601 let matching_elements = with_layout_state(|| {
1602 let layout_node = unsafe { traced_node.to_layout() };
1603 ServoDangerousStyleNode::from(layout_node)
1604 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1605 })?;
1606 let iter = matching_elements
1607 .into_iter()
1608 .map(ServoDangerousStyleElement::rooted)
1609 .map(DomRoot::upcast::<Node>);
1610
1611 Ok(NodeList::new_simple_list(
1614 &self.owner_window(),
1615 iter,
1616 CanGc::deprecated_note(),
1617 ))
1618 }
1619
1620 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1621 SimpleNodeIterator {
1622 current: self.GetParentNode(),
1623 next_node: |n| n.GetParentNode(),
1624 }
1625 }
1626
1627 pub(crate) fn inclusive_ancestors(
1629 &self,
1630 shadow_including: ShadowIncluding,
1631 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1632 SimpleNodeIterator {
1633 current: Some(DomRoot::from_ref(self)),
1634 next_node: move |n| {
1635 if shadow_including == ShadowIncluding::Yes &&
1636 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1637 {
1638 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1639 }
1640 n.GetParentNode()
1641 },
1642 }
1643 }
1644
1645 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1646 self.owner_doc.get().unwrap()
1647 }
1648
1649 pub(crate) fn set_owner_doc(&self, document: &Document) {
1650 self.owner_doc.set(Some(document));
1651 }
1652
1653 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1654 self.rare_data()
1655 .as_ref()?
1656 .containing_shadow_root
1657 .as_ref()
1658 .map(|sr| DomRoot::from_ref(&**sr))
1659 }
1660
1661 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1662 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1663 }
1664
1665 pub(crate) fn is_in_html_doc(&self) -> bool {
1666 self.owner_doc().is_html_document()
1667 }
1668
1669 pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1670 self.is_connected() && self.owner_doc().browsing_context().is_some()
1671 }
1672
1673 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1674 SimpleNodeIterator {
1675 current: self.GetFirstChild(),
1676 next_node: |n| n.GetNextSibling(),
1677 }
1678 }
1679
1680 pub(crate) fn children_unrooted<'a>(
1681 &self,
1682 no_gc: &'a NoGC,
1683 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1684 UnrootedSimpleNodeIterator {
1685 current: self.get_first_child_unrooted(no_gc),
1686 next_node: |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1687 no_gc,
1688 phantom: PhantomData,
1689 }
1690 }
1691
1692 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1693 SimpleNodeIterator {
1694 current: self.GetLastChild(),
1695 next_node: |n| n.GetPreviousSibling(),
1696 }
1697 }
1698
1699 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1701 self.children()
1702 .filter_map(DomRoot::downcast as fn(_) -> _)
1703 .peekable()
1704 }
1705
1706 pub(crate) fn child_elements_unrooted<'a>(
1707 &self,
1708 no_gc: &'a NoGC,
1709 ) -> impl Iterator<Item = UnrootedDom<'a, Element>> + use<'a> {
1710 self.children_unrooted(no_gc)
1711 .filter_map(UnrootedDom::downcast)
1712 .peekable()
1713 }
1714
1715 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1716 if let Some(ref parent) = self.GetParentNode() {
1717 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1718 }
1719 }
1720
1721 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1723 Ref::filter_map(self.rare_data(), |rare_data| {
1724 rare_data
1725 .as_ref()
1726 .and_then(|rare_data| rare_data.unique_id.as_ref())
1727 })
1728 .ok()
1729 .map(|unique_id| unique_id.borrow().simple().to_string())
1730 }
1731
1732 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1733 let mut rare_data = self.ensure_rare_data();
1734
1735 if rare_data.unique_id.is_none() {
1736 let node_id = UniqueId::new();
1737 ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string());
1738 rare_data.unique_id = Some(node_id);
1739 }
1740 rare_data
1741 .unique_id
1742 .as_ref()
1743 .unwrap()
1744 .borrow()
1745 .simple()
1746 .to_string()
1747 }
1748
1749 pub(crate) fn summarize(&self, cx: &mut JSContext) -> NodeInfo {
1750 let USVString(base_uri) = self.BaseURI();
1751 let node_type = self.NodeType();
1752 let pipeline = self.owner_window().pipeline_id();
1753
1754 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1755 let shadow_root_mode = maybe_shadow_root
1756 .map(ShadowRoot::Mode)
1757 .map(ShadowRootMode::convert);
1758 let host = maybe_shadow_root
1759 .map(ShadowRoot::Host)
1760 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1761 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1762 let Some(root) = potential_host.shadow_root() else {
1763 return false;
1764 };
1765 !root.is_user_agent_widget() || pref!(inspector_show_servo_internal_shadow_roots)
1766 });
1767
1768 let num_children = if is_shadow_host {
1769 self.ChildNodes(cx).Length() as usize + 1
1771 } else {
1772 self.ChildNodes(cx).Length() as usize
1773 };
1774
1775 let window = self.owner_window();
1776 let element = self.downcast::<Element>();
1777 let display = element
1778 .map(|elem| window.GetComputedStyle(elem, None))
1779 .map(|style| style.Display().into());
1780
1781 let is_displayed =
1787 element.is_none_or(|element| !element.is_display_none()) || self.is::<DocumentType>();
1788 let attrs = element.map(Element::summarize).unwrap_or_default();
1789
1790 NodeInfo {
1791 unique_id: self.unique_id(pipeline),
1792 host,
1793 base_uri,
1794 parent: self
1795 .GetParentNode()
1796 .map_or("".to_owned(), |node| node.unique_id(pipeline)),
1797 node_type,
1798 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1799 node_name: String::from(self.NodeName()),
1800 node_value: self.GetNodeValue().map(|v| v.into()),
1801 num_children,
1802 attrs,
1803 is_shadow_host,
1804 shadow_root_mode,
1805 display,
1806 is_displayed,
1807 doctype_name: self
1808 .downcast::<DocumentType>()
1809 .map(DocumentType::name)
1810 .cloned()
1811 .map(String::from),
1812 doctype_public_identifier: self
1813 .downcast::<DocumentType>()
1814 .map(DocumentType::public_id)
1815 .cloned()
1816 .map(String::from),
1817 doctype_system_identifier: self
1818 .downcast::<DocumentType>()
1819 .map(DocumentType::system_id)
1820 .cloned()
1821 .map(String::from),
1822 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1823 }
1824 }
1825
1826 pub(crate) fn insert_cell_or_row<F, G, I>(
1828 &self,
1829 cx: &mut JSContext,
1830 index: i32,
1831 get_items: F,
1832 new_child: G,
1833 ) -> Fallible<DomRoot<HTMLElement>>
1834 where
1835 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1836 G: Fn(&mut JSContext) -> DomRoot<I>,
1837 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1838 {
1839 if index < -1 {
1840 return Err(Error::IndexSize(None));
1841 }
1842
1843 let tr = new_child(cx);
1844
1845 {
1846 let tr_node = tr.upcast::<Node>();
1847 if index == -1 {
1848 self.InsertBefore(cx, tr_node, None)?;
1849 } else {
1850 let items = get_items(cx);
1851 let node = match items
1852 .elements_iter()
1853 .map(DomRoot::upcast::<Node>)
1854 .map(Some)
1855 .chain(iter::once(None))
1856 .nth(index as usize)
1857 {
1858 None => return Err(Error::IndexSize(None)),
1859 Some(node) => node,
1860 };
1861 self.InsertBefore(cx, tr_node, node.as_deref())?;
1862 }
1863 }
1864
1865 Ok(DomRoot::upcast::<HTMLElement>(tr))
1866 }
1867
1868 pub(crate) fn delete_cell_or_row<F, G>(
1870 &self,
1871 cx: &mut JSContext,
1872 index: i32,
1873 get_items: F,
1874 is_delete_type: G,
1875 ) -> ErrorResult
1876 where
1877 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1878 G: Fn(&Element) -> bool,
1879 {
1880 let element = match index {
1881 index if index < -1 => return Err(Error::IndexSize(None)),
1882 -1 => {
1883 let last_child = self.upcast::<Node>().GetLastChild();
1884 match last_child.and_then(|node| {
1885 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
1886 .filter_map(UnrootedDom::downcast::<Element>)
1887 .find(|elem| is_delete_type(elem))
1888 .map(|elem| elem.as_rooted())
1889 }) {
1890 Some(element) => element,
1891 None => return Ok(()),
1892 }
1893 },
1894 index => match get_items(cx).Item(index as u32) {
1895 Some(element) => element,
1896 None => return Err(Error::IndexSize(None)),
1897 },
1898 };
1899
1900 element.upcast::<Node>().remove_self(cx);
1901 Ok(())
1902 }
1903
1904 pub(crate) fn get_stylesheet(&self) -> Option<ServoArc<Stylesheet>> {
1905 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1906 node.get_stylesheet()
1907 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1908 node.get_stylesheet()
1909 } else {
1910 None
1911 }
1912 }
1913
1914 pub(crate) fn get_cssom_stylesheet(&self) -> Option<DomRoot<CSSStyleSheet>> {
1915 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1916 node.get_cssom_stylesheet()
1917 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1918 node.get_cssom_stylesheet(CanGc::deprecated_note())
1919 } else {
1920 None
1921 }
1922 }
1923
1924 pub(crate) fn get_lang(&self, cx: &mut JSContext) -> Option<String> {
1926 self.inclusive_ancestors(ShadowIncluding::Yes)
1927 .find_map(|node| {
1928 node.downcast::<Element>().and_then(|el| {
1929 el.get_attribute_with_namespace(cx, &ns!(xml), &local_name!("lang"))
1930 .or_else(|| el.get_attribute(&local_name!("lang")))
1931 .map(|attr| String::from(attr.Value()))
1932 })
1933 })
1936 }
1937
1938 pub(crate) fn assign_slottables_for_a_tree(
1940 &self,
1941 no_gc: &NoGC,
1942 force: ForceSlottableNodeReconciliation,
1943 ) {
1944 let is_shadow_root_with_slots = self
1951 .downcast::<ShadowRoot>()
1952 .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
1953 if !is_shadow_root_with_slots &&
1954 !self.is::<HTMLSlotElement>() &&
1955 matches!(force, ForceSlottableNodeReconciliation::Skip)
1956 {
1957 return;
1958 }
1959
1960 for node in self.traverse_preorder_non_rooting(no_gc, ShadowIncluding::No) {
1963 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
1964 slot.assign_slottables(no_gc);
1965 }
1966 }
1967 }
1968
1969 pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
1970 let assigned_slot = self
1971 .rare_data
1972 .borrow()
1973 .as_ref()?
1974 .slottable_data
1975 .assigned_slot
1976 .as_ref()?
1977 .as_rooted();
1978 Some(assigned_slot)
1979 }
1980
1981 pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
1982 self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
1983 }
1984
1985 pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
1986 let manually_assigned_slot = self
1987 .rare_data
1988 .borrow()
1989 .as_ref()?
1990 .slottable_data
1991 .manual_slot_assignment
1992 .as_ref()?
1993 .as_rooted();
1994 Some(manually_assigned_slot)
1995 }
1996
1997 pub(crate) fn set_manual_slot_assignment(
1998 &self,
1999 manually_assigned_slot: Option<&HTMLSlotElement>,
2000 ) {
2001 self.ensure_rare_data()
2002 .slottable_data
2003 .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
2004 }
2005
2006 pub(crate) fn parent_in_flat_tree(&self) -> Option<DomRoot<Node>> {
2012 if let Some(assigned_slot) = self.assigned_slot() {
2013 return Some(DomRoot::upcast(assigned_slot));
2014 }
2015
2016 let parent_or_none = self.GetParentNode();
2017 if let Some(parent) = parent_or_none.as_deref() &&
2018 let Some(shadow_root) = parent.downcast::<ShadowRoot>()
2019 {
2020 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
2021 }
2022
2023 parent_or_none
2024 }
2025
2026 pub(crate) fn inclusive_ancestors_in_flat_tree(
2027 &self,
2028 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
2029 SimpleNodeIterator {
2030 current: Some(DomRoot::from_ref(self)),
2031 next_node: move |n| n.parent_in_flat_tree(),
2032 }
2033 }
2034
2035 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2037 debug_assert!(self.is_in_ua_widget());
2039 debug_assert!(pseudo_element.is_element_backed());
2040 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2041 }
2042
2043 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2044 self.rare_data
2045 .borrow()
2046 .as_ref()
2047 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2048 }
2049
2050 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2052 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2056 if ancestor.is_editing_host() {
2057 return Some(ancestor);
2058 }
2059 if ancestor
2060 .downcast::<HTMLElement>()
2061 .is_some_and(|el| el.ContentEditable().str() == "false")
2062 {
2063 return None;
2064 }
2065 }
2066 None
2067 }
2068
2069 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2070 self.editing_host_of().is_some()
2071 }
2072
2073 pub(crate) fn is_editing_host(&self) -> bool {
2075 self.downcast::<HTMLElement>()
2076 .is_some_and(HTMLElement::is_editing_host)
2077 }
2078
2079 pub(crate) fn is_editable(&self) -> bool {
2081 if self.is_editing_host() {
2083 return false;
2084 }
2085 let html_element = self.downcast::<HTMLElement>();
2087 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2088 return false;
2089 }
2090 let Some(parent) = self.GetParentNode() else {
2092 return false;
2093 };
2094 if !parent.is_editable_or_editing_host() {
2095 return false;
2096 }
2097 html_element.is_some() ||
2099 (!self.is::<Element>() && parent.downcast::<HTMLElement>().is_some())
2100 }
2101}
2102
2103fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2105where
2106 I: Iterator<Item = DomRoot<Node>>,
2107{
2108 nodes.find(|node| {
2109 not_in.iter().all(|n| match *n {
2110 NodeOrString::Node(ref n) => n != node,
2111 _ => true,
2112 })
2113 })
2114}
2115
2116#[expect(unsafe_code)]
2119pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2120 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2121 DomRoot::from_ref(node)
2122}
2123
2124impl<'dom> LayoutDom<'dom, Node> {
2125 #[inline]
2126 #[expect(unsafe_code)]
2127 pub(crate) fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
2128 unsafe { self.unsafe_get().parent_node.get_inner_as_layout() }
2129 }
2130
2131 #[inline]
2132 pub(crate) fn type_id_for_layout(self) -> NodeTypeId {
2133 self.unsafe_get().type_id()
2134 }
2135
2136 #[inline]
2137 pub(crate) fn is_element_for_layout(&self) -> bool {
2138 (*self).is::<Element>()
2139 }
2140
2141 pub(crate) fn is_text_node_for_layout(&self) -> bool {
2142 matches!(
2143 self.type_id_for_layout(),
2144 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..))
2145 )
2146 }
2147
2148 #[inline]
2149 pub(crate) fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
2150 let parent = self.parent_node_ref();
2151 if let Some(parent) = parent &&
2152 let Some(shadow_root) = parent.downcast::<ShadowRoot>()
2153 {
2154 return Some(shadow_root.get_host_for_layout().upcast());
2155 }
2156 parent
2157 }
2158
2159 #[inline]
2160 pub(crate) fn traversal_parent(self) -> Option<LayoutDom<'dom, Element>> {
2161 if let Some(assigned_slot) = self.assigned_slot_for_layout() {
2162 return Some(assigned_slot.upcast());
2163 }
2164 let parent = self.parent_node_ref()?;
2165 if let Some(shadow) = parent.downcast::<ShadowRoot>() {
2166 return Some(shadow.get_host_for_layout());
2167 };
2168 parent.downcast()
2169 }
2170
2171 #[inline]
2172 #[expect(unsafe_code)]
2173 pub(crate) fn first_child_ref(self) -> Option<LayoutDom<'dom, Node>> {
2174 unsafe { self.unsafe_get().first_child.get_inner_as_layout() }
2175 }
2176
2177 #[inline]
2178 #[expect(unsafe_code)]
2179 pub(crate) fn last_child_ref(self) -> Option<LayoutDom<'dom, Node>> {
2180 unsafe { self.unsafe_get().last_child.get_inner_as_layout() }
2181 }
2182
2183 #[inline]
2184 #[expect(unsafe_code)]
2185 pub(crate) fn prev_sibling_ref(self) -> Option<LayoutDom<'dom, Node>> {
2186 unsafe { self.unsafe_get().prev_sibling.get_inner_as_layout() }
2187 }
2188
2189 #[inline]
2190 #[expect(unsafe_code)]
2191 pub(crate) fn next_sibling_ref(self) -> Option<LayoutDom<'dom, Node>> {
2192 unsafe { self.unsafe_get().next_sibling.get_inner_as_layout() }
2193 }
2194
2195 #[inline]
2196 #[expect(unsafe_code)]
2197 pub(crate) fn owner_doc_for_layout(self) -> LayoutDom<'dom, Document> {
2198 unsafe { self.unsafe_get().owner_doc.get_inner_as_layout().unwrap() }
2199 }
2200
2201 #[inline]
2202 #[expect(unsafe_code)]
2203 pub(crate) fn containing_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
2204 unsafe {
2205 self.unsafe_get()
2206 .rare_data
2207 .borrow_for_layout()
2208 .as_ref()?
2209 .containing_shadow_root
2210 .as_ref()
2211 .map(|sr| sr.to_layout())
2212 }
2213 }
2214
2215 #[inline]
2216 #[expect(unsafe_code)]
2217 pub(crate) fn assigned_slot_for_layout(self) -> Option<LayoutDom<'dom, HTMLSlotElement>> {
2218 unsafe {
2219 self.unsafe_get()
2220 .rare_data
2221 .borrow_for_layout()
2222 .as_ref()?
2223 .slottable_data
2224 .assigned_slot
2225 .as_ref()
2226 .map(|assigned_slot| assigned_slot.to_layout())
2227 }
2228 }
2229
2230 #[inline]
2235 #[expect(unsafe_code)]
2236 pub(crate) unsafe fn get_flag(self, flag: NodeFlags) -> bool {
2237 (self.unsafe_get()).flags.get().contains(flag)
2238 }
2239
2240 #[inline]
2241 #[expect(unsafe_code)]
2242 pub(crate) unsafe fn set_flag(self, flag: NodeFlags, value: bool) {
2243 let this = self.unsafe_get();
2244 let mut flags = (this).flags.get();
2245
2246 if value {
2247 flags.insert(flag);
2248 } else {
2249 flags.remove(flag);
2250 }
2251
2252 (this).flags.set(flags);
2253 }
2254
2255 #[inline]
2256 #[expect(unsafe_code)]
2257 pub(crate) fn layout_data(self) -> Option<&'dom GenericLayoutData> {
2258 unsafe { self.unsafe_get().layout_data.borrow_for_layout().as_deref() }
2259 }
2260
2261 #[inline]
2269 #[expect(unsafe_code)]
2270 pub(crate) unsafe fn initialize_layout_data(self, new_data: Box<GenericLayoutData>) {
2271 let data = unsafe { self.unsafe_get().layout_data.borrow_mut_for_layout() };
2272 debug_assert!(data.is_none());
2273 *data = Some(new_data);
2274 }
2275
2276 #[inline]
2284 #[expect(unsafe_code)]
2285 pub(crate) unsafe fn clear_layout_data(self) {
2286 unsafe {
2287 self.unsafe_get().layout_data.borrow_mut_for_layout().take();
2288 }
2289 }
2290
2291 pub(crate) fn is_single_line_text_inner_editor(&self) -> bool {
2294 matches!(
2295 self.implemented_pseudo_element(),
2296 Some(PseudoElement::ServoTextControlInnerEditor)
2297 )
2298 }
2299
2300 pub(crate) fn is_text_container_of_single_line_input(&self) -> bool {
2303 let is_single_line_text_inner_placeholder = matches!(
2304 self.implemented_pseudo_element(),
2305 Some(PseudoElement::Placeholder)
2306 );
2307 debug_assert!(
2309 !is_single_line_text_inner_placeholder ||
2310 self.containing_shadow_root_for_layout()
2311 .map(|root| root.get_host_for_layout())
2312 .map(|host| host.downcast::<HTMLInputElement>())
2313 .is_some()
2314 );
2315
2316 self.is_single_line_text_inner_editor() || is_single_line_text_inner_placeholder
2317 }
2318
2319 pub(crate) fn text_content(self) -> Cow<'dom, str> {
2320 self.downcast::<Text>()
2321 .expect("Called LayoutDom::text_content on non-Text node!")
2322 .upcast()
2323 .data_for_layout()
2324 .into()
2325 }
2326
2327 pub(crate) fn selection(self) -> Option<SharedSelection> {
2334 if let Some(input) = self.downcast::<HTMLInputElement>() {
2335 return input.selection_for_layout();
2336 }
2337 if let Some(textarea) = self.downcast::<HTMLTextAreaElement>() {
2338 return Some(textarea.selection_for_layout());
2339 }
2340
2341 let shadow_root = self
2342 .containing_shadow_root_for_layout()?
2343 .get_host_for_layout();
2344 if let Some(input) = shadow_root.downcast::<HTMLInputElement>() {
2345 return input.selection_for_layout();
2346 }
2347 shadow_root
2348 .downcast::<HTMLTextAreaElement>()
2349 .map(|textarea| textarea.selection_for_layout())
2350 }
2351
2352 pub(crate) fn image_url(self) -> Option<ServoUrl> {
2353 self.downcast::<HTMLImageElement>()
2354 .expect("not an image!")
2355 .image_url()
2356 }
2357
2358 pub(crate) fn image_data(self) -> Option<(Option<Image>, Option<ImageMetadata>)> {
2359 self.downcast::<HTMLImageElement>().map(|e| e.image_data())
2360 }
2361
2362 pub(crate) fn image_density(self) -> Option<f64> {
2363 self.downcast::<HTMLImageElement>()
2364 .expect("not an image!")
2365 .image_density()
2366 }
2367
2368 pub(crate) fn showing_broken_image_icon(self) -> bool {
2369 self.downcast::<HTMLImageElement>()
2370 .map(|image_element| image_element.showing_broken_image_icon())
2371 .unwrap_or_default()
2372 }
2373
2374 pub(crate) fn canvas_data(self) -> Option<HTMLCanvasData> {
2375 self.downcast::<HTMLCanvasElement>()
2376 .map(|canvas| canvas.data())
2377 }
2378
2379 pub(crate) fn media_data(self) -> Option<HTMLMediaData> {
2380 self.downcast::<HTMLVideoElement>()
2381 .map(|media| media.data())
2382 }
2383
2384 pub(crate) fn svg_data(self) -> Option<SVGElementData<'dom>> {
2385 self.downcast::<SVGSVGElement>().map(|svg| svg.data())
2386 }
2387
2388 pub(crate) fn iframe_browsing_context_id(self) -> Option<BrowsingContextId> {
2389 self.downcast::<HTMLIFrameElement>()
2390 .and_then(|iframe_element| iframe_element.browsing_context_id())
2391 }
2392
2393 pub(crate) fn iframe_pipeline_id(self) -> Option<PipelineId> {
2394 self.downcast::<HTMLIFrameElement>()
2395 .and_then(|iframe_element| iframe_element.pipeline_id())
2396 }
2397
2398 #[expect(unsafe_code)]
2399 pub(crate) fn opaque(self) -> OpaqueNode {
2400 unsafe { OpaqueNode(self.get_jsobject() as usize) }
2401 }
2402
2403 #[expect(unsafe_code)]
2404 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2405 unsafe {
2406 self.unsafe_get()
2407 .rare_data
2408 .borrow_for_layout()
2409 .as_ref()
2410 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2411 }
2412 }
2413
2414 pub(crate) fn is_in_ua_widget(&self) -> bool {
2415 self.unsafe_get().is_in_ua_widget()
2416 }
2417
2418 pub(crate) fn is_root_of_user_agent_widget(&self) -> bool {
2419 self.downcast::<Element>().is_some_and(|element| {
2420 element
2421 .get_shadow_root_for_layout()
2422 .is_some_and(|shadow_root| shadow_root.is_user_agent_widget())
2423 })
2424 }
2425}
2426
2427pub(crate) struct FollowingNodeIterator {
2432 current: Option<DomRoot<Node>>,
2433 root: DomRoot<Node>,
2434}
2435
2436impl FollowingNodeIterator {
2437 pub(crate) fn next_skipping_children(&mut self) -> Option<DomRoot<Node>> {
2439 let current = self.current.take()?;
2440 self.next_skipping_children_impl(current)
2441 }
2442
2443 fn next_skipping_children_impl(&mut self, current: DomRoot<Node>) -> Option<DomRoot<Node>> {
2444 if self.root == current {
2445 self.current = None;
2446 return None;
2447 }
2448
2449 if let Some(next_sibling) = current.GetNextSibling() {
2450 self.current = Some(next_sibling);
2451 return current.GetNextSibling();
2452 }
2453
2454 for ancestor in current.inclusive_ancestors(ShadowIncluding::No) {
2455 if self.root == ancestor {
2456 break;
2457 }
2458 if let Some(next_sibling) = ancestor.GetNextSibling() {
2459 self.current = Some(next_sibling);
2460 return ancestor.GetNextSibling();
2461 }
2462 }
2463 self.current = None;
2464 None
2465 }
2466}
2467
2468impl Iterator for FollowingNodeIterator {
2469 type Item = DomRoot<Node>;
2470
2471 fn next(&mut self) -> Option<DomRoot<Node>> {
2473 let current = self.current.take()?;
2474
2475 if let Some(first_child) = current.GetFirstChild() {
2476 self.current = Some(first_child);
2477 return current.GetFirstChild();
2478 }
2479
2480 self.next_skipping_children_impl(current)
2481 }
2482}
2483
2484pub(crate) struct PrecedingNodeIterator {
2485 current: Option<DomRoot<Node>>,
2486 root: DomRoot<Node>,
2487}
2488
2489impl Iterator for PrecedingNodeIterator {
2490 type Item = DomRoot<Node>;
2491
2492 fn next(&mut self) -> Option<DomRoot<Node>> {
2494 let current = self.current.take()?;
2495
2496 self.current = if self.root == current {
2497 None
2498 } else if let Some(previous_sibling) = current.GetPreviousSibling() {
2499 if self.root == previous_sibling {
2500 None
2501 } else if let Some(last_child) = previous_sibling.descending_last_children().last() {
2502 Some(last_child)
2503 } else {
2504 Some(previous_sibling)
2505 }
2506 } else {
2507 current.GetParentNode()
2508 };
2509 self.current.clone()
2510 }
2511}
2512
2513struct SimpleNodeIterator<I>
2514where
2515 I: Fn(&Node) -> Option<DomRoot<Node>>,
2516{
2517 current: Option<DomRoot<Node>>,
2518 next_node: I,
2519}
2520
2521impl<I> Iterator for SimpleNodeIterator<I>
2522where
2523 I: Fn(&Node) -> Option<DomRoot<Node>>,
2524{
2525 type Item = DomRoot<Node>;
2526
2527 fn next(&mut self) -> Option<Self::Item> {
2528 let current = self.current.take();
2529 self.current = current.as_ref().and_then(|c| (self.next_node)(c));
2530 current
2531 }
2532}
2533
2534#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
2542pub(crate) struct UnrootedSimpleNodeIterator<'a, 'b, I>
2543where
2544 I: Fn(&Node, &'b NoGC) -> Option<UnrootedDom<'b, Node>>,
2545{
2546 current: Option<UnrootedDom<'b, Node>>,
2547 next_node: I,
2548 no_gc: &'b NoGC,
2550 phantom: PhantomData<&'a Node>,
2551}
2552
2553impl<'a, 'b, I> Iterator for UnrootedSimpleNodeIterator<'a, 'b, I>
2554where
2555 'b: 'a,
2556 I: Fn(&Node, &'b NoGC) -> Option<UnrootedDom<'b, Node>>,
2557{
2558 type Item = UnrootedDom<'b, Node>;
2559
2560 fn next(&mut self) -> Option<Self::Item> {
2561 let current = self.current.take();
2562 self.current = current
2563 .as_ref()
2564 .and_then(|c| (self.next_node)(c, self.no_gc));
2565 current
2566 }
2567}
2568
2569#[derive(Clone, Copy, PartialEq)]
2571pub(crate) enum ShadowIncluding {
2572 No,
2573 Yes,
2574}
2575
2576pub(crate) struct TreeIterator {
2577 current: Option<DomRoot<Node>>,
2578 depth: usize,
2579 shadow_including: ShadowIncluding,
2580}
2581
2582impl TreeIterator {
2583 fn new(root: &Node, shadow_including: ShadowIncluding) -> TreeIterator {
2584 TreeIterator {
2585 current: Some(DomRoot::from_ref(root)),
2586 depth: 0,
2587 shadow_including,
2588 }
2589 }
2590
2591 pub(crate) fn next_skipping_children(&mut self) -> Option<DomRoot<Node>> {
2592 let current = self.current.take()?;
2593
2594 self.next_skipping_children_impl(current)
2595 }
2596
2597 fn next_skipping_children_impl(&mut self, current: DomRoot<Node>) -> Option<DomRoot<Node>> {
2598 let iter = current.inclusive_ancestors(self.shadow_including);
2599
2600 for ancestor in iter {
2601 if self.depth == 0 {
2602 break;
2603 }
2604 if let Some(next_sibling) = ancestor.GetNextSibling() {
2605 self.current = Some(next_sibling);
2606 return Some(current);
2607 }
2608 if let Some(shadow_root) = ancestor.downcast::<ShadowRoot>() {
2609 if let Some(child) = shadow_root.Host().upcast::<Node>().GetFirstChild() {
2612 self.current = Some(child);
2613 return Some(current);
2614 }
2615 }
2616 self.depth -= 1;
2617 }
2618 debug_assert_eq!(self.depth, 0);
2619 self.current = None;
2620 Some(current)
2621 }
2622
2623 pub(crate) fn peek(&self) -> Option<&DomRoot<Node>> {
2624 self.current.as_ref()
2625 }
2626}
2627
2628impl Iterator for TreeIterator {
2629 type Item = DomRoot<Node>;
2630
2631 fn next(&mut self) -> Option<DomRoot<Node>> {
2634 let current = self.current.take()?;
2635
2636 if let Some(element) = current.downcast::<Element>() &&
2638 let Some(shadow_root) = element.shadow_root() &&
2639 self.shadow_including == ShadowIncluding::Yes
2640 {
2641 self.current = Some(DomRoot::from_ref(shadow_root.upcast::<Node>()));
2642 self.depth += 1;
2643 return Some(current);
2644 }
2645
2646 if let Some(first_child) = current.GetFirstChild() {
2647 self.current = Some(first_child);
2648 self.depth += 1;
2649 return Some(current);
2650 };
2651
2652 self.next_skipping_children_impl(current)
2653 }
2654}
2655
2656#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
2664pub(crate) struct UnrootedTreeIterator<'a, 'b> {
2665 current: Option<UnrootedDom<'b, Node>>,
2666 depth: usize,
2667 shadow_including: ShadowIncluding,
2668 no_gc: &'b NoGC,
2670 phantom: PhantomData<&'a Node>,
2671}
2672
2673impl<'a, 'b> UnrootedTreeIterator<'a, 'b>
2674where
2675 'b: 'a,
2676{
2677 pub(crate) fn new(
2678 root: &'a Node,
2679 shadow_including: ShadowIncluding,
2680 no_gc: &'b NoGC,
2681 ) -> UnrootedTreeIterator<'a, 'b> {
2682 UnrootedTreeIterator {
2683 current: Some(UnrootedDom::from_dom(Dom::from_ref(root), no_gc)),
2684 depth: 0,
2685 shadow_including,
2686 no_gc,
2687 phantom: PhantomData,
2688 }
2689 }
2690
2691 pub(crate) fn next_skipping_children(&mut self) -> Option<UnrootedDom<'b, Node>> {
2692 let current = self.current.take()?;
2693
2694 let iter = current.inclusive_ancestors(self.shadow_including);
2695
2696 for ancestor in iter {
2697 if self.depth == 0 {
2698 break;
2699 }
2700
2701 let next_sibling_option = ancestor.get_next_sibling_unrooted(self.no_gc);
2702
2703 if let Some(next_sibling) = next_sibling_option {
2704 self.current = Some(next_sibling);
2705 return Some(current);
2706 }
2707
2708 if let Some(shadow_root) = ancestor.downcast::<ShadowRoot>() {
2709 let child_option = shadow_root
2712 .Host()
2713 .upcast::<Node>()
2714 .get_first_child_unrooted(self.no_gc);
2715
2716 if let Some(child) = child_option {
2717 self.current = Some(child);
2718 return Some(current);
2719 }
2720 }
2721 self.depth -= 1;
2722 }
2723 debug_assert_eq!(self.depth, 0);
2724 self.current = None;
2725 Some(current)
2726 }
2727}
2728
2729impl<'a, 'b> Iterator for UnrootedTreeIterator<'a, 'b>
2730where
2731 'b: 'a,
2732{
2733 type Item = UnrootedDom<'b, Node>;
2734
2735 fn next(&mut self) -> Option<UnrootedDom<'b, Node>> {
2738 let current = self.current.take()?;
2739
2740 if let Some(element) = current.downcast::<Element>() &&
2742 let Some(shadow_root) = element.shadow_root() &&
2743 self.shadow_including == ShadowIncluding::Yes
2744 {
2745 self.current = Some(UnrootedDom::from_dom(
2746 Dom::from_ref(shadow_root.upcast::<Node>()),
2747 self.no_gc,
2748 ));
2749 self.depth += 1;
2750 return Some(current);
2751 }
2752
2753 let first_child_option = current.get_first_child_unrooted(self.no_gc);
2754 if let Some(first_child) = first_child_option {
2755 self.current = Some(first_child);
2756 self.depth += 1;
2757 return Some(current);
2758 };
2759
2760 let _ = self.current.insert(current);
2762 self.next_skipping_children()
2763 }
2764}
2765
2766#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2768pub(crate) enum CloneChildrenFlag {
2769 CloneChildren,
2770 DoNotCloneChildren,
2771}
2772
2773impl From<bool> for CloneChildrenFlag {
2774 fn from(boolean: bool) -> Self {
2775 if boolean {
2776 CloneChildrenFlag::CloneChildren
2777 } else {
2778 CloneChildrenFlag::DoNotCloneChildren
2779 }
2780 }
2781}
2782
2783fn as_uintptr<T>(t: &T) -> uintptr_t {
2784 t as *const T as uintptr_t
2785}
2786
2787impl Node {
2788 pub(crate) fn reflect_node<N>(
2789 cx: &mut js::context::JSContext,
2790 node: Box<N>,
2791 document: &Document,
2792 ) -> DomRoot<N>
2793 where
2794 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2795 {
2796 Self::reflect_node_with_proto(cx, node, document, None)
2797 }
2798
2799 pub(crate) fn reflect_node_with_proto<N>(
2800 cx: &mut js::context::JSContext,
2801 node: Box<N>,
2802 document: &Document,
2803 proto: Option<HandleObject>,
2804 ) -> DomRoot<N>
2805 where
2806 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2807 {
2808 let window = document.window();
2809 reflect_dom_object_with_proto_and_cx(node, window, proto, cx)
2810 }
2811
2812 pub(crate) fn new_inherited(doc: &Document) -> Node {
2813 Node::new_(NodeFlags::empty(), Some(doc))
2814 }
2815
2816 pub(crate) fn new_document_node() -> Node {
2817 Node::new_(
2818 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2819 None,
2820 )
2821 }
2822
2823 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2824 Node {
2825 eventtarget: EventTarget::new_inherited(),
2826 parent_node: Default::default(),
2827 first_child: Default::default(),
2828 last_child: Default::default(),
2829 next_sibling: Default::default(),
2830 prev_sibling: Default::default(),
2831 owner_doc: MutNullableDom::new(doc),
2832 rare_data: Default::default(),
2833 children_count: Cell::new(0u32),
2834 flags: Cell::new(flags),
2835 inclusive_descendants_version: Cell::new(0),
2836 layout_data: Default::default(),
2837 }
2838 }
2839
2840 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2842 document.add_script_and_layout_blocker();
2843
2844 let old_doc = node.owner_doc();
2846 old_doc.add_script_and_layout_blocker();
2847
2848 node.remove_self(cx);
2850
2851 if &*old_doc != document {
2853 for descendant in node.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes) {
2855 descendant.set_owner_doc(document);
2857
2858 if let Some(element) = descendant.downcast::<Element>() {
2861 for attribute in element.attrs().borrow().iter() {
2862 if let Some(attr) = attribute.as_attr() {
2863 attr.upcast::<Node>().set_owner_doc(document);
2864 }
2865 }
2866 }
2867 }
2868
2869 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2873 for descendant in node
2874 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
2875 .filter_map(|d| d.as_custom_element())
2876 {
2877 custom_element_reaction_stack.enqueue_callback_reaction(
2878 &descendant,
2879 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2880 None,
2881 );
2882 }
2883
2884 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2887 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2888 }
2889 }
2890
2891 old_doc.remove_script_and_layout_blocker(cx);
2892 document.remove_script_and_layout_blocker(cx);
2893 }
2894
2895 pub(crate) fn ensure_pre_insertion_validity(
2897 no_gc: &NoGC,
2898 node: &Node,
2899 parent: &Node,
2900 child: Option<&Node>,
2901 ) -> ErrorResult {
2902 match parent.type_id() {
2904 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2905 },
2906 _ => {
2907 return Err(Error::HierarchyRequest(Some(
2908 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2909 )));
2910 },
2911 }
2912
2913 if node.is_host_including_inclusive_ancestor(parent) {
2915 return Err(Error::HierarchyRequest(Some(
2916 "Node is a host-including inclusive ancestor of parent".to_owned(),
2917 )));
2918 }
2919
2920 if let Some(child) = child &&
2922 !parent.is_parent_of(child)
2923 {
2924 return Err(Error::NotFound(Some(
2925 "Child is non-null and its parent is not parent".to_owned(),
2926 )));
2927 }
2928
2929 match node.type_id() {
2930 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2934 if parent.is::<Document>() {
2935 return Err(Error::HierarchyRequest(Some(
2936 "Node is a Text node and parent is a document".to_owned(),
2937 )));
2938 }
2939 },
2940 NodeTypeId::DocumentType => {
2941 if !parent.is::<Document>() {
2942 return Err(Error::HierarchyRequest(Some(
2943 "Node is a doctype and parent is not a document".to_owned(),
2944 )));
2945 }
2946 },
2947 NodeTypeId::DocumentFragment(_) |
2948 NodeTypeId::Element(_) |
2949 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2950 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2951 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2954 return Err(Error::HierarchyRequest(Some(
2955 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2956 .to_owned(),
2957 )));
2958 },
2959 }
2960
2961 if parent.is::<Document>() {
2964 match node.type_id() {
2965 NodeTypeId::DocumentFragment(_) => {
2966 if node.children_unrooted(no_gc).any(|c| c.is::<Text>()) {
2968 return Err(Error::HierarchyRequest(None));
2969 }
2970 match node.child_elements_unrooted(no_gc).count() {
2971 0 => (),
2972 1 => {
2975 if parent.child_elements_unrooted(no_gc).next().is_some() {
2976 return Err(Error::HierarchyRequest(None));
2977 }
2978 if let Some(child) = child &&
2979 child
2980 .inclusively_following_siblings_unrooted(no_gc)
2981 .any(|child| child.is_doctype())
2982 {
2983 return Err(Error::HierarchyRequest(None));
2984 }
2985 },
2986 _ => return Err(Error::HierarchyRequest(None)),
2987 }
2988 },
2989 NodeTypeId::Element(_) => {
2990 if parent.child_elements_unrooted(no_gc).next().is_some() {
2992 return Err(Error::HierarchyRequest(Some(
2993 "Parent has an element child".to_owned(),
2994 )));
2995 }
2996 if let Some(child) = child &&
2997 child
2998 .inclusively_following_siblings_unrooted(no_gc)
2999 .any(|following| following.is_doctype())
3000 {
3001 return Err(Error::HierarchyRequest(Some(
3002 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
3003 )));
3004 }
3005 },
3006 NodeTypeId::DocumentType => {
3007 if parent.children_unrooted(no_gc).any(|c| c.is_doctype()) {
3010 return Err(Error::HierarchyRequest(None));
3011 }
3012 match child {
3013 Some(child) => {
3014 if parent
3015 .children_unrooted(no_gc)
3016 .take_while(|c| **c != child)
3017 .any(|c| c.is::<Element>())
3018 {
3019 return Err(Error::HierarchyRequest(None));
3020 }
3021 },
3022 None => {
3023 if parent.child_elements_unrooted(no_gc).next().is_some() {
3024 return Err(Error::HierarchyRequest(None));
3025 }
3026 },
3027 }
3028 },
3029 NodeTypeId::CharacterData(_) => (),
3030 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
3033 }
3034 }
3035 Ok(())
3036 }
3037
3038 pub(crate) fn pre_insert(
3040 cx: &mut JSContext,
3041 node: &Node,
3042 parent: &Node,
3043 child: Option<&Node>,
3044 ) -> Fallible<DomRoot<Node>> {
3045 Node::ensure_pre_insertion_validity(cx.no_gc(), node, parent, child)?;
3047
3048 let reference_child_root;
3050 let reference_child = match child {
3051 Some(child) if child == node => {
3053 reference_child_root = node.GetNextSibling();
3054 reference_child_root.as_deref()
3055 },
3056 _ => child,
3057 };
3058
3059 Node::insert(
3061 cx,
3062 node,
3063 parent,
3064 reference_child,
3065 SuppressObserver::Unsuppressed,
3066 );
3067
3068 Ok(DomRoot::from_ref(node))
3070 }
3071
3072 fn insert(
3074 cx: &mut JSContext,
3075 node: &Node,
3076 parent: &Node,
3077 child: Option<&Node>,
3078 suppress_observers: SuppressObserver,
3079 ) {
3080 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
3081
3082 rooted_vec!(let mut new_nodes);
3084 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
3085 new_nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
3086 new_nodes.r()
3087 } else {
3088 from_ref(&node)
3089 };
3090
3091 let count = new_nodes.len();
3093
3094 if count == 0 {
3096 return;
3097 }
3098
3099 let parent_document = parent.owner_doc();
3102 let from_document = node.owner_doc();
3103 from_document.add_script_and_layout_blocker();
3104 parent_document.add_script_and_layout_blocker();
3105
3106 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
3108 for kid in new_nodes {
3110 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
3111 }
3112 vtable_for(node).children_changed(cx, &ChildrenMutation::replace_all(new_nodes, &[]));
3113
3114 let mutation = LazyCell::new(|| Mutation::ChildList {
3116 added: None,
3117 removed: Some(new_nodes),
3118 prev: None,
3119 next: None,
3120 });
3121 MutationObserver::queue_a_mutation_record(node, mutation);
3122 }
3123
3124 if let Some(child) = child &&
3130 !parent.ranges_is_empty()
3131 {
3132 parent
3133 .ranges()
3134 .increase_above(parent, child.index(), count.try_into().unwrap());
3135 }
3136
3137 let previous_sibling = match suppress_observers {
3139 SuppressObserver::Unsuppressed => match child {
3140 Some(child) => child.GetPreviousSibling(),
3141 None => parent.GetLastChild(),
3142 },
3143 SuppressObserver::Suppressed => None,
3144 };
3145
3146 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
3147
3148 let mut static_node_list: SmallVec<[_; 4]> = Default::default();
3150
3151 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
3152 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
3153 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
3154
3155 for kid in new_nodes {
3157 Node::adopt(cx, kid, &parent.owner_document());
3159
3160 parent.add_child(cx, kid, child);
3163
3164 if let Some(ref shadow_root) = parent_shadow_root &&
3167 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
3168 (kid.is::<Element>() || kid.is::<Text>())
3169 {
3170 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(kid)));
3171 slottable.assign_a_slot(cx.no_gc());
3172 }
3173
3174 if parent_in_shadow_tree &&
3177 let Some(slot_element) = parent_as_slot &&
3178 !slot_element.has_assigned_nodes()
3179 {
3180 slot_element.signal_a_slot_change();
3181 }
3182
3183 kid.GetRootNode(&GetRootNodeOptions::empty())
3185 .assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Skip);
3186
3187 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
3190 if descendant.is_connected() {
3193 static_node_list.push(descendant.clone());
3194 }
3195
3196 if let Some(descendant) = DomRoot::downcast::<Element>(descendant) {
3202 if descendant.is_custom() {
3203 if descendant.is_connected() {
3204 custom_element_reaction_stack.enqueue_callback_reaction(
3205 &descendant,
3206 CallbackReaction::Connected,
3207 None,
3208 );
3209 }
3210 } else {
3211 try_upgrade_element(&descendant);
3212 }
3213 }
3214 }
3215 }
3216
3217 if let SuppressObserver::Unsuppressed = suppress_observers {
3218 vtable_for(parent).children_changed(
3221 cx,
3222 &ChildrenMutation::insert(previous_sibling.as_deref(), new_nodes, child),
3223 );
3224
3225 let mutation = LazyCell::new(|| Mutation::ChildList {
3228 added: Some(new_nodes),
3229 removed: None,
3230 prev: previous_sibling.as_deref(),
3231 next: child,
3232 });
3233 MutationObserver::queue_a_mutation_record(parent, mutation);
3234 }
3235
3236 parent_document.add_delayed_task(
3247 task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
3248 for node in static_node_list {
3251 vtable_for(&node).post_connection_steps(cx);
3252 }
3253 }),
3254 );
3255
3256 parent_document.remove_script_and_layout_blocker(cx);
3257 from_document.remove_script_and_layout_blocker(cx);
3258 }
3259
3260 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
3262 parent.owner_doc().add_script_and_layout_blocker();
3263
3264 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
3266
3267 rooted_vec!(let mut added_nodes);
3271 let added_nodes = if let Some(node) = node.as_ref() {
3272 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
3273 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
3274 added_nodes.r()
3275 } else {
3276 from_ref(node)
3277 }
3278 } else {
3279 &[] as &[&Node]
3280 };
3281
3282 for child in &*removed_nodes {
3284 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
3285 }
3286
3287 if let Some(node) = node {
3289 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
3290 }
3291
3292 vtable_for(parent).children_changed(
3293 cx,
3294 &ChildrenMutation::replace_all(removed_nodes.r(), added_nodes),
3295 );
3296
3297 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
3300 let mutation = LazyCell::new(|| Mutation::ChildList {
3301 added: Some(added_nodes),
3302 removed: Some(removed_nodes.r()),
3303 prev: None,
3304 next: None,
3305 });
3306 MutationObserver::queue_a_mutation_record(parent, mutation);
3307 }
3308 parent.owner_doc().remove_script_and_layout_blocker(cx);
3309 }
3310
3311 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
3313 if string.is_empty() {
3314 Node::replace_all(cx, None, parent);
3315 } else {
3316 let text = Text::new(cx, string, &parent.owner_document());
3317 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
3318 };
3319 }
3320
3321 fn pre_remove(cx: &mut JSContext, child: &Node, parent: &Node) -> Fallible<DomRoot<Node>> {
3323 match child.GetParentNode() {
3325 Some(ref node) if &**node != parent => return Err(Error::NotFound(None)),
3326 None => return Err(Error::NotFound(None)),
3327 _ => (),
3328 }
3329
3330 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
3332
3333 Ok(DomRoot::from_ref(child))
3335 }
3336
3337 fn remove(
3339 cx: &mut JSContext,
3340 node: &Node,
3341 parent: &Node,
3342 suppress_observers: SuppressObserver,
3343 ) {
3344 parent.owner_doc().add_script_and_layout_blocker();
3345
3346 assert!(
3350 node.GetParentNode()
3351 .is_some_and(|node_parent| &*node_parent == parent)
3352 );
3353
3354 let cached_index = Node::live_range_pre_remove_steps(node, parent);
3357
3358 let old_previous_sibling = node.GetPreviousSibling();
3362
3363 let old_next_sibling = node.GetNextSibling();
3365
3366 parent.remove_child(cx, node, cached_index);
3369
3370 if let Some(slot) = node.assigned_slot() {
3372 slot.assign_slottables(cx.no_gc());
3373 }
3374
3375 if parent.is_in_a_shadow_tree() &&
3378 let Some(slot_element) = parent.downcast::<HTMLSlotElement>() &&
3379 !slot_element.has_assigned_nodes()
3380 {
3381 slot_element.signal_a_slot_change();
3382 }
3383
3384 let has_slot_descendant = node
3386 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
3387 .any(|elem| elem.is::<HTMLSlotElement>());
3388 if has_slot_descendant {
3389 parent
3391 .GetRootNode(&GetRootNodeOptions::empty())
3392 .assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Skip);
3393
3394 node.assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Force);
3396 }
3397
3398 if let SuppressObserver::Unsuppressed = suppress_observers {
3402 vtable_for(parent).children_changed(
3403 cx,
3404 &ChildrenMutation::replace(
3405 old_previous_sibling.as_deref(),
3406 &Some(node),
3407 &[],
3408 old_next_sibling.as_deref(),
3409 ),
3410 );
3411
3412 let removed = [node];
3413 let mutation = LazyCell::new(|| Mutation::ChildList {
3414 added: None,
3415 removed: Some(&removed),
3416 prev: old_previous_sibling.as_deref(),
3417 next: old_next_sibling.as_deref(),
3418 });
3419 MutationObserver::queue_a_mutation_record(parent, mutation);
3420 }
3421 parent.owner_doc().remove_script_and_layout_blocker(cx);
3422 }
3423
3424 fn live_range_pre_remove_steps(node: &Node, parent: &Node) -> Option<u32> {
3426 if parent.ranges_is_empty() {
3427 return None;
3428 }
3429
3430 let index = node.index();
3436
3437 parent.ranges().decrease_above(parent, index, 1);
3444
3445 Some(index)
3449 }
3450
3451 pub(crate) fn clone(
3453 cx: &mut JSContext,
3454 node: &Node,
3455 maybe_doc: Option<&Document>,
3456 clone_children: CloneChildrenFlag,
3457 registry: Option<DomRoot<CustomElementRegistry>>,
3458 ) -> DomRoot<Node> {
3459 let document = match maybe_doc {
3461 Some(doc) => DomRoot::from_ref(doc),
3462 None => node.owner_doc(),
3463 };
3464
3465 let copy: DomRoot<Node> = match node.type_id() {
3468 NodeTypeId::DocumentType => {
3469 let doctype = node.downcast::<DocumentType>().unwrap();
3470 let doctype = DocumentType::new(
3471 cx,
3472 doctype.name().clone(),
3473 Some(doctype.public_id().clone()),
3474 Some(doctype.system_id().clone()),
3475 &document,
3476 );
3477 DomRoot::upcast::<Node>(doctype)
3478 },
3479 NodeTypeId::Attr => {
3480 let attr = node.downcast::<Attr>().unwrap();
3481 let attr = Attr::new(
3482 cx,
3483 &document,
3484 attr.local_name().clone(),
3485 attr.value().clone(),
3486 attr.name().clone(),
3487 attr.namespace().clone(),
3488 attr.prefix().cloned(),
3489 None,
3490 );
3491 DomRoot::upcast::<Node>(attr)
3492 },
3493 NodeTypeId::DocumentFragment(_) => {
3494 let doc_fragment = DocumentFragment::new(cx, &document);
3495 DomRoot::upcast::<Node>(doc_fragment)
3496 },
3497 NodeTypeId::CharacterData(_) => {
3498 let cdata = node.downcast::<CharacterData>().unwrap();
3499 cdata.clone_with_data(cx, cdata.Data(), &document)
3500 },
3501 NodeTypeId::Document(_) => {
3502 let document = node.downcast::<Document>().unwrap();
3505 let is_html_doc = if document.is_html_document() {
3506 IsHTMLDocument::HTMLDocument
3507 } else {
3508 IsHTMLDocument::NonHTMLDocument
3509 };
3510 let window = document.window();
3511 let loader = DocumentLoader::new(&document.loader());
3512 let document = Document::new(
3513 window,
3514 HasBrowsingContext::No,
3515 Some(document.url()),
3516 None,
3517 document.origin().clone(),
3519 is_html_doc,
3520 None,
3521 None,
3522 DocumentActivity::Inactive,
3523 DocumentSource::NotFromParser,
3524 loader,
3525 None,
3526 document.status_code(),
3527 Default::default(),
3528 false,
3529 document.allow_declarative_shadow_roots(),
3530 Some(document.insecure_requests_policy()),
3531 document.has_trustworthy_ancestor_or_current_origin(),
3532 document.custom_element_reaction_stack(),
3533 document.creation_sandboxing_flag_set(),
3534 CanGc::from_cx(cx),
3535 );
3536 DomRoot::upcast::<Node>(document)
3540 },
3541 NodeTypeId::Element(..) => {
3543 let element = node.downcast::<Element>().unwrap();
3544 let registry = element.custom_element_registry().or(registry);
3547 let registry =
3550 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3551 Some(document.custom_element_registry())
3552 } else {
3553 registry
3554 };
3555 let name = QualName {
3559 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3560 ns: element.namespace().clone(),
3561 local: element.local_name().clone(),
3562 };
3563 let element = Element::create(
3564 cx,
3565 name,
3566 element.get_is(),
3567 &document,
3568 ElementCreator::ScriptCreated,
3569 CustomElementCreationMode::Asynchronous,
3570 None,
3571 );
3572 element.set_custom_element_registry(registry);
3574 DomRoot::upcast::<Node>(element)
3575 },
3576 };
3577
3578 let document = match copy.downcast::<Document>() {
3581 Some(doc) => DomRoot::from_ref(doc),
3582 None => DomRoot::from_ref(&*document),
3583 };
3584 assert!(copy.owner_doc() == document);
3585
3586 match node.type_id() {
3588 NodeTypeId::Document(_) => {
3589 let node_doc = node.downcast::<Document>().unwrap();
3590 let copy_doc = copy.downcast::<Document>().unwrap();
3591 copy_doc.set_encoding(node_doc.encoding());
3592 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3593 },
3594 NodeTypeId::Element(..) => {
3595 let node_elem = node.downcast::<Element>().unwrap();
3596 let copy_elem = copy.downcast::<Element>().unwrap();
3597
3598 node_elem.copy_all_attributes_to_other_element(cx, copy_elem);
3600 },
3601 _ => (),
3602 }
3603
3604 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3607
3608 if clone_children == CloneChildrenFlag::CloneChildren {
3611 for child in node.children() {
3612 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3613 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3614 }
3615 }
3616
3617 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3620 let node_elem = node.downcast::<Element>().unwrap();
3621 let copy_elem = copy.downcast::<Element>().unwrap();
3622
3623 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3624 assert!(!copy_elem.is_shadow_host());
3626
3627 let copy_shadow_root =
3631 copy_elem.attach_shadow(
3632 cx,
3633 IsUserAgentWidget::No,
3634 shadow_root.Mode(),
3635 shadow_root.Clonable(),
3636 shadow_root.Serializable(),
3637 shadow_root.DelegatesFocus(),
3638 shadow_root.SlotAssignment(),
3639 )
3640 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3641
3642 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3644
3645 for child in shadow_root.upcast::<Node>().children() {
3648 let child_copy = Node::clone(
3649 cx,
3650 &child,
3651 Some(&document),
3652 CloneChildrenFlag::CloneChildren,
3653 None,
3654 );
3655
3656 let _inserted_node =
3658 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3659 }
3660 }
3661 }
3662
3663 copy
3665 }
3666
3667 pub(crate) fn child_text_content(&self) -> DOMString {
3669 Node::collect_text_contents(self.children())
3670 }
3671
3672 pub(crate) fn descendant_text_content(&self) -> DOMString {
3674 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3675 }
3676
3677 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3678 iterator: T,
3679 ) -> DOMString {
3680 let mut content = String::new();
3681 for node in iterator {
3682 if let Some(text) = node.downcast::<Text>() {
3683 content.push_str(&text.upcast::<CharacterData>().data());
3684 }
3685 }
3686 DOMString::from(content)
3687 }
3688
3689 pub(crate) fn set_text_content_for_element(
3691 &self,
3692 cx: &mut JSContext,
3693 value: Option<DOMString>,
3694 ) {
3695 assert!(matches!(
3698 self.type_id(),
3699 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3700 ));
3701 let value = value.unwrap_or_default();
3702 let node = if value.is_empty() {
3703 None
3705 } else {
3706 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3709 };
3710
3711 Self::replace_all(cx, node.as_deref(), self);
3713 }
3714
3715 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3716 match namespace {
3717 ns!() => None,
3718 _ => Some(DOMString::from(&*namespace)),
3720 }
3721 }
3722
3723 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3725 match node.type_id() {
3726 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3727 NodeTypeId::Attr => node
3728 .downcast::<Attr>()
3729 .unwrap()
3730 .GetOwnerElement()
3731 .as_ref()
3732 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3733 NodeTypeId::Document(_) => node
3734 .downcast::<Document>()
3735 .unwrap()
3736 .GetDocumentElement()
3737 .as_ref()
3738 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3739 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3740 _ => node
3741 .GetParentElement()
3742 .as_ref()
3743 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3744 }
3745 }
3746
3747 #[expect(unsafe_code)]
3755 pub(crate) unsafe fn from_untrusted_node_address(
3756 candidate: UntrustedNodeAddress,
3757 ) -> &'static Self {
3758 let candidate = candidate.0 as usize;
3760 let object = candidate as *mut JSObject;
3761 if object.is_null() {
3762 panic!("Attempted to create a `Node` from an invalid pointer!")
3763 }
3764
3765 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3766 }
3767
3768 pub(crate) fn html_serialize(
3769 &self,
3770 cx: &mut js::context::JSContext,
3771 traversal_scope: html_serialize::TraversalScope,
3772 serialize_shadow_roots: bool,
3773 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3774 ) -> DOMString {
3775 let mut writer = vec![];
3776 let mut serializer = HtmlSerializer::new(
3777 &mut writer,
3778 html_serialize::SerializeOpts {
3779 traversal_scope: traversal_scope.clone(),
3780 ..Default::default()
3781 },
3782 );
3783
3784 serialize_html_fragment(
3785 cx,
3786 self,
3787 &mut serializer,
3788 traversal_scope,
3789 serialize_shadow_roots,
3790 shadow_roots,
3791 )
3792 .expect("Serializing node failed");
3793
3794 DOMString::from(String::from_utf8(writer).unwrap())
3796 }
3797
3798 pub(crate) fn xml_serialize(
3800 &self,
3801 traversal_scope: xml_serialize::TraversalScope,
3802 ) -> Fallible<DOMString> {
3803 let mut writer = vec![];
3804 xml_serialize::serialize(
3805 &mut writer,
3806 &HtmlSerialize::new(self),
3807 xml_serialize::SerializeOpts { traversal_scope },
3808 )
3809 .map_err(|error| {
3810 error!("Cannot serialize node: {error}");
3811 Error::InvalidState(None)
3812 })?;
3813
3814 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3816 error!("Cannot serialize node: {error}");
3817 Error::InvalidState(None)
3818 })?);
3819
3820 Ok(string)
3821 }
3822
3823 pub(crate) fn fragment_serialization_algorithm(
3825 &self,
3826 cx: &mut js::context::JSContext,
3827 require_well_formed: bool,
3828 ) -> Fallible<DOMString> {
3829 let context_document = self.owner_document();
3831
3832 if context_document.is_html_document() {
3835 return Ok(self.html_serialize(
3836 cx,
3837 html_serialize::TraversalScope::ChildrenOnly(None),
3838 false,
3839 vec![],
3840 ));
3841 }
3842
3843 let _ = require_well_formed;
3846 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3847 }
3848
3849 fn get_next_sibling_unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, Node>> {
3850 self.next_sibling.get_unrooted(no_gc)
3851 }
3852
3853 fn get_previous_sibling_unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, Node>> {
3854 self.prev_sibling.get_unrooted(no_gc)
3855 }
3856
3857 fn get_first_child_unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, Node>> {
3858 self.first_child.get_unrooted(no_gc)
3859 }
3860
3861 fn compare_dom_tree_position(&self, other: &Node, common_ancestor: &Node) -> Ordering {
3863 debug_assert!(
3864 self.inclusive_ancestors(ShadowIncluding::No)
3865 .any(|ancestor| &*ancestor == common_ancestor)
3866 );
3867 debug_assert!(
3868 other
3869 .inclusive_ancestors(ShadowIncluding::No)
3870 .any(|ancestor| &*ancestor == common_ancestor)
3871 );
3872
3873 if self == other {
3874 return Ordering::Equal;
3875 }
3876
3877 if self == common_ancestor {
3878 return Ordering::Less;
3879 }
3880 if other == common_ancestor {
3881 return Ordering::Greater;
3882 }
3883
3884 let my_ancestors: Vec<_> = self
3885 .inclusive_ancestors(ShadowIncluding::No)
3886 .take_while(|ancestor| &**ancestor != common_ancestor)
3887 .collect();
3888 let other_ancestors: Vec<_> = other
3889 .inclusive_ancestors(ShadowIncluding::No)
3890 .take_while(|ancestor| &**ancestor != common_ancestor)
3891 .collect();
3892
3893 let mut i = my_ancestors.len() - 1;
3895 let mut j = other_ancestors.len() - 1;
3896
3897 while my_ancestors[i] == other_ancestors[j] {
3898 if i == 0 {
3899 debug_assert_ne!(j, 0, "Equal inclusive ancestors but nodes are not equal?");
3901 return Ordering::Less;
3902 }
3903 if j == 0 {
3904 return Ordering::Greater;
3906 }
3907
3908 i -= 1;
3909 j -= 1;
3910 }
3911
3912 if my_ancestors[i]
3915 .preceding_siblings()
3916 .any(|sibling| sibling == other_ancestors[j])
3917 {
3918 Ordering::Greater
3920 } else {
3921 debug_assert!(
3923 other_ancestors[j]
3924 .preceding_siblings()
3925 .any(|sibling| sibling == my_ancestors[i])
3926 );
3927 Ordering::Less
3928 }
3929 }
3930}
3931
3932impl NodeMethods<crate::DomTypeHolder> for Node {
3933 fn NodeType(&self) -> u16 {
3935 match self.type_id() {
3936 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3937 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3938 NodeConstants::TEXT_NODE
3939 },
3940 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3941 NodeConstants::CDATA_SECTION_NODE
3942 },
3943 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3944 NodeConstants::PROCESSING_INSTRUCTION_NODE
3945 },
3946 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3947 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3948 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3949 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3950 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3951 }
3952 }
3953
3954 fn NodeName(&self) -> DOMString {
3956 match self.type_id() {
3957 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3958 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3959 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3960 DOMString::from("#text")
3961 },
3962 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3963 DOMString::from("#cdata-section")
3964 },
3965 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3966 self.downcast::<ProcessingInstruction>().unwrap().Target()
3967 },
3968 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => DOMString::from("#comment"),
3969 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3970 NodeTypeId::DocumentFragment(_) => DOMString::from("#document-fragment"),
3971 NodeTypeId::Document(_) => DOMString::from("#document"),
3972 }
3973 }
3974
3975 fn BaseURI(&self) -> USVString {
3977 USVString(String::from(self.owner_doc().base_url().as_str()))
3978 }
3979
3980 fn IsConnected(&self) -> bool {
3982 self.is_connected()
3983 }
3984
3985 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3987 match self.type_id() {
3988 NodeTypeId::Document(_) => None,
3989 _ => Some(self.owner_doc()),
3990 }
3991 }
3992
3993 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3995 if !options.composed &&
3996 let Some(shadow_root) = self.containing_shadow_root()
3997 {
3998 return DomRoot::upcast(shadow_root);
3999 }
4000
4001 if self.is_connected() {
4002 DomRoot::from_ref(self.owner_doc().upcast::<Node>())
4003 } else {
4004 self.inclusive_ancestors(ShadowIncluding::Yes)
4005 .last()
4006 .unwrap()
4007 }
4008 }
4009
4010 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
4012 self.parent_node.get()
4013 }
4014
4015 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
4017 self.GetParentNode().and_then(DomRoot::downcast)
4018 }
4019
4020 fn HasChildNodes(&self) -> bool {
4022 self.first_child.get().is_some()
4023 }
4024
4025 fn ChildNodes(&self, cx: &mut JSContext) -> DomRoot<NodeList> {
4027 if let Some(list) = self.ensure_rare_data().child_list.get() {
4028 return list;
4029 }
4030
4031 let doc = self.owner_doc();
4032 let window = doc.window();
4033 let list = NodeList::new_child_list(window, self, CanGc::from_cx(cx));
4034 self.ensure_rare_data().child_list.set(Some(&list));
4035 list
4036 }
4037
4038 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
4040 self.first_child.get()
4041 }
4042
4043 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
4045 self.last_child.get()
4046 }
4047
4048 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
4050 self.prev_sibling.get()
4051 }
4052
4053 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
4055 self.next_sibling.get()
4056 }
4057
4058 fn GetNodeValue(&self) -> Option<DOMString> {
4060 match self.type_id() {
4061 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
4062 NodeTypeId::CharacterData(_) => {
4063 self.downcast::<CharacterData>().map(CharacterData::Data)
4064 },
4065 _ => None,
4066 }
4067 }
4068
4069 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
4071 match self.type_id() {
4072 NodeTypeId::Attr => {
4073 let attr = self.downcast::<Attr>().unwrap();
4074 attr.SetValue(cx, val.unwrap_or_default())?;
4075 },
4076 NodeTypeId::CharacterData(_) => {
4077 let character_data = self.downcast::<CharacterData>().unwrap();
4078 character_data.SetData(val.unwrap_or_default());
4079 },
4080 _ => {},
4081 };
4082 Ok(())
4083 }
4084
4085 fn GetTextContent(&self) -> Option<DOMString> {
4087 match self.type_id() {
4088 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
4089 let content =
4090 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
4091 Some(content)
4092 },
4093 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
4094 NodeTypeId::CharacterData(..) => {
4095 let characterdata = self.downcast::<CharacterData>().unwrap();
4096 Some(characterdata.Data())
4097 },
4098 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
4099 }
4100 }
4101
4102 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
4104 match self.type_id() {
4105 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
4106 self.set_text_content_for_element(cx, value);
4107 },
4108 NodeTypeId::Attr => {
4109 let attr = self.downcast::<Attr>().unwrap();
4110 attr.SetValue(cx, value.unwrap_or_default())?;
4111 },
4112 NodeTypeId::CharacterData(..) => {
4113 let characterdata = self.downcast::<CharacterData>().unwrap();
4114 characterdata.SetData(value.unwrap_or_default());
4115 },
4116 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
4117 };
4118 Ok(())
4119 }
4120
4121 fn InsertBefore(
4123 &self,
4124 cx: &mut JSContext,
4125 node: &Node,
4126 child: Option<&Node>,
4127 ) -> Fallible<DomRoot<Node>> {
4128 Node::pre_insert(cx, node, self, child)
4129 }
4130
4131 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
4133 Node::pre_insert(cx, node, self, None)
4134 }
4135
4136 fn ReplaceChild(
4138 &self,
4139 cx: &mut JSContext,
4140 node: &Node,
4141 child: &Node,
4142 ) -> Fallible<DomRoot<Node>> {
4143 match self.type_id() {
4146 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
4147 },
4148 _ => return Err(Error::HierarchyRequest(None)),
4149 }
4150
4151 if node.is_inclusive_ancestor_of(self) {
4154 return Err(Error::HierarchyRequest(None));
4155 }
4156
4157 if !self.is_parent_of(child) {
4159 return Err(Error::NotFound(None));
4160 }
4161
4162 match node.type_id() {
4167 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
4168 return Err(Error::HierarchyRequest(None));
4169 },
4170 NodeTypeId::DocumentType if !self.is::<Document>() => {
4171 return Err(Error::HierarchyRequest(None));
4172 },
4173 NodeTypeId::Document(_) | NodeTypeId::Attr => {
4174 return Err(Error::HierarchyRequest(None));
4175 },
4176 _ => (),
4177 }
4178
4179 if self.is::<Document>() {
4182 match node.type_id() {
4183 NodeTypeId::DocumentFragment(_) => {
4185 if node.children_unrooted(cx.no_gc()).any(|c| c.is::<Text>()) {
4187 return Err(Error::HierarchyRequest(None));
4188 }
4189 match node.child_elements_unrooted(cx.no_gc()).count() {
4190 0 => (),
4191 1 => {
4193 if self
4194 .child_elements_unrooted(cx.no_gc())
4195 .any(|c| c.upcast::<Node>() != child)
4196 {
4197 return Err(Error::HierarchyRequest(None));
4198 }
4199 if child.following_siblings().any(|child| child.is_doctype()) {
4200 return Err(Error::HierarchyRequest(None));
4201 }
4202 },
4203 _ => return Err(Error::HierarchyRequest(None)),
4205 }
4206 },
4207 NodeTypeId::Element(..) => {
4209 if self
4210 .child_elements_unrooted(cx.no_gc())
4211 .any(|c| c.upcast::<Node>() != child)
4212 {
4213 return Err(Error::HierarchyRequest(None));
4214 }
4215 if child.following_siblings().any(|child| child.is_doctype()) {
4216 return Err(Error::HierarchyRequest(None));
4217 }
4218 },
4219 NodeTypeId::DocumentType => {
4221 if self
4222 .children_unrooted(cx.no_gc())
4223 .any(|c| c.is_doctype() && *c != child)
4224 {
4225 return Err(Error::HierarchyRequest(None));
4226 }
4227 if self
4228 .children_unrooted(cx.no_gc())
4229 .take_while(|c| **c != child)
4230 .any(|c| c.is::<Element>())
4231 {
4232 return Err(Error::HierarchyRequest(None));
4233 }
4234 },
4235 NodeTypeId::CharacterData(..) => (),
4236 NodeTypeId::Document(_) => unreachable!(),
4239 NodeTypeId::Attr => unreachable!(),
4240 }
4241 }
4242
4243 let child_next_sibling = child.GetNextSibling();
4246 let node_next_sibling = node.GetNextSibling();
4247 let reference_child = if child_next_sibling.as_deref() == Some(node) {
4248 node_next_sibling.as_deref()
4249 } else {
4250 child_next_sibling.as_deref()
4251 };
4252
4253 let previous_sibling = child.GetPreviousSibling();
4255
4256 let document = self.owner_document();
4260 Node::adopt(cx, node, &document);
4261
4262 let removed_child = if node != child {
4267 Node::remove(cx, child, self, SuppressObserver::Suppressed);
4269 Some(child)
4270 } else {
4271 None
4272 };
4273
4274 rooted_vec!(let mut nodes);
4276 let nodes = if node.type_id() ==
4277 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
4278 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
4279 {
4280 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
4281 nodes.r()
4282 } else {
4283 from_ref(&node)
4284 };
4285
4286 Node::insert(
4288 cx,
4289 node,
4290 self,
4291 reference_child,
4292 SuppressObserver::Suppressed,
4293 );
4294
4295 vtable_for(self).children_changed(
4296 cx,
4297 &ChildrenMutation::replace(
4298 previous_sibling.as_deref(),
4299 &removed_child,
4300 nodes,
4301 reference_child,
4302 ),
4303 );
4304
4305 let removed = removed_child.map(|r| [r]);
4308 let mutation = LazyCell::new(|| Mutation::ChildList {
4309 added: Some(nodes),
4310 removed: removed.as_ref().map(|r| &r[..]),
4311 prev: previous_sibling.as_deref(),
4312 next: reference_child,
4313 });
4314
4315 MutationObserver::queue_a_mutation_record(self, mutation);
4316
4317 Ok(DomRoot::from_ref(child))
4319 }
4320
4321 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
4323 Node::pre_remove(cx, node, self)
4324 }
4325
4326 fn Normalize(&self, cx: &mut JSContext) {
4328 let mut children = self.children().enumerate().peekable();
4329 while let Some((_, node)) = children.next() {
4330 if let Some(text) = node.downcast::<Text>() {
4331 if text.is::<CDATASection>() {
4332 continue;
4333 }
4334 let cdata = text.upcast::<CharacterData>();
4335 let mut length = cdata.Length();
4336 if length == 0 {
4337 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
4338 continue;
4339 }
4340 while children.peek().is_some_and(|(_, sibling)| {
4341 sibling.is::<Text>() && !sibling.is::<CDATASection>()
4342 }) {
4343 let (index, sibling) = children.next().unwrap();
4344 sibling
4345 .ranges()
4346 .drain_to_preceding_text_sibling(&sibling, &node, length);
4347 self.ranges()
4348 .move_to_text_child_at(self, index as u32, &node, length);
4349 let sibling_cdata = sibling.downcast::<CharacterData>().unwrap();
4350 length += sibling_cdata.Length();
4351 cdata.append_data(&sibling_cdata.data());
4352 Node::remove(cx, &sibling, self, SuppressObserver::Unsuppressed);
4353 }
4354 } else {
4355 node.Normalize(cx);
4356 }
4357 }
4358 }
4359
4360 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
4362 if self.is::<ShadowRoot>() {
4364 return Err(Error::NotSupported(None));
4365 }
4366
4367 let result = Node::clone(
4369 cx,
4370 self,
4371 None,
4372 if subtree {
4373 CloneChildrenFlag::CloneChildren
4374 } else {
4375 CloneChildrenFlag::DoNotCloneChildren
4376 },
4377 None,
4378 );
4379 Ok(result)
4380 }
4381
4382 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
4384 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
4385 let doctype = node.downcast::<DocumentType>().unwrap();
4386 let other_doctype = other.downcast::<DocumentType>().unwrap();
4387 (*doctype.name() == *other_doctype.name()) &&
4388 (*doctype.public_id() == *other_doctype.public_id()) &&
4389 (*doctype.system_id() == *other_doctype.system_id())
4390 }
4391 fn is_equal_element(node: &Node, other: &Node) -> bool {
4392 let element = node.downcast::<Element>().unwrap();
4393 let other_element = other.downcast::<Element>().unwrap();
4394 (*element.namespace() == *other_element.namespace()) &&
4395 (*element.prefix() == *other_element.prefix()) &&
4396 (*element.local_name() == *other_element.local_name()) &&
4397 (element.attrs().borrow().len() == other_element.attrs().borrow().len())
4398 }
4399 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
4400 let pi = node.downcast::<ProcessingInstruction>().unwrap();
4401 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
4402 (*pi.target() == *other_pi.target()) &&
4403 (*pi.upcast::<CharacterData>().data() ==
4404 *other_pi.upcast::<CharacterData>().data())
4405 }
4406 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
4407 let characterdata = node.downcast::<CharacterData>().unwrap();
4408 let other_characterdata = other.downcast::<CharacterData>().unwrap();
4409 *characterdata.data() == *other_characterdata.data()
4410 }
4411 fn is_equal_attr(node: &Node, other: &Node) -> bool {
4412 let attr = node.downcast::<Attr>().unwrap();
4413 let other_attr = other.downcast::<Attr>().unwrap();
4414 (*attr.namespace() == *other_attr.namespace()) &&
4415 (attr.local_name() == other_attr.local_name()) &&
4416 (**attr.value() == **other_attr.value())
4417 }
4418 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
4419 let element = node.downcast::<Element>().unwrap();
4420 let other_element = other.downcast::<Element>().unwrap();
4421 assert!(element.attrs().borrow().len() == other_element.attrs().borrow().len());
4422 element.attrs().borrow().iter().all(|attr| {
4423 other_element.attrs().borrow().iter().any(|other_attr| {
4424 (*attr.namespace() == *other_attr.namespace()) &&
4425 (attr.local_name() == other_attr.local_name()) &&
4426 (**attr.value() == **other_attr.value())
4427 })
4428 })
4429 }
4430
4431 fn is_equal_node(this: &Node, node: &Node) -> bool {
4432 if this.NodeType() != node.NodeType() {
4434 return false;
4435 }
4436
4437 match node.type_id() {
4438 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
4440 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
4441 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
4442 if !is_equal_processinginstruction(this, node) =>
4443 {
4444 return false;
4445 },
4446 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
4447 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
4448 if !is_equal_characterdata(this, node) =>
4449 {
4450 return false;
4451 },
4452 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
4454 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
4455
4456 _ => (),
4457 }
4458
4459 if this.children_count() != node.children_count() {
4461 return false;
4462 }
4463
4464 this.children()
4466 .zip(node.children())
4467 .all(|(child, other_child)| is_equal_node(&child, &other_child))
4468 }
4469 match maybe_node {
4470 None => false,
4472 Some(node) => is_equal_node(self, node),
4474 }
4475 }
4476
4477 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
4479 match other_node {
4480 Some(node) => self == node,
4481 None => false,
4482 }
4483 }
4484
4485 fn CompareDocumentPosition(&self, other: &Node) -> u16 {
4487 if self == other {
4489 return 0;
4490 }
4491
4492 let mut node1 = Some(other);
4494 let mut node2 = Some(self);
4495
4496 let mut attr1: Option<&Attr> = None;
4498 let mut attr2: Option<&Attr> = None;
4499
4500 let attr1owner;
4505 if let Some(a) = other.downcast::<Attr>() {
4506 attr1 = Some(a);
4507 attr1owner = a.GetOwnerElement();
4508 node1 = match attr1owner {
4509 Some(ref e) => Some(e.upcast()),
4510 None => None,
4511 }
4512 }
4513
4514 let attr2owner;
4517 if let Some(a) = self.downcast::<Attr>() {
4518 attr2 = Some(a);
4519 attr2owner = a.GetOwnerElement();
4520 node2 = match attr2owner {
4521 Some(ref e) => Some(e.upcast()),
4522 None => None,
4523 }
4524 }
4525
4526 if let Some(node2) = node2 &&
4531 Some(node2) == node1 &&
4532 let (Some(a1), Some(a2)) = (attr1, attr2)
4533 {
4534 let attrs = node2.downcast::<Element>().unwrap().attrs();
4535 for attr in attrs.borrow().iter() {
4539 if (*attr.namespace() == *a1.namespace()) &&
4540 (attr.local_name() == a1.local_name()) &&
4541 (**attr.value() == **a1.value())
4542 {
4543 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4544 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4545 }
4546 if (*attr.namespace() == *a2.namespace()) &&
4547 (attr.local_name() == a2.local_name()) &&
4548 (**attr.value() == **a2.value())
4549 {
4550 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4551 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4552 }
4553 }
4554 unreachable!();
4557 }
4558
4559 match (node1, node2) {
4561 (None, _) => {
4562 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4564 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4565 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4566 },
4567 (_, None) => {
4568 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4570 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4571 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4572 },
4573 (Some(node1), Some(node2)) => {
4574 let mut self_and_ancestors = node2
4576 .inclusive_ancestors(ShadowIncluding::No)
4577 .collect::<SmallVec<[_; 20]>>();
4578 let mut other_and_ancestors = node1
4579 .inclusive_ancestors(ShadowIncluding::No)
4580 .collect::<SmallVec<[_; 20]>>();
4581
4582 if self_and_ancestors.last() != other_and_ancestors.last() {
4583 let random = as_uintptr(self_and_ancestors.last().unwrap()) <
4584 as_uintptr(other_and_ancestors.last().unwrap());
4585 let random = if random {
4586 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4587 } else {
4588 NodeConstants::DOCUMENT_POSITION_PRECEDING
4589 };
4590
4591 return random +
4593 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4594 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4595 }
4596 let mut parent = self_and_ancestors.pop().unwrap();
4598 other_and_ancestors.pop().unwrap();
4599
4600 let mut current_position =
4601 cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
4602
4603 while current_position > 0 {
4604 current_position -= 1;
4605 let child_1 = self_and_ancestors.pop().unwrap();
4606 let child_2 = other_and_ancestors.pop().unwrap();
4607
4608 if child_1 != child_2 {
4609 for child in parent.children() {
4610 if child == child_1 {
4611 return NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4613 }
4614 if child == child_2 {
4615 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4617 }
4618 }
4619 }
4620
4621 parent = child_1;
4622 }
4623
4624 if self_and_ancestors.len() < other_and_ancestors.len() {
4629 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4630 NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
4631 } else {
4632 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4633 NodeConstants::DOCUMENT_POSITION_CONTAINS
4634 }
4635 },
4636 }
4637 }
4638
4639 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4641 match maybe_other {
4642 None => false,
4643 Some(other) => self.is_inclusive_ancestor_of(other),
4644 }
4645 }
4646
4647 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4649 let namespace = namespace_from_domstring(namespace);
4650
4651 if namespace == ns!() {
4653 return None;
4654 }
4655
4656 match self.type_id() {
4658 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4659 NodeTypeId::Document(_) => self
4660 .downcast::<Document>()
4661 .unwrap()
4662 .GetDocumentElement()
4663 .and_then(|element| element.lookup_prefix(namespace)),
4664 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4665 NodeTypeId::Attr => self
4666 .downcast::<Attr>()
4667 .unwrap()
4668 .GetOwnerElement()
4669 .and_then(|element| element.lookup_prefix(namespace)),
4670 _ => self
4671 .GetParentElement()
4672 .and_then(|element| element.lookup_prefix(namespace)),
4673 }
4674 }
4675
4676 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4678 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4680
4681 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4683 }
4684
4685 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4687 let namespace = namespace_from_domstring(namespace);
4689 Node::locate_namespace(self, None) == namespace
4691 }
4692}
4693
4694pub(crate) trait NodeTraits {
4695 fn owner_document(&self) -> DomRoot<Document>;
4699 fn owner_window(&self) -> DomRoot<Window>;
4703 fn owner_global(&self) -> DomRoot<GlobalScope>;
4707 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4709 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4712}
4713
4714impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4715 fn owner_document(&self) -> DomRoot<Document> {
4716 self.upcast().owner_doc()
4717 }
4718
4719 fn owner_window(&self) -> DomRoot<Window> {
4720 DomRoot::from_ref(self.owner_document().window())
4721 }
4722
4723 fn owner_global(&self) -> DomRoot<GlobalScope> {
4724 DomRoot::from_ref(self.owner_window().upcast())
4725 }
4726
4727 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4728 Node::containing_shadow_root(self.upcast())
4729 }
4730
4731 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4732 self.containing_shadow_root()
4733 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4734 .unwrap_or_else(|| {
4735 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4736 })
4737 }
4738}
4739
4740impl VirtualMethods for Node {
4741 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4742 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4743 }
4744
4745 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4746 if let Some(s) = self.super_type() {
4747 s.children_changed(cx, mutation);
4748 }
4749
4750 if let Some(data) = self.rare_data().as_ref() &&
4751 let Some(list) = data.child_list.get()
4752 {
4753 list.as_children_list().children_changed(mutation);
4754 }
4755
4756 self.owner_doc().content_and_heritage_changed(self);
4757 }
4758
4759 fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
4762 self.super_type().unwrap().unbind_from_tree(cx, context);
4763
4764 if !self.is_in_a_shadow_tree() && !self.ranges_is_empty() {
4769 self.ranges()
4770 .drain_to_parent(context.parent, context.index(), self);
4771 }
4772 }
4773
4774 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
4775 if let Some(super_type) = self.super_type() {
4776 super_type.moving_steps(cx, context);
4777 }
4778
4779 if let Some(old_parent) = context.old_parent &&
4784 !self.is_in_a_shadow_tree() &&
4785 !self.ranges_is_empty()
4786 {
4787 self.ranges()
4788 .drain_to_parent(old_parent, context.index(), self);
4789 }
4790
4791 self.owner_doc().content_and_heritage_changed(self);
4792 }
4793
4794 fn handle_event(&self, cx: &mut js::context::JSContext, event: &Event) {
4795 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4796 return;
4797 }
4798
4799 if let Some(event) = event.downcast::<KeyboardEvent>() {
4800 self.owner_document()
4801 .event_handler()
4802 .run_default_keyboard_event_handler(cx, self, event);
4803 }
4804 }
4805}
4806
4807#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4809pub(crate) enum NodeDamage {
4810 Style,
4812 ContentOrHeritage,
4815 Other,
4817}
4818
4819pub(crate) enum ChildrenMutation<'a> {
4820 Append {
4821 prev: &'a Node,
4822 added: &'a [&'a Node],
4823 },
4824 Insert {
4825 prev: &'a Node,
4826 added: &'a [&'a Node],
4827 next: &'a Node,
4828 },
4829 Prepend {
4830 added: &'a [&'a Node],
4831 next: &'a Node,
4832 },
4833 Replace {
4834 prev: Option<&'a Node>,
4835 removed: &'a Node,
4836 added: &'a [&'a Node],
4837 next: Option<&'a Node>,
4838 },
4839 ReplaceAll {
4840 removed: &'a [&'a Node],
4841 added: &'a [&'a Node],
4842 },
4843 ChangeText,
4848}
4849
4850impl<'a> ChildrenMutation<'a> {
4851 fn insert(
4852 prev: Option<&'a Node>,
4853 added: &'a [&'a Node],
4854 next: Option<&'a Node>,
4855 ) -> ChildrenMutation<'a> {
4856 match (prev, next) {
4857 (None, None) => ChildrenMutation::ReplaceAll {
4858 removed: &[],
4859 added,
4860 },
4861 (Some(prev), None) => ChildrenMutation::Append { prev, added },
4862 (None, Some(next)) => ChildrenMutation::Prepend { added, next },
4863 (Some(prev), Some(next)) => ChildrenMutation::Insert { prev, added, next },
4864 }
4865 }
4866
4867 fn replace(
4868 prev: Option<&'a Node>,
4869 removed: &'a Option<&'a Node>,
4870 added: &'a [&'a Node],
4871 next: Option<&'a Node>,
4872 ) -> ChildrenMutation<'a> {
4873 if let Some(ref removed) = *removed {
4874 if let (None, None) = (prev, next) {
4875 ChildrenMutation::ReplaceAll {
4876 removed: from_ref(removed),
4877 added,
4878 }
4879 } else {
4880 ChildrenMutation::Replace {
4881 prev,
4882 removed,
4883 added,
4884 next,
4885 }
4886 }
4887 } else {
4888 ChildrenMutation::insert(prev, added, next)
4889 }
4890 }
4891
4892 fn replace_all(removed: &'a [&'a Node], added: &'a [&'a Node]) -> ChildrenMutation<'a> {
4893 ChildrenMutation::ReplaceAll { removed, added }
4894 }
4895
4896 pub(crate) fn next_child(&self) -> Option<&Node> {
4901 match *self {
4902 ChildrenMutation::Append { .. } => None,
4903 ChildrenMutation::Insert { next, .. } => Some(next),
4904 ChildrenMutation::Prepend { next, .. } => Some(next),
4905 ChildrenMutation::Replace { next, .. } => next,
4906 ChildrenMutation::ReplaceAll { .. } => None,
4907 ChildrenMutation::ChangeText => None,
4908 }
4909 }
4910
4911 pub(crate) fn modified_edge_element(&self, no_gc: &NoGC) -> Option<DomRoot<Node>> {
4918 match *self {
4919 ChildrenMutation::Prepend { next, .. } |
4921 ChildrenMutation::Replace {
4922 prev: None,
4923 next: Some(next),
4924 ..
4925 } => next
4926 .inclusively_following_siblings_unrooted(no_gc)
4927 .find(|node| node.is::<Element>())
4928 .map(|node| node.as_rooted()),
4929 ChildrenMutation::Append { prev, .. } |
4931 ChildrenMutation::Replace {
4932 prev: Some(prev),
4933 next: None,
4934 ..
4935 } => prev
4936 .inclusively_preceding_siblings_unrooted(no_gc)
4937 .find(|node| node.is::<Element>())
4938 .map(|node| node.as_rooted()),
4939 ChildrenMutation::Insert { prev, next, .. } |
4941 ChildrenMutation::Replace {
4942 prev: Some(prev),
4943 next: Some(next),
4944 ..
4945 } => {
4946 if prev
4947 .inclusively_preceding_siblings_unrooted(no_gc)
4948 .all(|node| !node.is::<Element>())
4949 {
4950 next.inclusively_following_siblings_unrooted(no_gc)
4952 .find(|node| node.is::<Element>())
4953 .map(|node| node.as_rooted())
4954 } else if next
4955 .inclusively_following_siblings_unrooted(no_gc)
4956 .all(|node| !node.is::<Element>())
4957 {
4958 prev.inclusively_preceding_siblings_unrooted(no_gc)
4960 .find(|node| node.is::<Element>())
4961 .map(|node| node.as_rooted())
4962 } else {
4963 None
4964 }
4965 },
4966
4967 ChildrenMutation::Replace {
4968 prev: None,
4969 next: None,
4970 ..
4971 } => unreachable!(),
4972 ChildrenMutation::ReplaceAll { .. } => None,
4973 ChildrenMutation::ChangeText => None,
4974 }
4975 }
4976}
4977
4978pub(crate) struct BindContext<'a> {
4980 pub(crate) parent: &'a Node,
4982
4983 pub(crate) tree_connected: bool,
4987
4988 pub(crate) tree_is_in_a_document_tree: bool,
4992
4993 pub(crate) tree_is_in_a_shadow_tree: bool,
4995
4996 pub(crate) is_shadow_tree: IsShadowTree,
5001}
5002
5003#[derive(Debug, Eq, PartialEq)]
5004pub(crate) enum IsShadowTree {
5005 Yes,
5006 No,
5007}
5008
5009impl<'a> BindContext<'a> {
5010 pub(crate) fn new(parent: &'a Node, is_shadow_tree: IsShadowTree) -> Self {
5012 BindContext {
5013 parent,
5014 tree_connected: parent.is_connected(),
5015 tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
5016 tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
5017 is_shadow_tree,
5018 }
5019 }
5020
5021 pub(crate) fn is_in_tree(&self) -> bool {
5023 self.tree_is_in_a_document_tree || self.tree_is_in_a_shadow_tree
5024 }
5025}
5026
5027pub(crate) struct UnbindContext<'a> {
5030 index: Cell<Option<u32>>,
5032 pub(crate) parent: &'a Node,
5034 prev_sibling: Option<&'a Node>,
5036 pub(crate) next_sibling: Option<&'a Node>,
5038
5039 pub(crate) tree_connected: bool,
5043
5044 pub(crate) tree_is_in_a_document_tree: bool,
5048
5049 pub(crate) tree_is_in_a_shadow_tree: bool,
5051}
5052
5053impl<'a> UnbindContext<'a> {
5054 pub(crate) fn new(
5056 parent: &'a Node,
5057 prev_sibling: Option<&'a Node>,
5058 next_sibling: Option<&'a Node>,
5059 cached_index: Option<u32>,
5060 ) -> Self {
5061 UnbindContext {
5062 index: Cell::new(cached_index),
5063 parent,
5064 prev_sibling,
5065 next_sibling,
5066 tree_connected: parent.is_connected(),
5067 tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
5068 tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
5069 }
5070 }
5071
5072 pub(crate) fn index(&self) -> u32 {
5074 if let Some(index) = self.index.get() {
5075 return index;
5076 }
5077 let index = self.prev_sibling.map_or(0, |sibling| sibling.index() + 1);
5078 self.index.set(Some(index));
5079 index
5080 }
5081}
5082
5083pub(crate) struct MoveContext<'a> {
5086 index: Cell<Option<u32>>,
5088 pub(crate) old_parent: Option<&'a Node>,
5090 prev_sibling: Option<&'a Node>,
5092 pub(crate) next_sibling: Option<&'a Node>,
5094}
5095
5096impl<'a> MoveContext<'a> {
5097 pub(crate) fn new(
5099 old_parent: Option<&'a Node>,
5100 prev_sibling: Option<&'a Node>,
5101 next_sibling: Option<&'a Node>,
5102 cached_index: Option<u32>,
5103 ) -> Self {
5104 MoveContext {
5105 index: Cell::new(cached_index),
5106 old_parent,
5107 prev_sibling,
5108 next_sibling,
5109 }
5110 }
5111
5112 pub(crate) fn index(&self) -> u32 {
5114 if let Some(index) = self.index.get() {
5115 return index;
5116 }
5117 let index = self.prev_sibling.map_or(0, |sibling| sibling.index() + 1);
5118 self.index.set(Some(index));
5119 index
5120 }
5121}
5122
5123pub(crate) struct UniqueId {
5125 cell: UnsafeCell<Option<Box<Uuid>>>,
5126}
5127
5128unsafe_no_jsmanaged_fields!(UniqueId);
5129
5130impl MallocSizeOf for UniqueId {
5131 #[expect(unsafe_code)]
5132 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
5133 if let Some(uuid) = unsafe { &*self.cell.get() } {
5134 unsafe { ops.malloc_size_of(&**uuid) }
5135 } else {
5136 0
5137 }
5138 }
5139}
5140
5141impl UniqueId {
5142 fn new() -> UniqueId {
5144 UniqueId {
5145 cell: UnsafeCell::new(None),
5146 }
5147 }
5148
5149 #[expect(unsafe_code)]
5151 fn borrow(&self) -> &Uuid {
5152 unsafe {
5153 let ptr = self.cell.get();
5154 if (*ptr).is_none() {
5155 *ptr = Some(Box::new(Uuid::new_v4()));
5156 }
5157 (*ptr).as_ref().unwrap()
5158 }
5159 }
5160}
5161
5162pub(crate) struct NodeTypeIdWrapper(pub(crate) NodeTypeId);
5163
5164impl From<NodeTypeIdWrapper> for LayoutNodeType {
5165 #[inline(always)]
5166 fn from(node_type: NodeTypeIdWrapper) -> LayoutNodeType {
5167 match node_type.0 {
5168 NodeTypeId::Element(e) => LayoutNodeType::Element(ElementTypeIdWrapper(e).into()),
5169 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => LayoutNodeType::Text,
5170 x => unreachable!("Layout should not traverse nodes of type {:?}", x),
5171 }
5172 }
5173}
5174
5175struct ElementTypeIdWrapper(ElementTypeId);
5176
5177impl From<ElementTypeIdWrapper> for LayoutElementType {
5178 #[inline(always)]
5179 fn from(element_type: ElementTypeIdWrapper) -> LayoutElementType {
5180 match element_type.0 {
5181 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement) => {
5182 LayoutElementType::HTMLBodyElement
5183 },
5184 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBRElement) => {
5185 LayoutElementType::HTMLBRElement
5186 },
5187 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement) => {
5188 LayoutElementType::HTMLCanvasElement
5189 },
5190 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHtmlElement) => {
5191 LayoutElementType::HTMLHtmlElement
5192 },
5193 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement) => {
5194 LayoutElementType::HTMLIFrameElement
5195 },
5196 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement) => {
5197 LayoutElementType::HTMLImageElement
5198 },
5199 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(_)) => {
5200 LayoutElementType::HTMLMediaElement
5201 },
5202 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement) => {
5203 LayoutElementType::HTMLInputElement
5204 },
5205 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement) => {
5206 LayoutElementType::HTMLOptGroupElement
5207 },
5208 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement) => {
5209 LayoutElementType::HTMLOptionElement
5210 },
5211 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement) => {
5212 LayoutElementType::HTMLObjectElement
5213 },
5214 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLParagraphElement) => {
5215 LayoutElementType::HTMLParagraphElement
5216 },
5217 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLPreElement) => {
5218 LayoutElementType::HTMLPreElement
5219 },
5220 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement) => {
5221 LayoutElementType::HTMLSelectElement
5222 },
5223 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableCellElement) => {
5224 LayoutElementType::HTMLTableCellElement
5225 },
5226 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement) => {
5227 LayoutElementType::HTMLTableColElement
5228 },
5229 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement) => {
5230 LayoutElementType::HTMLTableElement
5231 },
5232 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement) => {
5233 LayoutElementType::HTMLTableRowElement
5234 },
5235 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement) => {
5236 LayoutElementType::HTMLTableSectionElement
5237 },
5238 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement) => {
5239 LayoutElementType::HTMLTextAreaElement
5240 },
5241 ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
5242 SVGGraphicsElementTypeId::SVGImageElement,
5243 )) => LayoutElementType::SVGImageElement,
5244 ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
5245 SVGGraphicsElementTypeId::SVGSVGElement,
5246 )) => LayoutElementType::SVGSVGElement,
5247 _ => LayoutElementType::Element,
5248 }
5249 }
5250}
5251
5252pub(crate) trait VecPreOrderInsertionHelper<T> {
5255 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
5256}
5257
5258impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
5259where
5260 T: DerivedFrom<Node> + DomObject,
5261{
5262 fn insert_pre_order(&mut self, node: &T, tree_root: &Node) {
5267 let Err(insertion_index) = self.binary_search_by(|candidate| {
5268 candidate
5269 .upcast()
5270 .compare_dom_tree_position(node.upcast(), tree_root)
5271 }) else {
5272 return;
5275 };
5276
5277 self.insert(insertion_index, Dom::from_ref(node));
5278 }
5279}