1 | /**************************************************************************** |
2 | * |
3 | * cffgload.c |
4 | * |
5 | * OpenType Glyph Loader (body). |
6 | * |
7 | * Copyright (C) 1996-2019 by |
8 | * David Turner, Robert Wilhelm, and Werner Lemberg. |
9 | * |
10 | * This file is part of the FreeType project, and may only be used, |
11 | * modified, and distributed under the terms of the FreeType project |
12 | * license, LICENSE.TXT. By continuing to use, modify, or distribute |
13 | * this file you indicate that you have read the license and |
14 | * understand and accept it fully. |
15 | * |
16 | */ |
17 | |
18 | |
19 | #include <ft2build.h> |
20 | #include FT_INTERNAL_DEBUG_H |
21 | #include FT_INTERNAL_STREAM_H |
22 | #include FT_INTERNAL_SFNT_H |
23 | #include FT_INTERNAL_CALC_H |
24 | #include FT_INTERNAL_POSTSCRIPT_AUX_H |
25 | #include FT_OUTLINE_H |
26 | #include FT_DRIVER_H |
27 | |
28 | #include "cffload.h" |
29 | #include "cffgload.h" |
30 | |
31 | #include "cfferrs.h" |
32 | |
33 | |
34 | /************************************************************************** |
35 | * |
36 | * The macro FT_COMPONENT is used in trace mode. It is an implicit |
37 | * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
38 | * messages during execution. |
39 | */ |
40 | #undef FT_COMPONENT |
41 | #define FT_COMPONENT cffgload |
42 | |
43 | |
44 | FT_LOCAL_DEF( FT_Error ) |
45 | cff_get_glyph_data( TT_Face face, |
46 | FT_UInt glyph_index, |
47 | FT_Byte** pointer, |
48 | FT_ULong* length ) |
49 | { |
50 | #ifdef FT_CONFIG_OPTION_INCREMENTAL |
51 | /* For incremental fonts get the character data using the */ |
52 | /* callback function. */ |
53 | if ( face->root.internal->incremental_interface ) |
54 | { |
55 | FT_Data data; |
56 | FT_Error error = |
57 | face->root.internal->incremental_interface->funcs->get_glyph_data( |
58 | face->root.internal->incremental_interface->object, |
59 | glyph_index, &data ); |
60 | |
61 | |
62 | *pointer = (FT_Byte*)data.pointer; |
63 | *length = (FT_ULong)data.length; |
64 | |
65 | return error; |
66 | } |
67 | else |
68 | #endif /* FT_CONFIG_OPTION_INCREMENTAL */ |
69 | |
70 | { |
71 | CFF_Font cff = (CFF_Font)(face->extra.data); |
72 | |
73 | |
74 | return cff_index_access_element( &cff->charstrings_index, glyph_index, |
75 | pointer, length ); |
76 | } |
77 | } |
78 | |
79 | |
80 | FT_LOCAL_DEF( void ) |
81 | cff_free_glyph_data( TT_Face face, |
82 | FT_Byte** pointer, |
83 | FT_ULong length ) |
84 | { |
85 | #ifndef FT_CONFIG_OPTION_INCREMENTAL |
86 | FT_UNUSED( length ); |
87 | #endif |
88 | |
89 | #ifdef FT_CONFIG_OPTION_INCREMENTAL |
90 | /* For incremental fonts get the character data using the */ |
91 | /* callback function. */ |
92 | if ( face->root.internal->incremental_interface ) |
93 | { |
94 | FT_Data data; |
95 | |
96 | |
97 | data.pointer = *pointer; |
98 | data.length = (FT_Int)length; |
99 | |
100 | face->root.internal->incremental_interface->funcs->free_glyph_data( |
101 | face->root.internal->incremental_interface->object, &data ); |
102 | } |
103 | else |
104 | #endif /* FT_CONFIG_OPTION_INCREMENTAL */ |
105 | |
106 | { |
107 | CFF_Font cff = (CFF_Font)(face->extra.data); |
108 | |
109 | |
110 | cff_index_forget_element( &cff->charstrings_index, pointer ); |
111 | } |
112 | } |
113 | |
114 | |
115 | /*************************************************************************/ |
116 | /*************************************************************************/ |
117 | /*************************************************************************/ |
118 | /********** *********/ |
119 | /********** *********/ |
120 | /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ |
121 | /********** *********/ |
122 | /********** The following code is in charge of computing *********/ |
123 | /********** the maximum advance width of the font. It *********/ |
124 | /********** quickly processes each glyph charstring to *********/ |
125 | /********** extract the value from either a `sbw' or `seac' *********/ |
126 | /********** operator. *********/ |
127 | /********** *********/ |
128 | /*************************************************************************/ |
129 | /*************************************************************************/ |
130 | /*************************************************************************/ |
131 | |
132 | |
133 | #if 0 /* unused until we support pure CFF fonts */ |
134 | |
135 | |
136 | FT_LOCAL_DEF( FT_Error ) |
137 | cff_compute_max_advance( TT_Face face, |
138 | FT_Int* max_advance ) |
139 | { |
140 | FT_Error error = FT_Err_Ok; |
141 | CFF_Decoder decoder; |
142 | FT_Int glyph_index; |
143 | CFF_Font cff = (CFF_Font)face->other; |
144 | |
145 | PSAux_Service psaux = (PSAux_Service)face->psaux; |
146 | const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs; |
147 | |
148 | |
149 | *max_advance = 0; |
150 | |
151 | /* Initialize load decoder */ |
152 | decoder_funcs->init( &decoder, face, 0, 0, 0, 0, 0, 0 ); |
153 | |
154 | decoder.builder.metrics_only = 1; |
155 | decoder.builder.load_points = 0; |
156 | |
157 | /* For each glyph, parse the glyph charstring and extract */ |
158 | /* the advance width. */ |
159 | for ( glyph_index = 0; glyph_index < face->root.num_glyphs; |
160 | glyph_index++ ) |
161 | { |
162 | FT_Byte* charstring; |
163 | FT_ULong charstring_len; |
164 | |
165 | |
166 | /* now get load the unscaled outline */ |
167 | error = cff_get_glyph_data( face, glyph_index, |
168 | &charstring, &charstring_len ); |
169 | if ( !error ) |
170 | { |
171 | error = decoder_funcs->prepare( &decoder, size, glyph_index ); |
172 | if ( !error ) |
173 | error = decoder_funcs->parse_charstrings_old( &decoder, |
174 | charstring, |
175 | charstring_len, |
176 | 0 ); |
177 | |
178 | cff_free_glyph_data( face, &charstring, &charstring_len ); |
179 | } |
180 | |
181 | /* ignore the error if one has occurred -- skip to next glyph */ |
182 | error = FT_Err_Ok; |
183 | } |
184 | |
185 | *max_advance = decoder.builder.advance.x; |
186 | |
187 | return FT_Err_Ok; |
188 | } |
189 | |
190 | |
191 | #endif /* 0 */ |
192 | |
193 | |
194 | FT_LOCAL_DEF( FT_Error ) |
195 | cff_slot_load( CFF_GlyphSlot glyph, |
196 | CFF_Size size, |
197 | FT_UInt glyph_index, |
198 | FT_Int32 load_flags ) |
199 | { |
200 | FT_Error error; |
201 | CFF_Decoder decoder; |
202 | PS_Decoder psdecoder; |
203 | TT_Face face = (TT_Face)glyph->root.face; |
204 | FT_Bool hinting, scaled, force_scaling; |
205 | CFF_Font cff = (CFF_Font)face->extra.data; |
206 | |
207 | PSAux_Service psaux = (PSAux_Service)face->psaux; |
208 | const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs; |
209 | |
210 | FT_Matrix font_matrix; |
211 | FT_Vector font_offset; |
212 | |
213 | |
214 | force_scaling = FALSE; |
215 | |
216 | /* in a CID-keyed font, consider `glyph_index' as a CID and map */ |
217 | /* it immediately to the real glyph_index -- if it isn't a */ |
218 | /* subsetted font, glyph_indices and CIDs are identical, though */ |
219 | if ( cff->top_font.font_dict.cid_registry != 0xFFFFU && |
220 | cff->charset.cids ) |
221 | { |
222 | /* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */ |
223 | if ( glyph_index != 0 ) |
224 | { |
225 | glyph_index = cff_charset_cid_to_gindex( &cff->charset, |
226 | glyph_index ); |
227 | if ( glyph_index == 0 ) |
228 | return FT_THROW( Invalid_Argument ); |
229 | } |
230 | } |
231 | else if ( glyph_index >= cff->num_glyphs ) |
232 | return FT_THROW( Invalid_Argument ); |
233 | |
234 | if ( load_flags & FT_LOAD_NO_RECURSE ) |
235 | load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; |
236 | |
237 | glyph->x_scale = 0x10000L; |
238 | glyph->y_scale = 0x10000L; |
239 | if ( size ) |
240 | { |
241 | glyph->x_scale = size->root.metrics.x_scale; |
242 | glyph->y_scale = size->root.metrics.y_scale; |
243 | } |
244 | |
245 | #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS |
246 | |
247 | /* try to load embedded bitmap if any */ |
248 | /* */ |
249 | /* XXX: The convention should be emphasized in */ |
250 | /* the documents because it can be confusing. */ |
251 | if ( size ) |
252 | { |
253 | CFF_Face cff_face = (CFF_Face)size->root.face; |
254 | SFNT_Service sfnt = (SFNT_Service)cff_face->sfnt; |
255 | FT_Stream stream = cff_face->root.stream; |
256 | |
257 | |
258 | if ( size->strike_index != 0xFFFFFFFFUL && |
259 | sfnt->load_eblc && |
260 | ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) |
261 | { |
262 | TT_SBit_MetricsRec metrics; |
263 | |
264 | |
265 | error = sfnt->load_sbit_image( face, |
266 | size->strike_index, |
267 | glyph_index, |
268 | (FT_UInt)load_flags, |
269 | stream, |
270 | &glyph->root.bitmap, |
271 | &metrics ); |
272 | |
273 | if ( !error ) |
274 | { |
275 | FT_Bool has_vertical_info; |
276 | FT_UShort advance; |
277 | FT_Short dummy; |
278 | |
279 | |
280 | glyph->root.outline.n_points = 0; |
281 | glyph->root.outline.n_contours = 0; |
282 | |
283 | glyph->root.metrics.width = (FT_Pos)metrics.width * 64; |
284 | glyph->root.metrics.height = (FT_Pos)metrics.height * 64; |
285 | |
286 | glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX * 64; |
287 | glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY * 64; |
288 | glyph->root.metrics.horiAdvance = (FT_Pos)metrics.horiAdvance * 64; |
289 | |
290 | glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX * 64; |
291 | glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY * 64; |
292 | glyph->root.metrics.vertAdvance = (FT_Pos)metrics.vertAdvance * 64; |
293 | |
294 | glyph->root.format = FT_GLYPH_FORMAT_BITMAP; |
295 | |
296 | if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) |
297 | { |
298 | glyph->root.bitmap_left = metrics.vertBearingX; |
299 | glyph->root.bitmap_top = metrics.vertBearingY; |
300 | } |
301 | else |
302 | { |
303 | glyph->root.bitmap_left = metrics.horiBearingX; |
304 | glyph->root.bitmap_top = metrics.horiBearingY; |
305 | } |
306 | |
307 | /* compute linear advance widths */ |
308 | |
309 | (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 0, |
310 | glyph_index, |
311 | &dummy, |
312 | &advance ); |
313 | glyph->root.linearHoriAdvance = advance; |
314 | |
315 | has_vertical_info = FT_BOOL( |
316 | face->vertical_info && |
317 | face->vertical.number_Of_VMetrics > 0 ); |
318 | |
319 | /* get the vertical metrics from the vmtx table if we have one */ |
320 | if ( has_vertical_info ) |
321 | { |
322 | (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1, |
323 | glyph_index, |
324 | &dummy, |
325 | &advance ); |
326 | glyph->root.linearVertAdvance = advance; |
327 | } |
328 | else |
329 | { |
330 | /* make up vertical ones */ |
331 | if ( face->os2.version != 0xFFFFU ) |
332 | glyph->root.linearVertAdvance = (FT_Pos) |
333 | ( face->os2.sTypoAscender - face->os2.sTypoDescender ); |
334 | else |
335 | glyph->root.linearVertAdvance = (FT_Pos) |
336 | ( face->horizontal.Ascender - face->horizontal.Descender ); |
337 | } |
338 | |
339 | return error; |
340 | } |
341 | } |
342 | } |
343 | |
344 | #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ |
345 | |
346 | /* return immediately if we only want the embedded bitmaps */ |
347 | if ( load_flags & FT_LOAD_SBITS_ONLY ) |
348 | return FT_THROW( Invalid_Argument ); |
349 | |
350 | /* if we have a CID subfont, use its matrix (which has already */ |
351 | /* been multiplied with the root matrix) */ |
352 | |
353 | /* this scaling is only relevant if the PS hinter isn't active */ |
354 | if ( cff->num_subfonts ) |
355 | { |
356 | FT_Long top_upm, sub_upm; |
357 | FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, |
358 | glyph_index ); |
359 | |
360 | |
361 | if ( fd_index >= cff->num_subfonts ) |
362 | fd_index = (FT_Byte)( cff->num_subfonts - 1 ); |
363 | |
364 | top_upm = (FT_Long)cff->top_font.font_dict.units_per_em; |
365 | sub_upm = (FT_Long)cff->subfonts[fd_index]->font_dict.units_per_em; |
366 | |
367 | |
368 | font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix; |
369 | font_offset = cff->subfonts[fd_index]->font_dict.font_offset; |
370 | |
371 | if ( top_upm != sub_upm ) |
372 | { |
373 | glyph->x_scale = FT_MulDiv( glyph->x_scale, top_upm, sub_upm ); |
374 | glyph->y_scale = FT_MulDiv( glyph->y_scale, top_upm, sub_upm ); |
375 | |
376 | force_scaling = TRUE; |
377 | } |
378 | } |
379 | else |
380 | { |
381 | font_matrix = cff->top_font.font_dict.font_matrix; |
382 | font_offset = cff->top_font.font_dict.font_offset; |
383 | } |
384 | |
385 | glyph->root.outline.n_points = 0; |
386 | glyph->root.outline.n_contours = 0; |
387 | |
388 | /* top-level code ensures that FT_LOAD_NO_HINTING is set */ |
389 | /* if FT_LOAD_NO_SCALE is active */ |
390 | hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); |
391 | scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); |
392 | |
393 | glyph->hint = hinting; |
394 | glyph->scaled = scaled; |
395 | glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */ |
396 | |
397 | { |
398 | #ifdef CFF_CONFIG_OPTION_OLD_ENGINE |
399 | PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face ); |
400 | #endif |
401 | |
402 | |
403 | FT_Byte* charstring; |
404 | FT_ULong charstring_len; |
405 | |
406 | |
407 | decoder_funcs->init( &decoder, face, size, glyph, hinting, |
408 | FT_LOAD_TARGET_MODE( load_flags ), |
409 | cff_get_glyph_data, |
410 | cff_free_glyph_data ); |
411 | |
412 | /* this is for pure CFFs */ |
413 | if ( load_flags & FT_LOAD_ADVANCE_ONLY ) |
414 | decoder.width_only = TRUE; |
415 | |
416 | decoder.builder.no_recurse = |
417 | FT_BOOL( load_flags & FT_LOAD_NO_RECURSE ); |
418 | |
419 | /* now load the unscaled outline */ |
420 | error = cff_get_glyph_data( face, glyph_index, |
421 | &charstring, &charstring_len ); |
422 | if ( error ) |
423 | goto Glyph_Build_Finished; |
424 | |
425 | error = decoder_funcs->prepare( &decoder, size, glyph_index ); |
426 | if ( error ) |
427 | goto Glyph_Build_Finished; |
428 | |
429 | #ifdef CFF_CONFIG_OPTION_OLD_ENGINE |
430 | /* choose which CFF renderer to use */ |
431 | if ( driver->hinting_engine == FT_HINTING_FREETYPE ) |
432 | error = decoder_funcs->parse_charstrings_old( &decoder, |
433 | charstring, |
434 | charstring_len, |
435 | 0 ); |
436 | else |
437 | #endif |
438 | { |
439 | psaux->ps_decoder_init( &psdecoder, &decoder, FALSE ); |
440 | |
441 | error = decoder_funcs->parse_charstrings( &psdecoder, |
442 | charstring, |
443 | charstring_len ); |
444 | |
445 | /* Adobe's engine uses 16.16 numbers everywhere; */ |
446 | /* as a consequence, glyphs larger than 2000ppem get rejected */ |
447 | if ( FT_ERR_EQ( error, Glyph_Too_Big ) ) |
448 | { |
449 | /* this time, we retry unhinted and scale up the glyph later on */ |
450 | /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */ |
451 | /* 0x400 for both `x_scale' and `y_scale' in this case) */ |
452 | hinting = FALSE; |
453 | force_scaling = TRUE; |
454 | glyph->hint = hinting; |
455 | |
456 | error = decoder_funcs->parse_charstrings( &psdecoder, |
457 | charstring, |
458 | charstring_len ); |
459 | } |
460 | } |
461 | |
462 | cff_free_glyph_data( face, &charstring, charstring_len ); |
463 | |
464 | if ( error ) |
465 | goto Glyph_Build_Finished; |
466 | |
467 | #ifdef FT_CONFIG_OPTION_INCREMENTAL |
468 | /* Control data and length may not be available for incremental */ |
469 | /* fonts. */ |
470 | if ( face->root.internal->incremental_interface ) |
471 | { |
472 | glyph->root.control_data = NULL; |
473 | glyph->root.control_len = 0; |
474 | } |
475 | else |
476 | #endif /* FT_CONFIG_OPTION_INCREMENTAL */ |
477 | |
478 | /* We set control_data and control_len if charstrings is loaded. */ |
479 | /* See how charstring loads at cff_index_access_element() in */ |
480 | /* cffload.c. */ |
481 | { |
482 | CFF_Index csindex = &cff->charstrings_index; |
483 | |
484 | |
485 | if ( csindex->offsets ) |
486 | { |
487 | glyph->root.control_data = csindex->bytes + |
488 | csindex->offsets[glyph_index] - 1; |
489 | glyph->root.control_len = (FT_Long)charstring_len; |
490 | } |
491 | } |
492 | |
493 | Glyph_Build_Finished: |
494 | /* save new glyph tables, if no error */ |
495 | if ( !error ) |
496 | decoder.builder.funcs.done( &decoder.builder ); |
497 | /* XXX: anything to do for broken glyph entry? */ |
498 | } |
499 | |
500 | #ifdef FT_CONFIG_OPTION_INCREMENTAL |
501 | |
502 | /* Incremental fonts can optionally override the metrics. */ |
503 | if ( !error && |
504 | face->root.internal->incremental_interface && |
505 | face->root.internal->incremental_interface->funcs->get_glyph_metrics ) |
506 | { |
507 | FT_Incremental_MetricsRec metrics; |
508 | |
509 | |
510 | metrics.bearing_x = decoder.builder.left_bearing.x; |
511 | metrics.bearing_y = 0; |
512 | metrics.advance = decoder.builder.advance.x; |
513 | metrics.advance_v = decoder.builder.advance.y; |
514 | |
515 | error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( |
516 | face->root.internal->incremental_interface->object, |
517 | glyph_index, FALSE, &metrics ); |
518 | |
519 | decoder.builder.left_bearing.x = metrics.bearing_x; |
520 | decoder.builder.advance.x = metrics.advance; |
521 | decoder.builder.advance.y = metrics.advance_v; |
522 | } |
523 | |
524 | #endif /* FT_CONFIG_OPTION_INCREMENTAL */ |
525 | |
526 | if ( !error ) |
527 | { |
528 | /* Now, set the metrics -- this is rather simple, as */ |
529 | /* the left side bearing is the xMin, and the top side */ |
530 | /* bearing the yMax. */ |
531 | |
532 | /* For composite glyphs, return only left side bearing and */ |
533 | /* advance width. */ |
534 | if ( load_flags & FT_LOAD_NO_RECURSE ) |
535 | { |
536 | FT_Slot_Internal internal = glyph->root.internal; |
537 | |
538 | |
539 | glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; |
540 | glyph->root.metrics.horiAdvance = decoder.glyph_width; |
541 | internal->glyph_matrix = font_matrix; |
542 | internal->glyph_delta = font_offset; |
543 | internal->glyph_transformed = 1; |
544 | } |
545 | else |
546 | { |
547 | FT_BBox cbox; |
548 | FT_Glyph_Metrics* metrics = &glyph->root.metrics; |
549 | FT_Bool has_vertical_info; |
550 | |
551 | |
552 | if ( face->horizontal.number_Of_HMetrics ) |
553 | { |
554 | FT_Short horiBearingX = 0; |
555 | FT_UShort horiAdvance = 0; |
556 | |
557 | |
558 | ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, |
559 | glyph_index, |
560 | &horiBearingX, |
561 | &horiAdvance ); |
562 | metrics->horiAdvance = horiAdvance; |
563 | metrics->horiBearingX = horiBearingX; |
564 | glyph->root.linearHoriAdvance = horiAdvance; |
565 | } |
566 | else |
567 | { |
568 | /* copy the _unscaled_ advance width */ |
569 | metrics->horiAdvance = decoder.glyph_width; |
570 | glyph->root.linearHoriAdvance = decoder.glyph_width; |
571 | } |
572 | |
573 | glyph->root.internal->glyph_transformed = 0; |
574 | |
575 | has_vertical_info = FT_BOOL( face->vertical_info && |
576 | face->vertical.number_Of_VMetrics > 0 ); |
577 | |
578 | /* get the vertical metrics from the vmtx table if we have one */ |
579 | if ( has_vertical_info ) |
580 | { |
581 | FT_Short vertBearingY = 0; |
582 | FT_UShort vertAdvance = 0; |
583 | |
584 | |
585 | ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, |
586 | glyph_index, |
587 | &vertBearingY, |
588 | &vertAdvance ); |
589 | metrics->vertBearingY = vertBearingY; |
590 | metrics->vertAdvance = vertAdvance; |
591 | } |
592 | else |
593 | { |
594 | /* make up vertical ones */ |
595 | if ( face->os2.version != 0xFFFFU ) |
596 | metrics->vertAdvance = (FT_Pos)( face->os2.sTypoAscender - |
597 | face->os2.sTypoDescender ); |
598 | else |
599 | metrics->vertAdvance = (FT_Pos)( face->horizontal.Ascender - |
600 | face->horizontal.Descender ); |
601 | } |
602 | |
603 | glyph->root.linearVertAdvance = metrics->vertAdvance; |
604 | |
605 | glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; |
606 | |
607 | glyph->root.outline.flags = 0; |
608 | if ( size && size->root.metrics.y_ppem < 24 ) |
609 | glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; |
610 | |
611 | glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL; |
612 | |
613 | /* apply the font matrix, if any */ |
614 | if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || |
615 | font_matrix.xy != 0 || font_matrix.yx != 0 ) |
616 | { |
617 | FT_Outline_Transform( &glyph->root.outline, &font_matrix ); |
618 | |
619 | metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, |
620 | font_matrix.xx ); |
621 | metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, |
622 | font_matrix.yy ); |
623 | } |
624 | |
625 | if ( font_offset.x || font_offset.y ) |
626 | { |
627 | FT_Outline_Translate( &glyph->root.outline, |
628 | font_offset.x, |
629 | font_offset.y ); |
630 | |
631 | metrics->horiAdvance += font_offset.x; |
632 | metrics->vertAdvance += font_offset.y; |
633 | } |
634 | |
635 | if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling ) |
636 | { |
637 | /* scale the outline and the metrics */ |
638 | FT_Int n; |
639 | FT_Outline* cur = &glyph->root.outline; |
640 | FT_Vector* vec = cur->points; |
641 | FT_Fixed x_scale = glyph->x_scale; |
642 | FT_Fixed y_scale = glyph->y_scale; |
643 | |
644 | |
645 | /* First of all, scale the points */ |
646 | if ( !hinting || !decoder.builder.hints_funcs ) |
647 | for ( n = cur->n_points; n > 0; n--, vec++ ) |
648 | { |
649 | vec->x = FT_MulFix( vec->x, x_scale ); |
650 | vec->y = FT_MulFix( vec->y, y_scale ); |
651 | } |
652 | |
653 | /* Then scale the metrics */ |
654 | metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); |
655 | metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); |
656 | } |
657 | |
658 | /* compute the other metrics */ |
659 | FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); |
660 | |
661 | metrics->width = cbox.xMax - cbox.xMin; |
662 | metrics->height = cbox.yMax - cbox.yMin; |
663 | |
664 | metrics->horiBearingX = cbox.xMin; |
665 | metrics->horiBearingY = cbox.yMax; |
666 | |
667 | if ( has_vertical_info ) |
668 | metrics->vertBearingX = metrics->horiBearingX - |
669 | metrics->horiAdvance / 2; |
670 | else |
671 | { |
672 | if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) |
673 | ft_synthesize_vertical_metrics( metrics, |
674 | metrics->vertAdvance ); |
675 | } |
676 | } |
677 | } |
678 | |
679 | return error; |
680 | } |
681 | |
682 | |
683 | /* END */ |
684 | |