Home | History | Annotate | Download | only in cff
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  cffgload.c                                                             */
      4 /*                                                                         */
      5 /*    OpenType Glyph Loader (body).                                        */
      6 /*                                                                         */
      7 /*  Copyright 1996-2018 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  trace_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  << 6;
    284           glyph->root.metrics.height = (FT_Pos)metrics.height << 6;
    285 
    286           glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6;
    287           glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6;
    288           glyph->root.metrics.horiAdvance  = (FT_Pos)metrics.horiAdvance  << 6;
    289 
    290           glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6;
    291           glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6;
    292           glyph->root.metrics.vertAdvance  = (FT_Pos)metrics.vertAdvance  << 6;
    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