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