@@ -10,7 +10,7 @@ use crate::{flow::{Char, Rect, Word}, util::avg};
10
10
pub fn concat_text < ' a , E : Encoder + ' a > ( out : & mut String , items : impl Iterator < Item =& ' a TextSpan < E > > + Clone ) -> Vec < Word > {
11
11
let word_gap = analyze_word_gap ( items. clone ( ) ) ;
12
12
let mut words = Vec :: new ( ) ;
13
- let mut current_word = WordBuilder :: new ( out. len ( ) ) ;
13
+ let mut current_word = WordBuilder :: new ( out. len ( ) , 0.0 ) ;
14
14
15
15
// Whether the last processed TextChar is a whitespace
16
16
// ' ' Space
@@ -20,6 +20,8 @@ pub fn concat_text<'a, E: Encoder + 'a>(out: &mut String, items: impl Iterator<I
20
20
// '\u{00A0}' Non-breaking space
21
21
let mut trailing_space = out. chars ( ) . last ( ) . map_or ( true , |c| c. is_whitespace ( ) ) ;
22
22
23
+ let mut end = 0. ; // trailing edge of the last char
24
+
23
25
for span in items {
24
26
let mut offset = 0 ;
25
27
let tr_inv = span. transform . matrix . inverse ( ) ;
@@ -42,27 +44,29 @@ pub fn concat_text<'a, E: Encoder + 'a>(out: &mut String, items: impl Iterator<I
42
44
43
45
let is_whitespace = text. chars ( ) . all ( |c| c. is_whitespace ( ) ) ;
44
46
45
- // byte offset
47
+ // byte offsets
46
48
let offset_increment = text. len ( ) ;
47
49
// Handle word boundaries
48
50
if trailing_space && !is_whitespace {
49
51
// Start new word after space
50
- current_word. start_new ( out. len ( ) , char_start) ;
52
+ current_word = WordBuilder :: new ( out. len ( ) , char_start) ;
51
53
current_word. add_char ( 0 , offset_increment, char_start, char_end) ;
54
+
52
55
out. extend ( text. nfkc ( ) ) ;
53
56
} else if !trailing_space {
54
57
if is_whitespace {
55
58
// End word at space
56
- words. push ( current_word. build ( out, char_end) ) ;
57
- current_word = WordBuilder :: new ( out. len ( ) ) ;
59
+ words. push ( current_word. build ( out) ) ;
60
+
61
+ current_word = WordBuilder :: new ( out. len ( ) , char_start) ;
58
62
out. push ( ' ' ) ;
59
- } else if current. pos + x_off > current_word . end_pos + word_gap {
63
+ } else if current. pos + x_off > end + word_gap {
60
64
// End word at large gap
61
- words. push ( current_word. build ( out, char_end ) ) ;
65
+ words. push ( current_word. build ( out) ) ;
62
66
63
- current_word = WordBuilder :: new ( out. len ( ) ) ;
64
- current_word. start_new ( out. len ( ) , char_start) ;
67
+ current_word = WordBuilder :: new ( out. len ( ) , char_start) ;
65
68
current_word. add_char ( 0 , offset_increment, char_start, char_end) ;
69
+
66
70
out. extend ( text. nfkc ( ) ) ;
67
71
} else {
68
72
// Continue current word
@@ -71,16 +75,17 @@ pub fn concat_text<'a, E: Encoder + 'a>(out: &mut String, items: impl Iterator<I
71
75
out. extend ( text. nfkc ( ) ) ;
72
76
}
73
77
}
74
-
75
78
trailing_space = is_whitespace;
79
+
80
+ end = current. pos + x_off + current. width ;
81
+
76
82
current_word. update_bounds ( span. rect . min_y ( ) , span. rect . max_y ( ) ) ;
77
83
}
78
84
}
79
85
80
86
// Add final word if any
81
87
if !current_word. is_empty ( ) {
82
- let end_pos = current_word. end_pos ;
83
- words. push ( current_word. build ( out, end_pos) ) ;
88
+ words. push ( current_word. build ( out) ) ;
84
89
}
85
90
86
91
words
@@ -102,40 +107,36 @@ struct WordBuilder {
102
107
}
103
108
104
109
impl WordBuilder {
105
- fn new ( word_start_idx : usize ) -> Self {
110
+ fn new ( word_start_idx : usize , start_pos : f32 ) -> Self {
106
111
Self {
107
112
word_start_idx,
108
- start_pos : 0.0 ,
113
+ start_pos,
109
114
end_pos : 0.0 ,
110
115
y_min : f32:: INFINITY ,
111
116
y_max : -f32:: INFINITY ,
112
117
chars : Vec :: new ( ) ,
113
118
byte_offset : 0 ,
114
- started : false ,
119
+ started : true ,
115
120
}
116
121
}
117
122
118
- fn start_new ( & mut self , word_start_idx : usize , start_pos : f32 ) {
119
- self . word_start_idx = word_start_idx;
120
- self . start_pos = start_pos;
121
- self . started = true ;
122
- }
123
-
124
123
fn add_char ( & mut self , offset : usize , offset_increment : usize , start : f32 , end : f32 ) {
125
124
self . chars . push ( Char {
126
125
offset,
127
126
pos : start,
128
127
width : end - start,
129
128
} ) ;
130
129
self . end_pos = end;
130
+
131
131
self . byte_offset += offset_increment;
132
132
}
133
133
134
134
fn update_bounds ( & mut self , min_y : f32 , max_y : f32 ) {
135
- if ! self . started {
135
+ if self . started {
136
136
self . y_min = min_y;
137
137
self . y_max = max_y;
138
- self . started = true ;
138
+
139
+ self . started = false ;
139
140
} else {
140
141
self . y_min = self . y_min . min ( min_y) ;
141
142
self . y_max = self . y_max . max ( max_y) ;
@@ -146,23 +147,23 @@ impl WordBuilder {
146
147
self . chars . is_empty ( )
147
148
}
148
149
149
- fn build ( mut self , out : & str , end_pos : f32 ) -> Word {
150
+ fn build ( mut self , out : & str ) -> Word {
150
151
Word {
151
152
text : out[ self . word_start_idx ..] . into ( ) ,
152
153
rect : Rect {
153
154
x : self . start_pos ,
154
155
y : self . y_min ,
155
156
h : self . y_max - self . y_min ,
156
- w : end_pos - self . start_pos
157
+ w : self . end_pos - self . start_pos
157
158
} ,
158
159
chars : take ( & mut self . chars )
159
160
}
160
161
}
161
162
}
162
163
163
- /// Calculate gaps between each char,
164
+ /// Calculate gaps between each char, the return value unit is em
165
+
164
166
/// The most important thing here is to make sure the gap is bigger than char gap, and less than word gap.
165
- ///
166
167
/// for example:
167
168
/// think of something like "ab____________c de"
168
169
///
@@ -186,7 +187,7 @@ fn analyze_word_gap<'a, E: Encoder + 'a>(items: impl Iterator<Item=&'a TextSpan<
186
187
let gaps = items. clone ( )
187
188
. flat_map ( |s| {
188
189
// the transform matrix is from em space to device space
189
- // so we need to invert it
190
+ // so we need to invert it, becoming device space to em space
190
191
let tr_inv = s. transform . matrix . inverse ( ) ;
191
192
let pos = ( tr_inv * s. transform . vector ) . x ( ) ;
192
193
0 commit comments