1 /**************************************************************************** 2 * 3 * ttmtx.c 4 * 5 * Load the metrics tables common to TTF and OTF fonts (body). 6 * 7 * Copyright (C) 2006-2020 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 ) tt_face_load_hmtx(TT_Face face,FT_Stream stream,FT_Bool vertical)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 ) tt_face_load_hhea(TT_Face face,FT_Stream stream,FT_Bool vertical)129 tt_face_load_hhea( TT_Face face, 130 FT_Stream stream, 131 FT_Bool vertical ) 132 { 133 FT_Error error; 134 TT_HoriHeader* header; 135 136 static const FT_Frame_Field metrics_header_fields[] = 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 ) tt_face_get_metrics(TT_Face face,FT_Bool vertical,FT_UInt gindex,FT_Short * abearing,FT_UShort * aadvance)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* header; 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->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 ) 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