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