Home | History | Annotate | Download | only in sfnt
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ttmtx.c                                                                */
      4 /*                                                                         */
      5 /*    Load the metrics tables common to TTF and OTF fonts (body).          */
      6 /*                                                                         */
      7 /*  Copyright 2006, 2007, 2008, 2009 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_TRUETYPE_TAGS_H
     23 #include "ttmtx.h"
     24 
     25 #include "sferrors.h"
     26 
     27 
     28   /*************************************************************************/
     29   /*                                                                       */
     30   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
     31   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
     32   /* messages during execution.                                            */
     33   /*                                                                       */
     34 #undef  FT_COMPONENT
     35 #define FT_COMPONENT  trace_ttmtx
     36 
     37 
     38   /*
     39    *  Unfortunately, we can't enable our memory optimizations if
     40    *  FT_CONFIG_OPTION_OLD_INTERNALS is defined.  This is because at least
     41    *  one rogue client (libXfont in the X.Org XServer) is directly accessing
     42    *  the metrics.
     43    */
     44 
     45   /*************************************************************************/
     46   /*                                                                       */
     47   /* <Function>                                                            */
     48   /*    tt_face_load_hmtx                                                  */
     49   /*                                                                       */
     50   /* <Description>                                                         */
     51   /*    Load the `hmtx' or `vmtx' table into a face object.                */
     52   /*                                                                       */
     53   /* <Input>                                                               */
     54   /*    face     :: A handle to the target face object.                    */
     55   /*                                                                       */
     56   /*    stream   :: The input stream.                                      */
     57   /*                                                                       */
     58   /*    vertical :: A boolean flag.  If set, load `vmtx'.                  */
     59   /*                                                                       */
     60   /* <Return>                                                              */
     61   /*    FreeType error code.  0 means success.                             */
     62   /*                                                                       */
     63 #ifndef FT_CONFIG_OPTION_OLD_INTERNALS
     64 
     65   FT_LOCAL_DEF( FT_Error )
     66   tt_face_load_hmtx( TT_Face    face,
     67                      FT_Stream  stream,
     68                      FT_Bool    vertical )
     69   {
     70     FT_Error   error;
     71     FT_ULong   tag, table_size;
     72     FT_ULong*  ptable_offset;
     73     FT_ULong*  ptable_size;
     74 
     75 
     76     if ( vertical )
     77     {
     78       tag           = TTAG_vmtx;
     79       ptable_offset = &face->vert_metrics_offset;
     80       ptable_size   = &face->vert_metrics_size;
     81     }
     82     else
     83     {
     84       tag           = TTAG_hmtx;
     85       ptable_offset = &face->horz_metrics_offset;
     86       ptable_size   = &face->horz_metrics_size;
     87     }
     88 
     89     error = face->goto_table( face, tag, stream, &table_size );
     90     if ( error )
     91       goto Fail;
     92 
     93     *ptable_size   = table_size;
     94     *ptable_offset = FT_STREAM_POS();
     95 
     96   Fail:
     97     return error;
     98   }
     99 
    100 #else /* !FT_CONFIG_OPTION_OLD_INTERNALS */
    101 
    102   FT_LOCAL_DEF( FT_Error )
    103   tt_face_load_hmtx( TT_Face    face,
    104                      FT_Stream  stream,
    105                      FT_Bool    vertical )
    106   {
    107     FT_Error   error;
    108     FT_Memory  memory = stream->memory;
    109 
    110     FT_ULong   table_len;
    111     FT_Long    num_shorts, num_longs, num_shorts_checked;
    112 
    113     TT_LongMetrics*    longs;
    114     TT_ShortMetrics**  shorts;
    115     FT_Byte*           p;
    116 
    117 
    118     if ( vertical )
    119     {
    120       void*   lm = &face->vertical.long_metrics;
    121       void**  sm = &face->vertical.short_metrics;
    122 
    123 
    124       error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
    125       if ( error )
    126         goto Fail;
    127 
    128       num_longs = face->vertical.number_Of_VMetrics;
    129       if ( (FT_ULong)num_longs > table_len / 4 )
    130         num_longs = (FT_Long)( table_len / 4 );
    131 
    132       face->vertical.number_Of_VMetrics = 0;
    133 
    134       longs  = (TT_LongMetrics*)lm;
    135       shorts = (TT_ShortMetrics**)sm;
    136     }
    137     else
    138     {
    139       void*   lm = &face->horizontal.long_metrics;
    140       void**  sm = &face->horizontal.short_metrics;
    141 
    142 
    143       error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
    144       if ( error )
    145         goto Fail;
    146 
    147       num_longs = face->horizontal.number_Of_HMetrics;
    148       if ( (FT_ULong)num_longs > table_len / 4 )
    149         num_longs = (FT_Long)( table_len / 4 );
    150 
    151       face->horizontal.number_Of_HMetrics = 0;
    152 
    153       longs  = (TT_LongMetrics*)lm;
    154       shorts = (TT_ShortMetrics**)sm;
    155     }
    156 
    157     /* never trust derived values */
    158 
    159     num_shorts         = face->max_profile.numGlyphs - num_longs;
    160     num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
    161 
    162     if ( num_shorts < 0 )
    163     {
    164       FT_TRACE0(( "tt_face_load_hmtx:"
    165                   " %cmtx has more metrics than glyphs.\n",
    166                   vertical ? "v" : "h" ));
    167 
    168       /* Adobe simply ignores this problem.  So we shall do the same. */
    169 #if 0
    170       error = vertical ? SFNT_Err_Invalid_Vert_Metrics
    171                        : SFNT_Err_Invalid_Horiz_Metrics;
    172       goto Exit;
    173 #else
    174       num_shorts = 0;
    175 #endif
    176     }
    177 
    178     if ( FT_QNEW_ARRAY( *longs,  num_longs  ) ||
    179          FT_QNEW_ARRAY( *shorts, num_shorts ) )
    180       goto Fail;
    181 
    182     if ( FT_FRAME_ENTER( table_len ) )
    183       goto Fail;
    184 
    185     p = stream->cursor;
    186 
    187     {
    188       TT_LongMetrics  cur   = *longs;
    189       TT_LongMetrics  limit = cur + num_longs;
    190 
    191 
    192       for ( ; cur < limit; cur++ )
    193       {
    194         cur->advance = FT_NEXT_USHORT( p );
    195         cur->bearing = FT_NEXT_SHORT( p );
    196       }
    197     }
    198 
    199     /* do we have an inconsistent number of metric values? */
    200     {
    201       TT_ShortMetrics*  cur   = *shorts;
    202       TT_ShortMetrics*  limit = cur +
    203                                 FT_MIN( num_shorts, num_shorts_checked );
    204 
    205 
    206       for ( ; cur < limit; cur++ )
    207         *cur = FT_NEXT_SHORT( p );
    208 
    209       /* We fill up the missing left side bearings with the     */
    210       /* last valid value.  Since this will occur for buggy CJK */
    211       /* fonts usually only, nothing serious will happen.       */
    212       if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
    213       {
    214         FT_Short  val = (*shorts)[num_shorts_checked - 1];
    215 
    216 
    217         limit = *shorts + num_shorts;
    218         for ( ; cur < limit; cur++ )
    219           *cur = val;
    220       }
    221     }
    222 
    223     FT_FRAME_EXIT();
    224 
    225     if ( vertical )
    226       face->vertical.number_Of_VMetrics = (FT_UShort)num_longs;
    227     else
    228       face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs;
    229 
    230   Fail:
    231     return error;
    232   }
    233 
    234 #endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */
    235 
    236 
    237   /*************************************************************************/
    238   /*                                                                       */
    239   /* <Function>                                                            */
    240   /*    tt_face_load_hhea                                                  */
    241   /*                                                                       */
    242   /* <Description>                                                         */
    243   /*    Load the `hhea' or 'vhea' table into a face object.                */
    244   /*                                                                       */
    245   /* <Input>                                                               */
    246   /*    face     :: A handle to the target face object.                    */
    247   /*                                                                       */
    248   /*    stream   :: The input stream.                                      */
    249   /*                                                                       */
    250   /*    vertical :: A boolean flag.  If set, load `vhea'.                  */
    251   /*                                                                       */
    252   /* <Return>                                                              */
    253   /*    FreeType error code.  0 means success.                             */
    254   /*                                                                       */
    255   FT_LOCAL_DEF( FT_Error )
    256   tt_face_load_hhea( TT_Face    face,
    257                      FT_Stream  stream,
    258                      FT_Bool    vertical )
    259   {
    260     FT_Error        error;
    261     TT_HoriHeader*  header;
    262 
    263     const FT_Frame_Field  metrics_header_fields[] =
    264     {
    265 #undef  FT_STRUCTURE
    266 #define FT_STRUCTURE  TT_HoriHeader
    267 
    268       FT_FRAME_START( 36 ),
    269         FT_FRAME_ULONG ( Version ),
    270         FT_FRAME_SHORT ( Ascender ),
    271         FT_FRAME_SHORT ( Descender ),
    272         FT_FRAME_SHORT ( Line_Gap ),
    273         FT_FRAME_USHORT( advance_Width_Max ),
    274         FT_FRAME_SHORT ( min_Left_Side_Bearing ),
    275         FT_FRAME_SHORT ( min_Right_Side_Bearing ),
    276         FT_FRAME_SHORT ( xMax_Extent ),
    277         FT_FRAME_SHORT ( caret_Slope_Rise ),
    278         FT_FRAME_SHORT ( caret_Slope_Run ),
    279         FT_FRAME_SHORT ( caret_Offset ),
    280         FT_FRAME_SHORT ( Reserved[0] ),
    281         FT_FRAME_SHORT ( Reserved[1] ),
    282         FT_FRAME_SHORT ( Reserved[2] ),
    283         FT_FRAME_SHORT ( Reserved[3] ),
    284         FT_FRAME_SHORT ( metric_Data_Format ),
    285         FT_FRAME_USHORT( number_Of_HMetrics ),
    286       FT_FRAME_END
    287     };
    288 
    289 
    290     if ( vertical )
    291     {
    292       void  *v = &face->vertical;
    293 
    294 
    295       error = face->goto_table( face, TTAG_vhea, stream, 0 );
    296       if ( error )
    297         goto Fail;
    298 
    299       header = (TT_HoriHeader*)v;
    300     }
    301     else
    302     {
    303       error = face->goto_table( face, TTAG_hhea, stream, 0 );
    304       if ( error )
    305         goto Fail;
    306 
    307       header = &face->horizontal;
    308     }
    309 
    310     if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
    311       goto Fail;
    312 
    313     FT_TRACE3(( "Ascender:          %5d\n", header->Ascender ));
    314     FT_TRACE3(( "Descender:         %5d\n", header->Descender ));
    315     FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics ));
    316 
    317     header->long_metrics  = NULL;
    318     header->short_metrics = NULL;
    319 
    320   Fail:
    321     return error;
    322   }
    323 
    324 
    325   /*************************************************************************/
    326   /*                                                                       */
    327   /* <Function>                                                            */
    328   /*    tt_face_get_metrics                                                */
    329   /*                                                                       */
    330   /* <Description>                                                         */
    331   /*    Returns the horizontal or vertical metrics in font units for a     */
    332   /*    given glyph.  The metrics are the left side bearing (resp. top     */
    333   /*    side bearing) and advance width (resp. advance height).            */
    334   /*                                                                       */
    335   /* <Input>                                                               */
    336   /*    header  :: A pointer to either the horizontal or vertical metrics  */
    337   /*               structure.                                              */
    338   /*                                                                       */
    339   /*    idx     :: The glyph index.                                        */
    340   /*                                                                       */
    341   /* <Output>                                                              */
    342   /*    bearing :: The bearing, either left side or top side.              */
    343   /*                                                                       */
    344   /*    advance :: The advance width resp. advance height.                 */
    345   /*                                                                       */
    346 #ifndef FT_CONFIG_OPTION_OLD_INTERNALS
    347 
    348   FT_LOCAL_DEF( FT_Error )
    349   tt_face_get_metrics( TT_Face     face,
    350                        FT_Bool     vertical,
    351                        FT_UInt     gindex,
    352                        FT_Short   *abearing,
    353                        FT_UShort  *aadvance )
    354   {
    355     FT_Error        error;
    356     FT_Stream       stream = face->root.stream;
    357     TT_HoriHeader*  header;
    358     FT_ULong        table_pos, table_size, table_end;
    359     FT_UShort       k;
    360 
    361 
    362     if ( vertical )
    363     {
    364       void*  v = &face->vertical;
    365 
    366 
    367       header     = (TT_HoriHeader*)v;
    368       table_pos  = face->vert_metrics_offset;
    369       table_size = face->vert_metrics_size;
    370     }
    371     else
    372     {
    373       header     = &face->horizontal;
    374       table_pos  = face->horz_metrics_offset;
    375       table_size = face->horz_metrics_size;
    376     }
    377 
    378     table_end = table_pos + table_size;
    379 
    380     k = header->number_Of_HMetrics;
    381 
    382     if ( k > 0 )
    383     {
    384       if ( gindex < (FT_UInt)k )
    385       {
    386         table_pos += 4 * gindex;
    387         if ( table_pos + 4 > table_end )
    388           goto NoData;
    389 
    390         if ( FT_STREAM_SEEK( table_pos ) ||
    391              FT_READ_USHORT( *aadvance ) ||
    392              FT_READ_SHORT( *abearing )  )
    393           goto NoData;
    394       }
    395       else
    396       {
    397         table_pos += 4 * ( k - 1 );
    398         if ( table_pos + 4 > table_end )
    399           goto NoData;
    400 
    401         if ( FT_STREAM_SEEK( table_pos ) ||
    402              FT_READ_USHORT( *aadvance ) )
    403           goto NoData;
    404 
    405         table_pos += 4 + 2 * ( gindex - k );
    406         if ( table_pos + 2 > table_end )
    407           *abearing = 0;
    408         else
    409         {
    410           if ( !FT_STREAM_SEEK( table_pos ) )
    411             (void)FT_READ_SHORT( *abearing );
    412         }
    413       }
    414     }
    415     else
    416     {
    417     NoData:
    418       *abearing = 0;
    419       *aadvance = 0;
    420     }
    421 
    422     return SFNT_Err_Ok;
    423   }
    424 
    425 #else /* !FT_CONFIG_OPTION_OLD_INTERNALS */
    426 
    427   FT_LOCAL_DEF( FT_Error )
    428   tt_face_get_metrics( TT_Face     face,
    429                        FT_Bool     vertical,
    430                        FT_UInt     gindex,
    431                        FT_Short*   abearing,
    432                        FT_UShort*  aadvance )
    433   {
    434     void*           v = &face->vertical;
    435     void*           h = &face->horizontal;
    436     TT_HoriHeader*  header = vertical ? (TT_HoriHeader*)v
    437                                       : (TT_HoriHeader*)h;
    438     TT_LongMetrics  longs_m;
    439     FT_UShort       k = header->number_Of_HMetrics;
    440 
    441 
    442     if ( k == 0                                         ||
    443          !header->long_metrics                          ||
    444          gindex >= (FT_UInt)face->max_profile.numGlyphs )
    445     {
    446       *abearing = *aadvance = 0;
    447       return SFNT_Err_Ok;
    448     }
    449 
    450     if ( gindex < (FT_UInt)k )
    451     {
    452       longs_m   = (TT_LongMetrics)header->long_metrics + gindex;
    453       *abearing = longs_m->bearing;
    454       *aadvance = longs_m->advance;
    455     }
    456     else
    457     {
    458       *abearing = ((TT_ShortMetrics*)header->short_metrics)[gindex - k];
    459       *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
    460     }
    461 
    462     return SFNT_Err_Ok;
    463   }
    464 
    465 #endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */
    466 
    467 
    468 /* END */
    469