1 /****************************************************************************
   2  *
   3  * ttmtx.c
   4  *
   5  *   Load the metrics tables common to TTF and OTF fonts (body).
   6  *
   7  * Copyright (C) 2006-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_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  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 */