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