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(Some(
231 "Range contains a doctype node".into(),
232 )));
233 }
234
235 Ok(ContainedChildren {
236 first_partially_contained_child,
237 last_partially_contained_child,
238 contained_children,
239 })
240 }
241
242 pub(crate) fn set_start(&self, no_gc: &NoGC, node: &Node, offset: u32) {
244 if self.set_start_without_reporting(node, offset) {
245 self.report_change(no_gc, SelectionLiveRangeNotification::Start);
246 }
247 }
248
249 pub(crate) fn set_start_without_reporting(&self, node: &Node, offset: u32) -> bool {
250 if self.start().node() == node && self.start_offset() == offset {
251 return false;
252 }
253 self.start().set(node, offset);
254 true
255 }
256
257 pub(crate) fn set_end(&self, no_gc: &NoGC, node: &Node, offset: u32) {
259 if self.set_end_without_reporting(node, offset) {
260 self.report_change(no_gc, SelectionLiveRangeNotification::End);
261 }
262 }
263
264 pub(crate) fn set_end_without_reporting(&self, node: &Node, offset: u32) -> bool {
265 if self.end().node() == node && self.end_offset() == offset {
266 return false;
267 }
268 self.end().set(node, offset);
269 true
270 }
271
272 fn compare_point(&self, no_gc: &NoGC, node: &Node, offset: u32) -> Fallible<Ordering> {
274 if node.GetRootNode(&Default::default()) != self.root() {
277 return Err(Error::WrongDocument(Some(
278 "Node is not in the same tree as the range".into(),
279 )));
280 }
281 if node.is_doctype() {
284 return Err(Error::InvalidNodeType(Some("Node is a doctype".into())));
285 }
286 if offset > node.len() {
289 return Err(Error::IndexSize(Some(
290 "Offset is greater than the node's length".into(),
291 )));
292 }
293 let start_node = self.start_container();
295 if let Ordering::Less = bp_position(no_gc, node, offset, &start_node, self.start_offset()) {
296 return Ok(Ordering::Less);
297 }
298 if let Ordering::Greater = bp_position(
300 no_gc,
301 node,
302 offset,
303 &self.end_container(),
304 self.end_offset(),
305 ) {
306 return Ok(Ordering::Greater);
307 }
308 Ok(Ordering::Equal)
310 }
311
312 pub(crate) fn associate_selection(&self, selection: &Selection) {
313 let mut selections = self.associated_selections.borrow_mut();
314 if !selections.iter().any(|s| &**s == selection) {
315 selections.push(Dom::from_ref(selection));
316 }
317 }
318
319 pub(crate) fn disassociate_selection(&self, selection: &Selection) {
320 self.associated_selections
321 .borrow_mut()
322 .retain(|s| &**s != selection);
323 }
324
325 pub(crate) fn report_change(&self, no_gc: &NoGC, notification: SelectionLiveRangeNotification) {
326 if notification.is_empty() {
327 return;
328 }
329
330 let selections: SmallVec<[DomRoot<Selection>; 1]> = self
333 .associated_selections
334 .borrow()
335 .iter()
336 .map(Dom::as_rooted)
337 .collect();
338 for selection in selections {
339 if !selection.clear_selection_if_live_range_document_changed(no_gc, self) {
340 selection.update_from_live_range(no_gc, self, notification);
341 }
342 }
343 }
344
345 fn abstract_range(&self) -> &AbstractRange {
346 &self.abstract_range
347 }
348
349 pub(crate) fn start(&self) -> &BoundaryPoint {
350 self.abstract_range().start()
351 }
352
353 pub(crate) fn end(&self) -> &BoundaryPoint {
354 self.abstract_range().end()
355 }
356
357 pub(crate) fn start_container(&self) -> DomRoot<Node> {
358 self.abstract_range().StartContainer()
359 }
360
361 pub(crate) fn start_offset(&self) -> u32 {
362 self.abstract_range().StartOffset()
363 }
364
365 pub(crate) fn end_container(&self) -> DomRoot<Node> {
366 self.abstract_range().EndContainer()
367 }
368
369 pub(crate) fn end_offset(&self) -> u32 {
370 self.abstract_range().EndOffset()
371 }
372
373 pub(crate) fn collapsed(&self) -> bool {
374 self.abstract_range().Collapsed()
375 }
376
377 fn client_rects(&self, cx: &mut JSContext) -> Vec<Rect<Au, CSSPixel>> {
379 let start = self.start_container();
382 let end = self.end_container();
383 if !start.is_connected() || !end.is_connected() {
386 return vec![];
387 }
388
389 if self.collapsed() {
392 if start.is::<CharacterData>() {
393 return start.border_boxes(cx);
394 } else {
395 return vec![];
396 }
397 }
398
399 let document = start.owner_doc();
400 let nodes: Vec<DomRoot<Node>> = {
401 let unrooted_end = end.as_unrooted(cx.no_gc());
402 start
403 .following_nodes_unrooted(
404 cx.no_gc(),
405 document.upcast::<Node>(),
406 ShadowIncluding::No,
407 )
408 .take_while(|node| *node != *end)
409 .chain(iter::once(unrooted_end))
410 .map(|node| node.as_rooted())
411 .collect()
412 };
413
414 nodes
415 .iter()
416 .flat_map(move |node| node.border_boxes(cx))
417 .collect()
418 }
419
420 fn set_the_start_or_end(
422 &self,
423 no_gc: &NoGC,
424 node: &Node,
425 offset: u32,
426 start_or_end: StartOrEnd,
427 ) -> ErrorResult {
428 if node.is_doctype() {
431 return Err(Error::InvalidNodeType(Some("Node is a doctype".into())));
432 }
433
434 if offset > node.len() {
437 return Err(Error::IndexSize(Some(
438 "Offset is greater than the node's length".into(),
439 )));
440 }
441
442 let mut notification = SelectionLiveRangeNotification::empty();
445 match start_or_end {
446 StartOrEnd::Start => {
448 if self.root() != node.GetRootNode(&Default::default()) ||
451 bp_position(
452 no_gc,
453 node,
454 offset,
455 &self.end_container(),
456 self.end_offset(),
457 ) == Ordering::Greater
458 {
459 self.set_end_without_reporting(node, offset);
460 }
461
462 notification.set(
464 SelectionLiveRangeNotification::Start,
465 self.set_start_without_reporting(node, offset),
466 );
467 },
468 StartOrEnd::End => {
470 if self.root() != node.GetRootNode(&Default::default()) ||
473 bp_position(
474 no_gc,
475 node,
476 offset,
477 &self.start_container(),
478 self.start_offset(),
479 ) == Ordering::Less
480 {
481 self.set_start_without_reporting(node, offset);
482 }
483
484 notification.set(
486 SelectionLiveRangeNotification::End,
487 self.set_end_without_reporting(node, offset),
488 );
489 },
490 }
491
492 self.maybe_update_document();
493 self.report_change(no_gc, notification);
494 Ok(())
495 }
496
497 pub(crate) fn maybe_update_document(&self) {
506 debug_assert!(
508 self.start_container().owner_document() == self.end_container().owner_document(),
509 );
510
511 let current_document = self.document.get();
512 let new_document = self.start_container().owner_document();
513 if new_document != current_document {
514 current_document.live_ranges().remove(self);
515 new_document.live_ranges().push(WeakRef::new(self));
516 self.document.set(&new_document);
517 }
518 }
519
520 pub(crate) fn start_and_end_are_in_document_tree(&self) -> bool {
521 self.start_container().is_in_a_document_tree() &&
522 self.end_container().is_in_a_document_tree()
523 }
524}
525
526impl std::fmt::Debug for Range {
527 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
528 write!(
529 f,
530 "[({:?}, {}) -> ({:?}, {})]",
531 self.start_container(),
532 self.start_offset(),
533 self.end_container(),
534 self.end_offset()
535 )
536 }
537}
538
539#[derive(Copy, Clone)]
540pub(crate) enum StartOrEnd {
541 Start,
542 End,
543}
544
545impl RangeMethods<crate::DomTypeHolder> for Range {
546 fn Constructor(
548 cx: &mut JSContext,
549 window: &Window,
550 proto: Option<HandleObject>,
551 ) -> Fallible<DomRoot<Range>> {
552 let document = window.Document();
553 Ok(Range::new_with_doc(cx, &document, proto))
554 }
555
556 fn CommonAncestorContainer(&self) -> DomRoot<Node> {
558 self.end_container()
559 .common_ancestor(&self.start_container(), ShadowIncluding::No)
560 .expect("Couldn't find common ancestor container")
561 }
562
563 fn SetStart(&self, no_gc: &NoGC, node: &Node, offset: u32) -> ErrorResult {
565 self.set_the_start_or_end(no_gc, node, offset, StartOrEnd::Start)
566 }
567
568 fn SetEnd(&self, no_gc: &NoGC, node: &Node, offset: u32) -> ErrorResult {
570 self.set_the_start_or_end(no_gc, node, offset, StartOrEnd::End)
571 }
572
573 fn SetStartBefore(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
575 let parent = node
576 .GetParentNode()
577 .ok_or(Error::InvalidNodeType(Some("Node has no parent".into())))?;
578 self.SetStart(no_gc, &parent, node.index())
579 }
580
581 fn SetStartAfter(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
583 let parent = node
584 .GetParentNode()
585 .ok_or(Error::InvalidNodeType(Some("Node has no parent".into())))?;
586 self.SetStart(no_gc, &parent, node.index() + 1)
587 }
588
589 fn SetEndBefore(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
591 let parent = node
592 .GetParentNode()
593 .ok_or(Error::InvalidNodeType(Some("Node has no parent".into())))?;
594 self.SetEnd(no_gc, &parent, node.index())
595 }
596
597 fn SetEndAfter(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
599 let parent = node
600 .GetParentNode()
601 .ok_or(Error::InvalidNodeType(Some("Node has no parent".into())))?;
602 self.SetEnd(no_gc, &parent, node.index() + 1)
603 }
604
605 fn Collapse(&self, no_gc: &NoGC, to_start: bool) {
607 if to_start {
608 self.set_end(no_gc, &self.start_container(), self.start_offset());
609 } else {
610 self.set_start(no_gc, &self.end_container(), self.end_offset());
611 }
612 }
613
614 fn SelectNode(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
616 let parent = node
618 .GetParentNode()
619 .ok_or(Error::InvalidNodeType(Some("Node has no parent".into())))?;
620 let index = node.index();
622 self.set_start(no_gc, &parent, index);
624 self.set_end(no_gc, &parent, index + 1);
626 Ok(())
627 }
628
629 fn SelectNodeContents(&self, no_gc: &NoGC, node: &Node) -> ErrorResult {
631 if node.is_doctype() {
632 return Err(Error::InvalidNodeType(Some("Node is a doctype".into())));
634 }
635 let length = node.len();
637 self.set_start(no_gc, node, 0);
639 self.set_end(no_gc, node, length);
641 Ok(())
642 }
643
644 fn CompareBoundaryPoints(&self, no_gc: &NoGC, how: u16, source_range: &Range) -> Fallible<i16> {
646 if how > RangeConstants::END_TO_START {
653 return Err(Error::NotSupported(Some(
654 "Invalid comparison method".into(),
655 )));
656 }
657 if self.root() != source_range.root() {
660 return Err(Error::WrongDocument(Some(
661 "Ranges are not in the same tree".into(),
662 )));
663 }
664 let (this_point, source_point) = match how {
675 RangeConstants::START_TO_START => (self.start(), source_range.start()),
676 RangeConstants::START_TO_END => (self.end(), source_range.start()),
677 RangeConstants::END_TO_END => (self.end(), source_range.end()),
678 RangeConstants::END_TO_START => (self.start(), source_range.end()),
679 _ => unreachable!(),
680 };
681 match this_point.partial_cmp(no_gc, source_point).unwrap() {
689 Ordering::Less => Ok(-1),
690 Ordering::Equal => Ok(0),
691 Ordering::Greater => Ok(1),
692 }
693 }
694
695 fn CloneRange(&self, cx: &mut JSContext) -> DomRoot<Range> {
697 let start_node = self.start_container();
698 let owner_doc = start_node.owner_doc();
699 Range::new(
700 cx,
701 &owner_doc,
702 &start_node,
703 self.start_offset(),
704 &self.end_container(),
705 self.end_offset(),
706 )
707 }
708
709 fn IsPointInRange(&self, no_gc: &NoGC, node: &Node, offset: u32) -> Fallible<bool> {
711 match self.compare_point(no_gc, node, offset) {
712 Ok(Ordering::Less) => Ok(false),
713 Ok(Ordering::Equal) => Ok(true),
714 Ok(Ordering::Greater) => Ok(false),
715 Err(Error::WrongDocument(_)) => {
716 Ok(false)
719 },
720 Err(error) => Err(error),
721 }
722 }
723
724 fn ComparePoint(&self, no_gc: &NoGC, node: &Node, offset: u32) -> Fallible<i16> {
726 self.compare_point(no_gc, node, offset)
727 .map(|order| match order {
728 Ordering::Less => -1,
729 Ordering::Equal => 0,
730 Ordering::Greater => 1,
731 })
732 }
733
734 fn IntersectsNode(&self, no_gc: &NoGC, node: &Node) -> bool {
736 if self.root() != node.GetRootNode(&Default::default()) {
738 return false;
739 }
740 let Some(parent) = node.GetParentNode() else {
742 return true;
744 };
745 let offset = node.index();
747 let start_node = self.start_container();
751 Ordering::Greater ==
752 bp_position(no_gc, &parent, offset + 1, &start_node, self.start_offset()) &&
753 Ordering::Less ==
754 bp_position(
755 no_gc,
756 &parent,
757 offset,
758 &self.end_container(),
759 self.end_offset(),
760 )
761 }
762
763 fn CloneContents(&self, cx: &mut JSContext) -> Fallible<DomRoot<DocumentFragment>> {
766 let start_node = self.start_container();
768 let start_offset = self.start_offset();
769 let end_node = self.end_container();
770 let end_offset = self.end_offset();
771
772 let fragment = DocumentFragment::new(cx, &start_node.owner_doc());
774
775 if self.start() == self.end() {
777 return Ok(fragment);
778 }
779
780 if end_node == start_node &&
781 let Some(cdata) = start_node.downcast::<CharacterData>()
782 {
783 let data = cdata
785 .SubstringData(start_offset, end_offset - start_offset)
786 .unwrap();
787 let clone = cdata.clone_with_data(cx, data, &start_node.owner_doc());
788 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
790 return Ok(fragment);
792 }
793
794 let ContainedChildren {
796 first_partially_contained_child,
797 last_partially_contained_child,
798 contained_children,
799 } = self.contained_children(cx.no_gc())?;
800
801 if let Some(child) = first_partially_contained_child {
802 if let Some(cdata) = child.downcast::<CharacterData>() {
804 assert!(child == start_node);
805 let data = cdata
807 .SubstringData(start_offset, start_node.len() - start_offset)
808 .unwrap();
809 let clone = cdata.clone_with_data(cx, data, &start_node.owner_doc());
810 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
812 } else {
813 let clone = child.CloneNode(cx, false)?;
815 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
817 let subrange = Range::new(
819 cx,
820 &clone.owner_doc(),
821 &start_node,
822 start_offset,
823 &child,
824 child.len(),
825 );
826 let subfragment = subrange.CloneContents(cx)?;
828 clone.AppendChild(cx, subfragment.upcast())?;
830 }
831 }
832
833 for child in contained_children {
835 let clone = child.CloneNode(cx, true)?;
837 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
839 }
840
841 if let Some(child) = last_partially_contained_child {
842 if let Some(cdata) = child.downcast::<CharacterData>() {
844 assert!(child == end_node);
845 let data = cdata.SubstringData(0, end_offset).unwrap();
847 let clone = cdata.clone_with_data(cx, data, &start_node.owner_doc());
848 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
850 } else {
851 let clone = child.CloneNode(cx, false)?;
853 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
855 let subrange = Range::new(cx, &clone.owner_doc(), &child, 0, &end_node, end_offset);
857 let subfragment = subrange.CloneContents(cx)?;
859 clone.AppendChild(cx, subfragment.upcast())?;
861 }
862 }
863
864 Ok(fragment)
866 }
867
868 fn ExtractContents(&self, cx: &mut JSContext) -> Fallible<DomRoot<DocumentFragment>> {
871 let start_node = self.start_container();
873 let start_offset = self.start_offset();
874 let end_node = self.end_container();
875 let end_offset = self.end_offset();
876
877 let fragment = DocumentFragment::new(cx, &start_node.owner_doc());
879
880 if self.collapsed() {
882 return Ok(fragment);
883 }
884
885 if end_node == start_node &&
886 let Some(end_data) = end_node.downcast::<CharacterData>()
887 {
888 let clone = end_node.CloneNode(cx, true)?;
890 let text = end_data.SubstringData(start_offset, end_offset - start_offset);
892 clone
893 .downcast::<CharacterData>()
894 .unwrap()
895 .SetData(cx, text.unwrap());
896 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
898 end_data.ReplaceData(
900 cx,
901 start_offset,
902 end_offset - start_offset,
903 DOMString::new(),
904 )?;
905 return Ok(fragment);
907 }
908
909 let ContainedChildren {
911 first_partially_contained_child,
912 last_partially_contained_child,
913 contained_children,
914 } = self.contained_children(cx.no_gc())?;
915
916 let (new_node, new_offset) = if start_node.is_inclusive_ancestor_of(&end_node) {
917 (DomRoot::from_ref(&*start_node), start_offset)
919 } else {
920 let reference_node = start_node
922 .ancestors()
923 .take_while(|n| !n.is_inclusive_ancestor_of(&end_node))
924 .last()
925 .unwrap_or(DomRoot::from_ref(&start_node));
926 (
928 reference_node.GetParentNode().unwrap(),
929 reference_node.index() + 1,
930 )
931 };
932
933 if let Some(child) = first_partially_contained_child {
934 if let Some(start_data) = child.downcast::<CharacterData>() {
935 assert!(child == start_node);
936 let clone = start_node.CloneNode(cx, true)?;
938 let text = start_data.SubstringData(start_offset, start_node.len() - start_offset);
940 clone
941 .downcast::<CharacterData>()
942 .unwrap()
943 .SetData(cx, text.unwrap());
944 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
946 start_data.ReplaceData(
948 cx,
949 start_offset,
950 start_node.len() - start_offset,
951 DOMString::new(),
952 )?;
953 } else {
954 let clone = child.CloneNode(cx, false)?;
956 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
958 let subrange = Range::new(
960 cx,
961 &clone.owner_doc(),
962 &start_node,
963 start_offset,
964 &child,
965 child.len(),
966 );
967 let subfragment = subrange.ExtractContents(cx)?;
969 clone.AppendChild(cx, subfragment.upcast())?;
971 }
972 }
973
974 for child in contained_children {
976 fragment.upcast::<Node>().AppendChild(cx, &child)?;
977 }
978
979 if let Some(child) = last_partially_contained_child {
980 if let Some(end_data) = child.downcast::<CharacterData>() {
981 assert!(child == end_node);
982 let clone = end_node.CloneNode(cx, true)?;
984 let text = end_data.SubstringData(0, end_offset);
986 clone
987 .downcast::<CharacterData>()
988 .unwrap()
989 .SetData(cx, text.unwrap());
990 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
992 end_data.ReplaceData(cx, 0, end_offset, DOMString::new())?;
994 } else {
995 let clone = child.CloneNode(cx, false)?;
997 fragment.upcast::<Node>().AppendChild(cx, &clone)?;
999 let subrange = Range::new(cx, &clone.owner_doc(), &child, 0, &end_node, end_offset);
1001 let subfragment = subrange.ExtractContents(cx)?;
1003 clone.AppendChild(cx, subfragment.upcast())?;
1005 }
1006 }
1007
1008 self.SetStart(cx.no_gc(), &new_node, new_offset)?;
1010 self.SetEnd(cx.no_gc(), &new_node, new_offset)?;
1011
1012 Ok(fragment)
1014 }
1015
1016 fn Detach(&self) {
1020 }
1022
1023 fn InsertNode(&self, cx: &mut JSContext, node: &Node) -> ErrorResult {
1026 let start_node = self.start_container();
1027 let start_offset = self.start_offset();
1028
1029 if &*start_node == node {
1031 return Err(Error::HierarchyRequest(Some(
1032 "Node is the range's start container".into(),
1033 )));
1034 }
1035 match start_node.type_id() {
1036 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => (),
1038 NodeTypeId::CharacterData(_) => {
1039 return Err(Error::HierarchyRequest(Some(
1040 "Cannot insert into a Comment or ProcessingInstruction node".into(),
1041 )));
1042 },
1043 _ => (),
1044 }
1045
1046 let (reference_node, parent) = match start_node.type_id() {
1048 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
1049 let parent = match start_node.GetParentNode() {
1051 Some(parent) => parent,
1052 None => {
1054 return Err(Error::HierarchyRequest(Some(
1055 "Range's start container has no parent".into(),
1056 )));
1057 },
1058 };
1059 (Some(DomRoot::from_ref(&*start_node)), parent)
1061 },
1062 _ => {
1063 let child = start_node.ChildNodes(cx).Item(cx, start_offset);
1065 (child, DomRoot::from_ref(&*start_node))
1066 },
1067 };
1068
1069 Node::ensure_pre_insertion_validity(
1071 cx.no_gc(),
1072 node,
1073 &parent,
1074 reference_node.as_deref(),
1075 &[],
1076 )?;
1077
1078 let split_text;
1080 let reference_node = match start_node.downcast::<Text>() {
1081 Some(text) => {
1082 split_text = text.SplitText(cx, start_offset)?;
1083 let new_reference = DomRoot::upcast::<Node>(split_text);
1084 assert!(new_reference.GetParentNode().as_deref() == Some(&parent));
1085 Some(new_reference)
1086 },
1087 _ => reference_node,
1088 };
1089
1090 let reference_node = if Some(node) == reference_node.as_deref() {
1092 node.GetNextSibling()
1093 } else {
1094 reference_node
1095 };
1096
1097 node.remove_self(cx);
1099
1100 let new_offset = reference_node
1102 .as_ref()
1103 .map_or(parent.len(), |node| node.index());
1104
1105 let new_offset = new_offset +
1107 if let NodeTypeId::DocumentFragment(_) = node.type_id() {
1108 node.len()
1109 } else {
1110 1
1111 };
1112
1113 Node::pre_insert(cx, node, &parent, reference_node.as_deref())?;
1115
1116 if self.collapsed() {
1118 self.set_end(cx.no_gc(), &parent, new_offset);
1119 }
1120
1121 Ok(())
1122 }
1123
1124 fn DeleteContents(&self, cx: &mut JSContext) -> ErrorResult {
1126 if self.collapsed() {
1128 return Ok(());
1129 }
1130
1131 let start_node = self.start_container();
1134 let end_node = self.end_container();
1135 let start_offset = self.start_offset();
1136 let end_offset = self.end_offset();
1137
1138 if start_node == end_node &&
1140 let Some(text) = start_node.downcast::<CharacterData>()
1141 {
1142 return text.ReplaceData(
1146 cx,
1147 start_offset,
1148 end_offset - start_offset,
1149 DOMString::new(),
1150 );
1151 }
1152
1153 rooted_vec!(let mut contained_children);
1156 let ancestor = self.CommonAncestorContainer();
1157
1158 let mut iter = start_node.following_nodes(&ancestor, ShadowIncluding::No);
1159
1160 let mut next = iter.next();
1161 while let Some(child) = next {
1162 if self.contains(cx.no_gc(), &child) {
1163 contained_children.push(Dom::from_ref(&*child));
1164 next = iter.next_skipping_children();
1165 } else {
1166 next = iter.next();
1167 }
1168 }
1169
1170 let (new_node, new_offset) = if start_node.is_inclusive_ancestor_of(&end_node) {
1174 (DomRoot::from_ref(&*start_node), start_offset)
1175 } else {
1176 fn compute_reference(start_node: &Node, end_node: &Node) -> (DomRoot<Node>, u32) {
1178 let mut reference_node = DomRoot::from_ref(start_node);
1180 while let Some(parent) = reference_node.GetParentNode() {
1183 if parent.is_inclusive_ancestor_of(end_node) {
1184 return (parent, reference_node.index() + 1);
1186 }
1187 reference_node = parent;
1188 }
1189 unreachable!()
1190 }
1191
1192 compute_reference(&start_node, &end_node)
1193 };
1194
1195 self.SetStart(cx.no_gc(), &new_node, new_offset).unwrap();
1197 self.SetEnd(cx.no_gc(), &new_node, new_offset).unwrap();
1198
1199 if let Some(text) = start_node.downcast::<CharacterData>() {
1203 text.ReplaceData(
1204 cx,
1205 start_offset,
1206 start_node.len() - start_offset,
1207 DOMString::new(),
1208 )
1209 .unwrap();
1210 }
1211
1212 for child in &*contained_children {
1214 child.remove_self(cx);
1215 }
1216
1217 if let Some(text) = end_node.downcast::<CharacterData>() {
1220 text.ReplaceData(cx, 0, end_offset, DOMString::new())
1221 .unwrap();
1222 }
1223
1224 Ok(())
1225 }
1226
1227 fn SurroundContents(&self, cx: &mut JSContext, new_parent: &Node) -> ErrorResult {
1229 let start = self.start_container();
1231 let end = self.end_container();
1232
1233 if start
1234 .inclusive_ancestors(ShadowIncluding::No)
1235 .any(|n| !n.is_inclusive_ancestor_of(&end) && !n.is::<Text>()) ||
1236 end.inclusive_ancestors(ShadowIncluding::No)
1237 .any(|n| !n.is_inclusive_ancestor_of(&start) && !n.is::<Text>())
1238 {
1239 return Err(Error::InvalidState(Some(
1240 "Range partially contains a non-Text node".into(),
1241 )));
1242 }
1243
1244 match new_parent.type_id() {
1246 NodeTypeId::Document(_) |
1247 NodeTypeId::DocumentType |
1248 NodeTypeId::DocumentFragment(_) => {
1249 return Err(Error::InvalidNodeType(Some(
1250 "Node cannot be a Document, DocumentType or DocumentFragment".into(),
1251 )));
1252 },
1253 _ => (),
1254 }
1255
1256 let fragment = self.ExtractContents(cx)?;
1258
1259 Node::replace_all(cx, None, new_parent);
1261
1262 self.InsertNode(cx, new_parent)?;
1264
1265 new_parent.AppendChild(cx, fragment.upcast())?;
1267
1268 self.SelectNode(cx.no_gc(), new_parent)
1270 }
1271
1272 fn Stringifier(&self, no_gc: &NoGC) -> DOMString {
1274 let start_node = self.start_container();
1275 let end_node = self.end_container();
1276
1277 let mut s = DOMString::new();
1279
1280 if let Some(text_node) = start_node.downcast::<Text>() {
1281 let char_data = text_node.upcast::<CharacterData>();
1282
1283 if start_node == end_node {
1287 return char_data
1288 .SubstringData(self.start_offset(), self.end_offset() - self.start_offset())
1289 .unwrap();
1290 }
1291
1292 s.push_str(
1295 &char_data
1296 .SubstringData(
1297 self.start_offset(),
1298 char_data.Length() - self.start_offset(),
1299 )
1300 .unwrap()
1301 .str(),
1302 );
1303 }
1304
1305 let ancestor = self.CommonAncestorContainer();
1308 let iter = start_node
1309 .following_nodes_unrooted(no_gc, &ancestor, ShadowIncluding::No)
1310 .filter_map(UnrootedDom::downcast::<Text>);
1311
1312 for child in iter {
1313 if self.contains(no_gc, child.upcast()) {
1314 s.push_str(&child.upcast::<CharacterData>().Data().str());
1315 }
1316 }
1317
1318 if let Some(text_node) = end_node.downcast::<Text>() {
1321 let char_data = text_node.upcast::<CharacterData>();
1322 s.push_str(&char_data.SubstringData(0, self.end_offset()).unwrap().str());
1323 }
1324
1325 s
1327 }
1328
1329 fn CreateContextualFragment(
1331 &self,
1332 cx: &mut JSContext,
1333 fragment: TrustedHTMLOrString,
1334 ) -> Fallible<DomRoot<DocumentFragment>> {
1335 let node = self.start_container();
1340
1341 let fragment = TrustedHTML::get_trusted_type_compliant_string(
1345 cx,
1346 node.owner_window().upcast(),
1347 fragment,
1348 "Range createContextualFragment",
1349 )?;
1350
1351 let owner_doc = node.owner_doc();
1352
1353 let element = match node.type_id() {
1357 NodeTypeId::Element(_) => Some(DomRoot::downcast::<Element>(node).unwrap()),
1358 NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1359 NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => node.GetParentElement(),
1360 _ => None,
1361 };
1362
1363 let element = Element::fragment_parsing_context(cx, &owner_doc, element.as_deref());
1365
1366 let fragment_node = element.parse_fragment(fragment, cx)?;
1368
1369 for node in fragment_node
1371 .upcast::<Node>()
1372 .traverse_preorder(ShadowIncluding::No)
1373 {
1374 if let Some(script) = node.downcast::<HTMLScriptElement>() {
1375 script.set_already_started(false);
1377 script.set_parser_inserted(false);
1379 }
1380 }
1381
1382 Ok(fragment_node)
1384 }
1385
1386 fn GetClientRects(&self, cx: &mut JSContext) -> DomRoot<DOMRectList> {
1388 let start = self.start_container();
1389 let window = start.owner_window();
1390
1391 let client_rects = self.client_rects(cx);
1392 let client_rects = client_rects
1393 .iter()
1394 .map(|rect| {
1395 DOMRect::new(
1396 cx,
1397 window.upcast(),
1398 rect.origin.x.to_f64_px(),
1399 rect.origin.y.to_f64_px(),
1400 rect.size.width.to_f64_px(),
1401 rect.size.height.to_f64_px(),
1402 )
1403 })
1404 .collect();
1405
1406 DOMRectList::new(cx, &window, client_rects)
1407 }
1408
1409 fn GetBoundingClientRect(&self, cx: &mut JSContext) -> DomRoot<DOMRect> {
1411 let window = self.start_container().owner_window();
1412
1413 let list = self.client_rects(cx);
1415
1416 let bounding_rect = list
1421 .into_iter()
1422 .fold(euclid::Rect::zero(), |acc, rect| acc.union(&rect));
1423
1424 DOMRect::new(
1425 cx,
1426 window.upcast(),
1427 bounding_rect.origin.x.to_f64_px(),
1428 bounding_rect.origin.y.to_f64_px(),
1429 bounding_rect.size.width.to_f64_px(),
1430 bounding_rect.size.height.to_f64_px(),
1431 )
1432 }
1433}
1434
1435#[derive(MallocSizeOf)]
1436pub(crate) struct WeakRangeVec {
1437 cell: DomRefCell<WeakRefVec<Range>>,
1438}
1439
1440impl Default for WeakRangeVec {
1441 fn default() -> Self {
1442 WeakRangeVec {
1443 cell: DomRefCell::new(WeakRefVec::new()),
1444 }
1445 }
1446}
1447
1448impl WeakRangeVec {
1449 pub(crate) fn as_vec(&self) -> SmallVec<[DomRoot<Range>; 4]> {
1451 self.cell
1452 .borrow()
1453 .iter()
1454 .filter_map(|range| range.root())
1455 .collect()
1456 }
1457
1458 pub(crate) fn for_each(&self, no_gc: &NoGC, mut callback: impl FnMut(&Range)) {
1459 for weak_range in self.cell.safe_borrow_mut(no_gc).iter() {
1460 if let Some(range) = weak_range.unrooted(no_gc) {
1461 callback(&range);
1462 }
1463 }
1464 }
1465
1466 pub(crate) fn is_empty(&self) -> bool {
1467 self.cell.borrow().is_empty()
1468 }
1469
1470 fn push(&self, weak_range: WeakRef<Range>) {
1471 self.cell.borrow_mut().push(weak_range);
1472 }
1473
1474 fn remove(&self, range_to_remove: &Range) {
1475 self.cell
1476 .borrow_mut()
1477 .retain(|range| range != range_to_remove);
1478 }
1479}
1480
1481#[expect(unsafe_code)]
1482unsafe impl JSTraceable for WeakRangeVec {
1483 unsafe fn trace(&self, _: *mut JSTracer) {
1484 self.cell.borrow_mut().retain_alive()
1485 }
1486}
1487
1488impl Document {
1489 pub(crate) fn live_range_insert_steps(
1493 &self,
1494 no_gc: &NoGC,
1495 parent: &Node,
1496 child: &Node,
1497 count: u32,
1498 ) {
1499 if self.live_ranges().is_empty() {
1500 return;
1501 }
1502
1503 let child_index = LazyCell::new(|| child.index());
1504 self.live_ranges().for_each(no_gc, |range| {
1505 if &*range.start_container() == parent && range.start_offset() > *child_index {
1508 range.set_start_without_reporting(parent, range.start_offset() + count);
1509 }
1510 if &*range.end_container() == parent && range.end_offset() > *child_index {
1513 range.set_end_without_reporting(parent, range.end_offset() + count);
1514 }
1515 });
1516 }
1517
1518 pub(crate) fn live_range_pre_remove_steps(
1520 &self,
1521 no_gc: &NoGC,
1522 removed_node: &Node, parent_of_removed_node: &Node, index_of_removed_node: &mut dyn FnMut() -> u32, ) {
1526 if self.live_ranges().is_empty() {
1527 return;
1528 }
1529
1530 self.live_ranges().for_each(no_gc, |range| {
1539 let start_container = range.start_container();
1542 if removed_node.is_inclusive_ancestor_of(&start_container) {
1543 range.set_start_without_reporting(parent_of_removed_node, index_of_removed_node());
1544 }
1545 if removed_node.is_inclusive_ancestor_of(&range.end_container()) {
1548 range.set_end_without_reporting(parent_of_removed_node, index_of_removed_node());
1549 }
1550
1551 if &*range.start_container() == parent_of_removed_node &&
1554 range.start_offset() > index_of_removed_node()
1555 {
1556 range.set_start_without_reporting(parent_of_removed_node, range.start_offset() - 1);
1557 }
1558 if &*range.end_container() == parent_of_removed_node &&
1561 range.end_offset() > index_of_removed_node()
1562 {
1563 range.set_end_without_reporting(parent_of_removed_node, range.end_offset() - 1);
1564 }
1565 });
1566 }
1567
1568 pub(crate) fn live_range_normalization_steps(
1579 &self,
1580 no_gc: &NoGC,
1581 parent: &Node,
1582 node: &Node,
1583 current_node: &Node,
1584 current_node_index: &dyn Fn() -> u32,
1585 length: u32,
1586 ) {
1587 if self.live_ranges().is_empty() {
1588 return;
1589 }
1590
1591 self.live_ranges().for_each(no_gc, |range| {
1592 if &*range.start_container() == current_node {
1595 range.set_start_without_reporting(node, range.start_offset() + length);
1596 }
1597 if &*range.end_container() == current_node {
1600 range.set_end_without_reporting(node, range.end_offset() + length);
1601 }
1602
1603 if &*range.start_container() == parent && range.start_offset() == current_node_index() {
1607 range.set_start_without_reporting(node, length);
1608 }
1609 if &*range.end_container() == parent && range.end_offset() == current_node_index() {
1613 range.set_end_without_reporting(node, length);
1614 }
1615 });
1616 }
1617
1618 pub(crate) fn live_range_replace_data_steps(
1620 &self,
1621 no_gc: &NoGC,
1622 node: &Node,
1623 offset: u32,
1624 removed_code_units: u32,
1625 added_code_units: &mut dyn FnMut() -> u32,
1626 ) {
1627 if self.live_ranges().is_empty() {
1628 return;
1629 }
1630
1631 self.live_ranges().for_each(no_gc, |range| {
1632 let start_container = range.start_container();
1636 let start_offset = range.start_offset();
1637 if &*start_container == node &&
1638 start_offset > offset &&
1639 start_offset <= offset.saturating_add(removed_code_units)
1640 {
1641 range.set_start_without_reporting(node, offset);
1642 }
1643 let end_container = range.end_container();
1647 let end_offset = range.end_offset();
1648 if &*end_container == node &&
1649 end_offset > offset &&
1650 end_offset <= offset.saturating_add(removed_code_units)
1651 {
1652 range.set_end_without_reporting(node, offset);
1653 }
1654 if &*start_container == node && start_offset > offset.saturating_add(removed_code_units)
1658 {
1659 range.set_start_without_reporting(
1660 node,
1661 start_offset + added_code_units() - removed_code_units,
1662 );
1663 }
1664 if &*end_container == node && end_offset > offset.saturating_add(removed_code_units) {
1668 range.set_end_without_reporting(
1669 node,
1670 end_offset + added_code_units() - removed_code_units,
1671 );
1672 }
1673 });
1674 }
1675
1676 pub(crate) fn live_range_text_split_steps(
1678 &self,
1679 no_gc: &NoGC,
1680 parent: &Node,
1681 node: &Node,
1682 offset: u32,
1683 new_node: &Node,
1684 ) {
1685 if self.live_ranges().is_empty() {
1686 return;
1687 }
1688
1689 let node_index = LazyCell::new(|| node.index());
1690 self.live_ranges().for_each(no_gc, |range| {
1691 if &*range.start_container() == node && range.start_offset() > offset {
1695 range.set_start_without_reporting(new_node, range.start_offset() - offset);
1696 }
1697 if &*range.end_container() == node && range.end_offset() > offset {
1701 range.set_end_without_reporting(new_node, range.end_offset() - offset);
1702 }
1703
1704 if &*range.start_container() == parent && range.start_offset() == *node_index + 1 {
1707 range.set_start_without_reporting(parent, range.start_offset() + 1);
1708 }
1709
1710 if &*range.end_container() == parent && range.end_offset() == *node_index + 1 {
1713 range.set_end_without_reporting(parent, range.end_offset() + 1);
1714 }
1715 });
1716 }
1717}