1 /***************************************************************************/ 2 /* */ 3 /* ttpload.c */ 4 /* */ 5 /* TrueType-specific tables loader (body). */ 6 /* */ 7 /* Copyright 1996-2015 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_OBJECTS_H 22 #include FT_INTERNAL_STREAM_H 23 #include FT_TRUETYPE_TAGS_H 24 25 #include "ttpload.h" 26 27 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT 28 #include "ttgxvar.h" 29 #endif 30 31 #include "tterrors.h" 32 33 34 /*************************************************************************/ 35 /* */ 36 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 37 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 38 /* messages during execution. */ 39 /* */ 40 #undef FT_COMPONENT 41 #define FT_COMPONENT trace_ttpload 42 43 44 /*************************************************************************/ 45 /* */ 46 /* <Function> */ 47 /* tt_face_load_loca */ 48 /* */ 49 /* <Description> */ 50 /* Load the locations table. */ 51 /* */ 52 /* <InOut> */ 53 /* face :: A handle to the target face object. */ 54 /* */ 55 /* <Input> */ 56 /* stream :: The input stream. */ 57 /* */ 58 /* <Return> */ 59 /* FreeType error code. 0 means success. */ 60 /* */ 61 FT_LOCAL_DEF( FT_Error ) tt_face_load_loca(TT_Face face,FT_Stream stream)62 tt_face_load_loca( TT_Face face, 63 FT_Stream stream ) 64 { 65 FT_Error error; 66 FT_ULong table_len; 67 FT_Int shift; 68 69 70 /* we need the size of the `glyf' table for malformed `loca' tables */ 71 error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); 72 73 /* it is possible that a font doesn't have a glyf table at all */ 74 /* or its size is zero */ 75 if ( FT_ERR_EQ( error, Table_Missing ) ) 76 face->glyf_len = 0; 77 else if ( error ) 78 goto Exit; 79 80 FT_TRACE2(( "Locations " )); 81 error = face->goto_table( face, TTAG_loca, stream, &table_len ); 82 if ( error ) 83 { 84 error = FT_THROW( Locations_Missing ); 85 goto Exit; 86 } 87 88 if ( face->header.Index_To_Loc_Format != 0 ) 89 { 90 shift = 2; 91 92 if ( table_len >= 0x40000L ) 93 { 94 FT_TRACE2(( "table too large\n" )); 95 error = FT_THROW( Invalid_Table ); 96 goto Exit; 97 } 98 face->num_locations = table_len >> shift; 99 } 100 else 101 { 102 shift = 1; 103 104 if ( table_len >= 0x20000L ) 105 { 106 FT_TRACE2(( "table too large\n" )); 107 error = FT_THROW( Invalid_Table ); 108 goto Exit; 109 } 110 face->num_locations = table_len >> shift; 111 } 112 113 if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 ) 114 { 115 FT_TRACE2(( "glyph count mismatch! loca: %d, maxp: %d\n", 116 face->num_locations - 1, face->root.num_glyphs )); 117 118 /* we only handle the case where `maxp' gives a larger value */ 119 if ( face->num_locations <= (FT_ULong)face->root.num_glyphs ) 120 { 121 FT_ULong new_loca_len = 122 ( (FT_ULong)face->root.num_glyphs + 1 ) << shift; 123 124 TT_Table entry = face->dir_tables; 125 TT_Table limit = entry + face->num_tables; 126 127 FT_Long pos = (FT_Long)FT_STREAM_POS(); 128 FT_Long dist = 0x7FFFFFFFL; 129 130 131 /* compute the distance to next table in font file */ 132 for ( ; entry < limit; entry++ ) 133 { 134 FT_Long diff = (FT_Long)entry->Offset - pos; 135 136 137 if ( diff > 0 && diff < dist ) 138 dist = diff; 139 } 140 141 if ( entry == limit ) 142 { 143 /* `loca' is the last table */ 144 dist = (FT_Long)stream->size - pos; 145 } 146 147 if ( new_loca_len <= (FT_ULong)dist ) 148 { 149 face->num_locations = (FT_ULong)face->root.num_glyphs + 1; 150 table_len = new_loca_len; 151 152 FT_TRACE2(( "adjusting num_locations to %d\n", 153 face->num_locations )); 154 } 155 } 156 } 157 158 /* 159 * Extract the frame. We don't need to decompress it since 160 * we are able to parse it directly. 161 */ 162 if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) ) 163 goto Exit; 164 165 FT_TRACE2(( "loaded\n" )); 166 167 Exit: 168 return error; 169 } 170 171 172 FT_LOCAL_DEF( FT_ULong ) tt_face_get_location(TT_Face face,FT_UInt gindex,FT_UInt * asize)173 tt_face_get_location( TT_Face face, 174 FT_UInt gindex, 175 FT_UInt *asize ) 176 { 177 FT_ULong pos1, pos2; 178 FT_Byte* p; 179 FT_Byte* p_limit; 180 181 182 pos1 = pos2 = 0; 183 184 if ( gindex < face->num_locations ) 185 { 186 if ( face->header.Index_To_Loc_Format != 0 ) 187 { 188 p = face->glyph_locations + gindex * 4; 189 p_limit = face->glyph_locations + face->num_locations * 4; 190 191 pos1 = FT_NEXT_ULONG( p ); 192 pos2 = pos1; 193 194 if ( p + 4 <= p_limit ) 195 pos2 = FT_NEXT_ULONG( p ); 196 } 197 else 198 { 199 p = face->glyph_locations + gindex * 2; 200 p_limit = face->glyph_locations + face->num_locations * 2; 201 202 pos1 = FT_NEXT_USHORT( p ); 203 pos2 = pos1; 204 205 if ( p + 2 <= p_limit ) 206 pos2 = FT_NEXT_USHORT( p ); 207 208 pos1 <<= 1; 209 pos2 <<= 1; 210 } 211 } 212 213 /* Check broken location data */ 214 if ( pos1 > face->glyf_len ) 215 { 216 FT_TRACE1(( "tt_face_get_location:" 217 " too large offset=0x%08lx found for gid=0x%04lx," 218 " exceeding the end of glyf table (0x%08lx)\n", 219 pos1, gindex, face->glyf_len )); 220 *asize = 0; 221 return 0; 222 } 223 224 if ( pos2 > face->glyf_len ) 225 { 226 FT_TRACE1(( "tt_face_get_location:" 227 " too large offset=0x%08lx found for gid=0x%04lx," 228 " truncate at the end of glyf table (0x%08lx)\n", 229 pos2, gindex + 1, face->glyf_len )); 230 pos2 = face->glyf_len; 231 } 232 233 /* The `loca' table must be ordered; it refers to the length of */ 234 /* an entry as the difference between the current and the next */ 235 /* position. However, there do exist (malformed) fonts which */ 236 /* don't obey this rule, so we are only able to provide an */ 237 /* upper bound for the size. */ 238 /* */ 239 /* We get (intentionally) a wrong, non-zero result in case the */ 240 /* `glyf' table is missing. */ 241 if ( pos2 >= pos1 ) 242 *asize = (FT_UInt)( pos2 - pos1 ); 243 else 244 *asize = (FT_UInt)( face->glyf_len - pos1 ); 245 246 return pos1; 247 } 248 249 250 FT_LOCAL_DEF( void ) tt_face_done_loca(TT_Face face)251 tt_face_done_loca( TT_Face face ) 252 { 253 FT_Stream stream = face->root.stream; 254 255 256 FT_FRAME_RELEASE( face->glyph_locations ); 257 face->num_locations = 0; 258 } 259 260 261 262 /*************************************************************************/ 263 /* */ 264 /* <Function> */ 265 /* tt_face_load_cvt */ 266 /* */ 267 /* <Description> */ 268 /* Load the control value table into a face object. */ 269 /* */ 270 /* <InOut> */ 271 /* face :: A handle to the target face object. */ 272 /* */ 273 /* <Input> */ 274 /* stream :: A handle to the input stream. */ 275 /* */ 276 /* <Return> */ 277 /* FreeType error code. 0 means success. */ 278 /* */ 279 FT_LOCAL_DEF( FT_Error ) tt_face_load_cvt(TT_Face face,FT_Stream stream)280 tt_face_load_cvt( TT_Face face, 281 FT_Stream stream ) 282 { 283 #ifdef TT_USE_BYTECODE_INTERPRETER 284 285 FT_Error error; 286 FT_Memory memory = stream->memory; 287 FT_ULong table_len; 288 289 290 FT_TRACE2(( "CVT " )); 291 292 error = face->goto_table( face, TTAG_cvt, stream, &table_len ); 293 if ( error ) 294 { 295 FT_TRACE2(( "is missing\n" )); 296 297 face->cvt_size = 0; 298 face->cvt = NULL; 299 error = FT_Err_Ok; 300 301 goto Exit; 302 } 303 304 face->cvt_size = table_len / 2; 305 306 if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) ) 307 goto Exit; 308 309 if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) 310 goto Exit; 311 312 { 313 FT_Short* cur = face->cvt; 314 FT_Short* limit = cur + face->cvt_size; 315 316 317 for ( ; cur < limit; cur++ ) 318 *cur = FT_GET_SHORT(); 319 } 320 321 FT_FRAME_EXIT(); 322 FT_TRACE2(( "loaded\n" )); 323 324 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT 325 if ( face->doblend ) 326 error = tt_face_vary_cvt( face, stream ); 327 #endif 328 329 Exit: 330 return error; 331 332 #else /* !TT_USE_BYTECODE_INTERPRETER */ 333 334 FT_UNUSED( face ); 335 FT_UNUSED( stream ); 336 337 return FT_Err_Ok; 338 339 #endif 340 } 341 342 343 /*************************************************************************/ 344 /* */ 345 /* <Function> */ 346 /* tt_face_load_fpgm */ 347 /* */ 348 /* <Description> */ 349 /* Load the font program. */ 350 /* */ 351 /* <InOut> */ 352 /* face :: A handle to the target face object. */ 353 /* */ 354 /* <Input> */ 355 /* stream :: A handle to the input stream. */ 356 /* */ 357 /* <Return> */ 358 /* FreeType error code. 0 means success. */ 359 /* */ 360 FT_LOCAL_DEF( FT_Error ) tt_face_load_fpgm(TT_Face face,FT_Stream stream)361 tt_face_load_fpgm( TT_Face face, 362 FT_Stream stream ) 363 { 364 #ifdef TT_USE_BYTECODE_INTERPRETER 365 366 FT_Error error; 367 FT_ULong table_len; 368 369 370 FT_TRACE2(( "Font program " )); 371 372 /* The font program is optional */ 373 error = face->goto_table( face, TTAG_fpgm, stream, &table_len ); 374 if ( error ) 375 { 376 face->font_program = NULL; 377 face->font_program_size = 0; 378 error = FT_Err_Ok; 379 380 FT_TRACE2(( "is missing\n" )); 381 } 382 else 383 { 384 face->font_program_size = table_len; 385 if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) 386 goto Exit; 387 388 FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size )); 389 } 390 391 Exit: 392 return error; 393 394 #else /* !TT_USE_BYTECODE_INTERPRETER */ 395 396 FT_UNUSED( face ); 397 FT_UNUSED( stream ); 398 399 return FT_Err_Ok; 400 401 #endif 402 } 403 404 405 /*************************************************************************/ 406 /* */ 407 /* <Function> */ 408 /* tt_face_load_prep */ 409 /* */ 410 /* <Description> */ 411 /* Load the cvt program. */ 412 /* */ 413 /* <InOut> */ 414 /* face :: A handle to the target face object. */ 415 /* */ 416 /* <Input> */ 417 /* stream :: A handle to the input stream. */ 418 /* */ 419 /* <Return> */ 420 /* FreeType error code. 0 means success. */ 421 /* */ 422 FT_LOCAL_DEF( FT_Error ) tt_face_load_prep(TT_Face face,FT_Stream stream)423 tt_face_load_prep( TT_Face face, 424 FT_Stream stream ) 425 { 426 #ifdef TT_USE_BYTECODE_INTERPRETER 427 428 FT_Error error; 429 FT_ULong table_len; 430 431 432 FT_TRACE2(( "Prep program " )); 433 434 error = face->goto_table( face, TTAG_prep, stream, &table_len ); 435 if ( error ) 436 { 437 face->cvt_program = NULL; 438 face->cvt_program_size = 0; 439 error = FT_Err_Ok; 440 441 FT_TRACE2(( "is missing\n" )); 442 } 443 else 444 { 445 face->cvt_program_size = table_len; 446 if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) 447 goto Exit; 448 449 FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size )); 450 } 451 452 Exit: 453 return error; 454 455 #else /* !TT_USE_BYTECODE_INTERPRETER */ 456 457 FT_UNUSED( face ); 458 FT_UNUSED( stream ); 459 460 return FT_Err_Ok; 461 462 #endif 463 } 464 465 466 /*************************************************************************/ 467 /* */ 468 /* <Function> */ 469 /* tt_face_load_hdmx */ 470 /* */ 471 /* <Description> */ 472 /* Load the `hdmx' table into the face object. */ 473 /* */ 474 /* <Input> */ 475 /* face :: A handle to the target face object. */ 476 /* */ 477 /* stream :: A handle to the input stream. */ 478 /* */ 479 /* <Return> */ 480 /* FreeType error code. 0 means success. */ 481 /* */ 482 483 FT_LOCAL_DEF( FT_Error ) tt_face_load_hdmx(TT_Face face,FT_Stream stream)484 tt_face_load_hdmx( TT_Face face, 485 FT_Stream stream ) 486 { 487 FT_Error error; 488 FT_Memory memory = stream->memory; 489 FT_UInt version, nn, num_records; 490 FT_ULong table_size, record_size; 491 FT_Byte* p; 492 FT_Byte* limit; 493 494 495 /* this table is optional */ 496 error = face->goto_table( face, TTAG_hdmx, stream, &table_size ); 497 if ( error || table_size < 8 ) 498 return FT_Err_Ok; 499 500 if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) ) 501 goto Exit; 502 503 p = face->hdmx_table; 504 limit = p + table_size; 505 506 version = FT_NEXT_USHORT( p ); 507 num_records = FT_NEXT_USHORT( p ); 508 record_size = FT_NEXT_ULONG( p ); 509 510 /* The maximum number of bytes in an hdmx device record is the */ 511 /* maximum number of glyphs + 2; this is 0xFFFF + 2, thus */ 512 /* explaining why `record_size' is a long (which we read as */ 513 /* unsigned long for convenience). In practice, two bytes are */ 514 /* sufficient to hold the size value. */ 515 /* */ 516 /* There are at least two fonts, HANNOM-A and HANNOM-B version */ 517 /* 2.0 (2005), which get this wrong: The upper two bytes of */ 518 /* the size value are set to 0xFF instead of 0x00. We catch */ 519 /* and fix this. */ 520 521 if ( record_size >= 0xFFFF0000UL ) 522 record_size &= 0xFFFFU; 523 524 /* The limit for `num_records' is a heuristic value. */ 525 if ( version != 0 || 526 num_records > 255 || 527 record_size > 0x10001L || 528 record_size < 4 ) 529 { 530 error = FT_THROW( Invalid_File_Format ); 531 goto Fail; 532 } 533 534 if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) ) 535 goto Fail; 536 537 for ( nn = 0; nn < num_records; nn++ ) 538 { 539 if ( p + record_size > limit ) 540 break; 541 542 face->hdmx_record_sizes[nn] = p[0]; 543 p += record_size; 544 } 545 546 face->hdmx_record_count = nn; 547 face->hdmx_table_size = table_size; 548 face->hdmx_record_size = record_size; 549 550 Exit: 551 return error; 552 553 Fail: 554 FT_FRAME_RELEASE( face->hdmx_table ); 555 face->hdmx_table_size = 0; 556 goto Exit; 557 } 558 559 560 FT_LOCAL_DEF( void ) tt_face_free_hdmx(TT_Face face)561 tt_face_free_hdmx( TT_Face face ) 562 { 563 FT_Stream stream = face->root.stream; 564 FT_Memory memory = stream->memory; 565 566 567 FT_FREE( face->hdmx_record_sizes ); 568 FT_FRAME_RELEASE( face->hdmx_table ); 569 } 570 571 572 /*************************************************************************/ 573 /* */ 574 /* Return the advance width table for a given pixel size if it is found */ 575 /* in the font's `hdmx' table (if any). */ 576 /* */ 577 FT_LOCAL_DEF( FT_Byte* ) tt_face_get_device_metrics(TT_Face face,FT_UInt ppem,FT_UInt gindex)578 tt_face_get_device_metrics( TT_Face face, 579 FT_UInt ppem, 580 FT_UInt gindex ) 581 { 582 FT_UInt nn; 583 FT_Byte* result = NULL; 584 FT_ULong record_size = face->hdmx_record_size; 585 FT_Byte* record = face->hdmx_table + 8; 586 587 588 for ( nn = 0; nn < face->hdmx_record_count; nn++ ) 589 if ( face->hdmx_record_sizes[nn] == ppem ) 590 { 591 gindex += 2; 592 if ( gindex < record_size ) 593 result = record + nn * record_size + gindex; 594 break; 595 } 596 597 return result; 598 } 599 600 601 /* END */ 602