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