1use std::cell::LazyCell;
6use std::cmp::Ordering;
7use std::iter;
8use std::rc::Rc;
9
10use app_units::Au;
11use dom_struct::dom_struct;
12use euclid::Rect;
13use js::context::{JSContext, NoGC};
14use js::jsapi::JSTracer;
15use js::rust::HandleObject;
16use script_bindings::cell::DomRefCell;
17use script_bindings::dom::{MutDom, UnrootedDom};
18use script_bindings::reflector::reflect_weak_referenceable_dom_object_with_proto;
19use smallvec::SmallVec;
20use style_traits::CSSPixel;
21
22use crate::dom::abstractrange::{AbstractRange, BoundaryPoint, bp_position};
23use crate::dom::bindings::codegen::Bindings::AbstractRangeBinding::AbstractRangeMethods;
24use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
25use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
26use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
27use crate::dom::bindings::codegen::Bindings::RangeBinding::{RangeConstants, RangeMethods};
28use crate::dom::bindings::codegen::Bindings::TextBinding::TextMethods;
29use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
30use crate::dom::bindings::codegen::UnionTypes::TrustedHTMLOrString;
31use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
32use crate::dom::bindings::inheritance::{Castable, CharacterDataTypeId, NodeTypeId};
33use crate::dom::bindings::root::{Dom, DomRoot};
34use crate::dom::bindings::str::DOMString;
35use crate::dom::bindings::trace::JSTraceable;
36use crate::dom::bindings::weakref::{WeakRef, WeakRefVec};
37use crate::dom::characterdata::CharacterData;
38use crate::dom::document::Document;
39use crate::dom::documentfragment::DocumentFragment;
40use crate::dom::domrect::DOMRect;
41use crate::dom::domrectlist::DOMRectList;
42use crate::dom::element::Element;
43use crate::dom::html::htmlscriptelement::HTMLScriptElement;
44use crate::dom::iterators::ShadowIncluding;
45use crate::dom::node::{Node, NodeTraits};
46use crate::dom::selection::{Selection, SelectionLiveRangeNotification};
47use crate::dom::text::Text;
48use crate::dom::trustedtypes::trustedhtml::TrustedHTML;
49use crate::dom::window::Window;
50
51#[dom_struct]
52pub(crate) struct Range {
53 abstract_range: AbstractRange,
54 document: MutDom<Document>,
58 associated_selections: DomRefCell<Vec<Dom<Selection>>>,
68}
69
70pub(crate) struct ContainedChildren {
71 pub(crate) first_partially_contained_child: Option<DomRoot<Node>>,
72 pub(crate) last_partially_contained_child: Option<DomRoot<Node>>,
73 pub(crate) contained_children: Vec<DomRoot<Node>>,
74}
75
76impl Range {
77 fn new_inherited(
78 start_container: &Node,
79 start_offset: u32,
80 end_container: &Node,
81 end_offset: u32,
82 start_container_document: &Document,
83 ) -> Self {
84 debug_assert!(start_offset <= start_container.len());
85 debug_assert!(end_offset <= end_container.len());
86 Self {
87 abstract_range: AbstractRange::new_inherited(
88 start_container,
89 start_offset,
90 end_container,
91 end_offset,
92 ),
93 document: MutDom::new(start_container_document),
94 associated_selections: DomRefCell::new(vec![]),
95 }
96 }
97
98 pub(crate) fn new_with_doc(
99 cx: &mut JSContext,
100 document: &Document,
101 proto: Option<HandleObject>,
102 ) -> DomRoot<Self> {
103 let root = document.upcast();
104 Self::new_with_proto(cx, document, proto, root, 0, root, 0)
105 }
106
107 pub(crate) fn new(
108 cx: &mut JSContext,
109 document: &Document,
110 start_container: &Node,
111 start_offset: u32,
112 end_container: &Node,
113 end_offset: u32,
114 ) -> DomRoot<Range> {
115 Self::new_with_proto(
116 cx,
117 document,
118 None,
119 start_container,
120 start_offset,
121 end_container,
122 end_offset,
123 )
124 }
125
126 fn new_with_proto(
127 cx: &mut JSContext,
128 document_to_reflect_into: &Document,
129 proto: Option<HandleObject>,
130 start_container: &Node,
131 start_offset: u32,
132 end_container: &Node,
133 end_offset: u32,
134 ) -> DomRoot<Range> {
135 let start_container_document = start_container.owner_document();
136 let range = reflect_weak_referenceable_dom_object_with_proto(
137 cx,
138 Rc::new(Self::new_inherited(
139 start_container,
140 start_offset,
141 end_container,
142 end_offset,
143 &start_container_document,
144 )),
145 document_to_reflect_into.window(),
146 proto,
147 );
148
149 start_container_document
150 .live_ranges()
151 .push(WeakRef::new(&range));
152
153 range
154 }
155
156 pub(crate) fn root(&self) -> DomRoot<Node> {
160 self.start_container().GetRootNode(&Default::default())
161 }
162
163 pub(crate) fn contains(&self, no_gc: &NoGC, node: &Node) -> bool {
165 node.GetRootNode(&Default::default()) == self.root() &&
168 matches!(
169 (
170 bp_position(no_gc, node, 0, &self.start_container(), self.start_offset()),
171 bp_position(
172 no_gc,
173 node,
174 node.len(),
175 &self.end_container(),
176 self.end_offset()
177 ),
178 ),
179 (Ordering::Greater, Ordering::Less)
180 )
181 }
182
183 fn partially_contains(&self, node: &Node) -> bool {
185 self.start_container()
188 .inclusive_ancestors(ShadowIncluding::No)
189 .any(|n| &*n == node) !=
190 self.end_container()
191 .inclusive_ancestors(ShadowIncluding::No)
192 .any(|n| &*n == node)
193 }
194
195 pub(crate) fn contained_children(&self, no_gc: &NoGC) -> Fallible<ContainedChildren> {
197 let start_node = self.start_container();
198 let end_node = self.end_container();
199 let common_ancestor = self.CommonAncestorContainer();
201
202 let first_partially_contained_child = if start_node.is_inclusive_ancestor_of(&end_node) {
203 None
205 } else {
206 common_ancestor
208 .children()
209 .find(|node| Range::partially_contains(self, node))
210 };
211
212 let last_partially_contained_child = if end_node.is_inclusive_ancestor_of(&start_node) {
213 None
215 } else {
216 common_ancestor
218 .rev_children()
219 .find(|node| Range::partially_contains(self, node))
220 };
221
222 let contained_children: Vec<DomRoot<Node>> = common_ancestor
224 .children()
225 .filter(|n| self.contains(no_gc, n))
226 .collect();
227
228 if contained_children.iter().any(|n| n.is_doctype()) {
230 return Err(Error::HierarchyRequest(None));
231 }
232
233 Ok(ContainedChildren {
234 first_partially_contained_child,
235 last_partially_contained_child,
236 contained_children,
237 })
238 }
239
240 pub(crate) fn set_start(&self, no_gc: &NoGC, node: &Node, offset: u32) {
242 if self.set_start_without_reporting(node, offset) {
243 self.report_change(no_gc, SelectionLiveRangeNotification::Start);
244 }
245 }
246
247 pub(crate) fn set_start_without_reporting(&self, node: &Node, offset: u32) -> bool {
248 if self.start().node() == node && self.start_offset() == offset {
249 return false;
250 }
251 self.start().set(node, offset);
252 true
253 }
254
255 pub(crate) fn set_end(&self, no_gc: &NoGC, node: &Node, offset: u32) {
257 if self.set_end_without_reporting(node, offset) {
258 self.report_change(no_gc, SelectionLiveRangeNotification::End);
259 }
260 }
261
262 pub(crate) fn set_end_without_reporting(&self, node: &Node, offset: u32) -> bool {
263 if self.end().node() == node && self.end_offset() == offset {
264 return false;
265 }
266 self.end().set(node, offset);
267 true
268 }
269
270 fn compare_point(&self, no_gc: &NoGC, node: &Node, offset: u32) -> Fallible<Ordering> {
272 if node.GetRootNode(&Default::default()) != self.root() {
275 return Err(Error::WrongDocument(None));
276 }
277 if node.is_doctype() {
280 return Err(Error::InvalidNodeType(None));
281 }
282 if offset > node.len() {
285 return Err(Error::IndexSize(None));
286 }
287 let start_node = self.start_container();
289 if let Ordering::Less = bp_position(no_gc, node, offset, &start_node, self.start_offset()) {
290 return Ok(Ordering::Less);
291 }
292 if let Ordering::Greater = bp_position(
294 no_gc,
295 node,
296 offset,
297 &self.end_container(),
298 self.end_offset(),
299 ) {
300 return Ok(Ordering::Greater);
301 }
302 Ok(Ordering::Equal)
304 }
305
306 pub(crate) fn associate_selection(&self, selection: &Selection) {
307 let mut selections = self.associated_selections.borrow_mut();
308 if !selections.iter().any(|s| &**s == selection) {
309 selections.push(Dom::from_ref(selection));
310 }
311 }
312
313 pub(crate) fn disassociate_selection(&self, selection: &Selection) {
314 self.associated_selections
315 .borrow_mut()
316 .retain(|s| &**s != selection);
317 }
318
319 pub(crate) fn report_change(&self, no_gc: &NoGC, notification: SelectionLiveRangeNotification) {
320 if notification.is_empty() {
321 return;
322 }
323
324 let selections: SmallVec<[DomRoot<Selection>; 1]> = self
327 .associated_selections
328 .borrow()
329 .iter()
330 .map(Dom::as_rooted)
331 .collect();
332 for selection in selections {
333 if !selection.clear_selection_if_live_range_document_changed(no_gc, self) {
334 selection.update_from_live_range(no_gc, self, notification);
335 }
336 }
337 }
338
339 fn abstract_range(&self) -> &AbstractRange {
340 &self.abstract_range
341 }
342
343 pub(crate) fn start(&self) -> &BoundaryPoint {
344 self.abstract_range().start()
345 }
346
347 pub(crate) fn end(&self) -> &BoundaryPoint {
348 self.abstract_range().end()
349 }
350
351 pub(crate) fn start_container(&self) -> DomRoot<Node> {
352 self.abstract_range().StartContainer()
353 }
354
355 pub(crate) fn start_offset(&self) -> u32 {
356 self.abstract_range().StartOffset()
357 }
358
359 pub(crate) fn end_container(&self) -> DomRoot<Node> {
360 self.abstract_range().EndContainer()
361 }
362
363 pub(crate) fn end_offset(&self) -> u32 {
364 self.abstract_range().EndOffset()
365 }
366
367 pub(crate) fn collapsed(&self) -> bool {
368 self.abstract_range().Collapsed()
369 }
370
371 fn client_rects(&self, no_gc: &NoGC) -> Vec<Rect<Au, CSSPixel>> {
373 let start = self.start_container();
376 let end = self.end_container();
377 if !start.is_connected() || !end.is_connected() {
380 return vec![];
381 }
382
383 if self.collapsed() {
386 if start.is::<CharacterData>() {
387 return start.border_boxes();
388 } else {
389 return vec![];
390 }
391 }
392
393 let document = start.owner_doc();
394 let unrooted_end = end.as_unrooted(no_gc);
395 start
396 .following_nodes_unrooted(no_gc, document.upcast::<Node>(), ShadowIncluding::No)
397 .take_while(move |node| *node != *end)
398 .chain(iter::once(unrooted_end))
399 .flat_map(move |node| node.border_boxes())
400 .collect()
401 }
402
403 fn set_the_start_or_end(
405 &self,
406 no_gc: &NoGC,
407 node: &Node,
408 offset: u32,
409 start_or_end: StartOrEnd,
410 ) -> ErrorResult {
411 if node.is_doctype() {
414 return Err(Error::InvalidNodeType(None));
415 }
416
417 if offset > node.len() {
420 return Err(Error::IndexSize(None));
421 }
422
423 let mut notification = SelectionLiveRangeNotification::empty();
426 match start_or_end {
427 StartOrEnd::Start => {
429 if self.root() != node.GetRootNode(&Default::default()) ||
432 bp_position(
433 no_gc,
434 node,
435 offset,
436 &self.end_container(),
437 self.end_offset(),
438 ) == Ordering::Greater
439 {
440 self.set_end_without_reporting(node, offset);
441 }
442
443 notification.set(
445 SelectionLiveRangeNotification::Start,
446 self.set_start_without_reporting(node, offset),
447 );
448 },
449 StartOrEnd::End => {
451 if self.root() != node.GetRootNode(&Default::default()) ||
454 bp_position(
455 no_gc,
456 node,
457 offset,
458 &self.start_container(),
459 self.start_offset(),
460 ) == Ordering::Less
461 {
462 self.set_start_without_reporting(node, offset);
463 }
464
465 notification.set(
467 SelectionLiveRangeNotification::End,
468 self.set_end_without_reporting(node, offset),
469 );
470 },
471 }
472
473 self.maybe_update_document();
474 self.report_change(no_gc, notification);
475 Ok(())
476 }
477
478 pub(crate) fn maybe_update_document(&self) {
487 debug_assert!(
489 self.start_container().owner_document() == self.end_container().owner_document(),
490 );
491
492 let current_document = self.document.get();
493 let new_document = self.start_container().owner_document();
494 if new_document != current_document {
495 current_document.live_ranges().remove(self);
496 new_document.live_ranges().push(WeakRef::new(self));
497 self.document.set(&new_document);
498 }
499 }
500
501 pub(crate) fn start_and_end_are_in_document_tree(&self) -> bool {
502 self.start_container().is_in_a_document_tree() &&
503 self.end_container().is_in_a_document_tree()
504 }
505}
506
507impl std::fmt::Debug for Range {
508 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
509 write!(
510 f,
511 "[({:?}, {}) -> ({:?}, {})]",
512 self.start_container(),
513 self.start_offset(),
514 self.end_container(),
515 self.end_offset()
516 )
517 }
518}
519
520#[derive(Copy, Clone)]
521pub(crate) enum StartOrEnd {
522 Start,
523 End,
524}
525
526impl RangeMethods<crate::DomTypeHolder> for Range {
527 fn Constructor(
529 cx: &mut JSContext,
530 window: &Window,
531 proto: Option<HandleObject>,
532 ) -> Fallible<DomRoot<Range>> {
533 let document = window.Document();
534 Ok(Range::new_with_doc(cx, &document, proto))
535 }
536
537 fn CommonAncestorContainer(&self) -> DomRoot<Node> {
539 self.end_container()
540 .common_ancestor(&self.start_container(), ShadowIncluding::No)
541 .expect("Couldn't find common ancestor container")
542 }
543
544 fn SetStart(&self, no_gc: &NoGC, node: &Node, offset: u32) -> ErrorResult {
546 self.set_the_start_or_end(no_gc, node, offset, StartOrEnd::Start)
547 }
548
549 fn SetEnd(&self, no_gc: &NoGC, node: &Node, offset: u32) -> ErrorResult {
551 self.set_the_start_or_end(no_gc, node, offset, StartOrEnd::End)
552 }
553
554 fn SetStartBefore(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
556 let parent = node.GetParentNode().ok_or(Error::InvalidNodeType(None))?;
557 self.SetStart(no_gc, &parent, node.index())
558 }
559
560 fn SetStartAfter(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
562 let parent = node.GetParentNode().ok_or(Error::InvalidNodeType(None))?;
563 self.SetStart(no_gc, &parent, node.index() + 1)
564 }
565
566 fn SetEndBefore(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
568 let parent = node.GetParentNode().ok_or(Error::InvalidNodeType(None))?;
569 self.SetEnd(no_gc, &parent, node.index())
570 }
571
572 fn SetEndAfter(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
574 let parent = node.GetParentNode().ok_or(Error::InvalidNodeType(None))?;
575 self.SetEnd(no_gc, &parent, node.index() + 1)
576 }
577
578 fn Collapse(&self, no_gc: &NoGC, to_start: bool) {
580 if to_start {
581 self.set_end(no_gc, &self.start_container(), self.start_offset());
582 } else {
583 self.set_start(no_gc, &self.end_container(), self.end_offset());
584 }
585 }
586
587 fn SelectNode(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
589 let parent = node.GetParentNode().ok_or(Error::InvalidNodeType(None))?;
591 let index = node.index();
593 self.set_start(no_gc, &parent, index);
595 self.set_end(no_gc, &parent, index + 1);
597 Ok(())
598 }
599
600 fn SelectNodeContents(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
602 if node.is_doctype() {
603 return Err(Error::InvalidNodeType(None));
605 }
606 let length = node.len();
608 self.set_start(no_gc, node, 0);
610 self.set_end(no_gc, node, length);
612 Ok(())
613 }
614
615 fn CompareBoundaryPoints(&self, no_gc: &NoGC, how: u16, source_range: &Range) -> Fallible<i16> {
617 if how > RangeConstants::END_TO_START {
624 return Err(Error::NotSupported(None));
625 }
626 if self.root() != source_range.root() {
629 return Err(Error::WrongDocument(None));
630 }
631 let (this_point, source_point) = match how {
642 RangeConstants::START_TO_START => (self.start(), source_range.start()),
643 RangeConstants::START_TO_END => (self.end(), source_range.start()),
644 RangeConstants::END_TO_END => (self.end(), source_range.end()),
645 RangeConstants::END_TO_START => (self.start(), source_range.end()),
646 _ => unreachable!(),
647 };
648 match this_point.partial_cmp(no_gc, source_point).unwrap() {
656 Ordering::Less => Ok(-1),
657 Ordering::Equal => Ok(0),
658 Ordering::Greater => Ok(1),
659 }
660 }
661
662 fn CloneRange(&self, cx: &mut JSContext) -> DomRoot<Range> {
664 let start_node = self.start_container();
665 let owner_doc = start_node.owner_doc();
666 Range::new(
667 cx,
668 &owner_doc,
669 &start_node,
670 self.start_offset(),
671 &self.end_container(),
672 self.end_offset(),
673 )
674 }
675
676 fn IsPointInRange(&self, no_gc: &NoGC, node: &Node, offset: u32) -> Fallible<bool> {
678 match self.compare_point(no_gc, node, offset) {
679 Ok(Ordering::Less) => Ok(false),
680 Ok(Ordering::Equal) => Ok(true),
681 Ok(Ordering::Greater) => Ok(false),
682 Err(Error::WrongDocument(None)) => {
683 Ok(false)
686 },
687 Err(error) => Err(error),
688 }
689 }
690
691 fn ComparePoint(&self, no_gc: &NoGC, node: &Node, offset: u32) -> Fallible<i16> {
693 self.compare_point(no_gc, node, offset)
694 .map(|order| match order {
695 Ordering::Less => -1,
696 Ordering::Equal => 0,
697 Ordering::Greater => 1,
698 })
699 }
700
701 fn IntersectsNode(&self, no_gc: &NoGC, node: &Node) -> bool {
703 if self.root() != node.GetRootNode(&Default::default()) {
705 return false;
706 }
707 let Some(parent) = node.GetParentNode() else {
709 return true;
711 };
712 let offset = node.index();
714 let start_node = self.start_container();
718 Ordering::Greater ==
719 bp_position(no_gc, &parent, offset + 1, &start_node, self.start_offset()) &&
720 Ordering::Less ==
721 bp_position(
722 no_gc,
723 &parent,
724 offset,
725 &self.end_container(),
726 self.end_offset(),
727 )
728 }
729
730 fn CloneContents(&self, cx: &mut JSContext) -> Fallible<DomRoot<DocumentFragment>> {
733 let start_node = self.start_container();
735 let start_offset = self.start_offset();
736 let end_node = self.end_container();
737 let end_offset = self.end_offset();
738
739 let fragment = DocumentFragment::new(cx, &start_node.owner_doc());
741
742 if self.start() == self.end() {
744 return Ok(fragment);
745 }
746
747 if end_node == start_node &&
748 let Some(cdata) = start_node.downcast::<CharacterData>()
749 {
750 let data = cdata
752 .SubstringData(start_offset, end_offset - start_offset)
753 .unwrap();
754 let clone = cdata.clone_with_data(cx, data, &start_node.owner_doc());
755 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
757 return Ok(fragment);
759 }
760
761 let ContainedChildren {
763 first_partially_contained_child,
764 last_partially_contained_child,
765 contained_children,
766 } = self.contained_children(cx.no_gc())?;
767
768 if let Some(child) = first_partially_contained_child {
769 if let Some(cdata) = child.downcast::<CharacterData>() {
771 assert!(child == start_node);
772 let data = cdata
774 .SubstringData(start_offset, start_node.len() - start_offset)
775 .unwrap();
776 let clone = cdata.clone_with_data(cx, data, &start_node.owner_doc());
777 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
779 } else {
780 let clone = child.CloneNode(cx, false)?;
782 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
784 let subrange = Range::new(
786 cx,
787 &clone.owner_doc(),
788 &start_node,
789 start_offset,
790 &child,
791 child.len(),
792 );
793 let subfragment = subrange.CloneContents(cx)?;
795 clone.AppendChild(cx, subfragment.upcast())?;
797 }
798 }
799
800 for child in contained_children {
802 let clone = child.CloneNode(cx, true)?;
804 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
806 }
807
808 if let Some(child) = last_partially_contained_child {
809 if let Some(cdata) = child.downcast::<CharacterData>() {
811 assert!(child == end_node);
812 let data = cdata.SubstringData(0, end_offset).unwrap();
814 let clone = cdata.clone_with_data(cx, data, &start_node.owner_doc());
815 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
817 } else {
818 let clone = child.CloneNode(cx, false)?;
820 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
822 let subrange = Range::new(cx, &clone.owner_doc(), &child, 0, &end_node, end_offset);
824 let subfragment = subrange.CloneContents(cx)?;
826 clone.AppendChild(cx, subfragment.upcast())?;
828 }
829 }
830
831 Ok(fragment)
833 }
834
835 fn ExtractContents(&self, cx: &mut JSContext) -> Fallible<DomRoot<DocumentFragment>> {
838 let start_node = self.start_container();
840 let start_offset = self.start_offset();
841 let end_node = self.end_container();
842 let end_offset = self.end_offset();
843
844 let fragment = DocumentFragment::new(cx, &start_node.owner_doc());
846
847 if self.collapsed() {
849 return Ok(fragment);
850 }
851
852 if end_node == start_node &&
853 let Some(end_data) = end_node.downcast::<CharacterData>()
854 {
855 let clone = end_node.CloneNode(cx, true)?;
857 let text = end_data.SubstringData(start_offset, end_offset - start_offset);
859 clone
860 .downcast::<CharacterData>()
861 .unwrap()
862 .SetData(cx, text.unwrap());
863 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
865 end_data.ReplaceData(
867 cx,
868 start_offset,
869 end_offset - start_offset,
870 DOMString::new(),
871 )?;
872 return Ok(fragment);
874 }
875
876 let ContainedChildren {
878 first_partially_contained_child,
879 last_partially_contained_child,
880 contained_children,
881 } = self.contained_children(cx.no_gc())?;
882
883 let (new_node, new_offset) = if start_node.is_inclusive_ancestor_of(&end_node) {
884 (DomRoot::from_ref(&*start_node), start_offset)
886 } else {
887 let reference_node = start_node
889 .ancestors()
890 .take_while(|n| !n.is_inclusive_ancestor_of(&end_node))
891 .last()
892 .unwrap_or(DomRoot::from_ref(&start_node));
893 (
895 reference_node.GetParentNode().unwrap(),
896 reference_node.index() + 1,
897 )
898 };
899
900 if let Some(child) = first_partially_contained_child {
901 if let Some(start_data) = child.downcast::<CharacterData>() {
902 assert!(child == start_node);
903 let clone = start_node.CloneNode(cx, true)?;
905 let text = start_data.SubstringData(start_offset, start_node.len() - start_offset);
907 clone
908 .downcast::<CharacterData>()
909 .unwrap()
910 .SetData(cx, text.unwrap());
911 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
913 start_data.ReplaceData(
915 cx,
916 start_offset,
917 start_node.len() - start_offset,
918 DOMString::new(),
919 )?;
920 } else {
921 let clone = child.CloneNode(cx, false)?;
923 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
925 let subrange = Range::new(
927 cx,
928 &clone.owner_doc(),
929 &start_node,
930 start_offset,
931 &child,
932 child.len(),
933 );
934 let subfragment = subrange.ExtractContents(cx)?;
936 clone.AppendChild(cx, subfragment.upcast())?;
938 }
939 }
940
941 for child in contained_children {
943 fragment.upcast::<Node>().AppendChild(cx, &child)?;
944 }
945
946 if let Some(child) = last_partially_contained_child {
947 if let Some(end_data) = child.downcast::<CharacterData>() {
948 assert!(child == end_node);
949 let clone = end_node.CloneNode(cx, true)?;
951 let text = end_data.SubstringData(0, end_offset);
953 clone
954 .downcast::<CharacterData>()
955 .unwrap()
956 .SetData(cx, text.unwrap());
957 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
959 end_data.ReplaceData(cx, 0, end_offset, DOMString::new())?;
961 } else {
962 let clone = child.CloneNode(cx, false)?;
964 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
966 let subrange = Range::new(cx, &clone.owner_doc(), &child, 0, &end_node, end_offset);
968 let subfragment = subrange.ExtractContents(cx)?;
970 clone.AppendChild(cx, subfragment.upcast())?;
972 }
973 }
974
975 self.SetStart(cx.no_gc(), &new_node, new_offset)?;
977 self.SetEnd(cx.no_gc(), &new_node, new_offset)?;
978
979 Ok(fragment)
981 }
982
983 fn Detach(&self) {
987 }
989
990 fn InsertNode(&self, cx: &mut JSContext, node: &Node) -> ErrorResult {
993 let start_node = self.start_container();
994 let start_offset = self.start_offset();
995
996 if &*start_node == node {
998 return Err(Error::HierarchyRequest(None));
999 }
1000 match start_node.type_id() {
1001 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => (),
1003 NodeTypeId::CharacterData(_) => return Err(Error::HierarchyRequest(None)),
1004 _ => (),
1005 }
1006
1007 let (reference_node, parent) = match start_node.type_id() {
1009 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1010 let parent = match start_node.GetParentNode() {
1012 Some(parent) => parent,
1013 None => return Err(Error::HierarchyRequest(None)),
1015 };
1016 (Some(DomRoot::from_ref(&*start_node)), parent)
1018 },
1019 _ => {
1020 let child = start_node.ChildNodes(cx).Item(cx, start_offset);
1022 (child, DomRoot::from_ref(&*start_node))
1023 },
1024 };
1025
1026 Node::ensure_pre_insertion_validity(cx.no_gc(), node, &parent, reference_node.as_deref())?;
1028
1029 let split_text;
1031 let reference_node = match start_node.downcast::<Text>() {
1032 Some(text) => {
1033 split_text = text.SplitText(cx, start_offset)?;
1034 let new_reference = DomRoot::upcast::<Node>(split_text);
1035 assert!(new_reference.GetParentNode().as_deref() == Some(&parent));
1036 Some(new_reference)
1037 },
1038 _ => reference_node,
1039 };
1040
1041 let reference_node = if Some(node) == reference_node.as_deref() {
1043 node.GetNextSibling()
1044 } else {
1045 reference_node
1046 };
1047
1048 node.remove_self(cx);
1050
1051 let new_offset = reference_node
1053 .as_ref()
1054 .map_or(parent.len(), |node| node.index());
1055
1056 let new_offset = new_offset +
1058 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
1059 node.len()
1060 } else {
1061 1
1062 };
1063
1064 Node::pre_insert(cx, node, &parent, reference_node.as_deref())?;
1066
1067 if self.collapsed() {
1069 self.set_end(cx.no_gc(), &parent, new_offset);
1070 }
1071
1072 Ok(())
1073 }
1074
1075 fn DeleteContents(&self, cx: &mut JSContext) -> ErrorResult {
1077 if self.collapsed() {
1079 return Ok(());
1080 }
1081
1082 let start_node = self.start_container();
1085 let end_node = self.end_container();
1086 let start_offset = self.start_offset();
1087 let end_offset = self.end_offset();
1088
1089 if start_node == end_node &&
1091 let Some(text) = start_node.downcast::<CharacterData>()
1092 {
1093 return text.ReplaceData(
1097 cx,
1098 start_offset,
1099 end_offset - start_offset,
1100 DOMString::new(),
1101 );
1102 }
1103
1104 rooted_vec!(let mut contained_children);
1107 let ancestor = self.CommonAncestorContainer();
1108
1109 let mut iter = start_node.following_nodes(&ancestor, ShadowIncluding::No);
1110
1111 let mut next = iter.next();
1112 while let Some(child) = next {
1113 if self.contains(cx.no_gc(), &child) {
1114 contained_children.push(Dom::from_ref(&*child));
1115 next = iter.next_skipping_children();
1116 } else {
1117 next = iter.next();
1118 }
1119 }
1120
1121 let (new_node, new_offset) = if start_node.is_inclusive_ancestor_of(&end_node) {
1125 (DomRoot::from_ref(&*start_node), start_offset)
1126 } else {
1127 fn compute_reference(start_node: &Node, end_node: &Node) -> (DomRoot<Node>, u32) {
1129 let mut reference_node = DomRoot::from_ref(start_node);
1131 while let Some(parent) = reference_node.GetParentNode() {
1134 if parent.is_inclusive_ancestor_of(end_node) {
1135 return (parent, reference_node.index() + 1);
1137 }
1138 reference_node = parent;
1139 }
1140 unreachable!()
1141 }
1142
1143 compute_reference(&start_node, &end_node)
1144 };
1145
1146 self.SetStart(cx.no_gc(), &new_node, new_offset).unwrap();
1148 self.SetEnd(cx.no_gc(), &new_node, new_offset).unwrap();
1149
1150 if let Some(text) = start_node.downcast::<CharacterData>() {
1154 text.ReplaceData(
1155 cx,
1156 start_offset,
1157 start_node.len() - start_offset,
1158 DOMString::new(),
1159 )
1160 .unwrap();
1161 }
1162
1163 for child in &*contained_children {
1165 child.remove_self(cx);
1166 }
1167
1168 if let Some(text) = end_node.downcast::<CharacterData>() {
1171 text.ReplaceData(cx, 0, end_offset, DOMString::new())
1172 .unwrap();
1173 }
1174
1175 Ok(())
1176 }
1177
1178 fn SurroundContents(&self, cx: &mut JSContext, new_parent: &Node) -> ErrorResult {
1180 let start = self.start_container();
1182 let end = self.end_container();
1183
1184 if start
1185 .inclusive_ancestors(ShadowIncluding::No)
1186 .any(|n| !n.is_inclusive_ancestor_of(&end) && !n.is::<Text>()) ||
1187 end.inclusive_ancestors(ShadowIncluding::No)
1188 .any(|n| !n.is_inclusive_ancestor_of(&start) && !n.is::<Text>())
1189 {
1190 return Err(Error::InvalidState(None));
1191 }
1192
1193 match new_parent.type_id() {
1195 NodeTypeId::Document(_) |
1196 NodeTypeId::DocumentType |
1197 NodeTypeId::DocumentFragment(_) => {
1198 return Err(Error::InvalidNodeType(None));
1199 },
1200 _ => (),
1201 }
1202
1203 let fragment = self.ExtractContents(cx)?;
1205
1206 Node::replace_all(cx, None, new_parent);
1208
1209 self.InsertNode(cx, new_parent)?;
1211
1212 new_parent.AppendChild(cx, fragment.upcast())?;
1214
1215 self.SelectNode(cx.no_gc(), new_parent)
1217 }
1218
1219 fn Stringifier(&self, no_gc: &NoGC) -> DOMString {
1221 let start_node = self.start_container();
1222 let end_node = self.end_container();
1223
1224 let mut s = DOMString::new();
1226
1227 if let Some(text_node) = start_node.downcast::<Text>() {
1228 let char_data = text_node.upcast::<CharacterData>();
1229
1230 if start_node == end_node {
1234 return char_data
1235 .SubstringData(self.start_offset(), self.end_offset() - self.start_offset())
1236 .unwrap();
1237 }
1238
1239 s.push_str(
1242 &char_data
1243 .SubstringData(
1244 self.start_offset(),
1245 char_data.Length() - self.start_offset(),
1246 )
1247 .unwrap()
1248 .str(),
1249 );
1250 }
1251
1252 let ancestor = self.CommonAncestorContainer();
1255 let iter = start_node
1256 .following_nodes_unrooted(no_gc, &ancestor, ShadowIncluding::No)
1257 .filter_map(UnrootedDom::downcast::<Text>);
1258
1259 for child in iter {
1260 if self.contains(no_gc, child.upcast()) {
1261 s.push_str(&child.upcast::<CharacterData>().Data().str());
1262 }
1263 }
1264
1265 if let Some(text_node) = end_node.downcast::<Text>() {
1268 let char_data = text_node.upcast::<CharacterData>();
1269 s.push_str(&char_data.SubstringData(0, self.end_offset()).unwrap().str());
1270 }
1271
1272 s
1274 }
1275
1276 fn CreateContextualFragment(
1278 &self,
1279 cx: &mut JSContext,
1280 fragment: TrustedHTMLOrString,
1281 ) -> Fallible<DomRoot<DocumentFragment>> {
1282 let node = self.start_container();
1287
1288 let fragment = TrustedHTML::get_trusted_type_compliant_string(
1292 cx,
1293 node.owner_window().upcast(),
1294 fragment,
1295 "Range createContextualFragment",
1296 )?;
1297
1298 let owner_doc = node.owner_doc();
1299
1300 let element = match node.type_id() {
1304 NodeTypeId::Element(_) => Some(DomRoot::downcast::<Element>(node).unwrap()),
1305 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1306 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => node.GetParentElement(),
1307 _ => None,
1308 };
1309
1310 let element = Element::fragment_parsing_context(cx, &owner_doc, element.as_deref());
1312
1313 let fragment_node = element.parse_fragment(fragment, cx)?;
1315
1316 for node in fragment_node
1318 .upcast::<Node>()
1319 .traverse_preorder(ShadowIncluding::No)
1320 {
1321 if let Some(script) = node.downcast::<HTMLScriptElement>() {
1322 script.set_already_started(false);
1324 script.set_parser_inserted(false);
1326 }
1327 }
1328
1329 Ok(fragment_node)
1331 }
1332
1333 fn GetClientRects(&self, cx: &mut JSContext) -> DomRoot<DOMRectList> {
1335 let start = self.start_container();
1336 let window = start.owner_window();
1337
1338 let client_rects = self.client_rects(cx.no_gc());
1339 let client_rects = client_rects
1340 .iter()
1341 .map(|rect| {
1342 DOMRect::new(
1343 cx,
1344 window.upcast(),
1345 rect.origin.x.to_f64_px(),
1346 rect.origin.y.to_f64_px(),
1347 rect.size.width.to_f64_px(),
1348 rect.size.height.to_f64_px(),
1349 )
1350 })
1351 .collect();
1352
1353 DOMRectList::new(cx, &window, client_rects)
1354 }
1355
1356 fn GetBoundingClientRect(&self, cx: &mut JSContext) -> DomRoot<DOMRect> {
1358 let window = self.start_container().owner_window();
1359
1360 let list = self.client_rects(cx.no_gc());
1362
1363 let bounding_rect = list
1368 .into_iter()
1369 .fold(euclid::Rect::zero(), |acc, rect| acc.union(&rect));
1370
1371 DOMRect::new(
1372 cx,
1373 window.upcast(),
1374 bounding_rect.origin.x.to_f64_px(),
1375 bounding_rect.origin.y.to_f64_px(),
1376 bounding_rect.size.width.to_f64_px(),
1377 bounding_rect.size.height.to_f64_px(),
1378 )
1379 }
1380}
1381
1382#[derive(MallocSizeOf)]
1383pub(crate) struct WeakRangeVec {
1384 cell: DomRefCell<WeakRefVec<Range>>,
1385}
1386
1387impl Default for WeakRangeVec {
1388 fn default() -> Self {
1389 WeakRangeVec {
1390 cell: DomRefCell::new(WeakRefVec::new()),
1391 }
1392 }
1393}
1394
1395impl WeakRangeVec {
1396 pub(crate) fn as_vec(&self) -> SmallVec<[DomRoot<Range>; 4]> {
1398 self.cell
1399 .borrow()
1400 .iter()
1401 .filter_map(|range| range.root())
1402 .collect()
1403 }
1404
1405 pub(crate) fn for_each(&self, no_gc: &NoGC, mut callback: impl FnMut(&Range)) {
1406 for weak_range in self.cell.safe_borrow_mut(no_gc).iter() {
1407 if let Some(range) = weak_range.unrooted(no_gc) {
1408 callback(&range);
1409 }
1410 }
1411 }
1412
1413 pub(crate) fn is_empty(&self) -> bool {
1414 self.cell.borrow().is_empty()
1415 }
1416
1417 fn push(&self, weak_range: WeakRef<Range>) {
1418 self.cell.borrow_mut().push(weak_range);
1419 }
1420
1421 fn remove(&self, range_to_remove: &Range) {
1422 self.cell
1423 .borrow_mut()
1424 .retain(|range| range != range_to_remove);
1425 }
1426}
1427
1428#[expect(unsafe_code)]
1429unsafe impl JSTraceable for WeakRangeVec {
1430 unsafe fn trace(&self, _: *mut JSTracer) {
1431 self.cell.borrow_mut().retain_alive()
1432 }
1433}
1434
1435impl Document {
1436 pub(crate) fn live_range_insert_steps(
1440 &self,
1441 no_gc: &NoGC,
1442 parent: &Node,
1443 child: &Node,
1444 count: u32,
1445 ) {
1446 if self.live_ranges().is_empty() {
1447 return;
1448 }
1449
1450 let child_index = LazyCell::new(|| child.index());
1451 self.live_ranges().for_each(no_gc, |range| {
1452 if &*range.start_container() == parent && range.start_offset() > *child_index {
1455 range.set_start_without_reporting(parent, range.start_offset() + count);
1456 }
1457 if &*range.end_container() == parent && range.end_offset() > *child_index {
1460 range.set_end_without_reporting(parent, range.end_offset() + count);
1461 }
1462 });
1463 }
1464
1465 pub(crate) fn live_range_pre_remove_steps(
1467 &self,
1468 no_gc: &NoGC,
1469 removed_node: &Node, parent_of_removed_node: &Node, index_of_removed_node: &mut dyn FnMut() -> u32, ) {
1473 if self.live_ranges().is_empty() {
1474 return;
1475 }
1476
1477 self.live_ranges().for_each(no_gc, |range| {
1486 let start_container = range.start_container();
1489 if removed_node.is_inclusive_ancestor_of(&start_container) {
1490 range.set_start_without_reporting(parent_of_removed_node, index_of_removed_node());
1491 }
1492 if removed_node.is_inclusive_ancestor_of(&range.end_container()) {
1495 range.set_end_without_reporting(parent_of_removed_node, index_of_removed_node());
1496 }
1497
1498 if &*range.start_container() == parent_of_removed_node &&
1501 range.start_offset() > index_of_removed_node()
1502 {
1503 range.set_start_without_reporting(parent_of_removed_node, range.start_offset() - 1);
1504 }
1505 if &*range.end_container() == parent_of_removed_node &&
1508 range.end_offset() > index_of_removed_node()
1509 {
1510 range.set_end_without_reporting(parent_of_removed_node, range.end_offset() - 1);
1511 }
1512 });
1513 }
1514
1515 pub(crate) fn live_range_normalization_steps(
1526 &self,
1527 no_gc: &NoGC,
1528 parent: &Node,
1529 node: &Node,
1530 current_node: &Node,
1531 current_node_index: &dyn Fn() -> u32,
1532 length: u32,
1533 ) {
1534 if self.live_ranges().is_empty() {
1535 return;
1536 }
1537
1538 self.live_ranges().for_each(no_gc, |range| {
1539 if &*range.start_container() == current_node {
1542 range.set_start_without_reporting(node, range.start_offset() + length);
1543 }
1544 if &*range.end_container() == current_node {
1547 range.set_end_without_reporting(node, range.end_offset() + length);
1548 }
1549
1550 if &*range.start_container() == parent && range.start_offset() == current_node_index() {
1554 range.set_start_without_reporting(node, length);
1555 }
1556 if &*range.end_container() == parent && range.end_offset() == current_node_index() {
1560 range.set_end_without_reporting(node, length);
1561 }
1562 });
1563 }
1564
1565 pub(crate) fn live_range_replace_data_steps(
1567 &self,
1568 no_gc: &NoGC,
1569 node: &Node,
1570 offset: u32,
1571 removed_code_units: u32,
1572 added_code_units: &mut dyn FnMut() -> u32,
1573 ) {
1574 if self.live_ranges().is_empty() {
1575 return;
1576 }
1577
1578 self.live_ranges().for_each(no_gc, |range| {
1579 let start_container = range.start_container();
1583 let start_offset = range.start_offset();
1584 if &*start_container == node &&
1585 start_offset > offset &&
1586 start_offset <= offset + removed_code_units
1587 {
1588 range.set_start_without_reporting(node, offset);
1589 }
1590 let end_container = range.end_container();
1594 let end_offset = range.end_offset();
1595 if &*end_container == node &&
1596 end_offset > offset &&
1597 end_offset <= offset + removed_code_units
1598 {
1599 range.set_end_without_reporting(node, offset);
1600 }
1601 if &*start_container == node && start_offset > offset + removed_code_units {
1605 range.set_start_without_reporting(
1606 node,
1607 start_offset + added_code_units() - removed_code_units,
1608 );
1609 }
1610 if &*end_container == node && end_offset > offset + removed_code_units {
1614 range.set_end_without_reporting(
1615 node,
1616 end_offset + added_code_units() - removed_code_units,
1617 );
1618 }
1619 });
1620 }
1621
1622 pub(crate) fn live_range_text_split_steps(
1624 &self,
1625 no_gc: &NoGC,
1626 parent: &Node,
1627 node: &Node,
1628 offset: u32,
1629 new_node: &Node,
1630 ) {
1631 if self.live_ranges().is_empty() {
1632 return;
1633 }
1634
1635 let node_index = LazyCell::new(|| node.index());
1636 self.live_ranges().for_each(no_gc, |range| {
1637 if &*range.start_container() == node && range.start_offset() > offset {
1641 range.set_start_without_reporting(new_node, range.start_offset() - offset);
1642 }
1643 if &*range.end_container() == node && range.end_offset() > offset {
1647 range.set_end_without_reporting(new_node, range.end_offset() - offset);
1648 }
1649
1650 if &*range.start_container() == parent && range.start_offset() == *node_index + 1 {
1653 range.set_start_without_reporting(parent, range.start_offset() + 1);
1654 }
1655
1656 if &*range.end_container() == parent && range.end_offset() == *node_index + 1 {
1659 range.set_end_without_reporting(parent, range.end_offset() + 1);
1660 }
1661 });
1662 }
1663}