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