1use accesskit::{
7 Color, Node as NodeData, Point, Rect, Role, TextAlign, TextDecoration, TextDirection,
8 TextPosition as WeakPosition, TextSelection, VerticalOffset,
9};
10use alloc::{string::String, vec::Vec};
11use core::{cmp::Ordering, fmt, iter::FusedIterator};
12
13use crate::{node::NodeId, FilterResult, Node, TreeState};
14
15#[derive(Clone, Copy, Debug)]
16pub(crate) struct InnerPosition<'a> {
17 pub(crate) node: Node<'a>,
18 pub(crate) character_index: usize,
19}
20
21impl<'a> InnerPosition<'a> {
22 fn upgrade(tree_state: &'a TreeState, weak: WeakPosition, node_id: NodeId) -> Option<Self> {
23 let node = tree_state.node_by_id(node_id.with_same_tree(weak.node))?;
24 if node.role() != Role::TextRun {
25 return None;
26 }
27 let character_index = weak.character_index;
28 if character_index > node.data().character_lengths().len() {
29 return None;
30 }
31 Some(Self {
32 node,
33 character_index,
34 })
35 }
36
37 fn clamped_upgrade(
38 tree_state: &'a TreeState,
39 weak: WeakPosition,
40 node_id: NodeId,
41 ) -> Option<Self> {
42 let node = tree_state.node_by_id(node_id.with_same_tree(weak.node))?;
43 if node.role() != Role::TextRun {
44 return None;
45 }
46 let character_index = weak
47 .character_index
48 .min(node.data().character_lengths().len());
49 Some(Self {
50 node,
51 character_index,
52 })
53 }
54
55 fn is_run_start(&self) -> bool {
56 self.character_index == 0
57 }
58
59 fn is_line_start(&self) -> bool {
60 self.is_run_start() && self.node.data().previous_on_line().is_none()
61 }
62
63 fn is_run_end(&self) -> bool {
64 self.character_index == self.node.data().character_lengths().len()
65 }
66
67 fn is_line_end(&self) -> bool {
68 self.is_run_end() && self.node.data().next_on_line().is_none()
69 }
70
71 fn is_paragraph_end(&self) -> bool {
72 self.is_line_end() && self.node.data().value().unwrap().ends_with('\n')
73 }
74
75 fn is_document_start(&self, root_node: &Node) -> bool {
76 self.is_run_start() && self.node.preceding_text_runs(root_node).next().is_none()
77 }
78
79 fn is_document_end(&self, root_node: &Node) -> bool {
80 self.is_run_end() && self.node.following_text_runs(root_node).next().is_none()
81 }
82
83 fn biased_to_start(&self, root_node: &Node) -> Self {
84 if self.is_run_end() {
85 if let Some(node) = self.node.following_text_runs(root_node).next() {
86 return Self {
87 node,
88 character_index: 0,
89 };
90 }
91 }
92 *self
93 }
94
95 fn biased_to_end(&self, root_node: &Node) -> Self {
96 if self.is_run_start() {
97 if let Some(node) = self.node.preceding_text_runs(root_node).next() {
98 return Self {
99 node,
100 character_index: node.data().character_lengths().len(),
101 };
102 }
103 }
104 *self
105 }
106
107 fn comparable(&self, root_node: &Node) -> (Vec<usize>, usize) {
108 let normalized = self.biased_to_start(root_node);
109 (
110 normalized.node.relative_index_path(root_node.id()),
111 normalized.character_index,
112 )
113 }
114
115 fn line_start(&self) -> Self {
116 let mut node = self.node;
117 while let Some(id) = node.data().previous_on_line() {
118 node = node
119 .tree_state
120 .node_by_id(node.id.with_same_tree(id))
121 .unwrap();
122 }
123 Self {
124 node,
125 character_index: 0,
126 }
127 }
128
129 fn line_end(&self) -> Self {
130 let mut node = self.node;
131 while let Some(id) = node.data().next_on_line() {
132 node = node
133 .tree_state
134 .node_by_id(node.id.with_same_tree(id))
135 .unwrap();
136 }
137 Self {
138 node,
139 character_index: node.data().character_lengths().len(),
140 }
141 }
142
143 pub(crate) fn downgrade(&self) -> WeakPosition {
144 let (local_node_id, _) = self.node.id.to_components();
145 WeakPosition {
146 node: local_node_id,
147 character_index: self.character_index,
148 }
149 }
150}
151
152impl PartialEq for InnerPosition<'_> {
153 fn eq(&self, other: &Self) -> bool {
154 self.node.id() == other.node.id() && self.character_index == other.character_index
155 }
156}
157
158impl Eq for InnerPosition<'_> {}
159
160#[derive(Clone, Copy, Debug)]
161pub struct Position<'a> {
162 root_node: Node<'a>,
163 pub(crate) inner: InnerPosition<'a>,
164}
165
166impl<'a> Position<'a> {
167 pub fn to_raw(self) -> WeakPosition {
168 self.inner.downgrade()
169 }
170
171 pub fn inner_node(&self) -> &Node<'a> {
172 &self.inner.node
173 }
174
175 pub fn is_format_start(&self) -> bool {
176 self.is_document_start()
177 || (self.inner.character_index == 0
178 && self.inner.node.text_attributes_differ(
179 &self
180 .inner
181 .node
182 .preceding_text_runs(&self.root_node)
183 .next()
184 .unwrap(),
185 ))
186 }
187
188 pub fn is_word_start(&self) -> bool {
189 self.is_paragraph_start()
190 || self
191 .inner
192 .node
193 .data()
194 .word_starts()
195 .binary_search(&(self.inner.character_index as u8))
196 .is_ok()
197 }
198
199 pub fn is_line_start(&self) -> bool {
200 self.inner.is_line_start()
201 }
202
203 pub fn is_line_end(&self) -> bool {
204 self.inner.is_line_end()
205 }
206
207 pub fn is_paragraph_start(&self) -> bool {
208 self.is_document_start()
209 || (self.is_line_start()
210 && self.inner.biased_to_end(&self.root_node).is_paragraph_end())
211 }
212
213 pub fn is_paragraph_end(&self) -> bool {
214 self.is_document_end() || self.inner.is_paragraph_end()
215 }
216
217 pub fn is_paragraph_separator(&self) -> bool {
218 if self.is_document_end() {
219 return false;
220 }
221 let next = self.forward_to_character_end();
222 !next.is_document_end() && next.is_paragraph_end()
223 }
224
225 pub fn is_page_start(&self) -> bool {
226 self.is_document_start()
227 }
228
229 pub fn is_document_start(&self) -> bool {
230 self.inner.is_document_start(&self.root_node)
231 }
232
233 pub fn is_document_end(&self) -> bool {
234 self.inner.is_document_end(&self.root_node)
235 }
236
237 pub fn to_degenerate_range(&self) -> Range<'a> {
238 Range::new(self.root_node, self.inner, self.inner)
239 }
240
241 pub fn to_global_usv_index(&self) -> usize {
242 let mut total_length = 0usize;
243 for node in self.root_node.text_runs() {
244 let node_text = node.data().value().unwrap();
245 if node.id() == self.inner.node.id() {
246 let character_lengths = node.data().character_lengths();
247 let slice_end = character_lengths[..self.inner.character_index]
248 .iter()
249 .copied()
250 .map(usize::from)
251 .sum::<usize>();
252 return total_length + node_text[..slice_end].chars().count();
253 }
254 total_length += node_text.chars().count();
255 }
256 panic!("invalid position")
257 }
258
259 pub fn to_global_utf16_index(&self) -> usize {
260 let mut total_length = 0usize;
261 for node in self.root_node.text_runs() {
262 let node_text = node.data().value().unwrap();
263 if node.id() == self.inner.node.id() {
264 let character_lengths = node.data().character_lengths();
265 let slice_end = character_lengths[..self.inner.character_index]
266 .iter()
267 .copied()
268 .map(usize::from)
269 .sum::<usize>();
270 return total_length
271 + node_text[..slice_end]
272 .chars()
273 .map(char::len_utf16)
274 .sum::<usize>();
275 }
276 total_length += node_text.chars().map(char::len_utf16).sum::<usize>();
277 }
278 panic!("invalid position")
279 }
280
281 pub fn to_line_index(&self) -> usize {
282 let mut pos = *self;
283 if !pos.is_line_start() {
284 pos = pos.backward_to_line_start();
285 }
286 let mut lines_before_current = 0usize;
287 while !pos.is_document_start() {
288 pos = pos.backward_to_line_start();
289 lines_before_current += 1;
290 }
291 lines_before_current
292 }
293
294 pub fn biased_to_start(&self) -> Self {
295 Self {
296 root_node: self.root_node,
297 inner: self.inner.biased_to_start(&self.root_node),
298 }
299 }
300
301 pub fn biased_to_end(&self) -> Self {
302 Self {
303 root_node: self.root_node,
304 inner: self.inner.biased_to_end(&self.root_node),
305 }
306 }
307
308 pub fn forward_to_character_start(&self) -> Self {
309 let pos = self.inner.biased_to_start(&self.root_node);
310 Self {
311 root_node: self.root_node,
312 inner: InnerPosition {
313 node: pos.node,
314 character_index: pos.character_index + 1,
315 }
316 .biased_to_start(&self.root_node),
317 }
318 }
319
320 pub fn forward_to_character_end(&self) -> Self {
321 let pos = self.inner.biased_to_start(&self.root_node);
322 Self {
323 root_node: self.root_node,
324 inner: InnerPosition {
325 node: pos.node,
326 character_index: pos.character_index + 1,
327 },
328 }
329 }
330
331 pub fn backward_to_character_start(&self) -> Self {
332 let pos = self.inner.biased_to_end(&self.root_node);
333 Self {
334 root_node: self.root_node,
335 inner: InnerPosition {
336 node: pos.node,
337 character_index: pos.character_index - 1,
338 }
339 .biased_to_start(&self.root_node),
340 }
341 }
342
343 pub fn forward_to_format_start(&self) -> Self {
344 for node in self.inner.node.following_text_runs(&self.root_node) {
345 if self.inner.node.text_attributes_differ(&node) {
346 return Self {
347 root_node: self.root_node,
348 inner: InnerPosition {
349 node,
350 character_index: 0,
351 },
352 };
353 }
354 }
355 self.document_end()
356 }
357
358 pub fn forward_to_format_end(&self) -> Self {
359 self.forward_to_format_start().biased_to_end()
360 }
361
362 pub fn backward_to_format_start(&self) -> Self {
363 if self.inner.character_index != 0 {
364 let test_pos = Self {
365 root_node: self.root_node,
366 inner: InnerPosition {
367 node: self.inner.node,
368 character_index: 0,
369 },
370 };
371 if test_pos.is_format_start() {
372 return test_pos;
373 }
374 }
375 for node in self.inner.node.preceding_text_runs(&self.root_node) {
376 let test_pos = Self {
377 root_node: self.root_node,
378 inner: InnerPosition {
379 node,
380 character_index: 0,
381 },
382 };
383 if test_pos.is_format_start() {
384 return test_pos;
385 }
386 }
387 self.document_start()
388 }
389
390 pub fn forward_to_word_start(&self) -> Self {
391 let pos = self.inner.biased_to_start(&self.root_node);
392 {
395 let word_starts = pos.node.data().word_starts();
396 let index = match word_starts.binary_search(&(pos.character_index as u8)) {
397 Ok(index) => index + 1,
398 Err(index) => index,
399 };
400 if let Some(start) = word_starts.get(index) {
401 return Self {
402 root_node: self.root_node,
403 inner: InnerPosition {
404 node: pos.node,
405 character_index: *start as usize,
406 },
407 };
408 }
409 }
410 for node in pos.node.following_text_runs(&self.root_node) {
411 let start_pos = Self {
412 root_node: self.root_node,
413 inner: InnerPosition {
414 node,
415 character_index: 0,
416 },
417 };
418 if start_pos.is_paragraph_start() {
419 return start_pos;
420 }
421 if let Some(start) = node.data().word_starts().first() {
422 return Self {
423 root_node: self.root_node,
424 inner: InnerPosition {
425 node,
426 character_index: *start as usize,
427 },
428 };
429 }
430 }
431 self.document_end()
432 }
433
434 pub fn forward_to_word_end(&self) -> Self {
435 self.forward_to_word_start().biased_to_end()
436 }
437
438 pub fn backward_to_word_start(&self) -> Self {
439 {
442 let word_starts = self.inner.node.data().word_starts();
443 let index = match word_starts.binary_search(&(self.inner.character_index as u8)) {
444 Ok(index) => index,
445 Err(index) => index,
446 };
447 if let Some(index) = index.checked_sub(1) {
448 return Self {
449 root_node: self.root_node,
450 inner: InnerPosition {
451 node: self.inner.node,
452 character_index: word_starts[index] as usize,
453 },
454 };
455 }
456 }
457 if self.inner.character_index != 0 {
458 let start_pos = Self {
459 root_node: self.root_node,
460 inner: InnerPosition {
461 node: self.inner.node,
462 character_index: 0,
463 },
464 };
465 if start_pos.is_paragraph_start() {
466 return start_pos;
467 }
468 }
469 for node in self.inner.node.preceding_text_runs(&self.root_node) {
470 if let Some(start) = node.data().word_starts().last() {
471 return Self {
472 root_node: self.root_node,
473 inner: InnerPosition {
474 node,
475 character_index: *start as usize,
476 },
477 };
478 }
479 let start_pos = Self {
480 root_node: self.root_node,
481 inner: InnerPosition {
482 node,
483 character_index: 0,
484 },
485 };
486 if start_pos.is_paragraph_start() {
487 return start_pos;
488 }
489 }
490 self.document_start()
491 }
492
493 pub fn forward_to_line_start(&self) -> Self {
494 Self {
495 root_node: self.root_node,
496 inner: self.inner.line_end().biased_to_start(&self.root_node),
497 }
498 }
499
500 pub fn forward_to_line_end(&self) -> Self {
501 let pos = self.inner.biased_to_start(&self.root_node);
502 Self {
503 root_node: self.root_node,
504 inner: pos.line_end(),
505 }
506 }
507
508 pub fn backward_to_line_start(&self) -> Self {
509 let pos = self.inner.biased_to_end(&self.root_node);
510 Self {
511 root_node: self.root_node,
512 inner: pos.line_start().biased_to_start(&self.root_node),
513 }
514 }
515
516 pub fn forward_to_paragraph_start(&self) -> Self {
517 let mut current = *self;
518 loop {
519 current = current.forward_to_line_start();
520 if current.is_document_end()
521 || current
522 .inner
523 .biased_to_end(&self.root_node)
524 .is_paragraph_end()
525 {
526 break;
527 }
528 }
529 current
530 }
531
532 pub fn forward_to_paragraph_end(&self) -> Self {
533 let mut current = *self;
534 loop {
535 current = current.forward_to_line_end();
536 if current.is_document_end() || current.inner.is_paragraph_end() {
537 break;
538 }
539 }
540 current
541 }
542
543 pub fn backward_to_paragraph_start(&self) -> Self {
544 let mut current = *self;
545 loop {
546 current = current.backward_to_line_start();
547 if current.is_paragraph_start() {
548 break;
549 }
550 }
551 current
552 }
553
554 pub fn forward_to_page_start(&self) -> Self {
555 self.document_end()
556 }
557
558 pub fn forward_to_page_end(&self) -> Self {
559 self.document_end()
560 }
561
562 pub fn backward_to_page_start(&self) -> Self {
563 self.document_start()
564 }
565
566 pub fn document_end(&self) -> Self {
567 self.root_node.document_end()
568 }
569
570 pub fn document_start(&self) -> Self {
571 self.root_node.document_start()
572 }
573}
574
575impl PartialEq for Position<'_> {
576 fn eq(&self, other: &Self) -> bool {
577 self.root_node.id() == other.root_node.id() && self.inner == other.inner
578 }
579}
580
581impl Eq for Position<'_> {}
582
583impl PartialOrd for Position<'_> {
584 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
585 if self.root_node.id() != other.root_node.id() {
586 return None;
587 }
588 let self_comparable = self.inner.comparable(&self.root_node);
589 let other_comparable = other.inner.comparable(&self.root_node);
590 Some(self_comparable.cmp(&other_comparable))
591 }
592}
593
594#[derive(Debug, PartialEq)]
595pub enum RangePropertyValue<T: alloc::fmt::Debug + PartialEq> {
596 Single(T),
597 Mixed,
598}
599
600impl<T: alloc::fmt::Debug + PartialEq> RangePropertyValue<Option<T>> {
601 pub fn map<U: alloc::fmt::Debug + PartialEq>(
602 self,
603 f: impl FnOnce(T) -> U,
604 ) -> RangePropertyValue<Option<U>> {
605 match self {
606 Self::Single(value) => RangePropertyValue::Single(value.map(f)),
607 Self::Mixed => RangePropertyValue::Mixed,
608 }
609 }
610}
611
612#[derive(Clone, Copy)]
613pub struct Range<'a> {
614 pub(crate) node: Node<'a>,
615 pub(crate) start: InnerPosition<'a>,
616 pub(crate) end: InnerPosition<'a>,
617}
618
619impl<'a> Range<'a> {
620 fn new(node: Node<'a>, mut start: InnerPosition<'a>, mut end: InnerPosition<'a>) -> Self {
621 if start.comparable(&node) > end.comparable(&node) {
622 core::mem::swap(&mut start, &mut end);
623 }
624 Self { node, start, end }
625 }
626
627 pub fn node(&self) -> &Node<'a> {
628 &self.node
629 }
630
631 pub fn start(&self) -> Position<'a> {
632 Position {
633 root_node: self.node,
634 inner: self.start,
635 }
636 }
637
638 pub fn end(&self) -> Position<'a> {
639 Position {
640 root_node: self.node,
641 inner: self.end,
642 }
643 }
644
645 pub fn is_degenerate(&self) -> bool {
646 self.start.comparable(&self.node) == self.end.comparable(&self.node)
647 }
648
649 fn walk<F, T>(&self, mut f: F) -> Option<T>
650 where
651 F: FnMut(&Node<'a>) -> Option<T>,
652 {
653 let (start, end) = if self.is_degenerate() {
657 (self.start, self.start)
658 } else {
659 let start = self.start.biased_to_start(&self.node);
660 let end = self.end.biased_to_end(&self.node);
661 (start, end)
662 };
663 if let Some(result) = f(&start.node) {
664 return Some(result);
665 }
666 if start.node.id() == end.node.id() {
667 return None;
668 }
669 for node in start.node.following_text_runs(&self.node) {
670 if let Some(result) = f(&node) {
671 return Some(result);
672 }
673 if node.id() == end.node.id() {
674 break;
675 }
676 }
677 None
678 }
679
680 pub fn traverse_text<F, T>(&self, mut f: F) -> Option<T>
681 where
682 F: FnMut(&Node<'a>, &str) -> Option<T>,
683 {
684 self.walk(|node| {
685 let character_lengths = node.data().character_lengths();
686 let start_index = if node.id() == self.start.node.id() {
687 self.start.character_index
688 } else {
689 0
690 };
691 let end_index = if node.id() == self.end.node.id() {
692 self.end.character_index
693 } else {
694 character_lengths.len()
695 };
696 let value = node.data().value().unwrap();
697 let s = if start_index == end_index {
698 ""
699 } else if start_index == 0 && end_index == character_lengths.len() {
700 value
701 } else {
702 let slice_start = character_lengths[..start_index]
703 .iter()
704 .copied()
705 .map(usize::from)
706 .sum::<usize>();
707 let slice_end = slice_start
708 + character_lengths[start_index..end_index]
709 .iter()
710 .copied()
711 .map(usize::from)
712 .sum::<usize>();
713 &value[slice_start..slice_end]
714 };
715 f(node, s)
716 })
717 }
718
719 pub fn write_text<W: fmt::Write>(&self, mut writer: W) -> fmt::Result {
720 if let Some(err) = self.traverse_text(|_, s| writer.write_str(s).err()) {
721 Err(err)
722 } else {
723 Ok(())
724 }
725 }
726
727 pub fn text(&self) -> String {
728 let mut result = String::new();
729 self.write_text(&mut result).unwrap();
730 result
731 }
732
733 pub fn bounding_boxes(&self) -> Vec<Rect> {
741 let mut result = Vec::new();
742 self.walk(|node| {
743 let mut rect = match node.data().bounds() {
744 Some(rect) => rect,
745 None => {
746 return Some(Vec::new());
747 }
748 };
749 let positions = match node.data().character_positions() {
750 Some(positions) => positions,
751 None => {
752 return Some(Vec::new());
753 }
754 };
755 let widths = match node.data().character_widths() {
756 Some(widths) => widths,
757 None => {
758 return Some(Vec::new());
759 }
760 };
761 let direction = match node.text_direction() {
762 Some(direction) => direction,
763 None => {
764 return Some(Vec::new());
765 }
766 };
767 let character_lengths = node.data().character_lengths();
768 let start_index = if node.id() == self.start.node.id() {
769 self.start.character_index
770 } else {
771 0
772 };
773 let end_index = if node.id() == self.end.node.id() {
774 self.end.character_index
775 } else {
776 character_lengths.len()
777 };
778 if start_index != 0 || end_index != character_lengths.len() {
779 let pixel_start = if start_index < character_lengths.len() {
780 positions[start_index]
781 } else {
782 positions[start_index - 1] + widths[start_index - 1]
783 };
784 let pixel_end = if end_index == start_index {
785 pixel_start
786 } else {
787 positions[end_index - 1] + widths[end_index - 1]
788 };
789 let pixel_start = f64::from(pixel_start);
790 let pixel_end = f64::from(pixel_end);
791 match direction {
792 TextDirection::LeftToRight => {
793 let orig_left = rect.x0;
794 rect.x0 = orig_left + pixel_start;
795 rect.x1 = orig_left + pixel_end;
796 }
797 TextDirection::RightToLeft => {
798 let orig_right = rect.x1;
799 rect.x1 = orig_right - pixel_start;
800 rect.x0 = orig_right - pixel_end;
801 }
802 TextDirection::TopToBottom => {
806 let orig_top = rect.y0;
807 rect.y0 = orig_top + pixel_start;
808 rect.y1 = orig_top + pixel_end;
809 }
810 TextDirection::BottomToTop => {
811 let orig_bottom = rect.y1;
812 rect.y1 = orig_bottom - pixel_start;
813 rect.y0 = orig_bottom - pixel_end;
814 }
815 }
816 }
817 result.push(node.transform().transform_rect_bbox(rect));
818 None
819 })
820 .unwrap_or(result)
821 }
822
823 fn fetch_property<T: alloc::fmt::Debug + PartialEq>(
824 &self,
825 getter: fn(&Node<'a>) -> T,
826 ) -> RangePropertyValue<T> {
827 let mut value = None;
828 self.walk(|node| {
829 let current = getter(node);
830 if let Some(value) = &value {
831 if *value != current {
832 return Some(RangePropertyValue::Mixed);
833 }
834 } else {
835 value = Some(current);
836 }
837 None
838 })
839 .unwrap_or_else(|| RangePropertyValue::Single(value.unwrap()))
840 }
841
842 fn fix_start_bias(&mut self) {
843 if !self.is_degenerate() {
844 self.start = self.start.biased_to_start(&self.node);
845 }
846 }
847
848 pub fn set_start(&mut self, pos: Position<'a>) {
849 assert_eq!(pos.root_node.id(), self.node.id());
850 self.start = pos.inner;
851 if self.start.comparable(&self.node) >= self.end.comparable(&self.node) {
854 self.end = self.start;
855 }
856 self.fix_start_bias();
857 }
858
859 pub fn set_end(&mut self, pos: Position<'a>) {
860 assert_eq!(pos.root_node.id(), self.node.id());
861 self.end = pos.inner;
862 if self.start.comparable(&self.node) >= self.end.comparable(&self.node) {
865 self.start = self.end;
866 }
867 self.fix_start_bias();
868 }
869
870 pub fn to_text_selection(&self) -> TextSelection {
871 TextSelection {
872 anchor: self.start.downgrade(),
873 focus: self.end.downgrade(),
874 }
875 }
876
877 pub fn downgrade(&self) -> WeakRange {
878 WeakRange {
879 node_id: self.node.id(),
880 start: self.start.downgrade(),
881 end: self.end.downgrade(),
882 start_comparable: self.start.comparable(&self.node),
883 end_comparable: self.end.comparable(&self.node),
884 }
885 }
886}
887
888impl PartialEq for Range<'_> {
889 fn eq(&self, other: &Self) -> bool {
890 self.node.id() == other.node.id() && self.start == other.start && self.end == other.end
891 }
892}
893
894impl Eq for Range<'_> {}
895
896#[derive(Clone, Debug, PartialEq, Eq)]
897pub struct WeakRange {
898 node_id: NodeId,
899 start: WeakPosition,
900 end: WeakPosition,
901 start_comparable: (Vec<usize>, usize),
902 end_comparable: (Vec<usize>, usize),
903}
904
905impl WeakRange {
906 pub fn node_id(&self) -> NodeId {
907 self.node_id
908 }
909
910 pub fn start_comparable(&self) -> &(Vec<usize>, usize) {
911 &self.start_comparable
912 }
913
914 pub fn end_comparable(&self) -> &(Vec<usize>, usize) {
915 &self.end_comparable
916 }
917
918 pub fn upgrade_node<'a>(&self, tree_state: &'a TreeState) -> Option<Node<'a>> {
919 tree_state
920 .node_by_id(self.node_id)
921 .filter(Node::supports_text_ranges)
922 }
923
924 pub fn upgrade<'a>(&self, tree_state: &'a TreeState) -> Option<Range<'a>> {
925 let node = self.upgrade_node(tree_state)?;
926 let start = InnerPosition::upgrade(tree_state, self.start, self.node_id)?;
927 let end = InnerPosition::upgrade(tree_state, self.end, self.node_id)?;
928 Some(Range { node, start, end })
929 }
930}
931
932fn text_node_filter(root_id: NodeId, node: &Node) -> FilterResult {
933 if node.id() == root_id || node.role() == Role::TextRun {
934 FilterResult::Include
935 } else {
936 FilterResult::ExcludeNode
937 }
938}
939
940fn character_index_at_point(node: &Node, point: Point) -> usize {
941 let rect = node.data().bounds().unwrap();
944 let character_lengths = node.data().character_lengths();
945 let positions = match node.data().character_positions() {
946 Some(positions) => positions,
947 None => {
948 return 0;
949 }
950 };
951 let widths = match node.data().character_widths() {
952 Some(widths) => widths,
953 None => {
954 return 0;
955 }
956 };
957 let direction = match node.text_direction() {
958 Some(direction) => direction,
959 None => {
960 return 0;
961 }
962 };
963 for (i, (position, width)) in positions.iter().zip(widths.iter()).enumerate().rev() {
964 let relative_pos = match direction {
965 TextDirection::LeftToRight => point.x - rect.x0,
966 TextDirection::RightToLeft => rect.x1 - point.x,
967 TextDirection::TopToBottom => point.y - rect.y0,
971 TextDirection::BottomToTop => rect.y1 - point.y,
972 };
973 if relative_pos >= f64::from(*position) && relative_pos < f64::from(*position + *width) {
974 return i;
975 }
976 }
977 character_lengths.len()
978}
979
980macro_rules! inherited_properties {
981 ($(($getter:ident, $type:ty, $setter:ident, $test_value_1:expr, $test_value_2:expr)),+) => {
982 impl<'a> Node<'a> {
983 $(pub fn $getter(&self) -> Option<$type> {
984 self.fetch_inherited_property(NodeData::$getter)
985 })*
986 }
987 impl<'a> Position<'a> {
988 $(pub fn $getter(&self) -> Option<$type> {
989 self.inner.node.$getter()
990 })*
991 }
992 impl<'a> Range<'a> {
993 $(pub fn $getter(&self) -> RangePropertyValue<Option<$type>> {
994 self.fetch_property(Node::$getter)
995 })*
996 }
997 $(#[cfg(test)]
998 mod $getter {
999 use accesskit::{Node, NodeId, Role, Tree, TreeId, TreeUpdate};
1000 use alloc::vec;
1001 use super::RangePropertyValue;
1002 use crate::tests::nid;
1003 #[test]
1004 fn directly_set() {
1005 let update = TreeUpdate {
1006 nodes: vec![
1007 (NodeId(0), {
1008 let mut node = Node::new(Role::TextInput);
1009 node.set_children(vec![NodeId(1)]);
1010 node
1011 }),
1012 (NodeId(1), {
1013 let mut node = Node::new(Role::TextRun);
1014 node.set_value("text");
1015 node.set_character_lengths([1, 1, 1, 1]);
1016 node.$setter($test_value_1);
1017 node
1018 }),
1019 ],
1020 tree: Some(Tree::new(NodeId(0))),
1021 tree_id: TreeId::ROOT,
1022 focus: NodeId(0),
1023 };
1024 let tree = crate::Tree::new(update, false);
1025 let state = tree.state();
1026 let node = state.node_by_id(nid(NodeId(0))).unwrap();
1027 let pos = node.document_start();
1028 assert_eq!(pos.$getter(), Some($test_value_1));
1029 let range = node.document_range();
1030 assert_eq!(range.$getter(), RangePropertyValue::Single(Some($test_value_1)));
1031 }
1032 #[test]
1033 fn set_on_parent() {
1034 let update = TreeUpdate {
1035 nodes: vec![
1036 (NodeId(0), {
1037 let mut node = Node::new(Role::TextInput);
1038 node.set_children(vec![NodeId(1)]);
1039 node.$setter($test_value_1);
1040 node
1041 }),
1042 (NodeId(1), {
1043 let mut node = Node::new(Role::TextRun);
1044 node.set_value("text");
1045 node.set_character_lengths([1, 1, 1, 1]);
1046 node
1047 }),
1048 ],
1049 tree: Some(Tree::new(NodeId(0))),
1050 tree_id: TreeId::ROOT,
1051 focus: NodeId(0),
1052 };
1053 let tree = crate::Tree::new(update, false);
1054 let state = tree.state();
1055 let node = state.node_by_id(nid(NodeId(0))).unwrap();
1056 let pos = node.document_start();
1057 assert_eq!(pos.$getter(), Some($test_value_1));
1058 let range = node.document_range();
1059 assert_eq!(range.$getter(), RangePropertyValue::Single(Some($test_value_1)));
1060 }
1061 #[test]
1062 fn only_child_overrides_parent() {
1063 let update = TreeUpdate {
1064 nodes: vec![
1065 (NodeId(0), {
1066 let mut node = Node::new(Role::TextInput);
1067 node.set_children(vec![NodeId(1)]);
1068 node.$setter($test_value_1);
1069 node
1070 }),
1071 (NodeId(1), {
1072 let mut node = Node::new(Role::TextRun);
1073 node.set_value("text");
1074 node.set_character_lengths([1, 1, 1, 1]);
1075 node.$setter($test_value_2);
1076 node
1077 }),
1078 ],
1079 tree: Some(Tree::new(NodeId(0))),
1080 tree_id: TreeId::ROOT,
1081 focus: NodeId(0),
1082 };
1083 let tree = crate::Tree::new(update, false);
1084 let state = tree.state();
1085 let node = state.node_by_id(nid(NodeId(0))).unwrap();
1086 assert_eq!(node.$getter(), Some($test_value_1));
1087 let pos = node.document_start();
1088 assert_eq!(pos.$getter(), Some($test_value_2));
1089 let range = node.document_range();
1090 assert_eq!(range.$getter(), RangePropertyValue::Single(Some($test_value_2)));
1091 }
1092 #[test]
1093 fn unset() {
1094 let update = TreeUpdate {
1095 nodes: vec![
1096 (NodeId(0), {
1097 let mut node = Node::new(Role::TextInput);
1098 node.set_children(vec![NodeId(1)]);
1099 node
1100 }),
1101 (NodeId(1), {
1102 let mut node = Node::new(Role::TextRun);
1103 node.set_value("text");
1104 node.set_character_lengths([1, 1, 1, 1]);
1105 node
1106 }),
1107 ],
1108 tree: Some(Tree::new(NodeId(0))),
1109 tree_id: TreeId::ROOT,
1110 focus: NodeId(0),
1111 };
1112 let tree = crate::Tree::new(update, false);
1113 let state = tree.state();
1114 let node = state.node_by_id(nid(NodeId(0))).unwrap();
1115 let pos = node.document_start();
1116 assert_eq!(pos.$getter(), None);
1117 let range = node.document_range();
1118 assert_eq!(range.$getter(), RangePropertyValue::Single(None));
1119 }
1120 #[test]
1121 fn mixed_some_and_none() {
1122 let update = TreeUpdate {
1123 nodes: vec![
1124 (NodeId(0), {
1125 let mut node = Node::new(Role::TextInput);
1126 node.set_children(vec![NodeId(1), NodeId(2)]);
1127 node
1128 }),
1129 (NodeId(1), {
1130 let mut node = Node::new(Role::TextRun);
1131 node.set_value("text 1\n");
1132 node.set_character_lengths([1, 1, 1, 1, 1, 1, 1]);
1133 node.$setter($test_value_1);
1134 node
1135 }),
1136 (NodeId(2), {
1137 let mut node = Node::new(Role::TextRun);
1138 node.set_value("text 2");
1139 node.set_character_lengths([1, 1, 1, 1, 1, 1]);
1140 node
1141 }),
1142 ],
1143 tree: Some(Tree::new(NodeId(0))),
1144 tree_id: TreeId::ROOT,
1145 focus: NodeId(0),
1146 };
1147 let tree = crate::Tree::new(update, false);
1148 let state = tree.state();
1149 let node = state.node_by_id(nid(NodeId(0))).unwrap();
1150 let range = node.document_range();
1151 assert_eq!(range.$getter(), RangePropertyValue::Mixed);
1152 }
1153 #[test]
1154 fn mixed_one_child_overrides_parent() {
1155 let update = TreeUpdate {
1156 nodes: vec![
1157 (NodeId(0), {
1158 let mut node = Node::new(Role::TextInput);
1159 node.set_children(vec![NodeId(1), NodeId(2)]);
1160 node.$setter($test_value_1);
1161 node
1162 }),
1163 (NodeId(1), {
1164 let mut node = Node::new(Role::TextRun);
1165 node.set_value("text 1\n");
1166 node.set_character_lengths([1, 1, 1, 1, 1, 1, 1]);
1167 node.$setter($test_value_2);
1168 node
1169 }),
1170 (NodeId(2), {
1171 let mut node = Node::new(Role::TextRun);
1172 node.set_value("text 2");
1173 node.set_character_lengths([1, 1, 1, 1, 1, 1]);
1174 node
1175 }),
1176 ],
1177 tree: Some(Tree::new(NodeId(0))),
1178 tree_id: TreeId::ROOT,
1179 focus: NodeId(0),
1180 };
1181 let tree = crate::Tree::new(update, false);
1182 let state = tree.state();
1183 let node = state.node_by_id(nid(NodeId(0))).unwrap();
1184 assert_eq!(node.$getter(), Some($test_value_1));
1185 let start = node.document_start();
1186 assert_eq!(start.$getter(), Some($test_value_2));
1187 let start_range = start.to_degenerate_range();
1188 assert_eq!(start_range.$getter(), RangePropertyValue::Single(Some($test_value_2)));
1189 let end = node.document_end();
1190 assert_eq!(end.$getter(), Some($test_value_1));
1191 let end_range = end.to_degenerate_range();
1192 assert_eq!(end_range.$getter(), RangePropertyValue::Single(Some($test_value_1)));
1193 let range = node.document_range();
1194 assert_eq!(range.$getter(), RangePropertyValue::Mixed);
1195 }
1196 })*
1197 }
1198}
1199
1200inherited_properties! {
1201 (text_direction, TextDirection, set_text_direction, accesskit::TextDirection::LeftToRight, accesskit::TextDirection::RightToLeft),
1202 (font_family, &'a str, set_font_family, "Noto", "Inconsolata"),
1203 (language, &'a str, set_language, "en", "fr"),
1204 (font_size, f32, set_font_size, 12.0, 24.0),
1205 (font_weight, f32, set_font_weight, 400.0, 700.0),
1206 (background_color, Color, set_background_color, accesskit::Color { red: 255, green: 255, blue: 255, alpha: 255 }, accesskit::Color { red: 255, green: 0, blue: 0, alpha: 255 }),
1207 (foreground_color, Color, set_foreground_color, accesskit::Color { red: 0, green: 0, blue: 0, alpha: 255 }, accesskit::Color { red: 0, green: 0, blue: 255, alpha: 255 }),
1208 (overline, TextDecoration, set_overline, crate::text::tests::TEST_TEXT_DECORATION_1, crate::text::tests::TEST_TEXT_DECORATION_2),
1209 (strikethrough, TextDecoration, set_strikethrough, crate::text::tests::TEST_TEXT_DECORATION_2, crate::text::tests::TEST_TEXT_DECORATION_3),
1210 (underline, TextDecoration, set_underline, crate::text::tests::TEST_TEXT_DECORATION_3, crate::text::tests::TEST_TEXT_DECORATION_4),
1211 (text_align, TextAlign, set_text_align, accesskit::TextAlign::Left, accesskit::TextAlign::Justify),
1212 (vertical_offset, VerticalOffset, set_vertical_offset, accesskit::VerticalOffset::Subscript, accesskit::VerticalOffset::Superscript)
1213}
1214
1215macro_rules! inherited_flags {
1216 ($(($getter:ident, $setter:ident)),+) => {
1217 impl<'a> Node<'a> {
1218 $(pub fn $getter(&self) -> bool {
1219 self.fetch_inherited_flag(NodeData::$getter)
1220 })*
1221 }
1222 impl<'a> Position<'a> {
1223 $(pub fn $getter(&self) -> bool {
1224 self.inner.node.$getter()
1225 })*
1226 }
1227 impl<'a> Range<'a> {
1228 $(pub fn $getter(&self) -> RangePropertyValue<bool> {
1229 self.fetch_property(Node::$getter)
1230 })*
1231 }
1232 $(#[cfg(test)]
1233 mod $getter {
1234 use accesskit::{Node, NodeId, Role, Tree, TreeId, TreeUpdate};
1235 use alloc::vec;
1236 use super::RangePropertyValue;
1237 use crate::tests::nid;
1238 #[test]
1239 fn directly_set() {
1240 let update = TreeUpdate {
1241 nodes: vec![
1242 (NodeId(0), {
1243 let mut node = Node::new(Role::TextInput);
1244 node.set_children(vec![NodeId(1)]);
1245 node
1246 }),
1247 (NodeId(1), {
1248 let mut node = Node::new(Role::TextRun);
1249 node.set_value("text");
1250 node.set_character_lengths([1, 1, 1, 1]);
1251 node.$setter();
1252 node
1253 }),
1254 ],
1255 tree: Some(Tree::new(NodeId(0))),
1256 tree_id: TreeId::ROOT,
1257 focus: NodeId(0),
1258 };
1259 let tree = crate::Tree::new(update, false);
1260 let state = tree.state();
1261 let node = state.node_by_id(nid(NodeId(0))).unwrap();
1262 let pos = node.document_start();
1263 assert!(pos.$getter());
1264 let range = node.document_range();
1265 assert_eq!(range.$getter(), RangePropertyValue::Single(true));
1266 }
1267 #[test]
1268 fn set_on_parent() {
1269 let update = TreeUpdate {
1270 nodes: vec![
1271 (NodeId(0), {
1272 let mut node = Node::new(Role::TextInput);
1273 node.set_children(vec![NodeId(1)]);
1274 node.$setter();
1275 node
1276 }),
1277 (NodeId(1), {
1278 let mut node = Node::new(Role::TextRun);
1279 node.set_value("text");
1280 node.set_character_lengths([1, 1, 1, 1]);
1281 node
1282 }),
1283 ],
1284 tree: Some(Tree::new(NodeId(0))),
1285 tree_id: TreeId::ROOT,
1286 focus: NodeId(0),
1287 };
1288 let tree = crate::Tree::new(update, false);
1289 let state = tree.state();
1290 let node = state.node_by_id(nid(NodeId(0))).unwrap();
1291 let pos = node.document_start();
1292 assert!(pos.$getter());
1293 let range = node.document_range();
1294 assert_eq!(range.$getter(), RangePropertyValue::Single(true));
1295 }
1296 #[test]
1297 fn unset() {
1298 let update = TreeUpdate {
1299 nodes: vec![
1300 (NodeId(0), {
1301 let mut node = Node::new(Role::TextInput);
1302 node.set_children(vec![NodeId(1)]);
1303 node
1304 }),
1305 (NodeId(1), {
1306 let mut node = Node::new(Role::TextRun);
1307 node.set_value("text");
1308 node.set_character_lengths([1, 1, 1, 1]);
1309 node
1310 }),
1311 ],
1312 tree: Some(Tree::new(NodeId(0))),
1313 tree_id: TreeId::ROOT,
1314 focus: NodeId(0),
1315 };
1316 let tree = crate::Tree::new(update, false);
1317 let state = tree.state();
1318 let node = state.node_by_id(nid(NodeId(0))).unwrap();
1319 let pos = node.document_start();
1320 assert!(!pos.$getter());
1321 let range = node.document_range();
1322 assert_eq!(range.$getter(), RangePropertyValue::Single(false));
1323 }
1324 #[test]
1325 fn mixed() {
1326 let update = TreeUpdate {
1327 nodes: vec![
1328 (NodeId(0), {
1329 let mut node = Node::new(Role::TextInput);
1330 node.set_children(vec![NodeId(1), NodeId(2)]);
1331 node
1332 }),
1333 (NodeId(1), {
1334 let mut node = Node::new(Role::TextRun);
1335 node.set_value("text 1\n");
1336 node.set_character_lengths([1, 1, 1, 1, 1, 1, 1]);
1337 node.$setter();
1338 node
1339 }),
1340 (NodeId(2), {
1341 let mut node = Node::new(Role::TextRun);
1342 node.set_value("text 2");
1343 node.set_character_lengths([1, 1, 1, 1, 1, 1]);
1344 node
1345 }),
1346 ],
1347 tree: Some(Tree::new(NodeId(0))),
1348 tree_id: TreeId::ROOT,
1349 focus: NodeId(0),
1350 };
1351 let tree = crate::Tree::new(update, false);
1352 let state = tree.state();
1353 let node = state.node_by_id(nid(NodeId(0))).unwrap();
1354 let range = node.document_range();
1355 assert_eq!(range.$getter(), RangePropertyValue::Mixed);
1356 }
1357 })*
1358 }
1359}
1360
1361inherited_flags! {
1362 (is_italic, set_italic)
1363}
1364
1365impl<'a> Node<'a> {
1366 fn text_attributes_differ(&self, other: &Self) -> bool {
1367 self.font_family() != other.font_family()
1368 || self.language() != other.language()
1369 || self.font_size() != other.font_size()
1370 || self.font_weight() != other.font_weight()
1371 || self.background_color() != other.background_color()
1372 || self.foreground_color() != other.foreground_color()
1373 || self.overline() != other.overline()
1374 || self.strikethrough() != other.strikethrough()
1375 || self.underline() != other.underline()
1376 || self.text_align() != other.text_align()
1377 || self.vertical_offset() != other.vertical_offset()
1378 }
1380
1381 pub(crate) fn text_runs(
1382 &self,
1383 ) -> impl DoubleEndedIterator<Item = Node<'a>> + FusedIterator<Item = Node<'a>> + 'a {
1384 let id = self.id();
1385 self.filtered_children(move |node| text_node_filter(id, node))
1386 }
1387
1388 fn following_text_runs(
1389 &self,
1390 root_node: &Node,
1391 ) -> impl DoubleEndedIterator<Item = Node<'a>> + FusedIterator<Item = Node<'a>> + 'a {
1392 let id = root_node.id();
1393 self.following_filtered_siblings(move |node| text_node_filter(id, node))
1394 }
1395
1396 fn preceding_text_runs(
1397 &self,
1398 root_node: &Node,
1399 ) -> impl DoubleEndedIterator<Item = Node<'a>> + FusedIterator<Item = Node<'a>> + 'a {
1400 let id = root_node.id();
1401 self.preceding_filtered_siblings(move |node| text_node_filter(id, node))
1402 }
1403
1404 pub fn supports_text_ranges(&self) -> bool {
1405 (self.is_text_input()
1406 || matches!(self.role(), Role::Label | Role::Document | Role::Terminal))
1407 && self.text_runs().next().is_some()
1408 }
1409
1410 fn document_start_inner(&self) -> InnerPosition<'a> {
1411 let node = self.text_runs().next().unwrap();
1412 InnerPosition {
1413 node,
1414 character_index: 0,
1415 }
1416 }
1417
1418 pub fn document_start(&self) -> Position<'a> {
1419 Position {
1420 root_node: *self,
1421 inner: self.document_start_inner(),
1422 }
1423 }
1424
1425 fn document_end_inner(&self) -> InnerPosition<'a> {
1426 let node = self.text_runs().next_back().unwrap();
1427 InnerPosition {
1428 node,
1429 character_index: node.data().character_lengths().len(),
1430 }
1431 }
1432
1433 pub fn document_end(&self) -> Position<'a> {
1434 Position {
1435 root_node: *self,
1436 inner: self.document_end_inner(),
1437 }
1438 }
1439
1440 pub fn document_range(&self) -> Range<'_> {
1441 let start = self.document_start_inner();
1442 let end = self.document_end_inner();
1443 Range::new(*self, start, end)
1444 }
1445
1446 pub fn has_text_selection(&self) -> bool {
1447 self.data().text_selection().is_some()
1448 }
1449
1450 pub fn text_selection(&self) -> Option<Range<'_>> {
1451 let id = self.id;
1452 self.data().text_selection().map(|selection| {
1453 let anchor =
1454 InnerPosition::clamped_upgrade(self.tree_state, selection.anchor, id).unwrap();
1455 let focus =
1456 InnerPosition::clamped_upgrade(self.tree_state, selection.focus, id).unwrap();
1457 Range::new(*self, anchor, focus)
1458 })
1459 }
1460
1461 pub fn text_selection_anchor(&self) -> Option<Position<'_>> {
1462 let id = self.id;
1463 self.data().text_selection().map(|selection| {
1464 let anchor =
1465 InnerPosition::clamped_upgrade(self.tree_state, selection.anchor, id).unwrap();
1466 Position {
1467 root_node: *self,
1468 inner: anchor,
1469 }
1470 })
1471 }
1472
1473 pub fn text_selection_focus(&self) -> Option<Position<'_>> {
1474 let id = self.id;
1475 self.data().text_selection().map(|selection| {
1476 let focus =
1477 InnerPosition::clamped_upgrade(self.tree_state, selection.focus, id).unwrap();
1478 Position {
1479 root_node: *self,
1480 inner: focus,
1481 }
1482 })
1483 }
1484
1485 pub fn text_position_at_point(&self, point: Point) -> Position<'_> {
1488 let id = self.id();
1489 if let Some((node, point)) = self.hit_test(point, &move |node| text_node_filter(id, node)) {
1490 if node.role() == Role::TextRun {
1491 let pos = InnerPosition {
1492 node,
1493 character_index: character_index_at_point(&node, point),
1494 };
1495 return Position {
1496 root_node: *self,
1497 inner: pos,
1498 };
1499 }
1500 }
1501
1502 if let Some(node) = self.text_runs().next() {
1506 if let Some(rect) = node.bounding_box_in_coordinate_space(self) {
1507 let origin = rect.origin();
1508 if point.x < origin.x || point.y < origin.y {
1509 return self.document_start();
1510 }
1511 }
1512 }
1513
1514 for node in self.text_runs().rev() {
1515 if let Some(rect) = node.bounding_box_in_coordinate_space(self) {
1516 if let Some(direction) = node.text_direction() {
1517 let is_past_end = match direction {
1518 TextDirection::LeftToRight => {
1519 point.y >= rect.y0 && point.y < rect.y1 && point.x >= rect.x1
1520 }
1521 TextDirection::RightToLeft => {
1522 point.y >= rect.y0 && point.y < rect.y1 && point.x < rect.x0
1523 }
1524 TextDirection::TopToBottom => {
1528 point.x >= rect.x0 && point.x < rect.x1 && point.y >= rect.y1
1529 }
1530 TextDirection::BottomToTop => {
1531 point.x >= rect.x0 && point.x < rect.x1 && point.y < rect.y0
1532 }
1533 };
1534 if is_past_end {
1535 return Position {
1536 root_node: *self,
1537 inner: InnerPosition {
1538 node,
1539 character_index: node.data().character_lengths().len(),
1540 },
1541 };
1542 }
1543 }
1544 }
1545 }
1546
1547 self.document_end()
1548 }
1549
1550 pub fn line_range_from_index(&self, line_index: usize) -> Option<Range<'_>> {
1551 let mut pos = self.document_start();
1552
1553 if line_index > 0 {
1554 if pos.is_document_end() || pos.forward_to_line_end().is_document_end() {
1555 return None;
1556 }
1557 for _ in 0..line_index {
1558 if pos.is_document_end() {
1559 return None;
1560 }
1561 pos = pos.forward_to_line_start();
1562 }
1563 }
1564
1565 let end = if pos.is_document_end() {
1566 pos
1567 } else {
1568 pos.forward_to_line_end()
1569 };
1570 Some(Range::new(*self, pos.inner, end.inner))
1571 }
1572
1573 pub fn text_position_from_global_usv_index(&self, index: usize) -> Option<Position<'_>> {
1574 let mut total_length = 0usize;
1575 for node in self.text_runs() {
1576 let node_text = node.data().value().unwrap();
1577 let node_text_length = node_text.chars().count();
1578 let new_total_length = total_length + node_text_length;
1579 if index >= total_length && index < new_total_length {
1580 let index = index - total_length;
1581 let mut utf8_length = 0usize;
1582 let mut usv_length = 0usize;
1583 for (character_index, utf8_char_length) in
1584 node.data().character_lengths().iter().enumerate()
1585 {
1586 let new_utf8_length = utf8_length + (*utf8_char_length as usize);
1587 let char_str = &node_text[utf8_length..new_utf8_length];
1588 let usv_char_length = char_str.chars().count();
1589 let new_usv_length = usv_length + usv_char_length;
1590 if index >= usv_length && index < new_usv_length {
1591 return Some(Position {
1592 root_node: *self,
1593 inner: InnerPosition {
1594 node,
1595 character_index,
1596 },
1597 });
1598 }
1599 utf8_length = new_utf8_length;
1600 usv_length = new_usv_length;
1601 }
1602 panic!("index out of range");
1603 }
1604 total_length = new_total_length;
1605 }
1606 if index == total_length {
1607 return Some(self.document_end());
1608 }
1609 None
1610 }
1611
1612 pub fn text_position_from_global_utf16_index(&self, index: usize) -> Option<Position<'_>> {
1613 let mut total_length = 0usize;
1614 for node in self.text_runs() {
1615 let node_text = node.data().value().unwrap();
1616 let node_text_length = node_text.chars().map(char::len_utf16).sum::<usize>();
1617 let new_total_length = total_length + node_text_length;
1618 if index >= total_length && index < new_total_length {
1619 let index = index - total_length;
1620 let mut utf8_length = 0usize;
1621 let mut utf16_length = 0usize;
1622 for (character_index, utf8_char_length) in
1623 node.data().character_lengths().iter().enumerate()
1624 {
1625 let new_utf8_length = utf8_length + (*utf8_char_length as usize);
1626 let char_str = &node_text[utf8_length..new_utf8_length];
1627 let utf16_char_length = char_str.chars().map(char::len_utf16).sum::<usize>();
1628 let new_utf16_length = utf16_length + utf16_char_length;
1629 if index >= utf16_length && index < new_utf16_length {
1630 return Some(Position {
1631 root_node: *self,
1632 inner: InnerPosition {
1633 node,
1634 character_index,
1635 },
1636 });
1637 }
1638 utf8_length = new_utf8_length;
1639 utf16_length = new_utf16_length;
1640 }
1641 panic!("index out of range");
1642 }
1643 total_length = new_total_length;
1644 }
1645 if index == total_length {
1646 return Some(self.document_end());
1647 }
1648 None
1649 }
1650}
1651
1652#[cfg(test)]
1653mod tests {
1654 use crate::tests::nid;
1655 use accesskit::{
1656 Color, NodeId, Point, Rect, TextDecoration, TextDecorationStyle, TextSelection,
1657 };
1658 use alloc::vec;
1659
1660 pub(crate) const TEST_TEXT_DECORATION_1: TextDecoration = TextDecoration {
1661 style: TextDecorationStyle::Solid,
1662 color: Color {
1663 red: 0,
1664 green: 0,
1665 blue: 0,
1666 alpha: 255,
1667 },
1668 };
1669 pub(crate) const TEST_TEXT_DECORATION_2: TextDecoration = TextDecoration {
1670 style: TextDecorationStyle::Dotted,
1671 color: Color {
1672 red: 255,
1673 green: 0,
1674 blue: 0,
1675 alpha: 255,
1676 },
1677 };
1678 pub(crate) const TEST_TEXT_DECORATION_3: TextDecoration = TextDecoration {
1679 style: TextDecorationStyle::Dashed,
1680 color: Color {
1681 red: 0,
1682 green: 255,
1683 blue: 0,
1684 alpha: 255,
1685 },
1686 };
1687 pub(crate) const TEST_TEXT_DECORATION_4: TextDecoration = TextDecoration {
1688 style: TextDecorationStyle::Double,
1689 color: Color {
1690 red: 0,
1691 green: 0,
1692 blue: 255,
1693 alpha: 255,
1694 },
1695 };
1696
1697 fn main_multiline_tree(selection: Option<TextSelection>) -> crate::Tree {
1700 use accesskit::{Action, Affine, Node, Role, TextDirection, Tree, TreeId, TreeUpdate};
1701
1702 let update = TreeUpdate {
1703 nodes: vec![
1704 (NodeId(0), {
1705 let mut node = Node::new(Role::Window);
1706 node.set_transform(Affine::scale(1.5));
1707 node.set_children(vec![NodeId(1)]);
1708 node
1709 }),
1710 (NodeId(1), {
1711 let mut node = Node::new(Role::MultilineTextInput);
1712 node.set_bounds(Rect {
1713 x0: 8.0,
1714 y0: 31.666664123535156,
1715 x1: 296.0,
1716 y1: 123.66666412353516,
1717 });
1718 node.set_children(vec![
1719 NodeId(2),
1720 NodeId(3),
1721 NodeId(4),
1722 NodeId(5),
1723 NodeId(6),
1724 NodeId(7),
1725 NodeId(8),
1726 NodeId(9),
1727 ]);
1728 node.add_action(Action::Focus);
1729 node.set_text_direction(TextDirection::LeftToRight);
1730 if let Some(selection) = selection {
1731 node.set_text_selection(selection);
1732 }
1733 node
1734 }),
1735 (NodeId(2), {
1736 let mut node = Node::new(Role::TextRun);
1737 node.set_bounds(Rect {
1738 x0: 12.0,
1739 y0: 33.666664123535156,
1740 x1: 290.9189147949219,
1741 y1: 48.33333206176758,
1742 });
1743 node.set_value("This paragraph is\u{a0}long enough to wrap ");
1748 node.set_character_lengths([
1749 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
1750 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1751 ]);
1752 node.set_character_positions([
1753 0.0, 7.3333335, 14.666667, 22.0, 29.333334, 36.666668, 44.0, 51.333332,
1754 58.666668, 66.0, 73.333336, 80.666664, 88.0, 95.333336, 102.666664, 110.0,
1755 117.333336, 124.666664, 132.0, 139.33333, 146.66667, 154.0, 161.33333,
1756 168.66667, 176.0, 183.33333, 190.66667, 198.0, 205.33333, 212.66667, 220.0,
1757 227.33333, 234.66667, 242.0, 249.33333, 256.66666, 264.0, 271.33334,
1758 ]);
1759 node.set_character_widths([
1760 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1761 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1762 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1763 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1764 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1765 ]);
1766 node.set_word_starts([5, 15, 18, 23, 30, 33]);
1767 node
1768 }),
1769 (NodeId(3), {
1770 let mut node = Node::new(Role::TextRun);
1771 node.set_bounds(Rect {
1772 x0: 12.0,
1773 y0: 48.33333206176758,
1774 x1: 34.252257,
1775 y1: 63.0,
1776 });
1777 node.set_value("to ");
1778 node.set_character_lengths([1, 1, 1]);
1779 node.set_character_positions([0.0, 7.3333435, 14.666687]);
1780 node.set_character_widths([7.58557, 7.58557, 7.58557]);
1781 node.set_word_starts([0]);
1782 node.set_next_on_line(NodeId(4));
1783 node
1784 }),
1785 (NodeId(4), {
1786 let mut node = Node::new(Role::TextRun);
1787 node.set_bounds(Rect {
1788 x0: 34.0,
1789 y0: 48.33333206176758,
1790 x1: 85.58557,
1791 y1: 63.0,
1792 });
1793 node.set_value("another");
1794 node.set_character_lengths([1, 1, 1, 1, 1, 1, 1]);
1795 node.set_character_positions([
1796 0.0, 7.333344, 14.666687, 22.0, 29.333344, 36.666687, 44.0,
1797 ]);
1798 node.set_character_widths([
1799 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1800 ]);
1801 node.set_word_starts([0]);
1802 node.set_underline(TEST_TEXT_DECORATION_1);
1803 node.set_previous_on_line(NodeId(3));
1804 node.set_next_on_line(NodeId(5));
1805 node
1806 }),
1807 (NodeId(5), {
1808 let mut node = Node::new(Role::TextRun);
1809 node.set_bounds(Rect {
1810 x0: 85.33334,
1811 y0: 48.33333206176758,
1812 x1: 129.5855712890625,
1813 y1: 63.0,
1814 });
1815 node.set_value(" line.\n");
1816 node.set_character_lengths([1, 1, 1, 1, 1, 1, 1]);
1817 node.set_character_positions([
1818 0.0, 7.333344, 14.666687, 22.0, 29.333344, 36.666687, 44.25226,
1819 ]);
1820 node.set_character_widths([
1821 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 0.0,
1822 ]);
1823 node.set_word_starts([1]);
1824 node.set_previous_on_line(NodeId(4));
1825 node
1826 }),
1827 (NodeId(6), {
1828 let mut node = Node::new(Role::TextRun);
1829 node.set_bounds(Rect {
1830 x0: 12.0,
1831 y0: 63.0,
1832 x1: 144.25222778320313,
1833 y1: 77.66666412353516,
1834 });
1835 node.set_value("Another paragraph.\n");
1836 node.set_character_lengths([
1837 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1838 ]);
1839 node.set_character_positions([
1840 0.0, 7.3333335, 14.666667, 22.0, 29.333334, 36.666668, 44.0, 51.333332,
1841 58.666668, 66.0, 73.333336, 80.666664, 88.0, 95.333336, 102.666664, 110.0,
1842 117.333336, 124.666664, 132.25223,
1843 ]);
1844 node.set_character_widths([
1845 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1846 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1847 7.58557, 7.58557, 0.0,
1848 ]);
1849 node.set_word_starts([8]);
1850 node
1851 }),
1852 (NodeId(7), {
1853 let mut node = Node::new(Role::TextRun);
1854 node.set_bounds(Rect {
1855 x0: 12.0,
1856 y0: 77.66666412353516,
1857 x1: 12.0,
1858 y1: 92.33332824707031,
1859 });
1860 node.set_value("\n");
1861 node.set_character_lengths([1]);
1862 node.set_character_positions([0.0]);
1863 node.set_character_widths([0.0]);
1864 node
1865 }),
1866 (NodeId(8), {
1867 let mut node = Node::new(Role::TextRun);
1868 node.set_bounds(Rect {
1869 x0: 12.0,
1870 y0: 92.33332824707031,
1871 x1: 158.9188995361328,
1872 y1: 107.0,
1873 });
1874 node.set_value("Last non-blank line\u{1f44d}\u{1f3fb}\n");
1879 node.set_character_lengths([
1880 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 1,
1881 ]);
1882 node.set_character_positions([
1883 0.0, 7.3333335, 14.666667, 22.0, 29.333334, 36.666668, 44.0, 51.333332,
1884 58.666668, 66.0, 73.333336, 80.666664, 88.0, 95.333336, 102.666664, 110.0,
1885 117.333336, 124.666664, 132.0, 139.33333, 146.9189,
1886 ]);
1887 node.set_character_widths([
1888 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1889 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1890 7.58557, 7.58557, 7.58557, 7.58557, 0.0,
1891 ]);
1892 node.set_word_starts([5, 9, 15]);
1893 node
1894 }),
1895 (NodeId(9), {
1896 let mut node = Node::new(Role::TextRun);
1897 node.set_bounds(Rect {
1898 x0: 12.0,
1899 y0: 107.0,
1900 x1: 12.0,
1901 y1: 121.66666412353516,
1902 });
1903 node.set_value("");
1904 node.set_character_lengths([]);
1905 node.set_character_positions([]);
1906 node.set_character_widths([]);
1907 node
1908 }),
1909 ],
1910 tree: Some(Tree::new(NodeId(0))),
1911 tree_id: TreeId::ROOT,
1912 focus: NodeId(1),
1913 };
1914
1915 crate::Tree::new(update, true)
1916 }
1917
1918 fn multiline_end_selection() -> TextSelection {
1919 use accesskit::TextPosition;
1920
1921 TextSelection {
1922 anchor: TextPosition {
1923 node: NodeId(9),
1924 character_index: 0,
1925 },
1926 focus: TextPosition {
1927 node: NodeId(9),
1928 character_index: 0,
1929 },
1930 }
1931 }
1932
1933 fn multiline_past_end_selection() -> TextSelection {
1934 use accesskit::TextPosition;
1935
1936 TextSelection {
1937 anchor: TextPosition {
1938 node: NodeId(9),
1939 character_index: 3,
1940 },
1941 focus: TextPosition {
1942 node: NodeId(9),
1943 character_index: 3,
1944 },
1945 }
1946 }
1947
1948 fn multiline_wrapped_line_end_selection() -> TextSelection {
1949 use accesskit::TextPosition;
1950
1951 TextSelection {
1952 anchor: TextPosition {
1953 node: NodeId(2),
1954 character_index: 38,
1955 },
1956 focus: TextPosition {
1957 node: NodeId(2),
1958 character_index: 38,
1959 },
1960 }
1961 }
1962
1963 fn multiline_first_line_middle_selection() -> TextSelection {
1964 use accesskit::TextPosition;
1965
1966 TextSelection {
1967 anchor: TextPosition {
1968 node: NodeId(2),
1969 character_index: 5,
1970 },
1971 focus: TextPosition {
1972 node: NodeId(2),
1973 character_index: 5,
1974 },
1975 }
1976 }
1977
1978 fn multiline_second_line_middle_selection() -> TextSelection {
1979 use accesskit::TextPosition;
1980
1981 TextSelection {
1982 anchor: TextPosition {
1983 node: NodeId(4),
1984 character_index: 3,
1985 },
1986 focus: TextPosition {
1987 node: NodeId(4),
1988 character_index: 3,
1989 },
1990 }
1991 }
1992
1993 #[test]
1994 fn supports_text_ranges() {
1995 let tree = main_multiline_tree(None);
1996 let state = tree.state();
1997 assert!(!state
1998 .node_by_id(nid(NodeId(0)))
1999 .unwrap()
2000 .supports_text_ranges());
2001 assert!(state
2002 .node_by_id(nid(NodeId(1)))
2003 .unwrap()
2004 .supports_text_ranges());
2005 }
2006
2007 #[test]
2008 fn multiline_document_range() {
2009 let tree = main_multiline_tree(None);
2010 let state = tree.state();
2011 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2012 let range = node.document_range();
2013 let start = range.start();
2014 assert!(start.is_word_start());
2015 assert!(start.is_line_start());
2016 assert!(!start.is_line_end());
2017 assert!(start.is_paragraph_start());
2018 assert!(start.is_document_start());
2019 assert!(!start.is_document_end());
2020 let end = range.end();
2021 assert!(start < end);
2022 assert!(end.is_word_start());
2023 assert!(end.is_line_start());
2024 assert!(end.is_line_end());
2025 assert!(end.is_paragraph_start());
2026 assert!(!end.is_document_start());
2027 assert!(end.is_document_end());
2028 assert_eq!(range.text(), "This paragraph is\u{a0}long enough to wrap to another line.\nAnother paragraph.\n\nLast non-blank line\u{1f44d}\u{1f3fb}\n");
2029 assert_eq!(
2030 range.bounding_boxes(),
2031 vec![
2032 Rect {
2033 x0: 18.0,
2034 y0: 50.499996185302734,
2035 x1: 436.3783721923828,
2036 y1: 72.49999809265137
2037 },
2038 Rect {
2039 x0: 18.0,
2040 y0: 72.49999809265137,
2041 x1: 51.3783855,
2042 y1: 94.5
2043 },
2044 Rect {
2045 x0: 51.0,
2046 y0: 72.49999809265137,
2047 x1: 128.378355,
2048 y1: 94.5
2049 },
2050 Rect {
2051 x0: 128.00001,
2052 y0: 72.49999809265137,
2053 x1: 194.37835693359375,
2054 y1: 94.5
2055 },
2056 Rect {
2057 x0: 18.0,
2058 y0: 94.5,
2059 x1: 216.3783416748047,
2060 y1: 116.49999618530273
2061 },
2062 Rect {
2063 x0: 18.0,
2064 y0: 116.49999618530273,
2065 x1: 18.0,
2066 y1: 138.49999237060547
2067 },
2068 Rect {
2069 x0: 18.0,
2070 y0: 138.49999237060547,
2071 x1: 238.37834930419922,
2072 y1: 160.5
2073 }
2074 ]
2075 );
2076 }
2077
2078 #[test]
2079 fn multiline_document_range_to_first_format_change() {
2080 let tree = main_multiline_tree(None);
2081 let state = tree.state();
2082 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2083 let mut range = node.document_range();
2084 range.set_end(range.start().forward_to_format_end());
2085 assert_eq!(
2086 range.text(),
2087 "This paragraph is\u{a0}long enough to wrap to "
2088 );
2089 assert_eq!(
2090 range.bounding_boxes(),
2091 vec![
2092 Rect {
2093 x0: 18.0,
2094 y0: 50.499996185302734,
2095 x1: 436.3783721923828,
2096 y1: 72.49999809265137
2097 },
2098 Rect {
2099 x0: 18.0,
2100 y0: 72.49999809265137,
2101 x1: 51.3783855,
2102 y1: 94.5
2103 }
2104 ]
2105 );
2106 }
2107
2108 #[test]
2109 fn multiline_document_range_from_last_format_change() {
2110 let tree = main_multiline_tree(None);
2111 let state = tree.state();
2112 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2113 let mut range = node.document_range();
2114 range.set_start(range.end().backward_to_format_start());
2115 assert_eq!(
2116 range.text(),
2117 " line.\nAnother paragraph.\n\nLast non-blank line\u{1f44d}\u{1f3fb}\n"
2118 );
2119 assert_eq!(
2120 range.bounding_boxes(),
2121 vec![
2122 Rect {
2123 x0: 128.00001,
2124 y0: 72.49999809265137,
2125 x1: 194.37835693359375,
2126 y1: 94.5
2127 },
2128 Rect {
2129 x0: 18.0,
2130 y0: 94.5,
2131 x1: 216.3783416748047,
2132 y1: 116.49999618530273
2133 },
2134 Rect {
2135 x0: 18.0,
2136 y0: 116.49999618530273,
2137 x1: 18.0,
2138 y1: 138.49999237060547
2139 },
2140 Rect {
2141 x0: 18.0,
2142 y0: 138.49999237060547,
2143 x1: 238.37834930419922,
2144 y1: 160.5
2145 }
2146 ]
2147 );
2148 }
2149
2150 #[test]
2151 fn multiline_end_degenerate_range() {
2152 let tree = main_multiline_tree(Some(multiline_end_selection()));
2153 let state = tree.state();
2154 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2155 let range = node.text_selection().unwrap();
2156 assert!(range.is_degenerate());
2157 let pos = range.start();
2158 assert!(pos.is_word_start());
2159 assert!(pos.is_line_start());
2160 assert!(pos.is_line_end());
2161 assert!(pos.is_paragraph_start());
2162 assert!(!pos.is_document_start());
2163 assert!(pos.is_document_end());
2164 assert_eq!(range.text(), "");
2165 assert_eq!(
2166 range.bounding_boxes(),
2167 vec![Rect {
2168 x0: 18.0,
2169 y0: 160.5,
2170 x1: 18.0,
2171 y1: 182.49999618530273,
2172 }]
2173 );
2174 }
2175
2176 #[test]
2177 fn multiline_wrapped_line_end_range() {
2178 let tree = main_multiline_tree(Some(multiline_wrapped_line_end_selection()));
2179 let state = tree.state();
2180 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2181 let range = node.text_selection().unwrap();
2182 assert!(range.is_degenerate());
2183 let pos = range.start();
2184 assert!(!pos.is_word_start());
2185 assert!(!pos.is_line_start());
2186 assert!(pos.is_line_end());
2187 assert!(!pos.is_paragraph_start());
2188 assert!(!pos.is_document_start());
2189 assert!(!pos.is_document_end());
2190 assert_eq!(range.text(), "");
2191 assert_eq!(
2192 range.bounding_boxes(),
2193 vec![Rect {
2194 x0: 436.3783721923828,
2195 y0: 50.499996185302734,
2196 x1: 436.3783721923828,
2197 y1: 72.49999809265137
2198 }]
2199 );
2200 let char_end_pos = pos.forward_to_character_end();
2201 let mut line_start_range = range;
2202 line_start_range.set_end(char_end_pos);
2203 assert!(!line_start_range.is_degenerate());
2204 assert!(line_start_range.start().is_line_start());
2205 assert_eq!(line_start_range.text(), "t");
2206 assert_eq!(
2207 line_start_range.bounding_boxes(),
2208 vec![Rect {
2209 x0: 18.0,
2210 y0: 72.49999809265137,
2211 x1: 29.378354787826538,
2212 y1: 94.5
2213 }]
2214 );
2215 let prev_char_pos = pos.backward_to_character_start();
2216 let mut prev_char_range = range;
2217 prev_char_range.set_start(prev_char_pos);
2218 assert!(!prev_char_range.is_degenerate());
2219 assert!(prev_char_range.end().is_line_end());
2220 assert_eq!(prev_char_range.text(), " ");
2221 assert_eq!(
2222 prev_char_range.bounding_boxes(),
2223 vec![Rect {
2224 x0: 425.00001525878906,
2225 y0: 50.499996185302734,
2226 x1: 436.3783721923828,
2227 y1: 72.49999809265137
2228 }]
2229 );
2230 assert!(prev_char_pos.forward_to_character_end().is_line_end());
2231 assert!(prev_char_pos.forward_to_word_end().is_line_end());
2232 assert!(prev_char_pos.forward_to_line_end().is_line_end());
2233 assert!(prev_char_pos.forward_to_character_start().is_line_start());
2234 assert!(prev_char_pos.forward_to_word_start().is_line_start());
2235 assert!(prev_char_pos.forward_to_line_start().is_line_start());
2236 }
2237
2238 #[test]
2239 fn multiline_find_line_ends_from_middle() {
2240 let tree = main_multiline_tree(Some(multiline_second_line_middle_selection()));
2241 let state = tree.state();
2242 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2243 let mut range = node.text_selection().unwrap();
2244 assert!(range.is_degenerate());
2245 let pos = range.start();
2246 assert!(!pos.is_line_start());
2247 assert!(!pos.is_line_end());
2248 assert!(!pos.is_document_start());
2249 assert!(!pos.is_document_end());
2250 let line_start = pos.backward_to_line_start();
2251 range.set_start(line_start);
2252 let line_end = line_start.forward_to_line_end();
2253 range.set_end(line_end);
2254 assert!(!range.is_degenerate());
2255 assert!(range.start().is_line_start());
2256 assert!(range.end().is_line_end());
2257 assert_eq!(range.text(), "to another line.\n");
2258 assert_eq!(
2259 range.bounding_boxes(),
2260 vec![
2261 Rect {
2262 x0: 18.0,
2263 y0: 72.49999809265137,
2264 x1: 51.3783855,
2265 y1: 94.5
2266 },
2267 Rect {
2268 x0: 51.0,
2269 y0: 72.49999809265137,
2270 x1: 128.378355,
2271 y1: 94.5
2272 },
2273 Rect {
2274 x0: 128.00001,
2275 y0: 72.49999809265137,
2276 x1: 194.37835693359375,
2277 y1: 94.5
2278 },
2279 ]
2280 );
2281 assert!(line_start.forward_to_line_start().is_line_start());
2282 }
2283
2284 #[test]
2285 fn multiline_find_wrapped_line_ends_from_middle() {
2286 let tree = main_multiline_tree(Some(multiline_first_line_middle_selection()));
2287 let state = tree.state();
2288 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2289 let mut range = node.text_selection().unwrap();
2290 assert!(range.is_degenerate());
2291 let pos = range.start();
2292 assert!(!pos.is_line_start());
2293 assert!(!pos.is_line_end());
2294 assert!(!pos.is_document_start());
2295 assert!(!pos.is_document_end());
2296 let line_start = pos.backward_to_line_start();
2297 range.set_start(line_start);
2298 let line_end = line_start.forward_to_line_end();
2299 range.set_end(line_end);
2300 assert!(!range.is_degenerate());
2301 assert!(range.start().is_line_start());
2302 assert!(range.end().is_line_end());
2303 assert_eq!(range.text(), "This paragraph is\u{a0}long enough to wrap ");
2304 assert_eq!(
2305 range.bounding_boxes(),
2306 vec![Rect {
2307 x0: 18.0,
2308 y0: 50.499996185302734,
2309 x1: 436.3783721923828,
2310 y1: 72.49999809265137
2311 }]
2312 );
2313 assert!(line_start.forward_to_line_start().is_line_start());
2314 }
2315
2316 #[test]
2317 fn multiline_find_paragraph_ends_from_middle() {
2318 let tree = main_multiline_tree(Some(multiline_second_line_middle_selection()));
2319 let state = tree.state();
2320 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2321 let mut range = node.text_selection().unwrap();
2322 assert!(range.is_degenerate());
2323 let pos = range.start();
2324 assert!(!pos.is_paragraph_start());
2325 assert!(!pos.is_document_start());
2326 assert!(!pos.is_document_end());
2327 let paragraph_start = pos.backward_to_paragraph_start();
2328 range.set_start(paragraph_start);
2329 let paragraph_end = paragraph_start.forward_to_paragraph_end();
2330 range.set_end(paragraph_end);
2331 assert!(!range.is_degenerate());
2332 assert!(range.start().is_paragraph_start());
2333 assert!(range.end().is_paragraph_end());
2334 assert_eq!(
2335 range.text(),
2336 "This paragraph is\u{a0}long enough to wrap to another line.\n"
2337 );
2338 assert_eq!(
2339 range.bounding_boxes(),
2340 vec![
2341 Rect {
2342 x0: 18.0,
2343 y0: 50.499996185302734,
2344 x1: 436.3783721923828,
2345 y1: 72.49999809265137
2346 },
2347 Rect {
2348 x0: 18.0,
2349 y0: 72.49999809265137,
2350 x1: 51.3783855,
2351 y1: 94.5
2352 },
2353 Rect {
2354 x0: 51.0,
2355 y0: 72.49999809265137,
2356 x1: 128.378355,
2357 y1: 94.5
2358 },
2359 Rect {
2360 x0: 128.00001,
2361 y0: 72.49999809265137,
2362 x1: 194.37835693359375,
2363 y1: 94.5
2364 },
2365 ]
2366 );
2367 assert!(paragraph_start
2368 .forward_to_paragraph_start()
2369 .is_paragraph_start());
2370 }
2371
2372 #[test]
2373 fn multiline_find_format_ends_from_middle() {
2374 let tree = main_multiline_tree(Some(multiline_second_line_middle_selection()));
2375 let state = tree.state();
2376 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2377 let mut range = node.text_selection().unwrap();
2378 assert!(range.is_degenerate());
2379 let pos = range.start();
2380 assert!(!pos.is_format_start());
2381 assert!(!pos.is_document_start());
2382 assert!(!pos.is_document_end());
2383 let format_start = pos.backward_to_format_start();
2384 range.set_start(format_start);
2385 let format_end = pos.forward_to_format_end();
2386 range.set_end(format_end);
2387 assert!(!range.is_degenerate());
2388 assert_eq!(range.text(), "another");
2389 assert_eq!(
2390 range.bounding_boxes(),
2391 vec![Rect {
2392 x0: 51.0,
2393 y0: 72.49999809265137,
2394 x1: 128.378355,
2395 y1: 94.5
2396 }]
2397 );
2398 }
2399
2400 #[test]
2401 fn multiline_find_word_ends_from_middle() {
2402 let tree = main_multiline_tree(Some(multiline_second_line_middle_selection()));
2403 let state = tree.state();
2404 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2405 let mut range = node.text_selection().unwrap();
2406 assert!(range.is_degenerate());
2407 let pos = range.start();
2408 assert!(!pos.is_word_start());
2409 assert!(!pos.is_document_start());
2410 assert!(!pos.is_document_end());
2411 let word_start = pos.backward_to_word_start();
2412 range.set_start(word_start);
2413 let word_end = word_start.forward_to_word_end();
2414 let word_end2 = pos.forward_to_word_end();
2415 assert_eq!(word_end, word_end2);
2416 let word_start2 = word_end.backward_to_word_start();
2417 assert_eq!(word_start, word_start2);
2418 range.set_end(word_end);
2419 assert!(!range.is_degenerate());
2420 assert_eq!(range.text(), "another ");
2421 assert_eq!(
2422 range.bounding_boxes(),
2423 [
2424 Rect {
2425 x0: 51.0,
2426 y0: 72.49999809265137,
2427 x1: 128.378355,
2428 y1: 94.5
2429 },
2430 Rect {
2431 x0: 128.00001,
2432 y0: 72.49999809265137,
2433 x1: 139.37836478782654,
2434 y1: 94.5
2435 }
2436 ]
2437 );
2438 }
2439
2440 #[test]
2441 fn text_position_at_point() {
2442 let tree = main_multiline_tree(None);
2443 let state = tree.state();
2444 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2445
2446 {
2447 let pos = node.text_position_at_point(Point::new(8.0, 31.666664123535156));
2448 assert!(pos.is_document_start());
2449 }
2450
2451 {
2452 let pos = node.text_position_at_point(Point::new(12.0, 33.666664123535156));
2453 assert!(pos.is_document_start());
2454 }
2455
2456 {
2457 let pos = node.text_position_at_point(Point::new(16.0, 40.0));
2458 assert!(pos.is_document_start());
2459 }
2460
2461 {
2462 let pos = node.text_position_at_point(Point::new(144.0, 40.0));
2463 assert!(!pos.is_document_start());
2464 assert!(!pos.is_document_end());
2465 assert!(!pos.is_line_end());
2466 let mut range = pos.to_degenerate_range();
2467 range.set_end(pos.forward_to_character_end());
2468 assert_eq!(range.text(), "l");
2469 }
2470
2471 {
2472 let pos = node.text_position_at_point(Point::new(150.0, 40.0));
2473 assert!(!pos.is_document_start());
2474 assert!(!pos.is_document_end());
2475 assert!(!pos.is_line_end());
2476 let mut range = pos.to_degenerate_range();
2477 range.set_end(pos.forward_to_character_end());
2478 assert_eq!(range.text(), "l");
2479 }
2480
2481 {
2482 let pos = node.text_position_at_point(Point::new(291.0, 40.0));
2483 assert!(!pos.is_document_start());
2484 assert!(!pos.is_document_end());
2485 assert!(pos.is_line_end());
2486 let mut range = pos.to_degenerate_range();
2487 range.set_start(pos.backward_to_word_start());
2488 assert_eq!(range.text(), "wrap ");
2489 }
2490
2491 {
2492 let pos = node.text_position_at_point(Point::new(12.0, 50.0));
2493 assert!(!pos.is_document_start());
2494 assert!(pos.is_line_start());
2495 assert!(!pos.is_paragraph_start());
2496 let mut range = pos.to_degenerate_range();
2497 range.set_end(pos.forward_to_word_end());
2498 assert_eq!(range.text(), "to ");
2499 }
2500
2501 {
2502 let pos = node.text_position_at_point(Point::new(130.0, 50.0));
2503 assert!(!pos.is_document_start());
2504 assert!(!pos.is_document_end());
2505 assert!(pos.is_line_end());
2506 let mut range = pos.to_degenerate_range();
2507 range.set_start(pos.backward_to_word_start());
2508 assert_eq!(range.text(), "line.\n");
2509 }
2510
2511 {
2512 let pos = node.text_position_at_point(Point::new(12.0, 80.0));
2513 assert!(!pos.is_document_start());
2514 assert!(!pos.is_document_end());
2515 assert!(pos.is_line_end());
2516 let mut range = pos.to_degenerate_range();
2517 range.set_start(pos.backward_to_line_start());
2518 assert_eq!(range.text(), "\n");
2519 }
2520
2521 {
2522 let pos = node.text_position_at_point(Point::new(12.0, 120.0));
2523 assert!(pos.is_document_end());
2524 }
2525
2526 {
2527 let pos = node.text_position_at_point(Point::new(250.0, 122.0));
2528 assert!(pos.is_document_end());
2529 }
2530 }
2531
2532 #[test]
2533 fn to_global_usv_index() {
2534 let tree = main_multiline_tree(None);
2535 let state = tree.state();
2536 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2537
2538 {
2539 let range = node.document_range();
2540 assert_eq!(range.start().to_global_usv_index(), 0);
2541 assert_eq!(range.end().to_global_usv_index(), 97);
2542 }
2543
2544 {
2545 let range = node.document_range();
2546 let pos = range.start().forward_to_line_end();
2547 assert_eq!(pos.to_global_usv_index(), 38);
2548 let pos = range.start().forward_to_line_start();
2549 assert_eq!(pos.to_global_usv_index(), 38);
2550 let pos = pos.forward_to_character_start();
2551 assert_eq!(pos.to_global_usv_index(), 39);
2552 let pos = pos.forward_to_line_start();
2553 assert_eq!(pos.to_global_usv_index(), 55);
2554 }
2555 }
2556
2557 #[test]
2558 fn to_global_utf16_index() {
2559 let tree = main_multiline_tree(None);
2560 let state = tree.state();
2561 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2562
2563 {
2564 let range = node.document_range();
2565 assert_eq!(range.start().to_global_utf16_index(), 0);
2566 assert_eq!(range.end().to_global_utf16_index(), 99);
2567 }
2568
2569 {
2570 let range = node.document_range();
2571 let pos = range.start().forward_to_line_end();
2572 assert_eq!(pos.to_global_utf16_index(), 38);
2573 let pos = range.start().forward_to_line_start();
2574 assert_eq!(pos.to_global_utf16_index(), 38);
2575 let pos = pos.forward_to_character_start();
2576 assert_eq!(pos.to_global_utf16_index(), 39);
2577 let pos = pos.forward_to_line_start();
2578 assert_eq!(pos.to_global_utf16_index(), 55);
2579 }
2580 }
2581
2582 #[test]
2583 fn to_line_index() {
2584 let tree = main_multiline_tree(None);
2585 let state = tree.state();
2586 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2587
2588 {
2589 let range = node.document_range();
2590 assert_eq!(range.start().to_line_index(), 0);
2591 assert_eq!(range.end().to_line_index(), 5);
2592 }
2593
2594 {
2595 let range = node.document_range();
2596 let pos = range.start().forward_to_line_end();
2597 assert_eq!(pos.to_line_index(), 0);
2598 let pos = range.start().forward_to_line_start();
2599 assert_eq!(pos.to_line_index(), 1);
2600 let pos = pos.forward_to_character_start();
2601 assert_eq!(pos.to_line_index(), 1);
2602 assert_eq!(pos.forward_to_line_end().to_line_index(), 1);
2603 let pos = pos.forward_to_line_start();
2604 assert_eq!(pos.to_line_index(), 2);
2605 }
2606 }
2607
2608 #[test]
2609 fn line_range_from_index() {
2610 let tree = main_multiline_tree(None);
2611 let state = tree.state();
2612 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2613
2614 {
2615 let range = node.line_range_from_index(0).unwrap();
2616 assert_eq!(range.text(), "This paragraph is\u{a0}long enough to wrap ");
2617 }
2618
2619 {
2620 let range = node.line_range_from_index(1).unwrap();
2621 assert_eq!(range.text(), "to another line.\n");
2622 }
2623
2624 {
2625 let range = node.line_range_from_index(2).unwrap();
2626 assert_eq!(range.text(), "Another paragraph.\n");
2627 }
2628
2629 {
2630 let range = node.line_range_from_index(3).unwrap();
2631 assert_eq!(range.text(), "\n");
2632 }
2633
2634 {
2635 let range = node.line_range_from_index(4).unwrap();
2636 assert_eq!(range.text(), "Last non-blank line\u{1f44d}\u{1f3fb}\n");
2637 }
2638
2639 {
2640 let range = node.line_range_from_index(5).unwrap();
2641 assert_eq!(range.text(), "");
2642 }
2643
2644 assert!(node.line_range_from_index(6).is_none());
2645 }
2646
2647 #[test]
2648 fn text_position_from_global_usv_index() {
2649 let tree = main_multiline_tree(None);
2650 let state = tree.state();
2651 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2652
2653 {
2654 let pos = node.text_position_from_global_usv_index(0).unwrap();
2655 assert!(pos.is_document_start());
2656 }
2657
2658 {
2659 let pos = node.text_position_from_global_usv_index(17).unwrap();
2660 let mut range = pos.to_degenerate_range();
2661 range.set_end(pos.forward_to_character_end());
2662 assert_eq!(range.text(), "\u{a0}");
2663 }
2664
2665 {
2666 let pos = node.text_position_from_global_usv_index(18).unwrap();
2667 let mut range = pos.to_degenerate_range();
2668 range.set_end(pos.forward_to_character_end());
2669 assert_eq!(range.text(), "l");
2670 }
2671
2672 {
2673 let pos = node.text_position_from_global_usv_index(37).unwrap();
2674 let mut range = pos.to_degenerate_range();
2675 range.set_end(pos.forward_to_character_end());
2676 assert_eq!(range.text(), " ");
2677 }
2678
2679 {
2680 let pos = node.text_position_from_global_usv_index(38).unwrap();
2681 assert!(!pos.is_paragraph_start());
2682 assert!(pos.is_line_start());
2683 let mut range = pos.to_degenerate_range();
2684 range.set_end(pos.forward_to_character_end());
2685 assert_eq!(range.text(), "t");
2686 }
2687
2688 {
2689 let pos = node.text_position_from_global_usv_index(54).unwrap();
2690 let mut range = pos.to_degenerate_range();
2691 range.set_end(pos.forward_to_character_end());
2692 assert_eq!(range.text(), "\n");
2693 }
2694
2695 {
2696 let pos = node.text_position_from_global_usv_index(55).unwrap();
2697 assert!(pos.is_paragraph_start());
2698 assert!(pos.is_line_start());
2699 let mut range = pos.to_degenerate_range();
2700 range.set_end(pos.forward_to_character_end());
2701 assert_eq!(range.text(), "A");
2702 }
2703
2704 for i in 94..=95 {
2705 let pos = node.text_position_from_global_usv_index(i).unwrap();
2706 let mut range = pos.to_degenerate_range();
2707 range.set_end(pos.forward_to_character_end());
2708 assert_eq!(range.text(), "\u{1f44d}\u{1f3fb}");
2709 }
2710
2711 {
2712 let pos = node.text_position_from_global_usv_index(96).unwrap();
2713 let mut range = pos.to_degenerate_range();
2714 range.set_end(pos.forward_to_character_end());
2715 assert_eq!(range.text(), "\n");
2716 }
2717
2718 {
2719 let pos = node.text_position_from_global_usv_index(97).unwrap();
2720 assert!(pos.is_document_end());
2721 }
2722
2723 assert!(node.text_position_from_global_usv_index(98).is_none());
2724 }
2725
2726 #[test]
2727 fn text_position_from_global_utf16_index() {
2728 let tree = main_multiline_tree(None);
2729 let state = tree.state();
2730 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2731
2732 {
2733 let pos = node.text_position_from_global_utf16_index(0).unwrap();
2734 assert!(pos.is_document_start());
2735 }
2736
2737 {
2738 let pos = node.text_position_from_global_utf16_index(17).unwrap();
2739 let mut range = pos.to_degenerate_range();
2740 range.set_end(pos.forward_to_character_end());
2741 assert_eq!(range.text(), "\u{a0}");
2742 }
2743
2744 {
2745 let pos = node.text_position_from_global_utf16_index(18).unwrap();
2746 let mut range = pos.to_degenerate_range();
2747 range.set_end(pos.forward_to_character_end());
2748 assert_eq!(range.text(), "l");
2749 }
2750
2751 {
2752 let pos = node.text_position_from_global_utf16_index(37).unwrap();
2753 let mut range = pos.to_degenerate_range();
2754 range.set_end(pos.forward_to_character_end());
2755 assert_eq!(range.text(), " ");
2756 }
2757
2758 {
2759 let pos = node.text_position_from_global_utf16_index(38).unwrap();
2760 assert!(!pos.is_paragraph_start());
2761 assert!(pos.is_line_start());
2762 let mut range = pos.to_degenerate_range();
2763 range.set_end(pos.forward_to_character_end());
2764 assert_eq!(range.text(), "t");
2765 }
2766
2767 {
2768 let pos = node.text_position_from_global_utf16_index(54).unwrap();
2769 let mut range = pos.to_degenerate_range();
2770 range.set_end(pos.forward_to_character_end());
2771 assert_eq!(range.text(), "\n");
2772 }
2773
2774 {
2775 let pos = node.text_position_from_global_utf16_index(55).unwrap();
2776 assert!(pos.is_paragraph_start());
2777 assert!(pos.is_line_start());
2778 let mut range = pos.to_degenerate_range();
2779 range.set_end(pos.forward_to_character_end());
2780 assert_eq!(range.text(), "A");
2781 }
2782
2783 for i in 94..=97 {
2784 let pos = node.text_position_from_global_utf16_index(i).unwrap();
2785 let mut range = pos.to_degenerate_range();
2786 range.set_end(pos.forward_to_character_end());
2787 assert_eq!(range.text(), "\u{1f44d}\u{1f3fb}");
2788 }
2789
2790 {
2791 let pos = node.text_position_from_global_utf16_index(98).unwrap();
2792 let mut range = pos.to_degenerate_range();
2793 range.set_end(pos.forward_to_character_end());
2794 assert_eq!(range.text(), "\n");
2795 }
2796
2797 {
2798 let pos = node.text_position_from_global_utf16_index(99).unwrap();
2799 assert!(pos.is_document_end());
2800 }
2801
2802 assert!(node.text_position_from_global_utf16_index(100).is_none());
2803 }
2804
2805 #[test]
2806 fn multiline_selection_clamping() {
2807 let tree = main_multiline_tree(Some(multiline_past_end_selection()));
2808 let state = tree.state();
2809 let node = state.node_by_id(nid(NodeId(1))).unwrap();
2810 let _ = node.text_selection().unwrap();
2811 }
2812
2813 #[test]
2814 fn range_property_value_map() {
2815 use super::RangePropertyValue;
2816 assert_eq!(
2817 RangePropertyValue::Single(Some(0)).map(|x| x + 1),
2818 RangePropertyValue::Single(Some(1))
2819 );
2820 assert_eq!(
2821 RangePropertyValue::<Option<usize>>::Single(None).map(|x| x + 1),
2822 RangePropertyValue::Single(None)
2823 );
2824 assert_eq!(
2825 RangePropertyValue::<Option<usize>>::Mixed.map(|x| x + 1),
2826 RangePropertyValue::Mixed
2827 );
2828 }
2829}