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#[test]
58fn test_linebreaker_ranges() {
59 let linebreaker = LineBreaker::new("abc def");
60 assert_eq!(linebreaker.linebreaks, [4, 7]);
61 assert_eq!(
62 linebreaker.linebreaks_in_range_after_current_offset(0..5),
63 0..1
64 );
65 assert_eq!(
67 linebreaker.linebreaks_in_range_after_current_offset(0..7),
68 0..1
69 );
70
71 let linebreaker = LineBreaker::new("abc d def");
72 assert_eq!(linebreaker.linebreaks, [4, 6, 9]);
73 assert_eq!(
74 linebreaker.linebreaks_in_range_after_current_offset(0..5),
75 0..1
76 );
77 assert_eq!(
78 linebreaker.linebreaks_in_range_after_current_offset(0..7),
79 0..2
80 );
81 assert_eq!(
82 linebreaker.linebreaks_in_range_after_current_offset(0..9),
83 0..2
84 );
85
86 assert_eq!(
87 linebreaker.linebreaks_in_range_after_current_offset(4..9),
88 0..2
89 );
90
91 std::panic::catch_unwind(|| {
92 let linebreaker = LineBreaker::new("abc def");
93 linebreaker.linebreaks_in_range_after_current_offset(5..2);
94 })
95 .expect_err("Reversed range should cause an assertion failure.");
96}
97
98#[test]
99fn test_linebreaker_stateful_advance() {
100 let mut linebreaker = LineBreaker::new("abc d def");
101 assert_eq!(linebreaker.linebreaks, [4, 6, 9]);
102 assert!(linebreaker.advance_to_linebreaks_in_range(0..7) == &[4, 6]);
103 assert!(linebreaker.advance_to_linebreaks_in_range(8..9).is_empty());
104
105 assert!(linebreaker.advance_to_linebreaks_in_range(0..9).is_empty());
107
108 linebreaker.current_offset = 0;
109
110 assert!(linebreaker.advance_to_linebreaks_in_range(0..999) == &[4, 6]);
112
113 linebreaker.current_offset = 0;
114
115 std::panic::catch_unwind(|| {
116 let mut linebreaker = LineBreaker::new("abc d def");
117 linebreaker.advance_to_linebreaks_in_range(2..0);
118 })
119 .expect_err("Reversed range should cause an assertion failure.");
120}