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