layout/flow/inline/
line_breaker.rs1use std::ops::Range;
6
7use icu_segmenter::LineSegmenter;
8
9pub(crate) struct LineBreaker {
10 linebreaks: Vec<usize>,
11 current_offset: usize,
12}
13
14impl LineBreaker {
15 pub(crate) fn new(string: &str) -> Self {
16 let line_segmenter = LineSegmenter::new_auto();
17 Self {
18 linebreaks: line_segmenter.segment_str(string).skip(1).collect(),
25 current_offset: 0,
26 }
27 }
28
29 pub(crate) fn advance_to_linebreaks_in_range(&mut self, text_range: Range<usize>) -> &[usize] {
30 let linebreaks_in_range = self.linebreaks_in_range_after_current_offset(text_range);
31 self.current_offset = linebreaks_in_range.end;
32 &self.linebreaks[linebreaks_in_range]
33 }
34
35 fn linebreaks_in_range_after_current_offset(&self, text_range: Range<usize>) -> Range<usize> {
36 assert!(text_range.start <= text_range.end);
37
38 let mut linebreaks_range = self.current_offset..self.linebreaks.len();
39
40 while self.linebreaks[linebreaks_range.start] < text_range.start &&
41 linebreaks_range.len() > 1
42 {
43 linebreaks_range.start += 1;
44 }
45
46 let mut ending_linebreak_index = linebreaks_range.start;
47 while self.linebreaks[ending_linebreak_index] < text_range.end &&
48 ending_linebreak_index < self.linebreaks.len() - 1
49 {
50 ending_linebreak_index += 1;
51 }
52 linebreaks_range.end = ending_linebreak_index;
53 linebreaks_range
54 }
55}
56
57#[cfg(test)]
58mod test {
59 use super::*;
60
61 #[test]
62 fn test_linebreaker_ranges() {
63 let linebreaker = LineBreaker::new("abc def");
64 assert_eq!(linebreaker.linebreaks, [4, 7]);
65 assert_eq!(
66 linebreaker.linebreaks_in_range_after_current_offset(0..5),
67 0..1
68 );
69 assert_eq!(
71 linebreaker.linebreaks_in_range_after_current_offset(0..7),
72 0..1
73 );
74
75 let linebreaker = LineBreaker::new("abc d def");
76 assert_eq!(linebreaker.linebreaks, [4, 6, 9]);
77 assert_eq!(
78 linebreaker.linebreaks_in_range_after_current_offset(0..5),
79 0..1
80 );
81 assert_eq!(
82 linebreaker.linebreaks_in_range_after_current_offset(0..7),
83 0..2
84 );
85 assert_eq!(
86 linebreaker.linebreaks_in_range_after_current_offset(0..9),
87 0..2
88 );
89
90 assert_eq!(
91 linebreaker.linebreaks_in_range_after_current_offset(4..9),
92 0..2
93 );
94
95 std::panic::catch_unwind(|| {
96 let linebreaker = LineBreaker::new("abc def");
97 linebreaker.linebreaks_in_range_after_current_offset(5..2);
98 })
99 .expect_err("Reversed range should cause an assertion failure.");
100 }
101
102 #[test]
103 fn test_linebreaker_stateful_advance() {
104 let mut linebreaker = LineBreaker::new("abc d def");
105 assert_eq!(linebreaker.linebreaks, [4, 6, 9]);
106 assert!(linebreaker.advance_to_linebreaks_in_range(0..7) == &[4, 6]);
107 assert!(linebreaker.advance_to_linebreaks_in_range(8..9).is_empty());
108
109 assert!(linebreaker.advance_to_linebreaks_in_range(0..9).is_empty());
111
112 linebreaker.current_offset = 0;
113
114 assert!(linebreaker.advance_to_linebreaks_in_range(0..999) == &[4, 6]);
116
117 linebreaker.current_offset = 0;
118
119 std::panic::catch_unwind(|| {
120 let mut linebreaker = LineBreaker::new("abc d def");
121 linebreaker.advance_to_linebreaks_in_range(2..0);
122 })
123 .expect_err("Reversed range should cause an assertion failure.");
124 }
125}