1use std::cell::{Cell, LazyCell};
6use std::cmp::Ordering;
7
8use bitflags::bitflags;
9use dom_struct::dom_struct;
10use js::context::{JSContext, NoGC};
11use rustc_hash::FxHashSet;
12use script_bindings::cell::DomRefCell;
13use script_bindings::codegen::GenericBindings::ShadowRootBinding::ShadowRootMethods;
14use script_bindings::dom::UnrootedDom;
15use script_bindings::reflector::{Reflector, reflect_dom_object};
16use servo_base::text::{RangeAny, Utf16CodeUnits, Utf32CodeUnits, Utf32CodeUnitsOrNodeOffset};
17
18use crate::dom::abstractrange::bp_position;
19use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
20use crate::dom::bindings::codegen::Bindings::RangeBinding::RangeMethods;
21use crate::dom::bindings::codegen::Bindings::SelectionBinding::SelectionMethods;
22use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
23use crate::dom::bindings::inheritance::Castable;
24use crate::dom::bindings::refcounted::Trusted;
25use crate::dom::bindings::reflector::DomGlobal;
26use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom};
27use crate::dom::bindings::str::DOMString;
28use crate::dom::document::Document;
29use crate::dom::eventtarget::EventTarget;
30use crate::dom::iterators::PrePostIteration;
31use crate::dom::node::{Node, NodeTraits};
32use crate::dom::range::Range;
33use crate::dom::selection_range::{SelectionBoundary, SelectionRange};
34use crate::dom::types::ShadowRoot;
35use crate::dom::{CharacterData, FlatTreeParent, NodeDamage, NodeFlags};
36
37#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
38enum Direction {
39 Forwards,
40 Backwards,
41 Directionless,
42}
43
44#[dom_struct]
46pub(crate) struct Selection {
47 reflector_: Reflector,
48 document: Dom<Document>,
49 range: DomRefCell<Option<SelectionRange>>,
52 live_range: MutNullableDom<Range>,
54 direction: Cell<Direction>,
57 has_scheduled_selectionchange_event: Cell<bool>,
59 visible_selection_dirty: Cell<bool>,
62}
63
64impl Selection {
65 fn new_inherited(document: &Document) -> Selection {
66 Selection {
67 reflector_: Reflector::new(),
68 document: Dom::from_ref(document),
69 range: Default::default(),
70 live_range: MutNullableDom::new(None),
71 direction: Cell::new(Direction::Directionless),
72 has_scheduled_selectionchange_event: Cell::new(false),
73 visible_selection_dirty: Cell::new(false),
74 }
75 }
76
77 pub(crate) fn new(cx: &mut JSContext, document: &Document) -> DomRoot<Selection> {
78 reflect_dom_object(
79 cx,
80 Box::new(Selection::new_inherited(document)),
81 &*document.global(),
82 )
83 }
84
85 pub(crate) fn visible_selection_dirty(&self) -> bool {
86 self.visible_selection_dirty.get()
87 }
88
89 fn clear_cached_live_range(&self) {
90 if let Some(old_range) = self.live_range.take() {
91 old_range.disassociate_selection(self);
92 }
93 }
94
95 pub(crate) fn update_from_live_range(
96 &self,
97 live_range: &Range,
98 notification: SelectionLiveRangeNotification,
99 ) {
100 let start_changed;
101 let end_changed;
102 {
103 let mut range = self.range.borrow_mut();
104 let range = range
105 .as_mut()
106 .expect("A live range implies a selection range");
107
108 start_changed = notification.contains(SelectionLiveRangeNotification::Start) &&
109 range.start != *live_range.start();
110 if start_changed {
111 range.start =
112 SelectionBoundary::new(&live_range.start_container(), live_range.start_offset())
113 }
114
115 end_changed = notification.contains(SelectionLiveRangeNotification::End) &&
116 range.end != *live_range.end();
117 if end_changed {
118 range.end =
119 SelectionBoundary::new(&live_range.end_container(), live_range.end_offset())
120 }
121 }
122
123 if start_changed || end_changed {
124 self.selection_boundaries_changed();
125 }
126 }
127
128 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
129 fn set_range(&self, new_range: Option<SelectionRange>) -> bool {
130 let changed;
131 {
132 let mut range = self.range.borrow_mut();
133 changed = *range != new_range;
134 *range = new_range;
135 }
136
137 self.clear_cached_live_range();
139
140 if changed {
141 self.selection_boundaries_changed();
142 self.assert_valid_selection();
143 }
144
145 changed
146 }
147
148 pub(crate) fn set_live_range(&self, new_range: Option<&Range>) {
149 if new_range == self.live_range.get().as_deref() {
150 return;
151 }
152
153 let boundaries_changed = self.set_range(new_range.map(|new_range| new_range.into()));
154
155 if let Some(old_range) = self.live_range.take() {
158 old_range.disassociate_selection(self);
159 }
160 if let Some(new_range) = new_range {
161 self.live_range.set(Some(new_range));
162 new_range.associate_selection(self);
163 }
164
165 if !boundaries_changed {
176 self.queue_selectionchange_task();
177 }
178 }
179
180 fn selection_boundaries_changed(&self) {
181 self.set_visible_selection_dirty();
182 self.queue_selectionchange_task();
183
184 self.document.clear_command_overrides();
193 }
194
195 fn iter_nodes_with_overlaps_document_selection_flag<'no_gc>(
196 &self,
197 no_gc: &'no_gc NoGC,
198 ) -> impl Iterator<Item = UnrootedDom<'no_gc, Node>> {
199 let mut traversal = self
200 .document
201 .upcast::<Node>()
202 .following_flat_tree_nodes_unrooted(no_gc);
203 let mut next = traversal.next();
204 std::iter::from_fn(move || {
205 while let Some(node) = next.take() {
206 match node {
207 PrePostIteration::Enter(node) => {
208 if node.get_flag(NodeFlags::OVERLAPS_DOCUMENT_SELECTION) {
209 next = traversal.next();
210 return Some(node);
211 } else {
212 next = traversal.next_skipping_subtree();
217 }
218 },
219 PrePostIteration::Leave(_) => next = traversal.next(),
220 }
221 }
222 None
223 })
224 }
225
226 pub(crate) fn update_overlaps_document_selection_flags<'no_gc>(&self, no_gc: &'no_gc NoGC) {
227 if !self.visible_selection_dirty.take() {
228 return;
229 }
230
231 let previously_flagged_nodes = self.iter_nodes_with_overlaps_document_selection_flag(no_gc);
232
233 let needs_new_display_list = Cell::new(false);
234 let set_text_run_selection =
235 |character_data: &CharacterData, range: Option<RangeAny<Utf32CodeUnits>>| {
236 if character_data.set_text_run_selection(range) {
237 needs_new_display_list.set(true)
238 } else {
239 character_data
240 .upcast::<Node>()
241 .dirty(no_gc, NodeDamage::ContentOrHeritage);
242 }
243 };
244 let remove_selection = |node: &Node| {
245 node.set_flag(NodeFlags::OVERLAPS_DOCUMENT_SELECTION, false);
246 if let Some(character_data) = node.downcast::<CharacterData>() {
248 set_text_run_selection(character_data, None)
249 }
250 };
251
252 let range = self.range.borrow();
253 let Some(range) = range.as_ref() else {
254 for node in previously_flagged_nodes {
255 remove_selection(&node)
256 }
257 if needs_new_display_list.get() {
258 self.document.window().layout().set_needs_new_display_list();
259 }
260 return;
261 };
262
263 let mut previously_flagged_nodes: FxHashSet<_> = previously_flagged_nodes.collect();
266
267 let start_offset = range.start.offset as usize;
268 let end_offset = range.end.offset as usize;
269 let start_container = range.start.container.as_rooted();
270 let end_container = range.end.container.as_rooted();
271 let start_position =
272 position_in_flat_tree_for_selection(no_gc, start_container.clone(), start_offset);
273 let end_position =
274 position_in_flat_tree_for_selection(no_gc, end_container.clone(), end_offset);
275
276 let start_node = start_position.node();
277 let end_node = end_position.node();
278
279 if let Some(character_data) = start_container.downcast::<CharacterData>() {
286 let text = character_data.data();
287 let range = RangeAny {
288 start: Some(Utf16CodeUnits(start_offset).to_utf32_code_units_in(&text)),
289 end: (start_node == end_node)
290 .then_some(Utf16CodeUnits(end_offset).to_utf32_code_units_in(&text)),
291 };
292 set_text_run_selection(character_data, Some(range))
293 }
294 if end_container != start_container &&
295 let Some(character_data) = end_container.downcast::<CharacterData>()
296 {
297 let text = character_data.data();
298 let range = RangeAny {
299 start: None,
300 end: Some(Utf16CodeUnits(end_offset).to_utf32_code_units_in(&text)),
301 };
302 set_text_run_selection(character_data, Some(range))
303 }
304
305 let mut set_selection_flag = |node: &UnrootedDom<'no_gc, Node>| {
306 if !node.get_flag(NodeFlags::OVERLAPS_DOCUMENT_SELECTION) {
307 node.set_flag(NodeFlags::OVERLAPS_DOCUMENT_SELECTION, true);
308 debug_assert!(!previously_flagged_nodes.contains(node));
309 } else {
310 previously_flagged_nodes.remove(node);
311 }
312 };
313
314 let mut maybe_parent = start_node.parent_in_flat_tree(no_gc);
320 while let FlatTreeParent::Parent(parent) = maybe_parent {
321 set_selection_flag(&parent);
322 maybe_parent = parent.parent_in_flat_tree(no_gc);
323 }
324
325 let mut traversal = start_node.following_flat_tree_nodes_unrooted(no_gc);
326
327 if matches!(start_position, FlatTreeNodePosition::After(_)) {
330 let leaving_start = traversal.next_skipping_subtree();
331 debug_assert!(
332 matches!(leaving_start, Some(PrePostIteration::Leave(node)) if node == *start_node)
333 );
334 }
335
336 for iteration in traversal {
337 match &iteration {
338 PrePostIteration::Enter(node) => {
339 if node == end_node && matches!(end_position, FlatTreeNodePosition::Before(_)) {
340 break;
341 }
342 if node == start_node {
343 continue;
344 }
345 set_selection_flag(node);
346 },
347 PrePostIteration::Leave(node) => {
348 set_selection_flag(node);
349 if node == end_node {
350 break;
351 }
352 if let Some(character_data) = node.downcast::<CharacterData>() {
353 set_text_run_selection(character_data, Some(RangeAny::full()))
354 }
355 },
356 }
357 }
358
359 for node in &previously_flagged_nodes {
362 remove_selection(node)
363 }
364 if needs_new_display_list.get() {
365 self.document.window().layout().set_needs_new_display_list();
366 }
367 }
368
369 pub(crate) fn queue_selectionchange_task(&self) {
371 if self.has_scheduled_selectionchange_event.get() {
373 return;
374 }
375 self.has_scheduled_selectionchange_event.set(true);
377 let this = Trusted::new(self);
380 self.document
381 .owner_global()
382 .task_manager()
383 .user_interaction_task_source() .queue(
385 task!(selectionchange_task_steps: move |cx| {
387 let this = this.root();
388 this.has_scheduled_selectionchange_event.set(false);
390 this.document.upcast::<EventTarget>().fire_event(cx, atom!("selectionchange"));
399 }),
400 );
401 }
402
403 fn is_in_document_of_range(&self, node: &Node) -> bool {
404 &*node.GetRootNode(&GetRootNodeOptions { composed: false }) ==
408 self.document.upcast::<Node>()
409 }
410
411 pub(crate) fn start_boundary(&self, cx: &mut JSContext) -> (DomRoot<Node>, u32) {
412 let range = self.expect_active_range(cx);
413 (range.start_container(), range.start_offset())
414 }
415
416 pub(crate) fn end_boundary(&self, cx: &mut JSContext) -> (DomRoot<Node>, u32) {
417 let range = self.expect_active_range(cx);
418 (range.end_container(), range.end_offset())
419 }
420
421 fn assert_valid_selection(&self) {
422 #[cfg(not(debug_assertions))]
423 return;
424
425 let range_borrow = self.range.borrow();
426 let Some(range) = range_borrow.as_ref() else {
427 return;
428 };
429 debug_assert_eq!(
430 range.start.container.GetRootNode(&Default::default()),
431 range.end.container.GetRootNode(&Default::default())
432 );
433 debug_assert!(
434 bp_position(
435 &range.start.container,
436 range.start.offset,
437 &range.end.container,
438 range.end.offset
439 ) != Ordering::Greater
440 );
441 }
442
443 fn assert_valid_selection_and_live_range(&self) {
444 #[cfg(not(debug_assertions))]
445 return;
446
447 self.assert_valid_selection();
448
449 let Some(active_range) = self.live_range.get() else {
450 return;
451 };
452
453 let range = self.range.borrow();
456 let range = range
457 .as_ref()
458 .expect("Should always have a range if we have an live range");
459 debug_assert!(*range.start.container == *active_range.start_container());
460 debug_assert_eq!(range.start.offset, active_range.start_offset());
461 debug_assert!(*range.end.container == *active_range.end_container());
462 debug_assert_eq!(range.end.offset, active_range.end_offset());
463 debug_assert!(
464 bp_position(
465 &active_range.start_container(),
466 active_range.start_offset(),
467 &active_range.end_container(),
468 active_range.end_offset()
469 ) != Ordering::Greater
470 );
471 }
472
473 pub(crate) fn active_range(&self, cx: &mut JSContext) -> Option<DomRoot<Range>> {
478 self.assert_valid_selection_and_live_range();
479
480 if let Some(active_range) = self.live_range.get() {
481 return Some(active_range);
482 }
483
484 let active_range = {
487 let range = self.range.borrow();
488 let range = range.as_ref()?;
489 Range::new(
490 cx,
491 &self.document,
492 &range.start.container,
493 range.start.offset,
494 &range.end.container,
495 range.end.offset,
496 )
497 };
498
499 self.live_range.set(Some(&active_range));
500 active_range.associate_selection(self);
501 Some(active_range)
502 }
503
504 pub(crate) fn expect_active_range(&self, cx: &mut JSContext) -> DomRoot<Range> {
505 self.active_range(cx)
506 .expect("Should always have an active range")
507 }
508
509 pub(crate) fn set_visible_selection_dirty(&self) {
510 self.visible_selection_dirty.set(true);
511 }
512
513 fn composed_anchor_position(&self) -> Option<(DomRoot<Node>, u32)> {
514 let range = self.range.borrow();
515 let range = range.as_ref()?;
516 Some(match self.direction.get() {
517 Direction::Forwards => (range.start.container.as_rooted(), range.start.offset),
518 _ => (range.end.container.as_rooted(), range.end.offset),
519 })
520 }
521
522 fn live_anchor_node(&self, cx: &mut JSContext) -> Option<DomRoot<Node>> {
524 self.active_range(cx)
525 .map(|range| match self.direction.get() {
526 Direction::Forwards => range.start_container(),
527 _ => range.end_container(),
528 })
529 }
530
531 fn live_anchor_offset(&self, cx: &mut JSContext) -> u32 {
533 self.active_range(cx)
534 .map_or(0, |range| match self.direction.get() {
535 Direction::Forwards => range.start_offset(),
536 _ => range.end_offset(),
537 })
538 }
539
540 fn live_focus_node(&self, cx: &mut JSContext) -> Option<DomRoot<Node>> {
542 self.active_range(cx)
543 .map(|range| match self.direction.get() {
544 Direction::Forwards => range.end_container(),
545 _ => range.start_container(),
546 })
547 }
548
549 fn live_focus_offset(&self, cx: &mut JSContext) -> u32 {
551 self.active_range(cx)
552 .map_or(0, |range| match self.direction.get() {
553 Direction::Forwards => range.end_offset(),
554 _ => range.start_offset(),
555 })
556 }
557
558 pub(crate) fn insert_steps(&self, parent: &Node, child: &Node, count: u32) {
563 let mut range_borrow = self.range.borrow_mut();
564 let Some(range) = &mut *range_borrow else {
565 return;
566 };
567 let child_index = LazyCell::new(|| child.index());
568 if range.start.container == parent && range.start.offset > *child_index {
571 range.start.offset += count;
572 self.selection_boundaries_changed();
573 }
574 if range.end.container == parent && range.end.offset > *child_index {
577 range.end.offset += count;
578 self.selection_boundaries_changed();
579 }
580 }
581
582 pub(crate) fn remove_steps_for_removed_subtree(
589 &self,
590 inclusive_descendant_of_removed_node: &Node, parent_of_removed_node: &Node, index_of_removed_node: &mut dyn FnMut() -> u32, ) {
594 if inclusive_descendant_of_removed_node.is_in_a_shadow_tree() {
599 return;
600 }
601
602 let mut range_borrow = self.range.borrow_mut();
603 let Some(range) = &mut *range_borrow else {
604 return;
605 };
606 if range.start.container == inclusive_descendant_of_removed_node {
609 range.start = SelectionBoundary::new(parent_of_removed_node, index_of_removed_node());
610 self.selection_boundaries_changed();
611 }
612 if range.end.container == inclusive_descendant_of_removed_node {
615 range.end = SelectionBoundary::new(parent_of_removed_node, index_of_removed_node());
616 self.selection_boundaries_changed();
617 }
618 }
619
620 pub(crate) fn remove_steps_for_parent(
623 &self,
624 parent: &Node,
625 node_index: &mut dyn FnMut() -> u32,
626 ) {
627 let mut range_borrow = self.range.borrow_mut();
628 let Some(range) = &mut *range_borrow else {
629 return;
630 };
631
632 if range.start.container == parent && range.start.offset > node_index() {
635 range.start.offset -= 1;
636 self.selection_boundaries_changed();
637 }
638 if range.end.container == parent && range.end.offset > node_index() {
641 range.end.offset -= 1;
642 self.selection_boundaries_changed();
643 }
644 }
645
646 pub(crate) fn normalization_steps(
655 &self,
656 parent: &Node,
657 node: &Node,
658 current_node: &Node,
659 current_node_index: &dyn Fn() -> u32,
660 length: u32,
661 ) {
662 let mut range_borrow = self.range.borrow_mut();
663 let Some(range) = &mut *range_borrow else {
664 return;
665 };
666 if range.start.container == current_node {
669 range.start.offset += length;
670 range.start.container = Dom::from_ref(node);
671 self.selection_boundaries_changed();
672 }
673 if range.end.container == current_node {
676 range.end.offset += length;
677 range.end.container = Dom::from_ref(node);
678 self.selection_boundaries_changed();
679 }
680 if range.start.container == parent && range.start.offset == current_node_index() {
684 range.start.container = Dom::from_ref(node);
685 range.start.offset = length;
686 self.selection_boundaries_changed();
687 }
688 if range.end.container == parent && range.end.offset == current_node_index() {
691 range.end.container = Dom::from_ref(node);
692 range.end.offset = length;
693 self.selection_boundaries_changed();
694 }
695 }
696
697 pub(crate) fn replace_data_steps(
700 &self,
701 node: &Node,
702 offset: u32,
703 removed_code_units: u32,
704 added_code_units: &mut dyn FnMut() -> u32,
705 ) {
706 let mut range_borrow = self.range.borrow_mut();
707 let Some(range) = &mut *range_borrow else {
708 return;
709 };
710 let start_container = &range.start.container;
714 let start_offset = range.start.offset;
715 if &**start_container == node &&
716 start_offset > offset &&
717 start_offset <= offset + removed_code_units
718 {
719 range.start.offset = offset;
720 self.selection_boundaries_changed();
721 }
722 let end_container = &range.end.container;
726 let end_offset = range.end.offset;
727 if &**end_container == node &&
728 end_offset > offset &&
729 end_offset <= offset + removed_code_units
730 {
731 range.end.offset = offset;
732 self.selection_boundaries_changed();
733 }
734 if &**start_container == node && start_offset > offset + removed_code_units {
738 range.start.offset = start_offset + added_code_units() - removed_code_units;
739 self.selection_boundaries_changed();
740 }
741 if &**end_container == node && end_offset > offset + removed_code_units {
745 range.end.offset = end_offset + added_code_units() - removed_code_units;
746 self.selection_boundaries_changed();
747 }
748 }
749
750 pub(crate) fn text_split_steps(
753 &self,
754 node: &Node,
755 offset: u32,
756 parent_node: &Node,
757 new_node: &Node,
758 ) {
759 let mut range_borrow = self.range.borrow_mut();
760 let Some(range) = &mut *range_borrow else {
761 return;
762 };
763 if range.start.container == node && range.start.offset > offset {
767 range.start.container = Dom::from_ref(new_node);
768 range.start.offset -= offset;
769 self.selection_boundaries_changed();
770 }
771 if range.end.container == node && range.end.offset > offset {
774 range.end.container = Dom::from_ref(new_node);
775 range.end.offset -= offset;
776 self.selection_boundaries_changed();
777 }
778 let node_index = LazyCell::new(|| node.index());
781 if range.start.container == parent_node && range.start.offset == *node_index + 1 {
782 range.start.offset += 1;
783 self.selection_boundaries_changed();
784 }
785 if range.end.container == parent_node && range.end.offset == *node_index + 1 {
788 range.end.offset += 1;
789 self.selection_boundaries_changed();
790 }
791 }
792
793 pub(crate) fn collapse_to_dom_position(
794 &self,
795 cx: &mut JSContext,
796 container: &Node,
797 offset: Utf32CodeUnitsOrNodeOffset,
798 ) {
799 let _ = self.Collapse(
800 cx,
801 Some(container),
802 container.to_sibling_or_utf16_offset(offset),
803 );
804 }
805
806 pub(crate) fn collapse_or_extend_to_dom_position(
807 &self,
808 cx: &mut JSContext,
809 container: &Node,
810 offset: Utf32CodeUnitsOrNodeOffset,
811 ) {
812 let offset = container.to_sibling_or_utf16_offset(offset);
813 let is_anchor =
814 self.composed_anchor_position()
815 .is_some_and(|(anchor_node, anchor_offset)| {
816 &*anchor_node == container && anchor_offset == offset
817 });
818
819 if self.range.borrow().is_none() || is_anchor {
820 let _ = self.Collapse(cx, Some(container), offset);
821 } else {
822 let _ = self.Extend(cx, container, offset);
823 }
824 }
825}
826
827impl SelectionMethods<crate::DomTypeHolder> for Selection {
828 fn GetAnchorNode(&self, cx: &mut JSContext) -> Option<DomRoot<Node>> {
830 let anchor_node = self.live_anchor_node(cx)?;
833 if !anchor_node.is_in_a_document_tree() {
834 return None;
835 }
836 Some(anchor_node)
837 }
838
839 fn AnchorOffset(&self, cx: &mut JSContext) -> u32 {
841 if self
844 .live_anchor_node(cx)
845 .is_none_or(|anchor_node| !anchor_node.is_in_a_document_tree())
846 {
847 return 0;
848 }
849 self.live_anchor_offset(cx)
850 }
851
852 fn GetFocusNode(&self, cx: &mut JSContext) -> Option<DomRoot<Node>> {
854 let focus_node = self.live_focus_node(cx)?;
857 if !focus_node.is_in_a_document_tree() {
858 return None;
859 }
860 Some(focus_node)
861 }
862
863 fn FocusOffset(&self, cx: &mut JSContext) -> u32 {
865 if self
868 .live_focus_node(cx)
869 .is_none_or(|focus_node| !focus_node.is_in_a_document_tree())
870 {
871 return 0;
872 }
873 self.live_focus_offset(cx)
874 }
875
876 fn IsCollapsed(&self, cx: &mut JSContext) -> bool {
878 self.active_range(cx).is_none_or(|range| range.collapsed())
881 }
882
883 fn RangeCount(&self) -> u32 {
885 let range = self.range.borrow();
888 let Some(range) = range.as_ref() else {
889 return 0;
890 };
891 if !range.start_and_end_are_in_document_tree() {
892 return 0;
893 }
894 1
895 }
896
897 fn Type(&self) -> DOMString {
899 let range = self.range.borrow();
903 let Some(range) = range.as_ref() else {
904 return DOMString::from_static("None");
905 };
906 if !range.start_and_end_are_in_document_tree() {
907 return DOMString::from_static("None");
908 }
909
910 if range.collapsed() {
911 DOMString::from_static("Caret")
912 } else {
913 DOMString::from_static("Range")
914 }
915 }
916
917 fn GetRangeAt(&self, cx: &mut JSContext, index: u32) -> Fallible<DomRoot<Range>> {
919 if index != 0 {
923 return Err(Error::IndexSize(Some("Index must be zero".into())));
924 }
925
926 let range = self.range.borrow();
927 let Some(range) = range.as_ref() else {
928 return Err(Error::IndexSize(Some("Selection is empty".into())));
929 };
930 if !range.start_and_end_are_in_document_tree() {
931 return Err(Error::IndexSize(Some(
932 "Start and end are not in document tree".into(),
933 )));
934 }
935 self.active_range(cx).ok_or(Error::IndexSize(Some(
936 "Could not create live range for selection".into(),
937 )))
938 }
939
940 fn AddRange(&self, range: &Range) {
942 if !self.is_in_document_of_range(&range.start_container()) {
945 return;
946 }
947
948 if self.RangeCount() != 0 {
950 return;
951 }
952
953 self.set_live_range(Some(range));
955
956 self.direction.set(Direction::Forwards);
958 }
959
960 fn RemoveRange(&self, range: &Range) -> ErrorResult {
962 if let Some(own_range) = self.live_range.get() &&
965 &*own_range == range
966 {
967 self.set_range(None);
968 return Ok(());
969 }
970 Err(Error::NotFound(None))
971 }
972
973 fn RemoveAllRanges(&self) {
975 self.set_range(None);
978 }
979
980 fn Empty(&self) {
982 self.RemoveAllRanges();
984 }
985
986 fn Collapse(&self, _cx: &mut JSContext, node: Option<&Node>, offset: u32) -> ErrorResult {
988 let Some(node) = node else {
991 self.set_range(None);
992 return Ok(());
993 };
994
995 if node.is_doctype() {
998 return Err(Error::InvalidNodeType(None));
999 }
1000
1001 if offset > node.len() {
1004 return Err(Error::IndexSize(None));
1005 }
1006
1007 if &*node.GetRootNode(&GetRootNodeOptions { composed: false }) !=
1014 self.document.upcast::<Node>()
1015 {
1016 return Ok(());
1017 }
1018
1019 self.set_range(Some(SelectionRange::collapsed_at(SelectionBoundary::new(
1023 node, offset,
1024 ))));
1025
1026 self.direction.set(Direction::Forwards);
1028
1029 Ok(())
1030 }
1031
1032 fn SetPosition(&self, cx: &mut JSContext, node: Option<&Node>, offset: u32) -> ErrorResult {
1034 self.Collapse(cx, node, offset)
1036 }
1037
1038 fn CollapseToStart(&self, cx: &mut JSContext) -> ErrorResult {
1040 let Some((start_container, start_offset)) = self
1045 .range
1046 .borrow()
1047 .as_ref()
1048 .map(|range| (range.start.container.as_rooted(), range.start.offset))
1049 else {
1050 return Err(Error::InvalidState(None));
1051 };
1052 self.Collapse(cx, Some(&*start_container), start_offset)
1053 }
1054
1055 fn CollapseToEnd(&self, cx: &mut JSContext) -> ErrorResult {
1057 let Some((end_container, end_offset)) = self
1061 .range
1062 .borrow()
1063 .as_ref()
1064 .map(|range| (range.end.container.as_rooted(), range.end.offset))
1065 else {
1066 return Err(Error::InvalidState(None));
1067 };
1068 self.Collapse(cx, Some(&*end_container), end_offset)
1069 }
1070
1071 fn Extend(&self, _cx: &mut JSContext, node: &Node, offset: u32) -> ErrorResult {
1073 if &*node.GetRootNode(&GetRootNodeOptions { composed: false }) !=
1080 self.document.upcast::<Node>()
1081 {
1082 return Ok(());
1083 }
1084
1085 let range_borrow = self.range.borrow();
1087 let Some(range) = range_borrow.as_ref() else {
1088 return Err(Error::InvalidState(None));
1089 };
1090
1091 if node.is_doctype() {
1094 return Err(Error::InvalidNodeType(None));
1095 }
1096
1097 if offset > node.len() {
1100 return Err(Error::IndexSize(None));
1101 }
1102
1103 let (old_anchor_node, old_anchor_offset) = self
1108 .composed_anchor_position()
1109 .expect("has range, therefore has anchor node");
1110
1111 let direction;
1114
1115 let is_in_document_of_range = self.is_in_document_of_range(&range.start.container);
1118 drop(range_borrow);
1119
1120 if !is_in_document_of_range {
1121 self.set_range(Some(SelectionRange::collapsed_at(SelectionBoundary::new(
1122 node, offset,
1123 ))));
1124 direction = Direction::Forwards;
1125 } else {
1126 let is_old_anchor_before_or_equal = matches!(
1127 bp_position(&old_anchor_node, old_anchor_offset, node, offset),
1128 Ordering::Less | Ordering::Equal
1129 );
1130 if is_old_anchor_before_or_equal {
1131 self.set_range(Some(SelectionRange::new(
1134 SelectionBoundary::new(&old_anchor_node, old_anchor_offset),
1135 SelectionBoundary::new(node, offset),
1136 )));
1137 direction = Direction::Forwards;
1138 } else {
1139 self.set_range(Some(SelectionRange::new(
1142 SelectionBoundary::new(node, offset),
1143 SelectionBoundary::new(&old_anchor_node, old_anchor_offset),
1144 )));
1145 direction = Direction::Backwards;
1146 }
1147 }
1148
1149 self.direction.set(direction);
1155
1156 Ok(())
1157 }
1158
1159 fn SetBaseAndExtent(
1161 &self,
1162 _cx: &mut JSContext,
1163 anchor_node: &Node,
1164 anchor_offset: u32,
1165 focus_node: &Node,
1166 focus_offset: u32,
1167 ) -> ErrorResult {
1168 if anchor_node.is_doctype() || focus_node.is_doctype() {
1171 return Err(Error::InvalidNodeType(None));
1172 }
1173
1174 if anchor_offset > anchor_node.len() || focus_offset > focus_node.len() {
1178 return Err(Error::IndexSize(None));
1179 }
1180
1181 if &*anchor_node.GetRootNode(&GetRootNodeOptions { composed: false }) !=
1188 self.document.upcast::<Node>()
1189 {
1190 return Ok(());
1191 }
1192 if &*focus_node.GetRootNode(&GetRootNodeOptions { composed: false }) !=
1193 self.document.upcast::<Node>()
1194 {
1195 return Ok(());
1196 }
1197
1198 let is_anchor_before_focus =
1210 bp_position(anchor_node, anchor_offset, focus_node, focus_offset) == Ordering::Less;
1211 let direction = if is_anchor_before_focus {
1212 self.set_range(Some(SelectionRange::new(
1213 SelectionBoundary::new(anchor_node, anchor_offset),
1214 SelectionBoundary::new(focus_node, focus_offset),
1215 )));
1216 Direction::Forwards
1217 } else {
1218 self.set_range(Some(SelectionRange::new(
1219 SelectionBoundary::new(focus_node, focus_offset),
1220 SelectionBoundary::new(anchor_node, anchor_offset),
1221 )));
1222 Direction::Backwards
1223 };
1224
1225 self.direction.set(direction);
1231
1232 Ok(())
1233 }
1234
1235 fn SelectAllChildren(&self, _cx: &mut JSContext, node: &Node) -> ErrorResult {
1237 if node.is_doctype() {
1240 return Err(Error::InvalidNodeType(None));
1241 }
1242
1243 if !self.is_in_document_of_range(node) {
1246 return Ok(());
1247 }
1248
1249 let child_count = node.children_count();
1251
1252 self.set_range(Some(SelectionRange::new(
1256 SelectionBoundary::new(node, 0),
1257 SelectionBoundary::new(node, child_count),
1258 )));
1259
1260 self.direction.set(Direction::Forwards);
1262
1263 Ok(())
1264 }
1265
1266 fn DeleteFromDocument(&self, cx: &mut JSContext) -> ErrorResult {
1268 if self
1272 .range
1273 .borrow()
1274 .as_ref()
1275 .is_none_or(|range| !range.start_and_end_are_in_document_tree())
1276 {
1277 return Ok(());
1278 }
1279
1280 self.active_range(cx)
1281 .map_or(Ok(()), |active_range| active_range.DeleteContents(cx))
1282 }
1283
1284 fn ContainsNode(&self, node: &Node, allow_partial_containment: bool) -> bool {
1286 if !self.is_in_document_of_range(node) {
1299 return false;
1300 }
1301 let range = self.range.borrow();
1302 let Some(range) = range.as_ref() else {
1303 return false;
1304 };
1305 let start_node = &*range.start.container;
1306 if !self.is_in_document_of_range(start_node) {
1307 return false;
1308 }
1309 let end_node = &*range.end.container;
1310
1311 let first_offset = 0;
1312 let last_offset = node.len();
1313 let (compare_start_to, compare_end_to) = if allow_partial_containment {
1314 (last_offset, first_offset)
1315 } else {
1316 (first_offset, last_offset)
1317 };
1318
1319 matches!(
1323 bp_position(start_node, range.start.offset, node, compare_start_to),
1324 Ordering::Less | Ordering::Equal
1325 ) && matches!(
1326 bp_position(end_node, range.end.offset, node, compare_end_to),
1327 Ordering::Greater | Ordering::Equal
1328 )
1329 }
1330
1331 fn Stringifier(&self, cx: &mut JSContext) -> DOMString {
1333 self.GetRangeAt(cx, 0)
1343 .map(|range| range.Stringifier(cx.no_gc()))
1344 .unwrap_or_default()
1345 }
1346}
1347
1348impl<'dom> LayoutDom<'dom, Selection> {
1349 #[expect(unsafe_code)]
1350 pub(crate) fn range_for_layout(&self) -> &Option<SelectionRange> {
1351 unsafe { self.unsafe_get().range.borrow_for_layout() }
1352 }
1353}
1354
1355enum FlatTreeNodePosition {
1356 Before(DomRoot<Node>),
1357 Inside(DomRoot<Node>),
1358 After(DomRoot<Node>),
1359}
1360
1361impl FlatTreeNodePosition {
1362 fn node(&self) -> &Node {
1363 match self {
1364 FlatTreeNodePosition::Before(node) => node,
1365 FlatTreeNodePosition::Inside(node) => node,
1366 FlatTreeNodePosition::After(node) => node,
1367 }
1368 }
1369}
1370
1371fn position_in_flat_tree_for_selection(
1375 no_gc: &NoGC,
1376 container: DomRoot<Node>,
1377 offset: usize,
1378) -> FlatTreeNodePosition {
1379 if container.is::<CharacterData>() {
1380 return FlatTreeNodePosition::Inside(container);
1381 }
1382
1383 let shadow_host_or_node = |node: &Node| {
1384 container
1385 .downcast::<ShadowRoot>()
1386 .map(|shadow_root| DomRoot::upcast(shadow_root.Host()))
1387 .unwrap_or(DomRoot::from_ref(node))
1388 };
1389
1390 if let Some(child) = container.children().nth(offset) {
1391 if let FlatTreeParent::Parent(_) = child.parent_in_flat_tree(no_gc) {
1392 return FlatTreeNodePosition::Before(child);
1393 }
1394 } else if let Some(last_child) = container.GetLastChild() &&
1395 let FlatTreeParent::Parent(_) = last_child.parent_in_flat_tree(no_gc)
1396 {
1397 return FlatTreeNodePosition::After(shadow_host_or_node(&container));
1398 }
1399
1400 FlatTreeNodePosition::Inside(shadow_host_or_node(&container))
1403}
1404
1405impl Node {
1406 fn to_sibling_or_utf16_offset(&self, offset: Utf32CodeUnitsOrNodeOffset) -> u32 {
1409 if let Some(character_data) = self.downcast::<CharacterData>() {
1410 offset.to_utf16_code_units_in(&character_data.data()).0 as u32
1411 } else {
1412 offset.0 as u32
1413 }
1414 }
1415}
1416
1417bitflags! {
1418 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1419 pub(crate) struct SelectionLiveRangeNotification: u8 {
1420 const Start = 1 << 0;
1421 const End = 1 << 1;
1422 }
1423}