1use std::borrow::Cow;
8use std::cell::{Cell, LazyCell, UnsafeCell};
9use std::default::Default;
10use std::f64::consts::PI;
11use std::marker::PhantomData;
12use std::ops::Deref;
13use std::slice::from_ref;
14use std::{cmp, fmt, iter};
15
16use app_units::Au;
17use bitflags::bitflags;
18use devtools_traits::NodeInfo;
19use dom_struct::dom_struct;
20use embedder_traits::UntrustedNodeAddress;
21use euclid::default::Size2D;
22use euclid::{Point2D, Rect};
23use html5ever::serialize::HtmlSerializer;
24use html5ever::{Namespace, Prefix, QualName, ns, serialize as html_serialize};
25use js::context::{JSContext, NoGC};
26use js::jsapi::JSObject;
27use js::rust::HandleObject;
28use keyboard_types::Modifiers;
29use layout_api::wrapper_traits::SharedSelection;
30use layout_api::{
31 AxesOverflow, BoxAreaType, CSSPixelRectIterator, GenericLayoutData, HTMLCanvasData,
32 HTMLMediaData, LayoutElementType, LayoutNodeType, PhysicalSides, QueryMsg, SVGElementData,
33 StyleData, 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::codegen::GenericBindings::EventBinding::EventMethods;
40use script_bindings::codegen::InheritTypes::DocumentFragmentTypeId;
41use script_traits::DocumentActivity;
42use servo_arc::Arc as ServoArc;
43use servo_base::id::{BrowsingContextId, PipelineId};
44use servo_config::pref;
45use servo_url::ServoUrl;
46use smallvec::SmallVec;
47use style::Atom;
48use style::attr::AttrValue;
49use style::context::QuirksMode;
50use style::dom::OpaqueNode;
51use style::dom_apis::{QueryAll, QueryFirst};
52use style::properties::ComputedValues;
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::cell::{DomRefCell, Ref, RefMut};
63use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
64use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
65use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
66use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
67use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
68use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
69use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
70use crate::dom::bindings::codegen::Bindings::NodeBinding::{
71 GetRootNodeOptions, NodeConstants, NodeMethods,
72};
73use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
74use crate::dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
75use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
76use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
77 ShadowRootMode, SlotAssignmentMode,
78};
79use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
80use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
81use crate::dom::bindings::conversions::{self, DerivedFrom};
82use crate::dom::bindings::domname::namespace_from_domstring;
83use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
84use crate::dom::bindings::inheritance::{
85 Castable, CharacterDataTypeId, ElementTypeId, EventTargetTypeId, HTMLElementTypeId, NodeTypeId,
86 SVGElementTypeId, SVGGraphicsElementTypeId, TextTypeId,
87};
88use crate::dom::bindings::reflector::{
89 DomObject, DomObjectWrap, reflect_dom_object_with_proto_and_cx,
90};
91use crate::dom::bindings::root::{
92 Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout, UnrootedDom,
93};
94use crate::dom::bindings::str::{DOMString, USVString};
95use crate::dom::characterdata::{CharacterData, LayoutCharacterDataHelpers};
96use crate::dom::css::cssstylesheet::CSSStyleSheet;
97use crate::dom::css::stylesheetlist::StyleSheetListOwner;
98use crate::dom::customelementregistry::{
99 CallbackReaction, CustomElementRegistry, try_upgrade_element,
100};
101use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
102use crate::dom::documentfragment::DocumentFragment;
103use crate::dom::documenttype::DocumentType;
104use crate::dom::element::{
105 AttributeMutationReason, CustomElementCreationMode, Element, ElementCreator,
106};
107use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
108use crate::dom::eventtarget::EventTarget;
109use crate::dom::globalscope::GlobalScope;
110use crate::dom::html::htmlcanvaselement::{HTMLCanvasElement, LayoutHTMLCanvasElementHelpers};
111use crate::dom::html::htmlcollection::HTMLCollection;
112use crate::dom::html::htmlelement::HTMLElement;
113use crate::dom::html::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
114use crate::dom::html::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
115use crate::dom::html::htmllinkelement::HTMLLinkElement;
116use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
117use crate::dom::html::htmlstyleelement::HTMLStyleElement;
118use crate::dom::html::htmltextareaelement::{
119 HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers,
120};
121use crate::dom::html::htmlvideoelement::{HTMLVideoElement, LayoutHTMLVideoElementHelpers};
122use crate::dom::html::input_element::{HTMLInputElement, LayoutHTMLInputElementHelpers};
123use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
124use crate::dom::node::nodelist::NodeList;
125use crate::dom::pointerevent::{PointerEvent, PointerId};
126use crate::dom::processinginstruction::ProcessingInstruction;
127use crate::dom::range::WeakRangeVec;
128use crate::dom::raredata::NodeRareData;
129use crate::dom::servoparser::html::HtmlSerialize;
130use crate::dom::servoparser::{ServoParser, serialize_html_fragment};
131use crate::dom::shadowroot::{IsUserAgentWidget, LayoutShadowRootHelpers, ShadowRoot};
132use crate::dom::svg::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement};
133use crate::dom::text::Text;
134use crate::dom::types::{CDATASection, KeyboardEvent};
135use crate::dom::virtualmethods::{VirtualMethods, vtable_for};
136use crate::dom::window::Window;
137use crate::layout_dom::ServoLayoutNode;
138use crate::script_runtime::CanGc;
139use crate::script_thread::ScriptThread;
140
141#[dom_struct]
147pub struct Node {
148 eventtarget: EventTarget,
150
151 parent_node: MutNullableDom<Node>,
153
154 first_child: MutNullableDom<Node>,
156
157 last_child: MutNullableDom<Node>,
159
160 next_sibling: MutNullableDom<Node>,
162
163 prev_sibling: MutNullableDom<Node>,
165
166 owner_doc: MutNullableDom<Document>,
168
169 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
171
172 children_count: Cell<u32>,
174
175 flags: Cell<NodeFlags>,
177
178 inclusive_descendants_version: Cell<u64>,
180
181 #[no_trace]
184 style_data: DomRefCell<Option<Box<StyleData>>>,
185
186 #[no_trace]
189 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
190}
191
192impl fmt::Debug for Node {
193 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
194 if matches!(self.type_id(), NodeTypeId::Element(_)) {
195 let el = self.downcast::<Element>().unwrap();
196 el.fmt(f)
197 } else {
198 write!(f, "[Node({:?})]", self.type_id())
199 }
200 }
201}
202
203#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
205pub(crate) struct NodeFlags(u16);
206
207bitflags! {
208 impl NodeFlags: u16 {
209 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
213
214 const HAS_DIRTY_DESCENDANTS = 1 << 1;
216
217 const CLICK_IN_PROGRESS = 1 << 2;
220
221 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
226
227 const HAS_SNAPSHOT = 1 << 7;
232
233 const HANDLED_SNAPSHOT = 1 << 8;
235
236 const IS_IN_SHADOW_TREE = 1 << 9;
238
239 const IS_CONNECTED = 1 << 10;
243
244 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
247
248 const IS_IN_UA_WIDGET = 1 << 12;
251
252 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
254 }
255}
256
257#[derive(Clone, Copy, MallocSizeOf)]
261enum SuppressObserver {
262 Suppressed,
263 Unsuppressed,
264}
265
266pub(crate) enum ForceSlottableNodeReconciliation {
267 Force,
268 Skip,
269}
270
271impl Node {
272 fn add_child(&self, cx: &mut JSContext, new_child: &Node, before: Option<&Node>) {
276 assert!(new_child.parent_node.get().is_none());
277 assert!(new_child.prev_sibling.get().is_none());
278 assert!(new_child.next_sibling.get().is_none());
279 match before {
280 Some(before) => {
281 assert!(before.parent_node.get().as_deref() == Some(self));
282 let prev_sibling = before.GetPreviousSibling();
283 match prev_sibling {
284 None => {
285 assert!(self.first_child.get().as_deref() == Some(before));
286 self.first_child.set(Some(new_child));
287 },
288 Some(ref prev_sibling) => {
289 prev_sibling.next_sibling.set(Some(new_child));
290 new_child.prev_sibling.set(Some(prev_sibling));
291 },
292 }
293 before.prev_sibling.set(Some(new_child));
294 new_child.next_sibling.set(Some(before));
295 },
296 None => {
297 let last_child = self.GetLastChild();
298 match last_child {
299 None => self.first_child.set(Some(new_child)),
300 Some(ref last_child) => {
301 assert!(last_child.next_sibling.get().is_none());
302 last_child.next_sibling.set(Some(new_child));
303 new_child.prev_sibling.set(Some(last_child));
304 },
305 }
306
307 self.last_child.set(Some(new_child));
308 },
309 }
310
311 new_child.parent_node.set(Some(self));
312 self.children_count.set(self.children_count.get() + 1);
313
314 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
315 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
316 let parent_is_connected = self.is_connected();
317 let parent_is_in_ua_widget = self.is_in_ua_widget();
318
319 let context = BindContext::new(self, IsShadowTree::No);
320
321 for node in new_child.traverse_preorder(ShadowIncluding::No) {
322 if parent_in_shadow_tree {
323 if let Some(shadow_root) = self.containing_shadow_root() {
324 node.set_containing_shadow_root(Some(&*shadow_root));
325 }
326 debug_assert!(node.containing_shadow_root().is_some());
327 }
328 node.set_flag(
329 NodeFlags::IS_IN_A_DOCUMENT_TREE,
330 parent_is_in_a_document_tree,
331 );
332 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
333 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
334 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
335
336 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
338 vtable_for(&node).bind_to_tree(cx, &context);
339 }
340 }
341
342 pub(crate) fn unsafely_set_html(
345 target: &Node,
346 context_element: &Element,
347 html: DOMString,
348 cx: &mut JSContext,
349 ) {
350 let new_children = ServoParser::parse_html_fragment(context_element, html, true, cx);
352
353 let context_document = context_element.owner_document();
356 let fragment = DocumentFragment::new(cx, &context_document);
357
358 for child in new_children {
360 fragment.upcast::<Node>().AppendChild(cx, &child).unwrap();
361 }
362
363 Node::replace_all(cx, Some(fragment.upcast()), target);
365 }
366
367 pub(crate) fn remove_layout_boxes_from_subtree(&self) {
371 for node in self.traverse_preorder(ShadowIncluding::Yes) {
372 node.layout_data.borrow_mut().take();
373 }
374 }
375
376 pub(crate) fn clean_up_style_and_layout_data(&self) {
377 self.owner_doc().cancel_animations_for_node(self);
378 self.style_data.borrow_mut().take();
379 self.layout_data.borrow_mut().take();
380 }
381
382 pub(crate) fn complete_remove_subtree(root: &Node, context: &UnbindContext, can_gc: CanGc) {
385 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
387 .union(NodeFlags::IS_CONNECTED)
388 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
389 .union(NodeFlags::HAS_SNAPSHOT)
390 .union(NodeFlags::HANDLED_SNAPSHOT);
391
392 for node in root.traverse_preorder(ShadowIncluding::No) {
393 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
394
395 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
398 for node in shadow_root
399 .upcast::<Node>()
400 .traverse_preorder(ShadowIncluding::Yes)
401 {
402 node.set_flag(RESET_FLAGS, false);
403 }
404 }
405 }
406
407 let is_parent_connected = context.parent.is_connected();
409 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
410
411 let cleanup_node = |node: &Node| {
414 node.clean_up_style_and_layout_data();
415
416 vtable_for(node).unbind_from_tree(context, can_gc);
421
422 if is_parent_connected {
424 if let Some(element) = node.as_custom_element() {
425 custom_element_reaction_stack.enqueue_callback_reaction(
426 &element,
427 CallbackReaction::Disconnected,
428 None,
429 );
430 }
431 }
432 };
433
434 for node in root.traverse_preorder(ShadowIncluding::No) {
435 cleanup_node(&node);
436
437 if node.containing_shadow_root().is_some() {
440 node.set_containing_shadow_root(None);
443 }
444
445 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
448 for node in shadow_root
449 .upcast::<Node>()
450 .traverse_preorder(ShadowIncluding::Yes)
451 {
452 cleanup_node(&node);
453 }
454 }
455 }
456 }
457
458 pub(crate) fn complete_move_subtree(root: &Node) {
459 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
461 .union(NodeFlags::IS_CONNECTED)
462 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
463 .union(NodeFlags::HAS_SNAPSHOT)
464 .union(NodeFlags::HANDLED_SNAPSHOT);
465
466 let cleanup_node = |node: &Node| {
469 node.style_data.borrow_mut().take();
470 node.layout_data.borrow_mut().take();
471 };
472
473 for node in root.traverse_preorder(ShadowIncluding::No) {
474 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
475 cleanup_node(&node);
476
477 if node.containing_shadow_root().is_some() {
480 node.set_containing_shadow_root(None);
483 }
484
485 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
489 for node in shadow_root
490 .upcast::<Node>()
491 .traverse_preorder(ShadowIncluding::Yes)
492 {
493 node.set_flag(RESET_FLAGS, false);
494 cleanup_node(&node);
495 }
496 }
497 }
498 }
499
500 fn remove_child(&self, child: &Node, cached_index: Option<u32>, can_gc: CanGc) {
504 assert!(child.parent_node.get().as_deref() == Some(self));
505 self.note_dirty_descendants();
506
507 let prev_sibling = child.GetPreviousSibling();
508 match prev_sibling {
509 None => {
510 self.first_child.set(child.next_sibling.get().as_deref());
511 },
512 Some(ref prev_sibling) => {
513 prev_sibling
514 .next_sibling
515 .set(child.next_sibling.get().as_deref());
516 },
517 }
518 let next_sibling = child.GetNextSibling();
519 match next_sibling {
520 None => {
521 self.last_child.set(child.prev_sibling.get().as_deref());
522 },
523 Some(ref next_sibling) => {
524 next_sibling
525 .prev_sibling
526 .set(child.prev_sibling.get().as_deref());
527 },
528 }
529
530 let context = UnbindContext::new(
531 self,
532 prev_sibling.as_deref(),
533 next_sibling.as_deref(),
534 cached_index,
535 );
536
537 child.prev_sibling.set(None);
538 child.next_sibling.set(None);
539 child.parent_node.set(None);
540 self.children_count.set(self.children_count.get() - 1);
541
542 Self::complete_remove_subtree(child, &context, can_gc);
543 }
544
545 fn move_child(&self, child: &Node) {
546 assert!(child.parent_node.get().as_deref() == Some(self));
547 self.note_dirty_descendants();
548
549 child.prev_sibling.set(None);
550 child.next_sibling.set(None);
551 child.parent_node.set(None);
552 self.children_count.set(self.children_count.get() - 1);
553 Self::complete_move_subtree(child)
554 }
555
556 pub(crate) fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
557 UntrustedNodeAddress(self.reflector().get_jsobject().get() as *const c_void)
558 }
559
560 pub(crate) fn to_opaque(&self) -> OpaqueNode {
561 OpaqueNode(self.reflector().get_jsobject().get() as usize)
562 }
563
564 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
565 self.downcast::<Element>().and_then(|element| {
566 if element.is_custom() {
567 assert!(element.get_custom_element_definition().is_some());
568 Some(DomRoot::from_ref(element))
569 } else {
570 None
571 }
572 })
573 }
574
575 pub(crate) fn fire_synthetic_pointer_event_not_trusted(&self, event_type: Atom, can_gc: CanGc) {
577 let window = self.owner_window();
581
582 let pointer_event = PointerEvent::new(
584 &window, event_type,
586 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![], can_gc,
613 );
614
615 pointer_event.upcast::<Event>().set_composed(true);
617
618 pointer_event.upcast::<Event>().set_trusted(false);
620
621 pointer_event
624 .upcast::<Event>()
625 .dispatch(self.upcast::<EventTarget>(), false, can_gc);
626 }
627
628 pub(crate) fn parent_directionality(&self) -> String {
629 let mut current = self.GetParentNode();
630
631 loop {
632 match current {
633 Some(node) => {
634 if let Some(directionality) = node
635 .downcast::<HTMLElement>()
636 .and_then(|html_element| html_element.directionality())
637 {
638 return directionality;
639 } else {
640 current = node.GetParentNode();
641 }
642 },
643 None => return "ltr".to_owned(),
644 }
645 }
646 }
647}
648
649impl Node {
650 fn rare_data(&self) -> Ref<'_, Option<Box<NodeRareData>>> {
651 self.rare_data.borrow()
652 }
653
654 fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
655 let mut rare_data = self.rare_data.borrow_mut();
656 if rare_data.is_none() {
657 *rare_data = Some(Default::default());
658 }
659 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
660 }
661
662 pub(crate) fn is_before(&self, other: &Node) -> bool {
665 let cmp = other.CompareDocumentPosition(self);
666 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
667 return false;
668 }
669
670 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
671 }
672
673 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
676 RefMut::map(self.ensure_rare_data(), |rare_data| {
677 &mut rare_data.mutation_observers
678 })
679 }
680
681 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
682 let rare_data: Ref<'_, _> = self.rare_data.borrow();
683
684 if rare_data.is_none() {
685 return None;
686 }
687 Some(Ref::map(rare_data, |rare_data| {
688 &rare_data.as_ref().unwrap().mutation_observers
689 }))
690 }
691
692 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
694 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
695 self.ensure_rare_data().mutation_observers.push(observer);
696 }
697
698 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
700 self.ensure_rare_data()
701 .mutation_observers
702 .retain(|reg_obs| &*reg_obs.observer != observer)
703 }
704
705 pub(crate) fn dump(&self) {
707 self.dump_indent(0);
708 }
709
710 pub(crate) fn dump_indent(&self, indent: u32) {
712 let mut s = String::new();
713 for _ in 0..indent {
714 s.push_str(" ");
715 }
716
717 s.push_str(&self.debug_str());
718 debug!("{:?}", s);
719
720 for kid in self.children() {
722 kid.dump_indent(indent + 1)
723 }
724 }
725
726 pub(crate) fn debug_str(&self) -> String {
728 format!("{:?}", self.type_id())
729 }
730
731 pub(crate) fn is_in_a_document_tree(&self) -> bool {
733 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
734 }
735
736 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
738 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
739 }
740
741 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
742 self.flags
743 .get()
744 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
745 }
746
747 pub(crate) fn set_weird_parser_insertion_mode(&self) {
748 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
749 }
750
751 pub(crate) fn is_connected(&self) -> bool {
753 self.flags.get().contains(NodeFlags::IS_CONNECTED)
754 }
755
756 pub(crate) fn set_in_ua_widget(&self, in_ua_widget: bool) {
757 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, in_ua_widget)
758 }
759
760 pub(crate) fn is_in_ua_widget(&self) -> bool {
761 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
762 }
763
764 pub(crate) fn type_id(&self) -> NodeTypeId {
766 match *self.eventtarget.type_id() {
767 EventTargetTypeId::Node(type_id) => type_id,
768 _ => unreachable!(),
769 }
770 }
771
772 pub(crate) fn len(&self) -> u32 {
774 match self.type_id() {
775 NodeTypeId::DocumentType => 0,
776 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
777 _ => self.children_count(),
778 }
779 }
780
781 pub(crate) fn is_empty(&self) -> bool {
782 self.len() == 0
784 }
785
786 pub(crate) fn index(&self) -> u32 {
788 self.preceding_siblings().count() as u32
789 }
790
791 pub(crate) fn has_parent(&self) -> bool {
793 self.parent_node.get().is_some()
794 }
795
796 pub(crate) fn children_count(&self) -> u32 {
797 self.children_count.get()
798 }
799
800 pub(crate) fn ranges(&self) -> RefMut<'_, WeakRangeVec> {
801 RefMut::map(self.ensure_rare_data(), |rare_data| &mut rare_data.ranges)
802 }
803
804 pub(crate) fn ranges_is_empty(&self) -> bool {
805 self.rare_data()
806 .as_ref()
807 .is_none_or(|data| data.ranges.is_empty())
808 }
809
810 #[inline]
811 pub(crate) fn is_doctype(&self) -> bool {
812 self.type_id() == NodeTypeId::DocumentType
813 }
814
815 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
816 self.flags.get().contains(flag)
817 }
818
819 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
820 let mut flags = self.flags.get();
821
822 if value {
823 flags.insert(flag);
824 } else {
825 flags.remove(flag);
826 }
827
828 self.flags.set(flags);
829 }
830
831 pub(crate) fn note_dirty_descendants(&self) {
833 self.owner_doc().note_node_with_dirty_descendants(self);
834 }
835
836 pub(crate) fn has_dirty_descendants(&self) -> bool {
837 self.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)
838 }
839
840 pub(crate) fn rev_version(&self) {
841 let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
846 let version = cmp::max(
847 self.inclusive_descendants_version(),
848 doc.inclusive_descendants_version(),
849 ) + 1;
850
851 let mut node = &MutNullableDom::new(Some(self));
854 while let Some(p) = node.if_is_some(|p| {
855 p.inclusive_descendants_version.set(version);
856 &p.parent_node
857 }) {
858 node = p
859 }
860 doc.inclusive_descendants_version.set(version);
861 }
862
863 pub(crate) fn dirty(&self, damage: NodeDamage) {
864 self.rev_version();
865 if !self.is_connected() {
866 return;
867 }
868
869 match self.type_id() {
870 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
871 self.parent_node
875 .get()
876 .unwrap()
877 .dirty(NodeDamage::ContentOrHeritage)
878 },
879 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(damage),
880 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
881 .downcast::<ShadowRoot>()
882 .unwrap()
883 .Host()
884 .upcast::<Element>()
885 .restyle(damage),
886 _ => {},
887 };
888 }
889
890 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
892 self.inclusive_descendants_version.get()
893 }
894
895 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
897 TreeIterator::new(self, shadow_including)
898 }
899
900 pub(crate) fn traverse_preorder_non_rooting<'a, 'b>(
902 &'a self,
903 no_gc: &'b NoGC,
904 shadow_including: ShadowIncluding,
905 ) -> UnrootedTreeIterator<'a, 'b>
906 where
907 'b: 'a,
908 {
909 UnrootedTreeIterator::new(self, shadow_including, no_gc)
910 }
911
912 pub(crate) fn inclusively_following_siblings(
913 &self,
914 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
915 SimpleNodeIterator {
916 current: Some(DomRoot::from_ref(self)),
917 next_node: |n| n.GetNextSibling(),
918 }
919 }
920
921 pub(crate) fn inclusively_following_siblings_unrooted<'b>(
922 &self,
923 no_gc: &'b NoGC,
924 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
925 UnrootedSimpleNodeIterator {
926 current: Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
927 next_node: |n, no_gc| n.get_next_sibling_unrooted(no_gc),
928 no_gc,
929 phantom: PhantomData,
930 }
931 }
932
933 pub(crate) fn inclusively_preceding_siblings(
934 &self,
935 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
936 SimpleNodeIterator {
937 current: Some(DomRoot::from_ref(self)),
938 next_node: |n| n.GetPreviousSibling(),
939 }
940 }
941
942 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
943 &self,
944 no_gc: &'b NoGC,
945 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
946 UnrootedSimpleNodeIterator {
947 current: Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
948 next_node: |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
949 no_gc,
950 phantom: PhantomData,
951 }
952 }
953
954 pub(crate) fn common_ancestor(
955 &self,
956 other: &Node,
957 shadow_including: ShadowIncluding,
958 ) -> Option<DomRoot<Node>> {
959 self.inclusive_ancestors(shadow_including).find(|ancestor| {
960 other
961 .inclusive_ancestors(shadow_including)
962 .any(|node| node == *ancestor)
963 })
964 }
965
966 pub(crate) fn common_ancestor_in_flat_tree(&self, other: &Node) -> Option<DomRoot<Node>> {
967 self.inclusive_ancestors_in_flat_tree().find(|ancestor| {
968 other
969 .inclusive_ancestors_in_flat_tree()
970 .any(|node| node == *ancestor)
971 })
972 }
973
974 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
976 self == child || self.is_ancestor_of(child)
978 }
979
980 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
982 let mut current = &possible_descendant.parent_node;
984 let mut done = false;
985
986 while let Some(node) = current.if_is_some(|node| {
987 done = node == self;
988 &node.parent_node
989 }) {
990 if done {
991 break;
992 }
993 current = node
994 }
995 done
996 }
997
998 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
1000 self.is_inclusive_ancestor_of(child) ||
1003 child
1004 .GetRootNode(&GetRootNodeOptions::empty())
1005 .downcast::<DocumentFragment>()
1006 .and_then(|fragment| fragment.host())
1007 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1008 }
1009
1010 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1012 node.inclusive_ancestors(ShadowIncluding::Yes)
1013 .any(|ancestor| &*ancestor == self)
1014 }
1015
1016 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1017 SimpleNodeIterator {
1018 current: self.GetNextSibling(),
1019 next_node: |n| n.GetNextSibling(),
1020 }
1021 }
1022
1023 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1024 SimpleNodeIterator {
1025 current: self.GetPreviousSibling(),
1026 next_node: |n| n.GetPreviousSibling(),
1027 }
1028 }
1029
1030 pub(crate) fn following_nodes(&self, root: &Node) -> FollowingNodeIterator {
1031 FollowingNodeIterator {
1032 current: Some(DomRoot::from_ref(self)),
1033 root: DomRoot::from_ref(root),
1034 }
1035 }
1036
1037 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1038 PrecedingNodeIterator {
1039 current: Some(DomRoot::from_ref(self)),
1040 root: DomRoot::from_ref(root),
1041 }
1042 }
1043
1044 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1047 SimpleNodeIterator {
1048 current: self.GetLastChild(),
1049 next_node: |n| n.GetLastChild(),
1050 }
1051 }
1052
1053 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1054 child
1055 .parent_node
1056 .get()
1057 .is_some_and(|parent| &*parent == self)
1058 }
1059
1060 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1061 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1062 }
1063
1064 pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1065 self.owner_window().padding_query_without_reflow(self)
1066 }
1067
1068 pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1069 self.owner_window()
1070 .box_area_query(self, BoxAreaType::Content, false)
1071 }
1072
1073 pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1074 self.owner_window()
1075 .box_area_query(self, BoxAreaType::Border, false)
1076 }
1077
1078 pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1079 self.owner_window()
1080 .box_area_query(self, BoxAreaType::Padding, false)
1081 }
1082
1083 pub(crate) fn border_boxes(&self) -> CSSPixelRectIterator {
1084 self.owner_window()
1085 .box_areas_query(self, BoxAreaType::Border)
1086 }
1087
1088 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1089 self.owner_window().client_rect_query(self)
1090 }
1091
1092 pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1095 let document = self.owner_doc();
1097
1098 if !document.is_active() {
1100 return Rect::zero();
1101 }
1102
1103 let window = document.window();
1106 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1107
1108 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1109 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1110 let is_body_element = self
1111 .downcast::<HTMLElement>()
1112 .is_some_and(|e| e.is_body_element());
1113
1114 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1120 let viewport_scrolling_area = window.scrolling_area_query(None);
1121 return Rect::new(
1122 viewport_scrolling_area.origin,
1123 viewport_scrolling_area.size.max(viewport),
1124 );
1125 }
1126
1127 window.scrolling_area_query(Some(self))
1131 }
1132
1133 pub(crate) fn effective_overflow(&self) -> Option<AxesOverflow> {
1134 self.owner_window().query_effective_overflow(self)
1135 }
1136
1137 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1138 self.owner_window()
1139 .query_effective_overflow_without_reflow(self)
1140 }
1141
1142 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1144 let parent = &self.parent_node;
1146
1147 let parent = match parent.get() {
1149 None => return Ok(()),
1150 Some(parent) => parent,
1151 };
1152
1153 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1155
1156 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1158
1159 let viable_previous_sibling = match viable_previous_sibling {
1161 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1162 None => parent.first_child.get(),
1163 };
1164
1165 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1167
1168 Ok(())
1169 }
1170
1171 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1173 let parent = &self.parent_node;
1175
1176 let parent = match parent.get() {
1178 None => return Ok(()),
1179 Some(parent) => parent,
1180 };
1181
1182 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1184
1185 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1187
1188 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1190
1191 Ok(())
1192 }
1193
1194 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1196 let Some(parent) = self.GetParentNode() else {
1198 return Ok(());
1200 };
1201
1202 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1204
1205 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1207
1208 if self.parent_node == Some(&*parent) {
1209 parent.ReplaceChild(cx, &node, self)?;
1211 } else {
1212 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1214 }
1215 Ok(())
1216 }
1217
1218 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1220 let doc = self.owner_doc();
1222 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1223 let first_child = self.first_child.get();
1225 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1226 }
1227
1228 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1230 let doc = self.owner_doc();
1232 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1233 self.AppendChild(cx, &node).map(|_| ())
1235 }
1236
1237 pub(crate) fn replace_children(
1239 &self,
1240 cx: &mut JSContext,
1241 nodes: Vec<NodeOrString>,
1242 ) -> ErrorResult {
1243 let doc = self.owner_doc();
1246 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1247
1248 Node::ensure_pre_insertion_validity(&node, self, None)?;
1250
1251 Node::replace_all(cx, Some(&node), self);
1253 Ok(())
1254 }
1255
1256 pub(crate) fn move_before(
1258 &self,
1259 cx: &mut JSContext,
1260 node: &Node,
1261 child: Option<&Node>,
1262 ) -> ErrorResult {
1263 let reference_child_root;
1266 let reference_child = match child {
1267 Some(child) if child == node => {
1268 reference_child_root = node.GetNextSibling();
1269 reference_child_root.as_deref()
1270 },
1271 _ => child,
1272 };
1273
1274 Node::move_fn(cx, node, self, reference_child)
1276 }
1277
1278 fn move_fn(
1280 cx: &mut JSContext,
1281 node: &Node,
1282 new_parent: &Node,
1283 child: Option<&Node>,
1284 ) -> ErrorResult {
1285 let mut options = GetRootNodeOptions::empty();
1290 options.composed = true;
1291 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1292 return Err(Error::HierarchyRequest(None));
1293 }
1294
1295 if node.is_inclusive_ancestor_of(new_parent) {
1298 return Err(Error::HierarchyRequest(None));
1299 }
1300
1301 if let Some(child) = child {
1304 if !new_parent.is_parent_of(child) {
1305 return Err(Error::NotFound(None));
1306 }
1307 }
1308
1309 match node.type_id() {
1314 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1315 if new_parent.is::<Document>() {
1316 return Err(Error::HierarchyRequest(None));
1317 }
1318 },
1319 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1320 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1321 NodeTypeId::Element(_) => (),
1322 NodeTypeId::DocumentFragment(_) |
1323 NodeTypeId::DocumentType |
1324 NodeTypeId::Document(_) |
1325 NodeTypeId::Attr => {
1326 return Err(Error::HierarchyRequest(None));
1327 },
1328 }
1329
1330 if new_parent.is::<Document>() && node.is::<Element>() {
1334 if new_parent.child_elements().next().is_some() {
1336 return Err(Error::HierarchyRequest(None));
1337 }
1338
1339 if child.is_some_and(|child| {
1342 child
1343 .inclusively_following_siblings_unrooted(cx.no_gc())
1344 .any(|child| child.is_doctype())
1345 }) {
1346 return Err(Error::HierarchyRequest(None));
1347 }
1348 }
1349
1350 let old_parent = node
1353 .parent_node
1354 .get()
1355 .expect("old_parent should always be initialized");
1356
1357 let cached_index = Node::live_range_pre_remove_steps(node, &old_parent);
1359
1360 let old_previous_sibling = node.prev_sibling.get();
1365
1366 let old_next_sibling = node.next_sibling.get();
1368
1369 let prev_sibling = node.GetPreviousSibling();
1370 match prev_sibling {
1371 None => {
1372 old_parent
1373 .first_child
1374 .set(node.next_sibling.get().as_deref());
1375 },
1376 Some(ref prev_sibling) => {
1377 prev_sibling
1378 .next_sibling
1379 .set(node.next_sibling.get().as_deref());
1380 },
1381 }
1382 let next_sibling = node.GetNextSibling();
1383 match next_sibling {
1384 None => {
1385 old_parent
1386 .last_child
1387 .set(node.prev_sibling.get().as_deref());
1388 },
1389 Some(ref next_sibling) => {
1390 next_sibling
1391 .prev_sibling
1392 .set(node.prev_sibling.get().as_deref());
1393 },
1394 }
1395
1396 let mut context = MoveContext::new(
1397 Some(&old_parent),
1398 prev_sibling.as_deref(),
1399 next_sibling.as_deref(),
1400 cached_index,
1401 );
1402
1403 old_parent.move_child(node);
1405
1406 if let Some(slot) = node.assigned_slot() {
1408 slot.assign_slottables();
1409 }
1410
1411 if old_parent.is_in_a_shadow_tree() {
1414 if let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() {
1415 if !slot_element.has_assigned_nodes() {
1416 slot_element.signal_a_slot_change();
1417 }
1418 }
1419 }
1420
1421 let has_slot_descendant = node
1423 .traverse_preorder(ShadowIncluding::No)
1424 .any(|element| element.is::<HTMLSlotElement>());
1425 if has_slot_descendant {
1426 old_parent
1428 .GetRootNode(&GetRootNodeOptions::empty())
1429 .assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Skip);
1430
1431 node.assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Skip);
1433 }
1434
1435 if let Some(child) = child {
1437 new_parent
1442 .ranges()
1443 .increase_above(new_parent, child.index(), 1)
1444 }
1445
1446 let new_previous_sibling = child.map_or_else(
1449 || new_parent.last_child.get(),
1450 |child| child.prev_sibling.get(),
1451 );
1452
1453 new_parent.add_child(cx, node, child);
1456
1457 if let Some(shadow_root) = new_parent
1460 .downcast::<Element>()
1461 .and_then(Element::shadow_root)
1462 {
1463 if shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1464 (node.is::<Element>() || node.is::<Text>())
1465 {
1466 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1467 slottable.assign_a_slot();
1468 }
1469 }
1470
1471 if new_parent.is_in_a_shadow_tree() {
1474 if let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() {
1475 if !slot_element.has_assigned_nodes() {
1476 slot_element.signal_a_slot_change();
1477 }
1478 }
1479 }
1480
1481 node.GetRootNode(&GetRootNodeOptions::empty())
1483 .assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Skip);
1484
1485 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1488 if descendant.deref() == node {
1492 vtable_for(&descendant).moving_steps(&context, CanGc::from_cx(cx));
1493 } else {
1494 context.old_parent = None;
1495 vtable_for(&descendant).moving_steps(&context, CanGc::from_cx(cx));
1496 }
1497
1498 if let Some(descendant) = descendant.downcast::<Element>() {
1500 if descendant.is_custom() && new_parent.is_connected() {
1501 let custom_element_reaction_stack =
1504 ScriptThread::custom_element_reaction_stack();
1505 custom_element_reaction_stack.enqueue_callback_reaction(
1506 descendant,
1507 CallbackReaction::ConnectedMove,
1508 None,
1509 );
1510 }
1511 }
1512 }
1513
1514 let moved = [node];
1517 let mutation = LazyCell::new(|| Mutation::ChildList {
1518 added: None,
1519 removed: Some(&moved),
1520 prev: old_previous_sibling.as_deref(),
1521 next: old_next_sibling.as_deref(),
1522 });
1523 MutationObserver::queue_a_mutation_record(&old_parent, mutation);
1524
1525 let mutation = LazyCell::new(|| Mutation::ChildList {
1528 added: Some(&moved),
1529 removed: None,
1530 prev: new_previous_sibling.as_deref(),
1531 next: child,
1532 });
1533 MutationObserver::queue_a_mutation_record(new_parent, mutation);
1534
1535 Ok(())
1536 }
1537
1538 #[allow(unsafe_code)]
1540 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1541 pub(crate) fn query_selector(
1542 &self,
1543 selectors: DOMString,
1544 ) -> Fallible<Option<DomRoot<Element>>> {
1545 let document_url = self.owner_document().url().get_arc();
1548
1549 let traced_node = Dom::from_ref(self);
1551
1552 let first_matching_element = with_layout_state(|| {
1553 let layout_node = unsafe { traced_node.to_layout() };
1554 ServoLayoutNode::from_layout_dom(layout_node)
1555 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1556 })?;
1557
1558 Ok(first_matching_element
1559 .map(|element| DomRoot::from_ref(unsafe { element.to_layout_dom().as_ref() })))
1560 }
1561
1562 #[allow(unsafe_code)]
1564 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1565 pub(crate) fn query_selector_all(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
1566 let document_url = self.owner_document().url().get_arc();
1569
1570 let traced_node = Dom::from_ref(self);
1572 let matching_elements = with_layout_state(|| {
1573 let layout_node = unsafe { traced_node.to_layout() };
1574 ServoLayoutNode::from_layout_dom(layout_node)
1575 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1576 })?;
1577 let iter = matching_elements
1578 .into_iter()
1579 .map(|element| DomRoot::from_ref(unsafe { element.to_layout_dom().as_ref() }))
1580 .map(DomRoot::upcast::<Node>);
1581
1582 Ok(NodeList::new_simple_list(
1585 &self.owner_window(),
1586 iter,
1587 CanGc::note(),
1588 ))
1589 }
1590
1591 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1592 SimpleNodeIterator {
1593 current: self.GetParentNode(),
1594 next_node: |n| n.GetParentNode(),
1595 }
1596 }
1597
1598 pub(crate) fn inclusive_ancestors(
1600 &self,
1601 shadow_including: ShadowIncluding,
1602 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1603 SimpleNodeIterator {
1604 current: Some(DomRoot::from_ref(self)),
1605 next_node: move |n| {
1606 if shadow_including == ShadowIncluding::Yes {
1607 if let Some(shadow_root) = n.downcast::<ShadowRoot>() {
1608 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1609 }
1610 }
1611 n.GetParentNode()
1612 },
1613 }
1614 }
1615
1616 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1617 self.owner_doc.get().unwrap()
1618 }
1619
1620 pub(crate) fn set_owner_doc(&self, document: &Document) {
1621 self.owner_doc.set(Some(document));
1622 }
1623
1624 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1625 self.rare_data()
1626 .as_ref()?
1627 .containing_shadow_root
1628 .as_ref()
1629 .map(|sr| DomRoot::from_ref(&**sr))
1630 }
1631
1632 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1633 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1634 }
1635
1636 pub(crate) fn is_in_html_doc(&self) -> bool {
1637 self.owner_doc().is_html_document()
1638 }
1639
1640 pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1641 self.is_connected() && self.owner_doc().browsing_context().is_some()
1642 }
1643
1644 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1645 SimpleNodeIterator {
1646 current: self.GetFirstChild(),
1647 next_node: |n| n.GetNextSibling(),
1648 }
1649 }
1650
1651 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1652 SimpleNodeIterator {
1653 current: self.GetLastChild(),
1654 next_node: |n| n.GetPreviousSibling(),
1655 }
1656 }
1657
1658 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1659 self.children()
1660 .filter_map(DomRoot::downcast as fn(_) -> _)
1661 .peekable()
1662 }
1663
1664 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1665 if let Some(ref parent) = self.GetParentNode() {
1666 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1667 }
1668 }
1669
1670 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1672 Ref::filter_map(self.rare_data(), |rare_data| {
1673 rare_data
1674 .as_ref()
1675 .and_then(|rare_data| rare_data.unique_id.as_ref())
1676 })
1677 .ok()
1678 .map(|unique_id| unique_id.borrow().simple().to_string())
1679 }
1680
1681 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1682 let mut rare_data = self.ensure_rare_data();
1683
1684 if rare_data.unique_id.is_none() {
1685 let node_id = UniqueId::new();
1686 ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string());
1687 rare_data.unique_id = Some(node_id);
1688 }
1689 rare_data
1690 .unique_id
1691 .as_ref()
1692 .unwrap()
1693 .borrow()
1694 .simple()
1695 .to_string()
1696 }
1697
1698 pub(crate) fn summarize(&self, can_gc: CanGc) -> NodeInfo {
1699 let USVString(base_uri) = self.BaseURI();
1700 let node_type = self.NodeType();
1701 let pipeline = self.owner_window().pipeline_id();
1702
1703 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1704 let shadow_root_mode = maybe_shadow_root
1705 .map(ShadowRoot::Mode)
1706 .map(ShadowRootMode::convert);
1707 let host = maybe_shadow_root
1708 .map(ShadowRoot::Host)
1709 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1710 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1711 let Some(root) = potential_host.shadow_root() else {
1712 return false;
1713 };
1714 !root.is_user_agent_widget() || pref!(inspector_show_servo_internal_shadow_roots)
1715 });
1716
1717 let num_children = if is_shadow_host {
1718 self.ChildNodes(can_gc).Length() as usize + 1
1720 } else {
1721 self.ChildNodes(can_gc).Length() as usize
1722 };
1723
1724 let window = self.owner_window();
1725 let display = self
1726 .downcast::<Element>()
1727 .map(|elem| window.GetComputedStyle(elem, None))
1728 .map(|style| style.Display().into());
1729
1730 NodeInfo {
1731 unique_id: self.unique_id(pipeline),
1732 host,
1733 base_uri,
1734 parent: self
1735 .GetParentNode()
1736 .map_or("".to_owned(), |node| node.unique_id(pipeline)),
1737 node_type,
1738 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1739 node_name: String::from(self.NodeName()),
1740 node_value: self.GetNodeValue().map(|v| v.into()),
1741 num_children,
1742 attrs: self.downcast().map(Element::summarize).unwrap_or(vec![]),
1743 is_shadow_host,
1744 shadow_root_mode,
1745 display,
1746 is_displayed: !self.is_display_none() || self.is::<DocumentType>(),
1750 doctype_name: self
1751 .downcast::<DocumentType>()
1752 .map(DocumentType::name)
1753 .cloned()
1754 .map(String::from),
1755 doctype_public_identifier: self
1756 .downcast::<DocumentType>()
1757 .map(DocumentType::public_id)
1758 .cloned()
1759 .map(String::from),
1760 doctype_system_identifier: self
1761 .downcast::<DocumentType>()
1762 .map(DocumentType::system_id)
1763 .cloned()
1764 .map(String::from),
1765 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1766 }
1767 }
1768
1769 pub(crate) fn insert_cell_or_row<F, G, I>(
1771 &self,
1772 cx: &mut JSContext,
1773 index: i32,
1774 get_items: F,
1775 new_child: G,
1776 ) -> Fallible<DomRoot<HTMLElement>>
1777 where
1778 F: Fn() -> DomRoot<HTMLCollection>,
1779 G: Fn(&mut JSContext) -> DomRoot<I>,
1780 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1781 {
1782 if index < -1 {
1783 return Err(Error::IndexSize(None));
1784 }
1785
1786 let tr = new_child(cx);
1787
1788 {
1789 let tr_node = tr.upcast::<Node>();
1790 if index == -1 {
1791 self.InsertBefore(cx, tr_node, None)?;
1792 } else {
1793 let items = get_items();
1794 let node = match items
1795 .elements_iter()
1796 .map(DomRoot::upcast::<Node>)
1797 .map(Some)
1798 .chain(iter::once(None))
1799 .nth(index as usize)
1800 {
1801 None => return Err(Error::IndexSize(None)),
1802 Some(node) => node,
1803 };
1804 self.InsertBefore(cx, tr_node, node.as_deref())?;
1805 }
1806 }
1807
1808 Ok(DomRoot::upcast::<HTMLElement>(tr))
1809 }
1810
1811 pub(crate) fn delete_cell_or_row<F, G>(
1813 &self,
1814 cx: &mut JSContext,
1815 index: i32,
1816 get_items: F,
1817 is_delete_type: G,
1818 ) -> ErrorResult
1819 where
1820 F: Fn() -> DomRoot<HTMLCollection>,
1821 G: Fn(&Element) -> bool,
1822 {
1823 let element = match index {
1824 index if index < -1 => return Err(Error::IndexSize(None)),
1825 -1 => {
1826 let last_child = self.upcast::<Node>().GetLastChild();
1827 match last_child.and_then(|node| {
1828 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
1829 .filter_map(UnrootedDom::downcast::<Element>)
1830 .find(|elem| is_delete_type(elem))
1831 .map(|elem| elem.as_rooted())
1832 }) {
1833 Some(element) => element,
1834 None => return Ok(()),
1835 }
1836 },
1837 index => match get_items().Item(index as u32) {
1838 Some(element) => element,
1839 None => return Err(Error::IndexSize(None)),
1840 },
1841 };
1842
1843 element.upcast::<Node>().remove_self(cx);
1844 Ok(())
1845 }
1846
1847 pub(crate) fn get_stylesheet(&self) -> Option<ServoArc<Stylesheet>> {
1848 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1849 node.get_stylesheet()
1850 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1851 node.get_stylesheet()
1852 } else {
1853 None
1854 }
1855 }
1856
1857 pub(crate) fn get_cssom_stylesheet(&self) -> Option<DomRoot<CSSStyleSheet>> {
1858 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1859 node.get_cssom_stylesheet()
1860 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1861 node.get_cssom_stylesheet(CanGc::note())
1862 } else {
1863 None
1864 }
1865 }
1866
1867 pub(crate) fn is_styled(&self) -> bool {
1868 self.style_data.borrow().is_some()
1869 }
1870
1871 pub(crate) fn is_display_none(&self) -> bool {
1872 self.style_data.borrow().as_ref().is_none_or(|data| {
1873 data.element_data
1874 .borrow()
1875 .styles
1876 .primary()
1877 .get_box()
1878 .display
1879 .is_none()
1880 })
1881 }
1882
1883 pub(crate) fn style(&self) -> Option<ServoArc<ComputedValues>> {
1884 self.owner_window().layout_reflow(QueryMsg::StyleQuery);
1885 self.style_data
1886 .borrow()
1887 .as_ref()
1888 .map(|data| data.element_data.borrow().styles.primary().clone())
1889 }
1890
1891 pub(crate) fn get_lang(&self) -> Option<String> {
1893 self.inclusive_ancestors(ShadowIncluding::Yes)
1894 .find_map(|node| {
1895 node.downcast::<Element>().and_then(|el| {
1896 el.get_attribute_with_namespace(&ns!(xml), &local_name!("lang"))
1897 .or_else(|| el.get_attribute(&local_name!("lang")))
1898 .map(|attr| String::from(attr.Value()))
1899 })
1900 })
1903 }
1904
1905 pub(crate) fn assign_slottables_for_a_tree(&self, force: ForceSlottableNodeReconciliation) {
1907 let is_shadow_root_with_slots = self
1914 .downcast::<ShadowRoot>()
1915 .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
1916 if !is_shadow_root_with_slots &&
1917 !self.is::<HTMLSlotElement>() &&
1918 matches!(force, ForceSlottableNodeReconciliation::Skip)
1919 {
1920 return;
1921 }
1922
1923 for node in self.traverse_preorder(ShadowIncluding::No) {
1926 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
1927 slot.assign_slottables();
1928 }
1929 }
1930 }
1931
1932 pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
1933 let assigned_slot = self
1934 .rare_data
1935 .borrow()
1936 .as_ref()?
1937 .slottable_data
1938 .assigned_slot
1939 .as_ref()?
1940 .as_rooted();
1941 Some(assigned_slot)
1942 }
1943
1944 pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
1945 self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
1946 }
1947
1948 pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
1949 let manually_assigned_slot = self
1950 .rare_data
1951 .borrow()
1952 .as_ref()?
1953 .slottable_data
1954 .manual_slot_assignment
1955 .as_ref()?
1956 .as_rooted();
1957 Some(manually_assigned_slot)
1958 }
1959
1960 pub(crate) fn set_manual_slot_assignment(
1961 &self,
1962 manually_assigned_slot: Option<&HTMLSlotElement>,
1963 ) {
1964 self.ensure_rare_data()
1965 .slottable_data
1966 .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
1967 }
1968
1969 pub(crate) fn parent_in_flat_tree(&self) -> Option<DomRoot<Node>> {
1975 if let Some(assigned_slot) = self.assigned_slot() {
1976 return Some(DomRoot::upcast(assigned_slot));
1977 }
1978
1979 let parent_or_none = self.GetParentNode();
1980 if let Some(parent) = parent_or_none.as_deref() {
1981 if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
1982 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1983 }
1984 }
1985
1986 parent_or_none
1987 }
1988
1989 pub(crate) fn inclusive_ancestors_in_flat_tree(
1990 &self,
1991 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1992 SimpleNodeIterator {
1993 current: Some(DomRoot::from_ref(self)),
1994 next_node: move |n| n.parent_in_flat_tree(),
1995 }
1996 }
1997
1998 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2000 debug_assert!(self.is_in_ua_widget());
2002 debug_assert!(pseudo_element.is_element_backed());
2003 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2004 }
2005
2006 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2007 self.rare_data
2008 .borrow()
2009 .as_ref()
2010 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2011 }
2012
2013 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2015 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2019 if ancestor.is_editing_host() {
2020 return Some(ancestor);
2021 }
2022 if ancestor
2023 .downcast::<HTMLElement>()
2024 .is_some_and(|el| el.ContentEditable().str() == "false")
2025 {
2026 return None;
2027 }
2028 }
2029 None
2030 }
2031
2032 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2033 self.editing_host_of().is_some()
2034 }
2035
2036 pub(crate) fn is_editing_host(&self) -> bool {
2038 self.downcast::<HTMLElement>()
2039 .is_some_and(HTMLElement::is_editing_host)
2040 }
2041
2042 pub(crate) fn is_editable(&self) -> bool {
2044 if self.is_editing_host() {
2046 return false;
2047 }
2048 let html_element = self.downcast::<HTMLElement>();
2050 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2051 return false;
2052 }
2053 let Some(parent) = self.GetParentNode() else {
2055 return false;
2056 };
2057 if !parent.is_editable_or_editing_host() {
2058 return false;
2059 }
2060 html_element.is_some() ||
2062 (!self.is::<Element>() && parent.downcast::<HTMLElement>().is_some())
2063 }
2064}
2065
2066fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2068where
2069 I: Iterator<Item = DomRoot<Node>>,
2070{
2071 nodes.find(|node| {
2072 not_in.iter().all(|n| match *n {
2073 NodeOrString::Node(ref n) => n != node,
2074 _ => true,
2075 })
2076 })
2077}
2078
2079#[expect(unsafe_code)]
2082pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2083 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2084 DomRoot::from_ref(node)
2085}
2086
2087#[expect(unsafe_code)]
2088pub(crate) trait LayoutNodeHelpers<'dom> {
2089 fn type_id_for_layout(self) -> NodeTypeId;
2090
2091 fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>>;
2092 fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>>;
2093 fn first_child_ref(self) -> Option<LayoutDom<'dom, Node>>;
2094 fn last_child_ref(self) -> Option<LayoutDom<'dom, Node>>;
2095 fn prev_sibling_ref(self) -> Option<LayoutDom<'dom, Node>>;
2096 fn next_sibling_ref(self) -> Option<LayoutDom<'dom, Node>>;
2097
2098 fn owner_doc_for_layout(self) -> LayoutDom<'dom, Document>;
2099 fn containing_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>>;
2100 fn assigned_slot_for_layout(self) -> Option<LayoutDom<'dom, HTMLSlotElement>>;
2101
2102 fn is_element_for_layout(&self) -> bool;
2103 fn is_text_node_for_layout(&self) -> bool;
2104 unsafe fn get_flag(self, flag: NodeFlags) -> bool;
2105 unsafe fn set_flag(self, flag: NodeFlags, value: bool);
2106
2107 fn style_data(self) -> Option<&'dom StyleData>;
2108 fn layout_data(self) -> Option<&'dom GenericLayoutData>;
2109
2110 unsafe fn initialize_style_data(self);
2118
2119 unsafe fn initialize_layout_data(self, data: Box<GenericLayoutData>);
2127
2128 unsafe fn clear_style_and_layout_data(self);
2136
2137 fn is_single_line_text_inner_editor(&self) -> bool;
2140
2141 fn is_text_container_of_single_line_input(&self) -> bool;
2144 fn text_content(self) -> Cow<'dom, str>;
2145 fn selection(self) -> Option<SharedSelection>;
2146 fn image_url(self) -> Option<ServoUrl>;
2147 fn image_density(self) -> Option<f64>;
2148 fn image_data(self) -> Option<(Option<Image>, Option<ImageMetadata>)>;
2149 fn showing_broken_image_icon(self) -> bool;
2150 fn canvas_data(self) -> Option<HTMLCanvasData>;
2151 fn media_data(self) -> Option<HTMLMediaData>;
2152 fn svg_data(self) -> Option<SVGElementData<'dom>>;
2153 fn iframe_browsing_context_id(self) -> Option<BrowsingContextId>;
2154 fn iframe_pipeline_id(self) -> Option<PipelineId>;
2155 fn opaque(self) -> OpaqueNode;
2156 fn implemented_pseudo_element(&self) -> Option<PseudoElement>;
2157 fn is_in_ua_widget(&self) -> bool;
2158}
2159
2160impl<'dom> LayoutDom<'dom, Node> {
2161 #[inline]
2162 #[expect(unsafe_code)]
2163 pub(crate) fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
2164 unsafe { self.unsafe_get().parent_node.get_inner_as_layout() }
2165 }
2166}
2167
2168impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
2169 #[inline]
2170 fn type_id_for_layout(self) -> NodeTypeId {
2171 self.unsafe_get().type_id()
2172 }
2173
2174 #[inline]
2175 fn is_element_for_layout(&self) -> bool {
2176 (*self).is::<Element>()
2177 }
2178
2179 fn is_text_node_for_layout(&self) -> bool {
2180 self.type_id_for_layout() ==
2181 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text))
2182 }
2183
2184 #[inline]
2185 #[expect(unsafe_code)]
2186 fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
2187 unsafe { self.unsafe_get().parent_node.get_inner_as_layout() }
2188 }
2189
2190 #[inline]
2191 fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
2192 let parent = self.parent_node_ref();
2193 if let Some(parent) = parent {
2194 if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
2195 return Some(shadow_root.get_host_for_layout().upcast());
2196 }
2197 }
2198 parent
2199 }
2200
2201 #[inline]
2202 #[expect(unsafe_code)]
2203 fn first_child_ref(self) -> Option<LayoutDom<'dom, Node>> {
2204 unsafe { self.unsafe_get().first_child.get_inner_as_layout() }
2205 }
2206
2207 #[inline]
2208 #[expect(unsafe_code)]
2209 fn last_child_ref(self) -> Option<LayoutDom<'dom, Node>> {
2210 unsafe { self.unsafe_get().last_child.get_inner_as_layout() }
2211 }
2212
2213 #[inline]
2214 #[expect(unsafe_code)]
2215 fn prev_sibling_ref(self) -> Option<LayoutDom<'dom, Node>> {
2216 unsafe { self.unsafe_get().prev_sibling.get_inner_as_layout() }
2217 }
2218
2219 #[inline]
2220 #[expect(unsafe_code)]
2221 fn next_sibling_ref(self) -> Option<LayoutDom<'dom, Node>> {
2222 unsafe { self.unsafe_get().next_sibling.get_inner_as_layout() }
2223 }
2224
2225 #[inline]
2226 #[expect(unsafe_code)]
2227 fn owner_doc_for_layout(self) -> LayoutDom<'dom, Document> {
2228 unsafe { self.unsafe_get().owner_doc.get_inner_as_layout().unwrap() }
2229 }
2230
2231 #[inline]
2232 #[expect(unsafe_code)]
2233 fn containing_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
2234 unsafe {
2235 self.unsafe_get()
2236 .rare_data
2237 .borrow_for_layout()
2238 .as_ref()?
2239 .containing_shadow_root
2240 .as_ref()
2241 .map(|sr| sr.to_layout())
2242 }
2243 }
2244
2245 #[inline]
2246 #[expect(unsafe_code)]
2247 fn assigned_slot_for_layout(self) -> Option<LayoutDom<'dom, HTMLSlotElement>> {
2248 unsafe {
2249 self.unsafe_get()
2250 .rare_data
2251 .borrow_for_layout()
2252 .as_ref()?
2253 .slottable_data
2254 .assigned_slot
2255 .as_ref()
2256 .map(|assigned_slot| assigned_slot.to_layout())
2257 }
2258 }
2259
2260 #[inline]
2265 #[expect(unsafe_code)]
2266 unsafe fn get_flag(self, flag: NodeFlags) -> bool {
2267 (self.unsafe_get()).flags.get().contains(flag)
2268 }
2269
2270 #[inline]
2271 #[expect(unsafe_code)]
2272 unsafe fn set_flag(self, flag: NodeFlags, value: bool) {
2273 let this = self.unsafe_get();
2274 let mut flags = (this).flags.get();
2275
2276 if value {
2277 flags.insert(flag);
2278 } else {
2279 flags.remove(flag);
2280 }
2281
2282 (this).flags.set(flags);
2283 }
2284
2285 #[inline]
2288 #[expect(unsafe_code)]
2289 fn style_data(self) -> Option<&'dom StyleData> {
2290 unsafe { self.unsafe_get().style_data.borrow_for_layout().as_deref() }
2291 }
2292
2293 #[inline]
2294 #[expect(unsafe_code)]
2295 fn layout_data(self) -> Option<&'dom GenericLayoutData> {
2296 unsafe { self.unsafe_get().layout_data.borrow_for_layout().as_deref() }
2297 }
2298
2299 #[inline]
2300 #[expect(unsafe_code)]
2301 unsafe fn initialize_style_data(self) {
2302 let data = unsafe { self.unsafe_get().style_data.borrow_mut_for_layout() };
2303 debug_assert!(data.is_none());
2304 *data = Some(Box::default());
2305 }
2306
2307 #[inline]
2308 #[expect(unsafe_code)]
2309 unsafe fn initialize_layout_data(self, new_data: Box<GenericLayoutData>) {
2310 let data = unsafe { self.unsafe_get().layout_data.borrow_mut_for_layout() };
2311 debug_assert!(data.is_none());
2312 *data = Some(new_data);
2313 }
2314
2315 #[inline]
2316 #[expect(unsafe_code)]
2317 unsafe fn clear_style_and_layout_data(self) {
2318 unsafe {
2319 self.unsafe_get().style_data.borrow_mut_for_layout().take();
2320 self.unsafe_get().layout_data.borrow_mut_for_layout().take();
2321 }
2322 }
2323
2324 fn is_single_line_text_inner_editor(&self) -> bool {
2325 matches!(
2326 self.implemented_pseudo_element(),
2327 Some(PseudoElement::ServoTextControlInnerEditor)
2328 )
2329 }
2330
2331 fn is_text_container_of_single_line_input(&self) -> bool {
2332 let is_single_line_text_inner_placeholder = matches!(
2333 self.implemented_pseudo_element(),
2334 Some(PseudoElement::Placeholder)
2335 );
2336 debug_assert!(
2338 !is_single_line_text_inner_placeholder ||
2339 self.containing_shadow_root_for_layout()
2340 .map(|root| root.get_host_for_layout())
2341 .map(|host| host.downcast::<HTMLInputElement>())
2342 .is_some()
2343 );
2344
2345 self.is_single_line_text_inner_editor() || is_single_line_text_inner_placeholder
2346 }
2347
2348 fn text_content(self) -> Cow<'dom, str> {
2349 self.downcast::<Text>()
2350 .expect("Called LayoutDom::text_content on non-Text node!")
2351 .upcast()
2352 .data_for_layout()
2353 .into()
2354 }
2355
2356 fn selection(self) -> Option<SharedSelection> {
2363 if let Some(input) = self.downcast::<HTMLInputElement>() {
2364 return input.selection_for_layout();
2365 }
2366 if let Some(textarea) = self.downcast::<HTMLTextAreaElement>() {
2367 return Some(textarea.selection_for_layout());
2368 }
2369
2370 let shadow_root = self
2371 .containing_shadow_root_for_layout()?
2372 .get_host_for_layout();
2373 if let Some(input) = shadow_root.downcast::<HTMLInputElement>() {
2374 return input.selection_for_layout();
2375 }
2376 shadow_root
2377 .downcast::<HTMLTextAreaElement>()
2378 .map(|textarea| textarea.selection_for_layout())
2379 }
2380
2381 fn image_url(self) -> Option<ServoUrl> {
2382 self.downcast::<HTMLImageElement>()
2383 .expect("not an image!")
2384 .image_url()
2385 }
2386
2387 fn image_data(self) -> Option<(Option<Image>, Option<ImageMetadata>)> {
2388 self.downcast::<HTMLImageElement>().map(|e| e.image_data())
2389 }
2390
2391 fn image_density(self) -> Option<f64> {
2392 self.downcast::<HTMLImageElement>()
2393 .expect("not an image!")
2394 .image_density()
2395 }
2396
2397 fn showing_broken_image_icon(self) -> bool {
2398 self.downcast::<HTMLImageElement>()
2399 .map(|image_element| image_element.showing_broken_image_icon())
2400 .unwrap_or_default()
2401 }
2402
2403 fn canvas_data(self) -> Option<HTMLCanvasData> {
2404 self.downcast::<HTMLCanvasElement>()
2405 .map(|canvas| canvas.data())
2406 }
2407
2408 fn media_data(self) -> Option<HTMLMediaData> {
2409 self.downcast::<HTMLVideoElement>()
2410 .map(|media| media.data())
2411 }
2412
2413 fn svg_data(self) -> Option<SVGElementData<'dom>> {
2414 self.downcast::<SVGSVGElement>().map(|svg| svg.data())
2415 }
2416
2417 fn iframe_browsing_context_id(self) -> Option<BrowsingContextId> {
2418 self.downcast::<HTMLIFrameElement>()
2419 .and_then(|iframe_element| iframe_element.browsing_context_id())
2420 }
2421
2422 fn iframe_pipeline_id(self) -> Option<PipelineId> {
2423 self.downcast::<HTMLIFrameElement>()
2424 .and_then(|iframe_element| iframe_element.pipeline_id())
2425 }
2426
2427 #[expect(unsafe_code)]
2428 fn opaque(self) -> OpaqueNode {
2429 unsafe { OpaqueNode(self.get_jsobject() as usize) }
2430 }
2431
2432 #[expect(unsafe_code)]
2433 fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2434 unsafe {
2435 self.unsafe_get()
2436 .rare_data
2437 .borrow_for_layout()
2438 .as_ref()
2439 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2440 }
2441 }
2442
2443 fn is_in_ua_widget(&self) -> bool {
2444 self.unsafe_get().is_in_ua_widget()
2445 }
2446}
2447
2448pub(crate) struct FollowingNodeIterator {
2453 current: Option<DomRoot<Node>>,
2454 root: DomRoot<Node>,
2455}
2456
2457impl FollowingNodeIterator {
2458 pub(crate) fn next_skipping_children(&mut self) -> Option<DomRoot<Node>> {
2460 let current = self.current.take()?;
2461 self.next_skipping_children_impl(current)
2462 }
2463
2464 fn next_skipping_children_impl(&mut self, current: DomRoot<Node>) -> Option<DomRoot<Node>> {
2465 if self.root == current {
2466 self.current = None;
2467 return None;
2468 }
2469
2470 if let Some(next_sibling) = current.GetNextSibling() {
2471 self.current = Some(next_sibling);
2472 return current.GetNextSibling();
2473 }
2474
2475 for ancestor in current.inclusive_ancestors(ShadowIncluding::No) {
2476 if self.root == ancestor {
2477 break;
2478 }
2479 if let Some(next_sibling) = ancestor.GetNextSibling() {
2480 self.current = Some(next_sibling);
2481 return ancestor.GetNextSibling();
2482 }
2483 }
2484 self.current = None;
2485 None
2486 }
2487}
2488
2489impl Iterator for FollowingNodeIterator {
2490 type Item = DomRoot<Node>;
2491
2492 fn next(&mut self) -> Option<DomRoot<Node>> {
2494 let current = self.current.take()?;
2495
2496 if let Some(first_child) = current.GetFirstChild() {
2497 self.current = Some(first_child);
2498 return current.GetFirstChild();
2499 }
2500
2501 self.next_skipping_children_impl(current)
2502 }
2503}
2504
2505pub(crate) struct PrecedingNodeIterator {
2506 current: Option<DomRoot<Node>>,
2507 root: DomRoot<Node>,
2508}
2509
2510impl Iterator for PrecedingNodeIterator {
2511 type Item = DomRoot<Node>;
2512
2513 fn next(&mut self) -> Option<DomRoot<Node>> {
2515 let current = self.current.take()?;
2516
2517 self.current = if self.root == current {
2518 None
2519 } else if let Some(previous_sibling) = current.GetPreviousSibling() {
2520 if self.root == previous_sibling {
2521 None
2522 } else if let Some(last_child) = previous_sibling.descending_last_children().last() {
2523 Some(last_child)
2524 } else {
2525 Some(previous_sibling)
2526 }
2527 } else {
2528 current.GetParentNode()
2529 };
2530 self.current.clone()
2531 }
2532}
2533
2534struct SimpleNodeIterator<I>
2535where
2536 I: Fn(&Node) -> Option<DomRoot<Node>>,
2537{
2538 current: Option<DomRoot<Node>>,
2539 next_node: I,
2540}
2541
2542impl<I> Iterator for SimpleNodeIterator<I>
2543where
2544 I: Fn(&Node) -> Option<DomRoot<Node>>,
2545{
2546 type Item = DomRoot<Node>;
2547
2548 fn next(&mut self) -> Option<Self::Item> {
2549 let current = self.current.take();
2550 self.current = current.as_ref().and_then(|c| (self.next_node)(c));
2551 current
2552 }
2553}
2554
2555#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
2563pub(crate) struct UnrootedSimpleNodeIterator<'a, 'b, I>
2564where
2565 I: Fn(&Node, &'b NoGC) -> Option<UnrootedDom<'b, Node>>,
2566{
2567 current: Option<UnrootedDom<'b, Node>>,
2568 next_node: I,
2569 no_gc: &'b NoGC,
2571 phantom: PhantomData<&'a Node>,
2572}
2573
2574impl<'a, 'b, I> Iterator for UnrootedSimpleNodeIterator<'a, 'b, I>
2575where
2576 'b: 'a,
2577 I: Fn(&Node, &'b NoGC) -> Option<UnrootedDom<'b, Node>>,
2578{
2579 type Item = UnrootedDom<'b, Node>;
2580
2581 fn next(&mut self) -> Option<Self::Item> {
2582 let current = self.current.take();
2583 self.current = current
2584 .as_ref()
2585 .and_then(|c| (self.next_node)(c, self.no_gc));
2586 current
2587 }
2588}
2589
2590#[derive(Clone, Copy, PartialEq)]
2592pub(crate) enum ShadowIncluding {
2593 No,
2594 Yes,
2595}
2596
2597pub(crate) struct TreeIterator {
2598 current: Option<DomRoot<Node>>,
2599 depth: usize,
2600 shadow_including: ShadowIncluding,
2601}
2602
2603impl TreeIterator {
2604 fn new(root: &Node, shadow_including: ShadowIncluding) -> TreeIterator {
2605 TreeIterator {
2606 current: Some(DomRoot::from_ref(root)),
2607 depth: 0,
2608 shadow_including,
2609 }
2610 }
2611
2612 pub(crate) fn next_skipping_children(&mut self) -> Option<DomRoot<Node>> {
2613 let current = self.current.take()?;
2614
2615 self.next_skipping_children_impl(current)
2616 }
2617
2618 fn next_skipping_children_impl(&mut self, current: DomRoot<Node>) -> Option<DomRoot<Node>> {
2619 let iter = current.inclusive_ancestors(self.shadow_including);
2620
2621 for ancestor in iter {
2622 if self.depth == 0 {
2623 break;
2624 }
2625 if let Some(next_sibling) = ancestor.GetNextSibling() {
2626 self.current = Some(next_sibling);
2627 return Some(current);
2628 }
2629 if let Some(shadow_root) = ancestor.downcast::<ShadowRoot>() {
2630 if let Some(child) = shadow_root.Host().upcast::<Node>().GetFirstChild() {
2633 self.current = Some(child);
2634 return Some(current);
2635 }
2636 }
2637 self.depth -= 1;
2638 }
2639 debug_assert_eq!(self.depth, 0);
2640 self.current = None;
2641 Some(current)
2642 }
2643
2644 pub(crate) fn peek(&self) -> Option<&DomRoot<Node>> {
2645 self.current.as_ref()
2646 }
2647}
2648
2649impl Iterator for TreeIterator {
2650 type Item = DomRoot<Node>;
2651
2652 fn next(&mut self) -> Option<DomRoot<Node>> {
2655 let current = self.current.take()?;
2656
2657 if let Some(element) = current.downcast::<Element>() {
2659 if let Some(shadow_root) = element.shadow_root() {
2660 if self.shadow_including == ShadowIncluding::Yes {
2661 self.current = Some(DomRoot::from_ref(shadow_root.upcast::<Node>()));
2662 self.depth += 1;
2663 return Some(current);
2664 }
2665 }
2666 }
2667
2668 if let Some(first_child) = current.GetFirstChild() {
2669 self.current = Some(first_child);
2670 self.depth += 1;
2671 return Some(current);
2672 };
2673
2674 self.next_skipping_children_impl(current)
2675 }
2676}
2677
2678#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
2686pub(crate) struct UnrootedTreeIterator<'a, 'b> {
2687 current: Option<UnrootedDom<'b, Node>>,
2688 depth: usize,
2689 shadow_including: ShadowIncluding,
2690 no_gc: &'b NoGC,
2692 phantom: PhantomData<&'a Node>,
2693}
2694
2695impl<'a, 'b> UnrootedTreeIterator<'a, 'b>
2696where
2697 'b: 'a,
2698{
2699 pub(crate) fn new(
2700 root: &'a Node,
2701 shadow_including: ShadowIncluding,
2702 no_gc: &'b NoGC,
2703 ) -> UnrootedTreeIterator<'a, 'b> {
2704 UnrootedTreeIterator {
2705 current: Some(UnrootedDom::from_dom(Dom::from_ref(root), no_gc)),
2706 depth: 0,
2707 shadow_including,
2708 no_gc,
2709 phantom: PhantomData,
2710 }
2711 }
2712
2713 pub(crate) fn next_skipping_children(&mut self) -> Option<UnrootedDom<'b, Node>> {
2714 let current = self.current.take()?;
2715
2716 let iter = current.inclusive_ancestors(self.shadow_including);
2717
2718 for ancestor in iter {
2719 if self.depth == 0 {
2720 break;
2721 }
2722
2723 let next_sibling_option = ancestor.get_next_sibling_unrooted(self.no_gc);
2724
2725 if let Some(next_sibling) = next_sibling_option {
2726 self.current = Some(next_sibling);
2727 return Some(current);
2728 }
2729
2730 if let Some(shadow_root) = ancestor.downcast::<ShadowRoot>() {
2731 let child_option = shadow_root
2734 .Host()
2735 .upcast::<Node>()
2736 .get_first_child_unrooted(self.no_gc);
2737
2738 if let Some(child) = child_option {
2739 self.current = Some(child);
2740 return Some(current);
2741 }
2742 }
2743 self.depth -= 1;
2744 }
2745 debug_assert_eq!(self.depth, 0);
2746 self.current = None;
2747 Some(current)
2748 }
2749}
2750
2751impl<'a, 'b> Iterator for UnrootedTreeIterator<'a, 'b>
2752where
2753 'b: 'a,
2754{
2755 type Item = UnrootedDom<'b, Node>;
2756
2757 fn next(&mut self) -> Option<UnrootedDom<'b, Node>> {
2760 let current = self.current.take()?;
2761
2762 if let Some(element) = current.downcast::<Element>() {
2764 if let Some(shadow_root) = element.shadow_root() {
2765 if self.shadow_including == ShadowIncluding::Yes {
2766 self.current = Some(UnrootedDom::from_dom(
2767 Dom::from_ref(shadow_root.upcast::<Node>()),
2768 self.no_gc,
2769 ));
2770 self.depth += 1;
2771 return Some(current);
2772 }
2773 }
2774 }
2775
2776 let first_child_option = current.get_first_child_unrooted(self.no_gc);
2777 if let Some(first_child) = first_child_option {
2778 self.current = Some(first_child);
2779 self.depth += 1;
2780 return Some(current);
2781 };
2782
2783 let _ = self.current.insert(current);
2785 self.next_skipping_children()
2786 }
2787}
2788
2789#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2791pub(crate) enum CloneChildrenFlag {
2792 CloneChildren,
2793 DoNotCloneChildren,
2794}
2795
2796impl From<bool> for CloneChildrenFlag {
2797 fn from(boolean: bool) -> Self {
2798 if boolean {
2799 CloneChildrenFlag::CloneChildren
2800 } else {
2801 CloneChildrenFlag::DoNotCloneChildren
2802 }
2803 }
2804}
2805
2806fn as_uintptr<T>(t: &T) -> uintptr_t {
2807 t as *const T as uintptr_t
2808}
2809
2810impl Node {
2811 pub(crate) fn reflect_node<N>(
2812 cx: &mut js::context::JSContext,
2813 node: Box<N>,
2814 document: &Document,
2815 ) -> DomRoot<N>
2816 where
2817 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2818 {
2819 Self::reflect_node_with_proto(cx, node, document, None)
2820 }
2821
2822 pub(crate) fn reflect_node_with_proto<N>(
2823 cx: &mut js::context::JSContext,
2824 node: Box<N>,
2825 document: &Document,
2826 proto: Option<HandleObject>,
2827 ) -> DomRoot<N>
2828 where
2829 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2830 {
2831 let window = document.window();
2832 reflect_dom_object_with_proto_and_cx(node, window, proto, cx)
2833 }
2834
2835 pub(crate) fn new_inherited(doc: &Document) -> Node {
2836 Node::new_(NodeFlags::empty(), Some(doc))
2837 }
2838
2839 pub(crate) fn new_document_node() -> Node {
2840 Node::new_(
2841 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2842 None,
2843 )
2844 }
2845
2846 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2847 Node {
2848 eventtarget: EventTarget::new_inherited(),
2849
2850 parent_node: Default::default(),
2851 first_child: Default::default(),
2852 last_child: Default::default(),
2853 next_sibling: Default::default(),
2854 prev_sibling: Default::default(),
2855 owner_doc: MutNullableDom::new(doc),
2856 rare_data: Default::default(),
2857 children_count: Cell::new(0u32),
2858 flags: Cell::new(flags),
2859 inclusive_descendants_version: Cell::new(0),
2860 style_data: Default::default(),
2861 layout_data: Default::default(),
2862 }
2863 }
2864
2865 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2867 document.add_script_and_layout_blocker();
2868
2869 let old_doc = node.owner_doc();
2871 old_doc.add_script_and_layout_blocker();
2872
2873 node.remove_self(cx);
2875
2876 if &*old_doc != document {
2878 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2880 descendant.set_owner_doc(document);
2882
2883 if let Some(element) = descendant.downcast::<Element>() {
2886 for attribute in element.attrs().iter() {
2887 attribute.upcast::<Node>().set_owner_doc(document);
2888 }
2889 }
2890 }
2891
2892 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2896 for descendant in node
2897 .traverse_preorder(ShadowIncluding::Yes)
2898 .filter_map(|d| d.as_custom_element())
2899 {
2900 custom_element_reaction_stack.enqueue_callback_reaction(
2901 &descendant,
2902 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2903 None,
2904 );
2905 }
2906
2907 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2910 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2911 }
2912 }
2913
2914 old_doc.remove_script_and_layout_blocker();
2915 document.remove_script_and_layout_blocker();
2916 }
2917
2918 pub(crate) fn ensure_pre_insertion_validity(
2920 node: &Node,
2921 parent: &Node,
2922 child: Option<&Node>,
2923 ) -> ErrorResult {
2924 match parent.type_id() {
2926 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2927 },
2928 _ => {
2929 return Err(Error::HierarchyRequest(Some(
2930 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2931 )));
2932 },
2933 }
2934
2935 if node.is_host_including_inclusive_ancestor(parent) {
2937 return Err(Error::HierarchyRequest(Some(
2938 "Node is a host-including inclusive ancestor of parent".to_owned(),
2939 )));
2940 }
2941
2942 if let Some(child) = child {
2944 if !parent.is_parent_of(child) {
2945 return Err(Error::NotFound(Some(
2946 "Child is non-null and its parent is not parent".to_owned(),
2947 )));
2948 }
2949 }
2950
2951 match node.type_id() {
2952 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2956 if parent.is::<Document>() {
2957 return Err(Error::HierarchyRequest(Some(
2958 "Node is a Text node and parent is a document".to_owned(),
2959 )));
2960 }
2961 },
2962 NodeTypeId::DocumentType => {
2963 if !parent.is::<Document>() {
2964 return Err(Error::HierarchyRequest(Some(
2965 "Node is a doctype and parent is not a document".to_owned(),
2966 )));
2967 }
2968 },
2969 NodeTypeId::DocumentFragment(_) |
2970 NodeTypeId::Element(_) |
2971 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2972 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2973 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2976 return Err(Error::HierarchyRequest(Some(
2977 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2978 .to_owned(),
2979 )));
2980 },
2981 }
2982
2983 if parent.is::<Document>() {
2986 match node.type_id() {
2987 NodeTypeId::DocumentFragment(_) => {
2988 if node.children().any(|c| c.is::<Text>()) {
2990 return Err(Error::HierarchyRequest(None));
2991 }
2992 match node.child_elements().count() {
2993 0 => (),
2994 1 => {
2997 if parent.child_elements().next().is_some() {
2998 return Err(Error::HierarchyRequest(None));
2999 }
3000 if let Some(child) = child {
3001 if child
3002 .inclusively_following_siblings()
3003 .any(|child| child.is_doctype())
3004 {
3005 return Err(Error::HierarchyRequest(None));
3006 }
3007 }
3008 },
3009 _ => return Err(Error::HierarchyRequest(None)),
3010 }
3011 },
3012 NodeTypeId::Element(_) => {
3013 if parent.child_elements().next().is_some() {
3015 return Err(Error::HierarchyRequest(Some(
3016 "Parent has an element child".to_owned(),
3017 )));
3018 }
3019 if let Some(child) = child {
3020 if child
3021 .inclusively_following_siblings()
3022 .any(|following| following.is_doctype())
3023 {
3024 return Err(Error::HierarchyRequest(Some(
3025 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
3026 )));
3027 }
3028 }
3029 },
3030 NodeTypeId::DocumentType => {
3031 if parent.children().any(|c| c.is_doctype()) {
3034 return Err(Error::HierarchyRequest(None));
3035 }
3036 match child {
3037 Some(child) => {
3038 if parent
3039 .children()
3040 .take_while(|c| &**c != child)
3041 .any(|c| c.is::<Element>())
3042 {
3043 return Err(Error::HierarchyRequest(None));
3044 }
3045 },
3046 None => {
3047 if parent.child_elements().next().is_some() {
3048 return Err(Error::HierarchyRequest(None));
3049 }
3050 },
3051 }
3052 },
3053 NodeTypeId::CharacterData(_) => (),
3054 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
3057 }
3058 }
3059 Ok(())
3060 }
3061
3062 pub(crate) fn pre_insert(
3064 cx: &mut JSContext,
3065 node: &Node,
3066 parent: &Node,
3067 child: Option<&Node>,
3068 ) -> Fallible<DomRoot<Node>> {
3069 Node::ensure_pre_insertion_validity(node, parent, child)?;
3071
3072 let reference_child_root;
3074 let reference_child = match child {
3075 Some(child) if child == node => {
3077 reference_child_root = node.GetNextSibling();
3078 reference_child_root.as_deref()
3079 },
3080 _ => child,
3081 };
3082
3083 Node::insert(
3085 cx,
3086 node,
3087 parent,
3088 reference_child,
3089 SuppressObserver::Unsuppressed,
3090 );
3091
3092 Ok(DomRoot::from_ref(node))
3094 }
3095
3096 fn insert(
3098 cx: &mut JSContext,
3099 node: &Node,
3100 parent: &Node,
3101 child: Option<&Node>,
3102 suppress_observers: SuppressObserver,
3103 ) {
3104 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
3105
3106 rooted_vec!(let mut new_nodes);
3108 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
3109 new_nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
3110 new_nodes.r()
3111 } else {
3112 from_ref(&node)
3113 };
3114
3115 let count = new_nodes.len();
3117
3118 if count == 0 {
3120 return;
3121 }
3122
3123 let parent_document = parent.owner_doc();
3126 let from_document = node.owner_doc();
3127 from_document.add_script_and_layout_blocker();
3128 parent_document.add_script_and_layout_blocker();
3129
3130 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
3132 for kid in new_nodes {
3134 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
3135 }
3136 vtable_for(node).children_changed(cx, &ChildrenMutation::replace_all(new_nodes, &[]));
3137
3138 let mutation = LazyCell::new(|| Mutation::ChildList {
3140 added: None,
3141 removed: Some(new_nodes),
3142 prev: None,
3143 next: None,
3144 });
3145 MutationObserver::queue_a_mutation_record(node, mutation);
3146 }
3147
3148 if let Some(child) = child {
3154 if !parent.ranges_is_empty() {
3155 parent
3156 .ranges()
3157 .increase_above(parent, child.index(), count.try_into().unwrap());
3158 }
3159 }
3160
3161 let previous_sibling = match suppress_observers {
3163 SuppressObserver::Unsuppressed => match child {
3164 Some(child) => child.GetPreviousSibling(),
3165 None => parent.GetLastChild(),
3166 },
3167 SuppressObserver::Suppressed => None,
3168 };
3169
3170 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
3171
3172 let mut static_node_list: SmallVec<[_; 4]> = Default::default();
3174
3175 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
3176 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
3177 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
3178
3179 for kid in new_nodes {
3181 Node::adopt(cx, kid, &parent.owner_document());
3183
3184 parent.add_child(cx, kid, child);
3187
3188 if let Some(ref shadow_root) = parent_shadow_root {
3191 if shadow_root.SlotAssignment() == SlotAssignmentMode::Named {
3192 let cx = GlobalScope::get_cx();
3193 if kid.is::<Element>() || kid.is::<Text>() {
3194 rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(kid)));
3195 slottable.assign_a_slot();
3196 }
3197 }
3198 }
3199
3200 if parent_in_shadow_tree {
3203 if let Some(slot_element) = parent_as_slot {
3204 if !slot_element.has_assigned_nodes() {
3205 slot_element.signal_a_slot_change();
3206 }
3207 }
3208 }
3209
3210 kid.GetRootNode(&GetRootNodeOptions::empty())
3212 .assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Skip);
3213
3214 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
3217 if descendant.is_connected() {
3220 static_node_list.push(descendant.clone());
3221 }
3222
3223 if let Some(descendant) = DomRoot::downcast::<Element>(descendant) {
3229 if descendant.is_custom() {
3230 if descendant.is_connected() {
3231 custom_element_reaction_stack.enqueue_callback_reaction(
3232 &descendant,
3233 CallbackReaction::Connected,
3234 None,
3235 );
3236 }
3237 } else {
3238 try_upgrade_element(&descendant);
3239 }
3240 }
3241 }
3242 }
3243
3244 if let SuppressObserver::Unsuppressed = suppress_observers {
3245 vtable_for(parent).children_changed(
3248 cx,
3249 &ChildrenMutation::insert(previous_sibling.as_deref(), new_nodes, child),
3250 );
3251
3252 let mutation = LazyCell::new(|| Mutation::ChildList {
3255 added: Some(new_nodes),
3256 removed: None,
3257 prev: previous_sibling.as_deref(),
3258 next: child,
3259 });
3260 MutationObserver::queue_a_mutation_record(parent, mutation);
3261 }
3262
3263 parent_document.add_delayed_task(
3274 task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
3275 for node in static_node_list {
3278 vtable_for(&node).post_connection_steps(cx);
3279 }
3280 }),
3281 );
3282
3283 parent_document.remove_script_and_layout_blocker();
3284 from_document.remove_script_and_layout_blocker();
3285 }
3286
3287 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
3289 parent.owner_doc().add_script_and_layout_blocker();
3290
3291 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
3293
3294 rooted_vec!(let mut added_nodes);
3298 let added_nodes = if let Some(node) = node.as_ref() {
3299 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
3300 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
3301 added_nodes.r()
3302 } else {
3303 from_ref(node)
3304 }
3305 } else {
3306 &[] as &[&Node]
3307 };
3308
3309 for child in &*removed_nodes {
3311 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
3312 }
3313
3314 if let Some(node) = node {
3316 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
3317 }
3318
3319 vtable_for(parent).children_changed(
3320 cx,
3321 &ChildrenMutation::replace_all(removed_nodes.r(), added_nodes),
3322 );
3323
3324 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
3327 let mutation = LazyCell::new(|| Mutation::ChildList {
3328 added: Some(added_nodes),
3329 removed: Some(removed_nodes.r()),
3330 prev: None,
3331 next: None,
3332 });
3333 MutationObserver::queue_a_mutation_record(parent, mutation);
3334 }
3335 parent.owner_doc().remove_script_and_layout_blocker();
3336 }
3337
3338 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
3340 if string.is_empty() {
3341 Node::replace_all(cx, None, parent);
3342 } else {
3343 let text = Text::new(cx, string, &parent.owner_document());
3344 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
3345 };
3346 }
3347
3348 fn pre_remove(cx: &mut JSContext, child: &Node, parent: &Node) -> Fallible<DomRoot<Node>> {
3350 match child.GetParentNode() {
3352 Some(ref node) if &**node != parent => return Err(Error::NotFound(None)),
3353 None => return Err(Error::NotFound(None)),
3354 _ => (),
3355 }
3356
3357 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
3359
3360 Ok(DomRoot::from_ref(child))
3362 }
3363
3364 fn remove(
3366 cx: &mut JSContext,
3367 node: &Node,
3368 parent: &Node,
3369 suppress_observers: SuppressObserver,
3370 ) {
3371 parent.owner_doc().add_script_and_layout_blocker();
3372
3373 assert!(
3377 node.GetParentNode()
3378 .is_some_and(|node_parent| &*node_parent == parent)
3379 );
3380
3381 let cached_index = Node::live_range_pre_remove_steps(node, parent);
3384
3385 let old_previous_sibling = node.GetPreviousSibling();
3389
3390 let old_next_sibling = node.GetNextSibling();
3392
3393 parent.remove_child(node, cached_index, CanGc::from_cx(cx));
3396
3397 if let Some(slot) = node.assigned_slot() {
3399 slot.assign_slottables();
3400 }
3401
3402 if parent.is_in_a_shadow_tree() {
3405 if let Some(slot_element) = parent.downcast::<HTMLSlotElement>() {
3406 if !slot_element.has_assigned_nodes() {
3407 slot_element.signal_a_slot_change();
3408 }
3409 }
3410 }
3411
3412 let has_slot_descendant = node
3414 .traverse_preorder(ShadowIncluding::No)
3415 .any(|elem| elem.is::<HTMLSlotElement>());
3416 if has_slot_descendant {
3417 parent
3419 .GetRootNode(&GetRootNodeOptions::empty())
3420 .assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Skip);
3421
3422 node.assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Force);
3424 }
3425
3426 if let SuppressObserver::Unsuppressed = suppress_observers {
3430 vtable_for(parent).children_changed(
3431 cx,
3432 &ChildrenMutation::replace(
3433 old_previous_sibling.as_deref(),
3434 &Some(node),
3435 &[],
3436 old_next_sibling.as_deref(),
3437 ),
3438 );
3439
3440 let removed = [node];
3441 let mutation = LazyCell::new(|| Mutation::ChildList {
3442 added: None,
3443 removed: Some(&removed),
3444 prev: old_previous_sibling.as_deref(),
3445 next: old_next_sibling.as_deref(),
3446 });
3447 MutationObserver::queue_a_mutation_record(parent, mutation);
3448 }
3449 parent.owner_doc().remove_script_and_layout_blocker();
3450 }
3451
3452 fn live_range_pre_remove_steps(node: &Node, parent: &Node) -> Option<u32> {
3454 if parent.ranges_is_empty() {
3455 return None;
3456 }
3457
3458 let index = node.index();
3464
3465 parent.ranges().decrease_above(parent, index, 1);
3472
3473 Some(index)
3477 }
3478
3479 fn compute_attribute_value_with_style_fast_path(attr: &Dom<Attr>, elem: &Element) -> AttrValue {
3485 if *attr.local_name() == local_name!("style") {
3486 if let Some(ref pdb) = *elem.style_attribute().borrow() {
3487 let document = elem.owner_document();
3488 let shared_lock = document.style_shared_lock();
3489 let new_pdb = pdb.read_with(&shared_lock.read()).clone();
3490 return AttrValue::Declaration(
3491 (**attr.value()).to_owned(),
3492 ServoArc::new(shared_lock.wrap(new_pdb)),
3493 );
3494 }
3495 }
3496
3497 attr.value().clone()
3498 }
3499
3500 pub(crate) fn clone(
3502 cx: &mut JSContext,
3503 node: &Node,
3504 maybe_doc: Option<&Document>,
3505 clone_children: CloneChildrenFlag,
3506 registry: Option<DomRoot<CustomElementRegistry>>,
3507 ) -> DomRoot<Node> {
3508 let document = match maybe_doc {
3510 Some(doc) => DomRoot::from_ref(doc),
3511 None => node.owner_doc(),
3512 };
3513
3514 let copy: DomRoot<Node> = match node.type_id() {
3517 NodeTypeId::DocumentType => {
3518 let doctype = node.downcast::<DocumentType>().unwrap();
3519 let doctype = DocumentType::new(
3520 cx,
3521 doctype.name().clone(),
3522 Some(doctype.public_id().clone()),
3523 Some(doctype.system_id().clone()),
3524 &document,
3525 );
3526 DomRoot::upcast::<Node>(doctype)
3527 },
3528 NodeTypeId::Attr => {
3529 let attr = node.downcast::<Attr>().unwrap();
3530 let attr = Attr::new(
3531 cx,
3532 &document,
3533 attr.local_name().clone(),
3534 attr.value().clone(),
3535 attr.name().clone(),
3536 attr.namespace().clone(),
3537 attr.prefix().cloned(),
3538 None,
3539 );
3540 DomRoot::upcast::<Node>(attr)
3541 },
3542 NodeTypeId::DocumentFragment(_) => {
3543 let doc_fragment = DocumentFragment::new(cx, &document);
3544 DomRoot::upcast::<Node>(doc_fragment)
3545 },
3546 NodeTypeId::CharacterData(_) => {
3547 let cdata = node.downcast::<CharacterData>().unwrap();
3548 cdata.clone_with_data(cx, cdata.Data(), &document)
3549 },
3550 NodeTypeId::Document(_) => {
3551 let document = node.downcast::<Document>().unwrap();
3554 let is_html_doc = if document.is_html_document() {
3555 IsHTMLDocument::HTMLDocument
3556 } else {
3557 IsHTMLDocument::NonHTMLDocument
3558 };
3559 let window = document.window();
3560 let loader = DocumentLoader::new(&document.loader());
3561 let document = Document::new(
3562 window,
3563 HasBrowsingContext::No,
3564 Some(document.url()),
3565 None,
3566 document.origin().clone(),
3568 is_html_doc,
3569 None,
3570 None,
3571 DocumentActivity::Inactive,
3572 DocumentSource::NotFromParser,
3573 loader,
3574 None,
3575 document.status_code(),
3576 Default::default(),
3577 false,
3578 document.allow_declarative_shadow_roots(),
3579 Some(document.insecure_requests_policy()),
3580 document.has_trustworthy_ancestor_or_current_origin(),
3581 document.custom_element_reaction_stack(),
3582 document.creation_sandboxing_flag_set(),
3583 CanGc::from_cx(cx),
3584 );
3585 DomRoot::upcast::<Node>(document)
3589 },
3590 NodeTypeId::Element(..) => {
3592 let element = node.downcast::<Element>().unwrap();
3593 let registry = element.custom_element_registry().or(registry);
3596 let registry =
3599 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3600 Some(document.custom_element_registry())
3601 } else {
3602 registry
3603 };
3604 let name = QualName {
3608 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3609 ns: element.namespace().clone(),
3610 local: element.local_name().clone(),
3611 };
3612 let element = Element::create(
3613 cx,
3614 name,
3615 element.get_is(),
3616 &document,
3617 ElementCreator::ScriptCreated,
3618 CustomElementCreationMode::Asynchronous,
3619 None,
3620 );
3621 element.set_custom_element_registry(registry);
3623 DomRoot::upcast::<Node>(element)
3624 },
3625 };
3626
3627 let document = match copy.downcast::<Document>() {
3630 Some(doc) => DomRoot::from_ref(doc),
3631 None => DomRoot::from_ref(&*document),
3632 };
3633 assert!(copy.owner_doc() == document);
3634
3635 match node.type_id() {
3637 NodeTypeId::Document(_) => {
3638 let node_doc = node.downcast::<Document>().unwrap();
3639 let copy_doc = copy.downcast::<Document>().unwrap();
3640 copy_doc.set_encoding(node_doc.encoding());
3641 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3642 },
3643 NodeTypeId::Element(..) => {
3644 let node_elem = node.downcast::<Element>().unwrap();
3645 let copy_elem = copy.downcast::<Element>().unwrap();
3646
3647 for attr in node_elem.attrs().iter() {
3649 let new_value =
3651 Node::compute_attribute_value_with_style_fast_path(attr, node_elem);
3652 copy_elem.push_new_attribute(
3654 attr.local_name().clone(),
3655 new_value,
3656 attr.name().clone(),
3657 attr.namespace().clone(),
3658 attr.prefix().cloned(),
3659 AttributeMutationReason::ByCloning,
3660 CanGc::from_cx(cx),
3661 );
3662 }
3663 },
3664 _ => (),
3665 }
3666
3667 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3670
3671 if clone_children == CloneChildrenFlag::CloneChildren {
3674 for child in node.children() {
3675 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3676 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3677 }
3678 }
3679
3680 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3683 let node_elem = node.downcast::<Element>().unwrap();
3684 let copy_elem = copy.downcast::<Element>().unwrap();
3685
3686 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3687 assert!(!copy_elem.is_shadow_host());
3689
3690 let copy_shadow_root =
3694 copy_elem.attach_shadow(
3695 cx,
3696 IsUserAgentWidget::No,
3697 shadow_root.Mode(),
3698 shadow_root.Clonable(),
3699 shadow_root.Serializable(),
3700 shadow_root.DelegatesFocus(),
3701 shadow_root.SlotAssignment(),
3702 )
3703 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3704
3705 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3707
3708 for child in shadow_root.upcast::<Node>().children() {
3711 let child_copy = Node::clone(
3712 cx,
3713 &child,
3714 Some(&document),
3715 CloneChildrenFlag::CloneChildren,
3716 None,
3717 );
3718
3719 let _inserted_node =
3721 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3722 }
3723 }
3724 }
3725
3726 copy
3728 }
3729
3730 pub(crate) fn child_text_content(&self) -> DOMString {
3732 Node::collect_text_contents(self.children())
3733 }
3734
3735 pub(crate) fn descendant_text_content(&self) -> DOMString {
3737 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3738 }
3739
3740 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3741 iterator: T,
3742 ) -> DOMString {
3743 let mut content = String::new();
3744 for node in iterator {
3745 if let Some(text) = node.downcast::<Text>() {
3746 content.push_str(&text.upcast::<CharacterData>().data());
3747 }
3748 }
3749 DOMString::from(content)
3750 }
3751
3752 pub(crate) fn set_text_content_for_element(
3754 &self,
3755 cx: &mut JSContext,
3756 value: Option<DOMString>,
3757 ) {
3758 assert!(matches!(
3761 self.type_id(),
3762 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3763 ));
3764 let value = value.unwrap_or_default();
3765 let node = if value.is_empty() {
3766 None
3768 } else {
3769 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3772 };
3773
3774 Self::replace_all(cx, node.as_deref(), self);
3776 }
3777
3778 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3779 match namespace {
3780 ns!() => None,
3781 _ => Some(DOMString::from(&*namespace)),
3783 }
3784 }
3785
3786 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3788 match node.type_id() {
3789 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3790 NodeTypeId::Attr => node
3791 .downcast::<Attr>()
3792 .unwrap()
3793 .GetOwnerElement()
3794 .as_ref()
3795 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3796 NodeTypeId::Document(_) => node
3797 .downcast::<Document>()
3798 .unwrap()
3799 .GetDocumentElement()
3800 .as_ref()
3801 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3802 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3803 _ => node
3804 .GetParentElement()
3805 .as_ref()
3806 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3807 }
3808 }
3809
3810 #[expect(unsafe_code)]
3818 pub(crate) unsafe fn from_untrusted_node_address(
3819 candidate: UntrustedNodeAddress,
3820 ) -> &'static Self {
3821 let candidate = candidate.0 as usize;
3823 let object = candidate as *mut JSObject;
3824 if object.is_null() {
3825 panic!("Attempted to create a `Node` from an invalid pointer!")
3826 }
3827
3828 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3829 }
3830
3831 pub(crate) fn html_serialize(
3832 &self,
3833 cx: &mut js::context::JSContext,
3834 traversal_scope: html_serialize::TraversalScope,
3835 serialize_shadow_roots: bool,
3836 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3837 ) -> DOMString {
3838 let mut writer = vec![];
3839 let mut serializer = HtmlSerializer::new(
3840 &mut writer,
3841 html_serialize::SerializeOpts {
3842 traversal_scope: traversal_scope.clone(),
3843 ..Default::default()
3844 },
3845 );
3846
3847 serialize_html_fragment(
3848 cx,
3849 self,
3850 &mut serializer,
3851 traversal_scope,
3852 serialize_shadow_roots,
3853 shadow_roots,
3854 )
3855 .expect("Serializing node failed");
3856
3857 DOMString::from(String::from_utf8(writer).unwrap())
3859 }
3860
3861 pub(crate) fn xml_serialize(
3863 &self,
3864 traversal_scope: xml_serialize::TraversalScope,
3865 ) -> Fallible<DOMString> {
3866 let mut writer = vec![];
3867 xml_serialize::serialize(
3868 &mut writer,
3869 &HtmlSerialize::new(self),
3870 xml_serialize::SerializeOpts { traversal_scope },
3871 )
3872 .map_err(|error| {
3873 error!("Cannot serialize node: {error}");
3874 Error::InvalidState(None)
3875 })?;
3876
3877 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3879 error!("Cannot serialize node: {error}");
3880 Error::InvalidState(None)
3881 })?);
3882
3883 Ok(string)
3884 }
3885
3886 pub(crate) fn fragment_serialization_algorithm(
3888 &self,
3889 cx: &mut js::context::JSContext,
3890 require_well_formed: bool,
3891 ) -> Fallible<DOMString> {
3892 let context_document = self.owner_document();
3894
3895 if context_document.is_html_document() {
3898 return Ok(self.html_serialize(
3899 cx,
3900 html_serialize::TraversalScope::ChildrenOnly(None),
3901 false,
3902 vec![],
3903 ));
3904 }
3905
3906 let _ = require_well_formed;
3909 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3910 }
3911
3912 fn get_next_sibling_unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, Node>> {
3913 self.next_sibling.get_unrooted(no_gc)
3914 }
3915
3916 fn get_previous_sibling_unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, Node>> {
3917 self.prev_sibling.get_unrooted(no_gc)
3918 }
3919
3920 fn get_first_child_unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, Node>> {
3921 self.first_child.get_unrooted(no_gc)
3922 }
3923}
3924
3925impl NodeMethods<crate::DomTypeHolder> for Node {
3926 fn NodeType(&self) -> u16 {
3928 match self.type_id() {
3929 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3930 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3931 NodeConstants::TEXT_NODE
3932 },
3933 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3934 NodeConstants::CDATA_SECTION_NODE
3935 },
3936 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3937 NodeConstants::PROCESSING_INSTRUCTION_NODE
3938 },
3939 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3940 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3941 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3942 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3943 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3944 }
3945 }
3946
3947 fn NodeName(&self) -> DOMString {
3949 match self.type_id() {
3950 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3951 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3952 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3953 DOMString::from("#text")
3954 },
3955 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3956 DOMString::from("#cdata-section")
3957 },
3958 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3959 self.downcast::<ProcessingInstruction>().unwrap().Target()
3960 },
3961 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => DOMString::from("#comment"),
3962 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3963 NodeTypeId::DocumentFragment(_) => DOMString::from("#document-fragment"),
3964 NodeTypeId::Document(_) => DOMString::from("#document"),
3965 }
3966 }
3967
3968 fn BaseURI(&self) -> USVString {
3970 USVString(String::from(self.owner_doc().base_url().as_str()))
3971 }
3972
3973 fn IsConnected(&self) -> bool {
3975 self.is_connected()
3976 }
3977
3978 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3980 match self.type_id() {
3981 NodeTypeId::Document(_) => None,
3982 _ => Some(self.owner_doc()),
3983 }
3984 }
3985
3986 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3988 if !options.composed {
3989 if let Some(shadow_root) = self.containing_shadow_root() {
3990 return DomRoot::upcast(shadow_root);
3991 }
3992 }
3993
3994 if self.is_connected() {
3995 DomRoot::from_ref(self.owner_doc().upcast::<Node>())
3996 } else {
3997 self.inclusive_ancestors(ShadowIncluding::Yes)
3998 .last()
3999 .unwrap()
4000 }
4001 }
4002
4003 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
4005 self.parent_node.get()
4006 }
4007
4008 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
4010 self.GetParentNode().and_then(DomRoot::downcast)
4011 }
4012
4013 fn HasChildNodes(&self) -> bool {
4015 self.first_child.get().is_some()
4016 }
4017
4018 fn ChildNodes(&self, can_gc: CanGc) -> DomRoot<NodeList> {
4020 if let Some(list) = self.ensure_rare_data().child_list.get() {
4021 return list;
4022 }
4023
4024 let doc = self.owner_doc();
4025 let window = doc.window();
4026 let list = NodeList::new_child_list(window, self, can_gc);
4027 self.ensure_rare_data().child_list.set(Some(&list));
4028 list
4029 }
4030
4031 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
4033 self.first_child.get()
4034 }
4035
4036 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
4038 self.last_child.get()
4039 }
4040
4041 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
4043 self.prev_sibling.get()
4044 }
4045
4046 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
4048 self.next_sibling.get()
4049 }
4050
4051 fn GetNodeValue(&self) -> Option<DOMString> {
4053 match self.type_id() {
4054 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
4055 NodeTypeId::CharacterData(_) => {
4056 self.downcast::<CharacterData>().map(CharacterData::Data)
4057 },
4058 _ => None,
4059 }
4060 }
4061
4062 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
4064 match self.type_id() {
4065 NodeTypeId::Attr => {
4066 let attr = self.downcast::<Attr>().unwrap();
4067 attr.SetValue(cx, val.unwrap_or_default())?;
4068 },
4069 NodeTypeId::CharacterData(_) => {
4070 let character_data = self.downcast::<CharacterData>().unwrap();
4071 character_data.SetData(val.unwrap_or_default());
4072 },
4073 _ => {},
4074 };
4075 Ok(())
4076 }
4077
4078 fn GetTextContent(&self) -> Option<DOMString> {
4080 match self.type_id() {
4081 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
4082 let content =
4083 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
4084 Some(content)
4085 },
4086 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
4087 NodeTypeId::CharacterData(..) => {
4088 let characterdata = self.downcast::<CharacterData>().unwrap();
4089 Some(characterdata.Data())
4090 },
4091 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
4092 }
4093 }
4094
4095 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
4097 match self.type_id() {
4098 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
4099 self.set_text_content_for_element(cx, value);
4100 },
4101 NodeTypeId::Attr => {
4102 let attr = self.downcast::<Attr>().unwrap();
4103 attr.SetValue(cx, value.unwrap_or_default())?;
4104 },
4105 NodeTypeId::CharacterData(..) => {
4106 let characterdata = self.downcast::<CharacterData>().unwrap();
4107 characterdata.SetData(value.unwrap_or_default());
4108 },
4109 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
4110 };
4111 Ok(())
4112 }
4113
4114 fn InsertBefore(
4116 &self,
4117 cx: &mut JSContext,
4118 node: &Node,
4119 child: Option<&Node>,
4120 ) -> Fallible<DomRoot<Node>> {
4121 Node::pre_insert(cx, node, self, child)
4122 }
4123
4124 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
4126 Node::pre_insert(cx, node, self, None)
4127 }
4128
4129 fn ReplaceChild(
4131 &self,
4132 cx: &mut JSContext,
4133 node: &Node,
4134 child: &Node,
4135 ) -> Fallible<DomRoot<Node>> {
4136 match self.type_id() {
4139 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
4140 },
4141 _ => return Err(Error::HierarchyRequest(None)),
4142 }
4143
4144 if node.is_inclusive_ancestor_of(self) {
4147 return Err(Error::HierarchyRequest(None));
4148 }
4149
4150 if !self.is_parent_of(child) {
4152 return Err(Error::NotFound(None));
4153 }
4154
4155 match node.type_id() {
4160 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
4161 return Err(Error::HierarchyRequest(None));
4162 },
4163 NodeTypeId::DocumentType if !self.is::<Document>() => {
4164 return Err(Error::HierarchyRequest(None));
4165 },
4166 NodeTypeId::Document(_) | NodeTypeId::Attr => {
4167 return Err(Error::HierarchyRequest(None));
4168 },
4169 _ => (),
4170 }
4171
4172 if self.is::<Document>() {
4175 match node.type_id() {
4176 NodeTypeId::DocumentFragment(_) => {
4178 if node.children().any(|c| c.is::<Text>()) {
4180 return Err(Error::HierarchyRequest(None));
4181 }
4182 match node.child_elements().count() {
4183 0 => (),
4184 1 => {
4186 if self.child_elements().any(|c| c.upcast::<Node>() != child) {
4187 return Err(Error::HierarchyRequest(None));
4188 }
4189 if child.following_siblings().any(|child| child.is_doctype()) {
4190 return Err(Error::HierarchyRequest(None));
4191 }
4192 },
4193 _ => return Err(Error::HierarchyRequest(None)),
4195 }
4196 },
4197 NodeTypeId::Element(..) => {
4199 if self.child_elements().any(|c| c.upcast::<Node>() != child) {
4200 return Err(Error::HierarchyRequest(None));
4201 }
4202 if child.following_siblings().any(|child| child.is_doctype()) {
4203 return Err(Error::HierarchyRequest(None));
4204 }
4205 },
4206 NodeTypeId::DocumentType => {
4208 if self.children().any(|c| c.is_doctype() && &*c != child) {
4209 return Err(Error::HierarchyRequest(None));
4210 }
4211 if self
4212 .children()
4213 .take_while(|c| &**c != child)
4214 .any(|c| c.is::<Element>())
4215 {
4216 return Err(Error::HierarchyRequest(None));
4217 }
4218 },
4219 NodeTypeId::CharacterData(..) => (),
4220 NodeTypeId::Document(_) => unreachable!(),
4223 NodeTypeId::Attr => unreachable!(),
4224 }
4225 }
4226
4227 let child_next_sibling = child.GetNextSibling();
4230 let node_next_sibling = node.GetNextSibling();
4231 let reference_child = if child_next_sibling.as_deref() == Some(node) {
4232 node_next_sibling.as_deref()
4233 } else {
4234 child_next_sibling.as_deref()
4235 };
4236
4237 let previous_sibling = child.GetPreviousSibling();
4239
4240 let document = self.owner_document();
4244 Node::adopt(cx, node, &document);
4245
4246 let removed_child = if node != child {
4251 Node::remove(cx, child, self, SuppressObserver::Suppressed);
4253 Some(child)
4254 } else {
4255 None
4256 };
4257
4258 rooted_vec!(let mut nodes);
4260 let nodes = if node.type_id() ==
4261 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
4262 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
4263 {
4264 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
4265 nodes.r()
4266 } else {
4267 from_ref(&node)
4268 };
4269
4270 Node::insert(
4272 cx,
4273 node,
4274 self,
4275 reference_child,
4276 SuppressObserver::Suppressed,
4277 );
4278
4279 vtable_for(self).children_changed(
4280 cx,
4281 &ChildrenMutation::replace(
4282 previous_sibling.as_deref(),
4283 &removed_child,
4284 nodes,
4285 reference_child,
4286 ),
4287 );
4288
4289 let removed = removed_child.map(|r| [r]);
4292 let mutation = LazyCell::new(|| Mutation::ChildList {
4293 added: Some(nodes),
4294 removed: removed.as_ref().map(|r| &r[..]),
4295 prev: previous_sibling.as_deref(),
4296 next: reference_child,
4297 });
4298
4299 MutationObserver::queue_a_mutation_record(self, mutation);
4300
4301 Ok(DomRoot::from_ref(child))
4303 }
4304
4305 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
4307 Node::pre_remove(cx, node, self)
4308 }
4309
4310 fn Normalize(&self, cx: &mut JSContext) {
4312 let mut children = self.children().enumerate().peekable();
4313 while let Some((_, node)) = children.next() {
4314 if let Some(text) = node.downcast::<Text>() {
4315 if text.is::<CDATASection>() {
4316 continue;
4317 }
4318 let cdata = text.upcast::<CharacterData>();
4319 let mut length = cdata.Length();
4320 if length == 0 {
4321 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
4322 continue;
4323 }
4324 while children.peek().is_some_and(|(_, sibling)| {
4325 sibling.is::<Text>() && !sibling.is::<CDATASection>()
4326 }) {
4327 let (index, sibling) = children.next().unwrap();
4328 sibling
4329 .ranges()
4330 .drain_to_preceding_text_sibling(&sibling, &node, length);
4331 self.ranges()
4332 .move_to_text_child_at(self, index as u32, &node, length);
4333 let sibling_cdata = sibling.downcast::<CharacterData>().unwrap();
4334 length += sibling_cdata.Length();
4335 cdata.append_data(&sibling_cdata.data());
4336 Node::remove(cx, &sibling, self, SuppressObserver::Unsuppressed);
4337 }
4338 } else {
4339 node.Normalize(cx);
4340 }
4341 }
4342 }
4343
4344 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
4346 if self.is::<ShadowRoot>() {
4348 return Err(Error::NotSupported(None));
4349 }
4350
4351 let result = Node::clone(
4353 cx,
4354 self,
4355 None,
4356 if subtree {
4357 CloneChildrenFlag::CloneChildren
4358 } else {
4359 CloneChildrenFlag::DoNotCloneChildren
4360 },
4361 None,
4362 );
4363 Ok(result)
4364 }
4365
4366 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
4368 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
4369 let doctype = node.downcast::<DocumentType>().unwrap();
4370 let other_doctype = other.downcast::<DocumentType>().unwrap();
4371 (*doctype.name() == *other_doctype.name()) &&
4372 (*doctype.public_id() == *other_doctype.public_id()) &&
4373 (*doctype.system_id() == *other_doctype.system_id())
4374 }
4375 fn is_equal_element(node: &Node, other: &Node) -> bool {
4376 let element = node.downcast::<Element>().unwrap();
4377 let other_element = other.downcast::<Element>().unwrap();
4378 (*element.namespace() == *other_element.namespace()) &&
4379 (*element.prefix() == *other_element.prefix()) &&
4380 (*element.local_name() == *other_element.local_name()) &&
4381 (element.attrs().len() == other_element.attrs().len())
4382 }
4383 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
4384 let pi = node.downcast::<ProcessingInstruction>().unwrap();
4385 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
4386 (*pi.target() == *other_pi.target()) &&
4387 (*pi.upcast::<CharacterData>().data() ==
4388 *other_pi.upcast::<CharacterData>().data())
4389 }
4390 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
4391 let characterdata = node.downcast::<CharacterData>().unwrap();
4392 let other_characterdata = other.downcast::<CharacterData>().unwrap();
4393 *characterdata.data() == *other_characterdata.data()
4394 }
4395 fn is_equal_attr(node: &Node, other: &Node) -> bool {
4396 let attr = node.downcast::<Attr>().unwrap();
4397 let other_attr = other.downcast::<Attr>().unwrap();
4398 (*attr.namespace() == *other_attr.namespace()) &&
4399 (attr.local_name() == other_attr.local_name()) &&
4400 (**attr.value() == **other_attr.value())
4401 }
4402 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
4403 let element = node.downcast::<Element>().unwrap();
4404 let other_element = other.downcast::<Element>().unwrap();
4405 assert!(element.attrs().len() == other_element.attrs().len());
4406 element.attrs().iter().all(|attr| {
4407 other_element.attrs().iter().any(|other_attr| {
4408 (*attr.namespace() == *other_attr.namespace()) &&
4409 (attr.local_name() == other_attr.local_name()) &&
4410 (**attr.value() == **other_attr.value())
4411 })
4412 })
4413 }
4414
4415 fn is_equal_node(this: &Node, node: &Node) -> bool {
4416 if this.NodeType() != node.NodeType() {
4418 return false;
4419 }
4420
4421 match node.type_id() {
4422 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
4424 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
4425 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
4426 if !is_equal_processinginstruction(this, node) =>
4427 {
4428 return false;
4429 },
4430 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
4431 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
4432 if !is_equal_characterdata(this, node) =>
4433 {
4434 return false;
4435 },
4436 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
4438 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
4439
4440 _ => (),
4441 }
4442
4443 if this.children_count() != node.children_count() {
4445 return false;
4446 }
4447
4448 this.children()
4450 .zip(node.children())
4451 .all(|(child, other_child)| is_equal_node(&child, &other_child))
4452 }
4453 match maybe_node {
4454 None => false,
4456 Some(node) => is_equal_node(self, node),
4458 }
4459 }
4460
4461 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
4463 match other_node {
4464 Some(node) => self == node,
4465 None => false,
4466 }
4467 }
4468
4469 fn CompareDocumentPosition(&self, other: &Node) -> u16 {
4471 if self == other {
4473 return 0;
4474 }
4475
4476 let mut node1 = Some(other);
4478 let mut node2 = Some(self);
4479
4480 let mut attr1: Option<&Attr> = None;
4482 let mut attr2: Option<&Attr> = None;
4483
4484 let attr1owner;
4489 if let Some(a) = other.downcast::<Attr>() {
4490 attr1 = Some(a);
4491 attr1owner = a.GetOwnerElement();
4492 node1 = match attr1owner {
4493 Some(ref e) => Some(e.upcast()),
4494 None => None,
4495 }
4496 }
4497
4498 let attr2owner;
4501 if let Some(a) = self.downcast::<Attr>() {
4502 attr2 = Some(a);
4503 attr2owner = a.GetOwnerElement();
4504 node2 = match attr2owner {
4505 Some(ref e) => Some(e.upcast()),
4506 None => None,
4507 }
4508 }
4509
4510 if let Some(node2) = node2 {
4515 if Some(node2) == node1 {
4516 if let (Some(a1), Some(a2)) = (attr1, attr2) {
4517 let attrs = node2.downcast::<Element>().unwrap().attrs();
4518 for attr in attrs.iter() {
4522 if (*attr.namespace() == *a1.namespace()) &&
4523 (attr.local_name() == a1.local_name()) &&
4524 (**attr.value() == **a1.value())
4525 {
4526 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4527 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4528 }
4529 if (*attr.namespace() == *a2.namespace()) &&
4530 (attr.local_name() == a2.local_name()) &&
4531 (**attr.value() == **a2.value())
4532 {
4533 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4534 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4535 }
4536 }
4537 unreachable!();
4540 }
4541 }
4542 }
4543
4544 match (node1, node2) {
4546 (None, _) => {
4547 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4549 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4550 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4551 },
4552 (_, None) => {
4553 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4555 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4556 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4557 },
4558 (Some(node1), Some(node2)) => {
4559 let mut self_and_ancestors = node2
4561 .inclusive_ancestors(ShadowIncluding::No)
4562 .collect::<SmallVec<[_; 20]>>();
4563 let mut other_and_ancestors = node1
4564 .inclusive_ancestors(ShadowIncluding::No)
4565 .collect::<SmallVec<[_; 20]>>();
4566
4567 if self_and_ancestors.last() != other_and_ancestors.last() {
4568 let random = as_uintptr(self_and_ancestors.last().unwrap()) <
4569 as_uintptr(other_and_ancestors.last().unwrap());
4570 let random = if random {
4571 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4572 } else {
4573 NodeConstants::DOCUMENT_POSITION_PRECEDING
4574 };
4575
4576 return random +
4578 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4579 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4580 }
4581 let mut parent = self_and_ancestors.pop().unwrap();
4583 other_and_ancestors.pop().unwrap();
4584
4585 let mut current_position =
4586 cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
4587
4588 while current_position > 0 {
4589 current_position -= 1;
4590 let child_1 = self_and_ancestors.pop().unwrap();
4591 let child_2 = other_and_ancestors.pop().unwrap();
4592
4593 if child_1 != child_2 {
4594 for child in parent.children() {
4595 if child == child_1 {
4596 return NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4598 }
4599 if child == child_2 {
4600 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4602 }
4603 }
4604 }
4605
4606 parent = child_1;
4607 }
4608
4609 if self_and_ancestors.len() < other_and_ancestors.len() {
4614 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4615 NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
4616 } else {
4617 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4618 NodeConstants::DOCUMENT_POSITION_CONTAINS
4619 }
4620 },
4621 }
4622 }
4623
4624 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4626 match maybe_other {
4627 None => false,
4628 Some(other) => self.is_inclusive_ancestor_of(other),
4629 }
4630 }
4631
4632 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4634 let namespace = namespace_from_domstring(namespace);
4635
4636 if namespace == ns!() {
4638 return None;
4639 }
4640
4641 match self.type_id() {
4643 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4644 NodeTypeId::Document(_) => self
4645 .downcast::<Document>()
4646 .unwrap()
4647 .GetDocumentElement()
4648 .and_then(|element| element.lookup_prefix(namespace)),
4649 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4650 NodeTypeId::Attr => self
4651 .downcast::<Attr>()
4652 .unwrap()
4653 .GetOwnerElement()
4654 .and_then(|element| element.lookup_prefix(namespace)),
4655 _ => self
4656 .GetParentElement()
4657 .and_then(|element| element.lookup_prefix(namespace)),
4658 }
4659 }
4660
4661 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4663 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4665
4666 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4668 }
4669
4670 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4672 let namespace = namespace_from_domstring(namespace);
4674 Node::locate_namespace(self, None) == namespace
4676 }
4677}
4678
4679pub(crate) trait NodeTraits {
4680 fn owner_document(&self) -> DomRoot<Document>;
4684 fn owner_window(&self) -> DomRoot<Window>;
4688 fn owner_global(&self) -> DomRoot<GlobalScope>;
4692 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4694 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4697}
4698
4699impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4700 fn owner_document(&self) -> DomRoot<Document> {
4701 self.upcast().owner_doc()
4702 }
4703
4704 fn owner_window(&self) -> DomRoot<Window> {
4705 DomRoot::from_ref(self.owner_document().window())
4706 }
4707
4708 fn owner_global(&self) -> DomRoot<GlobalScope> {
4709 DomRoot::from_ref(self.owner_window().upcast())
4710 }
4711
4712 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4713 Node::containing_shadow_root(self.upcast())
4714 }
4715
4716 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4717 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4718 self.containing_shadow_root()
4719 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4720 .unwrap_or_else(|| {
4721 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4722 })
4723 }
4724}
4725
4726impl VirtualMethods for Node {
4727 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4728 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4729 }
4730
4731 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4732 if let Some(s) = self.super_type() {
4733 s.children_changed(cx, mutation);
4734 }
4735
4736 if let Some(data) = self.rare_data().as_ref() {
4737 if let Some(list) = data.child_list.get() {
4738 list.as_children_list().children_changed(mutation);
4739 }
4740 }
4741
4742 self.owner_doc().content_and_heritage_changed(self);
4743 }
4744
4745 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
4748 self.super_type().unwrap().unbind_from_tree(context, can_gc);
4749
4750 if !self.is_in_a_shadow_tree() && !self.ranges_is_empty() {
4755 self.ranges()
4756 .drain_to_parent(context.parent, context.index(), self);
4757 }
4758 }
4759
4760 fn moving_steps(&self, context: &MoveContext, can_gc: CanGc) {
4761 if let Some(super_type) = self.super_type() {
4762 super_type.moving_steps(context, can_gc);
4763 }
4764
4765 if let Some(old_parent) = context.old_parent {
4770 if !self.is_in_a_shadow_tree() && !self.ranges_is_empty() {
4771 self.ranges()
4772 .drain_to_parent(old_parent, context.index(), self);
4773 }
4774 }
4775
4776 self.owner_doc().content_and_heritage_changed(self);
4777 }
4778
4779 fn handle_event(&self, event: &Event, can_gc: CanGc) {
4780 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4781 return;
4782 }
4783
4784 if let Some(event) = event.downcast::<KeyboardEvent>() {
4785 self.owner_document()
4786 .event_handler()
4787 .run_default_keyboard_event_handler(self, event, can_gc);
4788 }
4789 }
4790}
4791
4792#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4794pub(crate) enum NodeDamage {
4795 Style,
4797 ContentOrHeritage,
4800 Other,
4802}
4803
4804pub(crate) enum ChildrenMutation<'a> {
4805 Append {
4806 prev: &'a Node,
4807 added: &'a [&'a Node],
4808 },
4809 Insert {
4810 prev: &'a Node,
4811 added: &'a [&'a Node],
4812 next: &'a Node,
4813 },
4814 Prepend {
4815 added: &'a [&'a Node],
4816 next: &'a Node,
4817 },
4818 Replace {
4819 prev: Option<&'a Node>,
4820 removed: &'a Node,
4821 added: &'a [&'a Node],
4822 next: Option<&'a Node>,
4823 },
4824 ReplaceAll {
4825 removed: &'a [&'a Node],
4826 added: &'a [&'a Node],
4827 },
4828 ChangeText,
4833}
4834
4835impl<'a> ChildrenMutation<'a> {
4836 fn insert(
4837 prev: Option<&'a Node>,
4838 added: &'a [&'a Node],
4839 next: Option<&'a Node>,
4840 ) -> ChildrenMutation<'a> {
4841 match (prev, next) {
4842 (None, None) => ChildrenMutation::ReplaceAll {
4843 removed: &[],
4844 added,
4845 },
4846 (Some(prev), None) => ChildrenMutation::Append { prev, added },
4847 (None, Some(next)) => ChildrenMutation::Prepend { added, next },
4848 (Some(prev), Some(next)) => ChildrenMutation::Insert { prev, added, next },
4849 }
4850 }
4851
4852 fn replace(
4853 prev: Option<&'a Node>,
4854 removed: &'a Option<&'a Node>,
4855 added: &'a [&'a Node],
4856 next: Option<&'a Node>,
4857 ) -> ChildrenMutation<'a> {
4858 if let Some(ref removed) = *removed {
4859 if let (None, None) = (prev, next) {
4860 ChildrenMutation::ReplaceAll {
4861 removed: from_ref(removed),
4862 added,
4863 }
4864 } else {
4865 ChildrenMutation::Replace {
4866 prev,
4867 removed,
4868 added,
4869 next,
4870 }
4871 }
4872 } else {
4873 ChildrenMutation::insert(prev, added, next)
4874 }
4875 }
4876
4877 fn replace_all(removed: &'a [&'a Node], added: &'a [&'a Node]) -> ChildrenMutation<'a> {
4878 ChildrenMutation::ReplaceAll { removed, added }
4879 }
4880
4881 pub(crate) fn next_child(&self) -> Option<&Node> {
4886 match *self {
4887 ChildrenMutation::Append { .. } => None,
4888 ChildrenMutation::Insert { next, .. } => Some(next),
4889 ChildrenMutation::Prepend { next, .. } => Some(next),
4890 ChildrenMutation::Replace { next, .. } => next,
4891 ChildrenMutation::ReplaceAll { .. } => None,
4892 ChildrenMutation::ChangeText => None,
4893 }
4894 }
4895
4896 pub(crate) fn modified_edge_element(&self) -> Option<DomRoot<Node>> {
4903 match *self {
4904 ChildrenMutation::Prepend { next, .. } |
4906 ChildrenMutation::Replace {
4907 prev: None,
4908 next: Some(next),
4909 ..
4910 } => next
4911 .inclusively_following_siblings()
4912 .find(|node| node.is::<Element>()),
4913 ChildrenMutation::Append { prev, .. } |
4915 ChildrenMutation::Replace {
4916 prev: Some(prev),
4917 next: None,
4918 ..
4919 } => prev
4920 .inclusively_preceding_siblings()
4921 .find(|node| node.is::<Element>()),
4922 ChildrenMutation::Insert { prev, next, .. } |
4924 ChildrenMutation::Replace {
4925 prev: Some(prev),
4926 next: Some(next),
4927 ..
4928 } => {
4929 if prev
4930 .inclusively_preceding_siblings()
4931 .all(|node| !node.is::<Element>())
4932 {
4933 next.inclusively_following_siblings()
4935 .find(|node| node.is::<Element>())
4936 } else if next
4937 .inclusively_following_siblings()
4938 .all(|node| !node.is::<Element>())
4939 {
4940 prev.inclusively_preceding_siblings()
4942 .find(|node| node.is::<Element>())
4943 } else {
4944 None
4945 }
4946 },
4947
4948 ChildrenMutation::Replace {
4949 prev: None,
4950 next: None,
4951 ..
4952 } => unreachable!(),
4953 ChildrenMutation::ReplaceAll { .. } => None,
4954 ChildrenMutation::ChangeText => None,
4955 }
4956 }
4957}
4958
4959pub(crate) struct BindContext<'a> {
4961 pub(crate) parent: &'a Node,
4963
4964 pub(crate) tree_connected: bool,
4968
4969 pub(crate) tree_is_in_a_document_tree: bool,
4973
4974 pub(crate) tree_is_in_a_shadow_tree: bool,
4976
4977 pub(crate) is_shadow_tree: IsShadowTree,
4982}
4983
4984#[derive(Debug, Eq, PartialEq)]
4985pub(crate) enum IsShadowTree {
4986 Yes,
4987 No,
4988}
4989
4990impl<'a> BindContext<'a> {
4991 pub(crate) fn new(parent: &'a Node, is_shadow_tree: IsShadowTree) -> Self {
4993 BindContext {
4994 parent,
4995 tree_connected: parent.is_connected(),
4996 tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
4997 tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
4998 is_shadow_tree,
4999 }
5000 }
5001
5002 pub(crate) fn is_in_tree(&self) -> bool {
5004 self.tree_is_in_a_document_tree || self.tree_is_in_a_shadow_tree
5005 }
5006}
5007
5008pub(crate) struct UnbindContext<'a> {
5011 index: Cell<Option<u32>>,
5013 pub(crate) parent: &'a Node,
5015 prev_sibling: Option<&'a Node>,
5017 pub(crate) next_sibling: Option<&'a Node>,
5019
5020 pub(crate) tree_connected: bool,
5024
5025 pub(crate) tree_is_in_a_document_tree: bool,
5029
5030 pub(crate) tree_is_in_a_shadow_tree: bool,
5032}
5033
5034impl<'a> UnbindContext<'a> {
5035 pub(crate) fn new(
5037 parent: &'a Node,
5038 prev_sibling: Option<&'a Node>,
5039 next_sibling: Option<&'a Node>,
5040 cached_index: Option<u32>,
5041 ) -> Self {
5042 UnbindContext {
5043 index: Cell::new(cached_index),
5044 parent,
5045 prev_sibling,
5046 next_sibling,
5047 tree_connected: parent.is_connected(),
5048 tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
5049 tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
5050 }
5051 }
5052
5053 pub(crate) fn index(&self) -> u32 {
5055 if let Some(index) = self.index.get() {
5056 return index;
5057 }
5058 let index = self.prev_sibling.map_or(0, |sibling| sibling.index() + 1);
5059 self.index.set(Some(index));
5060 index
5061 }
5062}
5063
5064pub(crate) struct MoveContext<'a> {
5067 index: Cell<Option<u32>>,
5069 pub(crate) old_parent: Option<&'a Node>,
5071 prev_sibling: Option<&'a Node>,
5073 pub(crate) next_sibling: Option<&'a Node>,
5075}
5076
5077impl<'a> MoveContext<'a> {
5078 pub(crate) fn new(
5080 old_parent: Option<&'a Node>,
5081 prev_sibling: Option<&'a Node>,
5082 next_sibling: Option<&'a Node>,
5083 cached_index: Option<u32>,
5084 ) -> Self {
5085 MoveContext {
5086 index: Cell::new(cached_index),
5087 old_parent,
5088 prev_sibling,
5089 next_sibling,
5090 }
5091 }
5092
5093 pub(crate) fn index(&self) -> u32 {
5095 if let Some(index) = self.index.get() {
5096 return index;
5097 }
5098 let index = self.prev_sibling.map_or(0, |sibling| sibling.index() + 1);
5099 self.index.set(Some(index));
5100 index
5101 }
5102}
5103
5104pub(crate) struct UniqueId {
5106 cell: UnsafeCell<Option<Box<Uuid>>>,
5107}
5108
5109unsafe_no_jsmanaged_fields!(UniqueId);
5110
5111impl MallocSizeOf for UniqueId {
5112 #[expect(unsafe_code)]
5113 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
5114 if let Some(uuid) = unsafe { &*self.cell.get() } {
5115 unsafe { ops.malloc_size_of(&**uuid) }
5116 } else {
5117 0
5118 }
5119 }
5120}
5121
5122impl UniqueId {
5123 fn new() -> UniqueId {
5125 UniqueId {
5126 cell: UnsafeCell::new(None),
5127 }
5128 }
5129
5130 #[expect(unsafe_code)]
5132 fn borrow(&self) -> &Uuid {
5133 unsafe {
5134 let ptr = self.cell.get();
5135 if (*ptr).is_none() {
5136 *ptr = Some(Box::new(Uuid::new_v4()));
5137 }
5138 (*ptr).as_ref().unwrap()
5139 }
5140 }
5141}
5142
5143pub(crate) struct NodeTypeIdWrapper(pub(crate) NodeTypeId);
5144
5145impl From<NodeTypeIdWrapper> for LayoutNodeType {
5146 #[inline(always)]
5147 fn from(node_type: NodeTypeIdWrapper) -> LayoutNodeType {
5148 match node_type.0 {
5149 NodeTypeId::Element(e) => LayoutNodeType::Element(ElementTypeIdWrapper(e).into()),
5150 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => LayoutNodeType::Text,
5151 x => unreachable!("Layout should not traverse nodes of type {:?}", x),
5152 }
5153 }
5154}
5155
5156struct ElementTypeIdWrapper(ElementTypeId);
5157
5158impl From<ElementTypeIdWrapper> for LayoutElementType {
5159 #[inline(always)]
5160 fn from(element_type: ElementTypeIdWrapper) -> LayoutElementType {
5161 match element_type.0 {
5162 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement) => {
5163 LayoutElementType::HTMLBodyElement
5164 },
5165 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBRElement) => {
5166 LayoutElementType::HTMLBRElement
5167 },
5168 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement) => {
5169 LayoutElementType::HTMLCanvasElement
5170 },
5171 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHtmlElement) => {
5172 LayoutElementType::HTMLHtmlElement
5173 },
5174 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement) => {
5175 LayoutElementType::HTMLIFrameElement
5176 },
5177 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement) => {
5178 LayoutElementType::HTMLImageElement
5179 },
5180 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(_)) => {
5181 LayoutElementType::HTMLMediaElement
5182 },
5183 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement) => {
5184 LayoutElementType::HTMLInputElement
5185 },
5186 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement) => {
5187 LayoutElementType::HTMLOptGroupElement
5188 },
5189 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement) => {
5190 LayoutElementType::HTMLOptionElement
5191 },
5192 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement) => {
5193 LayoutElementType::HTMLObjectElement
5194 },
5195 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLParagraphElement) => {
5196 LayoutElementType::HTMLParagraphElement
5197 },
5198 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLPreElement) => {
5199 LayoutElementType::HTMLPreElement
5200 },
5201 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement) => {
5202 LayoutElementType::HTMLSelectElement
5203 },
5204 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableCellElement) => {
5205 LayoutElementType::HTMLTableCellElement
5206 },
5207 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement) => {
5208 LayoutElementType::HTMLTableColElement
5209 },
5210 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement) => {
5211 LayoutElementType::HTMLTableElement
5212 },
5213 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement) => {
5214 LayoutElementType::HTMLTableRowElement
5215 },
5216 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement) => {
5217 LayoutElementType::HTMLTableSectionElement
5218 },
5219 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement) => {
5220 LayoutElementType::HTMLTextAreaElement
5221 },
5222 ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
5223 SVGGraphicsElementTypeId::SVGImageElement,
5224 )) => LayoutElementType::SVGImageElement,
5225 ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
5226 SVGGraphicsElementTypeId::SVGSVGElement,
5227 )) => LayoutElementType::SVGSVGElement,
5228 _ => LayoutElementType::Element,
5229 }
5230 }
5231}
5232
5233pub(crate) trait VecPreOrderInsertionHelper<T> {
5236 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
5237}
5238
5239impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
5240where
5241 T: DerivedFrom<Node> + DomObject,
5242{
5243 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node) {
5253 if self.is_empty() {
5254 self.push(Dom::from_ref(elem));
5255 return;
5256 }
5257
5258 let elem_node = elem.upcast::<Node>();
5259 let mut head: usize = 0;
5260 for node in tree_root.traverse_preorder(ShadowIncluding::No) {
5261 let head_node = DomRoot::upcast::<Node>(DomRoot::from_ref(&*self[head]));
5262 if head_node == node {
5263 head += 1;
5264 }
5265 if elem_node == &*node || head == self.len() {
5266 break;
5267 }
5268 }
5269 self.insert(head, Dom::from_ref(elem));
5270 }
5271}