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