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