1
1
use fontspector_checkapi:: { fixfont, prelude:: * , testfont, FileTypeConvert } ;
2
+ use hashbrown:: HashMap ;
3
+ use itertools:: Itertools ;
2
4
use kurbo:: Affine ;
3
5
use read_fonts:: {
4
6
tables:: glyf:: { Anchor , CurvePoint , Glyph , Transform } ,
5
7
types:: F2Dot14 ,
6
8
FontData , TableProvider ,
7
9
} ;
8
- use skrifa:: GlyphId16 ;
10
+ use skrifa:: GlyphId ;
9
11
use write_fonts:: {
10
12
from_obj:: ToOwnedObj ,
11
13
tables:: glyf:: {
@@ -98,20 +100,40 @@ fn transformed_components(f: &Testable, context: &Context) -> CheckFnResult {
98
100
}
99
101
}
100
102
101
- fn bad_composite ( c : & CompositeGlyph ) -> bool {
102
- c. components ( ) . iter ( ) . any ( |component| {
103
- !transform_is_linear ( component. transform ) || transform_is_semi_flipped ( component. transform )
104
- } )
105
- }
106
-
107
103
fn decompose_transformed_components ( t : & Testable ) -> FixFnResult {
108
- decompose_components_impl ( t, bad_composite)
104
+ let f = fixfont ! ( t) ;
105
+ let loca = f
106
+ . font ( )
107
+ . loca ( None )
108
+ . map_err ( |_| "loca table not found" . to_string ( ) ) ?;
109
+ let glyf = f
110
+ . font ( )
111
+ . glyf ( )
112
+ . map_err ( |_| "glyf table not found" . to_string ( ) ) ?;
113
+ let bad_composites = f
114
+ . all_glyphs ( )
115
+ . filter_map ( |gid| {
116
+ loca. get_glyf ( gid, & glyf)
117
+ . ok ( )
118
+ . flatten ( )
119
+ . and_then ( |glyph| match glyph {
120
+ Glyph :: Composite ( composite)
121
+ if composite. components ( ) . any ( |component| {
122
+ !transform_is_linear ( component. transform )
123
+ || transform_is_semi_flipped ( component. transform )
124
+ } ) =>
125
+ {
126
+ Some ( gid)
127
+ }
128
+ _ => None ,
129
+ } )
130
+ } )
131
+ . collect :: < Vec < _ > > ( ) ;
132
+
133
+ decompose_components_impl ( t, & bad_composites)
109
134
}
110
135
111
- pub ( crate ) fn decompose_components_impl (
112
- t : & Testable ,
113
- bad_composite : impl Fn ( & CompositeGlyph ) -> bool ,
114
- ) -> FixFnResult {
136
+ pub ( crate ) fn decompose_components_impl ( t : & Testable , decompose_order : & [ GlyphId ] ) -> FixFnResult {
115
137
let f = fixfont ! ( t) ;
116
138
let mut new_font = FontBuilder :: new ( ) ;
117
139
let mut builder = GlyfLocaBuilder :: new ( ) ;
@@ -123,31 +145,36 @@ pub(crate) fn decompose_components_impl(
123
145
. font ( )
124
146
. glyf ( )
125
147
. map_err ( |_| "glyf table not found" . to_string ( ) ) ?;
126
- let all_glyphs: Vec < WriteGlyph > = f
148
+ let mut all_glyphs: HashMap < GlyphId , WriteGlyph > = f
127
149
. all_glyphs ( )
128
150
. map ( |gid| {
129
- loca. get_glyf ( gid, & glyf) . map ( |option_glyph| {
130
- option_glyph
131
- . map ( |glyph| {
132
- let g: WriteGlyph = glyph. to_owned_obj ( FontData :: new ( & [ ] ) ) ;
133
- g
134
- } )
135
- . unwrap_or ( WriteGlyph :: Empty )
136
- } )
151
+ loca. get_glyf ( gid, & glyf)
152
+ . map ( |option_glyph| {
153
+ option_glyph
154
+ . map ( |glyph| {
155
+ let g: WriteGlyph = glyph. to_owned_obj ( FontData :: new ( & [ ] ) ) ;
156
+ g
157
+ } )
158
+ . unwrap_or ( WriteGlyph :: Empty )
159
+ } )
160
+ . map ( |x| ( gid, x) )
137
161
} )
138
- . collect :: < Result < Vec < WriteGlyph > , _ > > ( )
162
+ . collect :: < Result < HashMap < GlyphId , WriteGlyph > , _ > > ( )
139
163
. map_err ( |x| x. to_string ( ) ) ?;
140
- for glyph in all_glyphs. iter ( ) {
141
- match glyph {
142
- WriteGlyph :: Composite ( composite) if bad_composite ( composite) => {
164
+ for glyph_id in decompose_order {
165
+ let current_glyph = all_glyphs. get ( glyph_id) . ok_or ( "glyph not found" ) ?;
166
+ match current_glyph {
167
+ WriteGlyph :: Composite ( composite) => {
143
168
let new_glyph = decompose_glyph ( composite, & all_glyphs) ?;
144
- builder. add_glyph ( & new_glyph) . map_err ( |x| x. to_string ( ) ) ?;
145
- }
146
- WriteGlyph :: Composite ( _) | WriteGlyph :: Empty | WriteGlyph :: Simple ( _) => {
147
- builder. add_glyph ( glyph) . map_err ( |x| x. to_string ( ) ) ?;
169
+ all_glyphs. insert ( * glyph_id, new_glyph) ;
148
170
}
171
+ WriteGlyph :: Empty | WriteGlyph :: Simple ( _) => { }
149
172
}
150
173
}
174
+ for glyph_id in all_glyphs. keys ( ) . sorted_by ( |a, b| a. cmp ( b) ) {
175
+ let glyph = all_glyphs. get ( glyph_id) . ok_or ( "glyph not found" ) ?;
176
+ builder. add_glyph ( glyph) . map_err ( |x| x. to_string ( ) ) ?;
177
+ }
151
178
let ( new_glyph, new_loca, _head_format) = builder. build ( ) ;
152
179
new_font. add_table ( & new_glyph) . map_err ( |x| x. to_string ( ) ) ?;
153
180
new_font. add_table ( & new_loca) . map_err ( |x| x. to_string ( ) ) ?;
@@ -160,12 +187,12 @@ pub(crate) fn decompose_components_impl(
160
187
161
188
fn decompose_glyph (
162
189
composite : & CompositeGlyph ,
163
- glyphs : & [ WriteGlyph ] ,
190
+ glyphs : & HashMap < GlyphId , WriteGlyph > ,
164
191
) -> Result < WriteGlyph , String > {
165
192
let mut new_glyph = SimpleGlyph :: default ( ) ;
166
193
for component in composite. components ( ) {
167
194
for ( gid, affine) in flatten_component ( glyphs, component) ? {
168
- let component_glyph = glyphs. get ( gid. to_u16 ( ) as usize ) . ok_or ( "glyph not found" ) ?;
195
+ let component_glyph = glyphs. get ( & gid) . ok_or ( "glyph not found" ) ?;
169
196
match component_glyph {
170
197
WriteGlyph :: Simple ( simple) => {
171
198
new_glyph
@@ -193,16 +220,16 @@ fn transform_contour(c: &Contour, affine: Affine) -> Contour {
193
220
}
194
221
195
222
fn flatten_component (
196
- glyphs : & [ WriteGlyph ] ,
223
+ glyphs : & HashMap < GlyphId , WriteGlyph > ,
197
224
component : & Component ,
198
- ) -> Result < Vec < ( GlyphId16 , kurbo:: Affine ) > , String > {
225
+ ) -> Result < Vec < ( GlyphId , kurbo:: Affine ) > , String > {
199
226
let glyph = glyphs
200
- . get ( component. glyph . to_u16 ( ) as usize )
227
+ . get ( & GlyphId :: from ( component. glyph ) )
201
228
. ok_or ( "glyph not found" ) ?;
202
229
Ok ( match glyph {
203
230
WriteGlyph :: Empty => vec ! [ ] ,
204
231
WriteGlyph :: Simple ( _) => vec ! [ (
205
- component. glyph,
232
+ component. glyph. into ( ) ,
206
233
to_kurbo_transform( & component. transform, & component. anchor) ,
207
234
) ] ,
208
235
WriteGlyph :: Composite ( composite_glyph) => {
0 commit comments