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