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