1use std::borrow::Cow;
8use std::cell::{Cell, LazyCell, UnsafeCell};
9use std::cmp::Ordering;
10use std::default::Default;
11use std::f64::consts::PI;
12use std::marker::PhantomData;
13use std::ops::Deref;
14use std::slice::from_ref;
15use std::{cmp, fmt, iter};
16
17use app_units::Au;
18use bitflags::bitflags;
19use devtools_traits::NodeInfo;
20use dom_struct::dom_struct;
21use embedder_traits::UntrustedNodeAddress;
22use euclid::default::Size2D;
23use euclid::{Point2D, Rect};
24use html5ever::serialize::HtmlSerializer;
25use html5ever::{Namespace, Prefix, QualName, ns, serialize as html_serialize};
26use js::context::{JSContext, NoGC};
27use js::jsapi::JSObject;
28use js::rust::HandleObject;
29use keyboard_types::Modifiers;
30use layout_api::{
31 AxesOverflow, BoxAreaType, CSSPixelRectIterator, GenericLayoutData, HTMLCanvasData,
32 HTMLMediaData, LayoutElementType, LayoutNodeType, NodeRenderingType, PhysicalSides,
33 SVGElementData, SharedSelection, TrustedNodeAddress, with_layout_state,
34};
35use libc::{self, c_void, uintptr_t};
36use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
37use net_traits::image_cache::Image;
38use pixels::ImageMetadata;
39use script_bindings::codegen::GenericBindings::EventBinding::EventMethods;
40use script_bindings::codegen::InheritTypes::DocumentFragmentTypeId;
41use script_traits::DocumentActivity;
42use servo_arc::Arc as ServoArc;
43use servo_base::id::{BrowsingContextId, PipelineId};
44use servo_config::pref;
45use servo_url::ServoUrl;
46use smallvec::SmallVec;
47use style::Atom;
48use style::context::QuirksMode;
49use style::dom::OpaqueNode;
50use style::dom_apis::{QueryAll, QueryFirst};
51use style::selector_parser::PseudoElement;
52use style::stylesheets::Stylesheet;
53use style_traits::CSSPixel;
54use uuid::Uuid;
55use xml5ever::{local_name, serialize as xml_serialize};
56
57use crate::conversions::Convert;
58use crate::document_loader::DocumentLoader;
59use crate::dom::attr::Attr;
60use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
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::reflector::{
87 DomObject, DomObjectWrap, reflect_dom_object_with_proto_and_cx,
88};
89use crate::dom::bindings::root::{
90 Dom, DomRoot, DomSlice, LayoutDom, MutNullableDom, ToLayout, UnrootedDom,
91};
92use crate::dom::bindings::str::{DOMString, USVString};
93use crate::dom::characterdata::CharacterData;
94use crate::dom::css::cssstylesheet::CSSStyleSheet;
95use crate::dom::css::stylesheetlist::StyleSheetListOwner;
96use crate::dom::customelementregistry::{
97 CallbackReaction, CustomElementRegistry, try_upgrade_element,
98};
99use crate::dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
100use crate::dom::documentfragment::DocumentFragment;
101use crate::dom::documenttype::DocumentType;
102use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
103use crate::dom::event::{Event, EventBubbles, EventCancelable, EventFlags};
104use crate::dom::eventtarget::EventTarget;
105use crate::dom::globalscope::GlobalScope;
106use crate::dom::html::htmlcanvaselement::HTMLCanvasElement;
107use crate::dom::html::htmlcollection::HTMLCollection;
108use crate::dom::html::htmlelement::HTMLElement;
109use crate::dom::html::htmliframeelement::HTMLIFrameElement;
110use crate::dom::html::htmlimageelement::HTMLImageElement;
111use crate::dom::html::htmllinkelement::HTMLLinkElement;
112use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
113use crate::dom::html::htmlstyleelement::HTMLStyleElement;
114use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
115use crate::dom::html::htmlvideoelement::HTMLVideoElement;
116use crate::dom::html::input_element::HTMLInputElement;
117use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
118use crate::dom::node::nodelist::NodeList;
119use crate::dom::pointerevent::{PointerEvent, PointerId};
120use crate::dom::processinginstruction::ProcessingInstruction;
121use crate::dom::range::WeakRangeVec;
122use crate::dom::raredata::NodeRareData;
123use crate::dom::servoparser::html::HtmlSerialize;
124use crate::dom::servoparser::{ServoParser, serialize_html_fragment};
125use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
126use crate::dom::svg::svgsvgelement::SVGSVGElement;
127use crate::dom::text::Text;
128use crate::dom::types::{CDATASection, KeyboardEvent};
129use crate::dom::virtualmethods::{VirtualMethods, vtable_for};
130use crate::dom::window::Window;
131use crate::layout_dom::{ServoDangerousStyleElement, ServoDangerousStyleNode};
132use crate::script_runtime::CanGc;
133use crate::script_thread::ScriptThread;
134
135#[dom_struct]
141pub struct Node {
142 eventtarget: EventTarget,
144
145 parent_node: MutNullableDom<Node>,
147
148 first_child: MutNullableDom<Node>,
150
151 last_child: MutNullableDom<Node>,
153
154 next_sibling: MutNullableDom<Node>,
156
157 prev_sibling: MutNullableDom<Node>,
159
160 owner_doc: MutNullableDom<Document>,
162
163 rare_data: DomRefCell<Option<Box<NodeRareData>>>,
165
166 children_count: Cell<u32>,
168
169 flags: Cell<NodeFlags>,
171
172 inclusive_descendants_version: Cell<u64>,
174
175 #[no_trace]
178 layout_data: DomRefCell<Option<Box<GenericLayoutData>>>,
179}
180
181impl fmt::Debug for Node {
182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 if matches!(self.type_id(), NodeTypeId::Element(_)) {
184 let el = self.downcast::<Element>().unwrap();
185 el.fmt(f)
186 } else {
187 write!(f, "[Node({:?})]", self.type_id())
188 }
189 }
190}
191
192#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
194pub(crate) struct NodeFlags(u16);
195
196bitflags! {
197 impl NodeFlags: u16 {
198 const IS_IN_A_DOCUMENT_TREE = 1 << 0;
202
203 const HAS_DIRTY_DESCENDANTS = 1 << 1;
205
206 const CLICK_IN_PROGRESS = 1 << 2;
209
210 const PARSER_ASSOCIATED_FORM_OWNER = 1 << 6;
215
216 const HAS_SNAPSHOT = 1 << 7;
221
222 const HANDLED_SNAPSHOT = 1 << 8;
224
225 const IS_IN_SHADOW_TREE = 1 << 9;
227
228 const IS_CONNECTED = 1 << 10;
232
233 const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
236
237 const IS_IN_UA_WIDGET = 1 << 12;
240
241 const USES_ATTR_IN_CONTENT_ATTRIBUTE = 1 << 13;
243 }
244}
245
246#[derive(Clone, Copy, MallocSizeOf)]
250enum SuppressObserver {
251 Suppressed,
252 Unsuppressed,
253}
254
255pub(crate) enum ForceSlottableNodeReconciliation {
256 Force,
257 Skip,
258}
259
260impl Node {
261 fn add_child(&self, cx: &mut JSContext, new_child: &Node, before: Option<&Node>) {
265 assert!(new_child.parent_node.get().is_none());
266 assert!(new_child.prev_sibling.get().is_none());
267 assert!(new_child.next_sibling.get().is_none());
268 match before {
269 Some(before) => {
270 assert!(before.parent_node.get().as_deref() == Some(self));
271 let prev_sibling = before.GetPreviousSibling();
272 match prev_sibling {
273 None => {
274 assert!(self.first_child.get().as_deref() == Some(before));
275 self.first_child.set(Some(new_child));
276 },
277 Some(ref prev_sibling) => {
278 prev_sibling.next_sibling.set(Some(new_child));
279 new_child.prev_sibling.set(Some(prev_sibling));
280 },
281 }
282 before.prev_sibling.set(Some(new_child));
283 new_child.next_sibling.set(Some(before));
284 },
285 None => {
286 let last_child = self.GetLastChild();
287 match last_child {
288 None => self.first_child.set(Some(new_child)),
289 Some(ref last_child) => {
290 assert!(last_child.next_sibling.get().is_none());
291 last_child.next_sibling.set(Some(new_child));
292 new_child.prev_sibling.set(Some(last_child));
293 },
294 }
295
296 self.last_child.set(Some(new_child));
297 },
298 }
299
300 new_child.parent_node.set(Some(self));
301 self.children_count.set(self.children_count.get() + 1);
302
303 let parent_is_in_a_document_tree = self.is_in_a_document_tree();
304 let parent_in_shadow_tree = self.is_in_a_shadow_tree();
305 let parent_is_connected = self.is_connected();
306 let parent_is_in_ua_widget = self.is_in_ua_widget();
307
308 let context = BindContext::new(self, IsShadowTree::No);
309
310 for node in new_child.traverse_preorder(ShadowIncluding::No) {
311 if parent_in_shadow_tree {
312 if let Some(shadow_root) = self.containing_shadow_root() {
313 node.set_containing_shadow_root(Some(&*shadow_root));
314 }
315 debug_assert!(node.containing_shadow_root().is_some());
316 }
317 node.set_flag(
318 NodeFlags::IS_IN_A_DOCUMENT_TREE,
319 parent_is_in_a_document_tree,
320 );
321 node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, parent_in_shadow_tree);
322 node.set_flag(NodeFlags::IS_CONNECTED, parent_is_connected);
323 node.set_flag(NodeFlags::IS_IN_UA_WIDGET, parent_is_in_ua_widget);
324
325 debug_assert!(!node.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS));
327 vtable_for(&node).bind_to_tree(cx, &context);
328 }
329 }
330
331 pub(crate) fn unsafely_set_html(
334 target: &Node,
335 context_element: &Element,
336 html: DOMString,
337 cx: &mut JSContext,
338 ) {
339 let new_children = ServoParser::parse_html_fragment(context_element, html, true, cx);
341
342 let context_document = context_element.owner_document();
345 let fragment = DocumentFragment::new(cx, &context_document);
346
347 for child in new_children {
349 fragment.upcast::<Node>().AppendChild(cx, &child).unwrap();
350 }
351
352 Node::replace_all(cx, Some(fragment.upcast()), target);
354 }
355
356 pub(crate) fn remove_style_and_layout_data_from_subtree(&self, no_gc: &NoGC) {
360 for node in self.traverse_preorder_non_rooting(no_gc, ShadowIncluding::Yes) {
361 node.clean_up_style_and_layout_data();
362 }
363 }
364
365 fn clean_up_style_and_layout_data(&self) {
366 self.layout_data.borrow_mut().take();
367 if let Some(element) = self.downcast::<Element>() {
368 element.clean_up_style_data();
369 }
370 }
371
372 pub(crate) fn complete_remove_subtree(
375 cx: &mut JSContext,
376 root: &Node,
377 context: &UnbindContext,
378 ) {
379 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
381 .union(NodeFlags::IS_CONNECTED)
382 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
383 .union(NodeFlags::HAS_SNAPSHOT)
384 .union(NodeFlags::HANDLED_SNAPSHOT);
385
386 for node in root.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No) {
387 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
388
389 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
392 for node in shadow_root
393 .upcast::<Node>()
394 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
395 {
396 node.set_flag(RESET_FLAGS, false);
397 }
398 }
399 }
400
401 let is_parent_connected = context.parent.is_connected();
403 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
404
405 let cleanup_node = |cx: &mut JSContext, node: &Node| {
408 node.owner_doc().cancel_animations_for_node(node);
409 node.clean_up_style_and_layout_data();
410
411 vtable_for(node).unbind_from_tree(cx, context);
416
417 if is_parent_connected {
419 if let Some(element) = node.as_custom_element() {
420 custom_element_reaction_stack.enqueue_callback_reaction(
421 &element,
422 CallbackReaction::Disconnected,
423 None,
424 );
425 }
426 }
427 };
428
429 for node in root.traverse_preorder(ShadowIncluding::No) {
430 cleanup_node(cx, &node);
431
432 if node.containing_shadow_root().is_some() {
435 node.set_containing_shadow_root(None);
438 }
439
440 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
443 for node in shadow_root
444 .upcast::<Node>()
445 .traverse_preorder(ShadowIncluding::Yes)
446 {
447 cleanup_node(cx, &node);
448 }
449 }
450 }
451 }
452
453 pub(crate) fn complete_move_subtree(root: &Node) {
454 const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_A_DOCUMENT_TREE
456 .union(NodeFlags::IS_CONNECTED)
457 .union(NodeFlags::HAS_DIRTY_DESCENDANTS)
458 .union(NodeFlags::HAS_SNAPSHOT)
459 .union(NodeFlags::HANDLED_SNAPSHOT);
460
461 for node in root.traverse_preorder(ShadowIncluding::No) {
462 node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false);
463 node.clean_up_style_and_layout_data();
464
465 if node.containing_shadow_root().is_some() {
468 node.set_containing_shadow_root(None);
471 }
472
473 if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) {
477 for node in shadow_root
478 .upcast::<Node>()
479 .traverse_preorder(ShadowIncluding::Yes)
480 {
481 node.set_flag(RESET_FLAGS, false);
482 node.clean_up_style_and_layout_data();
483 }
484 }
485 }
486 }
487
488 fn remove_child(&self, cx: &mut JSContext, child: &Node, cached_index: Option<u32>) {
492 assert!(child.parent_node.get().as_deref() == Some(self));
493 self.note_dirty_descendants();
494
495 let prev_sibling = child.GetPreviousSibling();
496 match prev_sibling {
497 None => {
498 self.first_child.set(child.next_sibling.get().as_deref());
499 },
500 Some(ref prev_sibling) => {
501 prev_sibling
502 .next_sibling
503 .set(child.next_sibling.get().as_deref());
504 },
505 }
506 let next_sibling = child.GetNextSibling();
507 match next_sibling {
508 None => {
509 self.last_child.set(child.prev_sibling.get().as_deref());
510 },
511 Some(ref next_sibling) => {
512 next_sibling
513 .prev_sibling
514 .set(child.prev_sibling.get().as_deref());
515 },
516 }
517
518 let context = UnbindContext::new(
519 self,
520 prev_sibling.as_deref(),
521 next_sibling.as_deref(),
522 cached_index,
523 );
524
525 child.prev_sibling.set(None);
526 child.next_sibling.set(None);
527 child.parent_node.set(None);
528 self.children_count.set(self.children_count.get() - 1);
529
530 Self::complete_remove_subtree(cx, child, &context);
531 }
532
533 fn move_child(&self, child: &Node) {
534 assert!(child.parent_node.get().as_deref() == Some(self));
535 self.note_dirty_descendants();
536
537 child.prev_sibling.set(None);
538 child.next_sibling.set(None);
539 child.parent_node.set(None);
540 self.children_count.set(self.children_count.get() - 1);
541 Self::complete_move_subtree(child)
542 }
543
544 pub(crate) fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
545 UntrustedNodeAddress(self.reflector().get_jsobject().get() as *const c_void)
546 }
547
548 pub(crate) fn to_opaque(&self) -> OpaqueNode {
549 OpaqueNode(self.reflector().get_jsobject().get() as usize)
550 }
551
552 pub(crate) fn as_custom_element(&self) -> Option<DomRoot<Element>> {
553 self.downcast::<Element>().and_then(|element| {
554 if element.is_custom() {
555 assert!(element.get_custom_element_definition().is_some());
556 Some(DomRoot::from_ref(element))
557 } else {
558 None
559 }
560 })
561 }
562
563 pub(crate) fn fire_synthetic_pointer_event_not_trusted(&self, event_type: Atom, can_gc: CanGc) {
565 let window = self.owner_window();
569
570 let pointer_event = PointerEvent::new(
572 &window, event_type,
574 EventBubbles::Bubbles, EventCancelable::Cancelable, Some(&window), 0, Point2D::zero(), Point2D::zero(), Point2D::zero(), Modifiers::empty(), 0, 0, None, None, PointerId::NonPointerDevice as i32, 1, 1, 0.5, 0.0, 0, 0, 0, PI / 2.0, 0.0, DOMString::from(""), false, vec![], vec![], can_gc,
601 );
602
603 pointer_event.upcast::<Event>().set_composed(true);
605
606 pointer_event.upcast::<Event>().set_trusted(false);
608
609 pointer_event
612 .upcast::<Event>()
613 .dispatch(self.upcast::<EventTarget>(), false, can_gc);
614 }
615
616 pub(crate) fn parent_directionality(&self) -> String {
617 let mut current = self.GetParentNode();
618
619 loop {
620 match current {
621 Some(node) => {
622 if let Some(directionality) = node
623 .downcast::<HTMLElement>()
624 .and_then(|html_element| html_element.directionality())
625 {
626 return directionality;
627 } else {
628 current = node.GetParentNode();
629 }
630 },
631 None => return "ltr".to_owned(),
632 }
633 }
634 }
635
636 pub(crate) fn is_being_rendered_or_delegates_rendering(
640 &self,
641 pseudo_element: Option<PseudoElement>,
642 ) -> bool {
643 matches!(
644 self.owner_window()
645 .layout()
646 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
647 NodeRenderingType::Rendered | NodeRenderingType::DelegatesRendering
648 )
649 }
650
651 pub(crate) fn is_being_rendered(&self, pseudo_element: Option<PseudoElement>) -> bool {
653 matches!(
654 self.owner_window()
655 .layout()
656 .node_rendering_type(self.to_trusted_node_address(), pseudo_element),
657 NodeRenderingType::Rendered
658 )
659 }
660}
661
662impl Node {
663 fn rare_data(&self) -> Ref<'_, Option<Box<NodeRareData>>> {
664 self.rare_data.borrow()
665 }
666
667 fn ensure_rare_data(&self) -> RefMut<'_, Box<NodeRareData>> {
668 let mut rare_data = self.rare_data.borrow_mut();
669 if rare_data.is_none() {
670 *rare_data = Some(Default::default());
671 }
672 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
673 }
674
675 pub(crate) fn is_before(&self, other: &Node) -> bool {
678 let cmp = other.CompareDocumentPosition(self);
679 if cmp & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
680 return false;
681 }
682
683 cmp & NodeConstants::DOCUMENT_POSITION_PRECEDING != 0
684 }
685
686 pub(crate) fn registered_mutation_observers_mut(&self) -> RefMut<'_, Vec<RegisteredObserver>> {
689 RefMut::map(self.ensure_rare_data(), |rare_data| {
690 &mut rare_data.mutation_observers
691 })
692 }
693
694 pub(crate) fn registered_mutation_observers(&self) -> Option<Ref<'_, Vec<RegisteredObserver>>> {
695 let rare_data: Ref<'_, _> = self.rare_data.borrow();
696
697 if rare_data.is_none() {
698 return None;
699 }
700 Some(Ref::map(rare_data, |rare_data| {
701 &rare_data.as_ref().unwrap().mutation_observers
702 }))
703 }
704
705 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
707 pub(crate) fn add_mutation_observer(&self, observer: RegisteredObserver) {
708 self.ensure_rare_data().mutation_observers.push(observer);
709 }
710
711 pub(crate) fn remove_mutation_observer(&self, observer: &MutationObserver) {
713 self.ensure_rare_data()
714 .mutation_observers
715 .retain(|reg_obs| &*reg_obs.observer != observer)
716 }
717
718 pub(crate) fn dump(&self) {
720 self.dump_indent(0);
721 }
722
723 pub(crate) fn dump_indent(&self, indent: u32) {
725 let mut s = String::new();
726 for _ in 0..indent {
727 s.push_str(" ");
728 }
729
730 s.push_str(&self.debug_str());
731 debug!("{:?}", s);
732
733 for kid in self.children() {
735 kid.dump_indent(indent + 1)
736 }
737 }
738
739 pub(crate) fn debug_str(&self) -> String {
741 format!("{:?}", self.type_id())
742 }
743
744 pub(crate) fn is_in_a_document_tree(&self) -> bool {
746 self.flags.get().contains(NodeFlags::IS_IN_A_DOCUMENT_TREE)
747 }
748
749 pub(crate) fn is_in_a_shadow_tree(&self) -> bool {
751 self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
752 }
753
754 pub(crate) fn has_weird_parser_insertion_mode(&self) -> bool {
755 self.flags
756 .get()
757 .contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
758 }
759
760 pub(crate) fn set_weird_parser_insertion_mode(&self) {
761 self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
762 }
763
764 pub(crate) fn is_connected(&self) -> bool {
766 self.flags.get().contains(NodeFlags::IS_CONNECTED)
767 }
768
769 pub(crate) fn set_in_ua_widget(&self, in_ua_widget: bool) {
770 self.set_flag(NodeFlags::IS_IN_UA_WIDGET, in_ua_widget)
771 }
772
773 pub(crate) fn is_in_ua_widget(&self) -> bool {
774 self.flags.get().contains(NodeFlags::IS_IN_UA_WIDGET)
775 }
776
777 pub(crate) fn type_id(&self) -> NodeTypeId {
779 match *self.eventtarget.type_id() {
780 EventTargetTypeId::Node(type_id) => type_id,
781 _ => unreachable!(),
782 }
783 }
784
785 pub(crate) fn len(&self) -> u32 {
787 match self.type_id() {
788 NodeTypeId::DocumentType => 0,
789 NodeTypeId::CharacterData(_) => self.downcast::<CharacterData>().unwrap().Length(),
790 _ => self.children_count(),
791 }
792 }
793
794 pub(crate) fn is_empty(&self) -> bool {
795 self.len() == 0
797 }
798
799 pub(crate) fn index(&self) -> u32 {
801 self.preceding_siblings().count() as u32
802 }
803
804 pub(crate) fn has_parent(&self) -> bool {
806 self.parent_node.get().is_some()
807 }
808
809 pub(crate) fn children_count(&self) -> u32 {
810 self.children_count.get()
811 }
812
813 pub(crate) fn ranges(&self) -> RefMut<'_, WeakRangeVec> {
814 RefMut::map(self.ensure_rare_data(), |rare_data| &mut rare_data.ranges)
815 }
816
817 pub(crate) fn ranges_is_empty(&self) -> bool {
818 self.rare_data()
819 .as_ref()
820 .is_none_or(|data| data.ranges.is_empty())
821 }
822
823 #[inline]
824 pub(crate) fn is_doctype(&self) -> bool {
825 self.type_id() == NodeTypeId::DocumentType
826 }
827
828 pub(crate) fn get_flag(&self, flag: NodeFlags) -> bool {
829 self.flags.get().contains(flag)
830 }
831
832 pub(crate) fn set_flag(&self, flag: NodeFlags, value: bool) {
833 let mut flags = self.flags.get();
834
835 if value {
836 flags.insert(flag);
837 } else {
838 flags.remove(flag);
839 }
840
841 self.flags.set(flags);
842 }
843
844 pub(crate) fn note_dirty_descendants(&self) {
846 self.owner_doc().note_node_with_dirty_descendants(self);
847 }
848
849 pub(crate) fn has_dirty_descendants(&self) -> bool {
850 self.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)
851 }
852
853 pub(crate) fn rev_version(&self) {
854 let doc: DomRoot<Node> = DomRoot::upcast(self.owner_doc());
859 let version = cmp::max(
860 self.inclusive_descendants_version(),
861 doc.inclusive_descendants_version(),
862 ) + 1;
863
864 let mut node = &MutNullableDom::new(Some(self));
867 while let Some(p) = node.if_is_some(|p| {
868 p.inclusive_descendants_version.set(version);
869 &p.parent_node
870 }) {
871 node = p
872 }
873 doc.inclusive_descendants_version.set(version);
874 }
875
876 pub(crate) fn dirty(&self, damage: NodeDamage) {
877 self.rev_version();
878 if !self.is_connected() {
879 return;
880 }
881
882 match self.type_id() {
883 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
884 self.parent_node
888 .get()
889 .unwrap()
890 .dirty(NodeDamage::ContentOrHeritage)
891 },
892 NodeTypeId::Element(_) => self.downcast::<Element>().unwrap().restyle(damage),
893 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => self
894 .downcast::<ShadowRoot>()
895 .unwrap()
896 .Host()
897 .upcast::<Element>()
898 .restyle(damage),
899 _ => {},
900 };
901 }
902
903 pub(crate) fn inclusive_descendants_version(&self) -> u64 {
905 self.inclusive_descendants_version.get()
906 }
907
908 pub(crate) fn traverse_preorder(&self, shadow_including: ShadowIncluding) -> TreeIterator {
910 TreeIterator::new(self, shadow_including)
911 }
912
913 pub(crate) fn traverse_preorder_non_rooting<'a, 'b>(
915 &'a self,
916 no_gc: &'b NoGC,
917 shadow_including: ShadowIncluding,
918 ) -> UnrootedTreeIterator<'a, 'b>
919 where
920 'b: 'a,
921 {
922 UnrootedTreeIterator::new(self, shadow_including, no_gc)
923 }
924
925 pub(crate) fn inclusively_following_siblings(
926 &self,
927 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
928 SimpleNodeIterator {
929 current: Some(DomRoot::from_ref(self)),
930 next_node: |n| n.GetNextSibling(),
931 }
932 }
933
934 pub(crate) fn inclusively_following_siblings_unrooted<'b>(
935 &self,
936 no_gc: &'b NoGC,
937 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
938 UnrootedSimpleNodeIterator {
939 current: Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
940 next_node: |n, no_gc| n.get_next_sibling_unrooted(no_gc),
941 no_gc,
942 phantom: PhantomData,
943 }
944 }
945
946 pub(crate) fn inclusively_preceding_siblings(
947 &self,
948 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
949 SimpleNodeIterator {
950 current: Some(DomRoot::from_ref(self)),
951 next_node: |n| n.GetPreviousSibling(),
952 }
953 }
954
955 pub(crate) fn inclusively_preceding_siblings_unrooted<'b>(
956 &self,
957 no_gc: &'b NoGC,
958 ) -> impl Iterator<Item = UnrootedDom<'b, Node>> + use<'b> {
959 UnrootedSimpleNodeIterator {
960 current: Some(UnrootedDom::from_dom(Dom::from_ref(self), no_gc)),
961 next_node: |n, no_gc| n.get_previous_sibling_unrooted(no_gc),
962 no_gc,
963 phantom: PhantomData,
964 }
965 }
966
967 pub(crate) fn common_ancestor(
968 &self,
969 other: &Node,
970 shadow_including: ShadowIncluding,
971 ) -> Option<DomRoot<Node>> {
972 self.inclusive_ancestors(shadow_including).find(|ancestor| {
973 other
974 .inclusive_ancestors(shadow_including)
975 .any(|node| node == *ancestor)
976 })
977 }
978
979 pub(crate) fn common_ancestor_in_flat_tree(&self, other: &Node) -> Option<DomRoot<Node>> {
980 self.inclusive_ancestors_in_flat_tree().find(|ancestor| {
981 other
982 .inclusive_ancestors_in_flat_tree()
983 .any(|node| node == *ancestor)
984 })
985 }
986
987 pub(crate) fn is_inclusive_ancestor_of(&self, child: &Node) -> bool {
989 self == child || self.is_ancestor_of(child)
991 }
992
993 pub(crate) fn is_ancestor_of(&self, possible_descendant: &Node) -> bool {
995 let mut current = &possible_descendant.parent_node;
997 let mut done = false;
998
999 while let Some(node) = current.if_is_some(|node| {
1000 done = node == self;
1001 &node.parent_node
1002 }) {
1003 if done {
1004 break;
1005 }
1006 current = node
1007 }
1008 done
1009 }
1010
1011 fn is_host_including_inclusive_ancestor(&self, child: &Node) -> bool {
1013 self.is_inclusive_ancestor_of(child) ||
1016 child
1017 .GetRootNode(&GetRootNodeOptions::empty())
1018 .downcast::<DocumentFragment>()
1019 .and_then(|fragment| fragment.host())
1020 .is_some_and(|host| self.is_host_including_inclusive_ancestor(host.upcast()))
1021 }
1022
1023 pub(crate) fn is_shadow_including_inclusive_ancestor_of(&self, node: &Node) -> bool {
1025 node.inclusive_ancestors(ShadowIncluding::Yes)
1026 .any(|ancestor| &*ancestor == self)
1027 }
1028
1029 pub(crate) fn following_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1030 SimpleNodeIterator {
1031 current: self.GetNextSibling(),
1032 next_node: |n| n.GetNextSibling(),
1033 }
1034 }
1035
1036 pub(crate) fn preceding_siblings(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1037 SimpleNodeIterator {
1038 current: self.GetPreviousSibling(),
1039 next_node: |n| n.GetPreviousSibling(),
1040 }
1041 }
1042
1043 pub(crate) fn following_nodes(&self, root: &Node) -> FollowingNodeIterator {
1044 FollowingNodeIterator {
1045 current: Some(DomRoot::from_ref(self)),
1046 root: DomRoot::from_ref(root),
1047 }
1048 }
1049
1050 pub(crate) fn preceding_nodes(&self, root: &Node) -> PrecedingNodeIterator {
1051 PrecedingNodeIterator {
1052 current: Some(DomRoot::from_ref(self)),
1053 root: DomRoot::from_ref(root),
1054 }
1055 }
1056
1057 pub(crate) fn descending_last_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1060 SimpleNodeIterator {
1061 current: self.GetLastChild(),
1062 next_node: |n| n.GetLastChild(),
1063 }
1064 }
1065
1066 pub(crate) fn is_parent_of(&self, child: &Node) -> bool {
1067 child
1068 .parent_node
1069 .get()
1070 .is_some_and(|parent| &*parent == self)
1071 }
1072
1073 pub(crate) fn to_trusted_node_address(&self) -> TrustedNodeAddress {
1074 TrustedNodeAddress(self as *const Node as *const libc::c_void)
1075 }
1076
1077 pub(crate) fn containing_block_node_without_reflow(&self) -> Option<DomRoot<Node>> {
1079 self.owner_window()
1080 .containing_block_node_query_without_reflow(self)
1081 }
1082
1083 pub(crate) fn padding(&self) -> Option<PhysicalSides> {
1084 self.owner_window().padding_query_without_reflow(self)
1085 }
1086
1087 pub(crate) fn content_box(&self) -> Option<Rect<Au, CSSPixel>> {
1088 self.owner_window()
1089 .box_area_query(self, BoxAreaType::Content, false)
1090 }
1091
1092 pub(crate) fn border_box(&self) -> Option<Rect<Au, CSSPixel>> {
1093 self.owner_window()
1094 .box_area_query(self, BoxAreaType::Border, false)
1095 }
1096
1097 pub(crate) fn border_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1098 self.owner_window()
1099 .box_area_query_without_reflow(self, BoxAreaType::Border, false)
1100 }
1101
1102 pub(crate) fn padding_box(&self) -> Option<Rect<Au, CSSPixel>> {
1103 self.owner_window()
1104 .box_area_query(self, BoxAreaType::Padding, false)
1105 }
1106
1107 pub(crate) fn padding_box_without_reflow(&self) -> Option<Rect<Au, CSSPixel>> {
1108 self.owner_window()
1109 .box_area_query_without_reflow(self, BoxAreaType::Padding, false)
1110 }
1111
1112 pub(crate) fn border_boxes(&self) -> CSSPixelRectIterator {
1113 self.owner_window()
1114 .box_areas_query(self, BoxAreaType::Border)
1115 }
1116
1117 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
1118 self.owner_window().client_rect_query(self)
1119 }
1120
1121 pub(crate) fn scroll_area(&self) -> Rect<i32, CSSPixel> {
1124 let document = self.owner_doc();
1126
1127 if !document.is_active() {
1129 return Rect::zero();
1130 }
1131
1132 let window = document.window();
1135 let viewport = Size2D::new(window.InnerWidth(), window.InnerHeight()).cast_unit();
1136
1137 let in_quirks_mode = document.quirks_mode() == QuirksMode::Quirks;
1138 let is_root = self.downcast::<Element>().is_some_and(|e| e.is_root());
1139 let is_body_element = self
1140 .downcast::<HTMLElement>()
1141 .is_some_and(|e| e.is_body_element());
1142
1143 if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) {
1149 let viewport_scrolling_area = window.scrolling_area_query(None);
1150 return Rect::new(
1151 viewport_scrolling_area.origin,
1152 viewport_scrolling_area.size.max(viewport),
1153 );
1154 }
1155
1156 window.scrolling_area_query(Some(self))
1160 }
1161
1162 pub(crate) fn effective_overflow(&self) -> Option<AxesOverflow> {
1163 self.owner_window().query_effective_overflow(self)
1164 }
1165
1166 pub(crate) fn effective_overflow_without_reflow(&self) -> Option<AxesOverflow> {
1167 self.owner_window()
1168 .query_effective_overflow_without_reflow(self)
1169 }
1170
1171 pub(crate) fn before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1173 let parent = &self.parent_node;
1175
1176 let parent = match parent.get() {
1178 None => return Ok(()),
1179 Some(parent) => parent,
1180 };
1181
1182 let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes);
1184
1185 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1187
1188 let viable_previous_sibling = match viable_previous_sibling {
1190 Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(),
1191 None => parent.first_child.get(),
1192 };
1193
1194 Node::pre_insert(cx, &node, &parent, viable_previous_sibling.as_deref())?;
1196
1197 Ok(())
1198 }
1199
1200 pub(crate) fn after(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1202 let parent = &self.parent_node;
1204
1205 let parent = match parent.get() {
1207 None => return Ok(()),
1208 Some(parent) => parent,
1209 };
1210
1211 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1213
1214 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1216
1217 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1219
1220 Ok(())
1221 }
1222
1223 pub(crate) fn replace_with(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1225 let Some(parent) = self.GetParentNode() else {
1227 return Ok(());
1229 };
1230
1231 let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
1233
1234 let node = self.owner_doc().node_from_nodes_and_strings(cx, nodes)?;
1236
1237 if self.parent_node == Some(&*parent) {
1238 parent.ReplaceChild(cx, &node, self)?;
1240 } else {
1241 Node::pre_insert(cx, &node, &parent, viable_next_sibling.as_deref())?;
1243 }
1244 Ok(())
1245 }
1246
1247 pub(crate) fn prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1249 let doc = self.owner_doc();
1251 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1252 let first_child = self.first_child.get();
1254 Node::pre_insert(cx, &node, self, first_child.as_deref()).map(|_| ())
1255 }
1256
1257 pub(crate) fn append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
1259 let doc = self.owner_doc();
1261 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1262 self.AppendChild(cx, &node).map(|_| ())
1264 }
1265
1266 pub(crate) fn replace_children(
1268 &self,
1269 cx: &mut JSContext,
1270 nodes: Vec<NodeOrString>,
1271 ) -> ErrorResult {
1272 let doc = self.owner_doc();
1275 let node = doc.node_from_nodes_and_strings(cx, nodes)?;
1276
1277 Node::ensure_pre_insertion_validity(cx.no_gc(), &node, self, None)?;
1279
1280 Node::replace_all(cx, Some(&node), self);
1282 Ok(())
1283 }
1284
1285 pub(crate) fn move_before(
1287 &self,
1288 cx: &mut JSContext,
1289 node: &Node,
1290 child: Option<&Node>,
1291 ) -> ErrorResult {
1292 let reference_child_root;
1295 let reference_child = match child {
1296 Some(child) if child == node => {
1297 reference_child_root = node.GetNextSibling();
1298 reference_child_root.as_deref()
1299 },
1300 _ => child,
1301 };
1302
1303 Node::move_fn(cx, node, self, reference_child)
1305 }
1306
1307 fn move_fn(
1309 cx: &mut JSContext,
1310 node: &Node,
1311 new_parent: &Node,
1312 child: Option<&Node>,
1313 ) -> ErrorResult {
1314 let mut options = GetRootNodeOptions::empty();
1319 options.composed = true;
1320 if new_parent.GetRootNode(&options) != node.GetRootNode(&options) {
1321 return Err(Error::HierarchyRequest(None));
1322 }
1323
1324 if node.is_inclusive_ancestor_of(new_parent) {
1327 return Err(Error::HierarchyRequest(None));
1328 }
1329
1330 if let Some(child) = child {
1333 if !new_parent.is_parent_of(child) {
1334 return Err(Error::NotFound(None));
1335 }
1336 }
1337
1338 match node.type_id() {
1343 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1344 if new_parent.is::<Document>() {
1345 return Err(Error::HierarchyRequest(None));
1346 }
1347 },
1348 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1349 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1350 NodeTypeId::Element(_) => (),
1351 NodeTypeId::DocumentFragment(_) |
1352 NodeTypeId::DocumentType |
1353 NodeTypeId::Document(_) |
1354 NodeTypeId::Attr => {
1355 return Err(Error::HierarchyRequest(None));
1356 },
1357 }
1358
1359 if new_parent.is::<Document>() && node.is::<Element>() {
1363 if new_parent.child_elements().next().is_some() {
1365 return Err(Error::HierarchyRequest(None));
1366 }
1367
1368 if child.is_some_and(|child| {
1371 child
1372 .inclusively_following_siblings_unrooted(cx.no_gc())
1373 .any(|child| child.is_doctype())
1374 }) {
1375 return Err(Error::HierarchyRequest(None));
1376 }
1377 }
1378
1379 let old_parent = node
1382 .parent_node
1383 .get()
1384 .expect("old_parent should always be initialized");
1385
1386 let cached_index = Node::live_range_pre_remove_steps(node, &old_parent);
1388
1389 let old_previous_sibling = node.prev_sibling.get();
1394
1395 let old_next_sibling = node.next_sibling.get();
1397
1398 let prev_sibling = node.GetPreviousSibling();
1399 match prev_sibling {
1400 None => {
1401 old_parent
1402 .first_child
1403 .set(node.next_sibling.get().as_deref());
1404 },
1405 Some(ref prev_sibling) => {
1406 prev_sibling
1407 .next_sibling
1408 .set(node.next_sibling.get().as_deref());
1409 },
1410 }
1411 let next_sibling = node.GetNextSibling();
1412 match next_sibling {
1413 None => {
1414 old_parent
1415 .last_child
1416 .set(node.prev_sibling.get().as_deref());
1417 },
1418 Some(ref next_sibling) => {
1419 next_sibling
1420 .prev_sibling
1421 .set(node.prev_sibling.get().as_deref());
1422 },
1423 }
1424
1425 let mut context = MoveContext::new(
1426 Some(&old_parent),
1427 prev_sibling.as_deref(),
1428 next_sibling.as_deref(),
1429 cached_index,
1430 );
1431
1432 old_parent.move_child(node);
1434
1435 if let Some(slot) = node.assigned_slot() {
1437 slot.assign_slottables();
1438 }
1439
1440 if old_parent.is_in_a_shadow_tree() {
1443 if let Some(slot_element) = old_parent.downcast::<HTMLSlotElement>() {
1444 if !slot_element.has_assigned_nodes() {
1445 slot_element.signal_a_slot_change();
1446 }
1447 }
1448 }
1449
1450 let has_slot_descendant = node
1452 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
1453 .any(|element| element.is::<HTMLSlotElement>());
1454 if has_slot_descendant {
1455 old_parent
1457 .GetRootNode(&GetRootNodeOptions::empty())
1458 .assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Skip);
1459
1460 node.assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Skip);
1462 }
1463
1464 if let Some(child) = child {
1466 new_parent
1471 .ranges()
1472 .increase_above(new_parent, child.index(), 1)
1473 }
1474
1475 let new_previous_sibling = child.map_or_else(
1478 || new_parent.last_child.get(),
1479 |child| child.prev_sibling.get(),
1480 );
1481
1482 new_parent.add_child(cx, node, child);
1485
1486 if let Some(shadow_root) = new_parent
1489 .downcast::<Element>()
1490 .and_then(Element::shadow_root)
1491 {
1492 if shadow_root.SlotAssignment() == SlotAssignmentMode::Named &&
1493 (node.is::<Element>() || node.is::<Text>())
1494 {
1495 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(node)));
1496 slottable.assign_a_slot();
1497 }
1498 }
1499
1500 if new_parent.is_in_a_shadow_tree() {
1503 if let Some(slot_element) = new_parent.downcast::<HTMLSlotElement>() {
1504 if !slot_element.has_assigned_nodes() {
1505 slot_element.signal_a_slot_change();
1506 }
1507 }
1508 }
1509
1510 node.GetRootNode(&GetRootNodeOptions::empty())
1512 .assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Skip);
1513
1514 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
1517 if descendant.deref() == node {
1521 vtable_for(&descendant).moving_steps(cx, &context);
1522 } else {
1523 context.old_parent = None;
1524 vtable_for(&descendant).moving_steps(cx, &context);
1525 }
1526
1527 if let Some(descendant) = descendant.downcast::<Element>() {
1529 if descendant.is_custom() && new_parent.is_connected() {
1530 let custom_element_reaction_stack =
1533 ScriptThread::custom_element_reaction_stack();
1534 custom_element_reaction_stack.enqueue_callback_reaction(
1535 descendant,
1536 CallbackReaction::ConnectedMove,
1537 None,
1538 );
1539 }
1540 }
1541 }
1542
1543 let moved = [node];
1546 let mutation = LazyCell::new(|| Mutation::ChildList {
1547 added: None,
1548 removed: Some(&moved),
1549 prev: old_previous_sibling.as_deref(),
1550 next: old_next_sibling.as_deref(),
1551 });
1552 MutationObserver::queue_a_mutation_record(&old_parent, mutation);
1553
1554 let mutation = LazyCell::new(|| Mutation::ChildList {
1557 added: Some(&moved),
1558 removed: None,
1559 prev: new_previous_sibling.as_deref(),
1560 next: child,
1561 });
1562 MutationObserver::queue_a_mutation_record(new_parent, mutation);
1563
1564 Ok(())
1565 }
1566
1567 #[allow(unsafe_code)]
1569 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1570 pub(crate) fn query_selector(
1571 &self,
1572 selectors: DOMString,
1573 ) -> Fallible<Option<DomRoot<Element>>> {
1574 let document_url = self.owner_document().url().get_arc();
1577
1578 let traced_node = Dom::from_ref(self);
1580
1581 let first_matching_element = with_layout_state(|| {
1582 let layout_node = unsafe { traced_node.to_layout() };
1583 ServoDangerousStyleNode::from(layout_node)
1584 .scope_match_a_selectors_string::<QueryFirst>(document_url, &selectors.str())
1585 })?;
1586
1587 Ok(first_matching_element.map(ServoDangerousStyleElement::rooted))
1588 }
1589
1590 #[allow(unsafe_code)]
1592 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
1593 pub(crate) fn query_selector_all(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
1594 let document_url = self.owner_document().url().get_arc();
1597
1598 let traced_node = Dom::from_ref(self);
1600 let matching_elements = with_layout_state(|| {
1601 let layout_node = unsafe { traced_node.to_layout() };
1602 ServoDangerousStyleNode::from(layout_node)
1603 .scope_match_a_selectors_string::<QueryAll>(document_url, &selectors.str())
1604 })?;
1605 let iter = matching_elements
1606 .into_iter()
1607 .map(ServoDangerousStyleElement::rooted)
1608 .map(DomRoot::upcast::<Node>);
1609
1610 Ok(NodeList::new_simple_list(
1613 &self.owner_window(),
1614 iter,
1615 CanGc::deprecated_note(),
1616 ))
1617 }
1618
1619 pub(crate) fn ancestors(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1620 SimpleNodeIterator {
1621 current: self.GetParentNode(),
1622 next_node: |n| n.GetParentNode(),
1623 }
1624 }
1625
1626 pub(crate) fn inclusive_ancestors(
1628 &self,
1629 shadow_including: ShadowIncluding,
1630 ) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1631 SimpleNodeIterator {
1632 current: Some(DomRoot::from_ref(self)),
1633 next_node: move |n| {
1634 if shadow_including == ShadowIncluding::Yes {
1635 if let Some(shadow_root) = n.downcast::<ShadowRoot>() {
1636 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
1637 }
1638 }
1639 n.GetParentNode()
1640 },
1641 }
1642 }
1643
1644 pub(crate) fn owner_doc(&self) -> DomRoot<Document> {
1645 self.owner_doc.get().unwrap()
1646 }
1647
1648 pub(crate) fn set_owner_doc(&self, document: &Document) {
1649 self.owner_doc.set(Some(document));
1650 }
1651
1652 pub(crate) fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
1653 self.rare_data()
1654 .as_ref()?
1655 .containing_shadow_root
1656 .as_ref()
1657 .map(|sr| DomRoot::from_ref(&**sr))
1658 }
1659
1660 pub(crate) fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) {
1661 self.ensure_rare_data().containing_shadow_root = shadow_root.map(Dom::from_ref);
1662 }
1663
1664 pub(crate) fn is_in_html_doc(&self) -> bool {
1665 self.owner_doc().is_html_document()
1666 }
1667
1668 pub(crate) fn is_connected_with_browsing_context(&self) -> bool {
1669 self.is_connected() && self.owner_doc().browsing_context().is_some()
1670 }
1671
1672 pub(crate) fn children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1673 SimpleNodeIterator {
1674 current: self.GetFirstChild(),
1675 next_node: |n| n.GetNextSibling(),
1676 }
1677 }
1678
1679 pub(crate) fn children_unrooted<'a>(
1680 &self,
1681 no_gc: &'a NoGC,
1682 ) -> impl Iterator<Item = UnrootedDom<'a, Node>> + use<'a> {
1683 UnrootedSimpleNodeIterator {
1684 current: self.get_first_child_unrooted(no_gc),
1685 next_node: |n, no_gc| n.get_next_sibling_unrooted(no_gc),
1686 no_gc,
1687 phantom: PhantomData,
1688 }
1689 }
1690
1691 pub(crate) fn rev_children(&self) -> impl Iterator<Item = DomRoot<Node>> + use<> {
1692 SimpleNodeIterator {
1693 current: self.GetLastChild(),
1694 next_node: |n| n.GetPreviousSibling(),
1695 }
1696 }
1697
1698 pub(crate) fn child_elements(&self) -> impl Iterator<Item = DomRoot<Element>> + use<> {
1700 self.children()
1701 .filter_map(DomRoot::downcast as fn(_) -> _)
1702 .peekable()
1703 }
1704
1705 pub(crate) fn child_elements_unrooted<'a>(
1706 &self,
1707 no_gc: &'a NoGC,
1708 ) -> impl Iterator<Item = UnrootedDom<'a, Element>> + use<'a> {
1709 self.children_unrooted(no_gc)
1710 .filter_map(UnrootedDom::downcast)
1711 .peekable()
1712 }
1713
1714 pub(crate) fn remove_self(&self, cx: &mut JSContext) {
1715 if let Some(ref parent) = self.GetParentNode() {
1716 Node::remove(cx, self, parent, SuppressObserver::Unsuppressed);
1717 }
1718 }
1719
1720 pub(crate) fn unique_id_if_already_present(&self) -> Option<String> {
1722 Ref::filter_map(self.rare_data(), |rare_data| {
1723 rare_data
1724 .as_ref()
1725 .and_then(|rare_data| rare_data.unique_id.as_ref())
1726 })
1727 .ok()
1728 .map(|unique_id| unique_id.borrow().simple().to_string())
1729 }
1730
1731 pub(crate) fn unique_id(&self, pipeline: PipelineId) -> String {
1732 let mut rare_data = self.ensure_rare_data();
1733
1734 if rare_data.unique_id.is_none() {
1735 let node_id = UniqueId::new();
1736 ScriptThread::save_node_id(pipeline, node_id.borrow().simple().to_string());
1737 rare_data.unique_id = Some(node_id);
1738 }
1739 rare_data
1740 .unique_id
1741 .as_ref()
1742 .unwrap()
1743 .borrow()
1744 .simple()
1745 .to_string()
1746 }
1747
1748 pub(crate) fn summarize(&self, cx: &mut JSContext) -> NodeInfo {
1749 let USVString(base_uri) = self.BaseURI();
1750 let node_type = self.NodeType();
1751 let pipeline = self.owner_window().pipeline_id();
1752
1753 let maybe_shadow_root = self.downcast::<ShadowRoot>();
1754 let shadow_root_mode = maybe_shadow_root
1755 .map(ShadowRoot::Mode)
1756 .map(ShadowRootMode::convert);
1757 let host = maybe_shadow_root
1758 .map(ShadowRoot::Host)
1759 .map(|host| host.upcast::<Node>().unique_id(pipeline));
1760 let is_shadow_host = self.downcast::<Element>().is_some_and(|potential_host| {
1761 let Some(root) = potential_host.shadow_root() else {
1762 return false;
1763 };
1764 !root.is_user_agent_widget() || pref!(inspector_show_servo_internal_shadow_roots)
1765 });
1766
1767 let num_children = if is_shadow_host {
1768 self.ChildNodes(cx).Length() as usize + 1
1770 } else {
1771 self.ChildNodes(cx).Length() as usize
1772 };
1773
1774 let window = self.owner_window();
1775 let element = self.downcast::<Element>();
1776 let display = element
1777 .map(|elem| window.GetComputedStyle(elem, None))
1778 .map(|style| style.Display().into());
1779
1780 let is_displayed =
1786 element.is_none_or(|element| !element.is_display_none()) || self.is::<DocumentType>();
1787 let attrs = element.map(Element::summarize).unwrap_or_default();
1788
1789 NodeInfo {
1790 unique_id: self.unique_id(pipeline),
1791 host,
1792 base_uri,
1793 parent: self
1794 .GetParentNode()
1795 .map_or("".to_owned(), |node| node.unique_id(pipeline)),
1796 node_type,
1797 is_top_level_document: node_type == NodeConstants::DOCUMENT_NODE,
1798 node_name: String::from(self.NodeName()),
1799 node_value: self.GetNodeValue().map(|v| v.into()),
1800 num_children,
1801 attrs,
1802 is_shadow_host,
1803 shadow_root_mode,
1804 display,
1805 is_displayed,
1806 doctype_name: self
1807 .downcast::<DocumentType>()
1808 .map(DocumentType::name)
1809 .cloned()
1810 .map(String::from),
1811 doctype_public_identifier: self
1812 .downcast::<DocumentType>()
1813 .map(DocumentType::public_id)
1814 .cloned()
1815 .map(String::from),
1816 doctype_system_identifier: self
1817 .downcast::<DocumentType>()
1818 .map(DocumentType::system_id)
1819 .cloned()
1820 .map(String::from),
1821 has_event_listeners: self.upcast::<EventTarget>().has_handlers(),
1822 }
1823 }
1824
1825 pub(crate) fn insert_cell_or_row<F, G, I>(
1827 &self,
1828 cx: &mut JSContext,
1829 index: i32,
1830 get_items: F,
1831 new_child: G,
1832 ) -> Fallible<DomRoot<HTMLElement>>
1833 where
1834 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1835 G: Fn(&mut JSContext) -> DomRoot<I>,
1836 I: DerivedFrom<Node> + DerivedFrom<HTMLElement> + DomObject,
1837 {
1838 if index < -1 {
1839 return Err(Error::IndexSize(None));
1840 }
1841
1842 let tr = new_child(cx);
1843
1844 {
1845 let tr_node = tr.upcast::<Node>();
1846 if index == -1 {
1847 self.InsertBefore(cx, tr_node, None)?;
1848 } else {
1849 let items = get_items(cx);
1850 let node = match items
1851 .elements_iter()
1852 .map(DomRoot::upcast::<Node>)
1853 .map(Some)
1854 .chain(iter::once(None))
1855 .nth(index as usize)
1856 {
1857 None => return Err(Error::IndexSize(None)),
1858 Some(node) => node,
1859 };
1860 self.InsertBefore(cx, tr_node, node.as_deref())?;
1861 }
1862 }
1863
1864 Ok(DomRoot::upcast::<HTMLElement>(tr))
1865 }
1866
1867 pub(crate) fn delete_cell_or_row<F, G>(
1869 &self,
1870 cx: &mut JSContext,
1871 index: i32,
1872 get_items: F,
1873 is_delete_type: G,
1874 ) -> ErrorResult
1875 where
1876 F: Fn(&mut JSContext) -> DomRoot<HTMLCollection>,
1877 G: Fn(&Element) -> bool,
1878 {
1879 let element = match index {
1880 index if index < -1 => return Err(Error::IndexSize(None)),
1881 -1 => {
1882 let last_child = self.upcast::<Node>().GetLastChild();
1883 match last_child.and_then(|node| {
1884 node.inclusively_preceding_siblings_unrooted(cx.no_gc())
1885 .filter_map(UnrootedDom::downcast::<Element>)
1886 .find(|elem| is_delete_type(elem))
1887 .map(|elem| elem.as_rooted())
1888 }) {
1889 Some(element) => element,
1890 None => return Ok(()),
1891 }
1892 },
1893 index => match get_items(cx).Item(index as u32) {
1894 Some(element) => element,
1895 None => return Err(Error::IndexSize(None)),
1896 },
1897 };
1898
1899 element.upcast::<Node>().remove_self(cx);
1900 Ok(())
1901 }
1902
1903 pub(crate) fn get_stylesheet(&self) -> Option<ServoArc<Stylesheet>> {
1904 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1905 node.get_stylesheet()
1906 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1907 node.get_stylesheet()
1908 } else {
1909 None
1910 }
1911 }
1912
1913 pub(crate) fn get_cssom_stylesheet(&self) -> Option<DomRoot<CSSStyleSheet>> {
1914 if let Some(node) = self.downcast::<HTMLStyleElement>() {
1915 node.get_cssom_stylesheet()
1916 } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
1917 node.get_cssom_stylesheet(CanGc::deprecated_note())
1918 } else {
1919 None
1920 }
1921 }
1922
1923 pub(crate) fn get_lang(&self) -> Option<String> {
1925 self.inclusive_ancestors(ShadowIncluding::Yes)
1926 .find_map(|node| {
1927 node.downcast::<Element>().and_then(|el| {
1928 el.get_attribute_with_namespace(&ns!(xml), &local_name!("lang"))
1929 .or_else(|| el.get_attribute(&local_name!("lang")))
1930 .map(|attr| String::from(attr.Value()))
1931 })
1932 })
1935 }
1936
1937 pub(crate) fn assign_slottables_for_a_tree(&self, force: ForceSlottableNodeReconciliation) {
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(ShadowIncluding::No) {
1958 if let Some(slot) = node.downcast::<HTMLSlotElement>() {
1959 slot.assign_slottables();
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 if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
2014 return Some(DomRoot::from_ref(shadow_root.Host().upcast::<Node>()));
2015 }
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 {
2025 current: Some(DomRoot::from_ref(self)),
2026 next_node: move |n| n.parent_in_flat_tree(),
2027 }
2028 }
2029
2030 pub(crate) fn set_implemented_pseudo_element(&self, pseudo_element: PseudoElement) {
2032 debug_assert!(self.is_in_ua_widget());
2034 debug_assert!(pseudo_element.is_element_backed());
2035 self.ensure_rare_data().implemented_pseudo_element = Some(pseudo_element);
2036 }
2037
2038 pub(crate) fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
2039 self.rare_data
2040 .borrow()
2041 .as_ref()
2042 .and_then(|rare_data| rare_data.implemented_pseudo_element)
2043 }
2044
2045 pub(crate) fn editing_host_of(&self) -> Option<DomRoot<Node>> {
2047 for ancestor in self.inclusive_ancestors(ShadowIncluding::No) {
2051 if ancestor.is_editing_host() {
2052 return Some(ancestor);
2053 }
2054 if ancestor
2055 .downcast::<HTMLElement>()
2056 .is_some_and(|el| el.ContentEditable().str() == "false")
2057 {
2058 return None;
2059 }
2060 }
2061 None
2062 }
2063
2064 pub(crate) fn is_editable_or_editing_host(&self) -> bool {
2065 self.editing_host_of().is_some()
2066 }
2067
2068 pub(crate) fn is_editing_host(&self) -> bool {
2070 self.downcast::<HTMLElement>()
2071 .is_some_and(HTMLElement::is_editing_host)
2072 }
2073
2074 pub(crate) fn is_editable(&self) -> bool {
2076 if self.is_editing_host() {
2078 return false;
2079 }
2080 let html_element = self.downcast::<HTMLElement>();
2082 if html_element.is_some_and(|el| el.ContentEditable().str() == "false") {
2083 return false;
2084 }
2085 let Some(parent) = self.GetParentNode() else {
2087 return false;
2088 };
2089 if !parent.is_editable_or_editing_host() {
2090 return false;
2091 }
2092 html_element.is_some() ||
2094 (!self.is::<Element>() && parent.downcast::<HTMLElement>().is_some())
2095 }
2096}
2097
2098fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<DomRoot<Node>>
2100where
2101 I: Iterator<Item = DomRoot<Node>>,
2102{
2103 nodes.find(|node| {
2104 not_in.iter().all(|n| match *n {
2105 NodeOrString::Node(ref n) => n != node,
2106 _ => true,
2107 })
2108 })
2109}
2110
2111#[expect(unsafe_code)]
2114pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress) -> DomRoot<Node> {
2115 let node = unsafe { Node::from_untrusted_node_address(candidate) };
2116 DomRoot::from_ref(node)
2117}
2118
2119impl<'dom> LayoutDom<'dom, Node> {
2120 #[inline]
2121 #[expect(unsafe_code)]
2122 pub(crate) fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
2123 unsafe { self.unsafe_get().parent_node.get_inner_as_layout() }
2124 }
2125
2126 #[inline]
2127 pub(crate) fn type_id_for_layout(self) -> NodeTypeId {
2128 self.unsafe_get().type_id()
2129 }
2130
2131 #[inline]
2132 pub(crate) fn is_element_for_layout(&self) -> bool {
2133 (*self).is::<Element>()
2134 }
2135
2136 pub(crate) fn is_text_node_for_layout(&self) -> bool {
2137 self.type_id_for_layout() ==
2138 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text))
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 if let Some(shadow_root) = parent.downcast::<ShadowRoot>() {
2146 return Some(shadow_root.get_host_for_layout().upcast());
2147 }
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
2420pub(crate) struct FollowingNodeIterator {
2425 current: Option<DomRoot<Node>>,
2426 root: DomRoot<Node>,
2427}
2428
2429impl FollowingNodeIterator {
2430 pub(crate) fn next_skipping_children(&mut self) -> Option<DomRoot<Node>> {
2432 let current = self.current.take()?;
2433 self.next_skipping_children_impl(current)
2434 }
2435
2436 fn next_skipping_children_impl(&mut self, current: DomRoot<Node>) -> Option<DomRoot<Node>> {
2437 if self.root == current {
2438 self.current = None;
2439 return None;
2440 }
2441
2442 if let Some(next_sibling) = current.GetNextSibling() {
2443 self.current = Some(next_sibling);
2444 return current.GetNextSibling();
2445 }
2446
2447 for ancestor in current.inclusive_ancestors(ShadowIncluding::No) {
2448 if self.root == ancestor {
2449 break;
2450 }
2451 if let Some(next_sibling) = ancestor.GetNextSibling() {
2452 self.current = Some(next_sibling);
2453 return ancestor.GetNextSibling();
2454 }
2455 }
2456 self.current = None;
2457 None
2458 }
2459}
2460
2461impl Iterator for FollowingNodeIterator {
2462 type Item = DomRoot<Node>;
2463
2464 fn next(&mut self) -> Option<DomRoot<Node>> {
2466 let current = self.current.take()?;
2467
2468 if let Some(first_child) = current.GetFirstChild() {
2469 self.current = Some(first_child);
2470 return current.GetFirstChild();
2471 }
2472
2473 self.next_skipping_children_impl(current)
2474 }
2475}
2476
2477pub(crate) struct PrecedingNodeIterator {
2478 current: Option<DomRoot<Node>>,
2479 root: DomRoot<Node>,
2480}
2481
2482impl Iterator for PrecedingNodeIterator {
2483 type Item = DomRoot<Node>;
2484
2485 fn next(&mut self) -> Option<DomRoot<Node>> {
2487 let current = self.current.take()?;
2488
2489 self.current = if self.root == current {
2490 None
2491 } else if let Some(previous_sibling) = current.GetPreviousSibling() {
2492 if self.root == previous_sibling {
2493 None
2494 } else if let Some(last_child) = previous_sibling.descending_last_children().last() {
2495 Some(last_child)
2496 } else {
2497 Some(previous_sibling)
2498 }
2499 } else {
2500 current.GetParentNode()
2501 };
2502 self.current.clone()
2503 }
2504}
2505
2506struct SimpleNodeIterator<I>
2507where
2508 I: Fn(&Node) -> Option<DomRoot<Node>>,
2509{
2510 current: Option<DomRoot<Node>>,
2511 next_node: I,
2512}
2513
2514impl<I> Iterator for SimpleNodeIterator<I>
2515where
2516 I: Fn(&Node) -> Option<DomRoot<Node>>,
2517{
2518 type Item = DomRoot<Node>;
2519
2520 fn next(&mut self) -> Option<Self::Item> {
2521 let current = self.current.take();
2522 self.current = current.as_ref().and_then(|c| (self.next_node)(c));
2523 current
2524 }
2525}
2526
2527#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
2535pub(crate) struct UnrootedSimpleNodeIterator<'a, 'b, I>
2536where
2537 I: Fn(&Node, &'b NoGC) -> Option<UnrootedDom<'b, Node>>,
2538{
2539 current: Option<UnrootedDom<'b, Node>>,
2540 next_node: I,
2541 no_gc: &'b NoGC,
2543 phantom: PhantomData<&'a Node>,
2544}
2545
2546impl<'a, 'b, I> Iterator for UnrootedSimpleNodeIterator<'a, 'b, I>
2547where
2548 'b: 'a,
2549 I: Fn(&Node, &'b NoGC) -> Option<UnrootedDom<'b, Node>>,
2550{
2551 type Item = UnrootedDom<'b, Node>;
2552
2553 fn next(&mut self) -> Option<Self::Item> {
2554 let current = self.current.take();
2555 self.current = current
2556 .as_ref()
2557 .and_then(|c| (self.next_node)(c, self.no_gc));
2558 current
2559 }
2560}
2561
2562#[derive(Clone, Copy, PartialEq)]
2564pub(crate) enum ShadowIncluding {
2565 No,
2566 Yes,
2567}
2568
2569pub(crate) struct TreeIterator {
2570 current: Option<DomRoot<Node>>,
2571 depth: usize,
2572 shadow_including: ShadowIncluding,
2573}
2574
2575impl TreeIterator {
2576 fn new(root: &Node, shadow_including: ShadowIncluding) -> TreeIterator {
2577 TreeIterator {
2578 current: Some(DomRoot::from_ref(root)),
2579 depth: 0,
2580 shadow_including,
2581 }
2582 }
2583
2584 pub(crate) fn next_skipping_children(&mut self) -> Option<DomRoot<Node>> {
2585 let current = self.current.take()?;
2586
2587 self.next_skipping_children_impl(current)
2588 }
2589
2590 fn next_skipping_children_impl(&mut self, current: DomRoot<Node>) -> Option<DomRoot<Node>> {
2591 let iter = current.inclusive_ancestors(self.shadow_including);
2592
2593 for ancestor in iter {
2594 if self.depth == 0 {
2595 break;
2596 }
2597 if let Some(next_sibling) = ancestor.GetNextSibling() {
2598 self.current = Some(next_sibling);
2599 return Some(current);
2600 }
2601 if let Some(shadow_root) = ancestor.downcast::<ShadowRoot>() {
2602 if let Some(child) = shadow_root.Host().upcast::<Node>().GetFirstChild() {
2605 self.current = Some(child);
2606 return Some(current);
2607 }
2608 }
2609 self.depth -= 1;
2610 }
2611 debug_assert_eq!(self.depth, 0);
2612 self.current = None;
2613 Some(current)
2614 }
2615
2616 pub(crate) fn peek(&self) -> Option<&DomRoot<Node>> {
2617 self.current.as_ref()
2618 }
2619}
2620
2621impl Iterator for TreeIterator {
2622 type Item = DomRoot<Node>;
2623
2624 fn next(&mut self) -> Option<DomRoot<Node>> {
2627 let current = self.current.take()?;
2628
2629 if let Some(element) = current.downcast::<Element>() {
2631 if let Some(shadow_root) = element.shadow_root() {
2632 if self.shadow_including == ShadowIncluding::Yes {
2633 self.current = Some(DomRoot::from_ref(shadow_root.upcast::<Node>()));
2634 self.depth += 1;
2635 return Some(current);
2636 }
2637 }
2638 }
2639
2640 if let Some(first_child) = current.GetFirstChild() {
2641 self.current = Some(first_child);
2642 self.depth += 1;
2643 return Some(current);
2644 };
2645
2646 self.next_skipping_children_impl(current)
2647 }
2648}
2649
2650#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
2658pub(crate) struct UnrootedTreeIterator<'a, 'b> {
2659 current: Option<UnrootedDom<'b, Node>>,
2660 depth: usize,
2661 shadow_including: ShadowIncluding,
2662 no_gc: &'b NoGC,
2664 phantom: PhantomData<&'a Node>,
2665}
2666
2667impl<'a, 'b> UnrootedTreeIterator<'a, 'b>
2668where
2669 'b: 'a,
2670{
2671 pub(crate) fn new(
2672 root: &'a Node,
2673 shadow_including: ShadowIncluding,
2674 no_gc: &'b NoGC,
2675 ) -> UnrootedTreeIterator<'a, 'b> {
2676 UnrootedTreeIterator {
2677 current: Some(UnrootedDom::from_dom(Dom::from_ref(root), no_gc)),
2678 depth: 0,
2679 shadow_including,
2680 no_gc,
2681 phantom: PhantomData,
2682 }
2683 }
2684
2685 pub(crate) fn next_skipping_children(&mut self) -> Option<UnrootedDom<'b, Node>> {
2686 let current = self.current.take()?;
2687
2688 let iter = current.inclusive_ancestors(self.shadow_including);
2689
2690 for ancestor in iter {
2691 if self.depth == 0 {
2692 break;
2693 }
2694
2695 let next_sibling_option = ancestor.get_next_sibling_unrooted(self.no_gc);
2696
2697 if let Some(next_sibling) = next_sibling_option {
2698 self.current = Some(next_sibling);
2699 return Some(current);
2700 }
2701
2702 if let Some(shadow_root) = ancestor.downcast::<ShadowRoot>() {
2703 let child_option = shadow_root
2706 .Host()
2707 .upcast::<Node>()
2708 .get_first_child_unrooted(self.no_gc);
2709
2710 if let Some(child) = child_option {
2711 self.current = Some(child);
2712 return Some(current);
2713 }
2714 }
2715 self.depth -= 1;
2716 }
2717 debug_assert_eq!(self.depth, 0);
2718 self.current = None;
2719 Some(current)
2720 }
2721}
2722
2723impl<'a, 'b> Iterator for UnrootedTreeIterator<'a, 'b>
2724where
2725 'b: 'a,
2726{
2727 type Item = UnrootedDom<'b, Node>;
2728
2729 fn next(&mut self) -> Option<UnrootedDom<'b, Node>> {
2732 let current = self.current.take()?;
2733
2734 if let Some(element) = current.downcast::<Element>() {
2736 if let Some(shadow_root) = element.shadow_root() {
2737 if self.shadow_including == ShadowIncluding::Yes {
2738 self.current = Some(UnrootedDom::from_dom(
2739 Dom::from_ref(shadow_root.upcast::<Node>()),
2740 self.no_gc,
2741 ));
2742 self.depth += 1;
2743 return Some(current);
2744 }
2745 }
2746 }
2747
2748 let first_child_option = current.get_first_child_unrooted(self.no_gc);
2749 if let Some(first_child) = first_child_option {
2750 self.current = Some(first_child);
2751 self.depth += 1;
2752 return Some(current);
2753 };
2754
2755 let _ = self.current.insert(current);
2757 self.next_skipping_children()
2758 }
2759}
2760
2761#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
2763pub(crate) enum CloneChildrenFlag {
2764 CloneChildren,
2765 DoNotCloneChildren,
2766}
2767
2768impl From<bool> for CloneChildrenFlag {
2769 fn from(boolean: bool) -> Self {
2770 if boolean {
2771 CloneChildrenFlag::CloneChildren
2772 } else {
2773 CloneChildrenFlag::DoNotCloneChildren
2774 }
2775 }
2776}
2777
2778fn as_uintptr<T>(t: &T) -> uintptr_t {
2779 t as *const T as uintptr_t
2780}
2781
2782impl Node {
2783 pub(crate) fn reflect_node<N>(
2784 cx: &mut js::context::JSContext,
2785 node: Box<N>,
2786 document: &Document,
2787 ) -> DomRoot<N>
2788 where
2789 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2790 {
2791 Self::reflect_node_with_proto(cx, node, document, None)
2792 }
2793
2794 pub(crate) fn reflect_node_with_proto<N>(
2795 cx: &mut js::context::JSContext,
2796 node: Box<N>,
2797 document: &Document,
2798 proto: Option<HandleObject>,
2799 ) -> DomRoot<N>
2800 where
2801 N: DerivedFrom<Node> + DomObject + DomObjectWrap<crate::DomTypeHolder>,
2802 {
2803 let window = document.window();
2804 reflect_dom_object_with_proto_and_cx(node, window, proto, cx)
2805 }
2806
2807 pub(crate) fn new_inherited(doc: &Document) -> Node {
2808 Node::new_(NodeFlags::empty(), Some(doc))
2809 }
2810
2811 pub(crate) fn new_document_node() -> Node {
2812 Node::new_(
2813 NodeFlags::IS_IN_A_DOCUMENT_TREE | NodeFlags::IS_CONNECTED,
2814 None,
2815 )
2816 }
2817
2818 fn new_(flags: NodeFlags, doc: Option<&Document>) -> Node {
2819 Node {
2820 eventtarget: EventTarget::new_inherited(),
2821 parent_node: Default::default(),
2822 first_child: Default::default(),
2823 last_child: Default::default(),
2824 next_sibling: Default::default(),
2825 prev_sibling: Default::default(),
2826 owner_doc: MutNullableDom::new(doc),
2827 rare_data: Default::default(),
2828 children_count: Cell::new(0u32),
2829 flags: Cell::new(flags),
2830 inclusive_descendants_version: Cell::new(0),
2831 layout_data: Default::default(),
2832 }
2833 }
2834
2835 pub(crate) fn adopt(cx: &mut JSContext, node: &Node, document: &Document) {
2837 document.add_script_and_layout_blocker();
2838
2839 let old_doc = node.owner_doc();
2841 old_doc.add_script_and_layout_blocker();
2842
2843 node.remove_self(cx);
2845
2846 if &*old_doc != document {
2848 for descendant in node.traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes) {
2850 descendant.set_owner_doc(document);
2852
2853 if let Some(element) = descendant.downcast::<Element>() {
2856 for attribute in element.attrs().iter() {
2857 attribute.upcast::<Node>().set_owner_doc(document);
2858 }
2859 }
2860 }
2861
2862 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
2866 for descendant in node
2867 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::Yes)
2868 .filter_map(|d| d.as_custom_element())
2869 {
2870 custom_element_reaction_stack.enqueue_callback_reaction(
2871 &descendant,
2872 CallbackReaction::Adopted(old_doc.clone(), DomRoot::from_ref(document)),
2873 None,
2874 );
2875 }
2876
2877 for descendant in node.traverse_preorder(ShadowIncluding::Yes) {
2880 vtable_for(&descendant).adopting_steps(cx, &old_doc);
2881 }
2882 }
2883
2884 old_doc.remove_script_and_layout_blocker(cx);
2885 document.remove_script_and_layout_blocker(cx);
2886 }
2887
2888 pub(crate) fn ensure_pre_insertion_validity(
2890 no_gc: &NoGC,
2891 node: &Node,
2892 parent: &Node,
2893 child: Option<&Node>,
2894 ) -> ErrorResult {
2895 match parent.type_id() {
2897 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
2898 },
2899 _ => {
2900 return Err(Error::HierarchyRequest(Some(
2901 "Parent is not a Document, DocumentFragment, or Element node".to_owned(),
2902 )));
2903 },
2904 }
2905
2906 if node.is_host_including_inclusive_ancestor(parent) {
2908 return Err(Error::HierarchyRequest(Some(
2909 "Node is a host-including inclusive ancestor of parent".to_owned(),
2910 )));
2911 }
2912
2913 if let Some(child) = child {
2915 if !parent.is_parent_of(child) {
2916 return Err(Error::NotFound(Some(
2917 "Child is non-null and its parent is not parent".to_owned(),
2918 )));
2919 }
2920 }
2921
2922 match node.type_id() {
2923 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
2927 if parent.is::<Document>() {
2928 return Err(Error::HierarchyRequest(Some(
2929 "Node is a Text node and parent is a document".to_owned(),
2930 )));
2931 }
2932 },
2933 NodeTypeId::DocumentType => {
2934 if !parent.is::<Document>() {
2935 return Err(Error::HierarchyRequest(Some(
2936 "Node is a doctype and parent is not a document".to_owned(),
2937 )));
2938 }
2939 },
2940 NodeTypeId::DocumentFragment(_) |
2941 NodeTypeId::Element(_) |
2942 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
2943 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
2944 NodeTypeId::Document(_) | NodeTypeId::Attr => {
2947 return Err(Error::HierarchyRequest(Some(
2948 "Node is not a DocumentFragment, DocumentType, Element, or CharacterData node"
2949 .to_owned(),
2950 )));
2951 },
2952 }
2953
2954 if parent.is::<Document>() {
2957 match node.type_id() {
2958 NodeTypeId::DocumentFragment(_) => {
2959 if node.children_unrooted(no_gc).any(|c| c.is::<Text>()) {
2961 return Err(Error::HierarchyRequest(None));
2962 }
2963 match node.child_elements_unrooted(no_gc).count() {
2964 0 => (),
2965 1 => {
2968 if parent.child_elements_unrooted(no_gc).next().is_some() {
2969 return Err(Error::HierarchyRequest(None));
2970 }
2971 if let Some(child) = child {
2972 if child
2973 .inclusively_following_siblings_unrooted(no_gc)
2974 .any(|child| child.is_doctype())
2975 {
2976 return Err(Error::HierarchyRequest(None));
2977 }
2978 }
2979 },
2980 _ => return Err(Error::HierarchyRequest(None)),
2981 }
2982 },
2983 NodeTypeId::Element(_) => {
2984 if parent.child_elements_unrooted(no_gc).next().is_some() {
2986 return Err(Error::HierarchyRequest(Some(
2987 "Parent has an element child".to_owned(),
2988 )));
2989 }
2990 if let Some(child) = child {
2991 if child
2992 .inclusively_following_siblings_unrooted(no_gc)
2993 .any(|following| following.is_doctype())
2994 {
2995 return Err(Error::HierarchyRequest(Some(
2996 "Child is a doctype, or child is non-null and a doctype is following child".to_owned(),
2997 )));
2998 }
2999 }
3000 },
3001 NodeTypeId::DocumentType => {
3002 if parent.children_unrooted(no_gc).any(|c| c.is_doctype()) {
3005 return Err(Error::HierarchyRequest(None));
3006 }
3007 match child {
3008 Some(child) => {
3009 if parent
3010 .children_unrooted(no_gc)
3011 .take_while(|c| **c != child)
3012 .any(|c| c.is::<Element>())
3013 {
3014 return Err(Error::HierarchyRequest(None));
3015 }
3016 },
3017 None => {
3018 if parent.child_elements_unrooted(no_gc).next().is_some() {
3019 return Err(Error::HierarchyRequest(None));
3020 }
3021 },
3022 }
3023 },
3024 NodeTypeId::CharacterData(_) => (),
3025 NodeTypeId::Document(_) | NodeTypeId::Attr => unreachable!(),
3028 }
3029 }
3030 Ok(())
3031 }
3032
3033 pub(crate) fn pre_insert(
3035 cx: &mut JSContext,
3036 node: &Node,
3037 parent: &Node,
3038 child: Option<&Node>,
3039 ) -> Fallible<DomRoot<Node>> {
3040 Node::ensure_pre_insertion_validity(cx.no_gc(), node, parent, child)?;
3042
3043 let reference_child_root;
3045 let reference_child = match child {
3046 Some(child) if child == node => {
3048 reference_child_root = node.GetNextSibling();
3049 reference_child_root.as_deref()
3050 },
3051 _ => child,
3052 };
3053
3054 Node::insert(
3056 cx,
3057 node,
3058 parent,
3059 reference_child,
3060 SuppressObserver::Unsuppressed,
3061 );
3062
3063 Ok(DomRoot::from_ref(node))
3065 }
3066
3067 fn insert(
3069 cx: &mut JSContext,
3070 node: &Node,
3071 parent: &Node,
3072 child: Option<&Node>,
3073 suppress_observers: SuppressObserver,
3074 ) {
3075 debug_assert!(child.is_none_or(|child| Some(parent) == child.GetParentNode().as_deref()));
3076
3077 rooted_vec!(let mut new_nodes);
3079 let new_nodes = if let NodeTypeId::DocumentFragment(_) = node.type_id() {
3080 new_nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
3081 new_nodes.r()
3082 } else {
3083 from_ref(&node)
3084 };
3085
3086 let count = new_nodes.len();
3088
3089 if count == 0 {
3091 return;
3092 }
3093
3094 let parent_document = parent.owner_doc();
3097 let from_document = node.owner_doc();
3098 from_document.add_script_and_layout_blocker();
3099 parent_document.add_script_and_layout_blocker();
3100
3101 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
3103 for kid in new_nodes {
3105 Node::remove(cx, kid, node, SuppressObserver::Suppressed);
3106 }
3107 vtable_for(node).children_changed(cx, &ChildrenMutation::replace_all(new_nodes, &[]));
3108
3109 let mutation = LazyCell::new(|| Mutation::ChildList {
3111 added: None,
3112 removed: Some(new_nodes),
3113 prev: None,
3114 next: None,
3115 });
3116 MutationObserver::queue_a_mutation_record(node, mutation);
3117 }
3118
3119 if let Some(child) = child {
3125 if !parent.ranges_is_empty() {
3126 parent
3127 .ranges()
3128 .increase_above(parent, child.index(), count.try_into().unwrap());
3129 }
3130 }
3131
3132 let previous_sibling = match suppress_observers {
3134 SuppressObserver::Unsuppressed => match child {
3135 Some(child) => child.GetPreviousSibling(),
3136 None => parent.GetLastChild(),
3137 },
3138 SuppressObserver::Suppressed => None,
3139 };
3140
3141 let custom_element_reaction_stack = ScriptThread::custom_element_reaction_stack();
3142
3143 let mut static_node_list: SmallVec<[_; 4]> = Default::default();
3145
3146 let parent_shadow_root = parent.downcast::<Element>().and_then(Element::shadow_root);
3147 let parent_in_shadow_tree = parent.is_in_a_shadow_tree();
3148 let parent_as_slot = parent.downcast::<HTMLSlotElement>();
3149
3150 for kid in new_nodes {
3152 Node::adopt(cx, kid, &parent.owner_document());
3154
3155 parent.add_child(cx, kid, child);
3158
3159 if let Some(ref shadow_root) = parent_shadow_root {
3162 if shadow_root.SlotAssignment() == SlotAssignmentMode::Named {
3163 let cx = GlobalScope::get_cx();
3164 if kid.is::<Element>() || kid.is::<Text>() {
3165 rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(kid)));
3166 slottable.assign_a_slot();
3167 }
3168 }
3169 }
3170
3171 if parent_in_shadow_tree {
3174 if let Some(slot_element) = parent_as_slot {
3175 if !slot_element.has_assigned_nodes() {
3176 slot_element.signal_a_slot_change();
3177 }
3178 }
3179 }
3180
3181 kid.GetRootNode(&GetRootNodeOptions::empty())
3183 .assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Skip);
3184
3185 for descendant in kid.traverse_preorder(ShadowIncluding::Yes) {
3188 if descendant.is_connected() {
3191 static_node_list.push(descendant.clone());
3192 }
3193
3194 if let Some(descendant) = DomRoot::downcast::<Element>(descendant) {
3200 if descendant.is_custom() {
3201 if descendant.is_connected() {
3202 custom_element_reaction_stack.enqueue_callback_reaction(
3203 &descendant,
3204 CallbackReaction::Connected,
3205 None,
3206 );
3207 }
3208 } else {
3209 try_upgrade_element(&descendant);
3210 }
3211 }
3212 }
3213 }
3214
3215 if let SuppressObserver::Unsuppressed = suppress_observers {
3216 vtable_for(parent).children_changed(
3219 cx,
3220 &ChildrenMutation::insert(previous_sibling.as_deref(), new_nodes, child),
3221 );
3222
3223 let mutation = LazyCell::new(|| Mutation::ChildList {
3226 added: Some(new_nodes),
3227 removed: None,
3228 prev: previous_sibling.as_deref(),
3229 next: child,
3230 });
3231 MutationObserver::queue_a_mutation_record(parent, mutation);
3232 }
3233
3234 parent_document.add_delayed_task(
3245 task!(PostConnectionSteps: |cx, static_node_list: SmallVec<[DomRoot<Node>; 4]>| {
3246 for node in static_node_list {
3249 vtable_for(&node).post_connection_steps(cx);
3250 }
3251 }),
3252 );
3253
3254 parent_document.remove_script_and_layout_blocker(cx);
3255 from_document.remove_script_and_layout_blocker(cx);
3256 }
3257
3258 pub(crate) fn replace_all(cx: &mut JSContext, node: Option<&Node>, parent: &Node) {
3260 parent.owner_doc().add_script_and_layout_blocker();
3261
3262 rooted_vec!(let removed_nodes <- parent.children().map(|child| DomRoot::as_traced(&child)));
3264
3265 rooted_vec!(let mut added_nodes);
3269 let added_nodes = if let Some(node) = node.as_ref() {
3270 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
3271 added_nodes.extend(node.children().map(|child| Dom::from_ref(&*child)));
3272 added_nodes.r()
3273 } else {
3274 from_ref(node)
3275 }
3276 } else {
3277 &[] as &[&Node]
3278 };
3279
3280 for child in &*removed_nodes {
3282 Node::remove(cx, child, parent, SuppressObserver::Suppressed);
3283 }
3284
3285 if let Some(node) = node {
3287 Node::insert(cx, node, parent, None, SuppressObserver::Suppressed);
3288 }
3289
3290 vtable_for(parent).children_changed(
3291 cx,
3292 &ChildrenMutation::replace_all(removed_nodes.r(), added_nodes),
3293 );
3294
3295 if !removed_nodes.is_empty() || !added_nodes.is_empty() {
3298 let mutation = LazyCell::new(|| Mutation::ChildList {
3299 added: Some(added_nodes),
3300 removed: Some(removed_nodes.r()),
3301 prev: None,
3302 next: None,
3303 });
3304 MutationObserver::queue_a_mutation_record(parent, mutation);
3305 }
3306 parent.owner_doc().remove_script_and_layout_blocker(cx);
3307 }
3308
3309 pub(crate) fn string_replace_all(cx: &mut JSContext, string: DOMString, parent: &Node) {
3311 if string.is_empty() {
3312 Node::replace_all(cx, None, parent);
3313 } else {
3314 let text = Text::new(cx, string, &parent.owner_document());
3315 Node::replace_all(cx, Some(text.upcast::<Node>()), parent);
3316 };
3317 }
3318
3319 fn pre_remove(cx: &mut JSContext, child: &Node, parent: &Node) -> Fallible<DomRoot<Node>> {
3321 match child.GetParentNode() {
3323 Some(ref node) if &**node != parent => return Err(Error::NotFound(None)),
3324 None => return Err(Error::NotFound(None)),
3325 _ => (),
3326 }
3327
3328 Node::remove(cx, child, parent, SuppressObserver::Unsuppressed);
3330
3331 Ok(DomRoot::from_ref(child))
3333 }
3334
3335 fn remove(
3337 cx: &mut JSContext,
3338 node: &Node,
3339 parent: &Node,
3340 suppress_observers: SuppressObserver,
3341 ) {
3342 parent.owner_doc().add_script_and_layout_blocker();
3343
3344 assert!(
3348 node.GetParentNode()
3349 .is_some_and(|node_parent| &*node_parent == parent)
3350 );
3351
3352 let cached_index = Node::live_range_pre_remove_steps(node, parent);
3355
3356 let old_previous_sibling = node.GetPreviousSibling();
3360
3361 let old_next_sibling = node.GetNextSibling();
3363
3364 parent.remove_child(cx, node, cached_index);
3367
3368 if let Some(slot) = node.assigned_slot() {
3370 slot.assign_slottables();
3371 }
3372
3373 if parent.is_in_a_shadow_tree() {
3376 if let Some(slot_element) = parent.downcast::<HTMLSlotElement>() {
3377 if !slot_element.has_assigned_nodes() {
3378 slot_element.signal_a_slot_change();
3379 }
3380 }
3381 }
3382
3383 let has_slot_descendant = node
3385 .traverse_preorder_non_rooting(cx.no_gc(), ShadowIncluding::No)
3386 .any(|elem| elem.is::<HTMLSlotElement>());
3387 if has_slot_descendant {
3388 parent
3390 .GetRootNode(&GetRootNodeOptions::empty())
3391 .assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Skip);
3392
3393 node.assign_slottables_for_a_tree(ForceSlottableNodeReconciliation::Force);
3395 }
3396
3397 if let SuppressObserver::Unsuppressed = suppress_observers {
3401 vtable_for(parent).children_changed(
3402 cx,
3403 &ChildrenMutation::replace(
3404 old_previous_sibling.as_deref(),
3405 &Some(node),
3406 &[],
3407 old_next_sibling.as_deref(),
3408 ),
3409 );
3410
3411 let removed = [node];
3412 let mutation = LazyCell::new(|| Mutation::ChildList {
3413 added: None,
3414 removed: Some(&removed),
3415 prev: old_previous_sibling.as_deref(),
3416 next: old_next_sibling.as_deref(),
3417 });
3418 MutationObserver::queue_a_mutation_record(parent, mutation);
3419 }
3420 parent.owner_doc().remove_script_and_layout_blocker(cx);
3421 }
3422
3423 fn live_range_pre_remove_steps(node: &Node, parent: &Node) -> Option<u32> {
3425 if parent.ranges_is_empty() {
3426 return None;
3427 }
3428
3429 let index = node.index();
3435
3436 parent.ranges().decrease_above(parent, index, 1);
3443
3444 Some(index)
3448 }
3449
3450 pub(crate) fn clone(
3452 cx: &mut JSContext,
3453 node: &Node,
3454 maybe_doc: Option<&Document>,
3455 clone_children: CloneChildrenFlag,
3456 registry: Option<DomRoot<CustomElementRegistry>>,
3457 ) -> DomRoot<Node> {
3458 let document = match maybe_doc {
3460 Some(doc) => DomRoot::from_ref(doc),
3461 None => node.owner_doc(),
3462 };
3463
3464 let copy: DomRoot<Node> = match node.type_id() {
3467 NodeTypeId::DocumentType => {
3468 let doctype = node.downcast::<DocumentType>().unwrap();
3469 let doctype = DocumentType::new(
3470 cx,
3471 doctype.name().clone(),
3472 Some(doctype.public_id().clone()),
3473 Some(doctype.system_id().clone()),
3474 &document,
3475 );
3476 DomRoot::upcast::<Node>(doctype)
3477 },
3478 NodeTypeId::Attr => {
3479 let attr = node.downcast::<Attr>().unwrap();
3480 let attr = Attr::new(
3481 cx,
3482 &document,
3483 attr.local_name().clone(),
3484 attr.value().clone(),
3485 attr.name().clone(),
3486 attr.namespace().clone(),
3487 attr.prefix().cloned(),
3488 None,
3489 );
3490 DomRoot::upcast::<Node>(attr)
3491 },
3492 NodeTypeId::DocumentFragment(_) => {
3493 let doc_fragment = DocumentFragment::new(cx, &document);
3494 DomRoot::upcast::<Node>(doc_fragment)
3495 },
3496 NodeTypeId::CharacterData(_) => {
3497 let cdata = node.downcast::<CharacterData>().unwrap();
3498 cdata.clone_with_data(cx, cdata.Data(), &document)
3499 },
3500 NodeTypeId::Document(_) => {
3501 let document = node.downcast::<Document>().unwrap();
3504 let is_html_doc = if document.is_html_document() {
3505 IsHTMLDocument::HTMLDocument
3506 } else {
3507 IsHTMLDocument::NonHTMLDocument
3508 };
3509 let window = document.window();
3510 let loader = DocumentLoader::new(&document.loader());
3511 let document = Document::new(
3512 window,
3513 HasBrowsingContext::No,
3514 Some(document.url()),
3515 None,
3516 document.origin().clone(),
3518 is_html_doc,
3519 None,
3520 None,
3521 DocumentActivity::Inactive,
3522 DocumentSource::NotFromParser,
3523 loader,
3524 None,
3525 document.status_code(),
3526 Default::default(),
3527 false,
3528 document.allow_declarative_shadow_roots(),
3529 Some(document.insecure_requests_policy()),
3530 document.has_trustworthy_ancestor_or_current_origin(),
3531 document.custom_element_reaction_stack(),
3532 document.creation_sandboxing_flag_set(),
3533 CanGc::from_cx(cx),
3534 );
3535 DomRoot::upcast::<Node>(document)
3539 },
3540 NodeTypeId::Element(..) => {
3542 let element = node.downcast::<Element>().unwrap();
3543 let registry = element.custom_element_registry().or(registry);
3546 let registry =
3549 if CustomElementRegistry::is_a_global_element_registry(registry.as_deref()) {
3550 Some(document.custom_element_registry())
3551 } else {
3552 registry
3553 };
3554 let name = QualName {
3558 prefix: element.prefix().as_ref().map(|p| Prefix::from(&**p)),
3559 ns: element.namespace().clone(),
3560 local: element.local_name().clone(),
3561 };
3562 let element = Element::create(
3563 cx,
3564 name,
3565 element.get_is(),
3566 &document,
3567 ElementCreator::ScriptCreated,
3568 CustomElementCreationMode::Asynchronous,
3569 None,
3570 );
3571 element.set_custom_element_registry(registry);
3573 DomRoot::upcast::<Node>(element)
3574 },
3575 };
3576
3577 let document = match copy.downcast::<Document>() {
3580 Some(doc) => DomRoot::from_ref(doc),
3581 None => DomRoot::from_ref(&*document),
3582 };
3583 assert!(copy.owner_doc() == document);
3584
3585 match node.type_id() {
3587 NodeTypeId::Document(_) => {
3588 let node_doc = node.downcast::<Document>().unwrap();
3589 let copy_doc = copy.downcast::<Document>().unwrap();
3590 copy_doc.set_encoding(node_doc.encoding());
3591 copy_doc.set_quirks_mode(node_doc.quirks_mode());
3592 },
3593 NodeTypeId::Element(..) => {
3594 let node_elem = node.downcast::<Element>().unwrap();
3595 let copy_elem = copy.downcast::<Element>().unwrap();
3596
3597 node_elem.copy_all_attributes_to_other_element(cx, copy_elem);
3599 },
3600 _ => (),
3601 }
3602
3603 vtable_for(node).cloning_steps(cx, ©, maybe_doc, clone_children);
3606
3607 if clone_children == CloneChildrenFlag::CloneChildren {
3610 for child in node.children() {
3611 let child_copy = Node::clone(cx, &child, Some(&document), clone_children, None);
3612 let _inserted_node = Node::pre_insert(cx, &child_copy, ©, None);
3613 }
3614 }
3615
3616 if matches!(node.type_id(), NodeTypeId::Element(_)) {
3619 let node_elem = node.downcast::<Element>().unwrap();
3620 let copy_elem = copy.downcast::<Element>().unwrap();
3621
3622 if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) {
3623 assert!(!copy_elem.is_shadow_host());
3625
3626 let copy_shadow_root =
3630 copy_elem.attach_shadow(
3631 cx,
3632 IsUserAgentWidget::No,
3633 shadow_root.Mode(),
3634 shadow_root.Clonable(),
3635 shadow_root.Serializable(),
3636 shadow_root.DelegatesFocus(),
3637 shadow_root.SlotAssignment(),
3638 )
3639 .expect("placement of attached shadow root must be valid, as this is a copy of an existing one");
3640
3641 copy_shadow_root.set_declarative(shadow_root.is_declarative());
3643
3644 for child in shadow_root.upcast::<Node>().children() {
3647 let child_copy = Node::clone(
3648 cx,
3649 &child,
3650 Some(&document),
3651 CloneChildrenFlag::CloneChildren,
3652 None,
3653 );
3654
3655 let _inserted_node =
3657 Node::pre_insert(cx, &child_copy, copy_shadow_root.upcast::<Node>(), None);
3658 }
3659 }
3660 }
3661
3662 copy
3664 }
3665
3666 pub(crate) fn child_text_content(&self) -> DOMString {
3668 Node::collect_text_contents(self.children())
3669 }
3670
3671 pub(crate) fn descendant_text_content(&self) -> DOMString {
3673 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No))
3674 }
3675
3676 pub(crate) fn collect_text_contents<T: Iterator<Item = DomRoot<Node>>>(
3677 iterator: T,
3678 ) -> DOMString {
3679 let mut content = String::new();
3680 for node in iterator {
3681 if let Some(text) = node.downcast::<Text>() {
3682 content.push_str(&text.upcast::<CharacterData>().data());
3683 }
3684 }
3685 DOMString::from(content)
3686 }
3687
3688 pub(crate) fn set_text_content_for_element(
3690 &self,
3691 cx: &mut JSContext,
3692 value: Option<DOMString>,
3693 ) {
3694 assert!(matches!(
3697 self.type_id(),
3698 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..)
3699 ));
3700 let value = value.unwrap_or_default();
3701 let node = if value.is_empty() {
3702 None
3704 } else {
3705 Some(DomRoot::upcast(self.owner_doc().CreateTextNode(cx, value)))
3708 };
3709
3710 Self::replace_all(cx, node.as_deref(), self);
3712 }
3713
3714 pub(crate) fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
3715 match namespace {
3716 ns!() => None,
3717 _ => Some(DOMString::from(&*namespace)),
3719 }
3720 }
3721
3722 pub(crate) fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
3724 match node.type_id() {
3725 NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
3726 NodeTypeId::Attr => node
3727 .downcast::<Attr>()
3728 .unwrap()
3729 .GetOwnerElement()
3730 .as_ref()
3731 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3732 NodeTypeId::Document(_) => node
3733 .downcast::<Document>()
3734 .unwrap()
3735 .GetDocumentElement()
3736 .as_ref()
3737 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3738 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => ns!(),
3739 _ => node
3740 .GetParentElement()
3741 .as_ref()
3742 .map_or(ns!(), |elem| elem.locate_namespace(prefix)),
3743 }
3744 }
3745
3746 #[expect(unsafe_code)]
3754 pub(crate) unsafe fn from_untrusted_node_address(
3755 candidate: UntrustedNodeAddress,
3756 ) -> &'static Self {
3757 let candidate = candidate.0 as usize;
3759 let object = candidate as *mut JSObject;
3760 if object.is_null() {
3761 panic!("Attempted to create a `Node` from an invalid pointer!")
3762 }
3763
3764 unsafe { &*(conversions::private_from_object(object) as *const Self) }
3765 }
3766
3767 pub(crate) fn html_serialize(
3768 &self,
3769 cx: &mut js::context::JSContext,
3770 traversal_scope: html_serialize::TraversalScope,
3771 serialize_shadow_roots: bool,
3772 shadow_roots: Vec<DomRoot<ShadowRoot>>,
3773 ) -> DOMString {
3774 let mut writer = vec![];
3775 let mut serializer = HtmlSerializer::new(
3776 &mut writer,
3777 html_serialize::SerializeOpts {
3778 traversal_scope: traversal_scope.clone(),
3779 ..Default::default()
3780 },
3781 );
3782
3783 serialize_html_fragment(
3784 cx,
3785 self,
3786 &mut serializer,
3787 traversal_scope,
3788 serialize_shadow_roots,
3789 shadow_roots,
3790 )
3791 .expect("Serializing node failed");
3792
3793 DOMString::from(String::from_utf8(writer).unwrap())
3795 }
3796
3797 pub(crate) fn xml_serialize(
3799 &self,
3800 traversal_scope: xml_serialize::TraversalScope,
3801 ) -> Fallible<DOMString> {
3802 let mut writer = vec![];
3803 xml_serialize::serialize(
3804 &mut writer,
3805 &HtmlSerialize::new(self),
3806 xml_serialize::SerializeOpts { traversal_scope },
3807 )
3808 .map_err(|error| {
3809 error!("Cannot serialize node: {error}");
3810 Error::InvalidState(None)
3811 })?;
3812
3813 let string = DOMString::from(String::from_utf8(writer).map_err(|error| {
3815 error!("Cannot serialize node: {error}");
3816 Error::InvalidState(None)
3817 })?);
3818
3819 Ok(string)
3820 }
3821
3822 pub(crate) fn fragment_serialization_algorithm(
3824 &self,
3825 cx: &mut js::context::JSContext,
3826 require_well_formed: bool,
3827 ) -> Fallible<DOMString> {
3828 let context_document = self.owner_document();
3830
3831 if context_document.is_html_document() {
3834 return Ok(self.html_serialize(
3835 cx,
3836 html_serialize::TraversalScope::ChildrenOnly(None),
3837 false,
3838 vec![],
3839 ));
3840 }
3841
3842 let _ = require_well_formed;
3845 self.xml_serialize(xml_serialize::TraversalScope::ChildrenOnly(None))
3846 }
3847
3848 fn get_next_sibling_unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, Node>> {
3849 self.next_sibling.get_unrooted(no_gc)
3850 }
3851
3852 fn get_previous_sibling_unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, Node>> {
3853 self.prev_sibling.get_unrooted(no_gc)
3854 }
3855
3856 fn get_first_child_unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, Node>> {
3857 self.first_child.get_unrooted(no_gc)
3858 }
3859
3860 fn compare_dom_tree_position(&self, other: &Node, common_ancestor: &Node) -> Ordering {
3862 debug_assert!(
3863 self.inclusive_ancestors(ShadowIncluding::No)
3864 .any(|ancestor| &*ancestor == common_ancestor)
3865 );
3866 debug_assert!(
3867 other
3868 .inclusive_ancestors(ShadowIncluding::No)
3869 .any(|ancestor| &*ancestor == common_ancestor)
3870 );
3871
3872 if self == other {
3873 return Ordering::Equal;
3874 }
3875
3876 if self == common_ancestor {
3877 return Ordering::Less;
3878 }
3879 if other == common_ancestor {
3880 return Ordering::Greater;
3881 }
3882
3883 let my_ancestors: Vec<_> = self
3884 .inclusive_ancestors(ShadowIncluding::No)
3885 .take_while(|ancestor| &**ancestor != common_ancestor)
3886 .collect();
3887 let other_ancestors: Vec<_> = other
3888 .inclusive_ancestors(ShadowIncluding::No)
3889 .take_while(|ancestor| &**ancestor != common_ancestor)
3890 .collect();
3891
3892 let mut i = my_ancestors.len() - 1;
3894 let mut j = other_ancestors.len() - 1;
3895
3896 while my_ancestors[i] == other_ancestors[j] {
3897 if i == 0 {
3898 debug_assert_ne!(j, 0, "Equal inclusive ancestors but nodes are not equal?");
3900 return Ordering::Less;
3901 }
3902 if j == 0 {
3903 return Ordering::Greater;
3905 }
3906
3907 i -= 1;
3908 j -= 1;
3909 }
3910
3911 if my_ancestors[i]
3914 .preceding_siblings()
3915 .any(|sibling| sibling == other_ancestors[j])
3916 {
3917 Ordering::Greater
3919 } else {
3920 debug_assert!(
3922 other_ancestors[j]
3923 .preceding_siblings()
3924 .any(|sibling| sibling == my_ancestors[i])
3925 );
3926 Ordering::Less
3927 }
3928 }
3929}
3930
3931impl NodeMethods<crate::DomTypeHolder> for Node {
3932 fn NodeType(&self) -> u16 {
3934 match self.type_id() {
3935 NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
3936 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3937 NodeConstants::TEXT_NODE
3938 },
3939 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3940 NodeConstants::CDATA_SECTION_NODE
3941 },
3942 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3943 NodeConstants::PROCESSING_INSTRUCTION_NODE
3944 },
3945 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE,
3946 NodeTypeId::Document(_) => NodeConstants::DOCUMENT_NODE,
3947 NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE,
3948 NodeTypeId::DocumentFragment(_) => NodeConstants::DOCUMENT_FRAGMENT_NODE,
3949 NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE,
3950 }
3951 }
3952
3953 fn NodeName(&self) -> DOMString {
3955 match self.type_id() {
3956 NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
3957 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
3958 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
3959 DOMString::from("#text")
3960 },
3961 NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
3962 DOMString::from("#cdata-section")
3963 },
3964 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
3965 self.downcast::<ProcessingInstruction>().unwrap().Target()
3966 },
3967 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => DOMString::from("#comment"),
3968 NodeTypeId::DocumentType => self.downcast::<DocumentType>().unwrap().name().clone(),
3969 NodeTypeId::DocumentFragment(_) => DOMString::from("#document-fragment"),
3970 NodeTypeId::Document(_) => DOMString::from("#document"),
3971 }
3972 }
3973
3974 fn BaseURI(&self) -> USVString {
3976 USVString(String::from(self.owner_doc().base_url().as_str()))
3977 }
3978
3979 fn IsConnected(&self) -> bool {
3981 self.is_connected()
3982 }
3983
3984 fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
3986 match self.type_id() {
3987 NodeTypeId::Document(_) => None,
3988 _ => Some(self.owner_doc()),
3989 }
3990 }
3991
3992 fn GetRootNode(&self, options: &GetRootNodeOptions) -> DomRoot<Node> {
3994 if !options.composed {
3995 if let Some(shadow_root) = self.containing_shadow_root() {
3996 return DomRoot::upcast(shadow_root);
3997 }
3998 }
3999
4000 if self.is_connected() {
4001 DomRoot::from_ref(self.owner_doc().upcast::<Node>())
4002 } else {
4003 self.inclusive_ancestors(ShadowIncluding::Yes)
4004 .last()
4005 .unwrap()
4006 }
4007 }
4008
4009 fn GetParentNode(&self) -> Option<DomRoot<Node>> {
4011 self.parent_node.get()
4012 }
4013
4014 fn GetParentElement(&self) -> Option<DomRoot<Element>> {
4016 self.GetParentNode().and_then(DomRoot::downcast)
4017 }
4018
4019 fn HasChildNodes(&self) -> bool {
4021 self.first_child.get().is_some()
4022 }
4023
4024 fn ChildNodes(&self, cx: &mut JSContext) -> DomRoot<NodeList> {
4026 if let Some(list) = self.ensure_rare_data().child_list.get() {
4027 return list;
4028 }
4029
4030 let doc = self.owner_doc();
4031 let window = doc.window();
4032 let list = NodeList::new_child_list(window, self, CanGc::from_cx(cx));
4033 self.ensure_rare_data().child_list.set(Some(&list));
4034 list
4035 }
4036
4037 fn GetFirstChild(&self) -> Option<DomRoot<Node>> {
4039 self.first_child.get()
4040 }
4041
4042 fn GetLastChild(&self) -> Option<DomRoot<Node>> {
4044 self.last_child.get()
4045 }
4046
4047 fn GetPreviousSibling(&self) -> Option<DomRoot<Node>> {
4049 self.prev_sibling.get()
4050 }
4051
4052 fn GetNextSibling(&self) -> Option<DomRoot<Node>> {
4054 self.next_sibling.get()
4055 }
4056
4057 fn GetNodeValue(&self) -> Option<DOMString> {
4059 match self.type_id() {
4060 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
4061 NodeTypeId::CharacterData(_) => {
4062 self.downcast::<CharacterData>().map(CharacterData::Data)
4063 },
4064 _ => None,
4065 }
4066 }
4067
4068 fn SetNodeValue(&self, cx: &mut JSContext, val: Option<DOMString>) -> Fallible<()> {
4070 match self.type_id() {
4071 NodeTypeId::Attr => {
4072 let attr = self.downcast::<Attr>().unwrap();
4073 attr.SetValue(cx, val.unwrap_or_default())?;
4074 },
4075 NodeTypeId::CharacterData(_) => {
4076 let character_data = self.downcast::<CharacterData>().unwrap();
4077 character_data.SetData(val.unwrap_or_default());
4078 },
4079 _ => {},
4080 };
4081 Ok(())
4082 }
4083
4084 fn GetTextContent(&self) -> Option<DOMString> {
4086 match self.type_id() {
4087 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
4088 let content =
4089 Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
4090 Some(content)
4091 },
4092 NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
4093 NodeTypeId::CharacterData(..) => {
4094 let characterdata = self.downcast::<CharacterData>().unwrap();
4095 Some(characterdata.Data())
4096 },
4097 NodeTypeId::DocumentType | NodeTypeId::Document(_) => None,
4098 }
4099 }
4100
4101 fn SetTextContent(&self, cx: &mut JSContext, value: Option<DOMString>) -> Fallible<()> {
4103 match self.type_id() {
4104 NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
4105 self.set_text_content_for_element(cx, value);
4106 },
4107 NodeTypeId::Attr => {
4108 let attr = self.downcast::<Attr>().unwrap();
4109 attr.SetValue(cx, value.unwrap_or_default())?;
4110 },
4111 NodeTypeId::CharacterData(..) => {
4112 let characterdata = self.downcast::<CharacterData>().unwrap();
4113 characterdata.SetData(value.unwrap_or_default());
4114 },
4115 NodeTypeId::DocumentType | NodeTypeId::Document(_) => {},
4116 };
4117 Ok(())
4118 }
4119
4120 fn InsertBefore(
4122 &self,
4123 cx: &mut JSContext,
4124 node: &Node,
4125 child: Option<&Node>,
4126 ) -> Fallible<DomRoot<Node>> {
4127 Node::pre_insert(cx, node, self, child)
4128 }
4129
4130 fn AppendChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
4132 Node::pre_insert(cx, node, self, None)
4133 }
4134
4135 fn ReplaceChild(
4137 &self,
4138 cx: &mut JSContext,
4139 node: &Node,
4140 child: &Node,
4141 ) -> Fallible<DomRoot<Node>> {
4142 match self.type_id() {
4145 NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
4146 },
4147 _ => return Err(Error::HierarchyRequest(None)),
4148 }
4149
4150 if node.is_inclusive_ancestor_of(self) {
4153 return Err(Error::HierarchyRequest(None));
4154 }
4155
4156 if !self.is_parent_of(child) {
4158 return Err(Error::NotFound(None));
4159 }
4160
4161 match node.type_id() {
4166 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
4167 return Err(Error::HierarchyRequest(None));
4168 },
4169 NodeTypeId::DocumentType if !self.is::<Document>() => {
4170 return Err(Error::HierarchyRequest(None));
4171 },
4172 NodeTypeId::Document(_) | NodeTypeId::Attr => {
4173 return Err(Error::HierarchyRequest(None));
4174 },
4175 _ => (),
4176 }
4177
4178 if self.is::<Document>() {
4181 match node.type_id() {
4182 NodeTypeId::DocumentFragment(_) => {
4184 if node.children_unrooted(cx.no_gc()).any(|c| c.is::<Text>()) {
4186 return Err(Error::HierarchyRequest(None));
4187 }
4188 match node.child_elements_unrooted(cx.no_gc()).count() {
4189 0 => (),
4190 1 => {
4192 if self
4193 .child_elements_unrooted(cx.no_gc())
4194 .any(|c| c.upcast::<Node>() != child)
4195 {
4196 return Err(Error::HierarchyRequest(None));
4197 }
4198 if child.following_siblings().any(|child| child.is_doctype()) {
4199 return Err(Error::HierarchyRequest(None));
4200 }
4201 },
4202 _ => return Err(Error::HierarchyRequest(None)),
4204 }
4205 },
4206 NodeTypeId::Element(..) => {
4208 if self
4209 .child_elements_unrooted(cx.no_gc())
4210 .any(|c| c.upcast::<Node>() != child)
4211 {
4212 return Err(Error::HierarchyRequest(None));
4213 }
4214 if child.following_siblings().any(|child| child.is_doctype()) {
4215 return Err(Error::HierarchyRequest(None));
4216 }
4217 },
4218 NodeTypeId::DocumentType => {
4220 if self
4221 .children_unrooted(cx.no_gc())
4222 .any(|c| c.is_doctype() && *c != child)
4223 {
4224 return Err(Error::HierarchyRequest(None));
4225 }
4226 if self
4227 .children_unrooted(cx.no_gc())
4228 .take_while(|c| **c != child)
4229 .any(|c| c.is::<Element>())
4230 {
4231 return Err(Error::HierarchyRequest(None));
4232 }
4233 },
4234 NodeTypeId::CharacterData(..) => (),
4235 NodeTypeId::Document(_) => unreachable!(),
4238 NodeTypeId::Attr => unreachable!(),
4239 }
4240 }
4241
4242 let child_next_sibling = child.GetNextSibling();
4245 let node_next_sibling = node.GetNextSibling();
4246 let reference_child = if child_next_sibling.as_deref() == Some(node) {
4247 node_next_sibling.as_deref()
4248 } else {
4249 child_next_sibling.as_deref()
4250 };
4251
4252 let previous_sibling = child.GetPreviousSibling();
4254
4255 let document = self.owner_document();
4259 Node::adopt(cx, node, &document);
4260
4261 let removed_child = if node != child {
4266 Node::remove(cx, child, self, SuppressObserver::Suppressed);
4268 Some(child)
4269 } else {
4270 None
4271 };
4272
4273 rooted_vec!(let mut nodes);
4275 let nodes = if node.type_id() ==
4276 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
4277 node.type_id() == NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot)
4278 {
4279 nodes.extend(node.children().map(|node| Dom::from_ref(&*node)));
4280 nodes.r()
4281 } else {
4282 from_ref(&node)
4283 };
4284
4285 Node::insert(
4287 cx,
4288 node,
4289 self,
4290 reference_child,
4291 SuppressObserver::Suppressed,
4292 );
4293
4294 vtable_for(self).children_changed(
4295 cx,
4296 &ChildrenMutation::replace(
4297 previous_sibling.as_deref(),
4298 &removed_child,
4299 nodes,
4300 reference_child,
4301 ),
4302 );
4303
4304 let removed = removed_child.map(|r| [r]);
4307 let mutation = LazyCell::new(|| Mutation::ChildList {
4308 added: Some(nodes),
4309 removed: removed.as_ref().map(|r| &r[..]),
4310 prev: previous_sibling.as_deref(),
4311 next: reference_child,
4312 });
4313
4314 MutationObserver::queue_a_mutation_record(self, mutation);
4315
4316 Ok(DomRoot::from_ref(child))
4318 }
4319
4320 fn RemoveChild(&self, cx: &mut JSContext, node: &Node) -> Fallible<DomRoot<Node>> {
4322 Node::pre_remove(cx, node, self)
4323 }
4324
4325 fn Normalize(&self, cx: &mut JSContext) {
4327 let mut children = self.children().enumerate().peekable();
4328 while let Some((_, node)) = children.next() {
4329 if let Some(text) = node.downcast::<Text>() {
4330 if text.is::<CDATASection>() {
4331 continue;
4332 }
4333 let cdata = text.upcast::<CharacterData>();
4334 let mut length = cdata.Length();
4335 if length == 0 {
4336 Node::remove(cx, &node, self, SuppressObserver::Unsuppressed);
4337 continue;
4338 }
4339 while children.peek().is_some_and(|(_, sibling)| {
4340 sibling.is::<Text>() && !sibling.is::<CDATASection>()
4341 }) {
4342 let (index, sibling) = children.next().unwrap();
4343 sibling
4344 .ranges()
4345 .drain_to_preceding_text_sibling(&sibling, &node, length);
4346 self.ranges()
4347 .move_to_text_child_at(self, index as u32, &node, length);
4348 let sibling_cdata = sibling.downcast::<CharacterData>().unwrap();
4349 length += sibling_cdata.Length();
4350 cdata.append_data(&sibling_cdata.data());
4351 Node::remove(cx, &sibling, self, SuppressObserver::Unsuppressed);
4352 }
4353 } else {
4354 node.Normalize(cx);
4355 }
4356 }
4357 }
4358
4359 fn CloneNode(&self, cx: &mut JSContext, subtree: bool) -> Fallible<DomRoot<Node>> {
4361 if self.is::<ShadowRoot>() {
4363 return Err(Error::NotSupported(None));
4364 }
4365
4366 let result = Node::clone(
4368 cx,
4369 self,
4370 None,
4371 if subtree {
4372 CloneChildrenFlag::CloneChildren
4373 } else {
4374 CloneChildrenFlag::DoNotCloneChildren
4375 },
4376 None,
4377 );
4378 Ok(result)
4379 }
4380
4381 fn IsEqualNode(&self, maybe_node: Option<&Node>) -> bool {
4383 fn is_equal_doctype(node: &Node, other: &Node) -> bool {
4384 let doctype = node.downcast::<DocumentType>().unwrap();
4385 let other_doctype = other.downcast::<DocumentType>().unwrap();
4386 (*doctype.name() == *other_doctype.name()) &&
4387 (*doctype.public_id() == *other_doctype.public_id()) &&
4388 (*doctype.system_id() == *other_doctype.system_id())
4389 }
4390 fn is_equal_element(node: &Node, other: &Node) -> bool {
4391 let element = node.downcast::<Element>().unwrap();
4392 let other_element = other.downcast::<Element>().unwrap();
4393 (*element.namespace() == *other_element.namespace()) &&
4394 (*element.prefix() == *other_element.prefix()) &&
4395 (*element.local_name() == *other_element.local_name()) &&
4396 (element.attrs().len() == other_element.attrs().len())
4397 }
4398 fn is_equal_processinginstruction(node: &Node, other: &Node) -> bool {
4399 let pi = node.downcast::<ProcessingInstruction>().unwrap();
4400 let other_pi = other.downcast::<ProcessingInstruction>().unwrap();
4401 (*pi.target() == *other_pi.target()) &&
4402 (*pi.upcast::<CharacterData>().data() ==
4403 *other_pi.upcast::<CharacterData>().data())
4404 }
4405 fn is_equal_characterdata(node: &Node, other: &Node) -> bool {
4406 let characterdata = node.downcast::<CharacterData>().unwrap();
4407 let other_characterdata = other.downcast::<CharacterData>().unwrap();
4408 *characterdata.data() == *other_characterdata.data()
4409 }
4410 fn is_equal_attr(node: &Node, other: &Node) -> bool {
4411 let attr = node.downcast::<Attr>().unwrap();
4412 let other_attr = other.downcast::<Attr>().unwrap();
4413 (*attr.namespace() == *other_attr.namespace()) &&
4414 (attr.local_name() == other_attr.local_name()) &&
4415 (**attr.value() == **other_attr.value())
4416 }
4417 fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
4418 let element = node.downcast::<Element>().unwrap();
4419 let other_element = other.downcast::<Element>().unwrap();
4420 assert!(element.attrs().len() == other_element.attrs().len());
4421 element.attrs().iter().all(|attr| {
4422 other_element.attrs().iter().any(|other_attr| {
4423 (*attr.namespace() == *other_attr.namespace()) &&
4424 (attr.local_name() == other_attr.local_name()) &&
4425 (**attr.value() == **other_attr.value())
4426 })
4427 })
4428 }
4429
4430 fn is_equal_node(this: &Node, node: &Node) -> bool {
4431 if this.NodeType() != node.NodeType() {
4433 return false;
4434 }
4435
4436 match node.type_id() {
4437 NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false,
4439 NodeTypeId::Element(..) if !is_equal_element(this, node) => return false,
4440 NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction)
4441 if !is_equal_processinginstruction(this, node) =>
4442 {
4443 return false;
4444 },
4445 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) |
4446 NodeTypeId::CharacterData(CharacterDataTypeId::Comment)
4447 if !is_equal_characterdata(this, node) =>
4448 {
4449 return false;
4450 },
4451 NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
4453 NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
4454
4455 _ => (),
4456 }
4457
4458 if this.children_count() != node.children_count() {
4460 return false;
4461 }
4462
4463 this.children()
4465 .zip(node.children())
4466 .all(|(child, other_child)| is_equal_node(&child, &other_child))
4467 }
4468 match maybe_node {
4469 None => false,
4471 Some(node) => is_equal_node(self, node),
4473 }
4474 }
4475
4476 fn IsSameNode(&self, other_node: Option<&Node>) -> bool {
4478 match other_node {
4479 Some(node) => self == node,
4480 None => false,
4481 }
4482 }
4483
4484 fn CompareDocumentPosition(&self, other: &Node) -> u16 {
4486 if self == other {
4488 return 0;
4489 }
4490
4491 let mut node1 = Some(other);
4493 let mut node2 = Some(self);
4494
4495 let mut attr1: Option<&Attr> = None;
4497 let mut attr2: Option<&Attr> = None;
4498
4499 let attr1owner;
4504 if let Some(a) = other.downcast::<Attr>() {
4505 attr1 = Some(a);
4506 attr1owner = a.GetOwnerElement();
4507 node1 = match attr1owner {
4508 Some(ref e) => Some(e.upcast()),
4509 None => None,
4510 }
4511 }
4512
4513 let attr2owner;
4516 if let Some(a) = self.downcast::<Attr>() {
4517 attr2 = Some(a);
4518 attr2owner = a.GetOwnerElement();
4519 node2 = match attr2owner {
4520 Some(ref e) => Some(e.upcast()),
4521 None => None,
4522 }
4523 }
4524
4525 if let Some(node2) = node2 {
4530 if Some(node2) == node1 {
4531 if let (Some(a1), Some(a2)) = (attr1, attr2) {
4532 let attrs = node2.downcast::<Element>().unwrap().attrs();
4533 for attr in attrs.iter() {
4537 if (*attr.namespace() == *a1.namespace()) &&
4538 (attr.local_name() == a1.local_name()) &&
4539 (**attr.value() == **a1.value())
4540 {
4541 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4542 NodeConstants::DOCUMENT_POSITION_PRECEDING;
4543 }
4544 if (*attr.namespace() == *a2.namespace()) &&
4545 (attr.local_name() == a2.local_name()) &&
4546 (**attr.value() == **a2.value())
4547 {
4548 return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
4549 NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4550 }
4551 }
4552 unreachable!();
4555 }
4556 }
4557 }
4558
4559 match (node1, node2) {
4561 (None, _) => {
4562 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4564 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4565 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4566 },
4567 (_, None) => {
4568 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4570 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4571 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
4572 },
4573 (Some(node1), Some(node2)) => {
4574 let mut self_and_ancestors = node2
4576 .inclusive_ancestors(ShadowIncluding::No)
4577 .collect::<SmallVec<[_; 20]>>();
4578 let mut other_and_ancestors = node1
4579 .inclusive_ancestors(ShadowIncluding::No)
4580 .collect::<SmallVec<[_; 20]>>();
4581
4582 if self_and_ancestors.last() != other_and_ancestors.last() {
4583 let random = as_uintptr(self_and_ancestors.last().unwrap()) <
4584 as_uintptr(other_and_ancestors.last().unwrap());
4585 let random = if random {
4586 NodeConstants::DOCUMENT_POSITION_FOLLOWING
4587 } else {
4588 NodeConstants::DOCUMENT_POSITION_PRECEDING
4589 };
4590
4591 return random +
4593 NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
4594 NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
4595 }
4596 let mut parent = self_and_ancestors.pop().unwrap();
4598 other_and_ancestors.pop().unwrap();
4599
4600 let mut current_position =
4601 cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
4602
4603 while current_position > 0 {
4604 current_position -= 1;
4605 let child_1 = self_and_ancestors.pop().unwrap();
4606 let child_2 = other_and_ancestors.pop().unwrap();
4607
4608 if child_1 != child_2 {
4609 for child in parent.children() {
4610 if child == child_1 {
4611 return NodeConstants::DOCUMENT_POSITION_FOLLOWING;
4613 }
4614 if child == child_2 {
4615 return NodeConstants::DOCUMENT_POSITION_PRECEDING;
4617 }
4618 }
4619 }
4620
4621 parent = child_1;
4622 }
4623
4624 if self_and_ancestors.len() < other_and_ancestors.len() {
4629 NodeConstants::DOCUMENT_POSITION_FOLLOWING +
4630 NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
4631 } else {
4632 NodeConstants::DOCUMENT_POSITION_PRECEDING +
4633 NodeConstants::DOCUMENT_POSITION_CONTAINS
4634 }
4635 },
4636 }
4637 }
4638
4639 fn Contains(&self, maybe_other: Option<&Node>) -> bool {
4641 match maybe_other {
4642 None => false,
4643 Some(other) => self.is_inclusive_ancestor_of(other),
4644 }
4645 }
4646
4647 fn LookupPrefix(&self, namespace: Option<DOMString>) -> Option<DOMString> {
4649 let namespace = namespace_from_domstring(namespace);
4650
4651 if namespace == ns!() {
4653 return None;
4654 }
4655
4656 match self.type_id() {
4658 NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().lookup_prefix(namespace),
4659 NodeTypeId::Document(_) => self
4660 .downcast::<Document>()
4661 .unwrap()
4662 .GetDocumentElement()
4663 .and_then(|element| element.lookup_prefix(namespace)),
4664 NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
4665 NodeTypeId::Attr => self
4666 .downcast::<Attr>()
4667 .unwrap()
4668 .GetOwnerElement()
4669 .and_then(|element| element.lookup_prefix(namespace)),
4670 _ => self
4671 .GetParentElement()
4672 .and_then(|element| element.lookup_prefix(namespace)),
4673 }
4674 }
4675
4676 fn LookupNamespaceURI(&self, prefix: Option<DOMString>) -> Option<DOMString> {
4678 let prefix = prefix.filter(|prefix| !prefix.is_empty());
4680
4681 Node::namespace_to_string(Node::locate_namespace(self, prefix))
4683 }
4684
4685 fn IsDefaultNamespace(&self, namespace: Option<DOMString>) -> bool {
4687 let namespace = namespace_from_domstring(namespace);
4689 Node::locate_namespace(self, None) == namespace
4691 }
4692}
4693
4694pub(crate) trait NodeTraits {
4695 fn owner_document(&self) -> DomRoot<Document>;
4699 fn owner_window(&self) -> DomRoot<Window>;
4703 fn owner_global(&self) -> DomRoot<GlobalScope>;
4707 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>>;
4709 fn stylesheet_list_owner(&self) -> StyleSheetListOwner;
4712}
4713
4714impl<T: DerivedFrom<Node> + DomObject> NodeTraits for T {
4715 fn owner_document(&self) -> DomRoot<Document> {
4716 self.upcast().owner_doc()
4717 }
4718
4719 fn owner_window(&self) -> DomRoot<Window> {
4720 DomRoot::from_ref(self.owner_document().window())
4721 }
4722
4723 fn owner_global(&self) -> DomRoot<GlobalScope> {
4724 DomRoot::from_ref(self.owner_window().upcast())
4725 }
4726
4727 fn containing_shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
4728 Node::containing_shadow_root(self.upcast())
4729 }
4730
4731 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
4732 fn stylesheet_list_owner(&self) -> StyleSheetListOwner {
4733 self.containing_shadow_root()
4734 .map(|shadow_root| StyleSheetListOwner::ShadowRoot(Dom::from_ref(&*shadow_root)))
4735 .unwrap_or_else(|| {
4736 StyleSheetListOwner::Document(Dom::from_ref(&*self.owner_document()))
4737 })
4738 }
4739}
4740
4741impl VirtualMethods for Node {
4742 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4743 Some(self.upcast::<EventTarget>() as &dyn VirtualMethods)
4744 }
4745
4746 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4747 if let Some(s) = self.super_type() {
4748 s.children_changed(cx, mutation);
4749 }
4750
4751 if let Some(data) = self.rare_data().as_ref() {
4752 if let Some(list) = data.child_list.get() {
4753 list.as_children_list().children_changed(mutation);
4754 }
4755 }
4756
4757 self.owner_doc().content_and_heritage_changed(self);
4758 }
4759
4760 fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
4763 self.super_type().unwrap().unbind_from_tree(cx, context);
4764
4765 if !self.is_in_a_shadow_tree() && !self.ranges_is_empty() {
4770 self.ranges()
4771 .drain_to_parent(context.parent, context.index(), self);
4772 }
4773 }
4774
4775 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
4776 if let Some(super_type) = self.super_type() {
4777 super_type.moving_steps(cx, context);
4778 }
4779
4780 if let Some(old_parent) = context.old_parent {
4785 if !self.is_in_a_shadow_tree() && !self.ranges_is_empty() {
4786 self.ranges()
4787 .drain_to_parent(old_parent, context.index(), self);
4788 }
4789 }
4790
4791 self.owner_doc().content_and_heritage_changed(self);
4792 }
4793
4794 fn handle_event(&self, cx: &mut js::context::JSContext, event: &Event) {
4795 if event.DefaultPrevented() || event.flags().contains(EventFlags::Handled) {
4796 return;
4797 }
4798
4799 if let Some(event) = event.downcast::<KeyboardEvent>() {
4800 self.owner_document()
4801 .event_handler()
4802 .run_default_keyboard_event_handler(cx, self, event);
4803 }
4804 }
4805}
4806
4807#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
4809pub(crate) enum NodeDamage {
4810 Style,
4812 ContentOrHeritage,
4815 Other,
4817}
4818
4819pub(crate) enum ChildrenMutation<'a> {
4820 Append {
4821 prev: &'a Node,
4822 added: &'a [&'a Node],
4823 },
4824 Insert {
4825 prev: &'a Node,
4826 added: &'a [&'a Node],
4827 next: &'a Node,
4828 },
4829 Prepend {
4830 added: &'a [&'a Node],
4831 next: &'a Node,
4832 },
4833 Replace {
4834 prev: Option<&'a Node>,
4835 removed: &'a Node,
4836 added: &'a [&'a Node],
4837 next: Option<&'a Node>,
4838 },
4839 ReplaceAll {
4840 removed: &'a [&'a Node],
4841 added: &'a [&'a Node],
4842 },
4843 ChangeText,
4848}
4849
4850impl<'a> ChildrenMutation<'a> {
4851 fn insert(
4852 prev: Option<&'a Node>,
4853 added: &'a [&'a Node],
4854 next: Option<&'a Node>,
4855 ) -> ChildrenMutation<'a> {
4856 match (prev, next) {
4857 (None, None) => ChildrenMutation::ReplaceAll {
4858 removed: &[],
4859 added,
4860 },
4861 (Some(prev), None) => ChildrenMutation::Append { prev, added },
4862 (None, Some(next)) => ChildrenMutation::Prepend { added, next },
4863 (Some(prev), Some(next)) => ChildrenMutation::Insert { prev, added, next },
4864 }
4865 }
4866
4867 fn replace(
4868 prev: Option<&'a Node>,
4869 removed: &'a Option<&'a Node>,
4870 added: &'a [&'a Node],
4871 next: Option<&'a Node>,
4872 ) -> ChildrenMutation<'a> {
4873 if let Some(ref removed) = *removed {
4874 if let (None, None) = (prev, next) {
4875 ChildrenMutation::ReplaceAll {
4876 removed: from_ref(removed),
4877 added,
4878 }
4879 } else {
4880 ChildrenMutation::Replace {
4881 prev,
4882 removed,
4883 added,
4884 next,
4885 }
4886 }
4887 } else {
4888 ChildrenMutation::insert(prev, added, next)
4889 }
4890 }
4891
4892 fn replace_all(removed: &'a [&'a Node], added: &'a [&'a Node]) -> ChildrenMutation<'a> {
4893 ChildrenMutation::ReplaceAll { removed, added }
4894 }
4895
4896 pub(crate) fn next_child(&self) -> Option<&Node> {
4901 match *self {
4902 ChildrenMutation::Append { .. } => None,
4903 ChildrenMutation::Insert { next, .. } => Some(next),
4904 ChildrenMutation::Prepend { next, .. } => Some(next),
4905 ChildrenMutation::Replace { next, .. } => next,
4906 ChildrenMutation::ReplaceAll { .. } => None,
4907 ChildrenMutation::ChangeText => None,
4908 }
4909 }
4910
4911 pub(crate) fn modified_edge_element(&self, no_gc: &NoGC) -> Option<DomRoot<Node>> {
4918 match *self {
4919 ChildrenMutation::Prepend { next, .. } |
4921 ChildrenMutation::Replace {
4922 prev: None,
4923 next: Some(next),
4924 ..
4925 } => next
4926 .inclusively_following_siblings_unrooted(no_gc)
4927 .find(|node| node.is::<Element>())
4928 .map(|node| node.as_rooted()),
4929 ChildrenMutation::Append { prev, .. } |
4931 ChildrenMutation::Replace {
4932 prev: Some(prev),
4933 next: None,
4934 ..
4935 } => prev
4936 .inclusively_preceding_siblings_unrooted(no_gc)
4937 .find(|node| node.is::<Element>())
4938 .map(|node| node.as_rooted()),
4939 ChildrenMutation::Insert { prev, next, .. } |
4941 ChildrenMutation::Replace {
4942 prev: Some(prev),
4943 next: Some(next),
4944 ..
4945 } => {
4946 if prev
4947 .inclusively_preceding_siblings_unrooted(no_gc)
4948 .all(|node| !node.is::<Element>())
4949 {
4950 next.inclusively_following_siblings_unrooted(no_gc)
4952 .find(|node| node.is::<Element>())
4953 .map(|node| node.as_rooted())
4954 } else if next
4955 .inclusively_following_siblings_unrooted(no_gc)
4956 .all(|node| !node.is::<Element>())
4957 {
4958 prev.inclusively_preceding_siblings_unrooted(no_gc)
4960 .find(|node| node.is::<Element>())
4961 .map(|node| node.as_rooted())
4962 } else {
4963 None
4964 }
4965 },
4966
4967 ChildrenMutation::Replace {
4968 prev: None,
4969 next: None,
4970 ..
4971 } => unreachable!(),
4972 ChildrenMutation::ReplaceAll { .. } => None,
4973 ChildrenMutation::ChangeText => None,
4974 }
4975 }
4976}
4977
4978pub(crate) struct BindContext<'a> {
4980 pub(crate) parent: &'a Node,
4982
4983 pub(crate) tree_connected: bool,
4987
4988 pub(crate) tree_is_in_a_document_tree: bool,
4992
4993 pub(crate) tree_is_in_a_shadow_tree: bool,
4995
4996 pub(crate) is_shadow_tree: IsShadowTree,
5001}
5002
5003#[derive(Debug, Eq, PartialEq)]
5004pub(crate) enum IsShadowTree {
5005 Yes,
5006 No,
5007}
5008
5009impl<'a> BindContext<'a> {
5010 pub(crate) fn new(parent: &'a Node, is_shadow_tree: IsShadowTree) -> Self {
5012 BindContext {
5013 parent,
5014 tree_connected: parent.is_connected(),
5015 tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
5016 tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
5017 is_shadow_tree,
5018 }
5019 }
5020
5021 pub(crate) fn is_in_tree(&self) -> bool {
5023 self.tree_is_in_a_document_tree || self.tree_is_in_a_shadow_tree
5024 }
5025}
5026
5027pub(crate) struct UnbindContext<'a> {
5030 index: Cell<Option<u32>>,
5032 pub(crate) parent: &'a Node,
5034 prev_sibling: Option<&'a Node>,
5036 pub(crate) next_sibling: Option<&'a Node>,
5038
5039 pub(crate) tree_connected: bool,
5043
5044 pub(crate) tree_is_in_a_document_tree: bool,
5048
5049 pub(crate) tree_is_in_a_shadow_tree: bool,
5051}
5052
5053impl<'a> UnbindContext<'a> {
5054 pub(crate) fn new(
5056 parent: &'a Node,
5057 prev_sibling: Option<&'a Node>,
5058 next_sibling: Option<&'a Node>,
5059 cached_index: Option<u32>,
5060 ) -> Self {
5061 UnbindContext {
5062 index: Cell::new(cached_index),
5063 parent,
5064 prev_sibling,
5065 next_sibling,
5066 tree_connected: parent.is_connected(),
5067 tree_is_in_a_document_tree: parent.is_in_a_document_tree(),
5068 tree_is_in_a_shadow_tree: parent.is_in_a_shadow_tree(),
5069 }
5070 }
5071
5072 pub(crate) fn index(&self) -> u32 {
5074 if let Some(index) = self.index.get() {
5075 return index;
5076 }
5077 let index = self.prev_sibling.map_or(0, |sibling| sibling.index() + 1);
5078 self.index.set(Some(index));
5079 index
5080 }
5081}
5082
5083pub(crate) struct MoveContext<'a> {
5086 index: Cell<Option<u32>>,
5088 pub(crate) old_parent: Option<&'a Node>,
5090 prev_sibling: Option<&'a Node>,
5092 pub(crate) next_sibling: Option<&'a Node>,
5094}
5095
5096impl<'a> MoveContext<'a> {
5097 pub(crate) fn new(
5099 old_parent: Option<&'a Node>,
5100 prev_sibling: Option<&'a Node>,
5101 next_sibling: Option<&'a Node>,
5102 cached_index: Option<u32>,
5103 ) -> Self {
5104 MoveContext {
5105 index: Cell::new(cached_index),
5106 old_parent,
5107 prev_sibling,
5108 next_sibling,
5109 }
5110 }
5111
5112 pub(crate) fn index(&self) -> u32 {
5114 if let Some(index) = self.index.get() {
5115 return index;
5116 }
5117 let index = self.prev_sibling.map_or(0, |sibling| sibling.index() + 1);
5118 self.index.set(Some(index));
5119 index
5120 }
5121}
5122
5123pub(crate) struct UniqueId {
5125 cell: UnsafeCell<Option<Box<Uuid>>>,
5126}
5127
5128unsafe_no_jsmanaged_fields!(UniqueId);
5129
5130impl MallocSizeOf for UniqueId {
5131 #[expect(unsafe_code)]
5132 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
5133 if let Some(uuid) = unsafe { &*self.cell.get() } {
5134 unsafe { ops.malloc_size_of(&**uuid) }
5135 } else {
5136 0
5137 }
5138 }
5139}
5140
5141impl UniqueId {
5142 fn new() -> UniqueId {
5144 UniqueId {
5145 cell: UnsafeCell::new(None),
5146 }
5147 }
5148
5149 #[expect(unsafe_code)]
5151 fn borrow(&self) -> &Uuid {
5152 unsafe {
5153 let ptr = self.cell.get();
5154 if (*ptr).is_none() {
5155 *ptr = Some(Box::new(Uuid::new_v4()));
5156 }
5157 (*ptr).as_ref().unwrap()
5158 }
5159 }
5160}
5161
5162pub(crate) struct NodeTypeIdWrapper(pub(crate) NodeTypeId);
5163
5164impl From<NodeTypeIdWrapper> for LayoutNodeType {
5165 #[inline(always)]
5166 fn from(node_type: NodeTypeIdWrapper) -> LayoutNodeType {
5167 match node_type.0 {
5168 NodeTypeId::Element(e) => LayoutNodeType::Element(ElementTypeIdWrapper(e).into()),
5169 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => LayoutNodeType::Text,
5170 x => unreachable!("Layout should not traverse nodes of type {:?}", x),
5171 }
5172 }
5173}
5174
5175struct ElementTypeIdWrapper(ElementTypeId);
5176
5177impl From<ElementTypeIdWrapper> for LayoutElementType {
5178 #[inline(always)]
5179 fn from(element_type: ElementTypeIdWrapper) -> LayoutElementType {
5180 match element_type.0 {
5181 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement) => {
5182 LayoutElementType::HTMLBodyElement
5183 },
5184 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBRElement) => {
5185 LayoutElementType::HTMLBRElement
5186 },
5187 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement) => {
5188 LayoutElementType::HTMLCanvasElement
5189 },
5190 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHtmlElement) => {
5191 LayoutElementType::HTMLHtmlElement
5192 },
5193 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement) => {
5194 LayoutElementType::HTMLIFrameElement
5195 },
5196 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement) => {
5197 LayoutElementType::HTMLImageElement
5198 },
5199 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(_)) => {
5200 LayoutElementType::HTMLMediaElement
5201 },
5202 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement) => {
5203 LayoutElementType::HTMLInputElement
5204 },
5205 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement) => {
5206 LayoutElementType::HTMLOptGroupElement
5207 },
5208 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement) => {
5209 LayoutElementType::HTMLOptionElement
5210 },
5211 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement) => {
5212 LayoutElementType::HTMLObjectElement
5213 },
5214 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLParagraphElement) => {
5215 LayoutElementType::HTMLParagraphElement
5216 },
5217 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLPreElement) => {
5218 LayoutElementType::HTMLPreElement
5219 },
5220 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement) => {
5221 LayoutElementType::HTMLSelectElement
5222 },
5223 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableCellElement) => {
5224 LayoutElementType::HTMLTableCellElement
5225 },
5226 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement) => {
5227 LayoutElementType::HTMLTableColElement
5228 },
5229 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement) => {
5230 LayoutElementType::HTMLTableElement
5231 },
5232 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement) => {
5233 LayoutElementType::HTMLTableRowElement
5234 },
5235 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement) => {
5236 LayoutElementType::HTMLTableSectionElement
5237 },
5238 ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement) => {
5239 LayoutElementType::HTMLTextAreaElement
5240 },
5241 ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
5242 SVGGraphicsElementTypeId::SVGImageElement,
5243 )) => LayoutElementType::SVGImageElement,
5244 ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
5245 SVGGraphicsElementTypeId::SVGSVGElement,
5246 )) => LayoutElementType::SVGSVGElement,
5247 _ => LayoutElementType::Element,
5248 }
5249 }
5250}
5251
5252pub(crate) trait VecPreOrderInsertionHelper<T> {
5255 fn insert_pre_order(&mut self, elem: &T, tree_root: &Node);
5256}
5257
5258impl<T> VecPreOrderInsertionHelper<T> for Vec<Dom<T>>
5259where
5260 T: DerivedFrom<Node> + DomObject,
5261{
5262 fn insert_pre_order(&mut self, node: &T, tree_root: &Node) {
5267 let Err(insertion_index) = self.binary_search_by(|candidate| {
5268 candidate
5269 .upcast()
5270 .compare_dom_tree_position(node.upcast(), tree_root)
5271 }) else {
5272 return;
5275 };
5276
5277 self.insert(insertion_index, Dom::from_ref(node));
5278 }
5279}