ftobjs.c (135320B)
1 /***************************************************************************/ 2 /* */ 3 /* ftobjs.c */ 4 /* */ 5 /* The FreeType private base classes (body). */ 6 /* */ 7 /* Copyright 1996-2013 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_LIST_H 21 #include FT_OUTLINE_H 22 #include FT_INTERNAL_VALIDATE_H 23 #include FT_INTERNAL_OBJECTS_H 24 #include FT_INTERNAL_DEBUG_H 25 #include FT_INTERNAL_RFORK_H 26 #include FT_INTERNAL_STREAM_H 27 #include FT_INTERNAL_SFNT_H /* for SFNT_Load_Table_Func */ 28 #include FT_TRUETYPE_TABLES_H 29 #include FT_TRUETYPE_TAGS_H 30 #include FT_TRUETYPE_IDS_H 31 32 #include FT_SERVICE_PROPERTIES_H 33 #include FT_SERVICE_SFNT_H 34 #include FT_SERVICE_POSTSCRIPT_NAME_H 35 #include FT_SERVICE_GLYPH_DICT_H 36 #include FT_SERVICE_TT_CMAP_H 37 #include FT_SERVICE_KERNING_H 38 #include FT_SERVICE_TRUETYPE_ENGINE_H 39 40 #ifdef FT_CONFIG_OPTION_MAC_FONTS 41 #include "ftbase.h" 42 #endif 43 44 45 #ifdef FT_DEBUG_LEVEL_TRACE 46 47 #include FT_BITMAP_H 48 49 #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ 50 /* We disable the warning `conversion from XXX to YYY, */ 51 /* possible loss of data' in order to compile cleanly with */ 52 /* the maximum level of warnings: `md5.c' is non-FreeType */ 53 /* code, and it gets used during development builds only. */ 54 #pragma warning( push ) 55 #pragma warning( disable : 4244 ) 56 #endif /* _MSC_VER */ 57 58 /* it's easiest to include `md5.c' directly */ 59 #define free md5_free /* suppress a shadow warning */ 60 #include "md5.c" 61 #undef free 62 63 #if defined( _MSC_VER ) 64 #pragma warning( pop ) 65 #endif 66 67 #endif /* FT_DEBUG_LEVEL_TRACE */ 68 69 70 #define GRID_FIT_METRICS 71 72 73 FT_BASE_DEF( FT_Pointer ) 74 ft_service_list_lookup( FT_ServiceDesc service_descriptors, 75 const char* service_id ) 76 { 77 FT_Pointer result = NULL; 78 FT_ServiceDesc desc = service_descriptors; 79 80 81 if ( desc && service_id ) 82 { 83 for ( ; desc->serv_id != NULL; desc++ ) 84 { 85 if ( ft_strcmp( desc->serv_id, service_id ) == 0 ) 86 { 87 result = (FT_Pointer)desc->serv_data; 88 break; 89 } 90 } 91 } 92 93 return result; 94 } 95 96 97 FT_BASE_DEF( void ) 98 ft_validator_init( FT_Validator valid, 99 const FT_Byte* base, 100 const FT_Byte* limit, 101 FT_ValidationLevel level ) 102 { 103 valid->base = base; 104 valid->limit = limit; 105 valid->level = level; 106 valid->error = FT_Err_Ok; 107 } 108 109 110 FT_BASE_DEF( FT_Int ) 111 ft_validator_run( FT_Validator valid ) 112 { 113 /* This function doesn't work! None should call it. */ 114 FT_UNUSED( valid ); 115 116 return -1; 117 } 118 119 120 FT_BASE_DEF( void ) 121 ft_validator_error( FT_Validator valid, 122 FT_Error error ) 123 { 124 /* since the cast below also disables the compiler's */ 125 /* type check, we introduce a dummy variable, which */ 126 /* will be optimized away */ 127 volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer; 128 129 130 valid->error = error; 131 132 /* throw away volatileness; use `jump_buffer' or the */ 133 /* compiler may warn about an unused local variable */ 134 ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 ); 135 } 136 137 138 /*************************************************************************/ 139 /*************************************************************************/ 140 /*************************************************************************/ 141 /**** ****/ 142 /**** ****/ 143 /**** S T R E A M ****/ 144 /**** ****/ 145 /**** ****/ 146 /*************************************************************************/ 147 /*************************************************************************/ 148 /*************************************************************************/ 149 150 151 /* create a new input stream from an FT_Open_Args structure */ 152 /* */ 153 FT_BASE_DEF( FT_Error ) 154 FT_Stream_New( FT_Library library, 155 const FT_Open_Args* args, 156 FT_Stream *astream ) 157 { 158 FT_Error error; 159 FT_Memory memory; 160 FT_Stream stream = NULL; 161 162 163 *astream = 0; 164 165 if ( !library ) 166 return FT_THROW( Invalid_Library_Handle ); 167 168 if ( !args ) 169 return FT_THROW( Invalid_Argument ); 170 171 memory = library->memory; 172 173 if ( FT_NEW( stream ) ) 174 goto Exit; 175 176 stream->memory = memory; 177 178 if ( args->flags & FT_OPEN_MEMORY ) 179 { 180 /* create a memory-based stream */ 181 FT_Stream_OpenMemory( stream, 182 (const FT_Byte*)args->memory_base, 183 args->memory_size ); 184 } 185 186 #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT 187 188 else if ( args->flags & FT_OPEN_PATHNAME ) 189 { 190 /* create a normal system stream */ 191 error = FT_Stream_Open( stream, args->pathname ); 192 stream->pathname.pointer = args->pathname; 193 } 194 else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) 195 { 196 /* use an existing, user-provided stream */ 197 198 /* in this case, we do not need to allocate a new stream object */ 199 /* since the caller is responsible for closing it himself */ 200 FT_FREE( stream ); 201 stream = args->stream; 202 } 203 204 #endif 205 206 else 207 error = FT_THROW( Invalid_Argument ); 208 209 if ( error ) 210 FT_FREE( stream ); 211 else 212 stream->memory = memory; /* just to be certain */ 213 214 *astream = stream; 215 216 Exit: 217 return error; 218 } 219 220 221 FT_BASE_DEF( void ) 222 FT_Stream_Free( FT_Stream stream, 223 FT_Int external ) 224 { 225 if ( stream ) 226 { 227 FT_Memory memory = stream->memory; 228 229 230 FT_Stream_Close( stream ); 231 232 if ( !external ) 233 FT_FREE( stream ); 234 } 235 } 236 237 238 /*************************************************************************/ 239 /* */ 240 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 241 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 242 /* messages during execution. */ 243 /* */ 244 #undef FT_COMPONENT 245 #define FT_COMPONENT trace_objs 246 247 248 /*************************************************************************/ 249 /*************************************************************************/ 250 /*************************************************************************/ 251 /**** ****/ 252 /**** ****/ 253 /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/ 254 /**** ****/ 255 /**** ****/ 256 /*************************************************************************/ 257 /*************************************************************************/ 258 /*************************************************************************/ 259 260 261 static FT_Error 262 ft_glyphslot_init( FT_GlyphSlot slot ) 263 { 264 FT_Driver driver = slot->face->driver; 265 FT_Driver_Class clazz = driver->clazz; 266 FT_Memory memory = driver->root.memory; 267 FT_Error error = FT_Err_Ok; 268 FT_Slot_Internal internal = NULL; 269 270 271 slot->library = driver->root.library; 272 273 if ( FT_NEW( internal ) ) 274 goto Exit; 275 276 slot->internal = internal; 277 278 if ( FT_DRIVER_USES_OUTLINES( driver ) ) 279 error = FT_GlyphLoader_New( memory, &internal->loader ); 280 281 if ( !error && clazz->init_slot ) 282 error = clazz->init_slot( slot ); 283 284 Exit: 285 return error; 286 } 287 288 289 FT_BASE_DEF( void ) 290 ft_glyphslot_free_bitmap( FT_GlyphSlot slot ) 291 { 292 if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) 293 { 294 FT_Memory memory = FT_FACE_MEMORY( slot->face ); 295 296 297 FT_FREE( slot->bitmap.buffer ); 298 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; 299 } 300 else 301 { 302 /* assume that the bitmap buffer was stolen or not */ 303 /* allocated from the heap */ 304 slot->bitmap.buffer = NULL; 305 } 306 } 307 308 309 FT_BASE_DEF( void ) 310 ft_glyphslot_set_bitmap( FT_GlyphSlot slot, 311 FT_Byte* buffer ) 312 { 313 ft_glyphslot_free_bitmap( slot ); 314 315 slot->bitmap.buffer = buffer; 316 317 FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 ); 318 } 319 320 321 FT_BASE_DEF( FT_Error ) 322 ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, 323 FT_ULong size ) 324 { 325 FT_Memory memory = FT_FACE_MEMORY( slot->face ); 326 FT_Error error; 327 328 329 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) 330 FT_FREE( slot->bitmap.buffer ); 331 else 332 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 333 334 (void)FT_ALLOC( slot->bitmap.buffer, size ); 335 return error; 336 } 337 338 339 static void 340 ft_glyphslot_clear( FT_GlyphSlot slot ) 341 { 342 /* free bitmap if needed */ 343 ft_glyphslot_free_bitmap( slot ); 344 345 /* clear all public fields in the glyph slot */ 346 FT_ZERO( &slot->metrics ); 347 FT_ZERO( &slot->outline ); 348 349 slot->bitmap.width = 0; 350 slot->bitmap.rows = 0; 351 slot->bitmap.pitch = 0; 352 slot->bitmap.pixel_mode = 0; 353 /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */ 354 355 slot->bitmap_left = 0; 356 slot->bitmap_top = 0; 357 slot->num_subglyphs = 0; 358 slot->subglyphs = 0; 359 slot->control_data = 0; 360 slot->control_len = 0; 361 slot->other = 0; 362 slot->format = FT_GLYPH_FORMAT_NONE; 363 364 slot->linearHoriAdvance = 0; 365 slot->linearVertAdvance = 0; 366 slot->lsb_delta = 0; 367 slot->rsb_delta = 0; 368 } 369 370 371 static void 372 ft_glyphslot_done( FT_GlyphSlot slot ) 373 { 374 FT_Driver driver = slot->face->driver; 375 FT_Driver_Class clazz = driver->clazz; 376 FT_Memory memory = driver->root.memory; 377 378 379 if ( clazz->done_slot ) 380 clazz->done_slot( slot ); 381 382 /* free bitmap buffer if needed */ 383 ft_glyphslot_free_bitmap( slot ); 384 385 /* slot->internal might be NULL in out-of-memory situations */ 386 if ( slot->internal ) 387 { 388 /* free glyph loader */ 389 if ( FT_DRIVER_USES_OUTLINES( driver ) ) 390 { 391 FT_GlyphLoader_Done( slot->internal->loader ); 392 slot->internal->loader = 0; 393 } 394 395 FT_FREE( slot->internal ); 396 } 397 } 398 399 400 /* documentation is in ftobjs.h */ 401 402 FT_BASE_DEF( FT_Error ) 403 FT_New_GlyphSlot( FT_Face face, 404 FT_GlyphSlot *aslot ) 405 { 406 FT_Error error; 407 FT_Driver driver; 408 FT_Driver_Class clazz; 409 FT_Memory memory; 410 FT_GlyphSlot slot = NULL; 411 412 413 if ( !face || !face->driver ) 414 return FT_THROW( Invalid_Argument ); 415 416 driver = face->driver; 417 clazz = driver->clazz; 418 memory = driver->root.memory; 419 420 FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" )); 421 if ( !FT_ALLOC( slot, clazz->slot_object_size ) ) 422 { 423 slot->face = face; 424 425 error = ft_glyphslot_init( slot ); 426 if ( error ) 427 { 428 ft_glyphslot_done( slot ); 429 FT_FREE( slot ); 430 goto Exit; 431 } 432 433 slot->next = face->glyph; 434 face->glyph = slot; 435 436 if ( aslot ) 437 *aslot = slot; 438 } 439 else if ( aslot ) 440 *aslot = 0; 441 442 443 Exit: 444 FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error )); 445 return error; 446 } 447 448 449 /* documentation is in ftobjs.h */ 450 451 FT_BASE_DEF( void ) 452 FT_Done_GlyphSlot( FT_GlyphSlot slot ) 453 { 454 if ( slot ) 455 { 456 FT_Driver driver = slot->face->driver; 457 FT_Memory memory = driver->root.memory; 458 FT_GlyphSlot prev; 459 FT_GlyphSlot cur; 460 461 462 /* Remove slot from its parent face's list */ 463 prev = NULL; 464 cur = slot->face->glyph; 465 466 while ( cur ) 467 { 468 if ( cur == slot ) 469 { 470 if ( !prev ) 471 slot->face->glyph = cur->next; 472 else 473 prev->next = cur->next; 474 475 /* finalize client-specific data */ 476 if ( slot->generic.finalizer ) 477 slot->generic.finalizer( slot ); 478 479 ft_glyphslot_done( slot ); 480 FT_FREE( slot ); 481 break; 482 } 483 prev = cur; 484 cur = cur->next; 485 } 486 } 487 } 488 489 490 /* documentation is in freetype.h */ 491 492 FT_EXPORT_DEF( void ) 493 FT_Set_Transform( FT_Face face, 494 FT_Matrix* matrix, 495 FT_Vector* delta ) 496 { 497 FT_Face_Internal internal; 498 499 500 if ( !face ) 501 return; 502 503 internal = face->internal; 504 505 internal->transform_flags = 0; 506 507 if ( !matrix ) 508 { 509 internal->transform_matrix.xx = 0x10000L; 510 internal->transform_matrix.xy = 0; 511 internal->transform_matrix.yx = 0; 512 internal->transform_matrix.yy = 0x10000L; 513 matrix = &internal->transform_matrix; 514 } 515 else 516 internal->transform_matrix = *matrix; 517 518 /* set transform_flags bit flag 0 if `matrix' isn't the identity */ 519 if ( ( matrix->xy | matrix->yx ) || 520 matrix->xx != 0x10000L || 521 matrix->yy != 0x10000L ) 522 internal->transform_flags |= 1; 523 524 if ( !delta ) 525 { 526 internal->transform_delta.x = 0; 527 internal->transform_delta.y = 0; 528 delta = &internal->transform_delta; 529 } 530 else 531 internal->transform_delta = *delta; 532 533 /* set transform_flags bit flag 1 if `delta' isn't the null vector */ 534 if ( delta->x | delta->y ) 535 internal->transform_flags |= 2; 536 } 537 538 539 static FT_Renderer 540 ft_lookup_glyph_renderer( FT_GlyphSlot slot ); 541 542 543 #ifdef GRID_FIT_METRICS 544 static void 545 ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot, 546 FT_Bool vertical ) 547 { 548 FT_Glyph_Metrics* metrics = &slot->metrics; 549 FT_Pos right, bottom; 550 551 552 if ( vertical ) 553 { 554 metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); 555 metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY ); 556 557 right = FT_PIX_CEIL( metrics->vertBearingX + metrics->width ); 558 bottom = FT_PIX_CEIL( metrics->vertBearingY + metrics->height ); 559 560 metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); 561 metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); 562 563 metrics->width = right - metrics->vertBearingX; 564 metrics->height = bottom - metrics->vertBearingY; 565 } 566 else 567 { 568 metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); 569 metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); 570 571 right = FT_PIX_CEIL ( metrics->horiBearingX + metrics->width ); 572 bottom = FT_PIX_FLOOR( metrics->horiBearingY - metrics->height ); 573 574 metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); 575 metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY ); 576 577 metrics->width = right - metrics->horiBearingX; 578 metrics->height = metrics->horiBearingY - bottom; 579 } 580 581 metrics->horiAdvance = FT_PIX_ROUND( metrics->horiAdvance ); 582 metrics->vertAdvance = FT_PIX_ROUND( metrics->vertAdvance ); 583 } 584 #endif /* GRID_FIT_METRICS */ 585 586 587 /* documentation is in freetype.h */ 588 589 FT_EXPORT_DEF( FT_Error ) 590 FT_Load_Glyph( FT_Face face, 591 FT_UInt glyph_index, 592 FT_Int32 load_flags ) 593 { 594 FT_Error error; 595 FT_Driver driver; 596 FT_GlyphSlot slot; 597 FT_Library library; 598 FT_Bool autohint = FALSE; 599 FT_Module hinter; 600 TT_Face ttface = (TT_Face)face; 601 602 603 if ( !face || !face->size || !face->glyph ) 604 return FT_THROW( Invalid_Face_Handle ); 605 606 /* The validity test for `glyph_index' is performed by the */ 607 /* font drivers. */ 608 609 slot = face->glyph; 610 ft_glyphslot_clear( slot ); 611 612 driver = face->driver; 613 library = driver->root.library; 614 hinter = library->auto_hinter; 615 616 /* resolve load flags dependencies */ 617 618 if ( load_flags & FT_LOAD_NO_RECURSE ) 619 load_flags |= FT_LOAD_NO_SCALE | 620 FT_LOAD_IGNORE_TRANSFORM; 621 622 if ( load_flags & FT_LOAD_NO_SCALE ) 623 { 624 load_flags |= FT_LOAD_NO_HINTING | 625 FT_LOAD_NO_BITMAP; 626 627 load_flags &= ~FT_LOAD_RENDER; 628 } 629 630 /* 631 * Determine whether we need to auto-hint or not. 632 * The general rules are: 633 * 634 * - Do only auto-hinting if we have a hinter module, a scalable font 635 * format dealing with outlines, and no transforms except simple 636 * slants and/or rotations by integer multiples of 90 degrees. 637 * 638 * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't 639 * have a native font hinter. 640 * 641 * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't 642 * any hinting bytecode in the TrueType/OpenType font. 643 * 644 * - Exception: The font is `tricky' and requires the native hinter to 645 * load properly. 646 */ 647 648 if ( hinter && 649 !( load_flags & FT_LOAD_NO_HINTING ) && 650 !( load_flags & FT_LOAD_NO_AUTOHINT ) && 651 FT_DRIVER_IS_SCALABLE( driver ) && 652 FT_DRIVER_USES_OUTLINES( driver ) && 653 !FT_IS_TRICKY( face ) && 654 ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) || 655 ( face->internal->transform_matrix.yx == 0 && 656 face->internal->transform_matrix.xx != 0 ) || 657 ( face->internal->transform_matrix.xx == 0 && 658 face->internal->transform_matrix.yx != 0 ) ) ) 659 { 660 if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) || 661 !FT_DRIVER_HAS_HINTER( driver ) ) 662 autohint = TRUE; 663 else 664 { 665 FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); 666 667 668 /* the check for `num_locations' assures that we actually */ 669 /* test for instructions in a TTF and not in a CFF-based OTF */ 670 if ( mode == FT_RENDER_MODE_LIGHT || 671 face->internal->ignore_unpatented_hinter || 672 ( FT_IS_SFNT( face ) && 673 ttface->num_locations && 674 ttface->max_profile.maxSizeOfInstructions == 0 ) ) 675 autohint = TRUE; 676 } 677 } 678 679 if ( autohint ) 680 { 681 FT_AutoHinter_Interface hinting; 682 683 684 /* try to load embedded bitmaps first if available */ 685 /* */ 686 /* XXX: This is really a temporary hack that should disappear */ 687 /* promptly with FreeType 2.1! */ 688 /* */ 689 if ( FT_HAS_FIXED_SIZES( face ) && 690 ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) 691 { 692 error = driver->clazz->load_glyph( slot, face->size, 693 glyph_index, 694 load_flags | FT_LOAD_SBITS_ONLY ); 695 696 if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP ) 697 goto Load_Ok; 698 } 699 700 { 701 FT_Face_Internal internal = face->internal; 702 FT_Int transform_flags = internal->transform_flags; 703 704 705 /* since the auto-hinter calls FT_Load_Glyph by itself, */ 706 /* make sure that glyphs aren't transformed */ 707 internal->transform_flags = 0; 708 709 /* load auto-hinted outline */ 710 hinting = (FT_AutoHinter_Interface)hinter->clazz->module_interface; 711 712 error = hinting->load_glyph( (FT_AutoHinter)hinter, 713 slot, face->size, 714 glyph_index, load_flags ); 715 716 internal->transform_flags = transform_flags; 717 } 718 } 719 else 720 { 721 error = driver->clazz->load_glyph( slot, 722 face->size, 723 glyph_index, 724 load_flags ); 725 if ( error ) 726 goto Exit; 727 728 if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) 729 { 730 /* check that the loaded outline is correct */ 731 error = FT_Outline_Check( &slot->outline ); 732 if ( error ) 733 goto Exit; 734 735 #ifdef GRID_FIT_METRICS 736 if ( !( load_flags & FT_LOAD_NO_HINTING ) ) 737 ft_glyphslot_grid_fit_metrics( slot, 738 FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) ); 739 #endif 740 } 741 } 742 743 Load_Ok: 744 /* compute the advance */ 745 if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) 746 { 747 slot->advance.x = 0; 748 slot->advance.y = slot->metrics.vertAdvance; 749 } 750 else 751 { 752 slot->advance.x = slot->metrics.horiAdvance; 753 slot->advance.y = 0; 754 } 755 756 /* compute the linear advance in 16.16 pixels */ 757 if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 && 758 ( FT_IS_SCALABLE( face ) ) ) 759 { 760 FT_Size_Metrics* metrics = &face->size->metrics; 761 762 763 /* it's tricky! */ 764 slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance, 765 metrics->x_scale, 64 ); 766 767 slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance, 768 metrics->y_scale, 64 ); 769 } 770 771 if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 ) 772 { 773 FT_Face_Internal internal = face->internal; 774 775 776 /* now, transform the glyph image if needed */ 777 if ( internal->transform_flags ) 778 { 779 /* get renderer */ 780 FT_Renderer renderer = ft_lookup_glyph_renderer( slot ); 781 782 783 if ( renderer ) 784 error = renderer->clazz->transform_glyph( 785 renderer, slot, 786 &internal->transform_matrix, 787 &internal->transform_delta ); 788 else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) 789 { 790 /* apply `standard' transformation if no renderer is available */ 791 if ( internal->transform_flags & 1 ) 792 FT_Outline_Transform( &slot->outline, 793 &internal->transform_matrix ); 794 795 if ( internal->transform_flags & 2 ) 796 FT_Outline_Translate( &slot->outline, 797 internal->transform_delta.x, 798 internal->transform_delta.y ); 799 } 800 801 /* transform advance */ 802 FT_Vector_Transform( &slot->advance, &internal->transform_matrix ); 803 } 804 } 805 806 FT_TRACE5(( " x advance: %d\n" , slot->advance.x )); 807 FT_TRACE5(( " y advance: %d\n" , slot->advance.y )); 808 809 FT_TRACE5(( " linear x advance: %d\n" , slot->linearHoriAdvance )); 810 FT_TRACE5(( " linear y advance: %d\n" , slot->linearVertAdvance )); 811 812 /* do we need to render the image now? */ 813 if ( !error && 814 slot->format != FT_GLYPH_FORMAT_BITMAP && 815 slot->format != FT_GLYPH_FORMAT_COMPOSITE && 816 load_flags & FT_LOAD_RENDER ) 817 { 818 FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); 819 820 821 if ( mode == FT_RENDER_MODE_NORMAL && 822 (load_flags & FT_LOAD_MONOCHROME ) ) 823 mode = FT_RENDER_MODE_MONO; 824 825 error = FT_Render_Glyph( slot, mode ); 826 } 827 828 Exit: 829 return error; 830 } 831 832 833 /* documentation is in freetype.h */ 834 835 FT_EXPORT_DEF( FT_Error ) 836 FT_Load_Char( FT_Face face, 837 FT_ULong char_code, 838 FT_Int32 load_flags ) 839 { 840 FT_UInt glyph_index; 841 842 843 if ( !face ) 844 return FT_THROW( Invalid_Face_Handle ); 845 846 glyph_index = (FT_UInt)char_code; 847 if ( face->charmap ) 848 glyph_index = FT_Get_Char_Index( face, char_code ); 849 850 return FT_Load_Glyph( face, glyph_index, load_flags ); 851 } 852 853 854 /* destructor for sizes list */ 855 static void 856 destroy_size( FT_Memory memory, 857 FT_Size size, 858 FT_Driver driver ) 859 { 860 /* finalize client-specific data */ 861 if ( size->generic.finalizer ) 862 size->generic.finalizer( size ); 863 864 /* finalize format-specific stuff */ 865 if ( driver->clazz->done_size ) 866 driver->clazz->done_size( size ); 867 868 FT_FREE( size->internal ); 869 FT_FREE( size ); 870 } 871 872 873 static void 874 ft_cmap_done_internal( FT_CMap cmap ); 875 876 877 static void 878 destroy_charmaps( FT_Face face, 879 FT_Memory memory ) 880 { 881 FT_Int n; 882 883 884 if ( !face ) 885 return; 886 887 for ( n = 0; n < face->num_charmaps; n++ ) 888 { 889 FT_CMap cmap = FT_CMAP( face->charmaps[n] ); 890 891 892 ft_cmap_done_internal( cmap ); 893 894 face->charmaps[n] = NULL; 895 } 896 897 FT_FREE( face->charmaps ); 898 face->num_charmaps = 0; 899 } 900 901 902 /* destructor for faces list */ 903 static void 904 destroy_face( FT_Memory memory, 905 FT_Face face, 906 FT_Driver driver ) 907 { 908 FT_Driver_Class clazz = driver->clazz; 909 910 911 /* discard auto-hinting data */ 912 if ( face->autohint.finalizer ) 913 face->autohint.finalizer( face->autohint.data ); 914 915 /* Discard glyph slots for this face. */ 916 /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */ 917 while ( face->glyph ) 918 FT_Done_GlyphSlot( face->glyph ); 919 920 /* discard all sizes for this face */ 921 FT_List_Finalize( &face->sizes_list, 922 (FT_List_Destructor)destroy_size, 923 memory, 924 driver ); 925 face->size = 0; 926 927 /* now discard client data */ 928 if ( face->generic.finalizer ) 929 face->generic.finalizer( face ); 930 931 /* discard charmaps */ 932 destroy_charmaps( face, memory ); 933 934 /* finalize format-specific stuff */ 935 if ( clazz->done_face ) 936 clazz->done_face( face ); 937 938 /* close the stream for this face if needed */ 939 FT_Stream_Free( 940 face->stream, 941 ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); 942 943 face->stream = 0; 944 945 /* get rid of it */ 946 if ( face->internal ) 947 { 948 FT_FREE( face->internal ); 949 } 950 FT_FREE( face ); 951 } 952 953 954 static void 955 Destroy_Driver( FT_Driver driver ) 956 { 957 FT_List_Finalize( &driver->faces_list, 958 (FT_List_Destructor)destroy_face, 959 driver->root.memory, 960 driver ); 961 962 /* check whether we need to drop the driver's glyph loader */ 963 if ( FT_DRIVER_USES_OUTLINES( driver ) ) 964 FT_GlyphLoader_Done( driver->glyph_loader ); 965 } 966 967 968 /*************************************************************************/ 969 /* */ 970 /* <Function> */ 971 /* find_unicode_charmap */ 972 /* */ 973 /* <Description> */ 974 /* This function finds a Unicode charmap, if there is one. */ 975 /* And if there is more than one, it tries to favour the more */ 976 /* extensive one, i.e., one that supports UCS-4 against those which */ 977 /* are limited to the BMP (said UCS-2 encoding.) */ 978 /* */ 979 /* This function is called from open_face() (just below), and also */ 980 /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). */ 981 /* */ 982 static FT_Error 983 find_unicode_charmap( FT_Face face ) 984 { 985 FT_CharMap* first; 986 FT_CharMap* cur; 987 988 989 /* caller should have already checked that `face' is valid */ 990 FT_ASSERT( face ); 991 992 first = face->charmaps; 993 994 if ( !first ) 995 return FT_THROW( Invalid_CharMap_Handle ); 996 997 /* 998 * The original TrueType specification(s) only specified charmap 999 * formats that are capable of mapping 8 or 16 bit character codes to 1000 * glyph indices. 1001 * 1002 * However, recent updates to the Apple and OpenType specifications 1003 * introduced new formats that are capable of mapping 32-bit character 1004 * codes as well. And these are already used on some fonts, mainly to 1005 * map non-BMP Asian ideographs as defined in Unicode. 1006 * 1007 * For compatibility purposes, these fonts generally come with 1008 * *several* Unicode charmaps: 1009 * 1010 * - One of them in the "old" 16-bit format, that cannot access 1011 * all glyphs in the font. 1012 * 1013 * - Another one in the "new" 32-bit format, that can access all 1014 * the glyphs. 1015 * 1016 * This function has been written to always favor a 32-bit charmap 1017 * when found. Otherwise, a 16-bit one is returned when found. 1018 */ 1019 1020 /* Since the `interesting' table, with IDs (3,10), is normally the */ 1021 /* last one, we loop backwards. This loses with type1 fonts with */ 1022 /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */ 1023 /* chars (.01% ?), and this is the same about 99.99% of the time! */ 1024 1025 cur = first + face->num_charmaps; /* points after the last one */ 1026 1027 for ( ; --cur >= first; ) 1028 { 1029 if ( cur[0]->encoding == FT_ENCODING_UNICODE ) 1030 { 1031 /* XXX If some new encodings to represent UCS-4 are added, */ 1032 /* they should be added here. */ 1033 if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT && 1034 cur[0]->encoding_id == TT_MS_ID_UCS_4 ) || 1035 ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && 1036 cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) ) 1037 { 1038 #ifdef FT_MAX_CHARMAP_CACHEABLE 1039 if ( cur - first > FT_MAX_CHARMAP_CACHEABLE ) 1040 { 1041 FT_ERROR(( "find_unicode_charmap: UCS-4 cmap is found " 1042 "at too late position (%d)\n", cur - first )); 1043 continue; 1044 } 1045 #endif 1046 face->charmap = cur[0]; 1047 return FT_Err_Ok; 1048 } 1049 } 1050 } 1051 1052 /* We do not have any UCS-4 charmap. */ 1053 /* Do the loop again and search for UCS-2 charmaps. */ 1054 cur = first + face->num_charmaps; 1055 1056 for ( ; --cur >= first; ) 1057 { 1058 if ( cur[0]->encoding == FT_ENCODING_UNICODE ) 1059 { 1060 #ifdef FT_MAX_CHARMAP_CACHEABLE 1061 if ( cur - first > FT_MAX_CHARMAP_CACHEABLE ) 1062 { 1063 FT_ERROR(( "find_unicode_charmap: UCS-2 cmap is found " 1064 "at too late position (%d)\n", cur - first )); 1065 continue; 1066 } 1067 #endif 1068 face->charmap = cur[0]; 1069 return FT_Err_Ok; 1070 } 1071 } 1072 1073 return FT_THROW( Invalid_CharMap_Handle ); 1074 } 1075 1076 1077 /*************************************************************************/ 1078 /* */ 1079 /* <Function> */ 1080 /* find_variant_selector_charmap */ 1081 /* */ 1082 /* <Description> */ 1083 /* This function finds the variant selector charmap, if there is one. */ 1084 /* There can only be one (platform=0, specific=5, format=14). */ 1085 /* */ 1086 static FT_CharMap 1087 find_variant_selector_charmap( FT_Face face ) 1088 { 1089 FT_CharMap* first; 1090 FT_CharMap* end; 1091 FT_CharMap* cur; 1092 1093 1094 /* caller should have already checked that `face' is valid */ 1095 FT_ASSERT( face ); 1096 1097 first = face->charmaps; 1098 1099 if ( !first ) 1100 return NULL; 1101 1102 end = first + face->num_charmaps; /* points after the last one */ 1103 1104 for ( cur = first; cur < end; ++cur ) 1105 { 1106 if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && 1107 cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR && 1108 FT_Get_CMap_Format( cur[0] ) == 14 ) 1109 { 1110 #ifdef FT_MAX_CHARMAP_CACHEABLE 1111 if ( cur - first > FT_MAX_CHARMAP_CACHEABLE ) 1112 { 1113 FT_ERROR(( "find_unicode_charmap: UVS cmap is found " 1114 "at too late position (%d)\n", cur - first )); 1115 continue; 1116 } 1117 #endif 1118 return cur[0]; 1119 } 1120 } 1121 1122 return NULL; 1123 } 1124 1125 1126 /*************************************************************************/ 1127 /* */ 1128 /* <Function> */ 1129 /* open_face */ 1130 /* */ 1131 /* <Description> */ 1132 /* This function does some work for FT_Open_Face(). */ 1133 /* */ 1134 static FT_Error 1135 open_face( FT_Driver driver, 1136 FT_Stream stream, 1137 FT_Long face_index, 1138 FT_Int num_params, 1139 FT_Parameter* params, 1140 FT_Face *aface ) 1141 { 1142 FT_Memory memory; 1143 FT_Driver_Class clazz; 1144 FT_Face face = 0; 1145 FT_Error error, error2; 1146 FT_Face_Internal internal = NULL; 1147 1148 1149 clazz = driver->clazz; 1150 memory = driver->root.memory; 1151 1152 /* allocate the face object and perform basic initialization */ 1153 if ( FT_ALLOC( face, clazz->face_object_size ) ) 1154 goto Fail; 1155 1156 face->driver = driver; 1157 face->memory = memory; 1158 face->stream = stream; 1159 1160 if ( FT_NEW( internal ) ) 1161 goto Fail; 1162 1163 face->internal = internal; 1164 1165 #ifdef FT_CONFIG_OPTION_INCREMENTAL 1166 { 1167 int i; 1168 1169 1170 face->internal->incremental_interface = 0; 1171 for ( i = 0; i < num_params && !face->internal->incremental_interface; 1172 i++ ) 1173 if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL ) 1174 face->internal->incremental_interface = 1175 (FT_Incremental_Interface)params[i].data; 1176 } 1177 #endif 1178 1179 if ( clazz->init_face ) 1180 error = clazz->init_face( stream, 1181 face, 1182 (FT_Int)face_index, 1183 num_params, 1184 params ); 1185 if ( error ) 1186 goto Fail; 1187 1188 /* select Unicode charmap by default */ 1189 error2 = find_unicode_charmap( face ); 1190 1191 /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */ 1192 /* is returned. */ 1193 1194 /* no error should happen, but we want to play safe */ 1195 if ( error2 && FT_ERR_NEQ( error2, Invalid_CharMap_Handle ) ) 1196 { 1197 error = error2; 1198 goto Fail; 1199 } 1200 1201 *aface = face; 1202 1203 Fail: 1204 if ( error ) 1205 { 1206 destroy_charmaps( face, memory ); 1207 if ( clazz->done_face ) 1208 clazz->done_face( face ); 1209 FT_FREE( internal ); 1210 FT_FREE( face ); 1211 *aface = 0; 1212 } 1213 1214 return error; 1215 } 1216 1217 1218 /* there's a Mac-specific extended implementation of FT_New_Face() */ 1219 /* in src/base/ftmac.c */ 1220 1221 #ifndef FT_MACINTOSH 1222 1223 /* documentation is in freetype.h */ 1224 1225 FT_EXPORT_DEF( FT_Error ) 1226 FT_New_Face( FT_Library library, 1227 const char* pathname, 1228 FT_Long face_index, 1229 FT_Face *aface ) 1230 { 1231 FT_Open_Args args; 1232 1233 1234 /* test for valid `library' and `aface' delayed to FT_Open_Face() */ 1235 if ( !pathname ) 1236 return FT_THROW( Invalid_Argument ); 1237 1238 args.flags = FT_OPEN_PATHNAME; 1239 args.pathname = (char*)pathname; 1240 args.stream = NULL; 1241 1242 return FT_Open_Face( library, &args, face_index, aface ); 1243 } 1244 1245 #endif 1246 1247 1248 /* documentation is in freetype.h */ 1249 1250 FT_EXPORT_DEF( FT_Error ) 1251 FT_New_Memory_Face( FT_Library library, 1252 const FT_Byte* file_base, 1253 FT_Long file_size, 1254 FT_Long face_index, 1255 FT_Face *aface ) 1256 { 1257 FT_Open_Args args; 1258 1259 1260 /* test for valid `library' and `face' delayed to FT_Open_Face() */ 1261 if ( !file_base ) 1262 return FT_THROW( Invalid_Argument ); 1263 1264 args.flags = FT_OPEN_MEMORY; 1265 args.memory_base = file_base; 1266 args.memory_size = file_size; 1267 args.stream = NULL; 1268 1269 return FT_Open_Face( library, &args, face_index, aface ); 1270 } 1271 1272 1273 #ifdef FT_CONFIG_OPTION_MAC_FONTS 1274 1275 /* The behavior here is very similar to that in base/ftmac.c, but it */ 1276 /* is designed to work on non-mac systems, so no mac specific calls. */ 1277 /* */ 1278 /* We look at the file and determine if it is a mac dfont file or a mac */ 1279 /* resource file, or a macbinary file containing a mac resource file. */ 1280 /* */ 1281 /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */ 1282 /* the point, especially since there may be multiple `FOND' resources. */ 1283 /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */ 1284 /* they occur in the file. */ 1285 /* */ 1286 /* Note that multiple `POST' resources do not mean multiple postscript */ 1287 /* fonts; they all get jammed together to make what is essentially a */ 1288 /* pfb file. */ 1289 /* */ 1290 /* We aren't interested in `NFNT' or `FONT' bitmap resources. */ 1291 /* */ 1292 /* As soon as we get an `sfnt' load it into memory and pass it off to */ 1293 /* FT_Open_Face. */ 1294 /* */ 1295 /* If we have a (set of) `POST' resources, massage them into a (memory) */ 1296 /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */ 1297 /* going to try to save the kerning info. After all that lives in the */ 1298 /* `FOND' which isn't in the file containing the `POST' resources so */ 1299 /* we don't really have access to it. */ 1300 1301 1302 /* Finalizer for a memory stream; gets called by FT_Done_Face(). */ 1303 /* It frees the memory it uses. */ 1304 /* From ftmac.c. */ 1305 static void 1306 memory_stream_close( FT_Stream stream ) 1307 { 1308 FT_Memory memory = stream->memory; 1309 1310 1311 FT_FREE( stream->base ); 1312 1313 stream->size = 0; 1314 stream->base = 0; 1315 stream->close = 0; 1316 } 1317 1318 1319 /* Create a new memory stream from a buffer and a size. */ 1320 /* From ftmac.c. */ 1321 static FT_Error 1322 new_memory_stream( FT_Library library, 1323 FT_Byte* base, 1324 FT_ULong size, 1325 FT_Stream_CloseFunc close, 1326 FT_Stream *astream ) 1327 { 1328 FT_Error error; 1329 FT_Memory memory; 1330 FT_Stream stream = NULL; 1331 1332 1333 if ( !library ) 1334 return FT_THROW( Invalid_Library_Handle ); 1335 1336 if ( !base ) 1337 return FT_THROW( Invalid_Argument ); 1338 1339 *astream = 0; 1340 memory = library->memory; 1341 if ( FT_NEW( stream ) ) 1342 goto Exit; 1343 1344 FT_Stream_OpenMemory( stream, base, size ); 1345 1346 stream->close = close; 1347 1348 *astream = stream; 1349 1350 Exit: 1351 return error; 1352 } 1353 1354 1355 /* Create a new FT_Face given a buffer and a driver name. */ 1356 /* from ftmac.c */ 1357 FT_LOCAL_DEF( FT_Error ) 1358 open_face_from_buffer( FT_Library library, 1359 FT_Byte* base, 1360 FT_ULong size, 1361 FT_Long face_index, 1362 const char* driver_name, 1363 FT_Face *aface ) 1364 { 1365 FT_Open_Args args; 1366 FT_Error error; 1367 FT_Stream stream = NULL; 1368 FT_Memory memory = library->memory; 1369 1370 1371 error = new_memory_stream( library, 1372 base, 1373 size, 1374 memory_stream_close, 1375 &stream ); 1376 if ( error ) 1377 { 1378 FT_FREE( base ); 1379 return error; 1380 } 1381 1382 args.flags = FT_OPEN_STREAM; 1383 args.stream = stream; 1384 if ( driver_name ) 1385 { 1386 args.flags = args.flags | FT_OPEN_DRIVER; 1387 args.driver = FT_Get_Module( library, driver_name ); 1388 } 1389 1390 #ifdef FT_MACINTOSH 1391 /* At this point, face_index has served its purpose; */ 1392 /* whoever calls this function has already used it to */ 1393 /* locate the correct font data. We should not propagate */ 1394 /* this index to FT_Open_Face() (unless it is negative). */ 1395 1396 if ( face_index > 0 ) 1397 face_index = 0; 1398 #endif 1399 1400 error = FT_Open_Face( library, &args, face_index, aface ); 1401 1402 if ( error == FT_Err_Ok ) 1403 (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; 1404 else 1405 #ifdef FT_MACINTOSH 1406 FT_Stream_Free( stream, 0 ); 1407 #else 1408 { 1409 FT_Stream_Close( stream ); 1410 FT_FREE( stream ); 1411 } 1412 #endif 1413 1414 return error; 1415 } 1416 1417 1418 /* Look up `TYP1' or `CID ' table from sfnt table directory. */ 1419 /* `offset' and `length' must exclude the binary header in tables. */ 1420 1421 /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */ 1422 /* format too. Here, since we can't expect that the TrueType font */ 1423 /* driver is loaded unconditially, we must parse the font by */ 1424 /* ourselves. We are only interested in the name of the table and */ 1425 /* the offset. */ 1426 1427 static FT_Error 1428 ft_lookup_PS_in_sfnt_stream( FT_Stream stream, 1429 FT_Long face_index, 1430 FT_ULong* offset, 1431 FT_ULong* length, 1432 FT_Bool* is_sfnt_cid ) 1433 { 1434 FT_Error error; 1435 FT_UShort numTables; 1436 FT_Long pstable_index; 1437 FT_ULong tag; 1438 int i; 1439 1440 1441 *offset = 0; 1442 *length = 0; 1443 *is_sfnt_cid = FALSE; 1444 1445 /* TODO: support for sfnt-wrapped PS/CID in TTC format */ 1446 1447 /* version check for 'typ1' (should be ignored?) */ 1448 if ( FT_READ_ULONG( tag ) ) 1449 return error; 1450 if ( tag != TTAG_typ1 ) 1451 return FT_THROW( Unknown_File_Format ); 1452 1453 if ( FT_READ_USHORT( numTables ) ) 1454 return error; 1455 if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */ 1456 return error; 1457 1458 pstable_index = -1; 1459 *is_sfnt_cid = FALSE; 1460 1461 for ( i = 0; i < numTables; i++ ) 1462 { 1463 if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) || 1464 FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) ) 1465 return error; 1466 1467 if ( tag == TTAG_CID ) 1468 { 1469 pstable_index++; 1470 *offset += 22; 1471 *length -= 22; 1472 *is_sfnt_cid = TRUE; 1473 if ( face_index < 0 ) 1474 return FT_Err_Ok; 1475 } 1476 else if ( tag == TTAG_TYP1 ) 1477 { 1478 pstable_index++; 1479 *offset += 24; 1480 *length -= 24; 1481 *is_sfnt_cid = FALSE; 1482 if ( face_index < 0 ) 1483 return FT_Err_Ok; 1484 } 1485 if ( face_index >= 0 && pstable_index == face_index ) 1486 return FT_Err_Ok; 1487 } 1488 return FT_THROW( Table_Missing ); 1489 } 1490 1491 1492 FT_LOCAL_DEF( FT_Error ) 1493 open_face_PS_from_sfnt_stream( FT_Library library, 1494 FT_Stream stream, 1495 FT_Long face_index, 1496 FT_Int num_params, 1497 FT_Parameter *params, 1498 FT_Face *aface ) 1499 { 1500 FT_Error error; 1501 FT_Memory memory = library->memory; 1502 FT_ULong offset, length; 1503 FT_Long pos; 1504 FT_Bool is_sfnt_cid; 1505 FT_Byte* sfnt_ps = NULL; 1506 1507 FT_UNUSED( num_params ); 1508 FT_UNUSED( params ); 1509 1510 1511 pos = FT_Stream_Pos( stream ); 1512 1513 error = ft_lookup_PS_in_sfnt_stream( stream, 1514 face_index, 1515 &offset, 1516 &length, 1517 &is_sfnt_cid ); 1518 if ( error ) 1519 goto Exit; 1520 1521 if ( FT_Stream_Seek( stream, pos + offset ) ) 1522 goto Exit; 1523 1524 if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) ) 1525 goto Exit; 1526 1527 error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length ); 1528 if ( error ) 1529 goto Exit; 1530 1531 error = open_face_from_buffer( library, 1532 sfnt_ps, 1533 length, 1534 FT_MIN( face_index, 0 ), 1535 is_sfnt_cid ? "cid" : "type1", 1536 aface ); 1537 Exit: 1538 { 1539 FT_Error error1; 1540 1541 1542 if ( FT_ERR_EQ( error, Unknown_File_Format ) ) 1543 { 1544 error1 = FT_Stream_Seek( stream, pos ); 1545 if ( error1 ) 1546 return error1; 1547 } 1548 1549 return error; 1550 } 1551 } 1552 1553 1554 #ifndef FT_MACINTOSH 1555 1556 /* The resource header says we've got resource_cnt `POST' (type1) */ 1557 /* resources in this file. They all need to be coalesced into */ 1558 /* one lump which gets passed on to the type1 driver. */ 1559 /* Here can be only one PostScript font in a file so face_index */ 1560 /* must be 0 (or -1). */ 1561 /* */ 1562 static FT_Error 1563 Mac_Read_POST_Resource( FT_Library library, 1564 FT_Stream stream, 1565 FT_Long *offsets, 1566 FT_Long resource_cnt, 1567 FT_Long face_index, 1568 FT_Face *aface ) 1569 { 1570 FT_Error error = FT_ERR( Cannot_Open_Resource ); 1571 FT_Memory memory = library->memory; 1572 FT_Byte* pfb_data = NULL; 1573 int i, type, flags; 1574 FT_Long len; 1575 FT_Long pfb_len, pfb_pos, pfb_lenpos; 1576 FT_Long rlen, temp; 1577 1578 1579 if ( face_index == -1 ) 1580 face_index = 0; 1581 if ( face_index != 0 ) 1582 return error; 1583 1584 /* Find the length of all the POST resources, concatenated. Assume */ 1585 /* worst case (each resource in its own section). */ 1586 pfb_len = 0; 1587 for ( i = 0; i < resource_cnt; ++i ) 1588 { 1589 error = FT_Stream_Seek( stream, offsets[i] ); 1590 if ( error ) 1591 goto Exit; 1592 if ( FT_READ_LONG( temp ) ) 1593 goto Exit; 1594 pfb_len += temp + 6; 1595 } 1596 1597 if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) 1598 goto Exit; 1599 1600 pfb_data[0] = 0x80; 1601 pfb_data[1] = 1; /* Ascii section */ 1602 pfb_data[2] = 0; /* 4-byte length, fill in later */ 1603 pfb_data[3] = 0; 1604 pfb_data[4] = 0; 1605 pfb_data[5] = 0; 1606 pfb_pos = 6; 1607 pfb_lenpos = 2; 1608 1609 len = 0; 1610 type = 1; 1611 for ( i = 0; i < resource_cnt; ++i ) 1612 { 1613 error = FT_Stream_Seek( stream, offsets[i] ); 1614 if ( error ) 1615 goto Exit2; 1616 if ( FT_READ_LONG( rlen ) ) 1617 goto Exit; 1618 if ( FT_READ_USHORT( flags ) ) 1619 goto Exit; 1620 FT_TRACE3(( "POST fragment[%d]: offsets=0x%08x, rlen=0x%08x, flags=0x%04x\n", 1621 i, offsets[i], rlen, flags )); 1622 1623 /* postpone the check of rlen longer than buffer until FT_Stream_Read() */ 1624 if ( ( flags >> 8 ) == 0 ) /* Comment, should not be loaded */ 1625 continue; 1626 1627 /* the flags are part of the resource, so rlen >= 2. */ 1628 /* but some fonts declare rlen = 0 for empty fragment */ 1629 if ( rlen > 2 ) 1630 rlen -= 2; 1631 else 1632 rlen = 0; 1633 1634 if ( ( flags >> 8 ) == type ) 1635 len += rlen; 1636 else 1637 { 1638 if ( pfb_lenpos + 3 > pfb_len + 2 ) 1639 goto Exit2; 1640 pfb_data[pfb_lenpos ] = (FT_Byte)( len ); 1641 pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); 1642 pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); 1643 pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); 1644 1645 if ( ( flags >> 8 ) == 5 ) /* End of font mark */ 1646 break; 1647 1648 if ( pfb_pos + 6 > pfb_len + 2 ) 1649 goto Exit2; 1650 pfb_data[pfb_pos++] = 0x80; 1651 1652 type = flags >> 8; 1653 len = rlen; 1654 1655 pfb_data[pfb_pos++] = (FT_Byte)type; 1656 pfb_lenpos = pfb_pos; 1657 pfb_data[pfb_pos++] = 0; /* 4-byte length, fill in later */ 1658 pfb_data[pfb_pos++] = 0; 1659 pfb_data[pfb_pos++] = 0; 1660 pfb_data[pfb_pos++] = 0; 1661 } 1662 1663 error = FT_ERR( Cannot_Open_Resource ); 1664 if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len ) 1665 goto Exit2; 1666 1667 error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen ); 1668 if ( error ) 1669 goto Exit2; 1670 pfb_pos += rlen; 1671 } 1672 1673 if ( pfb_pos + 2 > pfb_len + 2 ) 1674 goto Exit2; 1675 pfb_data[pfb_pos++] = 0x80; 1676 pfb_data[pfb_pos++] = 3; 1677 1678 if ( pfb_lenpos + 3 > pfb_len + 2 ) 1679 goto Exit2; 1680 pfb_data[pfb_lenpos ] = (FT_Byte)( len ); 1681 pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); 1682 pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); 1683 pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); 1684 1685 return open_face_from_buffer( library, 1686 pfb_data, 1687 pfb_pos, 1688 face_index, 1689 "type1", 1690 aface ); 1691 1692 Exit2: 1693 FT_FREE( pfb_data ); 1694 1695 Exit: 1696 return error; 1697 } 1698 1699 1700 /* The resource header says we've got resource_cnt `sfnt' */ 1701 /* (TrueType/OpenType) resources in this file. Look through */ 1702 /* them for the one indicated by face_index, load it into mem, */ 1703 /* pass it on the the truetype driver and return it. */ 1704 /* */ 1705 static FT_Error 1706 Mac_Read_sfnt_Resource( FT_Library library, 1707 FT_Stream stream, 1708 FT_Long *offsets, 1709 FT_Long resource_cnt, 1710 FT_Long face_index, 1711 FT_Face *aface ) 1712 { 1713 FT_Memory memory = library->memory; 1714 FT_Byte* sfnt_data = NULL; 1715 FT_Error error; 1716 FT_Long flag_offset; 1717 FT_Long rlen; 1718 int is_cff; 1719 FT_Long face_index_in_resource = 0; 1720 1721 1722 if ( face_index == -1 ) 1723 face_index = 0; 1724 if ( face_index >= resource_cnt ) 1725 return FT_THROW( Cannot_Open_Resource ); 1726 1727 flag_offset = offsets[face_index]; 1728 error = FT_Stream_Seek( stream, flag_offset ); 1729 if ( error ) 1730 goto Exit; 1731 1732 if ( FT_READ_LONG( rlen ) ) 1733 goto Exit; 1734 if ( rlen == -1 ) 1735 return FT_THROW( Cannot_Open_Resource ); 1736 1737 error = open_face_PS_from_sfnt_stream( library, 1738 stream, 1739 face_index, 1740 0, NULL, 1741 aface ); 1742 if ( !error ) 1743 goto Exit; 1744 1745 /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */ 1746 if ( FT_Stream_Seek( stream, flag_offset + 4 ) ) 1747 goto Exit; 1748 1749 if ( FT_ALLOC( sfnt_data, (FT_Long)rlen ) ) 1750 return error; 1751 error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen ); 1752 if ( error ) 1753 goto Exit; 1754 1755 is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); 1756 error = open_face_from_buffer( library, 1757 sfnt_data, 1758 rlen, 1759 face_index_in_resource, 1760 is_cff ? "cff" : "truetype", 1761 aface ); 1762 1763 Exit: 1764 return error; 1765 } 1766 1767 1768 /* Check for a valid resource fork header, or a valid dfont */ 1769 /* header. In a resource fork the first 16 bytes are repeated */ 1770 /* at the location specified by bytes 4-7. In a dfont bytes */ 1771 /* 4-7 point to 16 bytes of zeroes instead. */ 1772 /* */ 1773 static FT_Error 1774 IsMacResource( FT_Library library, 1775 FT_Stream stream, 1776 FT_Long resource_offset, 1777 FT_Long face_index, 1778 FT_Face *aface ) 1779 { 1780 FT_Memory memory = library->memory; 1781 FT_Error error; 1782 FT_Long map_offset, rdara_pos; 1783 FT_Long *data_offsets; 1784 FT_Long count; 1785 1786 1787 error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset, 1788 &map_offset, &rdara_pos ); 1789 if ( error ) 1790 return error; 1791 1792 error = FT_Raccess_Get_DataOffsets( library, stream, 1793 map_offset, rdara_pos, 1794 TTAG_POST, 1795 &data_offsets, &count ); 1796 if ( !error ) 1797 { 1798 error = Mac_Read_POST_Resource( library, stream, data_offsets, count, 1799 face_index, aface ); 1800 FT_FREE( data_offsets ); 1801 /* POST exists in an LWFN providing a single face */ 1802 if ( !error ) 1803 (*aface)->num_faces = 1; 1804 return error; 1805 } 1806 1807 error = FT_Raccess_Get_DataOffsets( library, stream, 1808 map_offset, rdara_pos, 1809 TTAG_sfnt, 1810 &data_offsets, &count ); 1811 if ( !error ) 1812 { 1813 FT_Long face_index_internal = face_index % count; 1814 1815 1816 error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count, 1817 face_index_internal, aface ); 1818 FT_FREE( data_offsets ); 1819 if ( !error ) 1820 (*aface)->num_faces = count; 1821 } 1822 1823 return error; 1824 } 1825 1826 1827 /* Check for a valid macbinary header, and if we find one */ 1828 /* check that the (flattened) resource fork in it is valid. */ 1829 /* */ 1830 static FT_Error 1831 IsMacBinary( FT_Library library, 1832 FT_Stream stream, 1833 FT_Long face_index, 1834 FT_Face *aface ) 1835 { 1836 unsigned char header[128]; 1837 FT_Error error; 1838 FT_Long dlen, offset; 1839 1840 1841 if ( NULL == stream ) 1842 return FT_THROW( Invalid_Stream_Operation ); 1843 1844 error = FT_Stream_Seek( stream, 0 ); 1845 if ( error ) 1846 goto Exit; 1847 1848 error = FT_Stream_Read( stream, (FT_Byte*)header, 128 ); 1849 if ( error ) 1850 goto Exit; 1851 1852 if ( header[ 0] != 0 || 1853 header[74] != 0 || 1854 header[82] != 0 || 1855 header[ 1] == 0 || 1856 header[ 1] > 33 || 1857 header[63] != 0 || 1858 header[2 + header[1]] != 0 ) 1859 return FT_THROW( Unknown_File_Format ); 1860 1861 dlen = ( header[0x53] << 24 ) | 1862 ( header[0x54] << 16 ) | 1863 ( header[0x55] << 8 ) | 1864 header[0x56]; 1865 #if 0 1866 rlen = ( header[0x57] << 24 ) | 1867 ( header[0x58] << 16 ) | 1868 ( header[0x59] << 8 ) | 1869 header[0x5a]; 1870 #endif /* 0 */ 1871 offset = 128 + ( ( dlen + 127 ) & ~127 ); 1872 1873 return IsMacResource( library, stream, offset, face_index, aface ); 1874 1875 Exit: 1876 return error; 1877 } 1878 1879 1880 static FT_Error 1881 load_face_in_embedded_rfork( FT_Library library, 1882 FT_Stream stream, 1883 FT_Long face_index, 1884 FT_Face *aface, 1885 const FT_Open_Args *args ) 1886 { 1887 1888 #undef FT_COMPONENT 1889 #define FT_COMPONENT trace_raccess 1890 1891 FT_Memory memory = library->memory; 1892 FT_Error error = FT_ERR( Unknown_File_Format ); 1893 int i; 1894 1895 char * file_names[FT_RACCESS_N_RULES]; 1896 FT_Long offsets[FT_RACCESS_N_RULES]; 1897 FT_Error errors[FT_RACCESS_N_RULES]; 1898 FT_Bool is_darwin_vfs, vfs_rfork_has_no_font = FALSE; /* not tested */ 1899 1900 FT_Open_Args args2; 1901 FT_Stream stream2 = 0; 1902 1903 1904 FT_Raccess_Guess( library, stream, 1905 args->pathname, file_names, offsets, errors ); 1906 1907 for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) 1908 { 1909 is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i ); 1910 if ( is_darwin_vfs && vfs_rfork_has_no_font ) 1911 { 1912 FT_TRACE3(( "Skip rule %d: darwin vfs resource fork" 1913 " is already checked and" 1914 " no font is found\n", i )); 1915 continue; 1916 } 1917 1918 if ( errors[i] ) 1919 { 1920 FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors[i], i )); 1921 continue; 1922 } 1923 1924 args2.flags = FT_OPEN_PATHNAME; 1925 args2.pathname = file_names[i] ? file_names[i] : args->pathname; 1926 1927 FT_TRACE3(( "Try rule %d: %s (offset=%d) ...", 1928 i, args2.pathname, offsets[i] )); 1929 1930 error = FT_Stream_New( library, &args2, &stream2 ); 1931 if ( is_darwin_vfs && FT_ERR_EQ( error, Cannot_Open_Stream ) ) 1932 vfs_rfork_has_no_font = TRUE; 1933 1934 if ( error ) 1935 { 1936 FT_TRACE3(( "failed\n" )); 1937 continue; 1938 } 1939 1940 error = IsMacResource( library, stream2, offsets[i], 1941 face_index, aface ); 1942 FT_Stream_Free( stream2, 0 ); 1943 1944 FT_TRACE3(( "%s\n", error ? "failed": "successful" )); 1945 1946 if ( !error ) 1947 break; 1948 else if ( is_darwin_vfs ) 1949 vfs_rfork_has_no_font = TRUE; 1950 } 1951 1952 for (i = 0; i < FT_RACCESS_N_RULES; i++) 1953 { 1954 if ( file_names[i] ) 1955 FT_FREE( file_names[i] ); 1956 } 1957 1958 /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */ 1959 if ( error ) 1960 error = FT_ERR( Unknown_File_Format ); 1961 1962 return error; 1963 1964 #undef FT_COMPONENT 1965 #define FT_COMPONENT trace_objs 1966 1967 } 1968 1969 1970 /* Check for some macintosh formats without Carbon framework. */ 1971 /* Is this a macbinary file? If so look at the resource fork. */ 1972 /* Is this a mac dfont file? */ 1973 /* Is this an old style resource fork? (in data) */ 1974 /* Else call load_face_in_embedded_rfork to try extra rules */ 1975 /* (defined in `ftrfork.c'). */ 1976 /* */ 1977 static FT_Error 1978 load_mac_face( FT_Library library, 1979 FT_Stream stream, 1980 FT_Long face_index, 1981 FT_Face *aface, 1982 const FT_Open_Args *args ) 1983 { 1984 FT_Error error; 1985 FT_UNUSED( args ); 1986 1987 1988 error = IsMacBinary( library, stream, face_index, aface ); 1989 if ( FT_ERR_EQ( error, Unknown_File_Format ) ) 1990 { 1991 1992 #undef FT_COMPONENT 1993 #define FT_COMPONENT trace_raccess 1994 1995 FT_TRACE3(( "Try as dfont: %s ...", args->pathname )); 1996 1997 error = IsMacResource( library, stream, 0, face_index, aface ); 1998 1999 FT_TRACE3(( "%s\n", error ? "failed" : "successful" )); 2000 2001 #undef FT_COMPONENT 2002 #define FT_COMPONENT trace_objs 2003 2004 } 2005 2006 if ( ( FT_ERR_EQ( error, Unknown_File_Format ) || 2007 FT_ERR_EQ( error, Invalid_Stream_Operation ) ) && 2008 ( args->flags & FT_OPEN_PATHNAME ) ) 2009 error = load_face_in_embedded_rfork( library, stream, 2010 face_index, aface, args ); 2011 return error; 2012 } 2013 #endif 2014 2015 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ 2016 2017 2018 /* documentation is in freetype.h */ 2019 2020 FT_EXPORT_DEF( FT_Error ) 2021 FT_Open_Face( FT_Library library, 2022 const FT_Open_Args* args, 2023 FT_Long face_index, 2024 FT_Face *aface ) 2025 { 2026 FT_Error error; 2027 FT_Driver driver = NULL; 2028 FT_Memory memory = NULL; 2029 FT_Stream stream = NULL; 2030 FT_Face face = NULL; 2031 FT_ListNode node = NULL; 2032 FT_Bool external_stream; 2033 FT_Module* cur; 2034 FT_Module* limit; 2035 2036 2037 /* test for valid `library' delayed to */ 2038 /* FT_Stream_New() */ 2039 2040 if ( ( !aface && face_index >= 0 ) || !args ) 2041 return FT_THROW( Invalid_Argument ); 2042 2043 external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) && 2044 args->stream ); 2045 2046 /* create input stream */ 2047 error = FT_Stream_New( library, args, &stream ); 2048 if ( error ) 2049 goto Fail3; 2050 2051 memory = library->memory; 2052 2053 /* If the font driver is specified in the `args' structure, use */ 2054 /* it. Otherwise, we scan the list of registered drivers. */ 2055 if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver ) 2056 { 2057 driver = FT_DRIVER( args->driver ); 2058 2059 /* not all modules are drivers, so check... */ 2060 if ( FT_MODULE_IS_DRIVER( driver ) ) 2061 { 2062 FT_Int num_params = 0; 2063 FT_Parameter* params = 0; 2064 2065 2066 if ( args->flags & FT_OPEN_PARAMS ) 2067 { 2068 num_params = args->num_params; 2069 params = args->params; 2070 } 2071 2072 error = open_face( driver, stream, face_index, 2073 num_params, params, &face ); 2074 if ( !error ) 2075 goto Success; 2076 } 2077 else 2078 error = FT_THROW( Invalid_Handle ); 2079 2080 FT_Stream_Free( stream, external_stream ); 2081 goto Fail; 2082 } 2083 else 2084 { 2085 error = FT_ERR( Missing_Module ); 2086 2087 /* check each font driver for an appropriate format */ 2088 cur = library->modules; 2089 limit = cur + library->num_modules; 2090 2091 for ( ; cur < limit; cur++ ) 2092 { 2093 /* not all modules are font drivers, so check... */ 2094 if ( FT_MODULE_IS_DRIVER( cur[0] ) ) 2095 { 2096 FT_Int num_params = 0; 2097 FT_Parameter* params = 0; 2098 2099 2100 driver = FT_DRIVER( cur[0] ); 2101 2102 if ( args->flags & FT_OPEN_PARAMS ) 2103 { 2104 num_params = args->num_params; 2105 params = args->params; 2106 } 2107 2108 error = open_face( driver, stream, face_index, 2109 num_params, params, &face ); 2110 if ( !error ) 2111 goto Success; 2112 2113 #ifdef FT_CONFIG_OPTION_MAC_FONTS 2114 if ( ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 && 2115 FT_ERR_EQ( error, Table_Missing ) ) 2116 { 2117 /* TrueType but essential tables are missing */ 2118 if ( FT_Stream_Seek( stream, 0 ) ) 2119 break; 2120 2121 error = open_face_PS_from_sfnt_stream( library, 2122 stream, 2123 face_index, 2124 num_params, 2125 params, 2126 aface ); 2127 if ( !error ) 2128 { 2129 FT_Stream_Free( stream, external_stream ); 2130 return error; 2131 } 2132 } 2133 #endif 2134 2135 if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) 2136 goto Fail3; 2137 } 2138 } 2139 2140 Fail3: 2141 /* If we are on the mac, and we get an */ 2142 /* FT_Err_Invalid_Stream_Operation it may be because we have an */ 2143 /* empty data fork, so we need to check the resource fork. */ 2144 if ( FT_ERR_NEQ( error, Cannot_Open_Stream ) && 2145 FT_ERR_NEQ( error, Unknown_File_Format ) && 2146 FT_ERR_NEQ( error, Invalid_Stream_Operation ) ) 2147 goto Fail2; 2148 2149 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS ) 2150 error = load_mac_face( library, stream, face_index, aface, args ); 2151 if ( !error ) 2152 { 2153 /* We don't want to go to Success here. We've already done that. */ 2154 /* On the other hand, if we succeeded we still need to close this */ 2155 /* stream (we opened a different stream which extracted the */ 2156 /* interesting information out of this stream here. That stream */ 2157 /* will still be open and the face will point to it). */ 2158 FT_Stream_Free( stream, external_stream ); 2159 return error; 2160 } 2161 2162 if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) 2163 goto Fail2; 2164 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ 2165 2166 /* no driver is able to handle this format */ 2167 error = FT_THROW( Unknown_File_Format ); 2168 2169 Fail2: 2170 FT_Stream_Free( stream, external_stream ); 2171 goto Fail; 2172 } 2173 2174 Success: 2175 FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" )); 2176 2177 /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */ 2178 if ( external_stream ) 2179 face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; 2180 2181 /* add the face object to its driver's list */ 2182 if ( FT_NEW( node ) ) 2183 goto Fail; 2184 2185 node->data = face; 2186 /* don't assume driver is the same as face->driver, so use */ 2187 /* face->driver instead. */ 2188 FT_List_Add( &face->driver->faces_list, node ); 2189 2190 /* now allocate a glyph slot object for the face */ 2191 FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" )); 2192 2193 if ( face_index >= 0 ) 2194 { 2195 error = FT_New_GlyphSlot( face, NULL ); 2196 if ( error ) 2197 goto Fail; 2198 2199 /* finally, allocate a size object for the face */ 2200 { 2201 FT_Size size; 2202 2203 2204 FT_TRACE4(( "FT_Open_Face: Creating size object\n" )); 2205 2206 error = FT_New_Size( face, &size ); 2207 if ( error ) 2208 goto Fail; 2209 2210 face->size = size; 2211 } 2212 } 2213 2214 /* some checks */ 2215 2216 if ( FT_IS_SCALABLE( face ) ) 2217 { 2218 if ( face->height < 0 ) 2219 face->height = (FT_Short)-face->height; 2220 2221 if ( !FT_HAS_VERTICAL( face ) ) 2222 face->max_advance_height = (FT_Short)face->height; 2223 } 2224 2225 if ( FT_HAS_FIXED_SIZES( face ) ) 2226 { 2227 FT_Int i; 2228 2229 2230 for ( i = 0; i < face->num_fixed_sizes; i++ ) 2231 { 2232 FT_Bitmap_Size* bsize = face->available_sizes + i; 2233 2234 2235 if ( bsize->height < 0 ) 2236 bsize->height = (FT_Short)-bsize->height; 2237 if ( bsize->x_ppem < 0 ) 2238 bsize->x_ppem = (FT_Short)-bsize->x_ppem; 2239 if ( bsize->y_ppem < 0 ) 2240 bsize->y_ppem = -bsize->y_ppem; 2241 } 2242 } 2243 2244 /* initialize internal face data */ 2245 { 2246 FT_Face_Internal internal = face->internal; 2247 2248 2249 internal->transform_matrix.xx = 0x10000L; 2250 internal->transform_matrix.xy = 0; 2251 internal->transform_matrix.yx = 0; 2252 internal->transform_matrix.yy = 0x10000L; 2253 2254 internal->transform_delta.x = 0; 2255 internal->transform_delta.y = 0; 2256 2257 internal->refcount = 1; 2258 } 2259 2260 if ( aface ) 2261 *aface = face; 2262 else 2263 FT_Done_Face( face ); 2264 2265 goto Exit; 2266 2267 Fail: 2268 if ( node ) 2269 FT_Done_Face( face ); /* face must be in the driver's list */ 2270 else if ( face ) 2271 destroy_face( memory, face, driver ); 2272 2273 Exit: 2274 FT_TRACE4(( "FT_Open_Face: Return %d\n", error )); 2275 2276 return error; 2277 } 2278 2279 2280 /* documentation is in freetype.h */ 2281 2282 FT_EXPORT_DEF( FT_Error ) 2283 FT_Attach_File( FT_Face face, 2284 const char* filepathname ) 2285 { 2286 FT_Open_Args open; 2287 2288 2289 /* test for valid `face' delayed to FT_Attach_Stream() */ 2290 2291 if ( !filepathname ) 2292 return FT_THROW( Invalid_Argument ); 2293 2294 open.stream = NULL; 2295 open.flags = FT_OPEN_PATHNAME; 2296 open.pathname = (char*)filepathname; 2297 2298 return FT_Attach_Stream( face, &open ); 2299 } 2300 2301 2302 /* documentation is in freetype.h */ 2303 2304 FT_EXPORT_DEF( FT_Error ) 2305 FT_Attach_Stream( FT_Face face, 2306 FT_Open_Args* parameters ) 2307 { 2308 FT_Stream stream; 2309 FT_Error error; 2310 FT_Driver driver; 2311 2312 FT_Driver_Class clazz; 2313 2314 2315 /* test for valid `parameters' delayed to FT_Stream_New() */ 2316 2317 if ( !face ) 2318 return FT_THROW( Invalid_Face_Handle ); 2319 2320 driver = face->driver; 2321 if ( !driver ) 2322 return FT_THROW( Invalid_Driver_Handle ); 2323 2324 error = FT_Stream_New( driver->root.library, parameters, &stream ); 2325 if ( error ) 2326 goto Exit; 2327 2328 /* we implement FT_Attach_Stream in each driver through the */ 2329 /* `attach_file' interface */ 2330 2331 error = FT_ERR( Unimplemented_Feature ); 2332 clazz = driver->clazz; 2333 if ( clazz->attach_file ) 2334 error = clazz->attach_file( face, stream ); 2335 2336 /* close the attached stream */ 2337 FT_Stream_Free( stream, 2338 (FT_Bool)( parameters->stream && 2339 ( parameters->flags & FT_OPEN_STREAM ) ) ); 2340 2341 Exit: 2342 return error; 2343 } 2344 2345 2346 /* documentation is in freetype.h */ 2347 2348 FT_EXPORT_DEF( FT_Error ) 2349 FT_Reference_Face( FT_Face face ) 2350 { 2351 face->internal->refcount++; 2352 2353 return FT_Err_Ok; 2354 } 2355 2356 2357 /* documentation is in freetype.h */ 2358 2359 FT_EXPORT_DEF( FT_Error ) 2360 FT_Done_Face( FT_Face face ) 2361 { 2362 FT_Error error; 2363 FT_Driver driver; 2364 FT_Memory memory; 2365 FT_ListNode node; 2366 2367 2368 error = FT_ERR( Invalid_Face_Handle ); 2369 if ( face && face->driver ) 2370 { 2371 face->internal->refcount--; 2372 if ( face->internal->refcount > 0 ) 2373 error = FT_Err_Ok; 2374 else 2375 { 2376 driver = face->driver; 2377 memory = driver->root.memory; 2378 2379 /* find face in driver's list */ 2380 node = FT_List_Find( &driver->faces_list, face ); 2381 if ( node ) 2382 { 2383 /* remove face object from the driver's list */ 2384 FT_List_Remove( &driver->faces_list, node ); 2385 FT_FREE( node ); 2386 2387 /* now destroy the object proper */ 2388 destroy_face( memory, face, driver ); 2389 error = FT_Err_Ok; 2390 } 2391 } 2392 } 2393 2394 return error; 2395 } 2396 2397 2398 /* documentation is in ftobjs.h */ 2399 2400 FT_EXPORT_DEF( FT_Error ) 2401 FT_New_Size( FT_Face face, 2402 FT_Size *asize ) 2403 { 2404 FT_Error error; 2405 FT_Memory memory; 2406 FT_Driver driver; 2407 FT_Driver_Class clazz; 2408 2409 FT_Size size = 0; 2410 FT_ListNode node = 0; 2411 2412 2413 if ( !face ) 2414 return FT_THROW( Invalid_Face_Handle ); 2415 2416 if ( !asize ) 2417 return FT_THROW( Invalid_Size_Handle ); 2418 2419 if ( !face->driver ) 2420 return FT_THROW( Invalid_Driver_Handle ); 2421 2422 *asize = 0; 2423 2424 driver = face->driver; 2425 clazz = driver->clazz; 2426 memory = face->memory; 2427 2428 /* Allocate new size object and perform basic initialisation */ 2429 if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) ) 2430 goto Exit; 2431 2432 size->face = face; 2433 2434 /* for now, do not use any internal fields in size objects */ 2435 size->internal = 0; 2436 2437 if ( clazz->init_size ) 2438 error = clazz->init_size( size ); 2439 2440 /* in case of success, add to the face's list */ 2441 if ( !error ) 2442 { 2443 *asize = size; 2444 node->data = size; 2445 FT_List_Add( &face->sizes_list, node ); 2446 } 2447 2448 Exit: 2449 if ( error ) 2450 { 2451 FT_FREE( node ); 2452 FT_FREE( size ); 2453 } 2454 2455 return error; 2456 } 2457 2458 2459 /* documentation is in ftobjs.h */ 2460 2461 FT_EXPORT_DEF( FT_Error ) 2462 FT_Done_Size( FT_Size size ) 2463 { 2464 FT_Error error; 2465 FT_Driver driver; 2466 FT_Memory memory; 2467 FT_Face face; 2468 FT_ListNode node; 2469 2470 2471 if ( !size ) 2472 return FT_THROW( Invalid_Size_Handle ); 2473 2474 face = size->face; 2475 if ( !face ) 2476 return FT_THROW( Invalid_Face_Handle ); 2477 2478 driver = face->driver; 2479 if ( !driver ) 2480 return FT_THROW( Invalid_Driver_Handle ); 2481 2482 memory = driver->root.memory; 2483 2484 error = FT_Err_Ok; 2485 node = FT_List_Find( &face->sizes_list, size ); 2486 if ( node ) 2487 { 2488 FT_List_Remove( &face->sizes_list, node ); 2489 FT_FREE( node ); 2490 2491 if ( face->size == size ) 2492 { 2493 face->size = 0; 2494 if ( face->sizes_list.head ) 2495 face->size = (FT_Size)(face->sizes_list.head->data); 2496 } 2497 2498 destroy_size( memory, size, driver ); 2499 } 2500 else 2501 error = FT_THROW( Invalid_Size_Handle ); 2502 2503 return error; 2504 } 2505 2506 2507 /* documentation is in ftobjs.h */ 2508 2509 FT_BASE_DEF( FT_Error ) 2510 FT_Match_Size( FT_Face face, 2511 FT_Size_Request req, 2512 FT_Bool ignore_width, 2513 FT_ULong* size_index ) 2514 { 2515 FT_Int i; 2516 FT_Long w, h; 2517 2518 2519 if ( !FT_HAS_FIXED_SIZES( face ) ) 2520 return FT_THROW( Invalid_Face_Handle ); 2521 2522 /* FT_Bitmap_Size doesn't provide enough info... */ 2523 if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) 2524 return FT_THROW( Unimplemented_Feature ); 2525 2526 w = FT_REQUEST_WIDTH ( req ); 2527 h = FT_REQUEST_HEIGHT( req ); 2528 2529 if ( req->width && !req->height ) 2530 h = w; 2531 else if ( !req->width && req->height ) 2532 w = h; 2533 2534 w = FT_PIX_ROUND( w ); 2535 h = FT_PIX_ROUND( h ); 2536 2537 for ( i = 0; i < face->num_fixed_sizes; i++ ) 2538 { 2539 FT_Bitmap_Size* bsize = face->available_sizes + i; 2540 2541 2542 if ( h != FT_PIX_ROUND( bsize->y_ppem ) ) 2543 continue; 2544 2545 if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width ) 2546 { 2547 FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i )); 2548 2549 if ( size_index ) 2550 *size_index = (FT_ULong)i; 2551 2552 return FT_Err_Ok; 2553 } 2554 } 2555 2556 return FT_THROW( Invalid_Pixel_Size ); 2557 } 2558 2559 2560 /* documentation is in ftobjs.h */ 2561 2562 FT_BASE_DEF( void ) 2563 ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, 2564 FT_Pos advance ) 2565 { 2566 FT_Pos height = metrics->height; 2567 2568 2569 /* compensate for glyph with bbox above/below the baseline */ 2570 if ( metrics->horiBearingY < 0 ) 2571 { 2572 if ( height < metrics->horiBearingY ) 2573 height = metrics->horiBearingY; 2574 } 2575 else if ( metrics->horiBearingY > 0 ) 2576 height -= metrics->horiBearingY; 2577 2578 /* the factor 1.2 is a heuristical value */ 2579 if ( !advance ) 2580 advance = height * 12 / 10; 2581 2582 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2; 2583 metrics->vertBearingY = ( advance - height ) / 2; 2584 metrics->vertAdvance = advance; 2585 } 2586 2587 2588 static void 2589 ft_recompute_scaled_metrics( FT_Face face, 2590 FT_Size_Metrics* metrics ) 2591 { 2592 /* Compute root ascender, descender, test height, and max_advance */ 2593 2594 #ifdef GRID_FIT_METRICS 2595 metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender, 2596 metrics->y_scale ) ); 2597 2598 metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender, 2599 metrics->y_scale ) ); 2600 2601 metrics->height = FT_PIX_ROUND( FT_MulFix( face->height, 2602 metrics->y_scale ) ); 2603 2604 metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width, 2605 metrics->x_scale ) ); 2606 #else /* !GRID_FIT_METRICS */ 2607 metrics->ascender = FT_MulFix( face->ascender, 2608 metrics->y_scale ); 2609 2610 metrics->descender = FT_MulFix( face->descender, 2611 metrics->y_scale ); 2612 2613 metrics->height = FT_MulFix( face->height, 2614 metrics->y_scale ); 2615 2616 metrics->max_advance = FT_MulFix( face->max_advance_width, 2617 metrics->x_scale ); 2618 #endif /* !GRID_FIT_METRICS */ 2619 } 2620 2621 2622 FT_BASE_DEF( void ) 2623 FT_Select_Metrics( FT_Face face, 2624 FT_ULong strike_index ) 2625 { 2626 FT_Size_Metrics* metrics; 2627 FT_Bitmap_Size* bsize; 2628 2629 2630 metrics = &face->size->metrics; 2631 bsize = face->available_sizes + strike_index; 2632 2633 metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 ); 2634 metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 ); 2635 2636 if ( FT_IS_SCALABLE( face ) ) 2637 { 2638 metrics->x_scale = FT_DivFix( bsize->x_ppem, 2639 face->units_per_EM ); 2640 metrics->y_scale = FT_DivFix( bsize->y_ppem, 2641 face->units_per_EM ); 2642 2643 ft_recompute_scaled_metrics( face, metrics ); 2644 } 2645 else 2646 { 2647 metrics->x_scale = 1L << 16; 2648 metrics->y_scale = 1L << 16; 2649 metrics->ascender = bsize->y_ppem; 2650 metrics->descender = 0; 2651 metrics->height = bsize->height << 6; 2652 metrics->max_advance = bsize->x_ppem; 2653 } 2654 2655 FT_TRACE5(( "FT_Select_Metrics:\n" )); 2656 FT_TRACE5(( " x scale: %d (%f)\n", 2657 metrics->x_scale, metrics->x_scale / 65536.0 )); 2658 FT_TRACE5(( " y scale: %d (%f)\n", 2659 metrics->y_scale, metrics->y_scale / 65536.0 )); 2660 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); 2661 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); 2662 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); 2663 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); 2664 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); 2665 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); 2666 } 2667 2668 2669 FT_BASE_DEF( void ) 2670 FT_Request_Metrics( FT_Face face, 2671 FT_Size_Request req ) 2672 { 2673 FT_Size_Metrics* metrics; 2674 2675 2676 metrics = &face->size->metrics; 2677 2678 if ( FT_IS_SCALABLE( face ) ) 2679 { 2680 FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0; 2681 2682 2683 switch ( req->type ) 2684 { 2685 case FT_SIZE_REQUEST_TYPE_NOMINAL: 2686 w = h = face->units_per_EM; 2687 break; 2688 2689 case FT_SIZE_REQUEST_TYPE_REAL_DIM: 2690 w = h = face->ascender - face->descender; 2691 break; 2692 2693 case FT_SIZE_REQUEST_TYPE_BBOX: 2694 w = face->bbox.xMax - face->bbox.xMin; 2695 h = face->bbox.yMax - face->bbox.yMin; 2696 break; 2697 2698 case FT_SIZE_REQUEST_TYPE_CELL: 2699 w = face->max_advance_width; 2700 h = face->ascender - face->descender; 2701 break; 2702 2703 case FT_SIZE_REQUEST_TYPE_SCALES: 2704 metrics->x_scale = (FT_Fixed)req->width; 2705 metrics->y_scale = (FT_Fixed)req->height; 2706 if ( !metrics->x_scale ) 2707 metrics->x_scale = metrics->y_scale; 2708 else if ( !metrics->y_scale ) 2709 metrics->y_scale = metrics->x_scale; 2710 goto Calculate_Ppem; 2711 2712 case FT_SIZE_REQUEST_TYPE_MAX: 2713 break; 2714 } 2715 2716 /* to be on the safe side */ 2717 if ( w < 0 ) 2718 w = -w; 2719 2720 if ( h < 0 ) 2721 h = -h; 2722 2723 scaled_w = FT_REQUEST_WIDTH ( req ); 2724 scaled_h = FT_REQUEST_HEIGHT( req ); 2725 2726 /* determine scales */ 2727 if ( req->width ) 2728 { 2729 metrics->x_scale = FT_DivFix( scaled_w, w ); 2730 2731 if ( req->height ) 2732 { 2733 metrics->y_scale = FT_DivFix( scaled_h, h ); 2734 2735 if ( req->type == FT_SIZE_REQUEST_TYPE_CELL ) 2736 { 2737 if ( metrics->y_scale > metrics->x_scale ) 2738 metrics->y_scale = metrics->x_scale; 2739 else 2740 metrics->x_scale = metrics->y_scale; 2741 } 2742 } 2743 else 2744 { 2745 metrics->y_scale = metrics->x_scale; 2746 scaled_h = FT_MulDiv( scaled_w, h, w ); 2747 } 2748 } 2749 else 2750 { 2751 metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h ); 2752 scaled_w = FT_MulDiv( scaled_h, w, h ); 2753 } 2754 2755 Calculate_Ppem: 2756 /* calculate the ppems */ 2757 if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) 2758 { 2759 scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale ); 2760 scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale ); 2761 } 2762 2763 metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 ); 2764 metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 ); 2765 2766 ft_recompute_scaled_metrics( face, metrics ); 2767 } 2768 else 2769 { 2770 FT_ZERO( metrics ); 2771 metrics->x_scale = 1L << 16; 2772 metrics->y_scale = 1L << 16; 2773 } 2774 2775 FT_TRACE5(( "FT_Request_Metrics:\n" )); 2776 FT_TRACE5(( " x scale: %d (%f)\n", 2777 metrics->x_scale, metrics->x_scale / 65536.0 )); 2778 FT_TRACE5(( " y scale: %d (%f)\n", 2779 metrics->y_scale, metrics->y_scale / 65536.0 )); 2780 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); 2781 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); 2782 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); 2783 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); 2784 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); 2785 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); 2786 } 2787 2788 2789 /* documentation is in freetype.h */ 2790 2791 FT_EXPORT_DEF( FT_Error ) 2792 FT_Select_Size( FT_Face face, 2793 FT_Int strike_index ) 2794 { 2795 FT_Driver_Class clazz; 2796 2797 2798 if ( !face || !FT_HAS_FIXED_SIZES( face ) ) 2799 return FT_THROW( Invalid_Face_Handle ); 2800 2801 if ( strike_index < 0 || strike_index >= face->num_fixed_sizes ) 2802 return FT_THROW( Invalid_Argument ); 2803 2804 clazz = face->driver->clazz; 2805 2806 if ( clazz->select_size ) 2807 { 2808 FT_Error error; 2809 2810 2811 error = clazz->select_size( face->size, (FT_ULong)strike_index ); 2812 2813 #ifdef FT_DEBUG_LEVEL_TRACE 2814 { 2815 FT_Size_Metrics* metrics = &face->size->metrics; 2816 2817 2818 FT_TRACE5(( "FT_Select_Size (font driver's `select_size'):\n" )); 2819 FT_TRACE5(( " x scale: %d (%f)\n", 2820 metrics->x_scale, metrics->x_scale / 65536.0 )); 2821 FT_TRACE5(( " y scale: %d (%f)\n", 2822 metrics->y_scale, metrics->y_scale / 65536.0 )); 2823 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); 2824 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); 2825 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); 2826 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); 2827 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); 2828 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); 2829 } 2830 #endif 2831 2832 return error; 2833 } 2834 2835 FT_Select_Metrics( face, (FT_ULong)strike_index ); 2836 2837 return FT_Err_Ok; 2838 } 2839 2840 2841 /* documentation is in freetype.h */ 2842 2843 FT_EXPORT_DEF( FT_Error ) 2844 FT_Request_Size( FT_Face face, 2845 FT_Size_Request req ) 2846 { 2847 FT_Driver_Class clazz; 2848 FT_ULong strike_index; 2849 2850 2851 if ( !face ) 2852 return FT_THROW( Invalid_Face_Handle ); 2853 2854 if ( !req || req->width < 0 || req->height < 0 || 2855 req->type >= FT_SIZE_REQUEST_TYPE_MAX ) 2856 return FT_THROW( Invalid_Argument ); 2857 2858 clazz = face->driver->clazz; 2859 2860 if ( clazz->request_size ) 2861 { 2862 FT_Error error; 2863 2864 2865 error = clazz->request_size( face->size, req ); 2866 2867 #ifdef FT_DEBUG_LEVEL_TRACE 2868 { 2869 FT_Size_Metrics* metrics = &face->size->metrics; 2870 2871 2872 FT_TRACE5(( "FT_Request_Size (font driver's `request_size'):\n" )); 2873 FT_TRACE5(( " x scale: %d (%f)\n", 2874 metrics->x_scale, metrics->x_scale / 65536.0 )); 2875 FT_TRACE5(( " y scale: %d (%f)\n", 2876 metrics->y_scale, metrics->y_scale / 65536.0 )); 2877 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); 2878 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); 2879 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); 2880 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); 2881 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); 2882 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); 2883 } 2884 #endif 2885 2886 return error; 2887 } 2888 2889 /* 2890 * The reason that a driver doesn't have `request_size' defined is 2891 * either that the scaling here suffices or that the supported formats 2892 * are bitmap-only and size matching is not implemented. 2893 * 2894 * In the latter case, a simple size matching is done. 2895 */ 2896 if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) ) 2897 { 2898 FT_Error error; 2899 2900 2901 error = FT_Match_Size( face, req, 0, &strike_index ); 2902 if ( error ) 2903 return error; 2904 2905 return FT_Select_Size( face, (FT_Int)strike_index ); 2906 } 2907 2908 FT_Request_Metrics( face, req ); 2909 2910 return FT_Err_Ok; 2911 } 2912 2913 2914 /* documentation is in freetype.h */ 2915 2916 FT_EXPORT_DEF( FT_Error ) 2917 FT_Set_Char_Size( FT_Face face, 2918 FT_F26Dot6 char_width, 2919 FT_F26Dot6 char_height, 2920 FT_UInt horz_resolution, 2921 FT_UInt vert_resolution ) 2922 { 2923 FT_Size_RequestRec req; 2924 2925 2926 if ( !char_width ) 2927 char_width = char_height; 2928 else if ( !char_height ) 2929 char_height = char_width; 2930 2931 if ( !horz_resolution ) 2932 horz_resolution = vert_resolution; 2933 else if ( !vert_resolution ) 2934 vert_resolution = horz_resolution; 2935 2936 if ( char_width < 1 * 64 ) 2937 char_width = 1 * 64; 2938 if ( char_height < 1 * 64 ) 2939 char_height = 1 * 64; 2940 2941 if ( !horz_resolution ) 2942 horz_resolution = vert_resolution = 72; 2943 2944 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; 2945 req.width = char_width; 2946 req.height = char_height; 2947 req.horiResolution = horz_resolution; 2948 req.vertResolution = vert_resolution; 2949 2950 return FT_Request_Size( face, &req ); 2951 } 2952 2953 2954 /* documentation is in freetype.h */ 2955 2956 FT_EXPORT_DEF( FT_Error ) 2957 FT_Set_Pixel_Sizes( FT_Face face, 2958 FT_UInt pixel_width, 2959 FT_UInt pixel_height ) 2960 { 2961 FT_Size_RequestRec req; 2962 2963 2964 if ( pixel_width == 0 ) 2965 pixel_width = pixel_height; 2966 else if ( pixel_height == 0 ) 2967 pixel_height = pixel_width; 2968 2969 if ( pixel_width < 1 ) 2970 pixel_width = 1; 2971 if ( pixel_height < 1 ) 2972 pixel_height = 1; 2973 2974 /* use `>=' to avoid potential compiler warning on 16bit platforms */ 2975 if ( pixel_width >= 0xFFFFU ) 2976 pixel_width = 0xFFFFU; 2977 if ( pixel_height >= 0xFFFFU ) 2978 pixel_height = 0xFFFFU; 2979 2980 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; 2981 req.width = pixel_width << 6; 2982 req.height = pixel_height << 6; 2983 req.horiResolution = 0; 2984 req.vertResolution = 0; 2985 2986 return FT_Request_Size( face, &req ); 2987 } 2988 2989 2990 /* documentation is in freetype.h */ 2991 2992 FT_EXPORT_DEF( FT_Error ) 2993 FT_Get_Kerning( FT_Face face, 2994 FT_UInt left_glyph, 2995 FT_UInt right_glyph, 2996 FT_UInt kern_mode, 2997 FT_Vector *akerning ) 2998 { 2999 FT_Error error = FT_Err_Ok; 3000 FT_Driver driver; 3001 3002 3003 if ( !face ) 3004 return FT_THROW( Invalid_Face_Handle ); 3005 3006 if ( !akerning ) 3007 return FT_THROW( Invalid_Argument ); 3008 3009 driver = face->driver; 3010 3011 akerning->x = 0; 3012 akerning->y = 0; 3013 3014 if ( driver->clazz->get_kerning ) 3015 { 3016 error = driver->clazz->get_kerning( face, 3017 left_glyph, 3018 right_glyph, 3019 akerning ); 3020 if ( !error ) 3021 { 3022 if ( kern_mode != FT_KERNING_UNSCALED ) 3023 { 3024 akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale ); 3025 akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale ); 3026 3027 if ( kern_mode != FT_KERNING_UNFITTED ) 3028 { 3029 /* we scale down kerning values for small ppem values */ 3030 /* to avoid that rounding makes them too big. */ 3031 /* `25' has been determined heuristically. */ 3032 if ( face->size->metrics.x_ppem < 25 ) 3033 akerning->x = FT_MulDiv( akerning->x, 3034 face->size->metrics.x_ppem, 25 ); 3035 if ( face->size->metrics.y_ppem < 25 ) 3036 akerning->y = FT_MulDiv( akerning->y, 3037 face->size->metrics.y_ppem, 25 ); 3038 3039 akerning->x = FT_PIX_ROUND( akerning->x ); 3040 akerning->y = FT_PIX_ROUND( akerning->y ); 3041 } 3042 } 3043 } 3044 } 3045 3046 return error; 3047 } 3048 3049 3050 /* documentation is in freetype.h */ 3051 3052 FT_EXPORT_DEF( FT_Error ) 3053 FT_Get_Track_Kerning( FT_Face face, 3054 FT_Fixed point_size, 3055 FT_Int degree, 3056 FT_Fixed* akerning ) 3057 { 3058 FT_Service_Kerning service; 3059 FT_Error error = FT_Err_Ok; 3060 3061 3062 if ( !face ) 3063 return FT_THROW( Invalid_Face_Handle ); 3064 3065 if ( !akerning ) 3066 return FT_THROW( Invalid_Argument ); 3067 3068 FT_FACE_FIND_SERVICE( face, service, KERNING ); 3069 if ( !service ) 3070 return FT_THROW( Unimplemented_Feature ); 3071 3072 error = service->get_track( face, 3073 point_size, 3074 degree, 3075 akerning ); 3076 3077 return error; 3078 } 3079 3080 3081 /* documentation is in freetype.h */ 3082 3083 FT_EXPORT_DEF( FT_Error ) 3084 FT_Select_Charmap( FT_Face face, 3085 FT_Encoding encoding ) 3086 { 3087 FT_CharMap* cur; 3088 FT_CharMap* limit; 3089 3090 3091 if ( !face ) 3092 return FT_THROW( Invalid_Face_Handle ); 3093 3094 if ( encoding == FT_ENCODING_NONE ) 3095 return FT_THROW( Invalid_Argument ); 3096 3097 /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */ 3098 /* charmap available, i.e., one with UCS-4 characters, if possible. */ 3099 /* */ 3100 /* This is done by find_unicode_charmap() above, to share code. */ 3101 if ( encoding == FT_ENCODING_UNICODE ) 3102 return find_unicode_charmap( face ); 3103 3104 cur = face->charmaps; 3105 if ( !cur ) 3106 return FT_THROW( Invalid_CharMap_Handle ); 3107 3108 limit = cur + face->num_charmaps; 3109 3110 for ( ; cur < limit; cur++ ) 3111 { 3112 if ( cur[0]->encoding == encoding ) 3113 { 3114 #ifdef FT_MAX_CHARMAP_CACHEABLE 3115 if ( cur - face->charmaps > FT_MAX_CHARMAP_CACHEABLE ) 3116 { 3117 FT_ERROR(( "FT_Select_Charmap: requested charmap is found (%d), " 3118 "but in too late position to cache\n", 3119 cur - face->charmaps )); 3120 continue; 3121 } 3122 #endif 3123 face->charmap = cur[0]; 3124 return 0; 3125 } 3126 } 3127 3128 return FT_THROW( Invalid_Argument ); 3129 } 3130 3131 3132 /* documentation is in freetype.h */ 3133 3134 FT_EXPORT_DEF( FT_Error ) 3135 FT_Set_Charmap( FT_Face face, 3136 FT_CharMap charmap ) 3137 { 3138 FT_CharMap* cur; 3139 FT_CharMap* limit; 3140 3141 3142 if ( !face ) 3143 return FT_THROW( Invalid_Face_Handle ); 3144 3145 cur = face->charmaps; 3146 if ( !cur ) 3147 return FT_THROW( Invalid_CharMap_Handle ); 3148 if ( FT_Get_CMap_Format( charmap ) == 14 ) 3149 return FT_THROW( Invalid_Argument ); 3150 3151 limit = cur + face->num_charmaps; 3152 3153 for ( ; cur < limit; cur++ ) 3154 { 3155 if ( cur[0] == charmap ) 3156 { 3157 #ifdef FT_MAX_CHARMAP_CACHEABLE 3158 if ( cur - face->charmaps > FT_MAX_CHARMAP_CACHEABLE ) 3159 { 3160 FT_ERROR(( "FT_Set_Charmap: requested charmap is found (%d), " 3161 "but in too late position to cache\n", 3162 cur - face->charmaps )); 3163 continue; 3164 } 3165 #endif 3166 face->charmap = cur[0]; 3167 return 0; 3168 } 3169 } 3170 return FT_THROW( Invalid_Argument ); 3171 } 3172 3173 3174 /* documentation is in freetype.h */ 3175 3176 FT_EXPORT_DEF( FT_Int ) 3177 FT_Get_Charmap_Index( FT_CharMap charmap ) 3178 { 3179 FT_Int i; 3180 3181 3182 if ( !charmap || !charmap->face ) 3183 return -1; 3184 3185 for ( i = 0; i < charmap->face->num_charmaps; i++ ) 3186 if ( charmap->face->charmaps[i] == charmap ) 3187 break; 3188 3189 FT_ASSERT( i < charmap->face->num_charmaps ); 3190 3191 #ifdef FT_MAX_CHARMAP_CACHEABLE 3192 if ( i > FT_MAX_CHARMAP_CACHEABLE ) 3193 { 3194 FT_ERROR(( "FT_Get_Charmap_Index: requested charmap is found (%d), " 3195 "but in too late position to cache\n", 3196 i )); 3197 return -i; 3198 } 3199 #endif 3200 return i; 3201 } 3202 3203 3204 static void 3205 ft_cmap_done_internal( FT_CMap cmap ) 3206 { 3207 FT_CMap_Class clazz = cmap->clazz; 3208 FT_Face face = cmap->charmap.face; 3209 FT_Memory memory = FT_FACE_MEMORY( face ); 3210 3211 3212 if ( clazz->done ) 3213 clazz->done( cmap ); 3214 3215 FT_FREE( cmap ); 3216 } 3217 3218 3219 FT_BASE_DEF( void ) 3220 FT_CMap_Done( FT_CMap cmap ) 3221 { 3222 if ( cmap ) 3223 { 3224 FT_Face face = cmap->charmap.face; 3225 FT_Memory memory = FT_FACE_MEMORY( face ); 3226 FT_Error error; 3227 FT_Int i, j; 3228 3229 3230 for ( i = 0; i < face->num_charmaps; i++ ) 3231 { 3232 if ( (FT_CMap)face->charmaps[i] == cmap ) 3233 { 3234 FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1]; 3235 3236 3237 if ( FT_RENEW_ARRAY( face->charmaps, 3238 face->num_charmaps, 3239 face->num_charmaps - 1 ) ) 3240 return; 3241 3242 /* remove it from our list of charmaps */ 3243 for ( j = i + 1; j < face->num_charmaps; j++ ) 3244 { 3245 if ( j == face->num_charmaps - 1 ) 3246 face->charmaps[j - 1] = last_charmap; 3247 else 3248 face->charmaps[j - 1] = face->charmaps[j]; 3249 } 3250 3251 face->num_charmaps--; 3252 3253 if ( (FT_CMap)face->charmap == cmap ) 3254 face->charmap = NULL; 3255 3256 ft_cmap_done_internal( cmap ); 3257 3258 break; 3259 } 3260 } 3261 } 3262 } 3263 3264 3265 FT_BASE_DEF( FT_Error ) 3266 FT_CMap_New( FT_CMap_Class clazz, 3267 FT_Pointer init_data, 3268 FT_CharMap charmap, 3269 FT_CMap *acmap ) 3270 { 3271 FT_Error error = FT_Err_Ok; 3272 FT_Face face; 3273 FT_Memory memory; 3274 FT_CMap cmap = NULL; 3275 3276 3277 if ( clazz == NULL || charmap == NULL || charmap->face == NULL ) 3278 return FT_THROW( Invalid_Argument ); 3279 3280 face = charmap->face; 3281 memory = FT_FACE_MEMORY( face ); 3282 3283 if ( !FT_ALLOC( cmap, clazz->size ) ) 3284 { 3285 cmap->charmap = *charmap; 3286 cmap->clazz = clazz; 3287 3288 if ( clazz->init ) 3289 { 3290 error = clazz->init( cmap, init_data ); 3291 if ( error ) 3292 goto Fail; 3293 } 3294 3295 /* add it to our list of charmaps */ 3296 if ( FT_RENEW_ARRAY( face->charmaps, 3297 face->num_charmaps, 3298 face->num_charmaps + 1 ) ) 3299 goto Fail; 3300 3301 face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap; 3302 } 3303 3304 Exit: 3305 if ( acmap ) 3306 *acmap = cmap; 3307 3308 return error; 3309 3310 Fail: 3311 ft_cmap_done_internal( cmap ); 3312 cmap = NULL; 3313 goto Exit; 3314 } 3315 3316 3317 /* documentation is in freetype.h */ 3318 3319 FT_EXPORT_DEF( FT_UInt ) 3320 FT_Get_Char_Index( FT_Face face, 3321 FT_ULong charcode ) 3322 { 3323 FT_UInt result = 0; 3324 3325 3326 if ( face && face->charmap ) 3327 { 3328 FT_CMap cmap = FT_CMAP( face->charmap ); 3329 3330 3331 if ( charcode > 0xFFFFFFFFUL ) 3332 { 3333 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); 3334 FT_TRACE1(( " 0x%x is truncated\n", charcode )); 3335 } 3336 result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode ); 3337 } 3338 return result; 3339 } 3340 3341 3342 /* documentation is in freetype.h */ 3343 3344 FT_EXPORT_DEF( FT_ULong ) 3345 FT_Get_First_Char( FT_Face face, 3346 FT_UInt *agindex ) 3347 { 3348 FT_ULong result = 0; 3349 FT_UInt gindex = 0; 3350 3351 3352 if ( face && face->charmap && face->num_glyphs ) 3353 { 3354 gindex = FT_Get_Char_Index( face, 0 ); 3355 if ( gindex == 0 || gindex >= (FT_UInt)face->num_glyphs ) 3356 result = FT_Get_Next_Char( face, 0, &gindex ); 3357 } 3358 3359 if ( agindex ) 3360 *agindex = gindex; 3361 3362 return result; 3363 } 3364 3365 3366 /* documentation is in freetype.h */ 3367 3368 FT_EXPORT_DEF( FT_ULong ) 3369 FT_Get_Next_Char( FT_Face face, 3370 FT_ULong charcode, 3371 FT_UInt *agindex ) 3372 { 3373 FT_ULong result = 0; 3374 FT_UInt gindex = 0; 3375 3376 3377 if ( face && face->charmap && face->num_glyphs ) 3378 { 3379 FT_UInt32 code = (FT_UInt32)charcode; 3380 FT_CMap cmap = FT_CMAP( face->charmap ); 3381 3382 3383 do { 3384 gindex = cmap->clazz->char_next( cmap, &code ); 3385 } while ( gindex >= (FT_UInt)face->num_glyphs ); 3386 3387 result = ( gindex == 0 ) ? 0 : code; 3388 } 3389 3390 if ( agindex ) 3391 *agindex = gindex; 3392 3393 return result; 3394 } 3395 3396 3397 /* documentation is in freetype.h */ 3398 3399 FT_EXPORT_DEF( FT_UInt ) 3400 FT_Face_GetCharVariantIndex( FT_Face face, 3401 FT_ULong charcode, 3402 FT_ULong variantSelector ) 3403 { 3404 FT_UInt result = 0; 3405 3406 3407 if ( face && face->charmap && 3408 face->charmap->encoding == FT_ENCODING_UNICODE ) 3409 { 3410 FT_CharMap charmap = find_variant_selector_charmap( face ); 3411 FT_CMap ucmap = FT_CMAP( face->charmap ); 3412 3413 3414 if ( charmap != NULL ) 3415 { 3416 FT_CMap vcmap = FT_CMAP( charmap ); 3417 3418 3419 if ( charcode > 0xFFFFFFFFUL ) 3420 { 3421 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); 3422 FT_TRACE1(( " 0x%x is truncated\n", charcode )); 3423 } 3424 if ( variantSelector > 0xFFFFFFFFUL ) 3425 { 3426 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); 3427 FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); 3428 } 3429 3430 result = vcmap->clazz->char_var_index( vcmap, ucmap, 3431 (FT_UInt32)charcode, 3432 (FT_UInt32)variantSelector ); 3433 } 3434 } 3435 3436 return result; 3437 } 3438 3439 3440 /* documentation is in freetype.h */ 3441 3442 FT_EXPORT_DEF( FT_Int ) 3443 FT_Face_GetCharVariantIsDefault( FT_Face face, 3444 FT_ULong charcode, 3445 FT_ULong variantSelector ) 3446 { 3447 FT_Int result = -1; 3448 3449 3450 if ( face ) 3451 { 3452 FT_CharMap charmap = find_variant_selector_charmap( face ); 3453 3454 3455 if ( charmap != NULL ) 3456 { 3457 FT_CMap vcmap = FT_CMAP( charmap ); 3458 3459 3460 if ( charcode > 0xFFFFFFFFUL ) 3461 { 3462 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); 3463 FT_TRACE1(( " 0x%x is truncated\n", charcode )); 3464 } 3465 if ( variantSelector > 0xFFFFFFFFUL ) 3466 { 3467 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); 3468 FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); 3469 } 3470 3471 result = vcmap->clazz->char_var_default( vcmap, 3472 (FT_UInt32)charcode, 3473 (FT_UInt32)variantSelector ); 3474 } 3475 } 3476 3477 return result; 3478 } 3479 3480 3481 /* documentation is in freetype.h */ 3482 3483 FT_EXPORT_DEF( FT_UInt32* ) 3484 FT_Face_GetVariantSelectors( FT_Face face ) 3485 { 3486 FT_UInt32 *result = NULL; 3487 3488 3489 if ( face ) 3490 { 3491 FT_CharMap charmap = find_variant_selector_charmap( face ); 3492 3493 3494 if ( charmap != NULL ) 3495 { 3496 FT_CMap vcmap = FT_CMAP( charmap ); 3497 FT_Memory memory = FT_FACE_MEMORY( face ); 3498 3499 3500 result = vcmap->clazz->variant_list( vcmap, memory ); 3501 } 3502 } 3503 3504 return result; 3505 } 3506 3507 3508 /* documentation is in freetype.h */ 3509 3510 FT_EXPORT_DEF( FT_UInt32* ) 3511 FT_Face_GetVariantsOfChar( FT_Face face, 3512 FT_ULong charcode ) 3513 { 3514 FT_UInt32 *result = NULL; 3515 3516 3517 if ( face ) 3518 { 3519 FT_CharMap charmap = find_variant_selector_charmap( face ); 3520 3521 3522 if ( charmap != NULL ) 3523 { 3524 FT_CMap vcmap = FT_CMAP( charmap ); 3525 FT_Memory memory = FT_FACE_MEMORY( face ); 3526 3527 3528 if ( charcode > 0xFFFFFFFFUL ) 3529 { 3530 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); 3531 FT_TRACE1(( " 0x%x is truncated\n", charcode )); 3532 } 3533 3534 result = vcmap->clazz->charvariant_list( vcmap, memory, 3535 (FT_UInt32)charcode ); 3536 } 3537 } 3538 return result; 3539 } 3540 3541 3542 /* documentation is in freetype.h */ 3543 3544 FT_EXPORT_DEF( FT_UInt32* ) 3545 FT_Face_GetCharsOfVariant( FT_Face face, 3546 FT_ULong variantSelector ) 3547 { 3548 FT_UInt32 *result = NULL; 3549 3550 3551 if ( face ) 3552 { 3553 FT_CharMap charmap = find_variant_selector_charmap( face ); 3554 3555 3556 if ( charmap != NULL ) 3557 { 3558 FT_CMap vcmap = FT_CMAP( charmap ); 3559 FT_Memory memory = FT_FACE_MEMORY( face ); 3560 3561 3562 if ( variantSelector > 0xFFFFFFFFUL ) 3563 { 3564 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); 3565 FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); 3566 } 3567 3568 result = vcmap->clazz->variantchar_list( vcmap, memory, 3569 (FT_UInt32)variantSelector ); 3570 } 3571 } 3572 3573 return result; 3574 } 3575 3576 3577 /* documentation is in freetype.h */ 3578 3579 FT_EXPORT_DEF( FT_UInt ) 3580 FT_Get_Name_Index( FT_Face face, 3581 FT_String* glyph_name ) 3582 { 3583 FT_UInt result = 0; 3584 3585 3586 if ( face && FT_HAS_GLYPH_NAMES( face ) ) 3587 { 3588 FT_Service_GlyphDict service; 3589 3590 3591 FT_FACE_LOOKUP_SERVICE( face, 3592 service, 3593 GLYPH_DICT ); 3594 3595 if ( service && service->name_index ) 3596 result = service->name_index( face, glyph_name ); 3597 } 3598 3599 return result; 3600 } 3601 3602 3603 /* documentation is in freetype.h */ 3604 3605 FT_EXPORT_DEF( FT_Error ) 3606 FT_Get_Glyph_Name( FT_Face face, 3607 FT_UInt glyph_index, 3608 FT_Pointer buffer, 3609 FT_UInt buffer_max ) 3610 { 3611 FT_Error error = FT_ERR( Invalid_Argument ); 3612 3613 3614 /* clean up buffer */ 3615 if ( buffer && buffer_max > 0 ) 3616 ((FT_Byte*)buffer)[0] = 0; 3617 3618 if ( face && 3619 (FT_Long)glyph_index <= face->num_glyphs && 3620 FT_HAS_GLYPH_NAMES( face ) ) 3621 { 3622 FT_Service_GlyphDict service; 3623 3624 3625 FT_FACE_LOOKUP_SERVICE( face, 3626 service, 3627 GLYPH_DICT ); 3628 3629 if ( service && service->get_name ) 3630 error = service->get_name( face, glyph_index, buffer, buffer_max ); 3631 } 3632 3633 return error; 3634 } 3635 3636 3637 /* documentation is in freetype.h */ 3638 3639 FT_EXPORT_DEF( const char* ) 3640 FT_Get_Postscript_Name( FT_Face face ) 3641 { 3642 const char* result = NULL; 3643 3644 3645 if ( !face ) 3646 goto Exit; 3647 3648 if ( !result ) 3649 { 3650 FT_Service_PsFontName service; 3651 3652 3653 FT_FACE_LOOKUP_SERVICE( face, 3654 service, 3655 POSTSCRIPT_FONT_NAME ); 3656 3657 if ( service && service->get_ps_font_name ) 3658 result = service->get_ps_font_name( face ); 3659 } 3660 3661 Exit: 3662 return result; 3663 } 3664 3665 3666 /* documentation is in tttables.h */ 3667 3668 FT_EXPORT_DEF( void* ) 3669 FT_Get_Sfnt_Table( FT_Face face, 3670 FT_Sfnt_Tag tag ) 3671 { 3672 void* table = 0; 3673 FT_Service_SFNT_Table service; 3674 3675 3676 if ( face && FT_IS_SFNT( face ) ) 3677 { 3678 FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); 3679 if ( service != NULL ) 3680 table = service->get_table( face, tag ); 3681 } 3682 3683 return table; 3684 } 3685 3686 3687 /* documentation is in tttables.h */ 3688 3689 FT_EXPORT_DEF( FT_Error ) 3690 FT_Load_Sfnt_Table( FT_Face face, 3691 FT_ULong tag, 3692 FT_Long offset, 3693 FT_Byte* buffer, 3694 FT_ULong* length ) 3695 { 3696 FT_Service_SFNT_Table service; 3697 3698 3699 if ( !face || !FT_IS_SFNT( face ) ) 3700 return FT_THROW( Invalid_Face_Handle ); 3701 3702 FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); 3703 if ( service == NULL ) 3704 return FT_THROW( Unimplemented_Feature ); 3705 3706 return service->load_table( face, tag, offset, buffer, length ); 3707 } 3708 3709 3710 /* documentation is in tttables.h */ 3711 3712 FT_EXPORT_DEF( FT_Error ) 3713 FT_Sfnt_Table_Info( FT_Face face, 3714 FT_UInt table_index, 3715 FT_ULong *tag, 3716 FT_ULong *length ) 3717 { 3718 FT_Service_SFNT_Table service; 3719 FT_ULong offset; 3720 3721 3722 if ( !face || !FT_IS_SFNT( face ) ) 3723 return FT_THROW( Invalid_Face_Handle ); 3724 3725 FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); 3726 if ( service == NULL ) 3727 return FT_THROW( Unimplemented_Feature ); 3728 3729 return service->table_info( face, table_index, tag, &offset, length ); 3730 } 3731 3732 3733 /* documentation is in tttables.h */ 3734 3735 FT_EXPORT_DEF( FT_ULong ) 3736 FT_Get_CMap_Language_ID( FT_CharMap charmap ) 3737 { 3738 FT_Service_TTCMaps service; 3739 FT_Face face; 3740 TT_CMapInfo cmap_info; 3741 3742 3743 if ( !charmap || !charmap->face ) 3744 return 0; 3745 3746 face = charmap->face; 3747 FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); 3748 if ( service == NULL ) 3749 return 0; 3750 if ( service->get_cmap_info( charmap, &cmap_info )) 3751 return 0; 3752 3753 return cmap_info.language; 3754 } 3755 3756 3757 /* documentation is in tttables.h */ 3758 3759 FT_EXPORT_DEF( FT_Long ) 3760 FT_Get_CMap_Format( FT_CharMap charmap ) 3761 { 3762 FT_Service_TTCMaps service; 3763 FT_Face face; 3764 TT_CMapInfo cmap_info; 3765 3766 3767 if ( !charmap || !charmap->face ) 3768 return -1; 3769 3770 face = charmap->face; 3771 FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); 3772 if ( service == NULL ) 3773 return -1; 3774 if ( service->get_cmap_info( charmap, &cmap_info )) 3775 return -1; 3776 3777 return cmap_info.format; 3778 } 3779 3780 3781 /* documentation is in ftsizes.h */ 3782 3783 FT_EXPORT_DEF( FT_Error ) 3784 FT_Activate_Size( FT_Size size ) 3785 { 3786 FT_Face face; 3787 3788 3789 if ( size == NULL ) 3790 return FT_THROW( Invalid_Argument ); 3791 3792 face = size->face; 3793 if ( face == NULL || face->driver == NULL ) 3794 return FT_THROW( Invalid_Argument ); 3795 3796 /* we don't need anything more complex than that; all size objects */ 3797 /* are already listed by the face */ 3798 face->size = size; 3799 3800 return FT_Err_Ok; 3801 } 3802 3803 3804 /*************************************************************************/ 3805 /*************************************************************************/ 3806 /*************************************************************************/ 3807 /**** ****/ 3808 /**** ****/ 3809 /**** R E N D E R E R S ****/ 3810 /**** ****/ 3811 /**** ****/ 3812 /*************************************************************************/ 3813 /*************************************************************************/ 3814 /*************************************************************************/ 3815 3816 /* lookup a renderer by glyph format in the library's list */ 3817 FT_BASE_DEF( FT_Renderer ) 3818 FT_Lookup_Renderer( FT_Library library, 3819 FT_Glyph_Format format, 3820 FT_ListNode* node ) 3821 { 3822 FT_ListNode cur; 3823 FT_Renderer result = 0; 3824 3825 3826 if ( !library ) 3827 goto Exit; 3828 3829 cur = library->renderers.head; 3830 3831 if ( node ) 3832 { 3833 if ( *node ) 3834 cur = (*node)->next; 3835 *node = 0; 3836 } 3837 3838 while ( cur ) 3839 { 3840 FT_Renderer renderer = FT_RENDERER( cur->data ); 3841 3842 3843 if ( renderer->glyph_format == format ) 3844 { 3845 if ( node ) 3846 *node = cur; 3847 3848 result = renderer; 3849 break; 3850 } 3851 cur = cur->next; 3852 } 3853 3854 Exit: 3855 return result; 3856 } 3857 3858 3859 static FT_Renderer 3860 ft_lookup_glyph_renderer( FT_GlyphSlot slot ) 3861 { 3862 FT_Face face = slot->face; 3863 FT_Library library = FT_FACE_LIBRARY( face ); 3864 FT_Renderer result = library->cur_renderer; 3865 3866 3867 if ( !result || result->glyph_format != slot->format ) 3868 result = FT_Lookup_Renderer( library, slot->format, 0 ); 3869 3870 return result; 3871 } 3872 3873 3874 static void 3875 ft_set_current_renderer( FT_Library library ) 3876 { 3877 FT_Renderer renderer; 3878 3879 3880 renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 ); 3881 library->cur_renderer = renderer; 3882 } 3883 3884 3885 static FT_Error 3886 ft_add_renderer( FT_Module module ) 3887 { 3888 FT_Library library = module->library; 3889 FT_Memory memory = library->memory; 3890 FT_Error error; 3891 FT_ListNode node = NULL; 3892 3893 3894 if ( FT_NEW( node ) ) 3895 goto Exit; 3896 3897 { 3898 FT_Renderer render = FT_RENDERER( module ); 3899 FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz; 3900 3901 3902 render->clazz = clazz; 3903 render->glyph_format = clazz->glyph_format; 3904 3905 /* allocate raster object if needed */ 3906 if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && 3907 clazz->raster_class->raster_new ) 3908 { 3909 error = clazz->raster_class->raster_new( memory, &render->raster ); 3910 if ( error ) 3911 goto Fail; 3912 3913 render->raster_render = clazz->raster_class->raster_render; 3914 render->render = clazz->render_glyph; 3915 } 3916 3917 /* add to list */ 3918 node->data = module; 3919 FT_List_Add( &library->renderers, node ); 3920 3921 ft_set_current_renderer( library ); 3922 } 3923 3924 Fail: 3925 if ( error ) 3926 FT_FREE( node ); 3927 3928 Exit: 3929 return error; 3930 } 3931 3932 3933 static void 3934 ft_remove_renderer( FT_Module module ) 3935 { 3936 FT_Library library = module->library; 3937 FT_Memory memory = library->memory; 3938 FT_ListNode node; 3939 3940 3941 node = FT_List_Find( &library->renderers, module ); 3942 if ( node ) 3943 { 3944 FT_Renderer render = FT_RENDERER( module ); 3945 3946 3947 /* release raster object, if any */ 3948 if ( render->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && 3949 render->raster ) 3950 render->clazz->raster_class->raster_done( render->raster ); 3951 3952 /* remove from list */ 3953 FT_List_Remove( &library->renderers, node ); 3954 FT_FREE( node ); 3955 3956 ft_set_current_renderer( library ); 3957 } 3958 } 3959 3960 3961 /* documentation is in ftrender.h */ 3962 3963 FT_EXPORT_DEF( FT_Renderer ) 3964 FT_Get_Renderer( FT_Library library, 3965 FT_Glyph_Format format ) 3966 { 3967 /* test for valid `library' delayed to FT_Lookup_Renderer() */ 3968 3969 return FT_Lookup_Renderer( library, format, 0 ); 3970 } 3971 3972 3973 /* documentation is in ftrender.h */ 3974 3975 FT_EXPORT_DEF( FT_Error ) 3976 FT_Set_Renderer( FT_Library library, 3977 FT_Renderer renderer, 3978 FT_UInt num_params, 3979 FT_Parameter* parameters ) 3980 { 3981 FT_ListNode node; 3982 FT_Error error = FT_Err_Ok; 3983 3984 3985 if ( !library ) 3986 return FT_THROW( Invalid_Library_Handle ); 3987 3988 if ( !renderer ) 3989 return FT_THROW( Invalid_Argument ); 3990 3991 node = FT_List_Find( &library->renderers, renderer ); 3992 if ( !node ) 3993 { 3994 error = FT_THROW( Invalid_Argument ); 3995 goto Exit; 3996 } 3997 3998 FT_List_Up( &library->renderers, node ); 3999 4000 if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE ) 4001 library->cur_renderer = renderer; 4002 4003 if ( num_params > 0 ) 4004 { 4005 FT_Renderer_SetModeFunc set_mode = renderer->clazz->set_mode; 4006 4007 4008 for ( ; num_params > 0; num_params-- ) 4009 { 4010 error = set_mode( renderer, parameters->tag, parameters->data ); 4011 if ( error ) 4012 break; 4013 parameters++; 4014 } 4015 } 4016 4017 Exit: 4018 return error; 4019 } 4020 4021 4022 FT_BASE_DEF( FT_Error ) 4023 FT_Render_Glyph_Internal( FT_Library library, 4024 FT_GlyphSlot slot, 4025 FT_Render_Mode render_mode ) 4026 { 4027 FT_Error error = FT_Err_Ok; 4028 FT_Renderer renderer; 4029 4030 4031 /* if it is already a bitmap, no need to do anything */ 4032 switch ( slot->format ) 4033 { 4034 case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */ 4035 break; 4036 4037 default: 4038 { 4039 FT_ListNode node = 0; 4040 FT_Bool update = 0; 4041 4042 4043 /* small shortcut for the very common case */ 4044 if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) 4045 { 4046 renderer = library->cur_renderer; 4047 node = library->renderers.head; 4048 } 4049 else 4050 renderer = FT_Lookup_Renderer( library, slot->format, &node ); 4051 4052 error = FT_ERR( Unimplemented_Feature ); 4053 while ( renderer ) 4054 { 4055 error = renderer->render( renderer, slot, render_mode, NULL ); 4056 if ( !error || 4057 FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) 4058 break; 4059 4060 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ 4061 /* is unsupported by the current renderer for this glyph image */ 4062 /* format. */ 4063 4064 /* now, look for another renderer that supports the same */ 4065 /* format. */ 4066 renderer = FT_Lookup_Renderer( library, slot->format, &node ); 4067 update = 1; 4068 } 4069 4070 /* if we changed the current renderer for the glyph image format */ 4071 /* we need to select it as the next current one */ 4072 if ( !error && update && renderer ) 4073 FT_Set_Renderer( library, renderer, 0, 0 ); 4074 } 4075 } 4076 4077 #ifdef FT_DEBUG_LEVEL_TRACE 4078 4079 #undef FT_COMPONENT 4080 #define FT_COMPONENT trace_bitmap 4081 4082 /* we convert to a single bitmap format for computing the checksum */ 4083 { 4084 FT_Bitmap bitmap; 4085 FT_Error err; 4086 4087 4088 FT_Bitmap_New( &bitmap ); 4089 4090 err = FT_Bitmap_Convert( library, &slot->bitmap, &bitmap, 1 ); 4091 if ( !err ) 4092 { 4093 MD5_CTX ctx; 4094 unsigned char md5[16]; 4095 int i; 4096 4097 4098 MD5_Init( &ctx); 4099 MD5_Update( &ctx, bitmap.buffer, bitmap.rows * bitmap.pitch ); 4100 MD5_Final( md5, &ctx ); 4101 4102 FT_TRACE3(( "MD5 checksum for %dx%d bitmap:\n" 4103 " ", 4104 bitmap.rows, bitmap.pitch )); 4105 for ( i = 0; i < 16; i++ ) 4106 FT_TRACE3(( "%02X", md5[i] )); 4107 FT_TRACE3(( "\n" )); 4108 } 4109 4110 FT_Bitmap_Done( library, &bitmap ); 4111 } 4112 4113 #undef FT_COMPONENT 4114 #define FT_COMPONENT trace_objs 4115 4116 #endif /* FT_DEBUG_LEVEL_TRACE */ 4117 4118 return error; 4119 } 4120 4121 4122 /* documentation is in freetype.h */ 4123 4124 FT_EXPORT_DEF( FT_Error ) 4125 FT_Render_Glyph( FT_GlyphSlot slot, 4126 FT_Render_Mode render_mode ) 4127 { 4128 FT_Library library; 4129 4130 4131 if ( !slot || !slot->face ) 4132 return FT_THROW( Invalid_Argument ); 4133 4134 library = FT_FACE_LIBRARY( slot->face ); 4135 4136 return FT_Render_Glyph_Internal( library, slot, render_mode ); 4137 } 4138 4139 4140 /*************************************************************************/ 4141 /*************************************************************************/ 4142 /*************************************************************************/ 4143 /**** ****/ 4144 /**** ****/ 4145 /**** M O D U L E S ****/ 4146 /**** ****/ 4147 /**** ****/ 4148 /*************************************************************************/ 4149 /*************************************************************************/ 4150 /*************************************************************************/ 4151 4152 4153 /*************************************************************************/ 4154 /* */ 4155 /* <Function> */ 4156 /* Destroy_Module */ 4157 /* */ 4158 /* <Description> */ 4159 /* Destroys a given module object. For drivers, this also destroys */ 4160 /* all child faces. */ 4161 /* */ 4162 /* <InOut> */ 4163 /* module :: A handle to the target driver object. */ 4164 /* */ 4165 /* <Note> */ 4166 /* The driver _must_ be LOCKED! */ 4167 /* */ 4168 static void 4169 Destroy_Module( FT_Module module ) 4170 { 4171 FT_Memory memory = module->memory; 4172 FT_Module_Class* clazz = module->clazz; 4173 FT_Library library = module->library; 4174 4175 4176 if ( library && library->auto_hinter == module ) 4177 library->auto_hinter = 0; 4178 4179 /* if the module is a renderer */ 4180 if ( FT_MODULE_IS_RENDERER( module ) ) 4181 ft_remove_renderer( module ); 4182 4183 /* if the module is a font driver, add some steps */ 4184 if ( FT_MODULE_IS_DRIVER( module ) ) 4185 Destroy_Driver( FT_DRIVER( module ) ); 4186 4187 /* finalize the module object */ 4188 if ( clazz->module_done ) 4189 clazz->module_done( module ); 4190 4191 /* discard it */ 4192 FT_FREE( module ); 4193 } 4194 4195 4196 /* documentation is in ftmodapi.h */ 4197 4198 FT_EXPORT_DEF( FT_Error ) 4199 FT_Add_Module( FT_Library library, 4200 const FT_Module_Class* clazz ) 4201 { 4202 FT_Error error; 4203 FT_Memory memory; 4204 FT_Module module; 4205 FT_UInt nn; 4206 4207 4208 #define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \ 4209 FREETYPE_MINOR ) 4210 4211 if ( !library ) 4212 return FT_THROW( Invalid_Library_Handle ); 4213 4214 if ( !clazz ) 4215 return FT_THROW( Invalid_Argument ); 4216 4217 /* check freetype version */ 4218 if ( clazz->module_requires > FREETYPE_VER_FIXED ) 4219 return FT_THROW( Invalid_Version ); 4220 4221 /* look for a module with the same name in the library's table */ 4222 for ( nn = 0; nn < library->num_modules; nn++ ) 4223 { 4224 module = library->modules[nn]; 4225 if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 ) 4226 { 4227 /* this installed module has the same name, compare their versions */ 4228 if ( clazz->module_version <= module->clazz->module_version ) 4229 return FT_THROW( Lower_Module_Version ); 4230 4231 /* remove the module from our list, then exit the loop to replace */ 4232 /* it by our new version.. */ 4233 FT_Remove_Module( library, module ); 4234 break; 4235 } 4236 } 4237 4238 memory = library->memory; 4239 error = FT_Err_Ok; 4240 4241 if ( library->num_modules >= FT_MAX_MODULES ) 4242 { 4243 error = FT_THROW( Too_Many_Drivers ); 4244 goto Exit; 4245 } 4246 4247 /* allocate module object */ 4248 if ( FT_ALLOC( module, clazz->module_size ) ) 4249 goto Exit; 4250 4251 /* base initialization */ 4252 module->library = library; 4253 module->memory = memory; 4254 module->clazz = (FT_Module_Class*)clazz; 4255 4256 /* check whether the module is a renderer - this must be performed */ 4257 /* before the normal module initialization */ 4258 if ( FT_MODULE_IS_RENDERER( module ) ) 4259 { 4260 /* add to the renderers list */ 4261 error = ft_add_renderer( module ); 4262 if ( error ) 4263 goto Fail; 4264 } 4265 4266 /* is the module a auto-hinter? */ 4267 if ( FT_MODULE_IS_HINTER( module ) ) 4268 library->auto_hinter = module; 4269 4270 /* if the module is a font driver */ 4271 if ( FT_MODULE_IS_DRIVER( module ) ) 4272 { 4273 /* allocate glyph loader if needed */ 4274 FT_Driver driver = FT_DRIVER( module ); 4275 4276 4277 driver->clazz = (FT_Driver_Class)module->clazz; 4278 if ( FT_DRIVER_USES_OUTLINES( driver ) ) 4279 { 4280 error = FT_GlyphLoader_New( memory, &driver->glyph_loader ); 4281 if ( error ) 4282 goto Fail; 4283 } 4284 } 4285 4286 if ( clazz->module_init ) 4287 { 4288 error = clazz->module_init( module ); 4289 if ( error ) 4290 goto Fail; 4291 } 4292 4293 /* add module to the library's table */ 4294 library->modules[library->num_modules++] = module; 4295 4296 Exit: 4297 return error; 4298 4299 Fail: 4300 if ( FT_MODULE_IS_DRIVER( module ) ) 4301 { 4302 FT_Driver driver = FT_DRIVER( module ); 4303 4304 4305 if ( FT_DRIVER_USES_OUTLINES( driver ) ) 4306 FT_GlyphLoader_Done( driver->glyph_loader ); 4307 } 4308 4309 if ( FT_MODULE_IS_RENDERER( module ) ) 4310 { 4311 FT_Renderer renderer = FT_RENDERER( module ); 4312 4313 4314 if ( renderer->clazz && 4315 renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && 4316 renderer->raster ) 4317 renderer->clazz->raster_class->raster_done( renderer->raster ); 4318 } 4319 4320 FT_FREE( module ); 4321 goto Exit; 4322 } 4323 4324 4325 /* documentation is in ftmodapi.h */ 4326 4327 FT_EXPORT_DEF( FT_Module ) 4328 FT_Get_Module( FT_Library library, 4329 const char* module_name ) 4330 { 4331 FT_Module result = 0; 4332 FT_Module* cur; 4333 FT_Module* limit; 4334 4335 4336 if ( !library || !module_name ) 4337 return result; 4338 4339 cur = library->modules; 4340 limit = cur + library->num_modules; 4341 4342 for ( ; cur < limit; cur++ ) 4343 if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 ) 4344 { 4345 result = cur[0]; 4346 break; 4347 } 4348 4349 return result; 4350 } 4351 4352 4353 /* documentation is in ftobjs.h */ 4354 4355 FT_BASE_DEF( const void* ) 4356 FT_Get_Module_Interface( FT_Library library, 4357 const char* mod_name ) 4358 { 4359 FT_Module module; 4360 4361 4362 /* test for valid `library' delayed to FT_Get_Module() */ 4363 4364 module = FT_Get_Module( library, mod_name ); 4365 4366 return module ? module->clazz->module_interface : 0; 4367 } 4368 4369 4370 FT_BASE_DEF( FT_Pointer ) 4371 ft_module_get_service( FT_Module module, 4372 const char* service_id ) 4373 { 4374 FT_Pointer result = NULL; 4375 4376 4377 if ( module ) 4378 { 4379 FT_ASSERT( module->clazz && module->clazz->get_interface ); 4380 4381 /* first, look for the service in the module */ 4382 if ( module->clazz->get_interface ) 4383 result = module->clazz->get_interface( module, service_id ); 4384 4385 if ( result == NULL ) 4386 { 4387 /* we didn't find it, look in all other modules then */ 4388 FT_Library library = module->library; 4389 FT_Module* cur = library->modules; 4390 FT_Module* limit = cur + library->num_modules; 4391 4392 4393 for ( ; cur < limit; cur++ ) 4394 { 4395 if ( cur[0] != module ) 4396 { 4397 FT_ASSERT( cur[0]->clazz ); 4398 4399 if ( cur[0]->clazz->get_interface ) 4400 { 4401 result = cur[0]->clazz->get_interface( cur[0], service_id ); 4402 if ( result != NULL ) 4403 break; 4404 } 4405 } 4406 } 4407 } 4408 } 4409 4410 return result; 4411 } 4412 4413 4414 /* documentation is in ftmodapi.h */ 4415 4416 FT_EXPORT_DEF( FT_Error ) 4417 FT_Remove_Module( FT_Library library, 4418 FT_Module module ) 4419 { 4420 /* try to find the module from the table, then remove it from there */ 4421 4422 if ( !library ) 4423 return FT_THROW( Invalid_Library_Handle ); 4424 4425 if ( module ) 4426 { 4427 FT_Module* cur = library->modules; 4428 FT_Module* limit = cur + library->num_modules; 4429 4430 4431 for ( ; cur < limit; cur++ ) 4432 { 4433 if ( cur[0] == module ) 4434 { 4435 /* remove it from the table */ 4436 library->num_modules--; 4437 limit--; 4438 while ( cur < limit ) 4439 { 4440 cur[0] = cur[1]; 4441 cur++; 4442 } 4443 limit[0] = 0; 4444 4445 /* destroy the module */ 4446 Destroy_Module( module ); 4447 4448 return FT_Err_Ok; 4449 } 4450 } 4451 } 4452 return FT_THROW( Invalid_Driver_Handle ); 4453 } 4454 4455 4456 FT_Error 4457 ft_property_do( FT_Library library, 4458 const FT_String* module_name, 4459 const FT_String* property_name, 4460 void* value, 4461 FT_Bool set ) 4462 { 4463 FT_Module* cur; 4464 FT_Module* limit; 4465 FT_Module_Interface interface; 4466 4467 FT_Service_Properties service; 4468 4469 #ifdef FT_DEBUG_LEVEL_ERROR 4470 const FT_String* set_name = "FT_Property_Set"; 4471 const FT_String* get_name = "FT_Property_Get"; 4472 const FT_String* func_name = set ? set_name : get_name; 4473 #endif 4474 4475 FT_Bool missing_func; 4476 4477 4478 if ( !library ) 4479 return FT_THROW( Invalid_Library_Handle ); 4480 4481 if ( !module_name || !property_name || !value ) 4482 return FT_THROW( Invalid_Argument ); 4483 4484 cur = library->modules; 4485 limit = cur + library->num_modules; 4486 4487 /* search module */ 4488 for ( ; cur < limit; cur++ ) 4489 if ( !ft_strcmp( cur[0]->clazz->module_name, module_name ) ) 4490 break; 4491 4492 if ( cur == limit ) 4493 { 4494 FT_ERROR(( "%s: can't find module `%s'\n", 4495 func_name, module_name )); 4496 return FT_THROW( Missing_Module ); 4497 } 4498 4499 /* check whether we have a service interface */ 4500 if ( !cur[0]->clazz->get_interface ) 4501 { 4502 FT_ERROR(( "%s: module `%s' doesn't support properties\n", 4503 func_name, module_name )); 4504 return FT_THROW( Unimplemented_Feature ); 4505 } 4506 4507 /* search property service */ 4508 interface = cur[0]->clazz->get_interface( cur[0], 4509 FT_SERVICE_ID_PROPERTIES ); 4510 if ( !interface ) 4511 { 4512 FT_ERROR(( "%s: module `%s' doesn't support properties\n", 4513 func_name, module_name )); 4514 return FT_THROW( Unimplemented_Feature ); 4515 } 4516 4517 service = (FT_Service_Properties)interface; 4518 4519 if ( set ) 4520 missing_func = (FT_Bool)( !service->set_property ); 4521 else 4522 missing_func = (FT_Bool)( !service->get_property ); 4523 4524 if ( missing_func ) 4525 { 4526 FT_ERROR(( "%s: property service of module `%s' is broken\n", 4527 func_name, module_name )); 4528 return FT_THROW( Unimplemented_Feature ); 4529 } 4530 4531 return set ? service->set_property( cur[0], property_name, value ) 4532 : service->get_property( cur[0], property_name, value ); 4533 } 4534 4535 4536 /* documentation is in ftmodapi.h */ 4537 4538 FT_EXPORT_DEF( FT_Error ) 4539 FT_Property_Set( FT_Library library, 4540 const FT_String* module_name, 4541 const FT_String* property_name, 4542 const void* value ) 4543 { 4544 return ft_property_do( library, 4545 module_name, 4546 property_name, 4547 (void*)value, 4548 TRUE ); 4549 } 4550 4551 4552 /* documentation is in ftmodapi.h */ 4553 4554 FT_EXPORT_DEF( FT_Error ) 4555 FT_Property_Get( FT_Library library, 4556 const FT_String* module_name, 4557 const FT_String* property_name, 4558 void* value ) 4559 { 4560 return ft_property_do( library, 4561 module_name, 4562 property_name, 4563 value, 4564 FALSE ); 4565 } 4566 4567 4568 /*************************************************************************/ 4569 /*************************************************************************/ 4570 /*************************************************************************/ 4571 /**** ****/ 4572 /**** ****/ 4573 /**** L I B R A R Y ****/ 4574 /**** ****/ 4575 /**** ****/ 4576 /*************************************************************************/ 4577 /*************************************************************************/ 4578 /*************************************************************************/ 4579 4580 4581 /* documentation is in ftmodapi.h */ 4582 4583 FT_EXPORT_DEF( FT_Error ) 4584 FT_Reference_Library( FT_Library library ) 4585 { 4586 library->refcount++; 4587 4588 return FT_Err_Ok; 4589 } 4590 4591 4592 /* documentation is in ftmodapi.h */ 4593 4594 FT_EXPORT_DEF( FT_Error ) 4595 FT_New_Library( FT_Memory memory, 4596 FT_Library *alibrary ) 4597 { 4598 FT_Library library = NULL; 4599 FT_Error error; 4600 4601 4602 if ( !memory ) 4603 return FT_THROW( Invalid_Argument ); 4604 4605 #ifdef FT_DEBUG_LEVEL_ERROR 4606 /* init debugging support */ 4607 ft_debug_init(); 4608 #endif 4609 4610 /* first of all, allocate the library object */ 4611 if ( FT_NEW( library ) ) 4612 return error; 4613 4614 library->memory = memory; 4615 4616 #ifdef FT_CONFIG_OPTION_PIC 4617 /* initialize position independent code containers */ 4618 error = ft_pic_container_init( library ); 4619 if ( error ) 4620 goto Fail; 4621 #endif 4622 4623 /* allocate the render pool */ 4624 library->raster_pool_size = FT_RENDER_POOL_SIZE; 4625 #if FT_RENDER_POOL_SIZE > 0 4626 if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) ) 4627 goto Fail; 4628 #endif 4629 4630 library->version_major = FREETYPE_MAJOR; 4631 library->version_minor = FREETYPE_MINOR; 4632 library->version_patch = FREETYPE_PATCH; 4633 4634 library->refcount = 1; 4635 4636 /* That's ok now */ 4637 *alibrary = library; 4638 4639 return FT_Err_Ok; 4640 4641 Fail: 4642 #ifdef FT_CONFIG_OPTION_PIC 4643 ft_pic_container_destroy( library ); 4644 #endif 4645 FT_FREE( library ); 4646 return error; 4647 } 4648 4649 4650 /* documentation is in freetype.h */ 4651 4652 FT_EXPORT_DEF( void ) 4653 FT_Library_Version( FT_Library library, 4654 FT_Int *amajor, 4655 FT_Int *aminor, 4656 FT_Int *apatch ) 4657 { 4658 FT_Int major = 0; 4659 FT_Int minor = 0; 4660 FT_Int patch = 0; 4661 4662 4663 if ( library ) 4664 { 4665 major = library->version_major; 4666 minor = library->version_minor; 4667 patch = library->version_patch; 4668 } 4669 4670 if ( amajor ) 4671 *amajor = major; 4672 4673 if ( aminor ) 4674 *aminor = minor; 4675 4676 if ( apatch ) 4677 *apatch = patch; 4678 } 4679 4680 4681 /* documentation is in ftmodapi.h */ 4682 4683 FT_EXPORT_DEF( FT_Error ) 4684 FT_Done_Library( FT_Library library ) 4685 { 4686 FT_Memory memory; 4687 4688 4689 if ( !library ) 4690 return FT_THROW( Invalid_Library_Handle ); 4691 4692 library->refcount--; 4693 if ( library->refcount > 0 ) 4694 goto Exit; 4695 4696 memory = library->memory; 4697 4698 /* 4699 * Close all faces in the library. If we don't do this, we can have 4700 * some subtle memory leaks. 4701 * 4702 * Example: 4703 * 4704 * - the cff font driver uses the pshinter module in cff_size_done 4705 * - if the pshinter module is destroyed before the cff font driver, 4706 * opened FT_Face objects managed by the driver are not properly 4707 * destroyed, resulting in a memory leak 4708 * 4709 * Some faces are dependent on other faces, like Type42 faces that 4710 * depend on TrueType faces synthesized internally. 4711 * 4712 * The order of drivers should be specified in driver_name[]. 4713 */ 4714 { 4715 FT_UInt m, n; 4716 const char* driver_name[] = { "type42", NULL }; 4717 4718 4719 for ( m = 0; 4720 m < sizeof ( driver_name ) / sizeof ( driver_name[0] ); 4721 m++ ) 4722 { 4723 for ( n = 0; n < library->num_modules; n++ ) 4724 { 4725 FT_Module module = library->modules[n]; 4726 const char* module_name = module->clazz->module_name; 4727 FT_List faces; 4728 4729 4730 if ( driver_name[m] && 4731 ft_strcmp( module_name, driver_name[m] ) != 0 ) 4732 continue; 4733 4734 if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 ) 4735 continue; 4736 4737 FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name )); 4738 4739 faces = &FT_DRIVER( module )->faces_list; 4740 while ( faces->head ) 4741 { 4742 FT_Done_Face( FT_FACE( faces->head->data ) ); 4743 if ( faces->head ) 4744 FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" )); 4745 } 4746 } 4747 } 4748 } 4749 4750 /* Close all other modules in the library */ 4751 #if 1 4752 /* XXX Modules are removed in the reversed order so that */ 4753 /* type42 module is removed before truetype module. This */ 4754 /* avoids double free in some occasions. It is a hack. */ 4755 while ( library->num_modules > 0 ) 4756 FT_Remove_Module( library, 4757 library->modules[library->num_modules - 1] ); 4758 #else 4759 { 4760 FT_UInt n; 4761 4762 4763 for ( n = 0; n < library->num_modules; n++ ) 4764 { 4765 FT_Module module = library->modules[n]; 4766 4767 4768 if ( module ) 4769 { 4770 Destroy_Module( module ); 4771 library->modules[n] = 0; 4772 } 4773 } 4774 } 4775 #endif 4776 4777 /* Destroy raster objects */ 4778 FT_FREE( library->raster_pool ); 4779 library->raster_pool_size = 0; 4780 4781 #ifdef FT_CONFIG_OPTION_PIC 4782 /* Destroy pic container contents */ 4783 ft_pic_container_destroy( library ); 4784 #endif 4785 4786 FT_FREE( library ); 4787 4788 Exit: 4789 return FT_Err_Ok; 4790 } 4791 4792 4793 /* documentation is in ftmodapi.h */ 4794 4795 FT_EXPORT_DEF( void ) 4796 FT_Set_Debug_Hook( FT_Library library, 4797 FT_UInt hook_index, 4798 FT_DebugHook_Func debug_hook ) 4799 { 4800 if ( library && debug_hook && 4801 hook_index < 4802 ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) ) 4803 library->debug_hooks[hook_index] = debug_hook; 4804 } 4805 4806 4807 /* documentation is in ftmodapi.h */ 4808 4809 FT_EXPORT_DEF( FT_TrueTypeEngineType ) 4810 FT_Get_TrueType_Engine_Type( FT_Library library ) 4811 { 4812 FT_TrueTypeEngineType result = FT_TRUETYPE_ENGINE_TYPE_NONE; 4813 4814 4815 if ( library ) 4816 { 4817 FT_Module module = FT_Get_Module( library, "truetype" ); 4818 4819 4820 if ( module ) 4821 { 4822 FT_Service_TrueTypeEngine service; 4823 4824 4825 service = (FT_Service_TrueTypeEngine) 4826 ft_module_get_service( module, 4827 FT_SERVICE_ID_TRUETYPE_ENGINE ); 4828 if ( service ) 4829 result = service->engine_type; 4830 } 4831 } 4832 4833 return result; 4834 } 4835 4836 4837 /* documentation is in freetype.h */ 4838 4839 FT_EXPORT_DEF( FT_Error ) 4840 FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, 4841 FT_UInt sub_index, 4842 FT_Int *p_index, 4843 FT_UInt *p_flags, 4844 FT_Int *p_arg1, 4845 FT_Int *p_arg2, 4846 FT_Matrix *p_transform ) 4847 { 4848 FT_Error error = FT_ERR( Invalid_Argument ); 4849 4850 4851 if ( glyph && 4852 glyph->subglyphs && 4853 glyph->format == FT_GLYPH_FORMAT_COMPOSITE && 4854 sub_index < glyph->num_subglyphs ) 4855 { 4856 FT_SubGlyph subg = glyph->subglyphs + sub_index; 4857 4858 4859 *p_index = subg->index; 4860 *p_flags = subg->flags; 4861 *p_arg1 = subg->arg1; 4862 *p_arg2 = subg->arg2; 4863 *p_transform = subg->transform; 4864 } 4865 4866 return error; 4867 } 4868 4869 4870 /* END */