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