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-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_TRUETYPE_TAGS_H
     23 
     24 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
     25 #include FT_SERVICE_METRICS_VARIATIONS_H
     26 #endif
     27 
     28 #include "ttmtx.h"
     29 
     30 #include "sferrors.h"
     31 
     32 
     33   /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should   */
     34   /*            be identical except for the names of their fields,      */
     35   /*            which are different.                                    */
     36   /*                                                                    */
     37   /*            This ensures that `tt_face_load_hmtx' is able to read   */
     38   /*            both the horizontal and vertical headers.               */
     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  trace_ttmtx
     49 
     50 
     51   /**************************************************************************
     52    *
     53    * @Function:
     54    *   tt_face_load_hmtx
     55    *
     56    * @Description:
     57    *   Load the `hmtx' or `vmtx' table into a face object.
     58    *
     59    * @Input:
     60    *   face ::
     61    *     A handle to the target face object.
     62    *
     63    *   stream ::
     64    *     The input stream.
     65    *
     66    *   vertical ::
     67    *     A boolean flag.  If set, load `vmtx'.
     68    *
     69    * @Return:
     70    *   FreeType error code.  0 means success.
     71    */
     72   FT_LOCAL_DEF( FT_Error )
     73   tt_face_load_hmtx( TT_Face    face,
     74                      FT_Stream  stream,
     75                      FT_Bool    vertical )
     76   {
     77     FT_Error   error;
     78     FT_ULong   tag, table_size;
     79     FT_ULong*  ptable_offset;
     80     FT_ULong*  ptable_size;
     81 
     82 
     83     if ( vertical )
     84     {
     85       tag           = TTAG_vmtx;
     86       ptable_offset = &face->vert_metrics_offset;
     87       ptable_size   = &face->vert_metrics_size;
     88     }
     89     else
     90     {
     91       tag           = TTAG_hmtx;
     92       ptable_offset = &face->horz_metrics_offset;
     93       ptable_size   = &face->horz_metrics_size;
     94     }
     95 
     96     error = face->goto_table( face, tag, stream, &table_size );
     97     if ( error )
     98       goto Fail;
     99 
    100     *ptable_size   = table_size;
    101     *ptable_offset = FT_STREAM_POS();
    102 
    103   Fail:
    104     return error;
    105   }
    106 
    107 
    108   /**************************************************************************
    109    *
    110    * @Function:
    111    *   tt_face_load_hhea
    112    *
    113    * @Description:
    114    *   Load the `hhea' or 'vhea' table into a face object.
    115    *
    116    * @Input:
    117    *   face ::
    118    *     A handle to the target face object.
    119    *
    120    *   stream ::
    121    *     The input stream.
    122    *
    123    *   vertical ::
    124    *     A boolean flag.  If set, load `vhea'.
    125    *
    126    * @Return:
    127    *   FreeType error code.  0 means success.
    128    */
    129   FT_LOCAL_DEF( FT_Error )
    130   tt_face_load_hhea( TT_Face    face,
    131                      FT_Stream  stream,
    132                      FT_Bool    vertical )
    133   {
    134     FT_Error        error;
    135     TT_HoriHeader*  header;
    136 
    137     static const FT_Frame_Field  metrics_header_fields[] =
    138     {
    139 #undef  FT_STRUCTURE
    140 #define FT_STRUCTURE  TT_HoriHeader
    141 
    142       FT_FRAME_START( 36 ),
    143         FT_FRAME_ULONG ( Version ),
    144         FT_FRAME_SHORT ( Ascender ),
    145         FT_FRAME_SHORT ( Descender ),
    146         FT_FRAME_SHORT ( Line_Gap ),
    147         FT_FRAME_USHORT( advance_Width_Max ),
    148         FT_FRAME_SHORT ( min_Left_Side_Bearing ),
    149         FT_FRAME_SHORT ( min_Right_Side_Bearing ),
    150         FT_FRAME_SHORT ( xMax_Extent ),
    151         FT_FRAME_SHORT ( caret_Slope_Rise ),
    152         FT_FRAME_SHORT ( caret_Slope_Run ),
    153         FT_FRAME_SHORT ( caret_Offset ),
    154         FT_FRAME_SHORT ( Reserved[0] ),
    155         FT_FRAME_SHORT ( Reserved[1] ),
    156         FT_FRAME_SHORT ( Reserved[2] ),
    157         FT_FRAME_SHORT ( Reserved[3] ),
    158         FT_FRAME_SHORT ( metric_Data_Format ),
    159         FT_FRAME_USHORT( number_Of_HMetrics ),
    160       FT_FRAME_END
    161     };
    162 
    163 
    164     if ( vertical )
    165     {
    166       void  *v = &face->vertical;
    167 
    168 
    169       error = face->goto_table( face, TTAG_vhea, stream, 0 );
    170       if ( error )
    171         goto Fail;
    172 
    173       header = (TT_HoriHeader*)v;
    174     }
    175     else
    176     {
    177       error = face->goto_table( face, TTAG_hhea, stream, 0 );
    178       if ( error )
    179         goto Fail;
    180 
    181       header = &face->horizontal;
    182     }
    183 
    184     if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
    185       goto Fail;
    186 
    187     FT_TRACE3(( "Ascender:          %5d\n", header->Ascender ));
    188     FT_TRACE3(( "Descender:         %5d\n", header->Descender ));
    189     FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics ));
    190 
    191     header->long_metrics  = NULL;
    192     header->short_metrics = NULL;
    193 
    194   Fail:
    195     return error;
    196   }
    197 
    198 
    199   /**************************************************************************
    200    *
    201    * @Function:
    202    *   tt_face_get_metrics
    203    *
    204    * @Description:
    205    *   Return the horizontal or vertical metrics in font units for a
    206    *   given glyph.  The values are the left side bearing (top side
    207    *   bearing for vertical metrics) and advance width (advance height
    208    *   for vertical metrics).
    209    *
    210    * @Input:
    211    *   face ::
    212    *     A pointer to the TrueType face structure.
    213    *
    214    *   vertical ::
    215    *     If set to TRUE, get vertical metrics.
    216    *
    217    *   gindex ::
    218    *     The glyph index.
    219    *
    220    * @Output:
    221    *   abearing ::
    222    *     The bearing, either left side or top side.
    223    *
    224    *   aadvance ::
    225    *     The advance width or advance height, depending on
    226    *     the `vertical' flag.
    227    */
    228   FT_LOCAL_DEF( void )
    229   tt_face_get_metrics( TT_Face     face,
    230                        FT_Bool     vertical,
    231                        FT_UInt     gindex,
    232                        FT_Short   *abearing,
    233                        FT_UShort  *aadvance )
    234   {
    235     FT_Error        error;
    236     FT_Stream       stream = face->root.stream;
    237     TT_HoriHeader*  header;
    238     FT_ULong        table_pos, table_size, table_end;
    239     FT_UShort       k;
    240 
    241 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
    242     FT_Service_MetricsVariations  var =
    243       (FT_Service_MetricsVariations)face->var;
    244 #endif
    245 
    246 
    247     if ( vertical )
    248     {
    249       void*  v = &face->vertical;
    250 
    251 
    252       header     = (TT_HoriHeader*)v;
    253       table_pos  = face->vert_metrics_offset;
    254       table_size = face->vert_metrics_size;
    255     }
    256     else
    257     {
    258       header     = &face->horizontal;
    259       table_pos  = face->horz_metrics_offset;
    260       table_size = face->horz_metrics_size;
    261     }
    262 
    263     table_end = table_pos + table_size;
    264 
    265     k = header->number_Of_HMetrics;
    266 
    267     if ( k > 0 )
    268     {
    269       if ( gindex < (FT_UInt)k )
    270       {
    271         table_pos += 4 * gindex;
    272         if ( table_pos + 4 > table_end )
    273           goto NoData;
    274 
    275         if ( FT_STREAM_SEEK( table_pos ) ||
    276              FT_READ_USHORT( *aadvance ) ||
    277              FT_READ_SHORT( *abearing )  )
    278           goto NoData;
    279       }
    280       else
    281       {
    282         table_pos += 4 * ( k - 1 );
    283         if ( table_pos + 4 > table_end )
    284           goto NoData;
    285 
    286         if ( FT_STREAM_SEEK( table_pos ) ||
    287              FT_READ_USHORT( *aadvance ) )
    288           goto NoData;
    289 
    290         table_pos += 4 + 2 * ( gindex - k );
    291         if ( table_pos + 2 > table_end )
    292           *abearing = 0;
    293         else
    294         {
    295           if ( !FT_STREAM_SEEK( table_pos ) )
    296             (void)FT_READ_SHORT( *abearing );
    297         }
    298       }
    299     }
    300     else
    301     {
    302     NoData:
    303       *abearing = 0;
    304       *aadvance = 0;
    305     }
    306 
    307 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
    308     if ( var )
    309     {
    310       FT_Face  f = FT_FACE( face );
    311       FT_Int   a = (FT_Int)*aadvance;
    312       FT_Int   b = (FT_Int)*abearing;
    313 
    314 
    315       if ( vertical )
    316       {
    317         if ( var->vadvance_adjust )
    318           var->vadvance_adjust( f, gindex, &a );
    319         if ( var->tsb_adjust )
    320           var->tsb_adjust( f, gindex, &b );
    321       }
    322       else
    323       {
    324         if ( var->hadvance_adjust )
    325           var->hadvance_adjust( f, gindex, &a );
    326         if ( var->lsb_adjust )
    327           var->lsb_adjust( f, gindex, &b );
    328       }
    329 
    330       *aadvance = (FT_UShort)a;
    331       *abearing = (FT_Short)b;
    332     }
    333 #endif
    334   }
    335 
    336 
    337 /* END */
    338