1 /***************************************************************************/ 2 /* */ 3 /* ttobjs.c */ 4 /* */ 5 /* Objects manager (body). */ 6 /* */ 7 /* Copyright 1996-2011 */ 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_STREAM_H 22 #include FT_TRUETYPE_TAGS_H 23 #include FT_INTERNAL_SFNT_H 24 25 #include "ttgload.h" 26 #include "ttpload.h" 27 28 #include "tterrors.h" 29 30 #ifdef TT_USE_BYTECODE_INTERPRETER 31 #include "ttinterp.h" 32 #endif 33 34 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING 35 #include FT_TRUETYPE_UNPATENTED_H 36 #endif 37 38 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT 39 #include "ttgxvar.h" 40 #endif 41 42 /*************************************************************************/ 43 /* */ 44 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 45 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 46 /* messages during execution. */ 47 /* */ 48 #undef FT_COMPONENT 49 #define FT_COMPONENT trace_ttobjs 50 51 52 #ifdef TT_USE_BYTECODE_INTERPRETER 53 54 /*************************************************************************/ 55 /* */ 56 /* GLYPH ZONE FUNCTIONS */ 57 /* */ 58 /*************************************************************************/ 59 60 61 /*************************************************************************/ 62 /* */ 63 /* <Function> */ 64 /* tt_glyphzone_done */ 65 /* */ 66 /* <Description> */ 67 /* Deallocate a glyph zone. */ 68 /* */ 69 /* <Input> */ 70 /* zone :: A pointer to the target glyph zone. */ 71 /* */ 72 FT_LOCAL_DEF( void ) tt_glyphzone_done(TT_GlyphZone zone)73 tt_glyphzone_done( TT_GlyphZone zone ) 74 { 75 FT_Memory memory = zone->memory; 76 77 78 if ( memory ) 79 { 80 FT_FREE( zone->contours ); 81 FT_FREE( zone->tags ); 82 FT_FREE( zone->cur ); 83 FT_FREE( zone->org ); 84 FT_FREE( zone->orus ); 85 86 zone->max_points = zone->n_points = 0; 87 zone->max_contours = zone->n_contours = 0; 88 zone->memory = NULL; 89 } 90 } 91 92 93 /*************************************************************************/ 94 /* */ 95 /* <Function> */ 96 /* tt_glyphzone_new */ 97 /* */ 98 /* <Description> */ 99 /* Allocate a new glyph zone. */ 100 /* */ 101 /* <Input> */ 102 /* memory :: A handle to the current memory object. */ 103 /* */ 104 /* maxPoints :: The capacity of glyph zone in points. */ 105 /* */ 106 /* maxContours :: The capacity of glyph zone in contours. */ 107 /* */ 108 /* <Output> */ 109 /* zone :: A pointer to the target glyph zone record. */ 110 /* */ 111 /* <Return> */ 112 /* FreeType error code. 0 means success. */ 113 /* */ 114 FT_LOCAL_DEF( FT_Error ) tt_glyphzone_new(FT_Memory memory,FT_UShort maxPoints,FT_Short maxContours,TT_GlyphZone zone)115 tt_glyphzone_new( FT_Memory memory, 116 FT_UShort maxPoints, 117 FT_Short maxContours, 118 TT_GlyphZone zone ) 119 { 120 FT_Error error; 121 122 123 FT_MEM_ZERO( zone, sizeof ( *zone ) ); 124 zone->memory = memory; 125 126 if ( FT_NEW_ARRAY( zone->org, maxPoints ) || 127 FT_NEW_ARRAY( zone->cur, maxPoints ) || 128 FT_NEW_ARRAY( zone->orus, maxPoints ) || 129 FT_NEW_ARRAY( zone->tags, maxPoints ) || 130 FT_NEW_ARRAY( zone->contours, maxContours ) ) 131 { 132 tt_glyphzone_done( zone ); 133 } 134 else 135 { 136 zone->max_points = maxPoints; 137 zone->max_contours = maxContours; 138 } 139 140 return error; 141 } 142 #endif /* TT_USE_BYTECODE_INTERPRETER */ 143 144 145 /* Compare the face with a list of well-known `tricky' fonts. */ 146 /* This list shall be expanded as we find more of them. */ 147 148 static FT_Bool tt_check_trickyness_family(FT_String * name)149 tt_check_trickyness_family( FT_String* name ) 150 { 151 152 #define TRICK_NAMES_MAX_CHARACTERS 16 153 #define TRICK_NAMES_COUNT 8 154 155 static const char trick_names[TRICK_NAMES_COUNT] 156 [TRICK_NAMES_MAX_CHARACTERS + 1] = 157 { 158 "DFKaiSho-SB", /* dfkaisb.ttf */ 159 "DFKaiShu", 160 "DFKai-SB", /* kaiu.ttf */ 161 "HuaTianKaiTi?", /* htkt2.ttf */ 162 "HuaTianSongTi?", /* htst3.ttf */ 163 "MingLiU", /* mingliu.ttf & mingliu.ttc */ 164 "PMingLiU", /* mingliu.ttc */ 165 "MingLi43", /* mingli.ttf */ 166 }; 167 168 int nn; 169 170 171 for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ ) 172 if ( ft_strstr( name, trick_names[nn] ) ) 173 return TRUE; 174 175 return FALSE; 176 } 177 178 179 /* XXX: This function should be in the `sfnt' module. */ 180 181 /* Some PDF generators clear the checksums in the TrueType header table. */ 182 /* For example, Quartz ContextPDF clears all entries, or Bullzip PDF */ 183 /* Printer clears the entries for subsetted subtables. We thus have to */ 184 /* recalculate the checksums where necessary. */ 185 186 static FT_UInt32 tt_synth_sfnt_checksum(FT_Stream stream,FT_ULong length)187 tt_synth_sfnt_checksum( FT_Stream stream, 188 FT_ULong length ) 189 { 190 FT_Error error; 191 FT_UInt32 checksum = 0; 192 int i; 193 194 195 if ( FT_FRAME_ENTER( length ) ) 196 return 0; 197 198 for ( ; length > 3; length -= 4 ) 199 checksum += (FT_UInt32)FT_GET_ULONG(); 200 201 for ( i = 3; length > 0; length --, i-- ) 202 checksum += (FT_UInt32)( FT_GET_BYTE() << ( i * 8 ) ); 203 204 FT_FRAME_EXIT(); 205 206 return checksum; 207 } 208 209 210 /* XXX: This function should be in the `sfnt' module. */ 211 212 static FT_ULong tt_get_sfnt_checksum(TT_Face face,FT_UShort i)213 tt_get_sfnt_checksum( TT_Face face, 214 FT_UShort i ) 215 { 216 #if 0 /* if we believe the written value, use following part. */ 217 if ( face->dir_tables[i].CheckSum ) 218 return face->dir_tables[i].CheckSum; 219 #endif 220 221 if ( !face->goto_table ) 222 return 0; 223 224 if ( face->goto_table( face, 225 face->dir_tables[i].Tag, 226 face->root.stream, 227 NULL ) ) 228 return 0; 229 230 return (FT_ULong)tt_synth_sfnt_checksum( face->root.stream, 231 face->dir_tables[i].Length ); 232 } 233 234 235 typedef struct tt_sfnt_id_rec_ 236 { 237 FT_ULong CheckSum; 238 FT_ULong Length; 239 240 } tt_sfnt_id_rec; 241 242 243 static FT_Bool tt_check_trickyness_sfnt_ids(TT_Face face)244 tt_check_trickyness_sfnt_ids( TT_Face face ) 245 { 246 #define TRICK_SFNT_IDS_PER_FACE 3 247 #define TRICK_SFNT_IDS_NUM_FACES 13 248 249 static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES] 250 [TRICK_SFNT_IDS_PER_FACE] = { 251 252 #define TRICK_SFNT_ID_cvt 0 253 #define TRICK_SFNT_ID_fpgm 1 254 #define TRICK_SFNT_ID_prep 2 255 256 { /* MingLiU 1995 */ 257 { 0x05bcf058, 0x000002e4 }, /* cvt */ 258 { 0x28233bf1, 0x000087c4 }, /* fpgm */ 259 { 0xa344a1ea, 0x000001e1 } /* prep */ 260 }, 261 { /* MingLiU 1996- */ 262 { 0x05bcf058, 0x000002e4 }, /* cvt */ 263 { 0x28233bf1, 0x000087c4 }, /* fpgm */ 264 { 0xa344a1eb, 0x000001e1 } /* prep */ 265 }, 266 { /* DFKaiShu */ 267 { 0x11e5ead4, 0x00000350 }, /* cvt */ 268 { 0x5a30ca3b, 0x00009063 }, /* fpgm */ 269 { 0x13a42602, 0x0000007e } /* prep */ 270 }, 271 { /* HuaTianKaiTi */ 272 { 0xfffbfffc, 0x00000008 }, /* cvt */ 273 { 0x9c9e48b8, 0x0000bea2 }, /* fpgm */ 274 { 0x70020112, 0x00000008 } /* prep */ 275 }, 276 { /* HuaTianSongTi */ 277 { 0xfffbfffc, 0x00000008 }, /* cvt */ 278 { 0x0a5a0483, 0x00017c39 }, /* fpgm */ 279 { 0x70020112, 0x00000008 } /* prep */ 280 }, 281 { /* NEC fadpop7.ttf */ 282 { 0x00000000, 0x00000000 }, /* cvt */ 283 { 0x40c92555, 0x000000e5 }, /* fpgm */ 284 { 0xa39b58e3, 0x0000117c } /* prep */ 285 }, 286 { /* NEC fadrei5.ttf */ 287 { 0x00000000, 0x00000000 }, /* cvt */ 288 { 0x33c41652, 0x000000e5 }, /* fpgm */ 289 { 0x26d6c52a, 0x00000f6a } /* prep */ 290 }, 291 { /* NEC fangot7.ttf */ 292 { 0x00000000, 0x00000000 }, /* cvt */ 293 { 0x6db1651d, 0x0000019d }, /* fpgm */ 294 { 0x6c6e4b03, 0x00002492 } /* prep */ 295 }, 296 { /* NEC fangyo5.ttf */ 297 { 0x00000000, 0x00000000 }, /* cvt */ 298 { 0x40c92555, 0x000000e5 }, /* fpgm */ 299 { 0xde51fad0, 0x0000117c } /* prep */ 300 }, 301 { /* NEC fankyo5.ttf */ 302 { 0x00000000, 0x00000000 }, /* cvt */ 303 { 0x85e47664, 0x000000e5 }, /* fpgm */ 304 { 0xa6c62831, 0x00001caa } /* prep */ 305 }, 306 { /* NEC fanrgo5.ttf */ 307 { 0x00000000, 0x00000000 }, /* cvt */ 308 { 0x2d891cfd, 0x0000019d }, /* fpgm */ 309 { 0xa0604633, 0x00001de8 } /* prep */ 310 }, 311 { /* NEC fangot5.ttc */ 312 { 0x00000000, 0x00000000 }, /* cvt */ 313 { 0x40aa774c, 0x000001cb }, /* fpgm */ 314 { 0x9b5caa96, 0x00001f9a } /* prep */ 315 }, 316 { /* NEC fanmin3.ttc */ 317 { 0x00000000, 0x00000000 }, /* cvt */ 318 { 0x0d3de9cb, 0x00000141 }, /* fpgm */ 319 { 0xd4127766, 0x00002280 } /* prep */ 320 } 321 }; 322 323 FT_ULong checksum; 324 int num_matched_ids[TRICK_SFNT_IDS_NUM_FACES]; 325 FT_Bool has_cvt, has_fpgm, has_prep; 326 FT_UShort i; 327 int j, k; 328 329 330 FT_MEM_SET( num_matched_ids, 0, 331 sizeof ( int ) * TRICK_SFNT_IDS_NUM_FACES ); 332 has_cvt = FALSE; 333 has_fpgm = FALSE; 334 has_prep = FALSE; 335 336 for ( i = 0; i < face->num_tables; i++ ) 337 { 338 checksum = 0; 339 340 switch( face->dir_tables[i].Tag ) 341 { 342 case TTAG_cvt: 343 k = TRICK_SFNT_ID_cvt; 344 has_cvt = TRUE; 345 break; 346 347 case TTAG_fpgm: 348 k = TRICK_SFNT_ID_fpgm; 349 has_fpgm = TRUE; 350 break; 351 352 case TTAG_prep: 353 k = TRICK_SFNT_ID_prep; 354 has_prep = TRUE; 355 break; 356 357 default: 358 continue; 359 } 360 361 for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) 362 if ( face->dir_tables[i].Length == sfnt_id[j][k].Length ) 363 { 364 if ( !checksum ) 365 checksum = tt_get_sfnt_checksum( face, i ); 366 367 if ( sfnt_id[j][k].CheckSum == checksum ) 368 num_matched_ids[j]++; 369 370 if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) 371 return TRUE; 372 } 373 } 374 375 for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) 376 { 377 if ( !has_cvt && !sfnt_id[j][TRICK_SFNT_ID_cvt].Length ) 378 num_matched_ids[j] ++; 379 if ( !has_fpgm && !sfnt_id[j][TRICK_SFNT_ID_fpgm].Length ) 380 num_matched_ids[j] ++; 381 if ( !has_prep && !sfnt_id[j][TRICK_SFNT_ID_prep].Length ) 382 num_matched_ids[j] ++; 383 if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) 384 return TRUE; 385 } 386 387 return FALSE; 388 } 389 390 391 static FT_Bool tt_check_trickyness(FT_Face face)392 tt_check_trickyness( FT_Face face ) 393 { 394 if ( !face ) 395 return FALSE; 396 397 /* For first, check the face name for quick check. */ 398 if ( face->family_name && 399 tt_check_trickyness_family( face->family_name ) ) 400 return TRUE; 401 402 /* Type42 fonts may lack `name' tables, we thus try to identify */ 403 /* tricky fonts by checking the checksums of Type42-persistent */ 404 /* sfnt tables (`cvt', `fpgm', and `prep'). */ 405 if ( tt_check_trickyness_sfnt_ids( (TT_Face)face ) ) 406 return TRUE; 407 408 return FALSE; 409 } 410 411 412 /* Check whether `.notdef' is the only glyph in the `loca' table. */ 413 static FT_Bool tt_check_single_notdef(FT_Face ttface)414 tt_check_single_notdef( FT_Face ttface ) 415 { 416 FT_Bool result = FALSE; 417 418 TT_Face face = (TT_Face)ttface; 419 FT_UInt asize; 420 FT_ULong i; 421 FT_ULong glyph_index = 0; 422 FT_UInt count = 0; 423 424 425 for( i = 0; i < face->num_locations; i++ ) 426 { 427 tt_face_get_location( face, i, &asize ); 428 if ( asize > 0 ) 429 { 430 count += 1; 431 if ( count > 1 ) 432 break; 433 glyph_index = i; 434 } 435 } 436 437 /* Only have a single outline. */ 438 if ( count == 1 ) 439 { 440 if ( glyph_index == 0 ) 441 result = TRUE; 442 else 443 { 444 /* FIXME: Need to test glyphname == .notdef ? */ 445 FT_Error error; 446 char buf[8]; 447 448 449 error = FT_Get_Glyph_Name( ttface, glyph_index, buf, 8 ); 450 if ( !error && 451 buf[0] == '.' && !ft_strncmp( buf, ".notdef", 8 ) ) 452 result = TRUE; 453 } 454 } 455 456 return result; 457 } 458 459 460 /*************************************************************************/ 461 /* */ 462 /* <Function> */ 463 /* tt_face_init */ 464 /* */ 465 /* <Description> */ 466 /* Initialize a given TrueType face object. */ 467 /* */ 468 /* <Input> */ 469 /* stream :: The source font stream. */ 470 /* */ 471 /* face_index :: The index of the font face in the resource. */ 472 /* */ 473 /* num_params :: Number of additional generic parameters. Ignored. */ 474 /* */ 475 /* params :: Additional generic parameters. Ignored. */ 476 /* */ 477 /* <InOut> */ 478 /* face :: The newly built face object. */ 479 /* */ 480 /* <Return> */ 481 /* FreeType error code. 0 means success. */ 482 /* */ 483 FT_LOCAL_DEF( FT_Error ) tt_face_init(FT_Stream stream,FT_Face ttface,FT_Int face_index,FT_Int num_params,FT_Parameter * params)484 tt_face_init( FT_Stream stream, 485 FT_Face ttface, /* TT_Face */ 486 FT_Int face_index, 487 FT_Int num_params, 488 FT_Parameter* params ) 489 { 490 FT_Error error; 491 FT_Library library; 492 SFNT_Service sfnt; 493 TT_Face face = (TT_Face)ttface; 494 495 496 FT_TRACE2(( "TTF driver\n" )); 497 498 library = ttface->driver->root.library; 499 500 sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); 501 if ( !sfnt ) 502 { 503 FT_ERROR(( "tt_face_init: cannot access `sfnt' module\n" )); 504 error = TT_Err_Missing_Module; 505 goto Exit; 506 } 507 508 /* create input stream from resource */ 509 if ( FT_STREAM_SEEK( 0 ) ) 510 goto Exit; 511 512 /* check that we have a valid TrueType file */ 513 error = sfnt->init_face( stream, face, face_index, num_params, params ); 514 if ( error ) 515 goto Exit; 516 517 /* We must also be able to accept Mac/GX fonts, as well as OT ones. */ 518 /* The 0x00020000 tag is completely undocumented; some fonts from */ 519 /* Arphic made for Chinese Windows 3.1 have this. */ 520 if ( face->format_tag != 0x00010000L && /* MS fonts */ 521 face->format_tag != 0x00020000L && /* CJK fonts for Win 3.1 */ 522 face->format_tag != TTAG_true ) /* Mac fonts */ 523 { 524 FT_TRACE2(( " not a TTF font\n" )); 525 goto Bad_Format; 526 } 527 528 #ifdef TT_USE_BYTECODE_INTERPRETER 529 ttface->face_flags |= FT_FACE_FLAG_HINTER; 530 #endif 531 532 /* If we are performing a simple font format check, exit immediately. */ 533 if ( face_index < 0 ) 534 return TT_Err_Ok; 535 536 /* Load font directory */ 537 error = sfnt->load_face( stream, face, face_index, num_params, params ); 538 if ( error ) 539 goto Exit; 540 541 if ( tt_check_trickyness( ttface ) ) 542 ttface->face_flags |= FT_FACE_FLAG_TRICKY; 543 544 error = tt_face_load_hdmx( face, stream ); 545 if ( error ) 546 goto Exit; 547 548 if ( FT_IS_SCALABLE( ttface ) ) 549 { 550 551 #ifdef FT_CONFIG_OPTION_INCREMENTAL 552 553 if ( !ttface->internal->incremental_interface ) 554 error = tt_face_load_loca( face, stream ); 555 if ( !error ) 556 error = tt_face_load_cvt( face, stream ); 557 if ( !error ) 558 error = tt_face_load_fpgm( face, stream ); 559 if ( !error ) 560 error = tt_face_load_prep( face, stream ); 561 562 /* Check the scalable flag based on `loca'. */ 563 if ( !ttface->internal->incremental_interface && 564 ttface->num_fixed_sizes && 565 face->glyph_locations && 566 tt_check_single_notdef( ttface ) ) 567 { 568 FT_TRACE5(( "tt_face_init:" 569 " Only the `.notdef' glyph has an outline.\n" 570 " " 571 " Resetting scalable flag to FALSE.\n" )); 572 573 ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; 574 } 575 576 #else 577 578 if ( !error ) 579 error = tt_face_load_loca( face, stream ); 580 if ( !error ) 581 error = tt_face_load_cvt( face, stream ); 582 if ( !error ) 583 error = tt_face_load_fpgm( face, stream ); 584 if ( !error ) 585 error = tt_face_load_prep( face, stream ); 586 587 /* Check the scalable flag based on `loca'. */ 588 if ( ttface->num_fixed_sizes && 589 face->glyph_locations && 590 tt_check_single_notdef( ttface ) ) 591 { 592 FT_TRACE5(( "tt_face_init:" 593 " Only the `.notdef' glyph has an outline.\n" 594 " " 595 " Resetting scalable flag to FALSE.\n" )); 596 597 ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; 598 } 599 600 #endif 601 602 } 603 604 #if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING ) && \ 605 !defined( TT_CONFIG_OPTION_BYTECODE_INTERPRETER ) 606 607 { 608 FT_Bool unpatented_hinting; 609 int i; 610 611 612 /* Determine whether unpatented hinting is to be used for this face. */ 613 unpatented_hinting = FT_BOOL 614 ( library->debug_hooks[FT_DEBUG_HOOK_UNPATENTED_HINTING] != NULL ); 615 616 for ( i = 0; i < num_params && !face->unpatented_hinting; i++ ) 617 if ( params[i].tag == FT_PARAM_TAG_UNPATENTED_HINTING ) 618 unpatented_hinting = TRUE; 619 620 if ( !unpatented_hinting ) 621 ttface->internal->ignore_unpatented_hinter = TRUE; 622 } 623 624 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING && 625 !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ 626 627 /* initialize standard glyph loading routines */ 628 TT_Init_Glyph_Loading( face ); 629 630 Exit: 631 return error; 632 633 Bad_Format: 634 error = TT_Err_Unknown_File_Format; 635 goto Exit; 636 } 637 638 639 /*************************************************************************/ 640 /* */ 641 /* <Function> */ 642 /* tt_face_done */ 643 /* */ 644 /* <Description> */ 645 /* Finalize a given face object. */ 646 /* */ 647 /* <Input> */ 648 /* face :: A pointer to the face object to destroy. */ 649 /* */ 650 FT_LOCAL_DEF( void ) tt_face_done(FT_Face ttface)651 tt_face_done( FT_Face ttface ) /* TT_Face */ 652 { 653 TT_Face face = (TT_Face)ttface; 654 FT_Memory memory; 655 FT_Stream stream; 656 SFNT_Service sfnt; 657 658 659 if ( !face ) 660 return; 661 662 memory = ttface->memory; 663 stream = ttface->stream; 664 sfnt = (SFNT_Service)face->sfnt; 665 666 /* for `extended TrueType formats' (i.e. compressed versions) */ 667 if ( face->extra.finalizer ) 668 face->extra.finalizer( face->extra.data ); 669 670 if ( sfnt ) 671 sfnt->done_face( face ); 672 673 /* freeing the locations table */ 674 tt_face_done_loca( face ); 675 676 tt_face_free_hdmx( face ); 677 678 /* freeing the CVT */ 679 FT_FREE( face->cvt ); 680 face->cvt_size = 0; 681 682 /* freeing the programs */ 683 FT_FRAME_RELEASE( face->font_program ); 684 FT_FRAME_RELEASE( face->cvt_program ); 685 face->font_program_size = 0; 686 face->cvt_program_size = 0; 687 688 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT 689 tt_done_blend( memory, face->blend ); 690 face->blend = NULL; 691 #endif 692 } 693 694 695 /*************************************************************************/ 696 /* */ 697 /* SIZE FUNCTIONS */ 698 /* */ 699 /*************************************************************************/ 700 701 #ifdef TT_USE_BYTECODE_INTERPRETER 702 703 /*************************************************************************/ 704 /* */ 705 /* <Function> */ 706 /* tt_size_run_fpgm */ 707 /* */ 708 /* <Description> */ 709 /* Run the font program. */ 710 /* */ 711 /* <Input> */ 712 /* size :: A handle to the size object. */ 713 /* */ 714 /* pedantic :: Set if bytecode execution should be pedantic. */ 715 /* */ 716 /* <Return> */ 717 /* FreeType error code. 0 means success. */ 718 /* */ 719 FT_LOCAL_DEF( FT_Error ) tt_size_run_fpgm(TT_Size size,FT_Bool pedantic)720 tt_size_run_fpgm( TT_Size size, 721 FT_Bool pedantic ) 722 { 723 TT_Face face = (TT_Face)size->root.face; 724 TT_ExecContext exec; 725 FT_Error error; 726 727 728 /* debugging instances have their own context */ 729 if ( size->debug ) 730 exec = size->context; 731 else 732 exec = ( (TT_Driver)FT_FACE_DRIVER( face ) )->context; 733 734 if ( !exec ) 735 return TT_Err_Could_Not_Find_Context; 736 737 TT_Load_Context( exec, face, size ); 738 739 exec->callTop = 0; 740 exec->top = 0; 741 742 exec->period = 64; 743 exec->phase = 0; 744 exec->threshold = 0; 745 746 exec->instruction_trap = FALSE; 747 exec->F_dot_P = 0x10000L; 748 749 exec->pedantic_hinting = pedantic; 750 751 { 752 FT_Size_Metrics* metrics = &exec->metrics; 753 TT_Size_Metrics* tt_metrics = &exec->tt_metrics; 754 755 756 metrics->x_ppem = 0; 757 metrics->y_ppem = 0; 758 metrics->x_scale = 0; 759 metrics->y_scale = 0; 760 761 tt_metrics->ppem = 0; 762 tt_metrics->scale = 0; 763 tt_metrics->ratio = 0x10000L; 764 } 765 766 /* allow font program execution */ 767 TT_Set_CodeRange( exec, 768 tt_coderange_font, 769 face->font_program, 770 face->font_program_size ); 771 772 /* disable CVT and glyph programs coderange */ 773 TT_Clear_CodeRange( exec, tt_coderange_cvt ); 774 TT_Clear_CodeRange( exec, tt_coderange_glyph ); 775 776 if ( face->font_program_size > 0 ) 777 { 778 error = TT_Goto_CodeRange( exec, tt_coderange_font, 0 ); 779 780 if ( !error ) 781 { 782 FT_TRACE4(( "Executing `fpgm' table.\n" )); 783 784 error = face->interpreter( exec ); 785 } 786 } 787 else 788 error = TT_Err_Ok; 789 790 if ( !error ) 791 TT_Save_Context( exec, size ); 792 793 return error; 794 } 795 796 797 /*************************************************************************/ 798 /* */ 799 /* <Function> */ 800 /* tt_size_run_prep */ 801 /* */ 802 /* <Description> */ 803 /* Run the control value program. */ 804 /* */ 805 /* <Input> */ 806 /* size :: A handle to the size object. */ 807 /* */ 808 /* pedantic :: Set if bytecode execution should be pedantic. */ 809 /* */ 810 /* <Return> */ 811 /* FreeType error code. 0 means success. */ 812 /* */ 813 FT_LOCAL_DEF( FT_Error ) tt_size_run_prep(TT_Size size,FT_Bool pedantic)814 tt_size_run_prep( TT_Size size, 815 FT_Bool pedantic ) 816 { 817 TT_Face face = (TT_Face)size->root.face; 818 TT_ExecContext exec; 819 FT_Error error; 820 821 822 /* debugging instances have their own context */ 823 if ( size->debug ) 824 exec = size->context; 825 else 826 exec = ( (TT_Driver)FT_FACE_DRIVER( face ) )->context; 827 828 if ( !exec ) 829 return TT_Err_Could_Not_Find_Context; 830 831 TT_Load_Context( exec, face, size ); 832 833 exec->callTop = 0; 834 exec->top = 0; 835 836 exec->instruction_trap = FALSE; 837 838 exec->pedantic_hinting = pedantic; 839 840 TT_Set_CodeRange( exec, 841 tt_coderange_cvt, 842 face->cvt_program, 843 face->cvt_program_size ); 844 845 TT_Clear_CodeRange( exec, tt_coderange_glyph ); 846 847 if ( face->cvt_program_size > 0 ) 848 { 849 error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); 850 851 if ( !error && !size->debug ) 852 { 853 FT_TRACE4(( "Executing `prep' table.\n" )); 854 855 error = face->interpreter( exec ); 856 } 857 } 858 else 859 error = TT_Err_Ok; 860 861 /* save as default graphics state */ 862 size->GS = exec->GS; 863 864 TT_Save_Context( exec, size ); 865 866 return error; 867 } 868 869 #endif /* TT_USE_BYTECODE_INTERPRETER */ 870 871 872 #ifdef TT_USE_BYTECODE_INTERPRETER 873 874 static void tt_size_done_bytecode(FT_Size ftsize)875 tt_size_done_bytecode( FT_Size ftsize ) 876 { 877 TT_Size size = (TT_Size)ftsize; 878 TT_Face face = (TT_Face)ftsize->face; 879 FT_Memory memory = face->root.memory; 880 881 882 if ( size->debug ) 883 { 884 /* the debug context must be deleted by the debugger itself */ 885 size->context = NULL; 886 size->debug = FALSE; 887 } 888 889 FT_FREE( size->cvt ); 890 size->cvt_size = 0; 891 892 /* free storage area */ 893 FT_FREE( size->storage ); 894 size->storage_size = 0; 895 896 /* twilight zone */ 897 tt_glyphzone_done( &size->twilight ); 898 899 FT_FREE( size->function_defs ); 900 FT_FREE( size->instruction_defs ); 901 902 size->num_function_defs = 0; 903 size->max_function_defs = 0; 904 size->num_instruction_defs = 0; 905 size->max_instruction_defs = 0; 906 907 size->max_func = 0; 908 size->max_ins = 0; 909 910 size->bytecode_ready = 0; 911 size->cvt_ready = 0; 912 } 913 914 915 /* Initialize bytecode-related fields in the size object. */ 916 /* We do this only if bytecode interpretation is really needed. */ 917 static FT_Error tt_size_init_bytecode(FT_Size ftsize,FT_Bool pedantic)918 tt_size_init_bytecode( FT_Size ftsize, 919 FT_Bool pedantic ) 920 { 921 FT_Error error; 922 TT_Size size = (TT_Size)ftsize; 923 TT_Face face = (TT_Face)ftsize->face; 924 FT_Memory memory = face->root.memory; 925 FT_Int i; 926 927 FT_UShort n_twilight; 928 TT_MaxProfile* maxp = &face->max_profile; 929 930 931 size->bytecode_ready = 1; 932 size->cvt_ready = 0; 933 934 size->max_function_defs = maxp->maxFunctionDefs; 935 size->max_instruction_defs = maxp->maxInstructionDefs; 936 937 size->num_function_defs = 0; 938 size->num_instruction_defs = 0; 939 940 size->max_func = 0; 941 size->max_ins = 0; 942 943 size->cvt_size = face->cvt_size; 944 size->storage_size = maxp->maxStorage; 945 946 /* Set default metrics */ 947 { 948 TT_Size_Metrics* metrics = &size->ttmetrics; 949 950 951 metrics->rotated = FALSE; 952 metrics->stretched = FALSE; 953 954 /* set default compensation (all 0) */ 955 for ( i = 0; i < 4; i++ ) 956 metrics->compensations[i] = 0; 957 } 958 959 /* allocate function defs, instruction defs, cvt, and storage area */ 960 if ( FT_NEW_ARRAY( size->function_defs, size->max_function_defs ) || 961 FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) || 962 FT_NEW_ARRAY( size->cvt, size->cvt_size ) || 963 FT_NEW_ARRAY( size->storage, size->storage_size ) ) 964 goto Exit; 965 966 /* reserve twilight zone */ 967 n_twilight = maxp->maxTwilightPoints; 968 969 /* there are 4 phantom points (do we need this?) */ 970 n_twilight += 4; 971 972 error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight ); 973 if ( error ) 974 goto Exit; 975 976 size->twilight.n_points = n_twilight; 977 978 size->GS = tt_default_graphics_state; 979 980 /* set `face->interpreter' according to the debug hook present */ 981 { 982 FT_Library library = face->root.driver->root.library; 983 984 985 face->interpreter = (TT_Interpreter) 986 library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; 987 if ( !face->interpreter ) 988 face->interpreter = (TT_Interpreter)TT_RunIns; 989 } 990 991 /* Fine, now run the font program! */ 992 error = tt_size_run_fpgm( size, pedantic ); 993 994 Exit: 995 if ( error ) 996 tt_size_done_bytecode( ftsize ); 997 998 return error; 999 } 1000 1001 1002 FT_LOCAL_DEF( FT_Error ) tt_size_ready_bytecode(TT_Size size,FT_Bool pedantic)1003 tt_size_ready_bytecode( TT_Size size, 1004 FT_Bool pedantic ) 1005 { 1006 FT_Error error = TT_Err_Ok; 1007 1008 1009 if ( !size->bytecode_ready ) 1010 { 1011 error = tt_size_init_bytecode( (FT_Size)size, pedantic ); 1012 if ( error ) 1013 goto Exit; 1014 } 1015 1016 /* rescale CVT when needed */ 1017 if ( !size->cvt_ready ) 1018 { 1019 FT_UInt i; 1020 TT_Face face = (TT_Face)size->root.face; 1021 1022 1023 /* Scale the cvt values to the new ppem. */ 1024 /* We use by default the y ppem to scale the CVT. */ 1025 for ( i = 0; i < size->cvt_size; i++ ) 1026 size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); 1027 1028 /* all twilight points are originally zero */ 1029 for ( i = 0; i < (FT_UInt)size->twilight.n_points; i++ ) 1030 { 1031 size->twilight.org[i].x = 0; 1032 size->twilight.org[i].y = 0; 1033 size->twilight.cur[i].x = 0; 1034 size->twilight.cur[i].y = 0; 1035 } 1036 1037 /* clear storage area */ 1038 for ( i = 0; i < (FT_UInt)size->storage_size; i++ ) 1039 size->storage[i] = 0; 1040 1041 size->GS = tt_default_graphics_state; 1042 1043 error = tt_size_run_prep( size, pedantic ); 1044 if ( !error ) 1045 size->cvt_ready = 1; 1046 } 1047 1048 Exit: 1049 return error; 1050 } 1051 1052 #endif /* TT_USE_BYTECODE_INTERPRETER */ 1053 1054 1055 /*************************************************************************/ 1056 /* */ 1057 /* <Function> */ 1058 /* tt_size_init */ 1059 /* */ 1060 /* <Description> */ 1061 /* Initialize a new TrueType size object. */ 1062 /* */ 1063 /* <InOut> */ 1064 /* size :: A handle to the size object. */ 1065 /* */ 1066 /* <Return> */ 1067 /* FreeType error code. 0 means success. */ 1068 /* */ 1069 FT_LOCAL_DEF( FT_Error ) tt_size_init(FT_Size ttsize)1070 tt_size_init( FT_Size ttsize ) /* TT_Size */ 1071 { 1072 TT_Size size = (TT_Size)ttsize; 1073 FT_Error error = TT_Err_Ok; 1074 1075 #ifdef TT_USE_BYTECODE_INTERPRETER 1076 size->bytecode_ready = 0; 1077 size->cvt_ready = 0; 1078 #endif 1079 1080 size->ttmetrics.valid = FALSE; 1081 size->strike_index = 0xFFFFFFFFUL; 1082 1083 return error; 1084 } 1085 1086 1087 /*************************************************************************/ 1088 /* */ 1089 /* <Function> */ 1090 /* tt_size_done */ 1091 /* */ 1092 /* <Description> */ 1093 /* The TrueType size object finalizer. */ 1094 /* */ 1095 /* <Input> */ 1096 /* size :: A handle to the target size object. */ 1097 /* */ 1098 FT_LOCAL_DEF( void ) tt_size_done(FT_Size ttsize)1099 tt_size_done( FT_Size ttsize ) /* TT_Size */ 1100 { 1101 TT_Size size = (TT_Size)ttsize; 1102 1103 1104 #ifdef TT_USE_BYTECODE_INTERPRETER 1105 if ( size->bytecode_ready ) 1106 tt_size_done_bytecode( ttsize ); 1107 #endif 1108 1109 size->ttmetrics.valid = FALSE; 1110 } 1111 1112 1113 /*************************************************************************/ 1114 /* */ 1115 /* <Function> */ 1116 /* tt_size_reset */ 1117 /* */ 1118 /* <Description> */ 1119 /* Reset a TrueType size when resolutions and character dimensions */ 1120 /* have been changed. */ 1121 /* */ 1122 /* <Input> */ 1123 /* size :: A handle to the target size object. */ 1124 /* */ 1125 FT_LOCAL_DEF( FT_Error ) tt_size_reset(TT_Size size)1126 tt_size_reset( TT_Size size ) 1127 { 1128 TT_Face face; 1129 FT_Error error = TT_Err_Ok; 1130 FT_Size_Metrics* metrics; 1131 1132 1133 size->ttmetrics.valid = FALSE; 1134 1135 face = (TT_Face)size->root.face; 1136 1137 metrics = &size->metrics; 1138 1139 /* copy the result from base layer */ 1140 *metrics = size->root.metrics; 1141 1142 if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 ) 1143 return TT_Err_Invalid_PPem; 1144 1145 /* This bit flag, if set, indicates that the ppems must be */ 1146 /* rounded to integers. Nearly all TrueType fonts have this bit */ 1147 /* set, as hinting won't work really well otherwise. */ 1148 /* */ 1149 if ( face->header.Flags & 8 ) 1150 { 1151 metrics->x_scale = FT_DivFix( metrics->x_ppem << 6, 1152 face->root.units_per_EM ); 1153 metrics->y_scale = FT_DivFix( metrics->y_ppem << 6, 1154 face->root.units_per_EM ); 1155 1156 metrics->ascender = 1157 FT_PIX_ROUND( FT_MulFix( face->root.ascender, metrics->y_scale ) ); 1158 metrics->descender = 1159 FT_PIX_ROUND( FT_MulFix( face->root.descender, metrics->y_scale ) ); 1160 metrics->height = 1161 FT_PIX_ROUND( FT_MulFix( face->root.height, metrics->y_scale ) ); 1162 metrics->max_advance = 1163 FT_PIX_ROUND( FT_MulFix( face->root.max_advance_width, 1164 metrics->x_scale ) ); 1165 } 1166 1167 /* compute new transformation */ 1168 if ( metrics->x_ppem >= metrics->y_ppem ) 1169 { 1170 size->ttmetrics.scale = metrics->x_scale; 1171 size->ttmetrics.ppem = metrics->x_ppem; 1172 size->ttmetrics.x_ratio = 0x10000L; 1173 size->ttmetrics.y_ratio = FT_MulDiv( metrics->y_ppem, 1174 0x10000L, 1175 metrics->x_ppem ); 1176 } 1177 else 1178 { 1179 size->ttmetrics.scale = metrics->y_scale; 1180 size->ttmetrics.ppem = metrics->y_ppem; 1181 size->ttmetrics.x_ratio = FT_MulDiv( metrics->x_ppem, 1182 0x10000L, 1183 metrics->y_ppem ); 1184 size->ttmetrics.y_ratio = 0x10000L; 1185 } 1186 1187 #ifdef TT_USE_BYTECODE_INTERPRETER 1188 size->cvt_ready = 0; 1189 #endif /* TT_USE_BYTECODE_INTERPRETER */ 1190 1191 if ( !error ) 1192 size->ttmetrics.valid = TRUE; 1193 1194 return error; 1195 } 1196 1197 1198 /*************************************************************************/ 1199 /* */ 1200 /* <Function> */ 1201 /* tt_driver_init */ 1202 /* */ 1203 /* <Description> */ 1204 /* Initialize a given TrueType driver object. */ 1205 /* */ 1206 /* <Input> */ 1207 /* driver :: A handle to the target driver object. */ 1208 /* */ 1209 /* <Return> */ 1210 /* FreeType error code. 0 means success. */ 1211 /* */ 1212 FT_LOCAL_DEF( FT_Error ) tt_driver_init(FT_Module ttdriver)1213 tt_driver_init( FT_Module ttdriver ) /* TT_Driver */ 1214 { 1215 1216 #ifdef TT_USE_BYTECODE_INTERPRETER 1217 1218 TT_Driver driver = (TT_Driver)ttdriver; 1219 1220 1221 if ( !TT_New_Context( driver ) ) 1222 return TT_Err_Could_Not_Find_Context; 1223 1224 #else 1225 1226 FT_UNUSED( ttdriver ); 1227 1228 #endif 1229 1230 return TT_Err_Ok; 1231 } 1232 1233 1234 /*************************************************************************/ 1235 /* */ 1236 /* <Function> */ 1237 /* tt_driver_done */ 1238 /* */ 1239 /* <Description> */ 1240 /* Finalize a given TrueType driver. */ 1241 /* */ 1242 /* <Input> */ 1243 /* driver :: A handle to the target TrueType driver. */ 1244 /* */ 1245 FT_LOCAL_DEF( void ) tt_driver_done(FT_Module ttdriver)1246 tt_driver_done( FT_Module ttdriver ) /* TT_Driver */ 1247 { 1248 #ifdef TT_USE_BYTECODE_INTERPRETER 1249 TT_Driver driver = (TT_Driver)ttdriver; 1250 1251 1252 /* destroy the execution context */ 1253 if ( driver->context ) 1254 { 1255 TT_Done_Context( driver->context ); 1256 driver->context = NULL; 1257 } 1258 #else 1259 FT_UNUSED( ttdriver ); 1260 #endif 1261 1262 } 1263 1264 1265 /*************************************************************************/ 1266 /* */ 1267 /* <Function> */ 1268 /* tt_slot_init */ 1269 /* */ 1270 /* <Description> */ 1271 /* Initialize a new slot object. */ 1272 /* */ 1273 /* <InOut> */ 1274 /* slot :: A handle to the slot object. */ 1275 /* */ 1276 /* <Return> */ 1277 /* FreeType error code. 0 means success. */ 1278 /* */ 1279 FT_LOCAL_DEF( FT_Error ) tt_slot_init(FT_GlyphSlot slot)1280 tt_slot_init( FT_GlyphSlot slot ) 1281 { 1282 return FT_GlyphLoader_CreateExtra( slot->internal->loader ); 1283 } 1284 1285 1286 /* END */ 1287