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