accesskit_consumer/
text.rs

1// Copyright 2022 The AccessKit Authors. All rights reserved.
2// Licensed under the Apache License, Version 2.0 (found in
3// the LICENSE-APACHE file) or the MIT license (found in
4// the LICENSE-MIT file), at your option.
5
6use 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        // Wrap the following in a scope to make sure we can't misuse the
393        // `word_starts` local later.
394        {
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        // Wrap the following in a scope to make sure we can't misuse the
440        // `word_starts` local later.
441        {
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        // If the range is degenerate, we don't want to normalize it.
654        // This is important e.g. when getting the bounding rectangle
655        // of the caret range when the caret is at the end of a wrapped line.
656        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 text(&self) -> String {
681        let mut result = String::new();
682        self.write_text(&mut result).unwrap();
683        result
684    }
685
686    pub fn write_text<W: fmt::Write>(&self, mut writer: W) -> fmt::Result {
687        if let Some(err) = self.walk(|node| {
688            let character_lengths = node.data().character_lengths();
689            let start_index = if node.id() == self.start.node.id() {
690                self.start.character_index
691            } else {
692                0
693            };
694            let end_index = if node.id() == self.end.node.id() {
695                self.end.character_index
696            } else {
697                character_lengths.len()
698            };
699            let value = node.data().value().unwrap();
700            let s = if start_index == end_index {
701                ""
702            } else if start_index == 0 && end_index == character_lengths.len() {
703                value
704            } else {
705                let slice_start = character_lengths[..start_index]
706                    .iter()
707                    .copied()
708                    .map(usize::from)
709                    .sum::<usize>();
710                let slice_end = slice_start
711                    + character_lengths[start_index..end_index]
712                        .iter()
713                        .copied()
714                        .map(usize::from)
715                        .sum::<usize>();
716                &value[slice_start..slice_end]
717            };
718            writer.write_str(s).err()
719        }) {
720            Err(err)
721        } else {
722            Ok(())
723        }
724    }
725
726    /// Returns the range's transformed bounding boxes relative to the tree's
727    /// container (e.g. window).
728    ///
729    /// If the return value is empty, it means that the source tree doesn't
730    /// provide enough information to calculate bounding boxes. Otherwise,
731    /// there will always be at least one box, even if it's zero-width,
732    /// as it is for a degenerate range.
733    pub fn bounding_boxes(&self) -> Vec<Rect> {
734        let mut result = Vec::new();
735        self.walk(|node| {
736            let mut rect = match node.data().bounds() {
737                Some(rect) => rect,
738                None => {
739                    return Some(Vec::new());
740                }
741            };
742            let positions = match node.data().character_positions() {
743                Some(positions) => positions,
744                None => {
745                    return Some(Vec::new());
746                }
747            };
748            let widths = match node.data().character_widths() {
749                Some(widths) => widths,
750                None => {
751                    return Some(Vec::new());
752                }
753            };
754            let direction = match node.text_direction() {
755                Some(direction) => direction,
756                None => {
757                    return Some(Vec::new());
758                }
759            };
760            let character_lengths = node.data().character_lengths();
761            let start_index = if node.id() == self.start.node.id() {
762                self.start.character_index
763            } else {
764                0
765            };
766            let end_index = if node.id() == self.end.node.id() {
767                self.end.character_index
768            } else {
769                character_lengths.len()
770            };
771            if start_index != 0 || end_index != character_lengths.len() {
772                let pixel_start = if start_index < character_lengths.len() {
773                    positions[start_index]
774                } else {
775                    positions[start_index - 1] + widths[start_index - 1]
776                };
777                let pixel_end = if end_index == start_index {
778                    pixel_start
779                } else {
780                    positions[end_index - 1] + widths[end_index - 1]
781                };
782                let pixel_start = f64::from(pixel_start);
783                let pixel_end = f64::from(pixel_end);
784                match direction {
785                    TextDirection::LeftToRight => {
786                        let orig_left = rect.x0;
787                        rect.x0 = orig_left + pixel_start;
788                        rect.x1 = orig_left + pixel_end;
789                    }
790                    TextDirection::RightToLeft => {
791                        let orig_right = rect.x1;
792                        rect.x1 = orig_right - pixel_start;
793                        rect.x0 = orig_right - pixel_end;
794                    }
795                    // Note: The following directions assume that the rectangle,
796                    // in the node's coordinate space, is y-down. TBD: Will we
797                    // ever encounter a case where this isn't true?
798                    TextDirection::TopToBottom => {
799                        let orig_top = rect.y0;
800                        rect.y0 = orig_top + pixel_start;
801                        rect.y1 = orig_top + pixel_end;
802                    }
803                    TextDirection::BottomToTop => {
804                        let orig_bottom = rect.y1;
805                        rect.y1 = orig_bottom - pixel_start;
806                        rect.y0 = orig_bottom - pixel_end;
807                    }
808                }
809            }
810            result.push(node.transform().transform_rect_bbox(rect));
811            None
812        })
813        .unwrap_or(result)
814    }
815
816    fn fetch_property<T: alloc::fmt::Debug + PartialEq>(
817        &self,
818        getter: fn(&Node<'a>) -> T,
819    ) -> RangePropertyValue<T> {
820        let mut value = None;
821        self.walk(|node| {
822            let current = getter(node);
823            if let Some(value) = &value {
824                if *value != current {
825                    return Some(RangePropertyValue::Mixed);
826                }
827            } else {
828                value = Some(current);
829            }
830            None
831        })
832        .unwrap_or_else(|| RangePropertyValue::Single(value.unwrap()))
833    }
834
835    fn fix_start_bias(&mut self) {
836        if !self.is_degenerate() {
837            self.start = self.start.biased_to_start(&self.node);
838        }
839    }
840
841    pub fn set_start(&mut self, pos: Position<'a>) {
842        assert_eq!(pos.root_node.id(), self.node.id());
843        self.start = pos.inner;
844        // We use `>=` here because if the two endpoints are equivalent
845        // but with a different bias, we want to normalize the bias.
846        if self.start.comparable(&self.node) >= self.end.comparable(&self.node) {
847            self.end = self.start;
848        }
849        self.fix_start_bias();
850    }
851
852    pub fn set_end(&mut self, pos: Position<'a>) {
853        assert_eq!(pos.root_node.id(), self.node.id());
854        self.end = pos.inner;
855        // We use `>=` here because if the two endpoints are equivalent
856        // but with a different bias, we want to normalize the bias.
857        if self.start.comparable(&self.node) >= self.end.comparable(&self.node) {
858            self.start = self.end;
859        }
860        self.fix_start_bias();
861    }
862
863    pub fn to_text_selection(&self) -> TextSelection {
864        TextSelection {
865            anchor: self.start.downgrade(),
866            focus: self.end.downgrade(),
867        }
868    }
869
870    pub fn downgrade(&self) -> WeakRange {
871        WeakRange {
872            node_id: self.node.id(),
873            start: self.start.downgrade(),
874            end: self.end.downgrade(),
875            start_comparable: self.start.comparable(&self.node),
876            end_comparable: self.end.comparable(&self.node),
877        }
878    }
879}
880
881impl PartialEq for Range<'_> {
882    fn eq(&self, other: &Self) -> bool {
883        self.node.id() == other.node.id() && self.start == other.start && self.end == other.end
884    }
885}
886
887impl Eq for Range<'_> {}
888
889#[derive(Clone, Debug, PartialEq, Eq)]
890pub struct WeakRange {
891    node_id: NodeId,
892    start: WeakPosition,
893    end: WeakPosition,
894    start_comparable: (Vec<usize>, usize),
895    end_comparable: (Vec<usize>, usize),
896}
897
898impl WeakRange {
899    pub fn node_id(&self) -> NodeId {
900        self.node_id
901    }
902
903    pub fn start_comparable(&self) -> &(Vec<usize>, usize) {
904        &self.start_comparable
905    }
906
907    pub fn end_comparable(&self) -> &(Vec<usize>, usize) {
908        &self.end_comparable
909    }
910
911    pub fn upgrade_node<'a>(&self, tree_state: &'a TreeState) -> Option<Node<'a>> {
912        tree_state
913            .node_by_id(self.node_id)
914            .filter(Node::supports_text_ranges)
915    }
916
917    pub fn upgrade<'a>(&self, tree_state: &'a TreeState) -> Option<Range<'a>> {
918        let node = self.upgrade_node(tree_state)?;
919        let start = InnerPosition::upgrade(tree_state, self.start, self.node_id)?;
920        let end = InnerPosition::upgrade(tree_state, self.end, self.node_id)?;
921        Some(Range { node, start, end })
922    }
923}
924
925fn text_node_filter(root_id: NodeId, node: &Node) -> FilterResult {
926    if node.id() == root_id || node.role() == Role::TextRun {
927        FilterResult::Include
928    } else {
929        FilterResult::ExcludeNode
930    }
931}
932
933fn character_index_at_point(node: &Node, point: Point) -> usize {
934    // We know the node has a bounding rectangle because it was returned
935    // by a hit test.
936    let rect = node.data().bounds().unwrap();
937    let character_lengths = node.data().character_lengths();
938    let positions = match node.data().character_positions() {
939        Some(positions) => positions,
940        None => {
941            return 0;
942        }
943    };
944    let widths = match node.data().character_widths() {
945        Some(widths) => widths,
946        None => {
947            return 0;
948        }
949    };
950    let direction = match node.text_direction() {
951        Some(direction) => direction,
952        None => {
953            return 0;
954        }
955    };
956    for (i, (position, width)) in positions.iter().zip(widths.iter()).enumerate().rev() {
957        let relative_pos = match direction {
958            TextDirection::LeftToRight => point.x - rect.x0,
959            TextDirection::RightToLeft => rect.x1 - point.x,
960            // Note: The following directions assume that the rectangle,
961            // in the node's coordinate space, is y-down. TBD: Will we
962            // ever encounter a case where this isn't true?
963            TextDirection::TopToBottom => point.y - rect.y0,
964            TextDirection::BottomToTop => rect.y1 - point.y,
965        };
966        if relative_pos >= f64::from(*position) && relative_pos < f64::from(*position + *width) {
967            return i;
968        }
969    }
970    character_lengths.len()
971}
972
973macro_rules! inherited_properties {
974    ($(($getter:ident, $type:ty, $setter:ident, $test_value_1:expr, $test_value_2:expr)),+) => {
975        impl<'a> Node<'a> {
976            $(pub fn $getter(&self) -> Option<$type> {
977                self.fetch_inherited_property(NodeData::$getter)
978            })*
979        }
980        impl<'a> Position<'a> {
981            $(pub fn $getter(&self) -> Option<$type> {
982                self.inner.node.$getter()
983            })*
984        }
985        impl<'a> Range<'a> {
986            $(pub fn $getter(&self) -> RangePropertyValue<Option<$type>> {
987                self.fetch_property(Node::$getter)
988            })*
989        }
990        $(#[cfg(test)]
991        mod $getter {
992            use accesskit::{Node, NodeId, Role, Tree, TreeId, TreeUpdate};
993            use alloc::vec;
994            use super::RangePropertyValue;
995            use crate::tests::nid;
996            #[test]
997            fn directly_set() {
998                let update = TreeUpdate {
999                    nodes: vec![
1000                        (NodeId(0), {
1001                            let mut node = Node::new(Role::TextInput);
1002                            node.set_children(vec![NodeId(1)]);
1003                            node
1004                        }),
1005                        (NodeId(1), {
1006                            let mut node = Node::new(Role::TextRun);
1007                            node.set_value("text");
1008                            node.set_character_lengths([1, 1, 1, 1]);
1009                            node.$setter($test_value_1);
1010                            node
1011                        }),
1012                    ],
1013                    tree: Some(Tree::new(NodeId(0))),
1014                    tree_id: TreeId::ROOT,
1015                    focus: NodeId(0),
1016                };
1017                let tree = crate::Tree::new(update, false);
1018                let state = tree.state();
1019                let node = state.node_by_id(nid(NodeId(0))).unwrap();
1020                let pos = node.document_start();
1021                assert_eq!(pos.$getter(), Some($test_value_1));
1022                let range = node.document_range();
1023                assert_eq!(range.$getter(), RangePropertyValue::Single(Some($test_value_1)));
1024            }
1025            #[test]
1026            fn set_on_parent() {
1027                let update = TreeUpdate {
1028                    nodes: vec![
1029                        (NodeId(0), {
1030                            let mut node = Node::new(Role::TextInput);
1031                            node.set_children(vec![NodeId(1)]);
1032                            node.$setter($test_value_1);
1033                            node
1034                        }),
1035                        (NodeId(1), {
1036                            let mut node = Node::new(Role::TextRun);
1037                            node.set_value("text");
1038                            node.set_character_lengths([1, 1, 1, 1]);
1039                            node
1040                        }),
1041                    ],
1042                    tree: Some(Tree::new(NodeId(0))),
1043                    tree_id: TreeId::ROOT,
1044                    focus: NodeId(0),
1045                };
1046                let tree = crate::Tree::new(update, false);
1047                let state = tree.state();
1048                let node = state.node_by_id(nid(NodeId(0))).unwrap();
1049                let pos = node.document_start();
1050                assert_eq!(pos.$getter(), Some($test_value_1));
1051                let range = node.document_range();
1052                assert_eq!(range.$getter(), RangePropertyValue::Single(Some($test_value_1)));
1053            }
1054            #[test]
1055            fn only_child_overrides_parent() {
1056                let update = TreeUpdate {
1057                    nodes: vec![
1058                        (NodeId(0), {
1059                            let mut node = Node::new(Role::TextInput);
1060                            node.set_children(vec![NodeId(1)]);
1061                            node.$setter($test_value_1);
1062                            node
1063                        }),
1064                        (NodeId(1), {
1065                            let mut node = Node::new(Role::TextRun);
1066                            node.set_value("text");
1067                            node.set_character_lengths([1, 1, 1, 1]);
1068                            node.$setter($test_value_2);
1069                            node
1070                        }),
1071                    ],
1072                    tree: Some(Tree::new(NodeId(0))),
1073                    tree_id: TreeId::ROOT,
1074                    focus: NodeId(0),
1075                };
1076                let tree = crate::Tree::new(update, false);
1077                let state = tree.state();
1078                let node = state.node_by_id(nid(NodeId(0))).unwrap();
1079                assert_eq!(node.$getter(), Some($test_value_1));
1080                let pos = node.document_start();
1081                assert_eq!(pos.$getter(), Some($test_value_2));
1082                let range = node.document_range();
1083                assert_eq!(range.$getter(), RangePropertyValue::Single(Some($test_value_2)));
1084            }
1085            #[test]
1086            fn unset() {
1087                let update = TreeUpdate {
1088                    nodes: vec![
1089                        (NodeId(0), {
1090                            let mut node = Node::new(Role::TextInput);
1091                            node.set_children(vec![NodeId(1)]);
1092                            node
1093                        }),
1094                        (NodeId(1), {
1095                            let mut node = Node::new(Role::TextRun);
1096                            node.set_value("text");
1097                            node.set_character_lengths([1, 1, 1, 1]);
1098                            node
1099                        }),
1100                    ],
1101                    tree: Some(Tree::new(NodeId(0))),
1102                    tree_id: TreeId::ROOT,
1103                    focus: NodeId(0),
1104                };
1105                let tree = crate::Tree::new(update, false);
1106                let state = tree.state();
1107                let node = state.node_by_id(nid(NodeId(0))).unwrap();
1108                let pos = node.document_start();
1109                assert_eq!(pos.$getter(), None);
1110                let range = node.document_range();
1111                assert_eq!(range.$getter(), RangePropertyValue::Single(None));
1112            }
1113            #[test]
1114            fn mixed_some_and_none() {
1115                let update = TreeUpdate {
1116                    nodes: vec![
1117                        (NodeId(0), {
1118                            let mut node = Node::new(Role::TextInput);
1119                            node.set_children(vec![NodeId(1), NodeId(2)]);
1120                            node
1121                        }),
1122                        (NodeId(1), {
1123                            let mut node = Node::new(Role::TextRun);
1124                            node.set_value("text 1\n");
1125                            node.set_character_lengths([1, 1, 1, 1, 1, 1, 1]);
1126                            node.$setter($test_value_1);
1127                            node
1128                        }),
1129                        (NodeId(2), {
1130                            let mut node = Node::new(Role::TextRun);
1131                            node.set_value("text 2");
1132                            node.set_character_lengths([1, 1, 1, 1, 1, 1]);
1133                            node
1134                        }),
1135                    ],
1136                    tree: Some(Tree::new(NodeId(0))),
1137                    tree_id: TreeId::ROOT,
1138                    focus: NodeId(0),
1139                };
1140                let tree = crate::Tree::new(update, false);
1141                let state = tree.state();
1142                let node = state.node_by_id(nid(NodeId(0))).unwrap();
1143                let range = node.document_range();
1144                assert_eq!(range.$getter(), RangePropertyValue::Mixed);
1145            }
1146            #[test]
1147            fn mixed_one_child_overrides_parent() {
1148                let update = TreeUpdate {
1149                    nodes: vec![
1150                        (NodeId(0), {
1151                            let mut node = Node::new(Role::TextInput);
1152                            node.set_children(vec![NodeId(1), NodeId(2)]);
1153                            node.$setter($test_value_1);
1154                            node
1155                        }),
1156                        (NodeId(1), {
1157                            let mut node = Node::new(Role::TextRun);
1158                            node.set_value("text 1\n");
1159                            node.set_character_lengths([1, 1, 1, 1, 1, 1, 1]);
1160                            node.$setter($test_value_2);
1161                            node
1162                        }),
1163                        (NodeId(2), {
1164                            let mut node = Node::new(Role::TextRun);
1165                            node.set_value("text 2");
1166                            node.set_character_lengths([1, 1, 1, 1, 1, 1]);
1167                            node
1168                        }),
1169                    ],
1170                    tree: Some(Tree::new(NodeId(0))),
1171                    tree_id: TreeId::ROOT,
1172                    focus: NodeId(0),
1173                };
1174                let tree = crate::Tree::new(update, false);
1175                let state = tree.state();
1176                let node = state.node_by_id(nid(NodeId(0))).unwrap();
1177                assert_eq!(node.$getter(), Some($test_value_1));
1178                let start = node.document_start();
1179                assert_eq!(start.$getter(), Some($test_value_2));
1180                let start_range = start.to_degenerate_range();
1181                assert_eq!(start_range.$getter(), RangePropertyValue::Single(Some($test_value_2)));
1182                let end = node.document_end();
1183                assert_eq!(end.$getter(), Some($test_value_1));
1184                let end_range = end.to_degenerate_range();
1185                assert_eq!(end_range.$getter(), RangePropertyValue::Single(Some($test_value_1)));
1186                let range = node.document_range();
1187                assert_eq!(range.$getter(), RangePropertyValue::Mixed);
1188            }
1189        })*
1190    }
1191}
1192
1193inherited_properties! {
1194    (text_direction, TextDirection, set_text_direction, accesskit::TextDirection::LeftToRight, accesskit::TextDirection::RightToLeft),
1195    (font_family, &'a str, set_font_family, "Noto", "Inconsolata"),
1196    (language, &'a str, set_language, "en", "fr"),
1197    (font_size, f32, set_font_size, 12.0, 24.0),
1198    (font_weight, f32, set_font_weight, 400.0, 700.0),
1199    (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 }),
1200    (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 }),
1201    (overline, TextDecoration, set_overline, crate::text::tests::TEST_TEXT_DECORATION_1, crate::text::tests::TEST_TEXT_DECORATION_2),
1202    (strikethrough, TextDecoration, set_strikethrough, crate::text::tests::TEST_TEXT_DECORATION_2, crate::text::tests::TEST_TEXT_DECORATION_3),
1203    (underline, TextDecoration, set_underline, crate::text::tests::TEST_TEXT_DECORATION_3, crate::text::tests::TEST_TEXT_DECORATION_4),
1204    (text_align, TextAlign, set_text_align, accesskit::TextAlign::Left, accesskit::TextAlign::Justify),
1205    (vertical_offset, VerticalOffset, set_vertical_offset, accesskit::VerticalOffset::Subscript, accesskit::VerticalOffset::Superscript)
1206}
1207
1208macro_rules! inherited_flags {
1209    ($(($getter:ident, $setter:ident)),+) => {
1210        impl<'a> Node<'a> {
1211            $(pub fn $getter(&self) -> bool {
1212                self.fetch_inherited_flag(NodeData::$getter)
1213            })*
1214        }
1215        impl<'a> Position<'a> {
1216            $(pub fn $getter(&self) -> bool {
1217                self.inner.node.$getter()
1218            })*
1219        }
1220        impl<'a> Range<'a> {
1221            $(pub fn $getter(&self) -> RangePropertyValue<bool> {
1222                self.fetch_property(Node::$getter)
1223            })*
1224        }
1225        $(#[cfg(test)]
1226        mod $getter {
1227            use accesskit::{Node, NodeId, Role, Tree, TreeId, TreeUpdate};
1228            use alloc::vec;
1229            use super::RangePropertyValue;
1230            use crate::tests::nid;
1231            #[test]
1232            fn directly_set() {
1233                let update = TreeUpdate {
1234                    nodes: vec![
1235                        (NodeId(0), {
1236                            let mut node = Node::new(Role::TextInput);
1237                            node.set_children(vec![NodeId(1)]);
1238                            node
1239                        }),
1240                        (NodeId(1), {
1241                            let mut node = Node::new(Role::TextRun);
1242                            node.set_value("text");
1243                            node.set_character_lengths([1, 1, 1, 1]);
1244                            node.$setter();
1245                            node
1246                        }),
1247                    ],
1248                    tree: Some(Tree::new(NodeId(0))),
1249                    tree_id: TreeId::ROOT,
1250                    focus: NodeId(0),
1251                };
1252                let tree = crate::Tree::new(update, false);
1253                let state = tree.state();
1254                let node = state.node_by_id(nid(NodeId(0))).unwrap();
1255                let pos = node.document_start();
1256                assert!(pos.$getter());
1257                let range = node.document_range();
1258                assert_eq!(range.$getter(), RangePropertyValue::Single(true));
1259            }
1260            #[test]
1261            fn set_on_parent() {
1262                let update = TreeUpdate {
1263                    nodes: vec![
1264                        (NodeId(0), {
1265                            let mut node = Node::new(Role::TextInput);
1266                            node.set_children(vec![NodeId(1)]);
1267                            node.$setter();
1268                            node
1269                        }),
1270                        (NodeId(1), {
1271                            let mut node = Node::new(Role::TextRun);
1272                            node.set_value("text");
1273                            node.set_character_lengths([1, 1, 1, 1]);
1274                            node
1275                        }),
1276                    ],
1277                    tree: Some(Tree::new(NodeId(0))),
1278                    tree_id: TreeId::ROOT,
1279                    focus: NodeId(0),
1280                };
1281                let tree = crate::Tree::new(update, false);
1282                let state = tree.state();
1283                let node = state.node_by_id(nid(NodeId(0))).unwrap();
1284                let pos = node.document_start();
1285                assert!(pos.$getter());
1286                let range = node.document_range();
1287                assert_eq!(range.$getter(), RangePropertyValue::Single(true));
1288            }
1289            #[test]
1290            fn unset() {
1291                let update = TreeUpdate {
1292                    nodes: vec![
1293                        (NodeId(0), {
1294                            let mut node = Node::new(Role::TextInput);
1295                            node.set_children(vec![NodeId(1)]);
1296                            node
1297                        }),
1298                        (NodeId(1), {
1299                            let mut node = Node::new(Role::TextRun);
1300                            node.set_value("text");
1301                            node.set_character_lengths([1, 1, 1, 1]);
1302                            node
1303                        }),
1304                    ],
1305                    tree: Some(Tree::new(NodeId(0))),
1306                    tree_id: TreeId::ROOT,
1307                    focus: NodeId(0),
1308                };
1309                let tree = crate::Tree::new(update, false);
1310                let state = tree.state();
1311                let node = state.node_by_id(nid(NodeId(0))).unwrap();
1312                let pos = node.document_start();
1313                assert!(!pos.$getter());
1314                let range = node.document_range();
1315                assert_eq!(range.$getter(), RangePropertyValue::Single(false));
1316            }
1317            #[test]
1318            fn mixed() {
1319                let update = TreeUpdate {
1320                    nodes: vec![
1321                        (NodeId(0), {
1322                            let mut node = Node::new(Role::TextInput);
1323                            node.set_children(vec![NodeId(1), NodeId(2)]);
1324                            node
1325                        }),
1326                        (NodeId(1), {
1327                            let mut node = Node::new(Role::TextRun);
1328                            node.set_value("text 1\n");
1329                            node.set_character_lengths([1, 1, 1, 1, 1, 1, 1]);
1330                            node.$setter();
1331                            node
1332                        }),
1333                        (NodeId(2), {
1334                            let mut node = Node::new(Role::TextRun);
1335                            node.set_value("text 2");
1336                            node.set_character_lengths([1, 1, 1, 1, 1, 1]);
1337                            node
1338                        }),
1339                    ],
1340                    tree: Some(Tree::new(NodeId(0))),
1341                    tree_id: TreeId::ROOT,
1342                    focus: NodeId(0),
1343                };
1344                let tree = crate::Tree::new(update, false);
1345                let state = tree.state();
1346                let node = state.node_by_id(nid(NodeId(0))).unwrap();
1347                let range = node.document_range();
1348                assert_eq!(range.$getter(), RangePropertyValue::Mixed);
1349            }
1350        })*
1351    }
1352}
1353
1354inherited_flags! {
1355    (is_italic, set_italic)
1356}
1357
1358impl<'a> Node<'a> {
1359    fn text_attributes_differ(&self, other: &Self) -> bool {
1360        self.font_family() != other.font_family()
1361            || self.language() != other.language()
1362            || self.font_size() != other.font_size()
1363            || self.font_weight() != other.font_weight()
1364            || self.background_color() != other.background_color()
1365            || self.foreground_color() != other.foreground_color()
1366            || self.overline() != other.overline()
1367            || self.strikethrough() != other.strikethrough()
1368            || self.underline() != other.underline()
1369            || self.text_align() != other.text_align()
1370            || self.vertical_offset() != other.vertical_offset()
1371        // TODO: more attributes
1372    }
1373
1374    pub(crate) fn text_runs(
1375        &self,
1376    ) -> impl DoubleEndedIterator<Item = Node<'a>> + FusedIterator<Item = Node<'a>> + 'a {
1377        let id = self.id();
1378        self.filtered_children(move |node| text_node_filter(id, node))
1379    }
1380
1381    fn following_text_runs(
1382        &self,
1383        root_node: &Node,
1384    ) -> impl DoubleEndedIterator<Item = Node<'a>> + FusedIterator<Item = Node<'a>> + 'a {
1385        let id = root_node.id();
1386        self.following_filtered_siblings(move |node| text_node_filter(id, node))
1387    }
1388
1389    fn preceding_text_runs(
1390        &self,
1391        root_node: &Node,
1392    ) -> impl DoubleEndedIterator<Item = Node<'a>> + FusedIterator<Item = Node<'a>> + 'a {
1393        let id = root_node.id();
1394        self.preceding_filtered_siblings(move |node| text_node_filter(id, node))
1395    }
1396
1397    pub fn supports_text_ranges(&self) -> bool {
1398        (self.is_text_input()
1399            || matches!(self.role(), Role::Label | Role::Document | Role::Terminal))
1400            && self.text_runs().next().is_some()
1401    }
1402
1403    fn document_start_inner(&self) -> InnerPosition<'a> {
1404        let node = self.text_runs().next().unwrap();
1405        InnerPosition {
1406            node,
1407            character_index: 0,
1408        }
1409    }
1410
1411    pub fn document_start(&self) -> Position<'a> {
1412        Position {
1413            root_node: *self,
1414            inner: self.document_start_inner(),
1415        }
1416    }
1417
1418    fn document_end_inner(&self) -> InnerPosition<'a> {
1419        let node = self.text_runs().next_back().unwrap();
1420        InnerPosition {
1421            node,
1422            character_index: node.data().character_lengths().len(),
1423        }
1424    }
1425
1426    pub fn document_end(&self) -> Position<'a> {
1427        Position {
1428            root_node: *self,
1429            inner: self.document_end_inner(),
1430        }
1431    }
1432
1433    pub fn document_range(&self) -> Range<'_> {
1434        let start = self.document_start_inner();
1435        let end = self.document_end_inner();
1436        Range::new(*self, start, end)
1437    }
1438
1439    pub fn has_text_selection(&self) -> bool {
1440        self.data().text_selection().is_some()
1441    }
1442
1443    pub fn text_selection(&self) -> Option<Range<'_>> {
1444        let id = self.id;
1445        self.data().text_selection().map(|selection| {
1446            let anchor =
1447                InnerPosition::clamped_upgrade(self.tree_state, selection.anchor, id).unwrap();
1448            let focus =
1449                InnerPosition::clamped_upgrade(self.tree_state, selection.focus, id).unwrap();
1450            Range::new(*self, anchor, focus)
1451        })
1452    }
1453
1454    pub fn text_selection_anchor(&self) -> Option<Position<'_>> {
1455        let id = self.id;
1456        self.data().text_selection().map(|selection| {
1457            let anchor =
1458                InnerPosition::clamped_upgrade(self.tree_state, selection.anchor, id).unwrap();
1459            Position {
1460                root_node: *self,
1461                inner: anchor,
1462            }
1463        })
1464    }
1465
1466    pub fn text_selection_focus(&self) -> Option<Position<'_>> {
1467        let id = self.id;
1468        self.data().text_selection().map(|selection| {
1469            let focus =
1470                InnerPosition::clamped_upgrade(self.tree_state, selection.focus, id).unwrap();
1471            Position {
1472                root_node: *self,
1473                inner: focus,
1474            }
1475        })
1476    }
1477
1478    /// Returns the nearest text position to the given point
1479    /// in this node's coordinate space.
1480    pub fn text_position_at_point(&self, point: Point) -> Position<'_> {
1481        let id = self.id();
1482        if let Some((node, point)) = self.hit_test(point, &move |node| text_node_filter(id, node)) {
1483            if node.role() == Role::TextRun {
1484                let pos = InnerPosition {
1485                    node,
1486                    character_index: character_index_at_point(&node, point),
1487                };
1488                return Position {
1489                    root_node: *self,
1490                    inner: pos,
1491                };
1492            }
1493        }
1494
1495        // The following tests can assume that the point is not within
1496        // any text run.
1497
1498        if let Some(node) = self.text_runs().next() {
1499            if let Some(rect) = node.bounding_box_in_coordinate_space(self) {
1500                let origin = rect.origin();
1501                if point.x < origin.x || point.y < origin.y {
1502                    return self.document_start();
1503                }
1504            }
1505        }
1506
1507        for node in self.text_runs().rev() {
1508            if let Some(rect) = node.bounding_box_in_coordinate_space(self) {
1509                if let Some(direction) = node.text_direction() {
1510                    let is_past_end = match direction {
1511                        TextDirection::LeftToRight => {
1512                            point.y >= rect.y0 && point.y < rect.y1 && point.x >= rect.x1
1513                        }
1514                        TextDirection::RightToLeft => {
1515                            point.y >= rect.y0 && point.y < rect.y1 && point.x < rect.x0
1516                        }
1517                        // Note: The following directions assume that the rectangle,
1518                        // in the root node's coordinate space, is y-down. TBD: Will we
1519                        // ever encounter a case where this isn't true?
1520                        TextDirection::TopToBottom => {
1521                            point.x >= rect.x0 && point.x < rect.x1 && point.y >= rect.y1
1522                        }
1523                        TextDirection::BottomToTop => {
1524                            point.x >= rect.x0 && point.x < rect.x1 && point.y < rect.y0
1525                        }
1526                    };
1527                    if is_past_end {
1528                        return Position {
1529                            root_node: *self,
1530                            inner: InnerPosition {
1531                                node,
1532                                character_index: node.data().character_lengths().len(),
1533                            },
1534                        };
1535                    }
1536                }
1537            }
1538        }
1539
1540        self.document_end()
1541    }
1542
1543    pub fn line_range_from_index(&self, line_index: usize) -> Option<Range<'_>> {
1544        let mut pos = self.document_start();
1545
1546        if line_index > 0 {
1547            if pos.is_document_end() || pos.forward_to_line_end().is_document_end() {
1548                return None;
1549            }
1550            for _ in 0..line_index {
1551                if pos.is_document_end() {
1552                    return None;
1553                }
1554                pos = pos.forward_to_line_start();
1555            }
1556        }
1557
1558        let end = if pos.is_document_end() {
1559            pos
1560        } else {
1561            pos.forward_to_line_end()
1562        };
1563        Some(Range::new(*self, pos.inner, end.inner))
1564    }
1565
1566    pub fn text_position_from_global_usv_index(&self, index: usize) -> Option<Position<'_>> {
1567        let mut total_length = 0usize;
1568        for node in self.text_runs() {
1569            let node_text = node.data().value().unwrap();
1570            let node_text_length = node_text.chars().count();
1571            let new_total_length = total_length + node_text_length;
1572            if index >= total_length && index < new_total_length {
1573                let index = index - total_length;
1574                let mut utf8_length = 0usize;
1575                let mut usv_length = 0usize;
1576                for (character_index, utf8_char_length) in
1577                    node.data().character_lengths().iter().enumerate()
1578                {
1579                    let new_utf8_length = utf8_length + (*utf8_char_length as usize);
1580                    let char_str = &node_text[utf8_length..new_utf8_length];
1581                    let usv_char_length = char_str.chars().count();
1582                    let new_usv_length = usv_length + usv_char_length;
1583                    if index >= usv_length && index < new_usv_length {
1584                        return Some(Position {
1585                            root_node: *self,
1586                            inner: InnerPosition {
1587                                node,
1588                                character_index,
1589                            },
1590                        });
1591                    }
1592                    utf8_length = new_utf8_length;
1593                    usv_length = new_usv_length;
1594                }
1595                panic!("index out of range");
1596            }
1597            total_length = new_total_length;
1598        }
1599        if index == total_length {
1600            return Some(self.document_end());
1601        }
1602        None
1603    }
1604
1605    pub fn text_position_from_global_utf16_index(&self, index: usize) -> Option<Position<'_>> {
1606        let mut total_length = 0usize;
1607        for node in self.text_runs() {
1608            let node_text = node.data().value().unwrap();
1609            let node_text_length = node_text.chars().map(char::len_utf16).sum::<usize>();
1610            let new_total_length = total_length + node_text_length;
1611            if index >= total_length && index < new_total_length {
1612                let index = index - total_length;
1613                let mut utf8_length = 0usize;
1614                let mut utf16_length = 0usize;
1615                for (character_index, utf8_char_length) in
1616                    node.data().character_lengths().iter().enumerate()
1617                {
1618                    let new_utf8_length = utf8_length + (*utf8_char_length as usize);
1619                    let char_str = &node_text[utf8_length..new_utf8_length];
1620                    let utf16_char_length = char_str.chars().map(char::len_utf16).sum::<usize>();
1621                    let new_utf16_length = utf16_length + utf16_char_length;
1622                    if index >= utf16_length && index < new_utf16_length {
1623                        return Some(Position {
1624                            root_node: *self,
1625                            inner: InnerPosition {
1626                                node,
1627                                character_index,
1628                            },
1629                        });
1630                    }
1631                    utf8_length = new_utf8_length;
1632                    utf16_length = new_utf16_length;
1633                }
1634                panic!("index out of range");
1635            }
1636            total_length = new_total_length;
1637        }
1638        if index == total_length {
1639            return Some(self.document_end());
1640        }
1641        None
1642    }
1643}
1644
1645#[cfg(test)]
1646mod tests {
1647    use crate::tests::nid;
1648    use accesskit::{
1649        Color, NodeId, Point, Rect, TextDecoration, TextDecorationStyle, TextSelection,
1650    };
1651    use alloc::vec;
1652
1653    pub(crate) const TEST_TEXT_DECORATION_1: TextDecoration = TextDecoration {
1654        style: TextDecorationStyle::Solid,
1655        color: Color {
1656            red: 0,
1657            green: 0,
1658            blue: 0,
1659            alpha: 255,
1660        },
1661    };
1662    pub(crate) const TEST_TEXT_DECORATION_2: TextDecoration = TextDecoration {
1663        style: TextDecorationStyle::Dotted,
1664        color: Color {
1665            red: 255,
1666            green: 0,
1667            blue: 0,
1668            alpha: 255,
1669        },
1670    };
1671    pub(crate) const TEST_TEXT_DECORATION_3: TextDecoration = TextDecoration {
1672        style: TextDecorationStyle::Dashed,
1673        color: Color {
1674            red: 0,
1675            green: 255,
1676            blue: 0,
1677            alpha: 255,
1678        },
1679    };
1680    pub(crate) const TEST_TEXT_DECORATION_4: TextDecoration = TextDecoration {
1681        style: TextDecorationStyle::Double,
1682        color: Color {
1683            red: 0,
1684            green: 0,
1685            blue: 255,
1686            alpha: 255,
1687        },
1688    };
1689
1690    // This was originally based on an actual tree produced by egui but
1691    // has since been heavily modified by hand to cover various test cases.
1692    fn main_multiline_tree(selection: Option<TextSelection>) -> crate::Tree {
1693        use accesskit::{Action, Affine, Node, Role, TextDirection, Tree, TreeId, TreeUpdate};
1694
1695        let update = TreeUpdate {
1696            nodes: vec![
1697                (NodeId(0), {
1698                    let mut node = Node::new(Role::Window);
1699                    node.set_transform(Affine::scale(1.5));
1700                    node.set_children(vec![NodeId(1)]);
1701                    node
1702                }),
1703                (NodeId(1), {
1704                    let mut node = Node::new(Role::MultilineTextInput);
1705                    node.set_bounds(Rect {
1706                        x0: 8.0,
1707                        y0: 31.666664123535156,
1708                        x1: 296.0,
1709                        y1: 123.66666412353516,
1710                    });
1711                    node.set_children(vec![
1712                        NodeId(2),
1713                        NodeId(3),
1714                        NodeId(4),
1715                        NodeId(5),
1716                        NodeId(6),
1717                        NodeId(7),
1718                        NodeId(8),
1719                        NodeId(9),
1720                    ]);
1721                    node.add_action(Action::Focus);
1722                    node.set_text_direction(TextDirection::LeftToRight);
1723                    if let Some(selection) = selection {
1724                        node.set_text_selection(selection);
1725                    }
1726                    node
1727                }),
1728                (NodeId(2), {
1729                    let mut node = Node::new(Role::TextRun);
1730                    node.set_bounds(Rect {
1731                        x0: 12.0,
1732                        y0: 33.666664123535156,
1733                        x1: 290.9189147949219,
1734                        y1: 48.33333206176758,
1735                    });
1736                    // The non-breaking space in the following text
1737                    // is in an arbitrary spot; its only purpose
1738                    // is to test conversion between UTF-8 and UTF-16
1739                    // indices.
1740                    node.set_value("This paragraph is\u{a0}long enough to wrap ");
1741                    node.set_character_lengths([
1742                        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,
1743                        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1744                    ]);
1745                    node.set_character_positions([
1746                        0.0, 7.3333335, 14.666667, 22.0, 29.333334, 36.666668, 44.0, 51.333332,
1747                        58.666668, 66.0, 73.333336, 80.666664, 88.0, 95.333336, 102.666664, 110.0,
1748                        117.333336, 124.666664, 132.0, 139.33333, 146.66667, 154.0, 161.33333,
1749                        168.66667, 176.0, 183.33333, 190.66667, 198.0, 205.33333, 212.66667, 220.0,
1750                        227.33333, 234.66667, 242.0, 249.33333, 256.66666, 264.0, 271.33334,
1751                    ]);
1752                    node.set_character_widths([
1753                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1754                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1755                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1756                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1757                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1758                    ]);
1759                    node.set_word_starts([5, 15, 18, 23, 30, 33]);
1760                    node
1761                }),
1762                (NodeId(3), {
1763                    let mut node = Node::new(Role::TextRun);
1764                    node.set_bounds(Rect {
1765                        x0: 12.0,
1766                        y0: 48.33333206176758,
1767                        x1: 34.252257,
1768                        y1: 63.0,
1769                    });
1770                    node.set_value("to ");
1771                    node.set_character_lengths([1, 1, 1]);
1772                    node.set_character_positions([0.0, 7.3333435, 14.666687]);
1773                    node.set_character_widths([7.58557, 7.58557, 7.58557]);
1774                    node.set_word_starts([0]);
1775                    node.set_next_on_line(NodeId(4));
1776                    node
1777                }),
1778                (NodeId(4), {
1779                    let mut node = Node::new(Role::TextRun);
1780                    node.set_bounds(Rect {
1781                        x0: 34.0,
1782                        y0: 48.33333206176758,
1783                        x1: 85.58557,
1784                        y1: 63.0,
1785                    });
1786                    node.set_value("another");
1787                    node.set_character_lengths([1, 1, 1, 1, 1, 1, 1]);
1788                    node.set_character_positions([
1789                        0.0, 7.333344, 14.666687, 22.0, 29.333344, 36.666687, 44.0,
1790                    ]);
1791                    node.set_character_widths([
1792                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1793                    ]);
1794                    node.set_word_starts([0]);
1795                    node.set_underline(TEST_TEXT_DECORATION_1);
1796                    node.set_previous_on_line(NodeId(3));
1797                    node.set_next_on_line(NodeId(5));
1798                    node
1799                }),
1800                (NodeId(5), {
1801                    let mut node = Node::new(Role::TextRun);
1802                    node.set_bounds(Rect {
1803                        x0: 85.33334,
1804                        y0: 48.33333206176758,
1805                        x1: 129.5855712890625,
1806                        y1: 63.0,
1807                    });
1808                    node.set_value(" line.\n");
1809                    node.set_character_lengths([1, 1, 1, 1, 1, 1, 1]);
1810                    node.set_character_positions([
1811                        0.0, 7.333344, 14.666687, 22.0, 29.333344, 36.666687, 44.25226,
1812                    ]);
1813                    node.set_character_widths([
1814                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 0.0,
1815                    ]);
1816                    node.set_word_starts([1]);
1817                    node.set_previous_on_line(NodeId(4));
1818                    node
1819                }),
1820                (NodeId(6), {
1821                    let mut node = Node::new(Role::TextRun);
1822                    node.set_bounds(Rect {
1823                        x0: 12.0,
1824                        y0: 63.0,
1825                        x1: 144.25222778320313,
1826                        y1: 77.66666412353516,
1827                    });
1828                    node.set_value("Another paragraph.\n");
1829                    node.set_character_lengths([
1830                        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1831                    ]);
1832                    node.set_character_positions([
1833                        0.0, 7.3333335, 14.666667, 22.0, 29.333334, 36.666668, 44.0, 51.333332,
1834                        58.666668, 66.0, 73.333336, 80.666664, 88.0, 95.333336, 102.666664, 110.0,
1835                        117.333336, 124.666664, 132.25223,
1836                    ]);
1837                    node.set_character_widths([
1838                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1839                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1840                        7.58557, 7.58557, 0.0,
1841                    ]);
1842                    node.set_word_starts([8]);
1843                    node
1844                }),
1845                (NodeId(7), {
1846                    let mut node = Node::new(Role::TextRun);
1847                    node.set_bounds(Rect {
1848                        x0: 12.0,
1849                        y0: 77.66666412353516,
1850                        x1: 12.0,
1851                        y1: 92.33332824707031,
1852                    });
1853                    node.set_value("\n");
1854                    node.set_character_lengths([1]);
1855                    node.set_character_positions([0.0]);
1856                    node.set_character_widths([0.0]);
1857                    node
1858                }),
1859                (NodeId(8), {
1860                    let mut node = Node::new(Role::TextRun);
1861                    node.set_bounds(Rect {
1862                        x0: 12.0,
1863                        y0: 92.33332824707031,
1864                        x1: 158.9188995361328,
1865                        y1: 107.0,
1866                    });
1867                    // Use an arbitrary emoji consisting of two code points
1868                    // (combining characters), each of which encodes to two
1869                    // UTF-16 code units, to fully test conversion between
1870                    // UTF-8, UTF-16, and AccessKit character indices.
1871                    node.set_value("Last non-blank line\u{1f44d}\u{1f3fb}\n");
1872                    node.set_character_lengths([
1873                        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 1,
1874                    ]);
1875                    node.set_character_positions([
1876                        0.0, 7.3333335, 14.666667, 22.0, 29.333334, 36.666668, 44.0, 51.333332,
1877                        58.666668, 66.0, 73.333336, 80.666664, 88.0, 95.333336, 102.666664, 110.0,
1878                        117.333336, 124.666664, 132.0, 139.33333, 146.9189,
1879                    ]);
1880                    node.set_character_widths([
1881                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1882                        7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557, 7.58557,
1883                        7.58557, 7.58557, 7.58557, 7.58557, 0.0,
1884                    ]);
1885                    node.set_word_starts([5, 9, 15]);
1886                    node
1887                }),
1888                (NodeId(9), {
1889                    let mut node = Node::new(Role::TextRun);
1890                    node.set_bounds(Rect {
1891                        x0: 12.0,
1892                        y0: 107.0,
1893                        x1: 12.0,
1894                        y1: 121.66666412353516,
1895                    });
1896                    node.set_value("");
1897                    node.set_character_lengths([]);
1898                    node.set_character_positions([]);
1899                    node.set_character_widths([]);
1900                    node
1901                }),
1902            ],
1903            tree: Some(Tree::new(NodeId(0))),
1904            tree_id: TreeId::ROOT,
1905            focus: NodeId(1),
1906        };
1907
1908        crate::Tree::new(update, true)
1909    }
1910
1911    fn multiline_end_selection() -> TextSelection {
1912        use accesskit::TextPosition;
1913
1914        TextSelection {
1915            anchor: TextPosition {
1916                node: NodeId(9),
1917                character_index: 0,
1918            },
1919            focus: TextPosition {
1920                node: NodeId(9),
1921                character_index: 0,
1922            },
1923        }
1924    }
1925
1926    fn multiline_past_end_selection() -> TextSelection {
1927        use accesskit::TextPosition;
1928
1929        TextSelection {
1930            anchor: TextPosition {
1931                node: NodeId(9),
1932                character_index: 3,
1933            },
1934            focus: TextPosition {
1935                node: NodeId(9),
1936                character_index: 3,
1937            },
1938        }
1939    }
1940
1941    fn multiline_wrapped_line_end_selection() -> TextSelection {
1942        use accesskit::TextPosition;
1943
1944        TextSelection {
1945            anchor: TextPosition {
1946                node: NodeId(2),
1947                character_index: 38,
1948            },
1949            focus: TextPosition {
1950                node: NodeId(2),
1951                character_index: 38,
1952            },
1953        }
1954    }
1955
1956    fn multiline_first_line_middle_selection() -> TextSelection {
1957        use accesskit::TextPosition;
1958
1959        TextSelection {
1960            anchor: TextPosition {
1961                node: NodeId(2),
1962                character_index: 5,
1963            },
1964            focus: TextPosition {
1965                node: NodeId(2),
1966                character_index: 5,
1967            },
1968        }
1969    }
1970
1971    fn multiline_second_line_middle_selection() -> TextSelection {
1972        use accesskit::TextPosition;
1973
1974        TextSelection {
1975            anchor: TextPosition {
1976                node: NodeId(4),
1977                character_index: 3,
1978            },
1979            focus: TextPosition {
1980                node: NodeId(4),
1981                character_index: 3,
1982            },
1983        }
1984    }
1985
1986    #[test]
1987    fn supports_text_ranges() {
1988        let tree = main_multiline_tree(None);
1989        let state = tree.state();
1990        assert!(!state
1991            .node_by_id(nid(NodeId(0)))
1992            .unwrap()
1993            .supports_text_ranges());
1994        assert!(state
1995            .node_by_id(nid(NodeId(1)))
1996            .unwrap()
1997            .supports_text_ranges());
1998    }
1999
2000    #[test]
2001    fn multiline_document_range() {
2002        let tree = main_multiline_tree(None);
2003        let state = tree.state();
2004        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2005        let range = node.document_range();
2006        let start = range.start();
2007        assert!(start.is_word_start());
2008        assert!(start.is_line_start());
2009        assert!(!start.is_line_end());
2010        assert!(start.is_paragraph_start());
2011        assert!(start.is_document_start());
2012        assert!(!start.is_document_end());
2013        let end = range.end();
2014        assert!(start < end);
2015        assert!(end.is_word_start());
2016        assert!(end.is_line_start());
2017        assert!(end.is_line_end());
2018        assert!(end.is_paragraph_start());
2019        assert!(!end.is_document_start());
2020        assert!(end.is_document_end());
2021        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");
2022        assert_eq!(
2023            range.bounding_boxes(),
2024            vec![
2025                Rect {
2026                    x0: 18.0,
2027                    y0: 50.499996185302734,
2028                    x1: 436.3783721923828,
2029                    y1: 72.49999809265137
2030                },
2031                Rect {
2032                    x0: 18.0,
2033                    y0: 72.49999809265137,
2034                    x1: 51.3783855,
2035                    y1: 94.5
2036                },
2037                Rect {
2038                    x0: 51.0,
2039                    y0: 72.49999809265137,
2040                    x1: 128.378355,
2041                    y1: 94.5
2042                },
2043                Rect {
2044                    x0: 128.00001,
2045                    y0: 72.49999809265137,
2046                    x1: 194.37835693359375,
2047                    y1: 94.5
2048                },
2049                Rect {
2050                    x0: 18.0,
2051                    y0: 94.5,
2052                    x1: 216.3783416748047,
2053                    y1: 116.49999618530273
2054                },
2055                Rect {
2056                    x0: 18.0,
2057                    y0: 116.49999618530273,
2058                    x1: 18.0,
2059                    y1: 138.49999237060547
2060                },
2061                Rect {
2062                    x0: 18.0,
2063                    y0: 138.49999237060547,
2064                    x1: 238.37834930419922,
2065                    y1: 160.5
2066                }
2067            ]
2068        );
2069    }
2070
2071    #[test]
2072    fn multiline_document_range_to_first_format_change() {
2073        let tree = main_multiline_tree(None);
2074        let state = tree.state();
2075        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2076        let mut range = node.document_range();
2077        range.set_end(range.start().forward_to_format_end());
2078        assert_eq!(
2079            range.text(),
2080            "This paragraph is\u{a0}long enough to wrap to "
2081        );
2082        assert_eq!(
2083            range.bounding_boxes(),
2084            vec![
2085                Rect {
2086                    x0: 18.0,
2087                    y0: 50.499996185302734,
2088                    x1: 436.3783721923828,
2089                    y1: 72.49999809265137
2090                },
2091                Rect {
2092                    x0: 18.0,
2093                    y0: 72.49999809265137,
2094                    x1: 51.3783855,
2095                    y1: 94.5
2096                }
2097            ]
2098        );
2099    }
2100
2101    #[test]
2102    fn multiline_document_range_from_last_format_change() {
2103        let tree = main_multiline_tree(None);
2104        let state = tree.state();
2105        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2106        let mut range = node.document_range();
2107        range.set_start(range.end().backward_to_format_start());
2108        assert_eq!(
2109            range.text(),
2110            " line.\nAnother paragraph.\n\nLast non-blank line\u{1f44d}\u{1f3fb}\n"
2111        );
2112        assert_eq!(
2113            range.bounding_boxes(),
2114            vec![
2115                Rect {
2116                    x0: 128.00001,
2117                    y0: 72.49999809265137,
2118                    x1: 194.37835693359375,
2119                    y1: 94.5
2120                },
2121                Rect {
2122                    x0: 18.0,
2123                    y0: 94.5,
2124                    x1: 216.3783416748047,
2125                    y1: 116.49999618530273
2126                },
2127                Rect {
2128                    x0: 18.0,
2129                    y0: 116.49999618530273,
2130                    x1: 18.0,
2131                    y1: 138.49999237060547
2132                },
2133                Rect {
2134                    x0: 18.0,
2135                    y0: 138.49999237060547,
2136                    x1: 238.37834930419922,
2137                    y1: 160.5
2138                }
2139            ]
2140        );
2141    }
2142
2143    #[test]
2144    fn multiline_end_degenerate_range() {
2145        let tree = main_multiline_tree(Some(multiline_end_selection()));
2146        let state = tree.state();
2147        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2148        let range = node.text_selection().unwrap();
2149        assert!(range.is_degenerate());
2150        let pos = range.start();
2151        assert!(pos.is_word_start());
2152        assert!(pos.is_line_start());
2153        assert!(pos.is_line_end());
2154        assert!(pos.is_paragraph_start());
2155        assert!(!pos.is_document_start());
2156        assert!(pos.is_document_end());
2157        assert_eq!(range.text(), "");
2158        assert_eq!(
2159            range.bounding_boxes(),
2160            vec![Rect {
2161                x0: 18.0,
2162                y0: 160.5,
2163                x1: 18.0,
2164                y1: 182.49999618530273,
2165            }]
2166        );
2167    }
2168
2169    #[test]
2170    fn multiline_wrapped_line_end_range() {
2171        let tree = main_multiline_tree(Some(multiline_wrapped_line_end_selection()));
2172        let state = tree.state();
2173        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2174        let range = node.text_selection().unwrap();
2175        assert!(range.is_degenerate());
2176        let pos = range.start();
2177        assert!(!pos.is_word_start());
2178        assert!(!pos.is_line_start());
2179        assert!(pos.is_line_end());
2180        assert!(!pos.is_paragraph_start());
2181        assert!(!pos.is_document_start());
2182        assert!(!pos.is_document_end());
2183        assert_eq!(range.text(), "");
2184        assert_eq!(
2185            range.bounding_boxes(),
2186            vec![Rect {
2187                x0: 436.3783721923828,
2188                y0: 50.499996185302734,
2189                x1: 436.3783721923828,
2190                y1: 72.49999809265137
2191            }]
2192        );
2193        let char_end_pos = pos.forward_to_character_end();
2194        let mut line_start_range = range;
2195        line_start_range.set_end(char_end_pos);
2196        assert!(!line_start_range.is_degenerate());
2197        assert!(line_start_range.start().is_line_start());
2198        assert_eq!(line_start_range.text(), "t");
2199        assert_eq!(
2200            line_start_range.bounding_boxes(),
2201            vec![Rect {
2202                x0: 18.0,
2203                y0: 72.49999809265137,
2204                x1: 29.378354787826538,
2205                y1: 94.5
2206            }]
2207        );
2208        let prev_char_pos = pos.backward_to_character_start();
2209        let mut prev_char_range = range;
2210        prev_char_range.set_start(prev_char_pos);
2211        assert!(!prev_char_range.is_degenerate());
2212        assert!(prev_char_range.end().is_line_end());
2213        assert_eq!(prev_char_range.text(), " ");
2214        assert_eq!(
2215            prev_char_range.bounding_boxes(),
2216            vec![Rect {
2217                x0: 425.00001525878906,
2218                y0: 50.499996185302734,
2219                x1: 436.3783721923828,
2220                y1: 72.49999809265137
2221            }]
2222        );
2223        assert!(prev_char_pos.forward_to_character_end().is_line_end());
2224        assert!(prev_char_pos.forward_to_word_end().is_line_end());
2225        assert!(prev_char_pos.forward_to_line_end().is_line_end());
2226        assert!(prev_char_pos.forward_to_character_start().is_line_start());
2227        assert!(prev_char_pos.forward_to_word_start().is_line_start());
2228        assert!(prev_char_pos.forward_to_line_start().is_line_start());
2229    }
2230
2231    #[test]
2232    fn multiline_find_line_ends_from_middle() {
2233        let tree = main_multiline_tree(Some(multiline_second_line_middle_selection()));
2234        let state = tree.state();
2235        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2236        let mut range = node.text_selection().unwrap();
2237        assert!(range.is_degenerate());
2238        let pos = range.start();
2239        assert!(!pos.is_line_start());
2240        assert!(!pos.is_line_end());
2241        assert!(!pos.is_document_start());
2242        assert!(!pos.is_document_end());
2243        let line_start = pos.backward_to_line_start();
2244        range.set_start(line_start);
2245        let line_end = line_start.forward_to_line_end();
2246        range.set_end(line_end);
2247        assert!(!range.is_degenerate());
2248        assert!(range.start().is_line_start());
2249        assert!(range.end().is_line_end());
2250        assert_eq!(range.text(), "to another line.\n");
2251        assert_eq!(
2252            range.bounding_boxes(),
2253            vec![
2254                Rect {
2255                    x0: 18.0,
2256                    y0: 72.49999809265137,
2257                    x1: 51.3783855,
2258                    y1: 94.5
2259                },
2260                Rect {
2261                    x0: 51.0,
2262                    y0: 72.49999809265137,
2263                    x1: 128.378355,
2264                    y1: 94.5
2265                },
2266                Rect {
2267                    x0: 128.00001,
2268                    y0: 72.49999809265137,
2269                    x1: 194.37835693359375,
2270                    y1: 94.5
2271                },
2272            ]
2273        );
2274        assert!(line_start.forward_to_line_start().is_line_start());
2275    }
2276
2277    #[test]
2278    fn multiline_find_wrapped_line_ends_from_middle() {
2279        let tree = main_multiline_tree(Some(multiline_first_line_middle_selection()));
2280        let state = tree.state();
2281        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2282        let mut range = node.text_selection().unwrap();
2283        assert!(range.is_degenerate());
2284        let pos = range.start();
2285        assert!(!pos.is_line_start());
2286        assert!(!pos.is_line_end());
2287        assert!(!pos.is_document_start());
2288        assert!(!pos.is_document_end());
2289        let line_start = pos.backward_to_line_start();
2290        range.set_start(line_start);
2291        let line_end = line_start.forward_to_line_end();
2292        range.set_end(line_end);
2293        assert!(!range.is_degenerate());
2294        assert!(range.start().is_line_start());
2295        assert!(range.end().is_line_end());
2296        assert_eq!(range.text(), "This paragraph is\u{a0}long enough to wrap ");
2297        assert_eq!(
2298            range.bounding_boxes(),
2299            vec![Rect {
2300                x0: 18.0,
2301                y0: 50.499996185302734,
2302                x1: 436.3783721923828,
2303                y1: 72.49999809265137
2304            }]
2305        );
2306        assert!(line_start.forward_to_line_start().is_line_start());
2307    }
2308
2309    #[test]
2310    fn multiline_find_paragraph_ends_from_middle() {
2311        let tree = main_multiline_tree(Some(multiline_second_line_middle_selection()));
2312        let state = tree.state();
2313        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2314        let mut range = node.text_selection().unwrap();
2315        assert!(range.is_degenerate());
2316        let pos = range.start();
2317        assert!(!pos.is_paragraph_start());
2318        assert!(!pos.is_document_start());
2319        assert!(!pos.is_document_end());
2320        let paragraph_start = pos.backward_to_paragraph_start();
2321        range.set_start(paragraph_start);
2322        let paragraph_end = paragraph_start.forward_to_paragraph_end();
2323        range.set_end(paragraph_end);
2324        assert!(!range.is_degenerate());
2325        assert!(range.start().is_paragraph_start());
2326        assert!(range.end().is_paragraph_end());
2327        assert_eq!(
2328            range.text(),
2329            "This paragraph is\u{a0}long enough to wrap to another line.\n"
2330        );
2331        assert_eq!(
2332            range.bounding_boxes(),
2333            vec![
2334                Rect {
2335                    x0: 18.0,
2336                    y0: 50.499996185302734,
2337                    x1: 436.3783721923828,
2338                    y1: 72.49999809265137
2339                },
2340                Rect {
2341                    x0: 18.0,
2342                    y0: 72.49999809265137,
2343                    x1: 51.3783855,
2344                    y1: 94.5
2345                },
2346                Rect {
2347                    x0: 51.0,
2348                    y0: 72.49999809265137,
2349                    x1: 128.378355,
2350                    y1: 94.5
2351                },
2352                Rect {
2353                    x0: 128.00001,
2354                    y0: 72.49999809265137,
2355                    x1: 194.37835693359375,
2356                    y1: 94.5
2357                },
2358            ]
2359        );
2360        assert!(paragraph_start
2361            .forward_to_paragraph_start()
2362            .is_paragraph_start());
2363    }
2364
2365    #[test]
2366    fn multiline_find_format_ends_from_middle() {
2367        let tree = main_multiline_tree(Some(multiline_second_line_middle_selection()));
2368        let state = tree.state();
2369        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2370        let mut range = node.text_selection().unwrap();
2371        assert!(range.is_degenerate());
2372        let pos = range.start();
2373        assert!(!pos.is_format_start());
2374        assert!(!pos.is_document_start());
2375        assert!(!pos.is_document_end());
2376        let format_start = pos.backward_to_format_start();
2377        range.set_start(format_start);
2378        let format_end = pos.forward_to_format_end();
2379        range.set_end(format_end);
2380        assert!(!range.is_degenerate());
2381        assert_eq!(range.text(), "another");
2382        assert_eq!(
2383            range.bounding_boxes(),
2384            vec![Rect {
2385                x0: 51.0,
2386                y0: 72.49999809265137,
2387                x1: 128.378355,
2388                y1: 94.5
2389            }]
2390        );
2391    }
2392
2393    #[test]
2394    fn multiline_find_word_ends_from_middle() {
2395        let tree = main_multiline_tree(Some(multiline_second_line_middle_selection()));
2396        let state = tree.state();
2397        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2398        let mut range = node.text_selection().unwrap();
2399        assert!(range.is_degenerate());
2400        let pos = range.start();
2401        assert!(!pos.is_word_start());
2402        assert!(!pos.is_document_start());
2403        assert!(!pos.is_document_end());
2404        let word_start = pos.backward_to_word_start();
2405        range.set_start(word_start);
2406        let word_end = word_start.forward_to_word_end();
2407        let word_end2 = pos.forward_to_word_end();
2408        assert_eq!(word_end, word_end2);
2409        let word_start2 = word_end.backward_to_word_start();
2410        assert_eq!(word_start, word_start2);
2411        range.set_end(word_end);
2412        assert!(!range.is_degenerate());
2413        assert_eq!(range.text(), "another ");
2414        assert_eq!(
2415            range.bounding_boxes(),
2416            [
2417                Rect {
2418                    x0: 51.0,
2419                    y0: 72.49999809265137,
2420                    x1: 128.378355,
2421                    y1: 94.5
2422                },
2423                Rect {
2424                    x0: 128.00001,
2425                    y0: 72.49999809265137,
2426                    x1: 139.37836478782654,
2427                    y1: 94.5
2428                }
2429            ]
2430        );
2431    }
2432
2433    #[test]
2434    fn text_position_at_point() {
2435        let tree = main_multiline_tree(None);
2436        let state = tree.state();
2437        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2438
2439        {
2440            let pos = node.text_position_at_point(Point::new(8.0, 31.666664123535156));
2441            assert!(pos.is_document_start());
2442        }
2443
2444        {
2445            let pos = node.text_position_at_point(Point::new(12.0, 33.666664123535156));
2446            assert!(pos.is_document_start());
2447        }
2448
2449        {
2450            let pos = node.text_position_at_point(Point::new(16.0, 40.0));
2451            assert!(pos.is_document_start());
2452        }
2453
2454        {
2455            let pos = node.text_position_at_point(Point::new(144.0, 40.0));
2456            assert!(!pos.is_document_start());
2457            assert!(!pos.is_document_end());
2458            assert!(!pos.is_line_end());
2459            let mut range = pos.to_degenerate_range();
2460            range.set_end(pos.forward_to_character_end());
2461            assert_eq!(range.text(), "l");
2462        }
2463
2464        {
2465            let pos = node.text_position_at_point(Point::new(150.0, 40.0));
2466            assert!(!pos.is_document_start());
2467            assert!(!pos.is_document_end());
2468            assert!(!pos.is_line_end());
2469            let mut range = pos.to_degenerate_range();
2470            range.set_end(pos.forward_to_character_end());
2471            assert_eq!(range.text(), "l");
2472        }
2473
2474        {
2475            let pos = node.text_position_at_point(Point::new(291.0, 40.0));
2476            assert!(!pos.is_document_start());
2477            assert!(!pos.is_document_end());
2478            assert!(pos.is_line_end());
2479            let mut range = pos.to_degenerate_range();
2480            range.set_start(pos.backward_to_word_start());
2481            assert_eq!(range.text(), "wrap ");
2482        }
2483
2484        {
2485            let pos = node.text_position_at_point(Point::new(12.0, 50.0));
2486            assert!(!pos.is_document_start());
2487            assert!(pos.is_line_start());
2488            assert!(!pos.is_paragraph_start());
2489            let mut range = pos.to_degenerate_range();
2490            range.set_end(pos.forward_to_word_end());
2491            assert_eq!(range.text(), "to ");
2492        }
2493
2494        {
2495            let pos = node.text_position_at_point(Point::new(130.0, 50.0));
2496            assert!(!pos.is_document_start());
2497            assert!(!pos.is_document_end());
2498            assert!(pos.is_line_end());
2499            let mut range = pos.to_degenerate_range();
2500            range.set_start(pos.backward_to_word_start());
2501            assert_eq!(range.text(), "line.\n");
2502        }
2503
2504        {
2505            let pos = node.text_position_at_point(Point::new(12.0, 80.0));
2506            assert!(!pos.is_document_start());
2507            assert!(!pos.is_document_end());
2508            assert!(pos.is_line_end());
2509            let mut range = pos.to_degenerate_range();
2510            range.set_start(pos.backward_to_line_start());
2511            assert_eq!(range.text(), "\n");
2512        }
2513
2514        {
2515            let pos = node.text_position_at_point(Point::new(12.0, 120.0));
2516            assert!(pos.is_document_end());
2517        }
2518
2519        {
2520            let pos = node.text_position_at_point(Point::new(250.0, 122.0));
2521            assert!(pos.is_document_end());
2522        }
2523    }
2524
2525    #[test]
2526    fn to_global_usv_index() {
2527        let tree = main_multiline_tree(None);
2528        let state = tree.state();
2529        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2530
2531        {
2532            let range = node.document_range();
2533            assert_eq!(range.start().to_global_usv_index(), 0);
2534            assert_eq!(range.end().to_global_usv_index(), 97);
2535        }
2536
2537        {
2538            let range = node.document_range();
2539            let pos = range.start().forward_to_line_end();
2540            assert_eq!(pos.to_global_usv_index(), 38);
2541            let pos = range.start().forward_to_line_start();
2542            assert_eq!(pos.to_global_usv_index(), 38);
2543            let pos = pos.forward_to_character_start();
2544            assert_eq!(pos.to_global_usv_index(), 39);
2545            let pos = pos.forward_to_line_start();
2546            assert_eq!(pos.to_global_usv_index(), 55);
2547        }
2548    }
2549
2550    #[test]
2551    fn to_global_utf16_index() {
2552        let tree = main_multiline_tree(None);
2553        let state = tree.state();
2554        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2555
2556        {
2557            let range = node.document_range();
2558            assert_eq!(range.start().to_global_utf16_index(), 0);
2559            assert_eq!(range.end().to_global_utf16_index(), 99);
2560        }
2561
2562        {
2563            let range = node.document_range();
2564            let pos = range.start().forward_to_line_end();
2565            assert_eq!(pos.to_global_utf16_index(), 38);
2566            let pos = range.start().forward_to_line_start();
2567            assert_eq!(pos.to_global_utf16_index(), 38);
2568            let pos = pos.forward_to_character_start();
2569            assert_eq!(pos.to_global_utf16_index(), 39);
2570            let pos = pos.forward_to_line_start();
2571            assert_eq!(pos.to_global_utf16_index(), 55);
2572        }
2573    }
2574
2575    #[test]
2576    fn to_line_index() {
2577        let tree = main_multiline_tree(None);
2578        let state = tree.state();
2579        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2580
2581        {
2582            let range = node.document_range();
2583            assert_eq!(range.start().to_line_index(), 0);
2584            assert_eq!(range.end().to_line_index(), 5);
2585        }
2586
2587        {
2588            let range = node.document_range();
2589            let pos = range.start().forward_to_line_end();
2590            assert_eq!(pos.to_line_index(), 0);
2591            let pos = range.start().forward_to_line_start();
2592            assert_eq!(pos.to_line_index(), 1);
2593            let pos = pos.forward_to_character_start();
2594            assert_eq!(pos.to_line_index(), 1);
2595            assert_eq!(pos.forward_to_line_end().to_line_index(), 1);
2596            let pos = pos.forward_to_line_start();
2597            assert_eq!(pos.to_line_index(), 2);
2598        }
2599    }
2600
2601    #[test]
2602    fn line_range_from_index() {
2603        let tree = main_multiline_tree(None);
2604        let state = tree.state();
2605        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2606
2607        {
2608            let range = node.line_range_from_index(0).unwrap();
2609            assert_eq!(range.text(), "This paragraph is\u{a0}long enough to wrap ");
2610        }
2611
2612        {
2613            let range = node.line_range_from_index(1).unwrap();
2614            assert_eq!(range.text(), "to another line.\n");
2615        }
2616
2617        {
2618            let range = node.line_range_from_index(2).unwrap();
2619            assert_eq!(range.text(), "Another paragraph.\n");
2620        }
2621
2622        {
2623            let range = node.line_range_from_index(3).unwrap();
2624            assert_eq!(range.text(), "\n");
2625        }
2626
2627        {
2628            let range = node.line_range_from_index(4).unwrap();
2629            assert_eq!(range.text(), "Last non-blank line\u{1f44d}\u{1f3fb}\n");
2630        }
2631
2632        {
2633            let range = node.line_range_from_index(5).unwrap();
2634            assert_eq!(range.text(), "");
2635        }
2636
2637        assert!(node.line_range_from_index(6).is_none());
2638    }
2639
2640    #[test]
2641    fn text_position_from_global_usv_index() {
2642        let tree = main_multiline_tree(None);
2643        let state = tree.state();
2644        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2645
2646        {
2647            let pos = node.text_position_from_global_usv_index(0).unwrap();
2648            assert!(pos.is_document_start());
2649        }
2650
2651        {
2652            let pos = node.text_position_from_global_usv_index(17).unwrap();
2653            let mut range = pos.to_degenerate_range();
2654            range.set_end(pos.forward_to_character_end());
2655            assert_eq!(range.text(), "\u{a0}");
2656        }
2657
2658        {
2659            let pos = node.text_position_from_global_usv_index(18).unwrap();
2660            let mut range = pos.to_degenerate_range();
2661            range.set_end(pos.forward_to_character_end());
2662            assert_eq!(range.text(), "l");
2663        }
2664
2665        {
2666            let pos = node.text_position_from_global_usv_index(37).unwrap();
2667            let mut range = pos.to_degenerate_range();
2668            range.set_end(pos.forward_to_character_end());
2669            assert_eq!(range.text(), " ");
2670        }
2671
2672        {
2673            let pos = node.text_position_from_global_usv_index(38).unwrap();
2674            assert!(!pos.is_paragraph_start());
2675            assert!(pos.is_line_start());
2676            let mut range = pos.to_degenerate_range();
2677            range.set_end(pos.forward_to_character_end());
2678            assert_eq!(range.text(), "t");
2679        }
2680
2681        {
2682            let pos = node.text_position_from_global_usv_index(54).unwrap();
2683            let mut range = pos.to_degenerate_range();
2684            range.set_end(pos.forward_to_character_end());
2685            assert_eq!(range.text(), "\n");
2686        }
2687
2688        {
2689            let pos = node.text_position_from_global_usv_index(55).unwrap();
2690            assert!(pos.is_paragraph_start());
2691            assert!(pos.is_line_start());
2692            let mut range = pos.to_degenerate_range();
2693            range.set_end(pos.forward_to_character_end());
2694            assert_eq!(range.text(), "A");
2695        }
2696
2697        for i in 94..=95 {
2698            let pos = node.text_position_from_global_usv_index(i).unwrap();
2699            let mut range = pos.to_degenerate_range();
2700            range.set_end(pos.forward_to_character_end());
2701            assert_eq!(range.text(), "\u{1f44d}\u{1f3fb}");
2702        }
2703
2704        {
2705            let pos = node.text_position_from_global_usv_index(96).unwrap();
2706            let mut range = pos.to_degenerate_range();
2707            range.set_end(pos.forward_to_character_end());
2708            assert_eq!(range.text(), "\n");
2709        }
2710
2711        {
2712            let pos = node.text_position_from_global_usv_index(97).unwrap();
2713            assert!(pos.is_document_end());
2714        }
2715
2716        assert!(node.text_position_from_global_usv_index(98).is_none());
2717    }
2718
2719    #[test]
2720    fn text_position_from_global_utf16_index() {
2721        let tree = main_multiline_tree(None);
2722        let state = tree.state();
2723        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2724
2725        {
2726            let pos = node.text_position_from_global_utf16_index(0).unwrap();
2727            assert!(pos.is_document_start());
2728        }
2729
2730        {
2731            let pos = node.text_position_from_global_utf16_index(17).unwrap();
2732            let mut range = pos.to_degenerate_range();
2733            range.set_end(pos.forward_to_character_end());
2734            assert_eq!(range.text(), "\u{a0}");
2735        }
2736
2737        {
2738            let pos = node.text_position_from_global_utf16_index(18).unwrap();
2739            let mut range = pos.to_degenerate_range();
2740            range.set_end(pos.forward_to_character_end());
2741            assert_eq!(range.text(), "l");
2742        }
2743
2744        {
2745            let pos = node.text_position_from_global_utf16_index(37).unwrap();
2746            let mut range = pos.to_degenerate_range();
2747            range.set_end(pos.forward_to_character_end());
2748            assert_eq!(range.text(), " ");
2749        }
2750
2751        {
2752            let pos = node.text_position_from_global_utf16_index(38).unwrap();
2753            assert!(!pos.is_paragraph_start());
2754            assert!(pos.is_line_start());
2755            let mut range = pos.to_degenerate_range();
2756            range.set_end(pos.forward_to_character_end());
2757            assert_eq!(range.text(), "t");
2758        }
2759
2760        {
2761            let pos = node.text_position_from_global_utf16_index(54).unwrap();
2762            let mut range = pos.to_degenerate_range();
2763            range.set_end(pos.forward_to_character_end());
2764            assert_eq!(range.text(), "\n");
2765        }
2766
2767        {
2768            let pos = node.text_position_from_global_utf16_index(55).unwrap();
2769            assert!(pos.is_paragraph_start());
2770            assert!(pos.is_line_start());
2771            let mut range = pos.to_degenerate_range();
2772            range.set_end(pos.forward_to_character_end());
2773            assert_eq!(range.text(), "A");
2774        }
2775
2776        for i in 94..=97 {
2777            let pos = node.text_position_from_global_utf16_index(i).unwrap();
2778            let mut range = pos.to_degenerate_range();
2779            range.set_end(pos.forward_to_character_end());
2780            assert_eq!(range.text(), "\u{1f44d}\u{1f3fb}");
2781        }
2782
2783        {
2784            let pos = node.text_position_from_global_utf16_index(98).unwrap();
2785            let mut range = pos.to_degenerate_range();
2786            range.set_end(pos.forward_to_character_end());
2787            assert_eq!(range.text(), "\n");
2788        }
2789
2790        {
2791            let pos = node.text_position_from_global_utf16_index(99).unwrap();
2792            assert!(pos.is_document_end());
2793        }
2794
2795        assert!(node.text_position_from_global_utf16_index(100).is_none());
2796    }
2797
2798    #[test]
2799    fn multiline_selection_clamping() {
2800        let tree = main_multiline_tree(Some(multiline_past_end_selection()));
2801        let state = tree.state();
2802        let node = state.node_by_id(nid(NodeId(1))).unwrap();
2803        let _ = node.text_selection().unwrap();
2804    }
2805
2806    #[test]
2807    fn range_property_value_map() {
2808        use super::RangePropertyValue;
2809        assert_eq!(
2810            RangePropertyValue::Single(Some(0)).map(|x| x + 1),
2811            RangePropertyValue::Single(Some(1))
2812        );
2813        assert_eq!(
2814            RangePropertyValue::<Option<usize>>::Single(None).map(|x| x + 1),
2815            RangePropertyValue::Single(None)
2816        );
2817        assert_eq!(
2818            RangePropertyValue::<Option<usize>>::Mixed.map(|x| x + 1),
2819            RangePropertyValue::Mixed
2820        );
2821    }
2822}