1
- use crate :: vector:: PointId ;
1
+ use crate :: instances:: Instance ;
2
+ use crate :: vector:: { PointId , VectorData , VectorDataTable } ;
2
3
use bezier_rs:: { ManipulatorGroup , Subpath } ;
3
4
use core:: cell:: RefCell ;
4
5
use glam:: { DAffine2 , DVec2 } ;
@@ -20,24 +21,20 @@ thread_local! {
20
21
21
22
struct PathBuilder {
22
23
current_subpath : Subpath < PointId > ,
23
- glyph_subpaths : Vec < Subpath < PointId > > ,
24
- other_subpaths : Vec < Subpath < PointId > > ,
25
24
origin : DVec2 ,
25
+ glyph_subpaths : Vec < Subpath < PointId > > ,
26
+ vector_table : VectorDataTable ,
26
27
scale : f64 ,
27
28
id : PointId ,
28
29
}
29
30
30
31
impl PathBuilder {
31
32
fn point ( & self , x : f32 , y : f32 ) -> DVec2 {
32
- // Y-axis inversion converts from font coordinate system (Y-up) to graphics coordinate system (Y-down)
33
33
DVec2 :: new ( self . origin . x + x as f64 , self . origin . y - y as f64 ) * self . scale
34
34
}
35
35
36
- fn set_origin ( & mut self , x : f64 , y : f64 ) {
37
- self . origin = DVec2 :: new ( x, y) ;
38
- }
39
-
40
- fn draw_glyph ( & mut self , glyph : & OutlineGlyph < ' _ > , size : f32 , normalized_coords : & [ NormalizedCoord ] , style_skew : Option < DAffine2 > , skew : DAffine2 ) {
36
+ #[ allow( clippy:: too_many_arguments) ]
37
+ fn draw_glyph ( & mut self , glyph : & OutlineGlyph < ' _ > , size : f32 , normalized_coords : & [ NormalizedCoord ] , glyph_offset : DVec2 , style_skew : Option < DAffine2 > , skew : DAffine2 , per_glyph_instances : bool ) {
41
38
let location_ref = LocationRef :: new ( normalized_coords) ;
42
39
let settings = DrawSettings :: unhinted ( Size :: new ( size) , location_ref) ;
43
40
glyph. draw ( settings, self ) . unwrap ( ) ;
@@ -52,8 +49,19 @@ impl PathBuilder {
52
49
glyph_subpath. apply_transform ( skew) ;
53
50
}
54
51
55
- if !self . glyph_subpaths . is_empty ( ) {
56
- self . other_subpaths . extend ( core:: mem:: take ( & mut self . glyph_subpaths ) ) ;
52
+ if per_glyph_instances {
53
+ if !self . glyph_subpaths . is_empty ( ) {
54
+ self . vector_table . push ( Instance {
55
+ instance : VectorData :: from_subpaths ( core:: mem:: take ( & mut self . glyph_subpaths ) , false ) ,
56
+ transform : DAffine2 :: from_translation ( glyph_offset) ,
57
+ ..Default :: default ( )
58
+ } )
59
+ }
60
+ } else if !self . glyph_subpaths . is_empty ( ) {
61
+ for subpath in self . glyph_subpaths . iter ( ) {
62
+ // Unwrapping here is ok, since the check above guarantees there is at least one `VectorData`
63
+ self . vector_table . get_mut ( 0 ) . unwrap ( ) . instance . append_subpath ( subpath, false ) ;
64
+ }
57
65
}
58
66
}
59
67
}
@@ -112,7 +120,7 @@ impl Default for TypesettingConfig {
112
120
}
113
121
}
114
122
115
- fn render_glyph_run ( glyph_run : & GlyphRun < ' _ , ( ) > , path_builder : & mut PathBuilder , tilt : f64 ) {
123
+ fn render_glyph_run ( glyph_run : & GlyphRun < ' _ , ( ) > , path_builder : & mut PathBuilder , tilt : f64 , per_glyph_instances : bool ) {
116
124
let mut run_x = glyph_run. offset ( ) ;
117
125
let run_y = glyph_run. baseline ( ) ;
118
126
@@ -145,14 +153,15 @@ fn render_glyph_run(glyph_run: &GlyphRun<'_, ()>, path_builder: &mut PathBuilder
145
153
let outlines = font_ref. outline_glyphs ( ) ;
146
154
147
155
for glyph in glyph_run. glyphs ( ) {
148
- let glyph_x = run_x + glyph. x ;
149
- let glyph_y = run_y - glyph. y ;
156
+ let glyph_offset = DVec2 :: new ( ( run_x + glyph. x ) as f64 , ( run_y - glyph. y ) as f64 ) ;
150
157
run_x += glyph. advance ;
151
158
152
159
let glyph_id = GlyphId :: from ( glyph. id ) ;
153
160
if let Some ( glyph_outline) = outlines. get ( glyph_id) {
154
- path_builder. set_origin ( glyph_x as f64 , glyph_y as f64 ) ;
155
- path_builder. draw_glyph ( & glyph_outline, font_size, & normalized_coords, style_skew, skew) ;
161
+ if !per_glyph_instances {
162
+ path_builder. origin = glyph_offset;
163
+ }
164
+ path_builder. draw_glyph ( & glyph_outline, font_size, & normalized_coords, glyph_offset, style_skew, skew, per_glyph_instances) ;
156
165
}
157
166
}
158
167
}
@@ -187,27 +196,37 @@ fn layout_text(str: &str, font_data: Option<Blob<u8>>, typesetting: TypesettingC
187
196
Some ( layout)
188
197
}
189
198
190
- pub fn to_path ( str : & str , font_data : Option < Blob < u8 > > , typesetting : TypesettingConfig ) -> Vec < Subpath < PointId > > {
191
- let Some ( layout) = layout_text ( str, font_data, typesetting) else { return Vec :: new ( ) } ;
199
+ pub fn to_path ( str : & str , font_data : Option < Blob < u8 > > , typesetting : TypesettingConfig , per_glyph_instances : bool ) -> VectorDataTable {
200
+ let Some ( layout) = layout_text ( str, font_data, typesetting) else {
201
+ return VectorDataTable :: new ( VectorData :: default ( ) ) ;
202
+ } ;
192
203
193
204
let mut path_builder = PathBuilder {
194
205
current_subpath : Subpath :: new ( Vec :: new ( ) , false ) ,
195
206
glyph_subpaths : Vec :: new ( ) ,
196
- other_subpaths : Vec :: new ( ) ,
197
- origin : DVec2 :: ZERO ,
207
+ vector_table : if per_glyph_instances {
208
+ VectorDataTable :: default ( )
209
+ } else {
210
+ VectorDataTable :: new ( VectorData :: default ( ) )
211
+ } ,
198
212
scale : layout. scale ( ) as f64 ,
199
213
id : PointId :: ZERO ,
214
+ origin : DVec2 :: default ( ) ,
200
215
} ;
201
216
202
217
for line in layout. lines ( ) {
203
218
for item in line. items ( ) {
204
219
if let PositionedLayoutItem :: GlyphRun ( glyph_run) = item {
205
- render_glyph_run ( & glyph_run, & mut path_builder, typesetting. tilt ) ;
220
+ render_glyph_run ( & glyph_run, & mut path_builder, typesetting. tilt , per_glyph_instances ) ;
206
221
}
207
222
}
208
223
}
209
224
210
- path_builder. other_subpaths
225
+ if path_builder. vector_table . is_empty ( ) {
226
+ path_builder. vector_table = VectorDataTable :: new ( VectorData :: default ( ) ) ;
227
+ }
228
+
229
+ path_builder. vector_table
211
230
}
212
231
213
232
pub fn bounding_box ( str : & str , font_data : Option < Blob < u8 > > , typesetting : TypesettingConfig , for_clipping_test : bool ) -> DVec2 {
0 commit comments