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 ) tt_face_load_hmtx(TT_Face face,FT_Stream stream,FT_Bool vertical)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 ) tt_face_load_hhea(TT_Face face,FT_Stream stream,FT_Bool vertical)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 ) tt_face_get_metrics(TT_Face face,FT_Bool vertical,FT_UInt gindex,FT_Short * abearing,FT_UShort * aadvance)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 + 2 > 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 *abearing = 0; 297 else 298 (void)FT_READ_SHORT( *abearing ); 299 } 300 } 301 } 302 else 303 { 304 NoData: 305 *abearing = 0; 306 *aadvance = 0; 307 } 308 309 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT 310 if ( var ) 311 { 312 FT_Face f = FT_FACE( face ); 313 FT_Int a = (FT_Int)*aadvance; 314 FT_Int b = (FT_Int)*abearing; 315 316 317 if ( vertical ) 318 { 319 if ( var->vadvance_adjust ) 320 var->vadvance_adjust( f, gindex, &a ); 321 if ( var->tsb_adjust ) 322 var->tsb_adjust( f, gindex, &b ); 323 } 324 else 325 { 326 if ( var->hadvance_adjust ) 327 var->hadvance_adjust( f, gindex, &a ); 328 if ( var->lsb_adjust ) 329 var->lsb_adjust( f, gindex, &b ); 330 } 331 332 *aadvance = (FT_UShort)a; 333 *abearing = (FT_Short)b; 334 } 335 #endif 336 } 337 338 339 /* END */ 340