1
+ use std:: borrow:: Cow ;
1
2
use std:: collections:: HashMap ;
2
3
3
4
use allsorts:: cff:: CFF ;
4
5
use allsorts:: context:: Glyph ;
5
6
use allsorts:: error:: ParseError ;
6
7
use allsorts:: glyph_position:: { GlyphLayout , GlyphPosition , TextDirection } ;
7
- use allsorts:: gpos:: Info ;
8
+ use allsorts:: gpos:: { Info , Placement } ;
9
+ use allsorts:: gsub:: GlyphOrigin ;
8
10
use allsorts:: outline:: { OutlineBuilder , OutlineSink } ;
9
11
use allsorts:: pathfinder_geometry:: line_segment:: LineSegment2F ;
10
12
use allsorts:: pathfinder_geometry:: transform2d:: Matrix2x2F ;
@@ -64,8 +66,18 @@ impl<'a> OutlineBuilder for GlyfPost<'a> {
64
66
}
65
67
}
66
68
69
+ pub enum SVGMode {
70
+ /// SVGs are being generated to comply with the expected output of the
71
+ /// [Unicode text rendering tests](https://github.com/unicode-org/text-rendering-tests).
72
+ ///
73
+ /// The String is the testcase name to be used as a prefix on ids.
74
+ TextRenderingTests ( String ) ,
75
+ /// SVGs are being generated for human viewing
76
+ View ,
77
+ }
78
+
67
79
pub struct SVGWriter {
68
- id_prefix : Option < String > ,
80
+ mode : SVGMode ,
69
81
transform : Matrix2x2F ,
70
82
usage : Vec < ( usize , Vector2F ) > ,
71
83
}
@@ -76,9 +88,9 @@ struct Symbols<'info> {
76
88
}
77
89
78
90
impl SVGWriter {
79
- pub fn new ( id_prefix : Option < String > , transform : Matrix2x2F ) -> Self {
91
+ pub fn new ( mode : SVGMode , transform : Matrix2x2F ) -> Self {
80
92
SVGWriter {
81
- id_prefix ,
93
+ mode ,
82
94
transform,
83
95
usage : Vec :: new ( ) ,
84
96
}
@@ -188,9 +200,10 @@ impl SVGWriter {
188
200
// Write symbols
189
201
for symbol in & symbols. symbols {
190
202
w. start_element ( "symbol" ) ;
191
- let id = SVGWriter :: format_id ( & self . id_prefix , & symbol. glyph_name ) ;
192
- // let class = SVGWriter::class(&symbol.glyph_name);
193
- w. write_attribute ( "id" , & id) ;
203
+ w. write_attribute ( "id" , & symbol. id ( & self . mode ) ) ;
204
+ for ( key, value) in symbol. data ( & self . mode ) {
205
+ w. write_attribute ( key, & value) ;
206
+ }
194
207
w. write_attribute ( "overflow" , "visible" ) ;
195
208
w. start_element ( "path" ) ;
196
209
w. write_attribute ( "d" , & symbol. path ) ;
@@ -202,23 +215,14 @@ impl SVGWriter {
202
215
for ( symbol_index, point) in self . usage {
203
216
w. start_element ( "use" ) ;
204
217
let symbol = & symbols. symbols [ symbol_index] ;
205
- let id = SVGWriter :: format_id ( & self . id_prefix , & symbol. glyph_name ) ;
206
- let href = format ! ( "#{}" , id) ;
207
- w. write_attribute ( "xlink:href" , & href) ;
218
+ w. write_attribute ( "xlink:href" , & format ! ( "#{}" , symbol. id( & self . mode) ) ) ;
208
219
w. write_attribute ( "x" , & point. x ( ) . round ( ) ) ;
209
220
w. write_attribute ( "y" , & point. y ( ) . round ( ) ) ;
210
221
w. end_element ( ) ;
211
222
}
212
223
213
224
w. end_document ( )
214
225
}
215
-
216
- fn format_id ( id_prefix : & Option < String > , glyph_name : & str ) -> String {
217
- match id_prefix {
218
- Some ( id_prefix) => format ! ( "{}.{}" , id_prefix, glyph_name) ,
219
- None => glyph_name. to_owned ( ) ,
220
- }
221
- }
222
226
}
223
227
224
228
impl < ' info > Symbols < ' info > {
@@ -241,6 +245,59 @@ impl<'info> Symbol<'info> {
241
245
info,
242
246
}
243
247
}
248
+
249
+ fn id ( & self , mode : & SVGMode ) -> Cow < ' _ , str > {
250
+ match mode {
251
+ SVGMode :: TextRenderingTests ( id_prefix) => {
252
+ format ! ( "{}.{}" , id_prefix, self . glyph_name) . into ( )
253
+ }
254
+ SVGMode :: View => Cow :: from ( & self . glyph_name ) ,
255
+ }
256
+ }
257
+
258
+ fn data ( & self , mode : & SVGMode ) -> HashMap < & ' static str , String > {
259
+ match mode {
260
+ SVGMode :: TextRenderingTests ( _) => HashMap :: new ( ) ,
261
+ SVGMode :: View => {
262
+ let bool_true = String :: from ( "true" ) ;
263
+ let mut data = HashMap :: new ( ) ;
264
+ if matches ! (
265
+ self . info. placement,
266
+ Placement :: MarkAnchor ( _, _, _) | Placement :: MarkOverprint ( _)
267
+ ) {
268
+ data. insert ( "data-mark" , bool_true. clone ( ) ) ;
269
+ }
270
+ data. insert ( "data-glyph-index" , self . info . glyph . glyph_index . to_string ( ) ) ;
271
+ data. insert (
272
+ "data-liga-component-pos" ,
273
+ self . info . glyph . liga_component_pos . to_string ( ) ,
274
+ ) ;
275
+ data. insert (
276
+ "data-glyph-origin" ,
277
+ match self . info . glyph . glyph_origin {
278
+ GlyphOrigin :: Char ( _) => String :: from ( "char" ) ,
279
+ GlyphOrigin :: Direct => String :: from ( "direct" ) ,
280
+ } ,
281
+ ) ;
282
+ if self . info . glyph . small_caps {
283
+ data. insert ( "data-small-caps" , bool_true. clone ( ) ) ;
284
+ }
285
+ if self . info . glyph . multi_subst_dup {
286
+ data. insert ( "data-multi-subst-dup" , bool_true. clone ( ) ) ;
287
+ }
288
+ if self . info . glyph . is_vert_alt {
289
+ data. insert ( "data-is-vert-alt" , bool_true. clone ( ) ) ;
290
+ }
291
+ if self . info . glyph . fake_bold {
292
+ data. insert ( "data-fake-bold" , bool_true. clone ( ) ) ;
293
+ }
294
+ if self . info . glyph . fake_italic {
295
+ data. insert ( "data-fake-italic" , bool_true. clone ( ) ) ;
296
+ }
297
+ data
298
+ }
299
+ }
300
+ }
244
301
}
245
302
246
303
impl < ' info > OutlineSink for Symbols < ' info > {
0 commit comments