1use std::borrow::Cow;
8use std::cell::{Cell, LazyCell, UnsafeCell};
9use std::cmp::Ordering;
10use std::default::Default;
11use std::f64::consts::PI;
12use std::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::{
30 AxesOverflow, BoxAreaType, CSSPixelRectVec, GenericLayoutData, HTMLCanvasData, HTMLMediaData,
31 LayoutElementType, LayoutNodeType, NodeRenderingType, PhysicalSides, SVGElementData,
32 SharedSelection, TrustedNodeAddress, with_layout_state,
33};
34use libc::{self, c_void, uintptr_t};
35use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
36use net_traits::image_cache::Image;
37use pixels::ImageMetadata;
38use script_bindings::cell::{DomRefCell, Ref, RefMut};
39use script_bindings::codegen::GenericBindings::EventBinding::EventMethods;
40use script_bindings::codegen::InheritTypes::DocumentFragmentTypeId;
41use script_bindings::reflector::{DomObject, DomObjectWrap, reflect_dom_object_with_proto_and_cx};
42use script_traits::DocumentActivity;
43use servo_arc::Arc as ServoArc;
44use servo_base::id::{BrowsingContextId, PipelineId};
45use servo_config::pref;
46use servo_url::ServoUrl;
47use smallvec::SmallVec;
48use style::Atom;
49use style::context::QuirksMode;
50use style::dom::OpaqueNode;
51use style::dom_apis::{QueryAll, QueryFirst};
52use style::selector_parser::PseudoElement;
53use style::stylesheets::Stylesheet;
54use style_traits::CSSPixel;
55use uuid::Uuid;
56use xml5ever::{local_name, serialize as xml_serialize};
57
58use crate::conversions::Convert;
59use crate::document_loader::DocumentLoader;
60use crate::dom::attr::Attr;
61use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
62use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
63use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
64use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
65use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
66use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
67use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
68use crate::dom::bindings::codegen::Bindings::NodeBinding::{
69 GetRootNodeOptions, NodeConstants, NodeMethods,
70};
71use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
72use crate::dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
73use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
74use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
75 ShadowRootMode, SlotAssignmentMode,
76};
77use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
78use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
79use crate::dom::bindings::conversions::{self, DerivedFrom};
80use crate::dom::bindings::domname::namespace_from_domstring;
81use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
82use crate::dom::bindings::inheritance::{
83 Castable, CharacterDataTypeId, ElementTypeId, EventTargetTypeId, HTMLElementTypeId, NodeTypeId,
84 SVGElementTypeId, SVGGraphicsElementTypeId, TextTypeId,
85};
86use crate::dom::bindings::root::{
87 Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout, UnrootedDom,
88};
89use crate::dom::bindings::str::{DOMString, USVString};
90use crate::dom::characterdata::CharacterData;
91use crate::dom::css::cssstylesheet::CSSStyleSheet;
92use crate::dom::css::stylesheetlist::StyleSheetListOwner;
93use crate::dom::customelementregistry::{
94 CallbackReaction, CustomElementRegistry, try_upgrade_element,
95};
96use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
97use crate::dom::documentfragment::DocumentFragment;
98use crate::dom::documenttype::DocumentType;
99use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
100use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
101use crate::dom::eventtarget::EventTarget;
102use crate::dom::globalscope::GlobalScope;
103use crate::dom::html::htmlcanvaselement::HTMLCanvasElement;
104use crate::dom::html::htmlcollection::HTMLCollection;
105use crate::dom::html::htmlelement::HTMLElement;
106use crate::dom::html::htmliframeelement::HTMLIFrameElement;
107use crate::dom::html::htmlimageelement::HTMLImageElement;
108use crate::dom::html::htmllinkelement::HTMLLinkElement;
109use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
110use crate::dom::html::htmlstyleelement::HTMLStyleElement;
111use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
112use crate::dom::html::htmlvideoelement::HTMLVideoElement;
113use crate::dom::html::input_element::HTMLInputElement;
114use crate::dom::iterators::ShadowIncluding;
115use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
116use crate::dom::node::iterators::{
117 FollowingNodeIterator, PrecedingNodeIterator, SimpleNodeIterator, TreeIterator,
118 UnrootedSimpleNodeIterator, UnrootedTreeIterator,
119};
120use crate::dom::node::nodelist::NodeList;
121use crate::dom::pointerevent::{PointerEvent, PointerId};
122use crate::dom::processinginstruction::ProcessingInstruction;
123use crate::dom::range::WeakRangeVec;
124use crate::dom::raredata::NodeRareData;
125use crate::dom::servoparser::html::HtmlSerialize;
126use crate::dom::servoparser::serialize_html_fragment;
127use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
128use crate::dom::svg::svgsvgelement::SVGSVGElement;
129use crate::dom::text::Text;
130use crate::dom::types::{CDATASection, KeyboardEvent};
131use crate::dom::virtualmethods::{VirtualMethods, vtable_for};
132use crate::dom::window::Window;
133use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode};
134use crate::script_runtime::CanGc;
135use crate::script_thread::ScriptThread;
136
137#[dom_struct]
143pub struct Node {
144 eventtarget: EventTarget,
146
147 parent_node: MutNullableDom<Node>,
149
150 first_child: MutNullableDom<Node>,
152
153 last_child: MutNullableDom<Node>,
155
156 next_sibling: MutNullableDom<Node>,
158
159 prev_sibling: MutNullableDom<Node>,
161
162 owner_doc: MutNullableDom<Document>,
164
165 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
167
168 children_count: Cell<u32>,
170
171 flags: Cell<NodeFlags>,
173
174 inclusive_descendants_version: Cell<u64>,
176
177 #[no_trace]
180 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
181}
182
183impl fmt::Debug for Node {
184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 if let Some(element) = self.downcast::<Element>() {
186 element.fmt(f)
187 } else if let Some(character_data) = self.downcast::<CharacterData>() {
188 write!(f, "[Text({})]", character_data.data())
189 } else {
190 write!(f, "[Node({:?})]", self.type_id())
191 }
192 }
193}
194
195#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
197pub(crate) struct NodeFlags(u16);
198
199bitflags! {
200 impl NodeFlags: u16 {
201 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
205
206 const HAS_DIRTY_DESCENDANTS = 1 << 1;
208
209 const CLICK_IN_PROGRESS = 1 << 2;
212
213 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
218
219 const HAS_SNAPSHOT = 1 << 7;
224
225 const HANDLED_SNAPSHOT = 1 << 8;
227
228 const IS_IN_SHADOW_TREE = 1 << 9;
230
231 const IS_CONNECTED = 1 << 10;
235
236 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
239
240 const IS_IN_UA_WIDGET = 1 << 12;
243
244 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
246 }
247}
248
249#[derive(Clone, Copy, MallocSizeOf)]
253enum SuppressObserver {
254 Suppressed,
255 Unsuppressed,
256}
257
258pub(crate) enum ForceSlottableNodeReconciliation {
259 Force,
260 Skip,
261}
262
263impl Node {
264 fn add_child(&self, cx: &mut JSContext, new_child: &Node, before: Option<&Node>) {
268 assert!(new_child.parent_node.get().is_none());
269 assert!(new_child.prev_sibling.get().is_none());
270 assert!(new_child.next_sibling.get().is_none());
271 match before {
272 Some(before) => {
273 assert!(before.parent_node.get().as_deref() == Some(self));
274 let prev_sibling = before.GetPreviousSibling();
275 match prev_sibling {
276 None => {
277 assert!(self.first_child.get().as_deref() == Some(before));
278 self.first_child.set(Some(new_child));
279 },
280 Some(ref prev_sibling) => {
281 prev_sibling.next_sibling.set(Some(new_child));
282 new_child.prev_sibling.set(Some(prev_sibling));
283 },
284 }
285 before.prev_sibling.set(Some(new_child));
286 new_child.next_sibling.set(Some(before));
287 },
288 None => {
289 let last_child = self.GetLastChild();
290 match last_child {
291 None => self.first_child.set(Some(new_child)),
292 Some(ref last_child) => {
293 assert!(last_child.next_sibling.get().is_none());
294 last_child.next_sibling.set(Some(new_child));
295 new_child.prev_sibling.set(Some(last_child));
296 },
297 }
298
299 self.last_child.set(Some(new_child));
300 },
301 }
302
303 new_child.parent_node.set(Some(self));
304 self.children_count.set(self.children_count.get() + 1);
305
306 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
307 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
308 let parent_is_connected = self.is_connected();
309 let parent_is_in_ua_widget = self.is_in_ua_widget();
310
311 let context = BindContext::new(self, IsShadowTree::No);
312
313 for node in new_child.traverse_preorder(ShadowIncluding::No) {
314 if parent_in_shadow_tree {
315 if let Some(shadow_root) = self.containing_shadow_root() {
316 node.set_containing_shadow_root(Some(&*shadow_root));
317 }
318 debug_assert!(node.containing_shadow_root().is_some());
319 }
320 node.set_flag(
321 NodeFlags::IS_IN_A_DOCUMENT_TREE,
322 parent_is_in_a_document_tree,
323 );
324 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
325 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
326 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
327
328 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
330 vtable_for(&node).bind_to_tree(cx, &context);
331 }
332 }
333
334 pub(crate) fn remove_style_and_layout_data_from_subtree(&self, no_gc: &NoGC) {
338 for node in self.traverse_preorder_non_rooting(no_gc, ShadowIncluding::Yes) {
339 node.clean_up_style_and_layout_data();
340 }
341 }
342
343 fn clean_up_style_and_layout_data(&self) {
344 self.layout_data.borrow_mut().take();
345 if let Some(element) = self.downcast::<Element>() {
346 element.clean_up_style_data();
347 }
348 }
349
350 pub(crate) fn complete_remove_subtree(
353 cx: &mut JSContext,
354 root: &Node,
355 context: &UnbindContext,
356 ) {
357 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
359 .union(NodeFlags::IS_CONNECTED)
360 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
361 .union(NodeFlags::HAS_SNAPSHOT)
362 .union(NodeFlags::HANDLED_SNAPSHOT);
363
364 for node in root.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No) {
365 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
366
367 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
370 for node in shadow_root
371 .upcast::<Node>()
372 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
373 {
374 node.set_flag(RESET_FLAGS, false);
375 }
376 }
377 }
378
379 let is_parent_connected = context.parent.is_connected();
381 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
382
383 let cleanup_node = |cx: &mut JSContext, node: &Node| {
386 node.owner_doc().cancel_animations_for_node(node);
387 node.clean_up_style_and_layout_data();
388
389 vtable_for(node).unbind_from_tree(cx, context);
394
395 if is_parent_connected && let Some(element) = node.as_custom_element() {
397 custom_element_reaction_stack.enqueue_callback_reaction(
398 &element,
399 CallbackReaction::Disconnected,
400 None,
401 );
402 }
403 };
404
405 for node in root.traverse_preorder(ShadowIncluding::No) {
406 cleanup_node(cx, &node);
407
408 if node.containing_shadow_root().is_some() {
411 node.set_containing_shadow_root(None);
414 }
415
416 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
419 for node in shadow_root
420 .upcast::<Node>()
421 .traverse_preorder(ShadowIncluding::Yes)
422 {
423 cleanup_node(cx, &node);
424 }
425 }
426 }
427 }
428
429 pub(crate) fn complete_move_subtree(cx: &mut JSContext, root: &Node) {
430 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
432 .union(NodeFlags::IS_CONNECTED)
433 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
434 .union(NodeFlags::HAS_SNAPSHOT)
435 .union(NodeFlags::HANDLED_SNAPSHOT);
436
437 for node in root.traverse_preorder(ShadowIncluding::No) {
438 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
439 node.clean_up_style_and_layout_data();
440
441 if let Some(element) = node.downcast::<Element>() {
444 element.unregister_current_id_and_name_attribute(cx);
445 }
446
447 if node.containing_shadow_root().is_some() {
450 node.set_containing_shadow_root(None);
453 }
454
455 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
459 for node in shadow_root
460 .upcast::<Node>()
461 .traverse_preorder(ShadowIncluding::Yes)
462 {
463 node.set_flag(RESET_FLAGS, false);
464 node.clean_up_style_and_layout_data();
465 }
466 }
467 }
468 }
469
470 fn remove_child(&self, cx: &mut JSContext, child: &Node, cached_index: Option<u32>) {
474 assert!(child.parent_node.get().as_deref() == Some(self));
475 self.note_dirty_descendants();
476
477 let prev_sibling = child.GetPreviousSibling();
478 match prev_sibling {
479 None => {
480 self.first_child.set(child.next_sibling.get().as_deref());
481 },
482 Some(ref prev_sibling) => {
483 prev_sibling
484 .next_sibling
485 .set(child.next_sibling.get().as_deref());
486 },
487 }
488 let next_sibling = child.GetNextSibling();
489 match next_sibling {
490 None => {
491 self.last_child.set(child.prev_sibling.get().as_deref());
492 },
493 Some(ref next_sibling) => {
494 next_sibling
495 .prev_sibling
496 .set(child.prev_sibling.get().as_deref());
497 },
498 }
499
500 let context = UnbindContext::new(
501 self,
502 prev_sibling.as_deref(),
503 next_sibling.as_deref(),
504 cached_index,
505 );
506
507 child.prev_sibling.set(None);
508 child.next_sibling.set(None);
509 child.parent_node.set(None);
510 self.children_count.set(self.children_count.get() - 1);
511
512 Self::complete_remove_subtree(cx, child, &context);
513 }
514
515 fn move_child(&self, cx: &mut JSContext, child: &Node) {
516 assert!(child.parent_node.get().as_deref() == Some(self));
517 self.note_dirty_descendants();
518
519 child.prev_sibling.set(None);
520 child.next_sibling.set(None);
521 child.parent_node.set(None);
522 self.children_count.set(self.children_count.get() - 1);
523 Self::complete_move_subtree(cx, child)
524 }
525
526 pub(crate) fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
527 UntrustedNodeAddress(self.reflector().get_jsobject().get() as *const c_void)
528 }
529
530 pub(crate) fn to_opaque(&self) -> OpaqueNode {
531 OpaqueNode(self.reflector().get_jsobject().get() as usize)
532 }
533
534 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
535 self.downcast::<Element>().and_then(|element| {
536 if element.is_custom() {
537 assert!(element.get_custom_element_definition().is_some());
538 Some(DomRoot::from_ref(element))
539 } else {
540 None
541 }
542 })
543 }
544
545 pub(crate) fn fire_synthetic_pointer_event_not_trusted(
547 &self,
548 cx: &mut JSContext,
549 event_type: Atom,
550 ) {
551 let window = self.owner_window();
555
556 let pointer_event = PointerEvent::new(
558 &window, event_type,
560 EventBubbles::Bubbles, EventCancelable::Cancelable, Some(&window), 0, Point2D::zero(), Point2D::zero(), Point2D::zero(), Modifiers::empty(), 0, 0, None, None, PointerId::NonPointerDevice as i32, 1, 1, 0.5, 0.0, 0, 0, 0, PI / 2.0, 0.0, DOMString::from(""), false, vec![], vec![], CanGc::from_cx(cx),
587 );
588
589 pointer_event.upcast::<Event>().set_composed(true);
591
592 pointer_event.upcast::<Event>().set_trusted(false);
594
595 pointer_event
598 .upcast::<Event>()
599 .dispatch(cx, self.upcast::<EventTarget>(), false);
600 }
601
602 pub(crate) fn parent_directionality(&self) -> String {
603 let mut current = self.GetParentNode();
604
605 loop {
606 match current {
607 Some(node) => {
608 if let Some(directionality) = node
609 .downcast::<HTMLElement>()
610 .and_then(|html_element| html_element.directionality())
611 {
612 return directionality;
613 } else {
614 current = node.GetParentNode();
615 }
616 },
617 None => return "ltr".to_owned(),
618 }
619 }
620 }
621
622 pub(crate) fn is_being_rendered_or_delegates_rendering(
626 &self,
627 pseudo_element: Option<PseudoElement>,
628 ) -> bool {
629 matches!(
630 self.owner_window()
631 .layout()
632 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
633 NodeRenderingType::Rendered | NodeRenderingType::DelegatesRendering
634 )
635 }
636
637 pub(crate) fn is_being_rendered(&self, pseudo_element: Option<PseudoElement>) -> bool {
639 matches!(
640 self.owner_window()
641 .layout()
642 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
643 NodeRenderingType::Rendered
644 )
645 }
646}
647
648impl Node {
649 fn rare_data(&self) -> Ref<'_, Option<Box<NodeRareData>>> {
650 self.rare_data.borrow()
651 }
652
653 fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
654 let mut rare_data = self.rare_data.borrow_mut();
655 if rare_data.is_none() {
656 *rare_data = Some(Default::default());
657 }
658 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
659 }
660
661 pub(crate) fn is_before(&self, other: &Node) -> bool {
664 let cmp = other.CompareDocumentPosition(self);
665 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
666 return false;
667 }
668
669 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
670 }
671
672 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
675 RefMut::map(self.ensure_rare_data(), |rare_data| {
676 &mut rare_data.mutation_observers
677 })
678 }
679
680 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
681 let rare_data: Ref<'_, _> = self.rare_data.borrow();
682
683 if rare_data.is_none() {
684 return None;
685 }
686 Some(Ref::map(rare_data, |rare_data| {
687 &rare_data.as_ref().unwrap().mutation_observers
688 }))
689 }
690
691 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
693 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
694 self.ensure_rare_data().mutation_observers.push(observer);
695 }
696
697 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
699 self.ensure_rare_data()
700 .mutation_observers
701 .retain(|reg_obs| &*reg_obs.observer != observer)
702 }
703
704 pub(crate) fn dump(&self) {
706 self.dump_indent(0);
707 }
708
709 pub(crate) fn dump_indent(&self, indent: u32) {
711 let mut s = String::new();
712 for _ in 0..indent {
713 s.push_str(" ");
714 }
715
716 s.push_str(&self.debug_str());
717 debug!("{:?}", s);
718
719 for kid in self.children() {
721 kid.dump_indent(indent + 1)
722 }
723 }
724
725 pub(crate) fn debug_str(&self) -> String {
727 format!("{:?}", self.type_id())
728 }
729
730 pub(crate) fn is_in_a_document_tree(&self) -> bool {
732 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
733 }
734
735 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
737 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
738 }
739
740 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
741 self.flags
742 .get()
743 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
744 }
745
746 pub(crate) fn set_weird_parser_insertion_mode(&self) {
747 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
748 }
749
750 pub(crate) fn is_connected(&self) -> bool {
752 self.flags.get().contains(NodeFlags::IS_CONNECTED)
753 }
754
755 pub(crate) fn set_in_ua_widget(&self, in_ua_widget: bool) {
756 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, in_ua_widget)
757 }
758
759 pub(crate) fn is_in_ua_widget(&self) -> bool {
760 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
761 }
762
763 pub(crate) fn type_id(&self) -> NodeTypeId {
765 match *self.eventtarget.type_id() {
766 EventTargetTypeId::Node(type_id) => type_id,
767 _ => unreachable!(),
768 }
769 }
770
771 pub(crate) fn len(&self) -> u32 {
773 match self.type_id() {
774 NodeTypeId::DocumentType => 0,
775 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
776 _ => self.children_count(),
777 }
778 }
779
780 pub(crate) fn is_empty(&self) -> bool {
781 self.len() == 0
783 }
784
785 pub(crate) fn index(&self) -> u32 {
787 self.preceding_siblings().count() as u32
788 }
789
790 pub(crate) fn has_parent(&self) -> bool {
792 self.parent_node.get().is_some()
793 }
794
795 pub(crate) fn children_count(&self) -> u32 {
796 self.children_count.get()
797 }
798
799 pub(crate) fn ranges(&self) -> RefMut<'_, WeakRangeVec> {
800 RefMut::map(self.ensure_rare_data(), |rare_data| &mut rare_data.ranges)
801 }
802
803 pub(crate) fn ranges_is_empty(&self) -> bool {
804 self.rare_data()
805 .as_ref()
806 .is_none_or(|data| data.ranges.is_empty())
807 }
808
809 #[inline]
810 pub(crate) fn is_doctype(&self) -> bool {
811 self.type_id() == NodeTypeId::DocumentType
812 }
813
814 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
815 self.flags.get().contains(flag)
816 }
817
818 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
819 let mut flags = self.flags.get();
820
821 if value {
822 flags.insert(flag);
823 } else {
824 flags.remove(flag);
825 }
826
827 self.flags.set(flags);
828 }
829
830 pub(crate) fn note_dirty_descendants(&self) {
832 self.owner_doc().note_node_with_dirty_descendants(self);
833 }
834
835 pub(crate) fn has_dirty_descendants(&self) -> bool {
836 self.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)
837 }
838
839 pub(crate) fn rev_version(&self) {
840 let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
845 let version = cmp::max(
846 self.inclusive_descendants_version(),
847 doc.inclusive_descendants_version(),
848 ) + 1;
849
850 let mut node = &MutNullableDom::new(Some(self));
853 while let Some(p) = node.if_is_some(|p| {
854 p.inclusive_descendants_version.set(version);
855 &p.parent_node
856 }) {
857 node = p
858 }
859 doc.inclusive_descendants_version.set(version);
860 }
861
862 pub(crate) fn dirty(&self, damage: NodeDamage) {
863 self.rev_version();
864 if !self.is_connected() {
865 return;
866 }
867
868 match self.type_id() {
869 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..)) => {
870 *self.layout_data.borrow_mut() = None;
873
874 self.parent_node
878 .get()
879 .unwrap()
880 .dirty(NodeDamage::ContentOrHeritage)
881 },
882 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(damage),
883 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
884 .downcast::<ShadowRoot>()
885 .unwrap()
886 .Host()
887 .upcast::<Element>()
888 .restyle(damage),
889 _ => {},
890 };
891 }
892
893 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
895 self.inclusive_descendants_version.get()
896 }
897
898 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
900 TreeIterator::new(self, shadow_including)
901 }
902
903 pub(crate) fn traverse_preorder_non_rooting<'a, 'b>(
905 &'a self,
906 no_gc: &'b NoGC,
907 shadow_including: ShadowIncluding,
908 ) -> UnrootedTreeIterator<'a, 'b>
909 where
910 'b: 'a,
911 {
912 UnrootedTreeIterator::new(self, shadow_including, no_gc)
913 }
914
915 pub(crate) fn inclusively_following_siblings(
916 &self,
917 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
918 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), |n| n.GetNextSibling())
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::new(
926 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
927 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
928 no_gc,
929 )
930 }
931
932 pub(crate) fn inclusively_preceding_siblings(
933 &self,
934 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
935 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), |n| n.GetPreviousSibling())
936 }
937
938 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
939 &self,
940 no_gc: &'b NoGC,
941 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
942 UnrootedSimpleNodeIterator::new(
943 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
944 |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
945 no_gc,
946 )
947 }
948
949 pub(crate) fn common_ancestor(
950 &self,
951 other: &Node,
952 shadow_including: ShadowIncluding,
953 ) -> Option<DomRoot<Node>> {
954 self.inclusive_ancestors(shadow_including).find(|ancestor| {
955 other
956 .inclusive_ancestors(shadow_including)
957 .any(|node| node == *ancestor)
958 })
959 }
960
961 pub(crate) fn common_ancestor_in_flat_tree(&self, other: &Node) -> Option<DomRoot<Node>> {
962 self.inclusive_ancestors_in_flat_tree().find(|ancestor| {
963 other
964 .inclusive_ancestors_in_flat_tree()
965 .any(|node| node == *ancestor)
966 })
967 }
968
969 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
971 self == child || self.is_ancestor_of(child)
973 }
974
975 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
977 let mut current = &possible_descendant.parent_node;
979 let mut done = false;
980
981 while let Some(node) = current.if_is_some(|node| {
982 done = node == self;
983 &node.parent_node
984 }) {
985 if done {
986 break;
987 }
988 current = node
989 }
990 done
991 }
992
993 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
995 self.is_inclusive_ancestor_of(child) ||
998 child
999 .GetRootNode(&GetRootNodeOptions::empty())
1000 .downcast::<DocumentFragment>()
1001 .and_then(|fragment| fragment.host())
1002 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1003 }
1004
1005 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1007 node.inclusive_ancestors(ShadowIncluding::Yes)
1008 .any(|ancestor| &*ancestor == self)
1009 }
1010
1011 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1012 SimpleNodeIterator::new(self.GetNextSibling(), |n| n.GetNextSibling())
1013 }
1014
1015 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1016 SimpleNodeIterator::new(self.GetPreviousSibling(), |n| n.GetPreviousSibling())
1017 }
1018
1019 pub(crate) fn following_nodes(
1020 &self,
1021 root: &Node,
1022 shadow_including: ShadowIncluding,
1023 ) -> FollowingNodeIterator {
1024 FollowingNodeIterator::new(
1025 Some(DomRoot::from_ref(self)),
1026 DomRoot::from_ref(root),
1027 shadow_including,
1028 )
1029 }
1030
1031 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1032 PrecedingNodeIterator::new(Some(DomRoot::from_ref(self)), DomRoot::from_ref(root))
1033 }
1034
1035 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1038 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetLastChild())
1039 }
1040
1041 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1042 child
1043 .parent_node
1044 .get()
1045 .is_some_and(|parent| &*parent == self)
1046 }
1047
1048 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1049 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1050 }
1051
1052 pub(crate) fn containing_block_node_without_reflow(&self) -> Option<DomRoot<Node>> {
1054 self.owner_window()
1055 .containing_block_node_query_without_reflow(self)
1056 }
1057
1058 pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1059 self.owner_window().padding_query_without_reflow(self)
1060 }
1061
1062 pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1063 self.owner_window()
1064 .box_area_query(self, BoxAreaType::Content, false)
1065 }
1066
1067 pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1068 self.owner_window()
1069 .box_area_query(self, BoxAreaType::Border, false)
1070 }
1071
1072 pub(crate) fn border_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1073 self.owner_window()
1074 .box_area_query_without_reflow(self, BoxAreaType::Border, false)
1075 }
1076
1077 pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1078 self.owner_window()
1079 .box_area_query(self, BoxAreaType::Padding, false)
1080 }
1081
1082 pub(crate) fn padding_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1083 self.owner_window()
1084 .box_area_query_without_reflow(self, BoxAreaType::Padding, false)
1085 }
1086
1087 pub(crate) fn border_boxes(&self) -> CSSPixelRectVec {
1088 self.owner_window()
1089 .box_areas_query(self, BoxAreaType::Border)
1090 }
1091
1092 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1093 self.owner_window().client_rect_query(self)
1094 }
1095
1096 pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1099 let document = self.owner_doc();
1101
1102 if !document.is_active() {
1104 return Rect::zero();
1105 }
1106
1107 let window = document.window();
1110 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1111
1112 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1113 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1114 let is_body_element = self
1115 .downcast::<HTMLElement>()
1116 .is_some_and(|e| e.is_body_element());
1117
1118 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1124 let viewport_scrolling_area = window.scrolling_area_query(None);
1125 return Rect::new(
1126 viewport_scrolling_area.origin,
1127 viewport_scrolling_area.size.max(viewport),
1128 );
1129 }
1130
1131 window.scrolling_area_query(Some(self))
1135 }
1136
1137 pub(crate) fn effective_overflow(&self) -> Option<AxesOverflow> {
1138 self.owner_window().query_effective_overflow(self)
1139 }
1140
1141 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1142 self.owner_window()
1143 .query_effective_overflow_without_reflow(self)
1144 }
1145
1146 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1148 let parent = &self.parent_node;
1150
1151 let parent = match parent.get() {
1153 None => return Ok(()),
1154 Some(parent) => parent,
1155 };
1156
1157 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1159
1160 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1162
1163 let viable_previous_sibling = match viable_previous_sibling {
1165 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1166 None => parent.first_child.get(),
1167 };
1168
1169 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1171
1172 Ok(())
1173 }
1174
1175 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1177 let parent = &self.parent_node;
1179
1180 let parent = match parent.get() {
1182 None => return Ok(()),
1183 Some(parent) => parent,
1184 };
1185
1186 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1188
1189 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1191
1192 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1194
1195 Ok(())
1196 }
1197
1198 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1200 let Some(parent) = self.GetParentNode() else {
1202 return Ok(());
1204 };
1205
1206 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1208
1209 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1211
1212 if self.parent_node == Some(&*parent) {
1213 parent.ReplaceChild(cx, &node, self)?;
1215 } else {
1216 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1218 }
1219 Ok(())
1220 }
1221
1222 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1224 let doc = self.owner_doc();
1226 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1227 let first_child = self.first_child.get();
1229 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1230 }
1231
1232 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1234 let doc = self.owner_doc();
1236 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1237 self.AppendChild(cx, &node).map(|_| ())
1239 }
1240
1241 pub(crate) fn replace_children(
1243 &self,
1244 cx: &mut JSContext,
1245 nodes: Vec<NodeOrString>,
1246 ) -> ErrorResult {
1247 let doc = self.owner_doc();
1250 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1251
1252 Node::ensure_pre_insertion_validity(cx.no_gc(), &node, self, None)?;
1254
1255 Node::replace_all(cx, Some(&node), self);
1257 Ok(())
1258 }
1259
1260 pub(crate) fn move_before(
1262 &self,
1263 cx: &mut JSContext,
1264 node: &Node,
1265 child: Option<&Node>,
1266 ) -> ErrorResult {
1267 let reference_child_root;
1270 let reference_child = match child {
1271 Some(child) if child == node => {
1272 reference_child_root = node.GetNextSibling();
1273 reference_child_root.as_deref()
1274 },
1275 _ => child,
1276 };
1277
1278 Node::move_fn(cx, node, self, reference_child)
1280 }
1281
1282 fn move_fn(
1284 cx: &mut JSContext,
1285 node: &Node,
1286 new_parent: &Node,
1287 child: Option<&Node>,
1288 ) -> ErrorResult {
1289 let mut options = GetRootNodeOptions::empty();
1294 options.composed = true;
1295 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1296 return Err(Error::HierarchyRequest(None));
1297 }
1298
1299 if node.is_inclusive_ancestor_of(new_parent) {
1302 return Err(Error::HierarchyRequest(None));
1303 }
1304
1305 if let Some(child) = child &&
1308 !new_parent.is_parent_of(child)
1309 {
1310 return Err(Error::NotFound(None));
1311 }
1312
1313 match node.type_id() {
1318 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1319 if new_parent.is::<Document>() {
1320 return Err(Error::HierarchyRequest(None));
1321 }
1322 },
1323 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1324 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1325 NodeTypeId::Element(_) => (),
1326 NodeTypeId::DocumentFragment(_) |
1327 NodeTypeId::DocumentType |
1328 NodeTypeId::Document(_) |
1329 NodeTypeId::Attr => {
1330 return Err(Error::HierarchyRequest(None));
1331 },
1332 }
1333
1334 if new_parent.is::<Document>() && node.is::<Element>() {
1338 if new_parent.child_elements().next().is_some() {
1340 return Err(Error::HierarchyRequest(None));
1341 }
1342
1343 if child.is_some_and(|child| {
1346 child
1347 .inclusively_following_siblings_unrooted(cx.no_gc())
1348 .any(|child| child.is_doctype())
1349 }) {
1350 return Err(Error::HierarchyRequest(None));
1351 }
1352 }
1353
1354 let old_parent = node
1357 .parent_node
1358 .get()
1359 .expect("old_parent should always be initialized");
1360
1361 let cached_index = Node::live_range_pre_remove_steps(node, &old_parent);
1363
1364 let old_previous_sibling = node.prev_sibling.get();
1369
1370 let old_next_sibling = node.next_sibling.get();
1372
1373 let prev_sibling = node.GetPreviousSibling();
1374 match prev_sibling {
1375 None => {
1376 old_parent
1377 .first_child
1378 .set(node.next_sibling.get().as_deref());
1379 },
1380 Some(ref prev_sibling) => {
1381 prev_sibling
1382 .next_sibling
1383 .set(node.next_sibling.get().as_deref());
1384 },
1385 }
1386 let next_sibling = node.GetNextSibling();
1387 match next_sibling {
1388 None => {
1389 old_parent
1390 .last_child
1391 .set(node.prev_sibling.get().as_deref());
1392 },
1393 Some(ref next_sibling) => {
1394 next_sibling
1395 .prev_sibling
1396 .set(node.prev_sibling.get().as_deref());
1397 },
1398 }
1399
1400 let mut context = MoveContext::new(
1401 Some(&old_parent),
1402 prev_sibling.as_deref(),
1403 next_sibling.as_deref(),
1404 cached_index,
1405 );
1406
1407 old_parent.move_child(cx, node);
1409
1410 if let Some(slot) = node.assigned_slot() {
1412 slot.assign_slottables(cx.no_gc());
1413 }
1414
1415 if old_parent.is_in_a_shadow_tree() &&
1418 let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() &&
1419 !slot_element.has_assigned_nodes()
1420 {
1421 slot_element.signal_a_slot_change();
1422 }
1423
1424 let has_slot_descendant = node
1426 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
1427 .any(|element| element.is::<HTMLSlotElement>());
1428 if has_slot_descendant {
1429 old_parent
1431 .GetRootNode(&GetRootNodeOptions::empty())
1432 .assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Skip);
1433
1434 node.assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Skip);
1436 }
1437
1438 if let Some(child) = child {
1440 new_parent
1445 .ranges()
1446 .increase_above(new_parent, child.index(), 1)
1447 }
1448
1449 let new_previous_sibling = child.map_or_else(
1452 || new_parent.last_child.get(),
1453 |child| child.prev_sibling.get(),
1454 );
1455
1456 new_parent.add_child(cx, node, child);
1459
1460 if let Some(shadow_root) = new_parent
1463 .downcast::<Element>()
1464 .and_then(Element::shadow_root) &&
1465 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1466 (node.is::<Element>() || node.is::<Text>())
1467 {
1468 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1469 slottable.assign_a_slot(cx.no_gc());
1470 }
1471
1472 if new_parent.is_in_a_shadow_tree() &&
1475 let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() &&
1476 !slot_element.has_assigned_nodes()
1477 {
1478 slot_element.signal_a_slot_change();
1479 }
1480
1481 node.GetRootNode(&GetRootNodeOptions::empty())
1483 .assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Skip);
1484
1485 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1488 if descendant.deref() == node {
1492 vtable_for(&descendant).moving_steps(cx, &context);
1493 } else {
1494 context.old_parent = None;
1495 vtable_for(&descendant).moving_steps(cx, &context);
1496 }
1497
1498 if let Some(descendant) = descendant.downcast::<Element>() &&
1500 descendant.is_custom() &&
1501 new_parent.is_connected()
1502 {
1503 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
1506 custom_element_reaction_stack.enqueue_callback_reaction(
1507 descendant,
1508 CallbackReaction::ConnectedMove,
1509 None,
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 no_gc: &NoGC,
1544 selectors: DOMString,
1545 ) -> Fallible<Option<DomRoot<Element>>> {
1546 let document_url = self.owner_document().url().get_arc();
1549
1550 self.owner_document()
1553 .id_map()
1554 .resolve_all(no_gc, self.owner_doc().upcast());
1555
1556 let traced_node = Dom::from_ref(self);
1558
1559 let first_matching_element = with_layout_state(|| {
1560 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1561 ServoDangerousStyleNode::from(layout_node)
1562 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1563 })?;
1564
1565 Ok(first_matching_element.map(ServoDangerousStyleElement::rooted))
1566 }
1567
1568 #[allow(unsafe_code)]
1570 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1571 pub(crate) fn query_selector_all(
1572 &self,
1573 no_gc: &NoGC,
1574 selectors: DOMString,
1575 ) -> Fallible<DomRoot<NodeList>> {
1576 let document_url = self.owner_document().url().get_arc();
1579
1580 self.owner_document()
1583 .id_map()
1584 .resolve_all(no_gc, self.owner_doc().upcast());
1585
1586 let traced_node = Dom::from_ref(self);
1588 let matching_elements = with_layout_state(|| {
1589 let layout_node: LayoutDom<'_, _> = unsafe { traced_node.to_layout() };
1590 ServoDangerousStyleNode::from(layout_node)
1591 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1592 })?;
1593 let iter = matching_elements
1594 .into_iter()
1595 .map(ServoDangerousStyleElement::rooted)
1596 .map(DomRoot::upcast::<Node>);
1597
1598 Ok(NodeList::new_simple_list(
1601 &self.owner_window(),
1602 iter,
1603 CanGc::deprecated_note(),
1604 ))
1605 }
1606
1607 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1608 SimpleNodeIterator::new(self.GetParentNode(), |n| n.GetParentNode())
1609 }
1610
1611 pub(crate) fn inclusive_ancestors(
1613 &self,
1614 shadow_including: ShadowIncluding,
1615 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1616 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |n| {
1617 if shadow_including == ShadowIncluding::Yes &&
1618 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1619 {
1620 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1621 }
1622 n.GetParentNode()
1623 })
1624 }
1625
1626 pub(crate) fn inclusive_ancestors_unrooted<'a>(
1627 &self,
1628 no_gc: &'a NoGC,
1629 shadow_including: ShadowIncluding,
1630 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1631 UnrootedSimpleNodeIterator::new(
1632 Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
1633 move |n, no_gc| {
1634 if shadow_including == ShadowIncluding::Yes &&
1635 let Some(shadow_root) = n.downcast::<ShadowRoot>()
1636 {
1637 return Some(UnrootedDom::from_dom(
1638 Dom::from_ref(shadow_root.Host().upcast::<Node>()),
1639 no_gc,
1640 ));
1641 }
1642 n.get_parent_node_unrooted(no_gc)
1643 },
1644 no_gc,
1645 )
1646 }
1647
1648 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1649 self.owner_doc.get().unwrap()
1650 }
1651
1652 pub(crate) fn set_owner_doc(&self, document: &Document) {
1653 self.owner_doc.set(Some(document));
1654 }
1655
1656 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1657 self.rare_data()
1658 .as_ref()?
1659 .containing_shadow_root
1660 .as_ref()
1661 .map(|sr| DomRoot::from_ref(&**sr))
1662 }
1663
1664 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1665 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1666 }
1667
1668 pub(crate) fn is_in_html_doc(&self) -> bool {
1669 self.owner_doc().is_html_document()
1670 }
1671
1672 pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1673 self.is_connected() && self.owner_doc().browsing_context().is_some()
1674 }
1675
1676 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1677 SimpleNodeIterator::new(self.GetFirstChild(), |n| n.GetNextSibling())
1678 }
1679
1680 pub(crate) fn children_unrooted<'a>(
1681 &self,
1682 no_gc: &'a NoGC,
1683 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1684 UnrootedSimpleNodeIterator::new(
1685 self.get_first_child_unrooted(no_gc),
1686 |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1687 no_gc,
1688 )
1689 }
1690
1691 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1692 SimpleNodeIterator::new(self.GetLastChild(), |n| n.GetPreviousSibling())
1693 }
1694
1695 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1697 self.children()
1698 .filter_map(DomRoot::downcast as fn(_) -> _)
1699 .peekable()
1700 }
1701
1702 pub(crate) fn child_elements_unrooted<'a>(
1703 &self,
1704 no_gc: &'a NoGC,
1705 ) -> impl Iterator<Item = UnrootedDom<'a, Element>> + use<'a> {
1706 self.children_unrooted(no_gc)
1707 .filter_map(UnrootedDom::downcast)
1708 .peekable()
1709 }
1710
1711 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1712 if let Some(ref parent) = self.GetParentNode() {
1713 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1714 }
1715 }
1716
1717 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1719 Ref::filter_map(self.rare_data(), |rare_data| {
1720 rare_data
1721 .as_ref()
1722 .and_then(|rare_data| rare_data.unique_id.as_ref())
1723 })
1724 .ok()
1725 .map(|unique_id| unique_id.borrow().simple().to_string())
1726 }
1727
1728 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1729 let mut rare_data = self.ensure_rare_data();
1730
1731 if rare_data.unique_id.is_none() {
1732 let node_id = UniqueId::new();
1733 ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string());
1734 rare_data.unique_id = Some(node_id);
1735 }
1736 rare_data
1737 .unique_id
1738 .as_ref()
1739 .unwrap()
1740 .borrow()
1741 .simple()
1742 .to_string()
1743 }
1744
1745 pub(crate) fn summarize(&self, cx: &mut JSContext) -> NodeInfo {
1746 let USVString(base_uri) = self.BaseURI();
1747 let node_type = self.NodeType();
1748 let pipeline = self.owner_window().pipeline_id();
1749
1750 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1751 let shadow_root_mode = maybe_shadow_root
1752 .map(ShadowRoot::Mode)
1753 .map(ShadowRootMode::convert);
1754 let host = maybe_shadow_root
1755 .map(ShadowRoot::Host)
1756 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1757 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1758 let Some(root) = potential_host.shadow_root() else {
1759 return false;
1760 };
1761 !root.is_user_agent_widget() || pref!(inspector_show_servo_internal_shadow_roots)
1762 });
1763
1764 let num_children = if is_shadow_host {
1765 self.ChildNodes(cx).Length() as usize + 1
1767 } else {
1768 self.ChildNodes(cx).Length() as usize
1769 };
1770
1771 let window = self.owner_window();
1772 let element = self.downcast::<Element>();
1773 let display = element
1774 .map(|elem| window.GetComputedStyle(cx, elem, None))
1775 .map(|style| style.Display().into());
1776
1777 let is_displayed =
1783 element.is_none_or(|element| !element.is_display_none()) || self.is::<DocumentType>();
1784 let attrs = element.map(Element::summarize).unwrap_or_default();
1785
1786 NodeInfo {
1787 unique_id: self.unique_id(pipeline),
1788 host,
1789 base_uri,
1790 parent: self
1791 .GetParentNode()
1792 .map_or("".to_owned(), |node| node.unique_id(pipeline)),
1793 node_type,
1794 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1795 node_name: String::from(self.NodeName()),
1796 node_value: self.GetNodeValue().map(|v| v.into()),
1797 num_children,
1798 attrs,
1799 is_shadow_host,
1800 shadow_root_mode,
1801 display,
1802 is_displayed,
1803 doctype_name: self
1804 .downcast::<DocumentType>()
1805 .map(DocumentType::name)
1806 .cloned()
1807 .map(String::from),
1808 doctype_public_identifier: self
1809 .downcast::<DocumentType>()
1810 .map(DocumentType::public_id)
1811 .cloned()
1812 .map(String::from),
1813 doctype_system_identifier: self
1814 .downcast::<DocumentType>()
1815 .map(DocumentType::system_id)
1816 .cloned()
1817 .map(String::from),
1818 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1819 }
1820 }
1821
1822 pub(crate) fn insert_cell_or_row<F, G, I>(
1824 &self,
1825 cx: &mut JSContext,
1826 index: i32,
1827 get_items: F,
1828 new_child: G,
1829 ) -> Fallible<DomRoot<HTMLElement>>
1830 where
1831 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1832 G: Fn(&mut JSContext) -> DomRoot<I>,
1833 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1834 {
1835 if index < -1 {
1836 return Err(Error::IndexSize(None));
1837 }
1838
1839 let tr = new_child(cx);
1840
1841 {
1842 let tr_node = tr.upcast::<Node>();
1843 if index == -1 {
1844 self.InsertBefore(cx, tr_node, None)?;
1845 } else {
1846 let items = get_items(cx);
1847 let node = match items
1848 .elements_iter()
1849 .map(DomRoot::upcast::<Node>)
1850 .map(Some)
1851 .chain(iter::once(None))
1852 .nth(index as usize)
1853 {
1854 None => return Err(Error::IndexSize(None)),
1855 Some(node) => node,
1856 };
1857 self.InsertBefore(cx, tr_node, node.as_deref())?;
1858 }
1859 }
1860
1861 Ok(DomRoot::upcast::<HTMLElement>(tr))
1862 }
1863
1864 pub(crate) fn delete_cell_or_row<F, G>(
1866 &self,
1867 cx: &mut JSContext,
1868 index: i32,
1869 get_items: F,
1870 is_delete_type: G,
1871 ) -> ErrorResult
1872 where
1873 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1874 G: Fn(&Element) -> bool,
1875 {
1876 let element = match index {
1877 index if index < -1 => return Err(Error::IndexSize(None)),
1878 -1 => {
1879 let last_child = self.upcast::<Node>().GetLastChild();
1880 match last_child.and_then(|node| {
1881 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
1882 .filter_map(UnrootedDom::downcast::<Element>)
1883 .find(|elem| is_delete_type(elem))
1884 .map(|elem| elem.as_rooted())
1885 }) {
1886 Some(element) => element,
1887 None => return Ok(()),
1888 }
1889 },
1890 index => match get_items(cx).Item(index as u32) {
1891 Some(element) => element,
1892 None => return Err(Error::IndexSize(None)),
1893 },
1894 };
1895
1896 element.upcast::<Node>().remove_self(cx);
1897 Ok(())
1898 }
1899
1900 pub(crate) fn get_stylesheet(&self) -> Option<ServoArc<Stylesheet>> {
1901 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1902 node.get_stylesheet()
1903 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1904 node.get_stylesheet()
1905 } else {
1906 None
1907 }
1908 }
1909
1910 pub(crate) fn get_cssom_stylesheet(&self) -> Option<DomRoot<CSSStyleSheet>> {
1911 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1912 node.get_cssom_stylesheet()
1913 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1914 node.get_cssom_stylesheet(CanGc::deprecated_note())
1915 } else {
1916 None
1917 }
1918 }
1919
1920 pub(crate) fn get_lang(&self) -> Option<String> {
1922 self.inclusive_ancestors(ShadowIncluding::Yes)
1923 .find_map(|node| {
1924 node.downcast::<Element>().and_then(|el| {
1925 el.get_attribute_string_value_with_namespace(&ns!(xml), &local_name!("lang"))
1926 .or_else(|| el.get_attribute_string_value(&local_name!("lang")))
1927 })
1928 })
1931 }
1932
1933 pub(crate) fn assign_slottables_for_a_tree(
1935 &self,
1936 no_gc: &NoGC,
1937 force: ForceSlottableNodeReconciliation,
1938 ) {
1939 let is_shadow_root_with_slots = self
1946 .downcast::<ShadowRoot>()
1947 .is_some_and(|shadow_root| shadow_root.has_slot_descendants());
1948 if !is_shadow_root_with_slots &&
1949 !self.is::<HTMLSlotElement>() &&
1950 matches!(force, ForceSlottableNodeReconciliation::Skip)
1951 {
1952 return;
1953 }
1954
1955 for node in self.traverse_preorder_non_rooting(no_gc, ShadowIncluding::No) {
1958 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
1959 slot.assign_slottables(no_gc);
1960 }
1961 }
1962 }
1963
1964 pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> {
1965 let assigned_slot = self
1966 .rare_data
1967 .borrow()
1968 .as_ref()?
1969 .slottable_data
1970 .assigned_slot
1971 .as_ref()?
1972 .as_rooted();
1973 Some(assigned_slot)
1974 }
1975
1976 pub(crate) fn set_assigned_slot(&self, assigned_slot: Option<&HTMLSlotElement>) {
1977 self.ensure_rare_data().slottable_data.assigned_slot = assigned_slot.map(Dom::from_ref);
1978 }
1979
1980 pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> {
1981 let manually_assigned_slot = self
1982 .rare_data
1983 .borrow()
1984 .as_ref()?
1985 .slottable_data
1986 .manual_slot_assignment
1987 .as_ref()?
1988 .as_rooted();
1989 Some(manually_assigned_slot)
1990 }
1991
1992 pub(crate) fn set_manual_slot_assignment(
1993 &self,
1994 manually_assigned_slot: Option<&HTMLSlotElement>,
1995 ) {
1996 self.ensure_rare_data()
1997 .slottable_data
1998 .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref);
1999 }
2000
2001 pub(crate) fn parent_in_flat_tree(&self) -> Option<DomRoot<Node>> {
2007 if let Some(assigned_slot) = self.assigned_slot() {
2008 return Some(DomRoot::upcast(assigned_slot));
2009 }
2010
2011 let parent_or_none = self.GetParentNode();
2012 if let Some(parent) = parent_or_none.as_deref() &&
2013 let Some(shadow_root) = parent.downcast::<ShadowRoot>()
2014 {
2015 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
2016 }
2017
2018 parent_or_none
2019 }
2020
2021 pub(crate) fn inclusive_ancestors_in_flat_tree(
2022 &self,
2023 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
2024 SimpleNodeIterator::new(Some(DomRoot::from_ref(self)), move |n| {
2025 n.parent_in_flat_tree()
2026 })
2027 }
2028
2029 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2031 debug_assert!(self.is_in_ua_widget());
2033 debug_assert!(pseudo_element.is_element_backed());
2034 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2035 }
2036
2037 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2038 self.rare_data
2039 .borrow()
2040 .as_ref()
2041 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2042 }
2043
2044 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2046 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2050 if ancestor.is_editing_host() {
2051 return Some(ancestor);
2052 }
2053 if ancestor
2054 .downcast::<HTMLElement>()
2055 .is_some_and(|el| el.ContentEditable().str() == "false")
2056 {
2057 return None;
2058 }
2059 }
2060 None
2061 }
2062
2063 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2064 self.editing_host_of().is_some()
2065 }
2066
2067 pub(crate) fn is_editing_host(&self) -> bool {
2069 self.downcast::<HTMLElement>()
2070 .is_some_and(HTMLElement::is_editing_host)
2071 }
2072
2073 pub(crate) fn is_editable(&self) -> bool {
2075 if self.is_editing_host() {
2077 return false;
2078 }
2079 let html_element = self.downcast::<HTMLElement>();
2081 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2082 return false;
2083 }
2084 let Some(parent) = self.GetParentNode() else {
2086 return false;
2087 };
2088 if !parent.is_editable_or_editing_host() {
2089 return false;
2090 }
2091 html_element.is_some() || (!self.is::<Element>() && parent.is::<HTMLElement>())
2093 }
2094}
2095
2096fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2098where
2099 I: Iterator<Item = DomRoot<Node>>,
2100{
2101 nodes.find(|node| {
2102 not_in.iter().all(|n| match *n {
2103 NodeOrString::Node(ref n) => n != node,
2104 _ => true,
2105 })
2106 })
2107}
2108
2109#[expect(unsafe_code)]
2112pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2113 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2114 DomRoot::from_ref(node)
2115}
2116
2117impl<'dom> LayoutDom<'dom, Node> {
2118 #[inline]
2119 #[expect(unsafe_code)]
2120 pub(crate) fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
2121 unsafe { self.unsafe_get().parent_node.get_inner_as_layout() }
2122 }
2123
2124 #[inline]
2125 pub(crate) fn type_id_for_layout(self) -> NodeTypeId {
2126 self.unsafe_get().type_id()
2127 }
2128
2129 #[inline]
2130 pub(crate) fn is_element_for_layout(&self) -> bool {
2131 (*self).is::<Element>()
2132 }
2133
2134 pub(crate) fn is_text_node_for_layout(&self) -> bool {
2135 matches!(
2136 self.type_id_for_layout(),
2137 NodeTypeId::CharacterData(CharacterDataTypeId::Text(..))
2138 )
2139 }
2140
2141 #[inline]
2142 pub(crate) fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
2143 let parent = self.parent_node_ref();
2144 if let Some(parent) = parent &&
2145 let Some(shadow_root) = parent.downcast::<ShadowRoot>()
2146 {
2147 return Some(shadow_root.get_host_for_layout().upcast());
2148 }
2149 parent
2150 }
2151
2152 #[inline]
2153 pub(crate) fn traversal_parent(self) -> Option<LayoutDom<'dom, Element>> {
2154 if let Some(assigned_slot) = self.assigned_slot_for_layout() {
2155 return Some(assigned_slot.upcast());
2156 }
2157 let parent = self.parent_node_ref()?;
2158 if let Some(shadow) = parent.downcast::<ShadowRoot>() {
2159 return Some(shadow.get_host_for_layout());
2160 };
2161 parent.downcast()
2162 }
2163
2164 #[inline]
2165 #[expect(unsafe_code)]
2166 pub(crate) fn first_child_ref(self) -> Option<LayoutDom<'dom, Node>> {
2167 unsafe { self.unsafe_get().first_child.get_inner_as_layout() }
2168 }
2169
2170 #[inline]
2171 #[expect(unsafe_code)]
2172 pub(crate) fn last_child_ref(self) -> Option<LayoutDom<'dom, Node>> {
2173 unsafe { self.unsafe_get().last_child.get_inner_as_layout() }
2174 }
2175
2176 #[inline]
2177 #[expect(unsafe_code)]
2178 pub(crate) fn prev_sibling_ref(self) -> Option<LayoutDom<'dom, Node>> {
2179 unsafe { self.unsafe_get().prev_sibling.get_inner_as_layout() }
2180 }
2181
2182 #[inline]
2183 #[expect(unsafe_code)]
2184 pub(crate) fn next_sibling_ref(self) -> Option<LayoutDom<'dom, Node>> {
2185 unsafe { self.unsafe_get().next_sibling.get_inner_as_layout() }
2186 }
2187
2188 #[inline]
2189 #[expect(unsafe_code)]
2190 pub(crate) fn owner_doc_for_layout(self) -> LayoutDom<'dom, Document> {
2191 unsafe { self.unsafe_get().owner_doc.get_inner_as_layout().unwrap() }
2192 }
2193
2194 #[inline]
2195 #[expect(unsafe_code)]
2196 pub(crate) fn containing_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
2197 unsafe {
2198 self.unsafe_get()
2199 .rare_data
2200 .borrow_for_layout()
2201 .as_ref()?
2202 .containing_shadow_root
2203 .as_ref()
2204 .map(|sr| sr.to_layout())
2205 }
2206 }
2207
2208 #[inline]
2209 #[expect(unsafe_code)]
2210 pub(crate) fn assigned_slot_for_layout(self) -> Option<LayoutDom<'dom, HTMLSlotElement>> {
2211 unsafe {
2212 self.unsafe_get()
2213 .rare_data
2214 .borrow_for_layout()
2215 .as_ref()?
2216 .slottable_data
2217 .assigned_slot
2218 .as_ref()
2219 .map(|assigned_slot| assigned_slot.to_layout())
2220 }
2221 }
2222
2223 #[inline]
2228 #[expect(unsafe_code)]
2229 pub(crate) unsafe fn get_flag(self, flag: NodeFlags) -> bool {
2230 (self.unsafe_get()).flags.get().contains(flag)
2231 }
2232
2233 #[inline]
2234 #[expect(unsafe_code)]
2235 pub(crate) unsafe fn set_flag(self, flag: NodeFlags, value: bool) {
2236 let this = self.unsafe_get();
2237 let mut flags = (this).flags.get();
2238
2239 if value {
2240 flags.insert(flag);
2241 } else {
2242 flags.remove(flag);
2243 }
2244
2245 (this).flags.set(flags);
2246 }
2247
2248 #[inline]
2249 #[expect(unsafe_code)]
2250 pub(crate) fn layout_data(self) -> Option<&'dom GenericLayoutData> {
2251 unsafe { self.unsafe_get().layout_data.borrow_for_layout().as_deref() }
2252 }
2253
2254 #[inline]
2262 #[expect(unsafe_code)]
2263 pub(crate) unsafe fn initialize_layout_data(self, new_data: Box<GenericLayoutData>) {
2264 let data = unsafe { self.unsafe_get().layout_data.borrow_mut_for_layout() };
2265 debug_assert!(data.is_none());
2266 *data = Some(new_data);
2267 }
2268
2269 #[inline]
2277 #[expect(unsafe_code)]
2278 pub(crate) unsafe fn clear_layout_data(self) {
2279 unsafe {
2280 self.unsafe_get().layout_data.borrow_mut_for_layout().take();
2281 }
2282 }
2283
2284 pub(crate) fn is_single_line_text_inner_editor(&self) -> bool {
2287 matches!(
2288 self.implemented_pseudo_element(),
2289 Some(PseudoElement::ServoTextControlInnerEditor)
2290 )
2291 }
2292
2293 pub(crate) fn is_text_container_of_single_line_input(&self) -> bool {
2296 let is_single_line_text_inner_placeholder = matches!(
2297 self.implemented_pseudo_element(),
2298 Some(PseudoElement::Placeholder)
2299 );
2300 debug_assert!(
2302 !is_single_line_text_inner_placeholder ||
2303 self.containing_shadow_root_for_layout()
2304 .map(|root| root.get_host_for_layout())
2305 .map(|host| host.downcast::<HTMLInputElement>())
2306 .is_some()
2307 );
2308
2309 self.is_single_line_text_inner_editor() || is_single_line_text_inner_placeholder
2310 }
2311
2312 pub(crate) fn text_content(self) -> Cow<'dom, str> {
2313 self.downcast::<Text>()
2314 .expect("Called LayoutDom::text_content on non-Text node!")
2315 .upcast()
2316 .data_for_layout()
2317 .into()
2318 }
2319
2320 pub(crate) fn selection(self) -> Option<SharedSelection> {
2327 if let Some(input) = self.downcast::<HTMLInputElement>() {
2328 return input.selection_for_layout();
2329 }
2330 if let Some(textarea) = self.downcast::<HTMLTextAreaElement>() {
2331 return Some(textarea.selection_for_layout());
2332 }
2333
2334 let shadow_root = self
2335 .containing_shadow_root_for_layout()?
2336 .get_host_for_layout();
2337 if let Some(input) = shadow_root.downcast::<HTMLInputElement>() {
2338 return input.selection_for_layout();
2339 }
2340 shadow_root
2341 .downcast::<HTMLTextAreaElement>()
2342 .map(|textarea| textarea.selection_for_layout())
2343 }
2344
2345 pub(crate) fn image_url(self) -> Option<ServoUrl> {
2346 self.downcast::<HTMLImageElement>()
2347 .expect("not an image!")
2348 .image_url()
2349 }
2350
2351 pub(crate) fn image_data(self) -> Option<(Option<Image>, Option<ImageMetadata>)> {
2352 self.downcast::<HTMLImageElement>().map(|e| e.image_data())
2353 }
2354
2355 pub(crate) fn image_density(self) -> Option<f64> {
2356 self.downcast::<HTMLImageElement>()
2357 .expect("not an image!")
2358 .image_density()
2359 }
2360
2361 pub(crate) fn showing_broken_image_icon(self) -> bool {
2362 self.downcast::<HTMLImageElement>()
2363 .map(|image_element| image_element.showing_broken_image_icon())
2364 .unwrap_or_default()
2365 }
2366
2367 pub(crate) fn canvas_data(self) -> Option<HTMLCanvasData> {
2368 self.downcast::<HTMLCanvasElement>()
2369 .map(|canvas| canvas.data())
2370 }
2371
2372 pub(crate) fn media_data(self) -> Option<HTMLMediaData> {
2373 self.downcast::<HTMLVideoElement>()
2374 .map(|media| media.data())
2375 }
2376
2377 pub(crate) fn svg_data(self) -> Option<SVGElementData<'dom>> {
2378 self.downcast::<SVGSVGElement>().map(|svg| svg.data())
2379 }
2380
2381 pub(crate) fn iframe_browsing_context_id(self) -> Option<BrowsingContextId> {
2382 self.downcast::<HTMLIFrameElement>()
2383 .and_then(|iframe_element| iframe_element.browsing_context_id())
2384 }
2385
2386 pub(crate) fn iframe_pipeline_id(self) -> Option<PipelineId> {
2387 self.downcast::<HTMLIFrameElement>()
2388 .and_then(|iframe_element| iframe_element.pipeline_id())
2389 }
2390
2391 #[expect(unsafe_code)]
2392 pub(crate) fn opaque(self) -> OpaqueNode {
2393 unsafe { OpaqueNode(self.get_jsobject() as usize) }
2394 }
2395
2396 #[expect(unsafe_code)]
2397 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2398 unsafe {
2399 self.unsafe_get()
2400 .rare_data
2401 .borrow_for_layout()
2402 .as_ref()
2403 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2404 }
2405 }
2406
2407 pub(crate) fn is_in_ua_widget(&self) -> bool {
2408 self.unsafe_get().is_in_ua_widget()
2409 }
2410
2411 pub(crate) fn is_root_of_user_agent_widget(&self) -> bool {
2412 self.downcast::<Element>().is_some_and(|element| {
2413 element
2414 .get_shadow_root_for_layout()
2415 .is_some_and(|shadow_root| shadow_root.is_user_agent_widget())
2416 })
2417 }
2418}
2419
2420#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2422pub(crate) enum CloneChildrenFlag {
2423 CloneChildren,
2424 DoNotCloneChildren,
2425}
2426
2427impl From<bool> for CloneChildrenFlag {
2428 fn from(boolean: bool) -> Self {
2429 if boolean {
2430 CloneChildrenFlag::CloneChildren
2431 } else {
2432 CloneChildrenFlag::DoNotCloneChildren
2433 }
2434 }
2435}
2436
2437fn as_uintptr<T>(t: &T) -> uintptr_t {
2438 t as *const T as uintptr_t
2439}
2440
2441impl Node {
2442 pub(crate) fn reflect_node<N>(
2443 cx: &mut js::context::JSContext,
2444 node: Box<N>,
2445 document: &Document,
2446 ) -> DomRoot<N>
2447 where
2448 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2449 {
2450 Self::reflect_node_with_proto(cx, node, document, None)
2451 }
2452
2453 pub(crate) fn reflect_node_with_proto<N>(
2454 cx: &mut js::context::JSContext,
2455 node: Box<N>,
2456 document: &Document,
2457 proto: Option<HandleObject>,
2458 ) -> DomRoot<N>
2459 where
2460 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2461 {
2462 let window = document.window();
2463 reflect_dom_object_with_proto_and_cx(node, window, proto, cx)
2464 }
2465
2466 pub(crate) fn new_inherited(doc: &Document) -> Node {
2467 Node::new_(NodeFlags::empty(), Some(doc))
2468 }
2469
2470 pub(crate) fn new_document_node() -> Node {
2471 Node::new_(
2472 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2473 None,
2474 )
2475 }
2476
2477 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2478 Node {
2479 eventtarget: EventTarget::new_inherited(),
2480 parent_node: Default::default(),
2481 first_child: Default::default(),
2482 last_child: Default::default(),
2483 next_sibling: Default::default(),
2484 prev_sibling: Default::default(),
2485 owner_doc: MutNullableDom::new(doc),
2486 rare_data: Default::default(),
2487 children_count: Cell::new(0u32),
2488 flags: Cell::new(flags),
2489 inclusive_descendants_version: Cell::new(0),
2490 layout_data: Default::default(),
2491 }
2492 }
2493
2494 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2496 document.add_script_and_layout_blocker();
2497
2498 let old_doc = node.owner_doc();
2500 old_doc.add_script_and_layout_blocker();
2501
2502 node.remove_self(cx);
2504
2505 if &*old_doc != document {
2507 for descendant in node.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes) {
2509 descendant.set_owner_doc(document);
2511
2512 if let Some(element) = descendant.downcast::<Element>() {
2515 for attribute in element.attrs().borrow().iter() {
2516 if let Some(attr) = attribute.as_attr() {
2517 attr.upcast::<Node>().set_owner_doc(document);
2518 }
2519 }
2520 }
2521 }
2522
2523 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2527 for descendant in node
2528 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
2529 .filter_map(|d| d.as_custom_element())
2530 {
2531 custom_element_reaction_stack.enqueue_callback_reaction(
2532 &descendant,
2533 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2534 None,
2535 );
2536 }
2537
2538 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2541 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2542 }
2543 }
2544
2545 old_doc.remove_script_and_layout_blocker(cx);
2546 document.remove_script_and_layout_blocker(cx);
2547 }
2548
2549 pub(crate) fn ensure_pre_insertion_validity(
2551 no_gc: &NoGC,
2552 node: &Node,
2553 parent: &Node,
2554 child: Option<&Node>,
2555 ) -> ErrorResult {
2556 match parent.type_id() {
2558 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2559 },
2560 _ => {
2561 return Err(Error::HierarchyRequest(Some(
2562 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2563 )));
2564 },
2565 }
2566
2567 if node.is_host_including_inclusive_ancestor(parent) {
2569 return Err(Error::HierarchyRequest(Some(
2570 "Node is a host-including inclusive ancestor of parent".to_owned(),
2571 )));
2572 }
2573
2574 if let Some(child) = child &&
2576 !parent.is_parent_of(child)
2577 {
2578 return Err(Error::NotFound(Some(
2579 "Child is non-null and its parent is not parent".to_owned(),
2580 )));
2581 }
2582
2583 match node.type_id() {
2584 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2588 if parent.is::<Document>() {
2589 return Err(Error::HierarchyRequest(Some(
2590 "Node is a Text node and parent is a document".to_owned(),
2591 )));
2592 }
2593 },
2594 NodeTypeId::DocumentType => {
2595 if !parent.is::<Document>() {
2596 return Err(Error::HierarchyRequest(Some(
2597 "Node is a doctype and parent is not a document".to_owned(),
2598 )));
2599 }
2600 },
2601 NodeTypeId::DocumentFragment(_) |
2602 NodeTypeId::Element(_) |
2603 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2604 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2605 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2608 return Err(Error::HierarchyRequest(Some(
2609 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2610 .to_owned(),
2611 )));
2612 },
2613 }
2614
2615 if parent.is::<Document>() {
2618 match node.type_id() {
2619 NodeTypeId::DocumentFragment(_) => {
2620 if node.children_unrooted(no_gc).any(|c| c.is::<Text>()) {
2622 return Err(Error::HierarchyRequest(None));
2623 }
2624 match node.child_elements_unrooted(no_gc).count() {
2625 0 => (),
2626 1 => {
2629 if parent.child_elements_unrooted(no_gc).next().is_some() {
2630 return Err(Error::HierarchyRequest(None));
2631 }
2632 if let Some(child) = child &&
2633 child
2634 .inclusively_following_siblings_unrooted(no_gc)
2635 .any(|child| child.is_doctype())
2636 {
2637 return Err(Error::HierarchyRequest(None));
2638 }
2639 },
2640 _ => return Err(Error::HierarchyRequest(None)),
2641 }
2642 },
2643 NodeTypeId::Element(_) => {
2644 if parent.child_elements_unrooted(no_gc).next().is_some() {
2646 return Err(Error::HierarchyRequest(Some(
2647 "Parent has an element child".to_owned(),
2648 )));
2649 }
2650 if let Some(child) = child &&
2651 child
2652 .inclusively_following_siblings_unrooted(no_gc)
2653 .any(|following| following.is_doctype())
2654 {
2655 return Err(Error::HierarchyRequest(Some(
2656 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
2657 )));
2658 }
2659 },
2660 NodeTypeId::DocumentType => {
2661 if parent.children_unrooted(no_gc).any(|c| c.is_doctype()) {
2664 return Err(Error::HierarchyRequest(None));
2665 }
2666 match child {
2667 Some(child) => {
2668 if parent
2669 .children_unrooted(no_gc)
2670 .take_while(|c| **c != child)
2671 .any(|c| c.is::<Element>())
2672 {
2673 return Err(Error::HierarchyRequest(None));
2674 }
2675 },
2676 None => {
2677 if parent.child_elements_unrooted(no_gc).next().is_some() {
2678 return Err(Error::HierarchyRequest(None));
2679 }
2680 },
2681 }
2682 },
2683 NodeTypeId::CharacterData(_) => (),
2684 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
2687 }
2688 }
2689 Ok(())
2690 }
2691
2692 pub(crate) fn pre_insert(
2694 cx: &mut JSContext,
2695 node: &Node,
2696 parent: &Node,
2697 child: Option<&Node>,
2698 ) -> Fallible<DomRoot<Node>> {
2699 Node::ensure_pre_insertion_validity(cx.no_gc(), node, parent, child)?;
2701
2702 let reference_child_root;
2704 let reference_child = match child {
2705 Some(child) if child == node => {
2707 reference_child_root = node.GetNextSibling();
2708 reference_child_root.as_deref()
2709 },
2710 _ => child,
2711 };
2712
2713 Node::insert(
2715 cx,
2716 node,
2717 parent,
2718 reference_child,
2719 SuppressObserver::Unsuppressed,
2720 );
2721
2722 Ok(DomRoot::from_ref(node))
2724 }
2725
2726 fn insert(
2728 cx: &mut JSContext,
2729 node: &Node,
2730 parent: &Node,
2731 child: Option<&Node>,
2732 suppress_observers: SuppressObserver,
2733 ) {
2734 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
2735
2736 rooted_vec!(let mut new_nodes);
2738 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2739 new_nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
2740 new_nodes.r()
2741 } else {
2742 from_ref(&node)
2743 };
2744
2745 let count = new_nodes.len();
2747
2748 if count == 0 {
2750 return;
2751 }
2752
2753 let parent_document = parent.owner_doc();
2756 let from_document = node.owner_doc();
2757 from_document.add_script_and_layout_blocker();
2758 parent_document.add_script_and_layout_blocker();
2759
2760 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2762 for kid in new_nodes {
2764 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
2765 }
2766 vtable_for(node).children_changed(cx, &ChildrenMutation::replace_all(new_nodes, &[]));
2767
2768 let mutation = LazyCell::new(|| Mutation::ChildList {
2770 added: None,
2771 removed: Some(new_nodes),
2772 prev: None,
2773 next: None,
2774 });
2775 MutationObserver::queue_a_mutation_record(node, mutation);
2776 }
2777
2778 if let Some(child) = child &&
2784 !parent.ranges_is_empty()
2785 {
2786 parent
2787 .ranges()
2788 .increase_above(parent, child.index(), count.try_into().unwrap());
2789 }
2790
2791 let previous_sibling = match suppress_observers {
2793 SuppressObserver::Unsuppressed => match child {
2794 Some(child) => child.GetPreviousSibling(),
2795 None => parent.GetLastChild(),
2796 },
2797 SuppressObserver::Suppressed => None,
2798 };
2799
2800 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2801
2802 let mut static_node_list: SmallVec<[_; 4]> = Default::default();
2804
2805 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
2806 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
2807 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
2808
2809 for kid in new_nodes {
2811 Node::adopt(cx, kid, &parent.owner_document());
2813
2814 parent.add_child(cx, kid, child);
2817
2818 if let Some(ref shadow_root) = parent_shadow_root &&
2821 shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
2822 (kid.is::<Element>() || kid.is::<Text>())
2823 {
2824 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(kid)));
2825 slottable.assign_a_slot(cx.no_gc());
2826 }
2827
2828 if parent_in_shadow_tree &&
2831 let Some(slot_element) = parent_as_slot &&
2832 !slot_element.has_assigned_nodes()
2833 {
2834 slot_element.signal_a_slot_change();
2835 }
2836
2837 kid.GetRootNode(&GetRootNodeOptions::empty())
2839 .assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Skip);
2840
2841 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
2844 if descendant.is_connected() {
2847 static_node_list.push(descendant.clone());
2848 }
2849
2850 if let Some(descendant) = DomRoot::downcast::<Element>(descendant) {
2856 if descendant.is_custom() {
2857 if descendant.is_connected() {
2858 custom_element_reaction_stack.enqueue_callback_reaction(
2859 &descendant,
2860 CallbackReaction::Connected,
2861 None,
2862 );
2863 }
2864 } else {
2865 try_upgrade_element(&descendant);
2866 }
2867 }
2868 }
2869 }
2870
2871 if let SuppressObserver::Unsuppressed = suppress_observers {
2872 vtable_for(parent).children_changed(
2875 cx,
2876 &ChildrenMutation::insert(previous_sibling.as_deref(), new_nodes, child),
2877 );
2878
2879 let mutation = LazyCell::new(|| Mutation::ChildList {
2882 added: Some(new_nodes),
2883 removed: None,
2884 prev: previous_sibling.as_deref(),
2885 next: child,
2886 });
2887 MutationObserver::queue_a_mutation_record(parent, mutation);
2888 }
2889
2890 parent_document.add_delayed_task(
2901 task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
2902 for node in static_node_list {
2905 vtable_for(&node).post_connection_steps(cx);
2906 }
2907 }),
2908 );
2909
2910 parent_document.remove_script_and_layout_blocker(cx);
2911 from_document.remove_script_and_layout_blocker(cx);
2912 }
2913
2914 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
2916 parent.owner_doc().add_script_and_layout_blocker();
2917
2918 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
2920
2921 rooted_vec!(let mut added_nodes);
2925 let added_nodes = if let Some(node) = node.as_ref() {
2926 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
2927 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
2928 added_nodes.r()
2929 } else {
2930 from_ref(node)
2931 }
2932 } else {
2933 &[] as &[&Node]
2934 };
2935
2936 for child in &*removed_nodes {
2938 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
2939 }
2940
2941 if let Some(node) = node {
2943 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
2944 }
2945
2946 vtable_for(parent).children_changed(
2947 cx,
2948 &ChildrenMutation::replace_all(removed_nodes.r(), added_nodes),
2949 );
2950
2951 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
2954 let mutation = LazyCell::new(|| Mutation::ChildList {
2955 added: Some(added_nodes),
2956 removed: Some(removed_nodes.r()),
2957 prev: None,
2958 next: None,
2959 });
2960 MutationObserver::queue_a_mutation_record(parent, mutation);
2961 }
2962 parent.owner_doc().remove_script_and_layout_blocker(cx);
2963 }
2964
2965 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
2967 if string.is_empty() {
2968 Node::replace_all(cx, None, parent);
2969 } else {
2970 let text = Text::new(cx, string, &parent.owner_document());
2971 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
2972 };
2973 }
2974
2975 fn pre_remove(cx: &mut JSContext, child: &Node, parent: &Node) -> Fallible<DomRoot<Node>> {
2977 match child.GetParentNode() {
2979 Some(ref node) if &**node != parent => return Err(Error::NotFound(None)),
2980 None => return Err(Error::NotFound(None)),
2981 _ => (),
2982 }
2983
2984 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
2986
2987 Ok(DomRoot::from_ref(child))
2989 }
2990
2991 fn remove(
2993 cx: &mut JSContext,
2994 node: &Node,
2995 parent: &Node,
2996 suppress_observers: SuppressObserver,
2997 ) {
2998 parent.owner_doc().add_script_and_layout_blocker();
2999
3000 assert!(
3004 node.GetParentNode()
3005 .is_some_and(|node_parent| &*node_parent == parent)
3006 );
3007
3008 let cached_index = Node::live_range_pre_remove_steps(node, parent);
3011
3012 let old_previous_sibling = node.GetPreviousSibling();
3016
3017 let old_next_sibling = node.GetNextSibling();
3019
3020 parent.remove_child(cx, node, cached_index);
3023
3024 if let Some(slot) = node.assigned_slot() {
3026 slot.assign_slottables(cx.no_gc());
3027 }
3028
3029 if parent.is_in_a_shadow_tree() &&
3032 let Some(slot_element) = parent.downcast::<HTMLSlotElement>() &&
3033 !slot_element.has_assigned_nodes()
3034 {
3035 slot_element.signal_a_slot_change();
3036 }
3037
3038 let has_slot_descendant = node
3040 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
3041 .any(|elem| elem.is::<HTMLSlotElement>());
3042 if has_slot_descendant {
3043 parent
3045 .GetRootNode(&GetRootNodeOptions::empty())
3046 .assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Skip);
3047
3048 node.assign_slottables_for_a_tree(cx.no_gc(), ForceSlottableNodeReconciliation::Force);
3050 }
3051
3052 if let SuppressObserver::Unsuppressed = suppress_observers {
3056 vtable_for(parent).children_changed(
3057 cx,
3058 &ChildrenMutation::replace(
3059 old_previous_sibling.as_deref(),
3060 &Some(node),
3061 &[],
3062 old_next_sibling.as_deref(),
3063 ),
3064 );
3065
3066 let removed = [node];
3067 let mutation = LazyCell::new(|| Mutation::ChildList {
3068 added: None,
3069 removed: Some(&removed),
3070 prev: old_previous_sibling.as_deref(),
3071 next: old_next_sibling.as_deref(),
3072 });
3073 MutationObserver::queue_a_mutation_record(parent, mutation);
3074 }
3075 parent.owner_doc().remove_script_and_layout_blocker(cx);
3076 }
3077
3078 fn live_range_pre_remove_steps(node: &Node, parent: &Node) -> Option<u32> {
3080 if parent.ranges_is_empty() {
3081 return None;
3082 }
3083
3084 let index = node.index();
3090
3091 parent.ranges().decrease_above(parent, index, 1);
3098
3099 Some(index)
3103 }
3104
3105 pub(crate) fn clone(
3107 cx: &mut JSContext,
3108 node: &Node,
3109 maybe_doc: Option<&Document>,
3110 clone_children: CloneChildrenFlag,
3111 registry: Option<DomRoot<CustomElementRegistry>>,
3112 ) -> DomRoot<Node> {
3113 let document = match maybe_doc {
3115 Some(doc) => DomRoot::from_ref(doc),
3116 None => node.owner_doc(),
3117 };
3118
3119 let copy: DomRoot<Node> = match node.type_id() {
3122 NodeTypeId::DocumentType => {
3123 let doctype = node.downcast::<DocumentType>().unwrap();
3124 let doctype = DocumentType::new(
3125 cx,
3126 doctype.name().clone(),
3127 Some(doctype.public_id().clone()),
3128 Some(doctype.system_id().clone()),
3129 &document,
3130 );
3131 DomRoot::upcast::<Node>(doctype)
3132 },
3133 NodeTypeId::Attr => {
3134 let attr = node.downcast::<Attr>().unwrap();
3135 let attr = Attr::new(
3136 cx,
3137 &document,
3138 attr.local_name().clone(),
3139 attr.value().clone(),
3140 attr.name().clone(),
3141 attr.namespace().clone(),
3142 attr.prefix().cloned(),
3143 None,
3144 );
3145 DomRoot::upcast::<Node>(attr)
3146 },
3147 NodeTypeId::DocumentFragment(_) => {
3148 let doc_fragment = DocumentFragment::new(cx, &document);
3149 DomRoot::upcast::<Node>(doc_fragment)
3150 },
3151 NodeTypeId::CharacterData(_) => {
3152 let cdata = node.downcast::<CharacterData>().unwrap();
3153 cdata.clone_with_data(cx, cdata.Data(), &document)
3154 },
3155 NodeTypeId::Document(_) => {
3156 let document = node.downcast::<Document>().unwrap();
3159 let is_html_doc = if document.is_html_document() {
3160 IsHTMLDocument::HTMLDocument
3161 } else {
3162 IsHTMLDocument::NonHTMLDocument
3163 };
3164 let window = document.window();
3165 let loader = DocumentLoader::new(&document.loader());
3166 let document = Document::new(
3167 window,
3168 HasBrowsingContext::No,
3169 Some(document.url()),
3170 None,
3171 document.origin().clone(),
3173 is_html_doc,
3174 None,
3175 None,
3176 DocumentActivity::Inactive,
3177 DocumentSource::NotFromParser,
3178 loader,
3179 None,
3180 document.status_code(),
3181 Default::default(),
3182 false,
3183 document.allow_declarative_shadow_roots(),
3184 Some(document.insecure_requests_policy()),
3185 document.has_trustworthy_ancestor_or_current_origin(),
3186 document.custom_element_reaction_stack(),
3187 document.creation_sandboxing_flag_set(),
3188 CanGc::from_cx(cx),
3189 );
3190 DomRoot::upcast::<Node>(document)
3194 },
3195 NodeTypeId::Element(..) => {
3197 let element = node.downcast::<Element>().unwrap();
3198 let registry = element.custom_element_registry().or(registry);
3201 let registry =
3204 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3205 Some(document.custom_element_registry())
3206 } else {
3207 registry
3208 };
3209 let name = QualName {
3213 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3214 ns: element.namespace().clone(),
3215 local: element.local_name().clone(),
3216 };
3217 let element = Element::create(
3218 cx,
3219 name,
3220 element.get_is(),
3221 &document,
3222 ElementCreator::ScriptCreated,
3223 CustomElementCreationMode::Asynchronous,
3224 None,
3225 );
3226 element.set_custom_element_registry(registry);
3228 DomRoot::upcast::<Node>(element)
3229 },
3230 };
3231
3232 let document = match copy.downcast::<Document>() {
3235 Some(doc) => DomRoot::from_ref(doc),
3236 None => DomRoot::from_ref(&*document),
3237 };
3238 assert!(copy.owner_doc() == document);
3239
3240 match node.type_id() {
3242 NodeTypeId::Document(_) => {
3243 let node_doc = node.downcast::<Document>().unwrap();
3244 let copy_doc = copy.downcast::<Document>().unwrap();
3245 copy_doc.set_encoding(node_doc.encoding());
3246 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3247 },
3248 NodeTypeId::Element(..) => {
3249 let node_elem = node.downcast::<Element>().unwrap();
3250 let copy_elem = copy.downcast::<Element>().unwrap();
3251
3252 node_elem.copy_all_attributes_to_other_element(cx, copy_elem);
3254 },
3255 _ => (),
3256 }
3257
3258 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3261
3262 if clone_children == CloneChildrenFlag::CloneChildren {
3265 for child in node.children() {
3266 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3267 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3268 }
3269 }
3270
3271 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3274 let node_elem = node.downcast::<Element>().unwrap();
3275 let copy_elem = copy.downcast::<Element>().unwrap();
3276
3277 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3278 assert!(!copy_elem.is_shadow_host());
3280
3281 let copy_shadow_root =
3285 copy_elem.attach_shadow(
3286 cx,
3287 IsUserAgentWidget::No,
3288 shadow_root.Mode(),
3289 shadow_root.Clonable(),
3290 shadow_root.Serializable(),
3291 shadow_root.DelegatesFocus(),
3292 shadow_root.SlotAssignment(),
3293 )
3294 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3295
3296 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3298
3299 for child in shadow_root.upcast::<Node>().children() {
3302 let child_copy = Node::clone(
3303 cx,
3304 &child,
3305 Some(&document),
3306 CloneChildrenFlag::CloneChildren,
3307 None,
3308 );
3309
3310 let _inserted_node =
3312 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3313 }
3314 }
3315 }
3316
3317 copy
3319 }
3320
3321 pub(crate) fn child_text_content(&self) -> DOMString {
3323 Node::collect_text_contents(self.children())
3324 }
3325
3326 pub(crate) fn descendant_text_content(&self) -> DOMString {
3328 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3329 }
3330
3331 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3332 iterator: T,
3333 ) -> DOMString {
3334 let mut content = String::new();
3335 for node in iterator {
3336 if let Some(text) = node.downcast::<Text>() {
3337 content.push_str(&text.upcast::<CharacterData>().data());
3338 }
3339 }
3340 DOMString::from(content)
3341 }
3342
3343 pub(crate) fn set_text_content_for_element(
3345 &self,
3346 cx: &mut JSContext,
3347 value: Option<DOMString>,
3348 ) {
3349 assert!(matches!(
3352 self.type_id(),
3353 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3354 ));
3355 let value = value.unwrap_or_default();
3356 let node = if value.is_empty() {
3357 None
3359 } else {
3360 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3363 };
3364
3365 Self::replace_all(cx, node.as_deref(), self);
3367 }
3368
3369 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3370 match namespace {
3371 ns!() => None,
3372 _ => Some(DOMString::from(&*namespace)),
3374 }
3375 }
3376
3377 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3379 match node.type_id() {
3380 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3381 NodeTypeId::Attr => node
3382 .downcast::<Attr>()
3383 .unwrap()
3384 .GetOwnerElement()
3385 .as_ref()
3386 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3387 NodeTypeId::Document(_) => node
3388 .downcast::<Document>()
3389 .unwrap()
3390 .GetDocumentElement()
3391 .as_ref()
3392 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3393 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3394 _ => node
3395 .GetParentElement()
3396 .as_ref()
3397 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3398 }
3399 }
3400
3401 #[expect(unsafe_code)]
3409 pub(crate) unsafe fn from_untrusted_node_address(
3410 candidate: UntrustedNodeAddress,
3411 ) -> &'static Self {
3412 let candidate = candidate.0 as usize;
3414 let object = candidate as *mut JSObject;
3415 if object.is_null() {
3416 panic!("Attempted to create a `Node` from an invalid pointer!")
3417 }
3418
3419 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3420 }
3421
3422 pub(crate) fn html_serialize(
3423 &self,
3424 cx: &mut js::context::JSContext,
3425 traversal_scope: html_serialize::TraversalScope,
3426 serialize_shadow_roots: bool,
3427 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3428 ) -> DOMString {
3429 let mut writer = vec![];
3430 let mut serializer = HtmlSerializer::new(
3431 &mut writer,
3432 html_serialize::SerializeOpts {
3433 traversal_scope: traversal_scope.clone(),
3434 ..Default::default()
3435 },
3436 );
3437
3438 serialize_html_fragment(
3439 cx,
3440 self,
3441 &mut serializer,
3442 traversal_scope,
3443 serialize_shadow_roots,
3444 shadow_roots,
3445 )
3446 .expect("Serializing node failed");
3447
3448 DOMString::from(String::from_utf8(writer).unwrap())
3450 }
3451
3452 pub(crate) fn xml_serialize(
3454 &self,
3455 traversal_scope: xml_serialize::TraversalScope,
3456 ) -> Fallible<DOMString> {
3457 let mut writer = vec![];
3458 xml_serialize::serialize(
3459 &mut writer,
3460 &HtmlSerialize::new(self),
3461 xml_serialize::SerializeOpts { traversal_scope },
3462 )
3463 .map_err(|error| {
3464 error!("Cannot serialize node: {error}");
3465 Error::InvalidState(None)
3466 })?;
3467
3468 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3470 error!("Cannot serialize node: {error}");
3471 Error::InvalidState(None)
3472 })?);
3473
3474 Ok(string)
3475 }
3476
3477 pub(crate) fn fragment_serialization_algorithm(
3479 &self,
3480 cx: &mut js::context::JSContext,
3481 require_well_formed: bool,
3482 ) -> Fallible<DOMString> {
3483 let context_document = self.owner_document();
3485
3486 if context_document.is_html_document() {
3489 return Ok(self.html_serialize(
3490 cx,
3491 html_serialize::TraversalScope::ChildrenOnly(None),
3492 false,
3493 vec![],
3494 ));
3495 }
3496
3497 let _ = require_well_formed;
3500 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3501 }
3502
3503 pub(crate) fn get_next_sibling_unrooted<'a>(
3504 &self,
3505 no_gc: &'a NoGC,
3506 ) -> Option<UnrootedDom<'a, Node>> {
3507 self.next_sibling.get_unrooted(no_gc)
3508 }
3509
3510 pub(crate) fn get_previous_sibling_unrooted<'a>(
3511 &self,
3512 no_gc: &'a NoGC,
3513 ) -> Option<UnrootedDom<'a, Node>> {
3514 self.prev_sibling.get_unrooted(no_gc)
3515 }
3516
3517 pub(crate) fn get_first_child_unrooted<'a>(
3518 &self,
3519 no_gc: &'a NoGC,
3520 ) -> Option<UnrootedDom<'a, Node>> {
3521 self.first_child.get_unrooted(no_gc)
3522 }
3523
3524 pub(crate) fn get_parent_node_unrooted<'a>(
3525 &self,
3526 no_gc: &'a NoGC,
3527 ) -> Option<UnrootedDom<'a, Node>> {
3528 self.parent_node.get_unrooted(no_gc)
3529 }
3530
3531 pub(crate) fn compare_dom_tree_position(
3533 &self,
3534 other: &Node,
3535 common_ancestor: &Node,
3536 shadow_including: ShadowIncluding,
3537 ) -> Ordering {
3538 debug_assert!(
3539 self.inclusive_ancestors(shadow_including)
3540 .any(|ancestor| &*ancestor == common_ancestor)
3541 );
3542 debug_assert!(
3543 other
3544 .inclusive_ancestors(shadow_including)
3545 .any(|ancestor| &*ancestor == common_ancestor)
3546 );
3547
3548 if self == other {
3549 return Ordering::Equal;
3550 }
3551
3552 if self == common_ancestor {
3553 return Ordering::Less;
3554 }
3555 if other == common_ancestor {
3556 return Ordering::Greater;
3557 }
3558
3559 let my_ancestors: Vec<_> = self
3560 .inclusive_ancestors(shadow_including)
3561 .take_while(|ancestor| &**ancestor != common_ancestor)
3562 .collect();
3563 let other_ancestors: Vec<_> = other
3564 .inclusive_ancestors(shadow_including)
3565 .take_while(|ancestor| &**ancestor != common_ancestor)
3566 .collect();
3567
3568 let mut i = my_ancestors.len() - 1;
3570 let mut j = other_ancestors.len() - 1;
3571
3572 while my_ancestors[i] == other_ancestors[j] {
3573 if i == 0 {
3574 debug_assert_ne!(j, 0, "Equal inclusive ancestors but nodes are not equal?");
3576 return Ordering::Less;
3577 }
3578 if j == 0 {
3579 return Ordering::Greater;
3581 }
3582
3583 i -= 1;
3584 j -= 1;
3585 }
3586
3587 if my_ancestors[i]
3590 .preceding_siblings()
3591 .any(|sibling| sibling == other_ancestors[j])
3592 {
3593 Ordering::Greater
3595 } else {
3596 debug_assert!(
3598 other_ancestors[j]
3599 .preceding_siblings()
3600 .any(|sibling| sibling == my_ancestors[i])
3601 );
3602 Ordering::Less
3603 }
3604 }
3605}
3606
3607impl NodeMethods<crate::DomTypeHolder> for Node {
3608 fn NodeType(&self) -> u16 {
3610 match self.type_id() {
3611 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3612 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3613 NodeConstants::TEXT_NODE
3614 },
3615 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3616 NodeConstants::CDATA_SECTION_NODE
3617 },
3618 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3619 NodeConstants::PROCESSING_INSTRUCTION_NODE
3620 },
3621 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3622 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3623 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3624 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3625 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3626 }
3627 }
3628
3629 fn NodeName(&self) -> DOMString {
3631 match self.type_id() {
3632 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3633 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3634 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3635 DOMString::from("#text")
3636 },
3637 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3638 DOMString::from("#cdata-section")
3639 },
3640 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3641 self.downcast::<ProcessingInstruction>().unwrap().Target()
3642 },
3643 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => DOMString::from("#comment"),
3644 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3645 NodeTypeId::DocumentFragment(_) => DOMString::from("#document-fragment"),
3646 NodeTypeId::Document(_) => DOMString::from("#document"),
3647 }
3648 }
3649
3650 fn BaseURI(&self) -> USVString {
3652 USVString(String::from(self.owner_doc().base_url().as_str()))
3653 }
3654
3655 fn IsConnected(&self) -> bool {
3657 self.is_connected()
3658 }
3659
3660 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3662 match self.type_id() {
3663 NodeTypeId::Document(_) => None,
3664 _ => Some(self.owner_doc()),
3665 }
3666 }
3667
3668 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3670 if !options.composed &&
3671 let Some(shadow_root) = self.containing_shadow_root()
3672 {
3673 return DomRoot::upcast(shadow_root);
3674 }
3675
3676 if self.is_connected() {
3677 DomRoot::from_ref(self.owner_doc().upcast::<Node>())
3678 } else {
3679 self.inclusive_ancestors(ShadowIncluding::Yes)
3680 .last()
3681 .unwrap()
3682 }
3683 }
3684
3685 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
3687 self.parent_node.get()
3688 }
3689
3690 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
3692 self.GetParentNode().and_then(DomRoot::downcast)
3693 }
3694
3695 fn HasChildNodes(&self) -> bool {
3697 self.first_child.get().is_some()
3698 }
3699
3700 fn ChildNodes(&self, cx: &mut JSContext) -> DomRoot<NodeList> {
3702 if let Some(list) = self.ensure_rare_data().child_list.get() {
3703 return list;
3704 }
3705
3706 let doc = self.owner_doc();
3707 let window = doc.window();
3708 let list = NodeList::new_child_list(window, self, CanGc::from_cx(cx));
3709 self.ensure_rare_data().child_list.set(Some(&list));
3710 list
3711 }
3712
3713 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
3715 self.first_child.get()
3716 }
3717
3718 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
3720 self.last_child.get()
3721 }
3722
3723 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
3725 self.prev_sibling.get()
3726 }
3727
3728 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
3730 self.next_sibling.get()
3731 }
3732
3733 fn GetNodeValue(&self) -> Option<DOMString> {
3735 match self.type_id() {
3736 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3737 NodeTypeId::CharacterData(_) => {
3738 self.downcast::<CharacterData>().map(CharacterData::Data)
3739 },
3740 _ => None,
3741 }
3742 }
3743
3744 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
3746 match self.type_id() {
3747 NodeTypeId::Attr => {
3748 let attr = self.downcast::<Attr>().unwrap();
3749 attr.SetValue(cx, val.unwrap_or_default())?;
3750 },
3751 NodeTypeId::CharacterData(_) => {
3752 let character_data = self.downcast::<CharacterData>().unwrap();
3753 character_data.SetData(cx, val.unwrap_or_default());
3754 },
3755 _ => {},
3756 };
3757 Ok(())
3758 }
3759
3760 fn GetTextContent(&self) -> Option<DOMString> {
3762 match self.type_id() {
3763 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3764 let content =
3765 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
3766 Some(content)
3767 },
3768 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
3769 NodeTypeId::CharacterData(..) => {
3770 let characterdata = self.downcast::<CharacterData>().unwrap();
3771 Some(characterdata.Data())
3772 },
3773 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
3774 }
3775 }
3776
3777 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
3779 match self.type_id() {
3780 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3781 self.set_text_content_for_element(cx, value);
3782 },
3783 NodeTypeId::Attr => {
3784 let attr = self.downcast::<Attr>().unwrap();
3785 attr.SetValue(cx, value.unwrap_or_default())?;
3786 },
3787 NodeTypeId::CharacterData(..) => {
3788 let characterdata = self.downcast::<CharacterData>().unwrap();
3789 characterdata.SetData(cx, value.unwrap_or_default());
3790 },
3791 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
3792 };
3793 Ok(())
3794 }
3795
3796 fn InsertBefore(
3798 &self,
3799 cx: &mut JSContext,
3800 node: &Node,
3801 child: Option<&Node>,
3802 ) -> Fallible<DomRoot<Node>> {
3803 Node::pre_insert(cx, node, self, child)
3804 }
3805
3806 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3808 Node::pre_insert(cx, node, self, None)
3809 }
3810
3811 fn ReplaceChild(
3813 &self,
3814 cx: &mut JSContext,
3815 node: &Node,
3816 child: &Node,
3817 ) -> Fallible<DomRoot<Node>> {
3818 match self.type_id() {
3821 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
3822 },
3823 _ => return Err(Error::HierarchyRequest(None)),
3824 }
3825
3826 if node.is_inclusive_ancestor_of(self) {
3829 return Err(Error::HierarchyRequest(None));
3830 }
3831
3832 if !self.is_parent_of(child) {
3834 return Err(Error::NotFound(None));
3835 }
3836
3837 match node.type_id() {
3842 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
3843 return Err(Error::HierarchyRequest(None));
3844 },
3845 NodeTypeId::DocumentType if !self.is::<Document>() => {
3846 return Err(Error::HierarchyRequest(None));
3847 },
3848 NodeTypeId::Document(_) | NodeTypeId::Attr => {
3849 return Err(Error::HierarchyRequest(None));
3850 },
3851 _ => (),
3852 }
3853
3854 if self.is::<Document>() {
3857 match node.type_id() {
3858 NodeTypeId::DocumentFragment(_) => {
3860 if node.children_unrooted(cx.no_gc()).any(|c| c.is::<Text>()) {
3862 return Err(Error::HierarchyRequest(None));
3863 }
3864 match node.child_elements_unrooted(cx.no_gc()).count() {
3865 0 => (),
3866 1 => {
3868 if self
3869 .child_elements_unrooted(cx.no_gc())
3870 .any(|c| c.upcast::<Node>() != child)
3871 {
3872 return Err(Error::HierarchyRequest(None));
3873 }
3874 if child.following_siblings().any(|child| child.is_doctype()) {
3875 return Err(Error::HierarchyRequest(None));
3876 }
3877 },
3878 _ => return Err(Error::HierarchyRequest(None)),
3880 }
3881 },
3882 NodeTypeId::Element(..) => {
3884 if self
3885 .child_elements_unrooted(cx.no_gc())
3886 .any(|c| c.upcast::<Node>() != child)
3887 {
3888 return Err(Error::HierarchyRequest(None));
3889 }
3890 if child.following_siblings().any(|child| child.is_doctype()) {
3891 return Err(Error::HierarchyRequest(None));
3892 }
3893 },
3894 NodeTypeId::DocumentType => {
3896 if self
3897 .children_unrooted(cx.no_gc())
3898 .any(|c| c.is_doctype() && *c != child)
3899 {
3900 return Err(Error::HierarchyRequest(None));
3901 }
3902 if self
3903 .children_unrooted(cx.no_gc())
3904 .take_while(|c| **c != child)
3905 .any(|c| c.is::<Element>())
3906 {
3907 return Err(Error::HierarchyRequest(None));
3908 }
3909 },
3910 NodeTypeId::CharacterData(..) => (),
3911 NodeTypeId::Document(_) => unreachable!(),
3914 NodeTypeId::Attr => unreachable!(),
3915 }
3916 }
3917
3918 let child_next_sibling = child.GetNextSibling();
3921 let node_next_sibling = node.GetNextSibling();
3922 let reference_child = if child_next_sibling.as_deref() == Some(node) {
3923 node_next_sibling.as_deref()
3924 } else {
3925 child_next_sibling.as_deref()
3926 };
3927
3928 let previous_sibling = child.GetPreviousSibling();
3930
3931 let document = self.owner_document();
3935 Node::adopt(cx, node, &document);
3936
3937 let removed_child = if node != child {
3942 Node::remove(cx, child, self, SuppressObserver::Suppressed);
3944 Some(child)
3945 } else {
3946 None
3947 };
3948
3949 rooted_vec!(let mut nodes);
3951 let nodes = if node.type_id() ==
3952 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
3953 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
3954 {
3955 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
3956 nodes.r()
3957 } else {
3958 from_ref(&node)
3959 };
3960
3961 Node::insert(
3963 cx,
3964 node,
3965 self,
3966 reference_child,
3967 SuppressObserver::Suppressed,
3968 );
3969
3970 vtable_for(self).children_changed(
3971 cx,
3972 &ChildrenMutation::replace(
3973 previous_sibling.as_deref(),
3974 &removed_child,
3975 nodes,
3976 reference_child,
3977 ),
3978 );
3979
3980 let removed = removed_child.map(|r| [r]);
3983 let mutation = LazyCell::new(|| Mutation::ChildList {
3984 added: Some(nodes),
3985 removed: removed.as_ref().map(|r| &r[..]),
3986 prev: previous_sibling.as_deref(),
3987 next: reference_child,
3988 });
3989
3990 MutationObserver::queue_a_mutation_record(self, mutation);
3991
3992 Ok(DomRoot::from_ref(child))
3994 }
3995
3996 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
3998 Node::pre_remove(cx, node, self)
3999 }
4000
4001 fn Normalize(&self, cx: &mut JSContext) {
4003 let mut children = self.children().enumerate().peekable();
4004 while let Some((_, node)) = children.next() {
4005 if let Some(text) = node.downcast::<Text>() {
4006 if text.is::<CDATASection>() {
4007 continue;
4008 }
4009 let cdata = text.upcast::<CharacterData>();
4010 let mut length = cdata.Length();
4011 if length == 0 {
4012 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
4013 continue;
4014 }
4015 while children.peek().is_some_and(|(_, sibling)| {
4016 sibling.is::<Text>() && !sibling.is::<CDATASection>()
4017 }) {
4018 let (index, sibling) = children.next().unwrap();
4019 sibling
4020 .ranges()
4021 .drain_to_preceding_text_sibling(&sibling, &node, length);
4022 self.ranges()
4023 .move_to_text_child_at(self, index as u32, &node, length);
4024 let sibling_cdata = sibling.downcast::<CharacterData>().unwrap();
4025 length += sibling_cdata.Length();
4026 cdata.append_data(cx, &sibling_cdata.data());
4027 Node::remove(cx, &sibling, self, SuppressObserver::Unsuppressed);
4028 }
4029 } else {
4030 node.Normalize(cx);
4031 }
4032 }
4033 }
4034
4035 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
4037 if self.is::<ShadowRoot>() {
4039 return Err(Error::NotSupported(None));
4040 }
4041
4042 let result = Node::clone(
4044 cx,
4045 self,
4046 None,
4047 if subtree {
4048 CloneChildrenFlag::CloneChildren
4049 } else {
4050 CloneChildrenFlag::DoNotCloneChildren
4051 },
4052 None,
4053 );
4054 Ok(result)
4055 }
4056
4057 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
4059 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
4060 let doctype = node.downcast::<DocumentType>().unwrap();
4061 let other_doctype = other.downcast::<DocumentType>().unwrap();
4062 (*doctype.name() == *other_doctype.name()) &&
4063 (*doctype.public_id() == *other_doctype.public_id()) &&
4064 (*doctype.system_id() == *other_doctype.system_id())
4065 }
4066 fn is_equal_element(node: &Node, other: &Node) -> bool {
4067 let element = node.downcast::<Element>().unwrap();
4068 let other_element = other.downcast::<Element>().unwrap();
4069 (*element.namespace() == *other_element.namespace()) &&
4070 (*element.prefix() == *other_element.prefix()) &&
4071 (*element.local_name() == *other_element.local_name()) &&
4072 (element.attrs().borrow().len() == other_element.attrs().borrow().len())
4073 }
4074 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
4075 let pi = node.downcast::<ProcessingInstruction>().unwrap();
4076 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
4077 (*pi.target() == *other_pi.target()) &&
4078 (*pi.upcast::<CharacterData>().data() ==
4079 *other_pi.upcast::<CharacterData>().data())
4080 }
4081 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
4082 let characterdata = node.downcast::<CharacterData>().unwrap();
4083 let other_characterdata = other.downcast::<CharacterData>().unwrap();
4084 *characterdata.data() == *other_characterdata.data()
4085 }
4086 fn is_equal_attr(node: &Node, other: &Node) -> bool {
4087 let attr = node.downcast::<Attr>().unwrap();
4088 let other_attr = other.downcast::<Attr>().unwrap();
4089 (*attr.namespace() == *other_attr.namespace()) &&
4090 (attr.local_name() == other_attr.local_name()) &&
4091 (**attr.value() == **other_attr.value())
4092 }
4093 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
4094 let element = node.downcast::<Element>().unwrap();
4095 let other_element = other.downcast::<Element>().unwrap();
4096 assert!(element.attrs().borrow().len() == other_element.attrs().borrow().len());
4097 element.attrs().borrow().iter().all(|attr| {
4098 other_element.attrs().borrow().iter().any(|other_attr| {
4099 (*attr.namespace() == *other_attr.namespace()) &&
4100 (attr.local_name() == other_attr.local_name()) &&
4101 (**attr.value() == **other_attr.value())
4102 })
4103 })
4104 }
4105
4106 fn is_equal_node(this: &Node, node: &Node) -> bool {
4107 if this.NodeType() != node.NodeType() {
4109 return false;
4110 }
4111
4112 match node.type_id() {
4113 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
4115 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
4116 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
4117 if !is_equal_processinginstruction(this, node) =>
4118 {
4119 return false;
4120 },
4121 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
4122 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
4123 if !is_equal_characterdata(this, node) =>
4124 {
4125 return false;
4126 },
4127 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
4129 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
4130
4131 _ => (),
4132 }
4133
4134 if this.children_count() != node.children_count() {
4136 return false;
4137 }
4138
4139 this.children()
4141 .zip(node.children())
4142 .all(|(child, other_child)| is_equal_node(&child, &other_child))
4143 }
4144 match maybe_node {
4145 None => false,
4147 Some(node) => is_equal_node(self, node),
4149 }
4150 }
4151
4152 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
4154 match other_node {
4155 Some(node) => self == node,
4156 None => false,
4157 }
4158 }
4159
4160 fn CompareDocumentPosition(&self, other: &Node) -> u16 {
4162 if self == other {
4164 return 0;
4165 }
4166
4167 let mut node1 = Some(other);
4169 let mut node2 = Some(self);
4170
4171 let mut attr1: Option<&Attr> = None;
4173 let mut attr2: Option<&Attr> = None;
4174
4175 let attr1owner;
4180 if let Some(a) = other.downcast::<Attr>() {
4181 attr1 = Some(a);
4182 attr1owner = a.GetOwnerElement();
4183 node1 = match attr1owner {
4184 Some(ref e) => Some(e.upcast()),
4185 None => None,
4186 }
4187 }
4188
4189 let attr2owner;
4192 if let Some(a) = self.downcast::<Attr>() {
4193 attr2 = Some(a);
4194 attr2owner = a.GetOwnerElement();
4195 node2 = match attr2owner {
4196 Some(ref e) => Some(e.upcast()),
4197 None => None,
4198 }
4199 }
4200
4201 if let Some(node2) = node2 &&
4206 Some(node2) == node1 &&
4207 let (Some(a1), Some(a2)) = (attr1, attr2)
4208 {
4209 let attrs = node2.downcast::<Element>().unwrap().attrs();
4210 for attr in attrs.borrow().iter() {
4214 if (*attr.namespace() == *a1.namespace()) &&
4215 (attr.local_name() == a1.local_name()) &&
4216 (**attr.value() == **a1.value())
4217 {
4218 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4219 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4220 }
4221 if (*attr.namespace() == *a2.namespace()) &&
4222 (attr.local_name() == a2.local_name()) &&
4223 (**attr.value() == **a2.value())
4224 {
4225 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4226 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4227 }
4228 }
4229 unreachable!();
4232 }
4233
4234 match (node1, node2) {
4236 (None, _) => {
4237 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4239 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4240 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4241 },
4242 (_, None) => {
4243 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4245 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4246 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4247 },
4248 (Some(node1), Some(node2)) => {
4249 let mut self_and_ancestors = node2
4251 .inclusive_ancestors(ShadowIncluding::No)
4252 .collect::<SmallVec<[_; 20]>>();
4253 let mut other_and_ancestors = node1
4254 .inclusive_ancestors(ShadowIncluding::No)
4255 .collect::<SmallVec<[_; 20]>>();
4256
4257 if self_and_ancestors.last() != other_and_ancestors.last() {
4258 let random = as_uintptr(self_and_ancestors.last().unwrap()) <
4259 as_uintptr(other_and_ancestors.last().unwrap());
4260 let random = if random {
4261 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4262 } else {
4263 NodeConstants::DOCUMENT_POSITION_PRECEDING
4264 };
4265
4266 return random +
4268 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4269 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4270 }
4271 let mut parent = self_and_ancestors.pop().unwrap();
4273 other_and_ancestors.pop().unwrap();
4274
4275 let mut current_position =
4276 cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
4277
4278 while current_position > 0 {
4279 current_position -= 1;
4280 let child_1 = self_and_ancestors.pop().unwrap();
4281 let child_2 = other_and_ancestors.pop().unwrap();
4282
4283 if child_1 != child_2 {
4284 for child in parent.children() {
4285 if child == child_1 {
4286 return NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4288 }
4289 if child == child_2 {
4290 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4292 }
4293 }
4294 }
4295
4296 parent = child_1;
4297 }
4298
4299 if self_and_ancestors.len() < other_and_ancestors.len() {
4304 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4305 NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
4306 } else {
4307 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4308 NodeConstants::DOCUMENT_POSITION_CONTAINS
4309 }
4310 },
4311 }
4312 }
4313
4314 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4316 match maybe_other {
4317 None => false,
4318 Some(other) => self.is_inclusive_ancestor_of(other),
4319 }
4320 }
4321
4322 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4324 let namespace = namespace_from_domstring(namespace);
4325
4326 if namespace == ns!() {
4328 return None;
4329 }
4330
4331 match self.type_id() {
4333 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4334 NodeTypeId::Document(_) => self
4335 .downcast::<Document>()
4336 .unwrap()
4337 .GetDocumentElement()
4338 .and_then(|element| element.lookup_prefix(namespace)),
4339 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4340 NodeTypeId::Attr => self
4341 .downcast::<Attr>()
4342 .unwrap()
4343 .GetOwnerElement()
4344 .and_then(|element| element.lookup_prefix(namespace)),
4345 _ => self
4346 .GetParentElement()
4347 .and_then(|element| element.lookup_prefix(namespace)),
4348 }
4349 }
4350
4351 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4353 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4355
4356 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4358 }
4359
4360 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4362 let namespace = namespace_from_domstring(namespace);
4364 Node::locate_namespace(self, None) == namespace
4366 }
4367}
4368
4369pub(crate) trait NodeTraits {
4370 fn owner_document(&self) -> DomRoot<Document>;
4374 fn owner_window(&self) -> DomRoot<Window>;
4378 fn owner_global(&self) -> DomRoot<GlobalScope>;
4382 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4384 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4387}
4388
4389impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4390 fn owner_document(&self) -> DomRoot<Document> {
4391 self.upcast().owner_doc()
4392 }
4393
4394 fn owner_window(&self) -> DomRoot<Window> {
4395 DomRoot::from_ref(self.owner_document().window())
4396 }
4397
4398 fn owner_global(&self) -> DomRoot<GlobalScope> {
4399 DomRoot::from_ref(self.owner_window().upcast())
4400 }
4401
4402 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4403 Node::containing_shadow_root(self.upcast())
4404 }
4405
4406 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4407 self.containing_shadow_root()
4408 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4409 .unwrap_or_else(|| {
4410 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4411 })
4412 }
4413}
4414
4415impl VirtualMethods for Node {
4416 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4417 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4418 }
4419
4420 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4421 if let Some(s) = self.super_type() {
4422 s.children_changed(cx, mutation);
4423 }
4424
4425 if let Some(data) = self.rare_data().as_ref() &&
4426 let Some(list) = data.child_list.get()
4427 {
4428 list.as_children_list().children_changed(mutation);
4429 }
4430
4431 self.owner_doc().content_and_heritage_changed(self);
4432 }
4433
4434 fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
4437 self.super_type().unwrap().unbind_from_tree(cx, context);
4438
4439 if !self.is_in_a_shadow_tree() && !self.ranges_is_empty() {
4444 self.ranges()
4445 .drain_to_parent(context.parent, context.index(), self);
4446 }
4447
4448 if self.owner_document().accessibility_active() {
4449 self.owner_document()
4450 .accessibility_data_mut()
4451 .root_removed_node(cx.no_gc(), self);
4452 }
4453 }
4454
4455 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
4456 if let Some(super_type) = self.super_type() {
4457 super_type.moving_steps(cx, context);
4458 }
4459
4460 if let Some(old_parent) = context.old_parent &&
4465 !self.is_in_a_shadow_tree() &&
4466 !self.ranges_is_empty()
4467 {
4468 self.ranges()
4469 .drain_to_parent(old_parent, context.index(), self);
4470 }
4471
4472 self.owner_doc().content_and_heritage_changed(self);
4473 }
4474
4475 fn handle_event(&self, cx: &mut js::context::JSContext, event: &Event) {
4476 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4477 return;
4478 }
4479
4480 if let Some(event) = event.downcast::<KeyboardEvent>() {
4481 self.owner_document()
4482 .event_handler()
4483 .run_default_keyboard_event_handler(cx, self, event);
4484 }
4485 }
4486}
4487
4488#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4490pub(crate) enum NodeDamage {
4491 Style,
4493 ContentOrHeritage,
4496 Other,
4498}
4499
4500pub(crate) enum ChildrenMutation<'a> {
4501 Append {
4502 prev: &'a Node,
4503 added: &'a [&'a Node],
4504 },
4505 Insert {
4506 prev: &'a Node,
4507 added: &'a [&'a Node],
4508 next: &'a Node,
4509 },
4510 Prepend {
4511 added: &'a [&'a Node],
4512 next: &'a Node,
4513 },
4514 Replace {
4515 prev: Option<&'a Node>,
4516 removed: &'a Node,
4517 added: &'a [&'a Node],
4518 next: Option<&'a Node>,
4519 },
4520 ReplaceAll {
4521 removed: &'a [&'a Node],
4522 added: &'a [&'a Node],
4523 },
4524 ChangeText,
4529}
4530
4531impl<'a> ChildrenMutation<'a> {
4532 fn insert(
4533 prev: Option<&'a Node>,
4534 added: &'a [&'a Node],
4535 next: Option<&'a Node>,
4536 ) -> ChildrenMutation<'a> {
4537 match (prev, next) {
4538 (None, None) => ChildrenMutation::ReplaceAll {
4539 removed: &[],
4540 added,
4541 },
4542 (Some(prev), None) => ChildrenMutation::Append { prev, added },
4543 (None, Some(next)) => ChildrenMutation::Prepend { added, next },
4544 (Some(prev), Some(next)) => ChildrenMutation::Insert { prev, added, next },
4545 }
4546 }
4547
4548 fn replace(
4549 prev: Option<&'a Node>,
4550 removed: &'a Option<&'a Node>,
4551 added: &'a [&'a Node],
4552 next: Option<&'a Node>,
4553 ) -> ChildrenMutation<'a> {
4554 if let Some(ref removed) = *removed {
4555 if let (None, None) = (prev, next) {
4556 ChildrenMutation::ReplaceAll {
4557 removed: from_ref(removed),
4558 added,
4559 }
4560 } else {
4561 ChildrenMutation::Replace {
4562 prev,
4563 removed,
4564 added,
4565 next,
4566 }
4567 }
4568 } else {
4569 ChildrenMutation::insert(prev, added, next)
4570 }
4571 }
4572
4573 fn replace_all(removed: &'a [&'a Node], added: &'a [&'a Node]) -> ChildrenMutation<'a> {
4574 ChildrenMutation::ReplaceAll { removed, added }
4575 }
4576
4577 pub(crate) fn next_child(&self) -> Option<&Node> {
4582 match *self {
4583 ChildrenMutation::Append { .. } => None,
4584 ChildrenMutation::Insert { next, .. } => Some(next),
4585 ChildrenMutation::Prepend { next, .. } => Some(next),
4586 ChildrenMutation::Replace { next, .. } => next,
4587 ChildrenMutation::ReplaceAll { .. } => None,
4588 ChildrenMutation::ChangeText => None,
4589 }
4590 }
4591
4592 pub(crate) fn modified_edge_element(&self, no_gc: &NoGC) -> Option<DomRoot<Node>> {
4599 match *self {
4600 ChildrenMutation::Prepend { next, .. } |
4602 ChildrenMutation::Replace {
4603 prev: None,
4604 next: Some(next),
4605 ..
4606 } => next
4607 .inclusively_following_siblings_unrooted(no_gc)
4608 .find(|node| node.is::<Element>())
4609 .map(|node| node.as_rooted()),
4610 ChildrenMutation::Append { prev, .. } |
4612 ChildrenMutation::Replace {
4613 prev: Some(prev),
4614 next: None,
4615 ..
4616 } => prev
4617 .inclusively_preceding_siblings_unrooted(no_gc)
4618 .find(|node| node.is::<Element>())
4619 .map(|node| node.as_rooted()),
4620 ChildrenMutation::Insert { prev, next, .. } |
4622 ChildrenMutation::Replace {
4623 prev: Some(prev),
4624 next: Some(next),
4625 ..
4626 } => {
4627 if prev
4628 .inclusively_preceding_siblings_unrooted(no_gc)
4629 .all(|node| !node.is::<Element>())
4630 {
4631 next.inclusively_following_siblings_unrooted(no_gc)
4633 .find(|node| node.is::<Element>())
4634 .map(|node| node.as_rooted())
4635 } else if next
4636 .inclusively_following_siblings_unrooted(no_gc)
4637 .all(|node| !node.is::<Element>())
4638 {
4639 prev.inclusively_preceding_siblings_unrooted(no_gc)
4641 .find(|node| node.is::<Element>())
4642 .map(|node| node.as_rooted())
4643 } else {
4644 None
4645 }
4646 },
4647
4648 ChildrenMutation::Replace {
4649 prev: None,
4650 next: None,
4651 ..
4652 } => unreachable!(),
4653 ChildrenMutation::ReplaceAll { .. } => None,
4654 ChildrenMutation::ChangeText => None,
4655 }
4656 }
4657}
4658
4659pub(crate) struct BindContext<'a> {
4661 pub(crate) parent: &'a Node,
4663
4664 pub(crate) tree_connected: bool,
4668
4669 pub(crate) tree_is_in_a_document_tree: bool,
4673
4674 pub(crate) tree_is_in_a_shadow_tree: bool,
4676
4677 pub(crate) is_shadow_tree: IsShadowTree,
4682}
4683
4684#[derive(Debug, Eq, PartialEq)]
4685pub(crate) enum IsShadowTree {
4686 Yes,
4687 No,
4688}
4689
4690impl<'a> BindContext<'a> {
4691 pub(crate) fn new(parent: &'a Node, is_shadow_tree: IsShadowTree) -> Self {
4693 BindContext {
4694 parent,
4695 tree_connected: parent.is_connected(),
4696 tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
4697 tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
4698 is_shadow_tree,
4699 }
4700 }
4701
4702 pub(crate) fn is_in_tree(&self) -> bool {
4704 self.tree_is_in_a_document_tree || self.tree_is_in_a_shadow_tree
4705 }
4706}
4707
4708pub(crate) struct UnbindContext<'a> {
4711 index: Cell<Option<u32>>,
4713 pub(crate) parent: &'a Node,
4715 prev_sibling: Option<&'a Node>,
4717 pub(crate) next_sibling: Option<&'a Node>,
4719
4720 pub(crate) tree_connected: bool,
4724
4725 pub(crate) tree_is_in_a_document_tree: bool,
4729
4730 pub(crate) tree_is_in_a_shadow_tree: bool,
4732}
4733
4734impl<'a> UnbindContext<'a> {
4735 pub(crate) fn new(
4737 parent: &'a Node,
4738 prev_sibling: Option<&'a Node>,
4739 next_sibling: Option<&'a Node>,
4740 cached_index: Option<u32>,
4741 ) -> Self {
4742 UnbindContext {
4743 index: Cell::new(cached_index),
4744 parent,
4745 prev_sibling,
4746 next_sibling,
4747 tree_connected: parent.is_connected(),
4748 tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
4749 tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
4750 }
4751 }
4752
4753 pub(crate) fn index(&self) -> u32 {
4755 if let Some(index) = self.index.get() {
4756 return index;
4757 }
4758 let index = self.prev_sibling.map_or(0, |sibling| sibling.index() + 1);
4759 self.index.set(Some(index));
4760 index
4761 }
4762}
4763
4764pub(crate) struct MoveContext<'a> {
4767 index: Cell<Option<u32>>,
4769 pub(crate) old_parent: Option<&'a Node>,
4771 prev_sibling: Option<&'a Node>,
4773 pub(crate) next_sibling: Option<&'a Node>,
4775}
4776
4777impl<'a> MoveContext<'a> {
4778 pub(crate) fn new(
4780 old_parent: Option<&'a Node>,
4781 prev_sibling: Option<&'a Node>,
4782 next_sibling: Option<&'a Node>,
4783 cached_index: Option<u32>,
4784 ) -> Self {
4785 MoveContext {
4786 index: Cell::new(cached_index),
4787 old_parent,
4788 prev_sibling,
4789 next_sibling,
4790 }
4791 }
4792
4793 pub(crate) fn index(&self) -> u32 {
4795 if let Some(index) = self.index.get() {
4796 return index;
4797 }
4798 let index = self.prev_sibling.map_or(0, |sibling| sibling.index() + 1);
4799 self.index.set(Some(index));
4800 index
4801 }
4802}
4803
4804pub(crate) struct UniqueId {
4806 cell: UnsafeCell<Option<Box<Uuid>>>,
4807}
4808
4809unsafe_no_jsmanaged_fields!(UniqueId);
4810
4811impl MallocSizeOf for UniqueId {
4812 #[expect(unsafe_code)]
4813 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
4814 if let Some(uuid) = unsafe { &*self.cell.get() } {
4815 unsafe { ops.malloc_size_of(&**uuid) }
4816 } else {
4817 0
4818 }
4819 }
4820}
4821
4822impl UniqueId {
4823 fn new() -> UniqueId {
4825 UniqueId {
4826 cell: UnsafeCell::new(None),
4827 }
4828 }
4829
4830 #[expect(unsafe_code)]
4832 fn borrow(&self) -> &Uuid {
4833 unsafe {
4834 let ptr = self.cell.get();
4835 if (*ptr).is_none() {
4836 *ptr = Some(Box::new(Uuid::new_v4()));
4837 }
4838 (*ptr).as_ref().unwrap()
4839 }
4840 }
4841}
4842
4843pub(crate) struct NodeTypeIdWrapper(pub(crate) NodeTypeId);
4844
4845impl From<NodeTypeIdWrapper> for LayoutNodeType {
4846 #[inline(always)]
4847 fn from(node_type: NodeTypeIdWrapper) -> LayoutNodeType {
4848 match node_type.0 {
4849 NodeTypeId::Element(e) => LayoutNodeType::Element(ElementTypeIdWrapper(e).into()),
4850 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => LayoutNodeType::Text,
4851 x => unreachable!("Layout should not traverse nodes of type {:?}", x),
4852 }
4853 }
4854}
4855
4856struct ElementTypeIdWrapper(ElementTypeId);
4857
4858impl From<ElementTypeIdWrapper> for LayoutElementType {
4859 #[inline(always)]
4860 fn from(element_type: ElementTypeIdWrapper) -> LayoutElementType {
4861 match element_type.0 {
4862 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement) => {
4863 LayoutElementType::HTMLBodyElement
4864 },
4865 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBRElement) => {
4866 LayoutElementType::HTMLBRElement
4867 },
4868 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement) => {
4869 LayoutElementType::HTMLCanvasElement
4870 },
4871 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHtmlElement) => {
4872 LayoutElementType::HTMLHtmlElement
4873 },
4874 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement) => {
4875 LayoutElementType::HTMLIFrameElement
4876 },
4877 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement) => {
4878 LayoutElementType::HTMLImageElement
4879 },
4880 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(_)) => {
4881 LayoutElementType::HTMLMediaElement
4882 },
4883 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement) => {
4884 LayoutElementType::HTMLInputElement
4885 },
4886 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement) => {
4887 LayoutElementType::HTMLOptGroupElement
4888 },
4889 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement) => {
4890 LayoutElementType::HTMLOptionElement
4891 },
4892 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement) => {
4893 LayoutElementType::HTMLObjectElement
4894 },
4895 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLParagraphElement) => {
4896 LayoutElementType::HTMLParagraphElement
4897 },
4898 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLPreElement) => {
4899 LayoutElementType::HTMLPreElement
4900 },
4901 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement) => {
4902 LayoutElementType::HTMLSelectElement
4903 },
4904 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableCellElement) => {
4905 LayoutElementType::HTMLTableCellElement
4906 },
4907 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement) => {
4908 LayoutElementType::HTMLTableColElement
4909 },
4910 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement) => {
4911 LayoutElementType::HTMLTableElement
4912 },
4913 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement) => {
4914 LayoutElementType::HTMLTableRowElement
4915 },
4916 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement) => {
4917 LayoutElementType::HTMLTableSectionElement
4918 },
4919 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement) => {
4920 LayoutElementType::HTMLTextAreaElement
4921 },
4922 ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
4923 SVGGraphicsElementTypeId::SVGImageElement,
4924 )) => LayoutElementType::SVGImageElement,
4925 ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
4926 SVGGraphicsElementTypeId::SVGSVGElement,
4927 )) => LayoutElementType::SVGSVGElement,
4928 _ => LayoutElementType::Element,
4929 }
4930 }
4931}
4932
4933pub(crate) trait VecPreOrderInsertionHelper<T> {
4936 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
4937}
4938
4939impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
4940where
4941 T: DerivedFrom<Node> + DomObject,
4942{
4943 fn insert_pre_order(&mut self, node: &T, tree_root: &Node) {
4948 let Err(insertion_index) = self.binary_search_by(|candidate| {
4949 candidate.upcast().compare_dom_tree_position(
4950 node.upcast(),
4951 tree_root,
4952 ShadowIncluding::No,
4953 )
4954 }) else {
4955 return;
4958 };
4959
4960 self.insert(insertion_index, Dom::from_ref(node));
4961 }
4962}