script/dom/
range.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::RefCell;
6use std::cmp::{Ordering, PartialOrd};
7use std::iter;
8
9use dom_struct::dom_struct;
10use js::jsapi::JSTracer;
11use js::rust::HandleObject;
12
13use crate::dom::abstractrange::{AbstractRange, BoundaryPoint, bp_position};
14use crate::dom::bindings::cell::DomRefCell;
15use crate::dom::bindings::codegen::Bindings::AbstractRangeBinding::AbstractRangeMethods;
16use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
17use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
18use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
19use crate::dom::bindings::codegen::Bindings::RangeBinding::{RangeConstants, RangeMethods};
20use crate::dom::bindings::codegen::Bindings::TextBinding::TextMethods;
21use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
22use crate::dom::bindings::codegen::UnionTypes::TrustedHTMLOrString;
23use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
24use crate::dom::bindings::inheritance::{Castable, CharacterDataTypeId, NodeTypeId};
25use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
26use crate::dom::bindings::root::{Dom, DomRoot};
27use crate::dom::bindings::str::DOMString;
28use crate::dom::bindings::trace::JSTraceable;
29use crate::dom::bindings::weakref::{WeakRef, WeakRefVec};
30use crate::dom::characterdata::CharacterData;
31use crate::dom::document::Document;
32use crate::dom::documentfragment::DocumentFragment;
33use crate::dom::domrect::DOMRect;
34use crate::dom::domrectlist::DOMRectList;
35use crate::dom::element::Element;
36use crate::dom::html::htmlscriptelement::HTMLScriptElement;
37use crate::dom::node::{Node, NodeTraits, ShadowIncluding, UnbindContext};
38use crate::dom::selection::Selection;
39use crate::dom::text::Text;
40use crate::dom::trustedhtml::TrustedHTML;
41use crate::dom::window::Window;
42use crate::script_runtime::CanGc;
43
44#[dom_struct]
45pub(crate) struct Range {
46    abstract_range: AbstractRange,
47    // A range that belongs to a Selection needs to know about it
48    // so selectionchange can fire when the range changes.
49    // A range shouldn't belong to more than one Selection at a time,
50    // but from the spec as of Feb 1 2020 I can't rule out a corner case like:
51    // * Select a range R in document A, from node X to Y
52    // * Insert everything from X to Y into document B
53    // * Set B's selection's range to R
54    // which leaves R technically, and observably, associated with A even though
55    // it will fail the same-root-node check on many of A's selection's methods.
56    associated_selections: DomRefCell<Vec<Dom<Selection>>>,
57}
58
59struct ContainedChildren {
60    first_partially_contained_child: Option<DomRoot<Node>>,
61    last_partially_contained_child: Option<DomRoot<Node>>,
62    contained_children: Vec<DomRoot<Node>>,
63}
64
65impl Range {
66    fn new_inherited(
67        start_container: &Node,
68        start_offset: u32,
69        end_container: &Node,
70        end_offset: u32,
71    ) -> Range {
72        debug_assert!(start_offset <= start_container.len());
73        debug_assert!(end_offset <= end_container.len());
74        Range {
75            abstract_range: AbstractRange::new_inherited(
76                start_container,
77                start_offset,
78                end_container,
79                end_offset,
80            ),
81            associated_selections: DomRefCell::new(vec![]),
82        }
83    }
84
85    pub(crate) fn new_with_doc(
86        document: &Document,
87        proto: Option<HandleObject>,
88        can_gc: CanGc,
89    ) -> DomRoot<Range> {
90        let root = document.upcast();
91        Range::new_with_proto(document, proto, root, 0, root, 0, can_gc)
92    }
93
94    pub(crate) fn new(
95        document: &Document,
96        start_container: &Node,
97        start_offset: u32,
98        end_container: &Node,
99        end_offset: u32,
100        can_gc: CanGc,
101    ) -> DomRoot<Range> {
102        Self::new_with_proto(
103            document,
104            None,
105            start_container,
106            start_offset,
107            end_container,
108            end_offset,
109            can_gc,
110        )
111    }
112
113    fn new_with_proto(
114        document: &Document,
115        proto: Option<HandleObject>,
116        start_container: &Node,
117        start_offset: u32,
118        end_container: &Node,
119        end_offset: u32,
120        can_gc: CanGc,
121    ) -> DomRoot<Range> {
122        let range = reflect_dom_object_with_proto(
123            Box::new(Range::new_inherited(
124                start_container,
125                start_offset,
126                end_container,
127                end_offset,
128            )),
129            document.window(),
130            proto,
131            can_gc,
132        );
133        start_container.ranges().push(WeakRef::new(&range));
134        if start_container != end_container {
135            end_container.ranges().push(WeakRef::new(&range));
136        }
137        range
138    }
139
140    /// <https://dom.spec.whatwg.org/#contained>
141    fn contains(&self, node: &Node) -> bool {
142        matches!(
143            (
144                bp_position(node, 0, &self.start_container(), self.start_offset()),
145                bp_position(node, node.len(), &self.end_container(), self.end_offset()),
146            ),
147            (Some(Ordering::Greater), Some(Ordering::Less))
148        )
149    }
150
151    /// <https://dom.spec.whatwg.org/#partially-contained>
152    fn partially_contains(&self, node: &Node) -> bool {
153        self.start_container()
154            .inclusive_ancestors(ShadowIncluding::No)
155            .any(|n| &*n == node) !=
156            self.end_container()
157                .inclusive_ancestors(ShadowIncluding::No)
158                .any(|n| &*n == node)
159    }
160
161    /// <https://dom.spec.whatwg.org/#concept-range-clone>
162    fn contained_children(&self) -> Fallible<ContainedChildren> {
163        let start_node = self.start_container();
164        let end_node = self.end_container();
165        // Steps 5-6.
166        let common_ancestor = self.CommonAncestorContainer();
167
168        let first_partially_contained_child = if start_node.is_inclusive_ancestor_of(&end_node) {
169            // Step 7.
170            None
171        } else {
172            // Step 8.
173            common_ancestor
174                .children()
175                .find(|node| Range::partially_contains(self, node))
176        };
177
178        let last_partially_contained_child = if end_node.is_inclusive_ancestor_of(&start_node) {
179            // Step 9.
180            None
181        } else {
182            // Step 10.
183            common_ancestor
184                .rev_children()
185                .find(|node| Range::partially_contains(self, node))
186        };
187
188        // Step 11.
189        let contained_children: Vec<DomRoot<Node>> = common_ancestor
190            .children()
191            .filter(|n| self.contains(n))
192            .collect();
193
194        // Step 12.
195        if contained_children.iter().any(|n| n.is_doctype()) {
196            return Err(Error::HierarchyRequest);
197        }
198
199        Ok(ContainedChildren {
200            first_partially_contained_child,
201            last_partially_contained_child,
202            contained_children,
203        })
204    }
205
206    /// <https://dom.spec.whatwg.org/#concept-range-bp-set>
207    fn set_start(&self, node: &Node, offset: u32) {
208        if self.start().node() != node || self.start_offset() != offset {
209            self.report_change();
210        }
211        if self.start().node() != node {
212            if self.start().node() == self.end().node() {
213                node.ranges().push(WeakRef::new(self));
214            } else if self.end().node() == node {
215                self.start_container().ranges().remove(self);
216            } else {
217                node.ranges()
218                    .push(self.start_container().ranges().remove(self));
219            }
220        }
221        self.start().set(node, offset);
222    }
223
224    /// <https://dom.spec.whatwg.org/#concept-range-bp-set>
225    fn set_end(&self, node: &Node, offset: u32) {
226        if self.end().node() != node || self.end_offset() != offset {
227            self.report_change();
228        }
229        if self.end().node() != node {
230            if self.end().node() == self.start().node() {
231                node.ranges().push(WeakRef::new(self));
232            } else if self.start().node() == node {
233                self.end_container().ranges().remove(self);
234            } else {
235                node.ranges()
236                    .push(self.end_container().ranges().remove(self));
237            }
238        }
239        self.end().set(node, offset);
240    }
241
242    /// <https://dom.spec.whatwg.org/#dom-range-comparepointnode-offset>
243    fn compare_point(&self, node: &Node, offset: u32) -> Fallible<Ordering> {
244        let start_node = self.start_container();
245        let start_node_root = start_node
246            .inclusive_ancestors(ShadowIncluding::No)
247            .last()
248            .unwrap();
249        let node_root = node
250            .inclusive_ancestors(ShadowIncluding::No)
251            .last()
252            .unwrap();
253        if start_node_root != node_root {
254            // Step 1.
255            return Err(Error::WrongDocument);
256        }
257        if node.is_doctype() {
258            // Step 2.
259            return Err(Error::InvalidNodeType);
260        }
261        if offset > node.len() {
262            // Step 3.
263            return Err(Error::IndexSize);
264        }
265        if let Ordering::Less = bp_position(node, offset, &start_node, self.start_offset()).unwrap()
266        {
267            // Step 4.
268            return Ok(Ordering::Less);
269        }
270        if let Ordering::Greater =
271            bp_position(node, offset, &self.end_container(), self.end_offset()).unwrap()
272        {
273            // Step 5.
274            return Ok(Ordering::Greater);
275        }
276        // Step 6.
277        Ok(Ordering::Equal)
278    }
279
280    pub(crate) fn associate_selection(&self, selection: &Selection) {
281        let mut selections = self.associated_selections.borrow_mut();
282        if !selections.iter().any(|s| &**s == selection) {
283            selections.push(Dom::from_ref(selection));
284        }
285    }
286
287    pub(crate) fn disassociate_selection(&self, selection: &Selection) {
288        self.associated_selections
289            .borrow_mut()
290            .retain(|s| &**s != selection);
291    }
292
293    fn report_change(&self) {
294        self.associated_selections
295            .borrow()
296            .iter()
297            .for_each(|s| s.queue_selectionchange_task());
298    }
299
300    fn abstract_range(&self) -> &AbstractRange {
301        &self.abstract_range
302    }
303
304    fn start(&self) -> &BoundaryPoint {
305        self.abstract_range().start()
306    }
307
308    fn end(&self) -> &BoundaryPoint {
309        self.abstract_range().end()
310    }
311
312    pub(crate) fn start_container(&self) -> DomRoot<Node> {
313        self.abstract_range().StartContainer()
314    }
315
316    pub(crate) fn start_offset(&self) -> u32 {
317        self.abstract_range().StartOffset()
318    }
319
320    pub(crate) fn end_container(&self) -> DomRoot<Node> {
321        self.abstract_range().EndContainer()
322    }
323
324    pub(crate) fn end_offset(&self) -> u32 {
325        self.abstract_range().EndOffset()
326    }
327
328    pub(crate) fn collapsed(&self) -> bool {
329        self.abstract_range().Collapsed()
330    }
331
332    fn client_rects(
333        &self,
334    ) -> impl Iterator<Item = euclid::Rect<app_units::Au, euclid::UnknownUnit>> {
335        // FIXME: For text nodes that are only partially selected, this should return the client
336        // rect of the selected part, not the whole text node.
337        let start = self.start_container();
338        let end = self.end_container();
339        let document = start.owner_doc();
340        let end_clone = end.clone();
341        start
342            .following_nodes(document.upcast::<Node>())
343            .take_while(move |node| node != &end)
344            .chain(iter::once(end_clone))
345            .flat_map(move |node| node.border_boxes())
346    }
347
348    /// <https://dom.spec.whatwg.org/#concept-range-bp-set>
349    #[allow(clippy::neg_cmp_op_on_partial_ord)]
350    fn set_the_start_or_end(
351        &self,
352        node: &Node,
353        offset: u32,
354        start_or_end: StartOrEnd,
355    ) -> ErrorResult {
356        // Step 1. If node is a doctype, then throw an "InvalidNodeTypeError" DOMException.
357        if node.is_doctype() {
358            return Err(Error::InvalidNodeType);
359        }
360
361        // Step 2. If offset is greater than node’s length, then throw an "IndexSizeError" DOMException.
362        if offset > node.len() {
363            return Err(Error::IndexSize);
364        }
365
366        // Step 3. Let bp be the boundary point (node, offset).
367        // NOTE: We don't need this part.
368
369        match start_or_end {
370            // If these steps were invoked as "set the start"
371            StartOrEnd::Start => {
372                // Step 4.1  If range’s root is not equal to node’s root, or if bp is after the range’s end,
373                // set range’s end to bp.
374                // Step 4.2 Set range’s start to bp.
375                self.set_start(node, offset);
376                if !(self.start() <= self.end()) {
377                    self.set_end(node, offset);
378                }
379            },
380            // If these steps were invoked as "set the end"
381            StartOrEnd::End => {
382                // Step 4.1 If range’s root is not equal to node’s root, or if bp is before the range’s start,
383                // set range’s start to bp.
384                // Step 4.2 Set range’s end to bp.
385                self.set_end(node, offset);
386                if !(self.end() >= self.start()) {
387                    self.set_start(node, offset);
388                }
389            },
390        }
391
392        Ok(())
393    }
394}
395
396enum StartOrEnd {
397    Start,
398    End,
399}
400
401impl RangeMethods<crate::DomTypeHolder> for Range {
402    /// <https://dom.spec.whatwg.org/#dom-range>
403    fn Constructor(
404        window: &Window,
405        proto: Option<HandleObject>,
406        can_gc: CanGc,
407    ) -> Fallible<DomRoot<Range>> {
408        let document = window.Document();
409        Ok(Range::new_with_doc(&document, proto, can_gc))
410    }
411
412    /// <https://dom.spec.whatwg.org/#dom-range-commonancestorcontainer>
413    fn CommonAncestorContainer(&self) -> DomRoot<Node> {
414        self.end_container()
415            .common_ancestor(&self.start_container(), ShadowIncluding::No)
416            .expect("Couldn't find common ancestor container")
417    }
418
419    /// <https://dom.spec.whatwg.org/#dom-range-setstart>
420    fn SetStart(&self, node: &Node, offset: u32) -> ErrorResult {
421        self.set_the_start_or_end(node, offset, StartOrEnd::Start)
422    }
423
424    /// <https://dom.spec.whatwg.org/#dom-range-setend>
425    fn SetEnd(&self, node: &Node, offset: u32) -> ErrorResult {
426        self.set_the_start_or_end(node, offset, StartOrEnd::End)
427    }
428
429    /// <https://dom.spec.whatwg.org/#dom-range-setstartbefore>
430    fn SetStartBefore(&self, node: &Node) -> ErrorResult {
431        let parent = node.GetParentNode().ok_or(Error::InvalidNodeType)?;
432        self.SetStart(&parent, node.index())
433    }
434
435    /// <https://dom.spec.whatwg.org/#dom-range-setstartafter>
436    fn SetStartAfter(&self, node: &Node) -> ErrorResult {
437        let parent = node.GetParentNode().ok_or(Error::InvalidNodeType)?;
438        self.SetStart(&parent, node.index() + 1)
439    }
440
441    /// <https://dom.spec.whatwg.org/#dom-range-setendbefore>
442    fn SetEndBefore(&self, node: &Node) -> ErrorResult {
443        let parent = node.GetParentNode().ok_or(Error::InvalidNodeType)?;
444        self.SetEnd(&parent, node.index())
445    }
446
447    /// <https://dom.spec.whatwg.org/#dom-range-setendafter>
448    fn SetEndAfter(&self, node: &Node) -> ErrorResult {
449        let parent = node.GetParentNode().ok_or(Error::InvalidNodeType)?;
450        self.SetEnd(&parent, node.index() + 1)
451    }
452
453    /// <https://dom.spec.whatwg.org/#dom-range-collapse>
454    fn Collapse(&self, to_start: bool) {
455        if to_start {
456            self.set_end(&self.start_container(), self.start_offset());
457        } else {
458            self.set_start(&self.end_container(), self.end_offset());
459        }
460    }
461
462    /// <https://dom.spec.whatwg.org/#dom-range-selectnode>
463    fn SelectNode(&self, node: &Node) -> ErrorResult {
464        // Steps 1, 2.
465        let parent = node.GetParentNode().ok_or(Error::InvalidNodeType)?;
466        // Step 3.
467        let index = node.index();
468        // Step 4.
469        self.set_start(&parent, index);
470        // Step 5.
471        self.set_end(&parent, index + 1);
472        Ok(())
473    }
474
475    /// <https://dom.spec.whatwg.org/#dom-range-selectnodecontents>
476    fn SelectNodeContents(&self, node: &Node) -> ErrorResult {
477        if node.is_doctype() {
478            // Step 1.
479            return Err(Error::InvalidNodeType);
480        }
481        // Step 2.
482        let length = node.len();
483        // Step 3.
484        self.set_start(node, 0);
485        // Step 4.
486        self.set_end(node, length);
487        Ok(())
488    }
489
490    /// <https://dom.spec.whatwg.org/#dom-range-compareboundarypoints>
491    fn CompareBoundaryPoints(&self, how: u16, other: &Range) -> Fallible<i16> {
492        if how > RangeConstants::END_TO_START {
493            // Step 1.
494            return Err(Error::NotSupported);
495        }
496        let this_root = self
497            .start_container()
498            .inclusive_ancestors(ShadowIncluding::No)
499            .last()
500            .unwrap();
501        let other_root = other
502            .start_container()
503            .inclusive_ancestors(ShadowIncluding::No)
504            .last()
505            .unwrap();
506        if this_root != other_root {
507            // Step 2.
508            return Err(Error::WrongDocument);
509        }
510        // Step 3.
511        let (this_point, other_point) = match how {
512            RangeConstants::START_TO_START => (self.start(), other.start()),
513            RangeConstants::START_TO_END => (self.end(), other.start()),
514            RangeConstants::END_TO_END => (self.end(), other.end()),
515            RangeConstants::END_TO_START => (self.start(), other.end()),
516            _ => unreachable!(),
517        };
518        // step 4.
519        match this_point.partial_cmp(other_point).unwrap() {
520            Ordering::Less => Ok(-1),
521            Ordering::Equal => Ok(0),
522            Ordering::Greater => Ok(1),
523        }
524    }
525
526    /// <https://dom.spec.whatwg.org/#dom-range-clonerange>
527    fn CloneRange(&self, can_gc: CanGc) -> DomRoot<Range> {
528        let start_node = self.start_container();
529        let owner_doc = start_node.owner_doc();
530        Range::new(
531            &owner_doc,
532            &start_node,
533            self.start_offset(),
534            &self.end_container(),
535            self.end_offset(),
536            can_gc,
537        )
538    }
539
540    /// <https://dom.spec.whatwg.org/#dom-range-ispointinrange>
541    fn IsPointInRange(&self, node: &Node, offset: u32) -> Fallible<bool> {
542        match self.compare_point(node, offset) {
543            Ok(Ordering::Less) => Ok(false),
544            Ok(Ordering::Equal) => Ok(true),
545            Ok(Ordering::Greater) => Ok(false),
546            Err(Error::WrongDocument) => {
547                // Step 2.
548                Ok(false)
549            },
550            Err(error) => Err(error),
551        }
552    }
553
554    /// <https://dom.spec.whatwg.org/#dom-range-comparepoint>
555    fn ComparePoint(&self, node: &Node, offset: u32) -> Fallible<i16> {
556        self.compare_point(node, offset).map(|order| match order {
557            Ordering::Less => -1,
558            Ordering::Equal => 0,
559            Ordering::Greater => 1,
560        })
561    }
562
563    /// <https://dom.spec.whatwg.org/#dom-range-intersectsnode>
564    fn IntersectsNode(&self, node: &Node) -> bool {
565        let start_node = self.start_container();
566        let start_node_root = self
567            .start_container()
568            .inclusive_ancestors(ShadowIncluding::No)
569            .last()
570            .unwrap();
571        let node_root = node
572            .inclusive_ancestors(ShadowIncluding::No)
573            .last()
574            .unwrap();
575        if start_node_root != node_root {
576            // Step 1.
577            return false;
578        }
579        let parent = match node.GetParentNode() {
580            Some(parent) => parent,
581            None => {
582                // Step 3.
583                return true;
584            },
585        };
586        // Step 4.
587        let offset = node.index();
588        // Step 5.
589        Ordering::Greater ==
590            bp_position(&parent, offset + 1, &start_node, self.start_offset()).unwrap() &&
591            Ordering::Less ==
592                bp_position(&parent, offset, &self.end_container(), self.end_offset())
593                    .unwrap()
594    }
595
596    /// <https://dom.spec.whatwg.org/#dom-range-clonecontents>
597    /// <https://dom.spec.whatwg.org/#concept-range-clone>
598    fn CloneContents(&self, can_gc: CanGc) -> Fallible<DomRoot<DocumentFragment>> {
599        // Step 3.
600        let start_node = self.start_container();
601        let start_offset = self.start_offset();
602        let end_node = self.end_container();
603        let end_offset = self.end_offset();
604
605        // Step 1.
606        let fragment = DocumentFragment::new(&start_node.owner_doc(), can_gc);
607
608        // Step 2.
609        if self.start() == self.end() {
610            return Ok(fragment);
611        }
612
613        if end_node == start_node {
614            if let Some(cdata) = start_node.downcast::<CharacterData>() {
615                // Steps 4.1-2.
616                let data = cdata
617                    .SubstringData(start_offset, end_offset - start_offset)
618                    .unwrap();
619                let clone = cdata.clone_with_data(data, &start_node.owner_doc(), can_gc);
620                // Step 4.3.
621                fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
622                // Step 4.4
623                return Ok(fragment);
624            }
625        }
626
627        // Steps 5-12.
628        let ContainedChildren {
629            first_partially_contained_child,
630            last_partially_contained_child,
631            contained_children,
632        } = self.contained_children()?;
633
634        if let Some(child) = first_partially_contained_child {
635            // Step 13.
636            if let Some(cdata) = child.downcast::<CharacterData>() {
637                assert!(child == start_node);
638                // Steps 13.1-2.
639                let data = cdata
640                    .SubstringData(start_offset, start_node.len() - start_offset)
641                    .unwrap();
642                let clone = cdata.clone_with_data(data, &start_node.owner_doc(), can_gc);
643                // Step 13.3.
644                fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
645            } else {
646                // Step 14.1.
647                let clone = child.CloneNode(/* deep */ false, can_gc)?;
648                // Step 14.2.
649                fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
650                // Step 14.3.
651                let subrange = Range::new(
652                    &clone.owner_doc(),
653                    &start_node,
654                    start_offset,
655                    &child,
656                    child.len(),
657                    can_gc,
658                );
659                // Step 14.4.
660                let subfragment = subrange.CloneContents(can_gc)?;
661                // Step 14.5.
662                clone.AppendChild(subfragment.upcast(), can_gc)?;
663            }
664        }
665
666        // Step 15.
667        for child in contained_children {
668            // Step 15.1.
669            let clone = child.CloneNode(/* deep */ true, can_gc)?;
670            // Step 15.2.
671            fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
672        }
673
674        if let Some(child) = last_partially_contained_child {
675            // Step 16.
676            if let Some(cdata) = child.downcast::<CharacterData>() {
677                assert!(child == end_node);
678                // Steps 16.1-2.
679                let data = cdata.SubstringData(0, end_offset).unwrap();
680                let clone = cdata.clone_with_data(data, &start_node.owner_doc(), can_gc);
681                // Step 16.3.
682                fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
683            } else {
684                // Step 17.1.
685                let clone = child.CloneNode(/* deep */ false, can_gc)?;
686                // Step 17.2.
687                fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
688                // Step 17.3.
689                let subrange =
690                    Range::new(&clone.owner_doc(), &child, 0, &end_node, end_offset, can_gc);
691                // Step 17.4.
692                let subfragment = subrange.CloneContents(can_gc)?;
693                // Step 17.5.
694                clone.AppendChild(subfragment.upcast(), can_gc)?;
695            }
696        }
697
698        // Step 18.
699        Ok(fragment)
700    }
701
702    /// <https://dom.spec.whatwg.org/#dom-range-extractcontents>
703    /// <https://dom.spec.whatwg.org/#concept-range-extract>
704    fn ExtractContents(&self, can_gc: CanGc) -> Fallible<DomRoot<DocumentFragment>> {
705        // Step 3.
706        let start_node = self.start_container();
707        let start_offset = self.start_offset();
708        let end_node = self.end_container();
709        let end_offset = self.end_offset();
710
711        // Step 1.
712        let fragment = DocumentFragment::new(&start_node.owner_doc(), can_gc);
713
714        // Step 2.
715        if self.collapsed() {
716            return Ok(fragment);
717        }
718
719        if end_node == start_node {
720            if let Some(end_data) = end_node.downcast::<CharacterData>() {
721                // Step 4.1.
722                let clone = end_node.CloneNode(/* deep */ true, can_gc)?;
723                // Step 4.2.
724                let text = end_data.SubstringData(start_offset, end_offset - start_offset);
725                clone
726                    .downcast::<CharacterData>()
727                    .unwrap()
728                    .SetData(text.unwrap());
729                // Step 4.3.
730                fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
731                // Step 4.4.
732                end_data.ReplaceData(start_offset, end_offset - start_offset, DOMString::new())?;
733                // Step 4.5.
734                return Ok(fragment);
735            }
736        }
737
738        // Steps 5-12.
739        let ContainedChildren {
740            first_partially_contained_child,
741            last_partially_contained_child,
742            contained_children,
743        } = self.contained_children()?;
744
745        let (new_node, new_offset) = if start_node.is_inclusive_ancestor_of(&end_node) {
746            // Step 13.
747            (DomRoot::from_ref(&*start_node), start_offset)
748        } else {
749            // Step 14.1-2.
750            let reference_node = start_node
751                .ancestors()
752                .take_while(|n| !n.is_inclusive_ancestor_of(&end_node))
753                .last()
754                .unwrap_or(DomRoot::from_ref(&start_node));
755            // Step 14.3.
756            (
757                reference_node.GetParentNode().unwrap(),
758                reference_node.index() + 1,
759            )
760        };
761
762        if let Some(child) = first_partially_contained_child {
763            if let Some(start_data) = child.downcast::<CharacterData>() {
764                assert!(child == start_node);
765                // Step 15.1.
766                let clone = start_node.CloneNode(/* deep */ true, can_gc)?;
767                // Step 15.2.
768                let text = start_data.SubstringData(start_offset, start_node.len() - start_offset);
769                clone
770                    .downcast::<CharacterData>()
771                    .unwrap()
772                    .SetData(text.unwrap());
773                // Step 15.3.
774                fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
775                // Step 15.4.
776                start_data.ReplaceData(
777                    start_offset,
778                    start_node.len() - start_offset,
779                    DOMString::new(),
780                )?;
781            } else {
782                // Step 16.1.
783                let clone = child.CloneNode(/* deep */ false, can_gc)?;
784                // Step 16.2.
785                fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
786                // Step 16.3.
787                let subrange = Range::new(
788                    &clone.owner_doc(),
789                    &start_node,
790                    start_offset,
791                    &child,
792                    child.len(),
793                    can_gc,
794                );
795                // Step 16.4.
796                let subfragment = subrange.ExtractContents(can_gc)?;
797                // Step 16.5.
798                clone.AppendChild(subfragment.upcast(), can_gc)?;
799            }
800        }
801
802        // Step 17.
803        for child in contained_children {
804            fragment.upcast::<Node>().AppendChild(&child, can_gc)?;
805        }
806
807        if let Some(child) = last_partially_contained_child {
808            if let Some(end_data) = child.downcast::<CharacterData>() {
809                assert!(child == end_node);
810                // Step 18.1.
811                let clone = end_node.CloneNode(/* deep */ true, can_gc)?;
812                // Step 18.2.
813                let text = end_data.SubstringData(0, end_offset);
814                clone
815                    .downcast::<CharacterData>()
816                    .unwrap()
817                    .SetData(text.unwrap());
818                // Step 18.3.
819                fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
820                // Step 18.4.
821                end_data.ReplaceData(0, end_offset, DOMString::new())?;
822            } else {
823                // Step 19.1.
824                let clone = child.CloneNode(/* deep */ false, can_gc)?;
825                // Step 19.2.
826                fragment.upcast::<Node>().AppendChild(&clone, can_gc)?;
827                // Step 19.3.
828                let subrange =
829                    Range::new(&clone.owner_doc(), &child, 0, &end_node, end_offset, can_gc);
830                // Step 19.4.
831                let subfragment = subrange.ExtractContents(can_gc)?;
832                // Step 19.5.
833                clone.AppendChild(subfragment.upcast(), can_gc)?;
834            }
835        }
836
837        // Step 20.
838        self.SetStart(&new_node, new_offset)?;
839        self.SetEnd(&new_node, new_offset)?;
840
841        // Step 21.
842        Ok(fragment)
843    }
844
845    /// <https://dom.spec.whatwg.org/#dom-range-detach>
846    fn Detach(&self) {
847        // This method intentionally left blank.
848    }
849
850    /// <https://dom.spec.whatwg.org/#dom-range-insertnode>
851    /// <https://dom.spec.whatwg.org/#concept-range-insert>
852    fn InsertNode(&self, node: &Node, can_gc: CanGc) -> ErrorResult {
853        let start_node = self.start_container();
854        let start_offset = self.start_offset();
855
856        // Step 1.
857        if &*start_node == node {
858            return Err(Error::HierarchyRequest);
859        }
860        match start_node.type_id() {
861            // Handled under step 2.
862            NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => (),
863            NodeTypeId::CharacterData(_) => return Err(Error::HierarchyRequest),
864            _ => (),
865        }
866
867        // Step 2.
868        let (reference_node, parent) = match start_node.type_id() {
869            NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
870                // Step 3.
871                let parent = match start_node.GetParentNode() {
872                    Some(parent) => parent,
873                    // Step 1.
874                    None => return Err(Error::HierarchyRequest),
875                };
876                // Step 5.
877                (Some(DomRoot::from_ref(&*start_node)), parent)
878            },
879            _ => {
880                // Steps 4-5.
881                let child = start_node.ChildNodes(can_gc).Item(start_offset);
882                (child, DomRoot::from_ref(&*start_node))
883            },
884        };
885
886        // Step 6.
887        Node::ensure_pre_insertion_validity(node, &parent, reference_node.as_deref())?;
888
889        // Step 7.
890        let split_text;
891        let reference_node = match start_node.downcast::<Text>() {
892            Some(text) => {
893                split_text = text.SplitText(start_offset, can_gc)?;
894                let new_reference = DomRoot::upcast::<Node>(split_text);
895                assert!(new_reference.GetParentNode().as_deref() == Some(&parent));
896                Some(new_reference)
897            },
898            _ => reference_node,
899        };
900
901        // Step 8.
902        let reference_node = if Some(node) == reference_node.as_deref() {
903            node.GetNextSibling()
904        } else {
905            reference_node
906        };
907
908        // Step 9.
909        node.remove_self(can_gc);
910
911        // Step 10.
912        let new_offset = reference_node
913            .as_ref()
914            .map_or(parent.len(), |node| node.index());
915
916        // Step 11
917        let new_offset = new_offset +
918            if let NodeTypeId::DocumentFragment(_) = node.type_id() {
919                node.len()
920            } else {
921                1
922            };
923
924        // Step 12.
925        Node::pre_insert(node, &parent, reference_node.as_deref(), can_gc)?;
926
927        // Step 13.
928        if self.collapsed() {
929            self.set_end(&parent, new_offset);
930        }
931
932        Ok(())
933    }
934
935    /// <https://dom.spec.whatwg.org/#dom-range-deletecontents>
936    fn DeleteContents(&self) -> ErrorResult {
937        // Step 1.
938        if self.collapsed() {
939            return Ok(());
940        }
941
942        // Step 2.
943        let start_node = self.start_container();
944        let end_node = self.end_container();
945        let start_offset = self.start_offset();
946        let end_offset = self.end_offset();
947
948        // Step 3.
949        if start_node == end_node {
950            if let Some(text) = start_node.downcast::<CharacterData>() {
951                if end_offset > start_offset {
952                    self.report_change();
953                }
954                return text.ReplaceData(start_offset, end_offset - start_offset, DOMString::new());
955            }
956        }
957
958        // Step 4.
959        rooted_vec!(let mut contained_children);
960        let ancestor = self.CommonAncestorContainer();
961
962        let mut iter = start_node.following_nodes(&ancestor);
963
964        let mut next = iter.next();
965        while let Some(child) = next {
966            if self.contains(&child) {
967                contained_children.push(Dom::from_ref(&*child));
968                next = iter.next_skipping_children();
969            } else {
970                next = iter.next();
971            }
972        }
973
974        let (new_node, new_offset) = if start_node.is_inclusive_ancestor_of(&end_node) {
975            // Step 5.
976            (DomRoot::from_ref(&*start_node), start_offset)
977        } else {
978            // Step 6.
979            fn compute_reference(start_node: &Node, end_node: &Node) -> (DomRoot<Node>, u32) {
980                let mut reference_node = DomRoot::from_ref(start_node);
981                while let Some(parent) = reference_node.GetParentNode() {
982                    if parent.is_inclusive_ancestor_of(end_node) {
983                        return (parent, reference_node.index() + 1);
984                    }
985                    reference_node = parent;
986                }
987                unreachable!()
988            }
989
990            compute_reference(&start_node, &end_node)
991        };
992
993        // Step 7.
994        if let Some(text) = start_node.downcast::<CharacterData>() {
995            text.ReplaceData(
996                start_offset,
997                start_node.len() - start_offset,
998                DOMString::new(),
999            )
1000            .unwrap();
1001        }
1002
1003        // Step 8.
1004        for child in &*contained_children {
1005            child.remove_self(CanGc::note());
1006        }
1007
1008        // Step 9.
1009        if let Some(text) = end_node.downcast::<CharacterData>() {
1010            text.ReplaceData(0, end_offset, DOMString::new()).unwrap();
1011        }
1012
1013        // Step 10.
1014        self.SetStart(&new_node, new_offset).unwrap();
1015        self.SetEnd(&new_node, new_offset).unwrap();
1016        Ok(())
1017    }
1018
1019    /// <https://dom.spec.whatwg.org/#dom-range-surroundcontents>
1020    fn SurroundContents(&self, new_parent: &Node, can_gc: CanGc) -> ErrorResult {
1021        // Step 1.
1022        let start = self.start_container();
1023        let end = self.end_container();
1024
1025        if start
1026            .inclusive_ancestors(ShadowIncluding::No)
1027            .any(|n| !n.is_inclusive_ancestor_of(&end) && !n.is::<Text>()) ||
1028            end.inclusive_ancestors(ShadowIncluding::No)
1029                .any(|n| !n.is_inclusive_ancestor_of(&start) && !n.is::<Text>())
1030        {
1031            return Err(Error::InvalidState);
1032        }
1033
1034        // Step 2.
1035        match new_parent.type_id() {
1036            NodeTypeId::Document(_) |
1037            NodeTypeId::DocumentType |
1038            NodeTypeId::DocumentFragment(_) => {
1039                return Err(Error::InvalidNodeType);
1040            },
1041            _ => (),
1042        }
1043
1044        // Step 3.
1045        let fragment = self.ExtractContents(can_gc)?;
1046
1047        // Step 4.
1048        Node::replace_all(None, new_parent, can_gc);
1049
1050        // Step 5.
1051        self.InsertNode(new_parent, can_gc)?;
1052
1053        // Step 6.
1054        new_parent.AppendChild(fragment.upcast(), can_gc)?;
1055
1056        // Step 7.
1057        self.SelectNode(new_parent)
1058    }
1059
1060    /// <https://dom.spec.whatwg.org/#dom-range-stringifier>
1061    fn Stringifier(&self) -> DOMString {
1062        let start_node = self.start_container();
1063        let end_node = self.end_container();
1064
1065        // Step 1.
1066        let mut s = DOMString::new();
1067
1068        if let Some(text_node) = start_node.downcast::<Text>() {
1069            let char_data = text_node.upcast::<CharacterData>();
1070
1071            // Step 2.
1072            if start_node == end_node {
1073                return char_data
1074                    .SubstringData(self.start_offset(), self.end_offset() - self.start_offset())
1075                    .unwrap();
1076            }
1077
1078            // Step 3.
1079            s.push_str(
1080                &char_data
1081                    .SubstringData(
1082                        self.start_offset(),
1083                        char_data.Length() - self.start_offset(),
1084                    )
1085                    .unwrap(),
1086            );
1087        }
1088
1089        // Step 4.
1090        let ancestor = self.CommonAncestorContainer();
1091        let iter = start_node
1092            .following_nodes(&ancestor)
1093            .filter_map(DomRoot::downcast::<Text>);
1094
1095        for child in iter {
1096            if self.contains(child.upcast()) {
1097                s.push_str(&child.upcast::<CharacterData>().Data());
1098            }
1099        }
1100
1101        // Step 5.
1102        if let Some(text_node) = end_node.downcast::<Text>() {
1103            let char_data = text_node.upcast::<CharacterData>();
1104            s.push_str(&char_data.SubstringData(0, self.end_offset()).unwrap());
1105        }
1106
1107        // Step 6.
1108        s
1109    }
1110
1111    /// <https://html.spec.whatwg.org/multipage/#dom-range-createcontextualfragment>
1112    fn CreateContextualFragment(
1113        &self,
1114        fragment: TrustedHTMLOrString,
1115        can_gc: CanGc,
1116    ) -> Fallible<DomRoot<DocumentFragment>> {
1117        // Step 2. Let node be this's start node.
1118        //
1119        // Required to obtain the global, so we do this first. Shouldn't be an
1120        // observable difference.
1121        let node = self.start_container();
1122        // Step 1. Let compliantString be the result of invoking the
1123        // Get Trusted Type compliant string algorithm with TrustedHTML,
1124        // this's relevant global object, string, "Range createContextualFragment", and "script".
1125        let fragment = TrustedHTML::get_trusted_script_compliant_string(
1126            node.owner_window().upcast(),
1127            fragment,
1128            "Range createContextualFragment",
1129            can_gc,
1130        )?;
1131        let owner_doc = node.owner_doc();
1132        let element = match node.type_id() {
1133            // Step 3. Let element be null.
1134            NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) => None,
1135            // Step 4. If node implements Element, set element to node.
1136            NodeTypeId::Element(_) => Some(DomRoot::downcast::<Element>(node).unwrap()),
1137            // Step 5. Otherwise, if node implements Text or Comment, set element to node's parent element.
1138            NodeTypeId::CharacterData(CharacterDataTypeId::Comment) |
1139            NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => node.GetParentElement(),
1140            NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
1141            NodeTypeId::DocumentType => unreachable!(),
1142            NodeTypeId::Attr => unreachable!(),
1143        };
1144
1145        // Step 6. If element is null or all of the following are true:
1146        let element = Element::fragment_parsing_context(&owner_doc, element.as_deref(), can_gc);
1147
1148        // Step 7. Let fragment node be the result of invoking the fragment parsing algorithm steps with element and compliantString.
1149        let fragment_node = element.parse_fragment(fragment, can_gc)?;
1150
1151        // Step 8. For each script of fragment node's script element descendants:
1152        for node in fragment_node
1153            .upcast::<Node>()
1154            .traverse_preorder(ShadowIncluding::No)
1155        {
1156            if let Some(script) = node.downcast::<HTMLScriptElement>() {
1157                // Step 8.1. Set script's already started to false.
1158                script.set_already_started(false);
1159                // Step 8.2. Set script's parser document to null.
1160                script.set_parser_inserted(false);
1161            }
1162        }
1163
1164        // Step 9. Return fragment node.
1165        Ok(fragment_node)
1166    }
1167
1168    /// <https://drafts.csswg.org/cssom-view/#dom-range-getclientrects>
1169    fn GetClientRects(&self, can_gc: CanGc) -> DomRoot<DOMRectList> {
1170        let start = self.start_container();
1171        let window = start.owner_window();
1172
1173        let client_rects = self
1174            .client_rects()
1175            .map(|rect| {
1176                DOMRect::new(
1177                    window.upcast(),
1178                    rect.origin.x.to_f64_px(),
1179                    rect.origin.y.to_f64_px(),
1180                    rect.size.width.to_f64_px(),
1181                    rect.size.height.to_f64_px(),
1182                    can_gc,
1183                )
1184            })
1185            .collect();
1186
1187        DOMRectList::new(&window, client_rects, can_gc)
1188    }
1189
1190    /// <https://drafts.csswg.org/cssom-view/#dom-range-getboundingclientrect>
1191    fn GetBoundingClientRect(&self, can_gc: CanGc) -> DomRoot<DOMRect> {
1192        let window = self.start_container().owner_window();
1193
1194        // Step 1. Let list be the result of invoking getClientRects() on the same range this method was invoked on.
1195        let list = self.client_rects();
1196
1197        // Step 2. If list is empty return a DOMRect object whose x, y, width and height members are zero.
1198        // Step 3. If all rectangles in list have zero width or height, return the first rectangle in list.
1199        // Step 4. Otherwise, return a DOMRect object describing the smallest rectangle that includes all
1200        // of the rectangles in list of which the height or width is not zero.
1201        let bounding_rect = list.fold(euclid::Rect::zero(), |acc, rect| acc.union(&rect));
1202
1203        DOMRect::new(
1204            window.upcast(),
1205            bounding_rect.origin.x.to_f64_px(),
1206            bounding_rect.origin.y.to_f64_px(),
1207            bounding_rect.size.width.to_f64_px(),
1208            bounding_rect.size.height.to_f64_px(),
1209            can_gc,
1210        )
1211    }
1212}
1213
1214#[derive(MallocSizeOf)]
1215pub(crate) struct WeakRangeVec {
1216    cell: RefCell<WeakRefVec<Range>>,
1217}
1218
1219impl Default for WeakRangeVec {
1220    fn default() -> Self {
1221        WeakRangeVec {
1222            cell: RefCell::new(WeakRefVec::new()),
1223        }
1224    }
1225}
1226
1227#[allow(unsafe_code)]
1228impl WeakRangeVec {
1229    /// Whether that vector of ranges is empty.
1230    pub(crate) fn is_empty(&self) -> bool {
1231        self.cell.borrow().is_empty()
1232    }
1233
1234    /// Used for steps 2.1-2. when inserting a node.
1235    /// <https://dom.spec.whatwg.org/#concept-node-insert>
1236    pub(crate) fn increase_above(&self, node: &Node, offset: u32, delta: u32) {
1237        self.map_offset_above(node, offset, |offset| offset + delta);
1238    }
1239
1240    /// Used for steps 4-5. when removing a node.
1241    /// <https://dom.spec.whatwg.org/#concept-node-remove>
1242    pub(crate) fn decrease_above(&self, node: &Node, offset: u32, delta: u32) {
1243        self.map_offset_above(node, offset, |offset| offset - delta);
1244    }
1245
1246    /// Used for steps 2-3. when removing a node.
1247    ///
1248    /// <https://dom.spec.whatwg.org/#concept-node-remove>
1249    pub(crate) fn drain_to_parent(&self, context: &UnbindContext, child: &Node) {
1250        if self.is_empty() {
1251            return;
1252        }
1253
1254        let offset = context.index();
1255        let parent = context.parent;
1256        let ranges = &mut *self.cell.borrow_mut();
1257
1258        ranges.update(|entry| {
1259            let range = entry.root().unwrap();
1260            if range.start().node() == parent || range.end().node() == parent {
1261                entry.remove();
1262            }
1263            if range.start().node() == child {
1264                range.report_change();
1265                range.start().set(context.parent, offset);
1266            }
1267            if range.end().node() == child {
1268                range.report_change();
1269                range.end().set(context.parent, offset);
1270            }
1271        });
1272
1273        context
1274            .parent
1275            .ranges()
1276            .cell
1277            .borrow_mut()
1278            .extend(ranges.drain(..));
1279    }
1280
1281    /// Used for steps 6.1-2. when normalizing a node.
1282    /// <https://dom.spec.whatwg.org/#dom-node-normalize>
1283    pub(crate) fn drain_to_preceding_text_sibling(&self, node: &Node, sibling: &Node, length: u32) {
1284        if self.is_empty() {
1285            return;
1286        }
1287
1288        let ranges = &mut *self.cell.borrow_mut();
1289
1290        ranges.update(|entry| {
1291            let range = entry.root().unwrap();
1292            if range.start().node() == sibling || range.end().node() == sibling {
1293                entry.remove();
1294            }
1295            if range.start().node() == node {
1296                range.report_change();
1297                range.start().set(sibling, range.start_offset() + length);
1298            }
1299            if range.end().node() == node {
1300                range.report_change();
1301                range.end().set(sibling, range.end_offset() + length);
1302            }
1303        });
1304
1305        sibling.ranges().cell.borrow_mut().extend(ranges.drain(..));
1306    }
1307
1308    /// Used for steps 6.3-4. when normalizing a node.
1309    /// <https://dom.spec.whatwg.org/#dom-node-normalize>
1310    pub(crate) fn move_to_text_child_at(
1311        &self,
1312        node: &Node,
1313        offset: u32,
1314        child: &Node,
1315        new_offset: u32,
1316    ) {
1317        let child_ranges = child.ranges();
1318        let mut child_ranges = child_ranges.cell.borrow_mut();
1319
1320        self.cell.borrow_mut().update(|entry| {
1321            let range = entry.root().unwrap();
1322
1323            let node_is_start = range.start().node() == node;
1324            let node_is_end = range.end().node() == node;
1325
1326            let move_start = node_is_start && range.start_offset() == offset;
1327            let move_end = node_is_end && range.end_offset() == offset;
1328
1329            let remove_from_node =
1330                move_start && (move_end || !node_is_end) || move_end && !node_is_start;
1331
1332            let already_in_child = range.start().node() == child || range.end().node() == child;
1333            let push_to_child = !already_in_child && (move_start || move_end);
1334
1335            if remove_from_node {
1336                let ref_ = entry.remove();
1337                if push_to_child {
1338                    child_ranges.push(ref_);
1339                }
1340            } else if push_to_child {
1341                child_ranges.push(WeakRef::new(&range));
1342            }
1343
1344            if move_start {
1345                range.report_change();
1346                range.start().set(child, new_offset);
1347            }
1348            if move_end {
1349                range.report_change();
1350                range.end().set(child, new_offset);
1351            }
1352        });
1353    }
1354
1355    /// Used for steps 8-11. when replacing character data.
1356    /// <https://dom.spec.whatwg.org/#concept-cd-replace>
1357    pub(crate) fn replace_code_units(
1358        &self,
1359        node: &Node,
1360        offset: u32,
1361        removed_code_units: u32,
1362        added_code_units: u32,
1363    ) {
1364        self.map_offset_above(node, offset, |range_offset| {
1365            if range_offset <= offset + removed_code_units {
1366                offset
1367            } else {
1368                range_offset + added_code_units - removed_code_units
1369            }
1370        });
1371    }
1372
1373    /// Used for steps 7.2-3. when splitting a text node.
1374    /// <https://dom.spec.whatwg.org/#concept-text-split>
1375    pub(crate) fn move_to_following_text_sibling_above(
1376        &self,
1377        node: &Node,
1378        offset: u32,
1379        sibling: &Node,
1380    ) {
1381        let sibling_ranges = sibling.ranges();
1382        let mut sibling_ranges = sibling_ranges.cell.borrow_mut();
1383
1384        self.cell.borrow_mut().update(|entry| {
1385            let range = entry.root().unwrap();
1386            let start_offset = range.start_offset();
1387            let end_offset = range.end_offset();
1388
1389            let node_is_start = range.start().node() == node;
1390            let node_is_end = range.end().node() == node;
1391
1392            let move_start = node_is_start && start_offset > offset;
1393            let move_end = node_is_end && end_offset > offset;
1394
1395            let remove_from_node =
1396                move_start && (move_end || !node_is_end) || move_end && !node_is_start;
1397
1398            let already_in_sibling =
1399                range.start().node() == sibling || range.end().node() == sibling;
1400            let push_to_sibling = !already_in_sibling && (move_start || move_end);
1401
1402            if remove_from_node {
1403                let ref_ = entry.remove();
1404                if push_to_sibling {
1405                    sibling_ranges.push(ref_);
1406                }
1407            } else if push_to_sibling {
1408                sibling_ranges.push(WeakRef::new(&range));
1409            }
1410
1411            if move_start {
1412                range.report_change();
1413                range.start().set(sibling, start_offset - offset);
1414            }
1415            if move_end {
1416                range.report_change();
1417                range.end().set(sibling, end_offset - offset);
1418            }
1419        });
1420    }
1421
1422    /// Used for steps 7.4-5. when splitting a text node.
1423    /// <https://dom.spec.whatwg.org/#concept-text-split>
1424    pub(crate) fn increment_at(&self, node: &Node, offset: u32) {
1425        self.cell.borrow_mut().update(|entry| {
1426            let range = entry.root().unwrap();
1427            if range.start().node() == node && offset == range.start_offset() {
1428                range.report_change();
1429                range.start().set_offset(offset + 1);
1430            }
1431            if range.end().node() == node && offset == range.end_offset() {
1432                range.report_change();
1433                range.end().set_offset(offset + 1);
1434            }
1435        });
1436    }
1437
1438    fn map_offset_above<F: FnMut(u32) -> u32>(&self, node: &Node, offset: u32, mut f: F) {
1439        self.cell.borrow_mut().update(|entry| {
1440            let range = entry.root().unwrap();
1441            let start_offset = range.start_offset();
1442            if range.start().node() == node && start_offset > offset {
1443                range.report_change();
1444                range.start().set_offset(f(start_offset));
1445            }
1446            let end_offset = range.end_offset();
1447            if range.end().node() == node && end_offset > offset {
1448                range.report_change();
1449                range.end().set_offset(f(end_offset));
1450            }
1451        });
1452    }
1453
1454    pub(crate) fn push(&self, ref_: WeakRef<Range>) {
1455        self.cell.borrow_mut().push(ref_);
1456    }
1457
1458    fn remove(&self, range: &Range) -> WeakRef<Range> {
1459        let mut ranges = self.cell.borrow_mut();
1460        let position = ranges.iter().position(|ref_| ref_ == range).unwrap();
1461        ranges.swap_remove(position)
1462    }
1463}
1464
1465#[allow(unsafe_code)]
1466unsafe impl JSTraceable for WeakRangeVec {
1467    unsafe fn trace(&self, _: *mut JSTracer) {
1468        self.cell.borrow_mut().retain_alive()
1469    }
1470}