1 /***************************************************************************/ 2 /* */ 3 /* ftmac.c */ 4 /* */ 5 /* Mac FOND support. Written by just@letterror.com. */ 6 /* Heavily Fixed by mpsuzuki, George Williams and Sean McBride */ 7 /* */ 8 /* Copyright (C) 1996-2019 by */ 9 /* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */ 10 /* */ 11 /* This file is part of the FreeType project, and may only be used, */ 12 /* modified, and distributed under the terms of the FreeType project */ 13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 14 /* this file you indicate that you have read the license and */ 15 /* understand and accept it fully. */ 16 /* */ 17 /***************************************************************************/ 18 19 20 /* 21 Notes 22 23 Mac suitcase files can (and often do!) contain multiple fonts. To 24 support this I use the face_index argument of FT_(Open|New)_Face() 25 functions, and pretend the suitcase file is a collection. 26 27 Warning: fbit and NFNT bitmap resources are not supported yet. In old 28 sfnt fonts, bitmap glyph data for each size is stored in each `NFNT' 29 resources instead of the `bdat' table in the sfnt resource. Therefore, 30 face->num_fixed_sizes is set to 0, because bitmap data in `NFNT' 31 resource is unavailable at present. 32 33 The Mac FOND support works roughly like this: 34 35 - Check whether the offered stream points to a Mac suitcase file. This 36 is done by checking the file type: it has to be 'FFIL' or 'tfil'. The 37 stream that gets passed to our init_face() routine is a stdio stream, 38 which isn't usable for us, since the FOND resources live in the 39 resource fork. So we just grab the stream->pathname field. 40 41 - Read the FOND resource into memory, then check whether there is a 42 TrueType font and/or(!) a Type 1 font available. 43 44 - If there is a Type 1 font available (as a separate `LWFN' file), read 45 its data into memory, massage it slightly so it becomes PFB data, wrap 46 it into a memory stream, load the Type 1 driver and delegate the rest 47 of the work to it by calling FT_Open_Face(). (XXX TODO: after this 48 has been done, the kerning data from the FOND resource should be 49 appended to the face: On the Mac there are usually no AFM files 50 available. However, this is tricky since we need to map Mac char 51 codes to ps glyph names to glyph ID's...) 52 53 - If there is a TrueType font (an `sfnt' resource), read it into memory, 54 wrap it into a memory stream, load the TrueType driver and delegate 55 the rest of the work to it, by calling FT_Open_Face(). 56 57 - Some suitcase fonts (notably Onyx) might point the `LWFN' file to 58 itself, even though it doesn't contains `POST' resources. To handle 59 this special case without opening the file an extra time, we just 60 ignore errors from the `LWFN' and fallback to the `sfnt' if both are 61 available. 62 */ 63 64 65 #include <ft2build.h> 66 #include FT_FREETYPE_H 67 #include FT_TRUETYPE_TAGS_H 68 #include FT_INTERNAL_STREAM_H 69 #include "ftbase.h" 70 71 #if defined( __GNUC__ ) || defined( __IBMC__ ) 72 /* This is for Mac OS X. Without redefinition, OS_INLINE */ 73 /* expands to `static inline' which doesn't survive the */ 74 /* -ansi compilation flag of GCC. */ 75 #if !HAVE_ANSI_OS_INLINE 76 #undef OS_INLINE 77 #define OS_INLINE static __inline__ 78 #endif 79 #include <CoreServices/CoreServices.h> 80 #include <ApplicationServices/ApplicationServices.h> 81 #include <sys/syslimits.h> /* PATH_MAX */ 82 #else 83 #include <Resources.h> 84 #include <Fonts.h> 85 #include <Endian.h> 86 #include <Errors.h> 87 #include <Files.h> 88 #include <TextUtils.h> 89 #endif 90 91 #ifndef PATH_MAX 92 #define PATH_MAX 1024 /* same with Mac OS X's syslimits.h */ 93 #endif 94 95 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO 96 #include <FSp_fopen.h> 97 #endif 98 99 #define FT_DEPRECATED_ATTRIBUTE 100 101 #include FT_MAC_H 102 103 /* undefine blocking-macros in ftmac.h */ 104 #undef FT_GetFile_From_Mac_Name 105 #undef FT_GetFile_From_Mac_ATS_Name 106 #undef FT_New_Face_From_FOND 107 #undef FT_New_Face_From_FSSpec 108 #undef FT_New_Face_From_FSRef 109 110 111 /* FSSpec functions are deprecated since Mac OS X 10.4 */ 112 #ifndef HAVE_FSSPEC 113 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON 114 #define HAVE_FSSPEC 1 115 #else 116 #define HAVE_FSSPEC 0 117 #endif 118 #endif 119 120 /* most FSRef functions were introduced since Mac OS 9 */ 121 #ifndef HAVE_FSREF 122 #if TARGET_API_MAC_OSX 123 #define HAVE_FSREF 1 124 #else 125 #define HAVE_FSREF 0 126 #endif 127 #endif 128 129 /* QuickDraw is deprecated since Mac OS X 10.4 */ 130 #ifndef HAVE_QUICKDRAW_CARBON 131 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON 132 #define HAVE_QUICKDRAW_CARBON 1 133 #else 134 #define HAVE_QUICKDRAW_CARBON 0 135 #endif 136 #endif 137 138 /* AppleTypeService is available since Mac OS X */ 139 #ifndef HAVE_ATS 140 #if TARGET_API_MAC_OSX 141 #define HAVE_ATS 1 142 #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */ 143 #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault 144 #endif 145 #else 146 #define HAVE_ATS 0 147 #endif 148 #endif 149 150 /* `configure' checks the availability of `ResourceIndex' strictly */ 151 /* and sets HAVE_TYPE_RESOURCE_INDEX to 1 or 0 always. If it is */ 152 /* not set (e.g., a build without `configure'), the availability */ 153 /* is guessed from the SDK version. */ 154 #ifndef HAVE_TYPE_RESOURCE_INDEX 155 #if !defined( MAC_OS_X_VERSION_10_5 ) || \ 156 ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 ) 157 #define HAVE_TYPE_RESOURCE_INDEX 0 158 #else 159 #define HAVE_TYPE_RESOURCE_INDEX 1 160 #endif 161 #endif /* !HAVE_TYPE_RESOURCE_INDEX */ 162 163 #if ( HAVE_TYPE_RESOURCE_INDEX == 0 ) 164 typedef short ResourceIndex; 165 #endif 166 167 /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over 168 TrueType in case *both* are available (this is not common, 169 but it *is* possible). */ 170 #ifndef PREFER_LWFN 171 #define PREFER_LWFN 1 172 #endif 173 174 #ifdef FT_MACINTOSH 175 176 #if !HAVE_QUICKDRAW_CARBON /* QuickDraw is deprecated since Mac OS X 10.4 */ 177 178 FT_EXPORT_DEF( FT_Error ) FT_GetFile_From_Mac_Name(const char * fontName,FSSpec * pathSpec,FT_Long * face_index)179 FT_GetFile_From_Mac_Name( const char* fontName, 180 FSSpec* pathSpec, 181 FT_Long* face_index ) 182 { 183 FT_UNUSED( fontName ); 184 FT_UNUSED( pathSpec ); 185 FT_UNUSED( face_index ); 186 187 return FT_THROW( Unimplemented_Feature ); 188 } 189 190 #else 191 192 FT_EXPORT_DEF( FT_Error ) FT_GetFile_From_Mac_Name(const char * fontName,FSSpec * pathSpec,FT_Long * face_index)193 FT_GetFile_From_Mac_Name( const char* fontName, 194 FSSpec* pathSpec, 195 FT_Long* face_index ) 196 { 197 OptionBits options = kFMUseGlobalScopeOption; 198 199 FMFontFamilyIterator famIter; 200 OSStatus status = FMCreateFontFamilyIterator( NULL, NULL, 201 options, 202 &famIter ); 203 FMFont the_font = 0; 204 FMFontFamily family = 0; 205 206 207 if ( !fontName || !face_index ) 208 return FT_THROW( Invalid_Argument ); 209 210 *face_index = 0; 211 while ( status == 0 && !the_font ) 212 { 213 status = FMGetNextFontFamily( &famIter, &family ); 214 if ( status == 0 ) 215 { 216 int stat2; 217 FMFontFamilyInstanceIterator instIter; 218 Str255 famNameStr; 219 char famName[256]; 220 221 222 /* get the family name */ 223 FMGetFontFamilyName( family, famNameStr ); 224 CopyPascalStringToC( famNameStr, famName ); 225 226 /* iterate through the styles */ 227 FMCreateFontFamilyInstanceIterator( family, &instIter ); 228 229 *face_index = 0; 230 stat2 = 0; 231 232 while ( stat2 == 0 && !the_font ) 233 { 234 FMFontStyle style; 235 FMFontSize size; 236 FMFont font; 237 238 239 stat2 = FMGetNextFontFamilyInstance( &instIter, &font, 240 &style, &size ); 241 if ( stat2 == 0 && size == 0 ) 242 { 243 char fullName[256]; 244 245 246 /* build up a complete face name */ 247 ft_strcpy( fullName, famName ); 248 if ( style & bold ) 249 ft_strcat( fullName, " Bold" ); 250 if ( style & italic ) 251 ft_strcat( fullName, " Italic" ); 252 253 /* compare with the name we are looking for */ 254 if ( ft_strcmp( fullName, fontName ) == 0 ) 255 { 256 /* found it! */ 257 the_font = font; 258 } 259 else 260 ++(*face_index); 261 } 262 } 263 264 FMDisposeFontFamilyInstanceIterator( &instIter ); 265 } 266 } 267 268 FMDisposeFontFamilyIterator( &famIter ); 269 270 if ( the_font ) 271 { 272 FMGetFontContainer( the_font, pathSpec ); 273 return FT_Err_Ok; 274 } 275 else 276 return FT_THROW( Unknown_File_Format ); 277 } 278 279 #endif /* HAVE_QUICKDRAW_CARBON */ 280 281 282 #if HAVE_ATS 283 284 /* Private function. */ 285 /* The FSSpec type has been discouraged for a long time, */ 286 /* unfortunately an FSRef replacement API for */ 287 /* ATSFontGetFileSpecification() is only available in */ 288 /* Mac OS X 10.5 and later. */ 289 static OSStatus FT_ATSFontGetFileReference(ATSFontRef ats_font_id,FSRef * ats_font_ref)290 FT_ATSFontGetFileReference( ATSFontRef ats_font_id, 291 FSRef* ats_font_ref ) 292 { 293 OSStatus err; 294 295 #if !defined( MAC_OS_X_VERSION_10_5 ) || \ 296 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 297 FSSpec spec; 298 299 300 err = ATSFontGetFileSpecification( ats_font_id, &spec ); 301 if ( noErr == err ) 302 err = FSpMakeFSRef( &spec, ats_font_ref ); 303 #else 304 err = ATSFontGetFileReference( ats_font_id, ats_font_ref ); 305 #endif 306 307 return err; 308 } 309 310 311 static FT_Error FT_GetFileRef_From_Mac_ATS_Name(const char * fontName,FSRef * ats_font_ref,FT_Long * face_index)312 FT_GetFileRef_From_Mac_ATS_Name( const char* fontName, 313 FSRef* ats_font_ref, 314 FT_Long* face_index ) 315 { 316 CFStringRef cf_fontName; 317 ATSFontRef ats_font_id; 318 319 320 *face_index = 0; 321 322 cf_fontName = CFStringCreateWithCString( NULL, fontName, 323 kCFStringEncodingMacRoman ); 324 ats_font_id = ATSFontFindFromName( cf_fontName, 325 kATSOptionFlagsUnRestrictedScope ); 326 CFRelease( cf_fontName ); 327 328 if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) 329 return FT_THROW( Unknown_File_Format ); 330 331 if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) ) 332 return FT_THROW( Unknown_File_Format ); 333 334 /* face_index calculation by searching preceding fontIDs */ 335 /* with same FSRef */ 336 { 337 ATSFontRef id2 = ats_font_id - 1; 338 FSRef ref2; 339 340 341 while ( id2 > 0 ) 342 { 343 if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) ) 344 break; 345 if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) ) 346 break; 347 348 id2--; 349 } 350 *face_index = ats_font_id - ( id2 + 1 ); 351 } 352 353 return FT_Err_Ok; 354 } 355 356 #endif 357 358 #if !HAVE_ATS 359 360 FT_EXPORT_DEF( FT_Error ) FT_GetFilePath_From_Mac_ATS_Name(const char * fontName,UInt8 * path,UInt32 maxPathSize,FT_Long * face_index)361 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, 362 UInt8* path, 363 UInt32 maxPathSize, 364 FT_Long* face_index ) 365 { 366 FT_UNUSED( fontName ); 367 FT_UNUSED( path ); 368 FT_UNUSED( maxPathSize ); 369 FT_UNUSED( face_index ); 370 371 return FT_THROW( Unimplemented_Feature ); 372 } 373 374 #else 375 376 FT_EXPORT_DEF( FT_Error ) FT_GetFilePath_From_Mac_ATS_Name(const char * fontName,UInt8 * path,UInt32 maxPathSize,FT_Long * face_index)377 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, 378 UInt8* path, 379 UInt32 maxPathSize, 380 FT_Long* face_index ) 381 { 382 FSRef ref; 383 FT_Error err; 384 385 386 err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); 387 if ( err ) 388 return err; 389 390 if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) ) 391 return FT_THROW( Unknown_File_Format ); 392 393 return FT_Err_Ok; 394 } 395 396 #endif /* HAVE_ATS */ 397 398 399 #if !HAVE_FSSPEC || !HAVE_ATS 400 401 FT_EXPORT_DEF( FT_Error ) FT_GetFile_From_Mac_ATS_Name(const char * fontName,FSSpec * pathSpec,FT_Long * face_index)402 FT_GetFile_From_Mac_ATS_Name( const char* fontName, 403 FSSpec* pathSpec, 404 FT_Long* face_index ) 405 { 406 FT_UNUSED( fontName ); 407 FT_UNUSED( pathSpec ); 408 FT_UNUSED( face_index ); 409 410 return FT_THROW( Unimplemented_Feature ); 411 } 412 413 #else 414 415 /* This function is deprecated because FSSpec is deprecated in Mac OS X. */ 416 FT_EXPORT_DEF( FT_Error ) FT_GetFile_From_Mac_ATS_Name(const char * fontName,FSSpec * pathSpec,FT_Long * face_index)417 FT_GetFile_From_Mac_ATS_Name( const char* fontName, 418 FSSpec* pathSpec, 419 FT_Long* face_index ) 420 { 421 FSRef ref; 422 FT_Error err; 423 424 425 err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); 426 if ( err ) 427 return err; 428 429 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, 430 pathSpec, NULL ) ) 431 return FT_THROW( Unknown_File_Format ); 432 433 return FT_Err_Ok; 434 } 435 436 #endif 437 438 439 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO 440 441 #define STREAM_FILE( stream ) ( (FT_FILE*)stream->descriptor.pointer ) 442 443 444 FT_CALLBACK_DEF( void ) ft_FSp_stream_close(FT_Stream stream)445 ft_FSp_stream_close( FT_Stream stream ) 446 { 447 ft_fclose( STREAM_FILE( stream ) ); 448 449 stream->descriptor.pointer = NULL; 450 stream->size = 0; 451 stream->base = 0; 452 } 453 454 455 FT_CALLBACK_DEF( unsigned long ) ft_FSp_stream_io(FT_Stream stream,unsigned long offset,unsigned char * buffer,unsigned long count)456 ft_FSp_stream_io( FT_Stream stream, 457 unsigned long offset, 458 unsigned char* buffer, 459 unsigned long count ) 460 { 461 FT_FILE* file; 462 463 464 file = STREAM_FILE( stream ); 465 466 ft_fseek( file, offset, SEEK_SET ); 467 468 return (unsigned long)ft_fread( buffer, 1, count, file ); 469 } 470 471 #endif /* __MWERKS__ && !TARGET_RT_MAC_MACHO */ 472 473 474 #if HAVE_FSSPEC && !HAVE_FSREF 475 476 /* isDirectory is a dummy to synchronize API with FSPathMakeRef() */ 477 static OSErr FT_FSPathMakeSpec(const UInt8 * pathname,FSSpec * spec_p,Boolean isDirectory)478 FT_FSPathMakeSpec( const UInt8* pathname, 479 FSSpec* spec_p, 480 Boolean isDirectory ) 481 { 482 const char *p, *q; 483 short vRefNum; 484 long dirID; 485 Str255 nodeName; 486 OSErr err; 487 FT_UNUSED( isDirectory ); 488 489 490 p = q = (const char *)pathname; 491 dirID = 0; 492 vRefNum = 0; 493 494 while ( 1 ) 495 { 496 int len = ft_strlen( p ); 497 498 499 if ( len > 255 ) 500 len = 255; 501 502 q = p + len; 503 504 if ( q == p ) 505 return 0; 506 507 if ( 255 < ft_strlen( (char *)pathname ) ) 508 { 509 while ( p < q && *q != ':' ) 510 q--; 511 } 512 513 if ( p < q ) 514 *(char *)nodeName = q - p; 515 else if ( ft_strlen( p ) < 256 ) 516 *(char *)nodeName = ft_strlen( p ); 517 else 518 return errFSNameTooLong; 519 520 ft_strncpy( (char *)nodeName + 1, (char *)p, *(char *)nodeName ); 521 err = FSMakeFSSpec( vRefNum, dirID, nodeName, spec_p ); 522 if ( err || '\0' == *q ) 523 return err; 524 525 vRefNum = spec_p->vRefNum; 526 dirID = spec_p->parID; 527 528 p = q; 529 } 530 } 531 532 533 static OSErr FT_FSpMakePath(const FSSpec * spec_p,UInt8 * path,UInt32 maxPathSize)534 FT_FSpMakePath( const FSSpec* spec_p, 535 UInt8* path, 536 UInt32 maxPathSize ) 537 { 538 OSErr err; 539 FSSpec spec = *spec_p; 540 short vRefNum; 541 long dirID; 542 Str255 parDir_name; 543 544 545 FT_MEM_SET( path, 0, maxPathSize ); 546 while ( 1 ) 547 { 548 int child_namelen = ft_strlen( (char *)path ); 549 unsigned char node_namelen = spec.name[0]; 550 unsigned char* node_name = spec.name + 1; 551 552 553 if ( node_namelen + child_namelen > maxPathSize ) 554 return errFSNameTooLong; 555 556 FT_MEM_MOVE( path + node_namelen + 1, path, child_namelen ); 557 FT_MEM_COPY( path, node_name, node_namelen ); 558 if ( child_namelen > 0 ) 559 path[node_namelen] = ':'; 560 561 vRefNum = spec.vRefNum; 562 dirID = spec.parID; 563 parDir_name[0] = '\0'; 564 err = FSMakeFSSpec( vRefNum, dirID, parDir_name, &spec ); 565 if ( noErr != err || dirID == spec.parID ) 566 break; 567 } 568 return noErr; 569 } 570 571 #endif /* HAVE_FSSPEC && !HAVE_FSREF */ 572 573 574 static OSErr FT_FSPathMakeRes(const UInt8 * pathname,ResFileRefNum * res)575 FT_FSPathMakeRes( const UInt8* pathname, 576 ResFileRefNum* res ) 577 { 578 579 #if HAVE_FSREF 580 581 OSErr err; 582 FSRef ref; 583 584 585 if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) 586 return FT_THROW( Cannot_Open_Resource ); 587 588 /* at present, no support for dfont format */ 589 err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res ); 590 if ( noErr == err ) 591 return err; 592 593 /* fallback to original resource-fork font */ 594 *res = FSOpenResFile( &ref, fsRdPerm ); 595 err = ResError(); 596 597 #else 598 599 OSErr err; 600 FSSpec spec; 601 602 603 if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) ) 604 return FT_THROW( Cannot_Open_Resource ); 605 606 /* at present, no support for dfont format without FSRef */ 607 /* (see above), try original resource-fork font */ 608 *res = FSpOpenResFile( &spec, fsRdPerm ); 609 err = ResError(); 610 611 #endif /* HAVE_FSREF */ 612 613 return err; 614 } 615 616 617 /* Return the file type for given pathname */ 618 static OSType get_file_type_from_path(const UInt8 * pathname)619 get_file_type_from_path( const UInt8* pathname ) 620 { 621 622 #if HAVE_FSREF 623 624 FSRef ref; 625 FSCatalogInfo info; 626 627 628 if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) 629 return ( OSType ) 0; 630 631 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info, 632 NULL, NULL, NULL ) ) 633 return ( OSType ) 0; 634 635 return ((FInfo *)(info.finderInfo))->fdType; 636 637 #else 638 639 FSSpec spec; 640 FInfo finfo; 641 642 643 if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) ) 644 return ( OSType ) 0; 645 646 if ( noErr != FSpGetFInfo( &spec, &finfo ) ) 647 return ( OSType ) 0; 648 649 return finfo.fdType; 650 651 #endif /* HAVE_FSREF */ 652 653 } 654 655 656 /* Given a PostScript font name, create the Macintosh LWFN file name. */ 657 static void create_lwfn_name(char * ps_name,Str255 lwfn_file_name)658 create_lwfn_name( char* ps_name, 659 Str255 lwfn_file_name ) 660 { 661 int max = 5, count = 0; 662 FT_Byte* p = lwfn_file_name; 663 FT_Byte* q = (FT_Byte*)ps_name; 664 665 666 lwfn_file_name[0] = 0; 667 668 while ( *q ) 669 { 670 if ( ft_isupper( *q ) ) 671 { 672 if ( count ) 673 max = 3; 674 count = 0; 675 } 676 if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) ) 677 { 678 *++p = *q; 679 lwfn_file_name[0]++; 680 count++; 681 } 682 q++; 683 } 684 } 685 686 687 static short count_faces_sfnt(char * fond_data)688 count_faces_sfnt( char* fond_data ) 689 { 690 /* The count is 1 greater than the value in the FOND. */ 691 /* Isn't that cute? :-) */ 692 693 return EndianS16_BtoN( *( (short*)( fond_data + 694 sizeof ( FamRec ) ) ) ) + 1; 695 } 696 697 698 static short count_faces_scalable(char * fond_data)699 count_faces_scalable( char* fond_data ) 700 { 701 AsscEntry* assoc; 702 short i, face, face_all; 703 704 705 face_all = EndianS16_BtoN( *( (short *)( fond_data + 706 sizeof ( FamRec ) ) ) ) + 1; 707 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); 708 face = 0; 709 710 for ( i = 0; i < face_all; i++ ) 711 { 712 if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) ) 713 face++; 714 } 715 return face; 716 } 717 718 719 /* Look inside the FOND data, answer whether there should be an SFNT 720 resource, and answer the name of a possible LWFN Type 1 file. 721 722 Thanks to Paul Miller (paulm@profoundeffects.com) for the fix 723 to load a face OTHER than the first one in the FOND! 724 */ 725 726 static void parse_fond(char * fond_data,short * have_sfnt,ResID * sfnt_id,Str255 lwfn_file_name,short face_index)727 parse_fond( char* fond_data, 728 short* have_sfnt, 729 ResID* sfnt_id, 730 Str255 lwfn_file_name, 731 short face_index ) 732 { 733 AsscEntry* assoc; 734 AsscEntry* base_assoc; 735 FamRec* fond; 736 737 738 *sfnt_id = 0; 739 *have_sfnt = 0; 740 lwfn_file_name[0] = 0; 741 742 fond = (FamRec*)fond_data; 743 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); 744 base_assoc = assoc; 745 746 /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */ 747 if ( 47 < face_index ) 748 return; 749 750 /* Let's do a little range checking before we get too excited here */ 751 if ( face_index < count_faces_sfnt( fond_data ) ) 752 { 753 assoc += face_index; /* add on the face_index! */ 754 755 /* if the face at this index is not scalable, 756 fall back to the first one (old behavior) */ 757 if ( EndianS16_BtoN( assoc->fontSize ) == 0 ) 758 { 759 *have_sfnt = 1; 760 *sfnt_id = EndianS16_BtoN( assoc->fontID ); 761 } 762 else if ( base_assoc->fontSize == 0 ) 763 { 764 *have_sfnt = 1; 765 *sfnt_id = EndianS16_BtoN( base_assoc->fontID ); 766 } 767 } 768 769 if ( EndianS32_BtoN( fond->ffStylOff ) ) 770 { 771 unsigned char* p = (unsigned char*)fond_data; 772 StyleTable* style; 773 unsigned short string_count; 774 char ps_name[256]; 775 unsigned char* names[64]; 776 int i; 777 778 779 p += EndianS32_BtoN( fond->ffStylOff ); 780 style = (StyleTable*)p; 781 p += sizeof ( StyleTable ); 782 string_count = EndianS16_BtoN( *(short*)(p) ); 783 string_count = FT_MIN( 64, string_count ); 784 p += sizeof ( short ); 785 786 for ( i = 0; i < string_count; i++ ) 787 { 788 names[i] = p; 789 p += names[i][0]; 790 p++; 791 } 792 793 { 794 size_t ps_name_len = (size_t)names[0][0]; 795 796 797 if ( ps_name_len != 0 ) 798 { 799 ft_memcpy(ps_name, names[0] + 1, ps_name_len); 800 ps_name[ps_name_len] = 0; 801 } 802 if ( style->indexes[face_index] > 1 && 803 style->indexes[face_index] <= string_count ) 804 { 805 unsigned char* suffixes = names[style->indexes[face_index] - 1]; 806 807 808 for ( i = 1; i <= suffixes[0]; i++ ) 809 { 810 unsigned char* s; 811 size_t j = suffixes[i] - 1; 812 813 814 if ( j < string_count && ( s = names[j] ) != NULL ) 815 { 816 size_t s_len = (size_t)s[0]; 817 818 819 if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) ) 820 { 821 ft_memcpy( ps_name + ps_name_len, s + 1, s_len ); 822 ps_name_len += s_len; 823 ps_name[ps_name_len] = 0; 824 } 825 } 826 } 827 } 828 } 829 830 create_lwfn_name( ps_name, lwfn_file_name ); 831 } 832 } 833 834 835 static FT_Error lookup_lwfn_by_fond(const UInt8 * path_fond,ConstStr255Param base_lwfn,UInt8 * path_lwfn,int path_size)836 lookup_lwfn_by_fond( const UInt8* path_fond, 837 ConstStr255Param base_lwfn, 838 UInt8* path_lwfn, 839 int path_size ) 840 { 841 842 #if HAVE_FSREF 843 844 FSRef ref, par_ref; 845 int dirname_len; 846 847 848 /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */ 849 /* We should not extract parent directory by string manipulation. */ 850 851 if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) ) 852 return FT_THROW( Invalid_Argument ); 853 854 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, 855 NULL, NULL, NULL, &par_ref ) ) 856 return FT_THROW( Invalid_Argument ); 857 858 if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) ) 859 return FT_THROW( Invalid_Argument ); 860 861 if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size ) 862 return FT_THROW( Invalid_Argument ); 863 864 /* now we have absolute dirname in path_lwfn */ 865 if ( path_lwfn[0] == '/' ) 866 ft_strcat( (char *)path_lwfn, "/" ); 867 else 868 ft_strcat( (char *)path_lwfn, ":" ); 869 870 dirname_len = ft_strlen( (char *)path_lwfn ); 871 ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 ); 872 path_lwfn[dirname_len + base_lwfn[0]] = '\0'; 873 874 if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) ) 875 return FT_THROW( Cannot_Open_Resource ); 876 877 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, 878 NULL, NULL, NULL, NULL ) ) 879 return FT_THROW( Cannot_Open_Resource ); 880 881 return FT_Err_Ok; 882 883 #else 884 885 int i; 886 FSSpec spec; 887 888 889 /* pathname for FSSpec is always HFS format */ 890 if ( ft_strlen( (char *)path_fond ) > path_size ) 891 return FT_THROW( Invalid_Argument ); 892 893 ft_strcpy( (char *)path_lwfn, (char *)path_fond ); 894 895 i = ft_strlen( (char *)path_lwfn ) - 1; 896 while ( i > 0 && ':' != path_lwfn[i] ) 897 i--; 898 899 if ( i + 1 + base_lwfn[0] > path_size ) 900 return FT_THROW( Invalid_Argument ); 901 902 if ( ':' == path_lwfn[i] ) 903 { 904 ft_strcpy( (char *)path_lwfn + i + 1, (char *)base_lwfn + 1 ); 905 path_lwfn[i + 1 + base_lwfn[0]] = '\0'; 906 } 907 else 908 { 909 ft_strcpy( (char *)path_lwfn, (char *)base_lwfn + 1 ); 910 path_lwfn[base_lwfn[0]] = '\0'; 911 } 912 913 if ( noErr != FT_FSPathMakeSpec( path_lwfn, &spec, FALSE ) ) 914 return FT_THROW( Cannot_Open_Resource ); 915 916 return FT_Err_Ok; 917 918 #endif /* HAVE_FSREF */ 919 920 } 921 922 923 static short count_faces(Handle fond,const UInt8 * pathname)924 count_faces( Handle fond, 925 const UInt8* pathname ) 926 { 927 ResID sfnt_id; 928 short have_sfnt, have_lwfn; 929 Str255 lwfn_file_name; 930 UInt8 buff[PATH_MAX]; 931 FT_Error err; 932 short num_faces; 933 934 935 have_sfnt = have_lwfn = 0; 936 937 HLock( fond ); 938 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 ); 939 940 if ( lwfn_file_name[0] ) 941 { 942 err = lookup_lwfn_by_fond( pathname, lwfn_file_name, 943 buff, sizeof ( buff ) ); 944 if ( !err ) 945 have_lwfn = 1; 946 } 947 948 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) 949 num_faces = 1; 950 else 951 num_faces = count_faces_scalable( *fond ); 952 953 HUnlock( fond ); 954 return num_faces; 955 } 956 957 958 /* Read Type 1 data from the POST resources inside the LWFN file, 959 return a PFB buffer. This is somewhat convoluted because the FT2 960 PFB parser wants the ASCII header as one chunk, and the LWFN 961 chunks are often not organized that way, so we glue chunks 962 of the same type together. */ 963 static FT_Error read_lwfn(FT_Memory memory,ResFileRefNum res,FT_Byte ** pfb_data,FT_ULong * size)964 read_lwfn( FT_Memory memory, 965 ResFileRefNum res, 966 FT_Byte** pfb_data, 967 FT_ULong* size ) 968 { 969 FT_Error error = FT_Err_Ok; 970 ResID res_id; 971 unsigned char *buffer, *p, *size_p = NULL; 972 FT_ULong total_size = 0; 973 FT_ULong old_total_size = 0; 974 FT_ULong post_size, pfb_chunk_size; 975 Handle post_data; 976 char code, last_code; 977 978 979 UseResFile( res ); 980 981 /* First pass: load all POST resources, and determine the size of */ 982 /* the output buffer. */ 983 res_id = 501; 984 last_code = -1; 985 986 for (;;) 987 { 988 post_data = Get1Resource( TTAG_POST, res_id++ ); 989 if ( post_data == NULL ) 990 break; /* we are done */ 991 992 code = (*post_data)[0]; 993 994 if ( code != last_code ) 995 { 996 if ( code == 5 ) 997 total_size += 2; /* just the end code */ 998 else 999 total_size += 6; /* code + 4 bytes chunk length */ 1000 } 1001 1002 total_size += GetHandleSize( post_data ) - 2; 1003 last_code = code; 1004 1005 /* detect integer overflows */ 1006 if ( total_size < old_total_size ) 1007 { 1008 error = FT_ERR( Array_Too_Large ); 1009 goto Error; 1010 } 1011 1012 old_total_size = total_size; 1013 } 1014 1015 if ( FT_ALLOC( buffer, (FT_Long)total_size ) ) 1016 goto Error; 1017 1018 /* Second pass: append all POST data to the buffer, add PFB fields. */ 1019 /* Glue all consecutive chunks of the same type together. */ 1020 p = buffer; 1021 res_id = 501; 1022 last_code = -1; 1023 pfb_chunk_size = 0; 1024 1025 for (;;) 1026 { 1027 post_data = Get1Resource( TTAG_POST, res_id++ ); 1028 if ( post_data == NULL ) 1029 break; /* we are done */ 1030 1031 post_size = (FT_ULong)GetHandleSize( post_data ) - 2; 1032 code = (*post_data)[0]; 1033 1034 if ( code != last_code ) 1035 { 1036 if ( last_code != -1 ) 1037 { 1038 /* we are done adding a chunk, fill in the size field */ 1039 if ( size_p != NULL ) 1040 { 1041 *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF ); 1042 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF ); 1043 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF ); 1044 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF ); 1045 } 1046 pfb_chunk_size = 0; 1047 } 1048 1049 *p++ = 0x80; 1050 if ( code == 5 ) 1051 *p++ = 0x03; /* the end */ 1052 else if ( code == 2 ) 1053 *p++ = 0x02; /* binary segment */ 1054 else 1055 *p++ = 0x01; /* ASCII segment */ 1056 1057 if ( code != 5 ) 1058 { 1059 size_p = p; /* save for later */ 1060 p += 4; /* make space for size field */ 1061 } 1062 } 1063 1064 ft_memcpy( p, *post_data + 2, post_size ); 1065 pfb_chunk_size += post_size; 1066 p += post_size; 1067 last_code = code; 1068 } 1069 1070 *pfb_data = buffer; 1071 *size = total_size; 1072 1073 Error: 1074 CloseResFile( res ); 1075 return error; 1076 } 1077 1078 1079 /* Create a new FT_Face from a file spec to an LWFN file. */ 1080 static FT_Error FT_New_Face_From_LWFN(FT_Library library,const UInt8 * pathname,FT_Long face_index,FT_Face * aface)1081 FT_New_Face_From_LWFN( FT_Library library, 1082 const UInt8* pathname, 1083 FT_Long face_index, 1084 FT_Face* aface ) 1085 { 1086 FT_Byte* pfb_data; 1087 FT_ULong pfb_size; 1088 FT_Error error; 1089 ResFileRefNum res; 1090 1091 1092 if ( noErr != FT_FSPathMakeRes( pathname, &res ) ) 1093 return FT_THROW( Cannot_Open_Resource ); 1094 1095 pfb_data = NULL; 1096 pfb_size = 0; 1097 error = read_lwfn( library->memory, res, &pfb_data, &pfb_size ); 1098 CloseResFile( res ); /* PFB is already loaded, useless anymore */ 1099 if ( error ) 1100 return error; 1101 1102 return open_face_from_buffer( library, 1103 pfb_data, 1104 pfb_size, 1105 face_index, 1106 "type1", 1107 aface ); 1108 } 1109 1110 1111 /* Create a new FT_Face from an SFNT resource, specified by res ID. */ 1112 static FT_Error FT_New_Face_From_SFNT(FT_Library library,ResID sfnt_id,FT_Long face_index,FT_Face * aface)1113 FT_New_Face_From_SFNT( FT_Library library, 1114 ResID sfnt_id, 1115 FT_Long face_index, 1116 FT_Face* aface ) 1117 { 1118 Handle sfnt = NULL; 1119 FT_Byte* sfnt_data; 1120 size_t sfnt_size; 1121 FT_Error error = FT_Err_Ok; 1122 FT_Memory memory = library->memory; 1123 int is_cff, is_sfnt_ps; 1124 1125 1126 sfnt = GetResource( TTAG_sfnt, sfnt_id ); 1127 if ( sfnt == NULL ) 1128 return FT_THROW( Invalid_Handle ); 1129 1130 sfnt_size = (FT_ULong)GetHandleSize( sfnt ); 1131 if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) ) 1132 { 1133 ReleaseResource( sfnt ); 1134 return error; 1135 } 1136 1137 HLock( sfnt ); 1138 ft_memcpy( sfnt_data, *sfnt, sfnt_size ); 1139 HUnlock( sfnt ); 1140 ReleaseResource( sfnt ); 1141 1142 is_cff = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); 1143 is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 ); 1144 1145 if ( is_sfnt_ps ) 1146 { 1147 FT_Stream stream; 1148 1149 1150 if ( FT_NEW( stream ) ) 1151 goto Try_OpenType; 1152 1153 FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size ); 1154 if ( !open_face_PS_from_sfnt_stream( library, 1155 stream, 1156 face_index, 1157 0, NULL, 1158 aface ) ) 1159 { 1160 FT_Stream_Close( stream ); 1161 FT_FREE( stream ); 1162 FT_FREE( sfnt_data ); 1163 goto Exit; 1164 } 1165 1166 FT_FREE( stream ); 1167 } 1168 Try_OpenType: 1169 error = open_face_from_buffer( library, 1170 sfnt_data, 1171 sfnt_size, 1172 face_index, 1173 is_cff ? "cff" : "truetype", 1174 aface ); 1175 Exit: 1176 return error; 1177 } 1178 1179 1180 /* Create a new FT_Face from a file spec to a suitcase file. */ 1181 static FT_Error FT_New_Face_From_Suitcase(FT_Library library,const UInt8 * pathname,FT_Long face_index,FT_Face * aface)1182 FT_New_Face_From_Suitcase( FT_Library library, 1183 const UInt8* pathname, 1184 FT_Long face_index, 1185 FT_Face* aface ) 1186 { 1187 FT_Error error = FT_ERR( Cannot_Open_Resource ); 1188 ResFileRefNum res_ref; 1189 ResourceIndex res_index; 1190 Handle fond; 1191 short num_faces_in_res; 1192 1193 1194 if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) ) 1195 return FT_THROW( Cannot_Open_Resource ); 1196 1197 UseResFile( res_ref ); 1198 if ( ResError() ) 1199 return FT_THROW( Cannot_Open_Resource ); 1200 1201 num_faces_in_res = 0; 1202 for ( res_index = 1; ; ++res_index ) 1203 { 1204 short num_faces_in_fond; 1205 1206 1207 fond = Get1IndResource( TTAG_FOND, res_index ); 1208 if ( ResError() ) 1209 break; 1210 1211 num_faces_in_fond = count_faces( fond, pathname ); 1212 num_faces_in_res += num_faces_in_fond; 1213 1214 if ( 0 <= face_index && face_index < num_faces_in_fond && error ) 1215 error = FT_New_Face_From_FOND( library, fond, face_index, aface ); 1216 1217 face_index -= num_faces_in_fond; 1218 } 1219 1220 CloseResFile( res_ref ); 1221 if ( !error && aface ) 1222 (*aface)->num_faces = num_faces_in_res; 1223 return error; 1224 } 1225 1226 1227 /* documentation is in ftmac.h */ 1228 1229 FT_EXPORT_DEF( FT_Error ) FT_New_Face_From_FOND(FT_Library library,Handle fond,FT_Long face_index,FT_Face * aface)1230 FT_New_Face_From_FOND( FT_Library library, 1231 Handle fond, 1232 FT_Long face_index, 1233 FT_Face* aface ) 1234 { 1235 short have_sfnt, have_lwfn = 0; 1236 ResID sfnt_id, fond_id; 1237 OSType fond_type; 1238 Str255 fond_name; 1239 Str255 lwfn_file_name; 1240 UInt8 path_lwfn[PATH_MAX]; 1241 OSErr err; 1242 FT_Error error = FT_Err_Ok; 1243 1244 1245 /* test for valid `aface' and `library' delayed to */ 1246 /* `FT_New_Face_From_XXX' */ 1247 1248 GetResInfo( fond, &fond_id, &fond_type, fond_name ); 1249 if ( ResError() != noErr || fond_type != TTAG_FOND ) 1250 return FT_THROW( Invalid_File_Format ); 1251 1252 HLock( fond ); 1253 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index ); 1254 HUnlock( fond ); 1255 1256 if ( lwfn_file_name[0] ) 1257 { 1258 ResFileRefNum res; 1259 1260 1261 res = HomeResFile( fond ); 1262 if ( noErr != ResError() ) 1263 goto found_no_lwfn_file; 1264 1265 #if HAVE_FSREF 1266 1267 { 1268 UInt8 path_fond[PATH_MAX]; 1269 FSRef ref; 1270 1271 1272 err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum, 1273 NULL, NULL, NULL, &ref, NULL ); 1274 if ( noErr != err ) 1275 goto found_no_lwfn_file; 1276 1277 err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) ); 1278 if ( noErr != err ) 1279 goto found_no_lwfn_file; 1280 1281 error = lookup_lwfn_by_fond( path_fond, lwfn_file_name, 1282 path_lwfn, sizeof ( path_lwfn ) ); 1283 if ( !error ) 1284 have_lwfn = 1; 1285 } 1286 1287 #elif HAVE_FSSPEC 1288 1289 { 1290 UInt8 path_fond[PATH_MAX]; 1291 FCBPBRec pb; 1292 Str255 fond_file_name; 1293 FSSpec spec; 1294 1295 1296 FT_MEM_SET( &spec, 0, sizeof ( FSSpec ) ); 1297 FT_MEM_SET( &pb, 0, sizeof ( FCBPBRec ) ); 1298 1299 pb.ioNamePtr = fond_file_name; 1300 pb.ioVRefNum = 0; 1301 pb.ioRefNum = res; 1302 pb.ioFCBIndx = 0; 1303 1304 err = PBGetFCBInfoSync( &pb ); 1305 if ( noErr != err ) 1306 goto found_no_lwfn_file; 1307 1308 err = FSMakeFSSpec( pb.ioFCBVRefNum, pb.ioFCBParID, 1309 fond_file_name, &spec ); 1310 if ( noErr != err ) 1311 goto found_no_lwfn_file; 1312 1313 err = FT_FSpMakePath( &spec, path_fond, sizeof ( path_fond ) ); 1314 if ( noErr != err ) 1315 goto found_no_lwfn_file; 1316 1317 error = lookup_lwfn_by_fond( path_fond, lwfn_file_name, 1318 path_lwfn, sizeof ( path_lwfn ) ); 1319 if ( !error ) 1320 have_lwfn = 1; 1321 } 1322 1323 #endif /* HAVE_FSREF, HAVE_FSSPEC */ 1324 1325 } 1326 1327 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) 1328 error = FT_New_Face_From_LWFN( library, 1329 path_lwfn, 1330 face_index, 1331 aface ); 1332 else 1333 error = FT_ERR( Unknown_File_Format ); 1334 1335 found_no_lwfn_file: 1336 if ( have_sfnt && error ) 1337 error = FT_New_Face_From_SFNT( library, 1338 sfnt_id, 1339 face_index, 1340 aface ); 1341 1342 return error; 1343 } 1344 1345 1346 /* Common function to load a new FT_Face from a resource file. */ 1347 static FT_Error FT_New_Face_From_Resource(FT_Library library,const UInt8 * pathname,FT_Long face_index,FT_Face * aface)1348 FT_New_Face_From_Resource( FT_Library library, 1349 const UInt8* pathname, 1350 FT_Long face_index, 1351 FT_Face* aface ) 1352 { 1353 OSType file_type; 1354 FT_Error error; 1355 1356 1357 /* LWFN is a (very) specific file format, check for it explicitly */ 1358 file_type = get_file_type_from_path( pathname ); 1359 if ( file_type == TTAG_LWFN ) 1360 return FT_New_Face_From_LWFN( library, pathname, face_index, aface ); 1361 1362 /* Otherwise the file type doesn't matter (there are more than */ 1363 /* `FFIL' and `tfil'). Just try opening it as a font suitcase; */ 1364 /* if it works, fine. */ 1365 1366 error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface ); 1367 if ( !error ) 1368 return error; 1369 1370 /* let it fall through to normal loader (.ttf, .otf, etc.); */ 1371 /* we signal this by returning no error and no FT_Face */ 1372 *aface = NULL; 1373 return 0; 1374 } 1375 1376 1377 /*************************************************************************/ 1378 /* */ 1379 /* <Function> */ 1380 /* FT_New_Face */ 1381 /* */ 1382 /* <Description> */ 1383 /* This is the Mac-specific implementation of FT_New_Face. In */ 1384 /* addition to the standard FT_New_Face() functionality, it also */ 1385 /* accepts pathnames to Mac suitcase files. For further */ 1386 /* documentation see the original FT_New_Face() in freetype.h. */ 1387 /* */ 1388 FT_EXPORT_DEF( FT_Error ) FT_New_Face(FT_Library library,const char * pathname,FT_Long face_index,FT_Face * aface)1389 FT_New_Face( FT_Library library, 1390 const char* pathname, 1391 FT_Long face_index, 1392 FT_Face* aface ) 1393 { 1394 FT_Open_Args args; 1395 FT_Error error; 1396 1397 1398 /* test for valid `library' and `aface' delayed to FT_Open_Face() */ 1399 if ( !pathname ) 1400 return FT_THROW( Invalid_Argument ); 1401 1402 *aface = NULL; 1403 1404 /* try resourcefork based font: LWFN, FFIL */ 1405 error = FT_New_Face_From_Resource( library, (UInt8 *)pathname, 1406 face_index, aface ); 1407 if ( error || *aface ) 1408 return error; 1409 1410 /* let it fall through to normal loader (.ttf, .otf, etc.) */ 1411 args.flags = FT_OPEN_PATHNAME; 1412 args.pathname = (char*)pathname; 1413 return FT_Open_Face( library, &args, face_index, aface ); 1414 } 1415 1416 1417 /*************************************************************************/ 1418 /* */ 1419 /* <Function> */ 1420 /* FT_New_Face_From_FSRef */ 1421 /* */ 1422 /* <Description> */ 1423 /* FT_New_Face_From_FSRef is identical to FT_New_Face except it */ 1424 /* accepts an FSRef instead of a path. */ 1425 /* */ 1426 /* This function is deprecated because Carbon data types (FSRef) */ 1427 /* are not cross-platform, and thus not suitable for the FreeType API. */ 1428 FT_EXPORT_DEF( FT_Error ) FT_New_Face_From_FSRef(FT_Library library,const FSRef * ref,FT_Long face_index,FT_Face * aface)1429 FT_New_Face_From_FSRef( FT_Library library, 1430 const FSRef* ref, 1431 FT_Long face_index, 1432 FT_Face* aface ) 1433 { 1434 1435 #if !HAVE_FSREF 1436 1437 FT_UNUSED( library ); 1438 FT_UNUSED( ref ); 1439 FT_UNUSED( face_index ); 1440 FT_UNUSED( aface ); 1441 1442 return FT_THROW( Unimplemented_Feature ); 1443 1444 #else 1445 1446 FT_Error error; 1447 FT_Open_Args args; 1448 OSErr err; 1449 UInt8 pathname[PATH_MAX]; 1450 1451 1452 /* test for valid `library' and `aface' delayed to `FT_Open_Face' */ 1453 1454 if ( !ref ) 1455 return FT_THROW( Invalid_Argument ); 1456 1457 err = FSRefMakePath( ref, pathname, sizeof ( pathname ) ); 1458 if ( err ) 1459 error = FT_ERR( Cannot_Open_Resource ); 1460 1461 error = FT_New_Face_From_Resource( library, pathname, face_index, aface ); 1462 if ( error || *aface ) 1463 return error; 1464 1465 /* fallback to datafork font */ 1466 args.flags = FT_OPEN_PATHNAME; 1467 args.pathname = (char*)pathname; 1468 return FT_Open_Face( library, &args, face_index, aface ); 1469 1470 #endif /* HAVE_FSREF */ 1471 1472 } 1473 1474 1475 /*************************************************************************/ 1476 /* */ 1477 /* <Function> */ 1478 /* FT_New_Face_From_FSSpec */ 1479 /* */ 1480 /* <Description> */ 1481 /* FT_New_Face_From_FSSpec is identical to FT_New_Face except it */ 1482 /* accepts an FSSpec instead of a path. */ 1483 /* */ 1484 /* This function is deprecated because Carbon data types (FSSpec) */ 1485 /* are not cross-platform, and thus not suitable for the FreeType API. */ 1486 FT_EXPORT_DEF( FT_Error ) FT_New_Face_From_FSSpec(FT_Library library,const FSSpec * spec,FT_Long face_index,FT_Face * aface)1487 FT_New_Face_From_FSSpec( FT_Library library, 1488 const FSSpec* spec, 1489 FT_Long face_index, 1490 FT_Face* aface ) 1491 { 1492 1493 #if HAVE_FSREF 1494 1495 FSRef ref; 1496 1497 1498 if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr ) 1499 return FT_THROW( Invalid_Argument ); 1500 else 1501 return FT_New_Face_From_FSRef( library, &ref, face_index, aface ); 1502 1503 #elif HAVE_FSSPEC 1504 1505 FT_Error error; 1506 FT_Open_Args args; 1507 OSErr err; 1508 UInt8 pathname[PATH_MAX]; 1509 1510 1511 if ( !spec ) 1512 return FT_THROW( Invalid_Argument ); 1513 1514 err = FT_FSpMakePath( spec, pathname, sizeof ( pathname ) ); 1515 if ( err ) 1516 error = FT_ERR( Cannot_Open_Resource ); 1517 1518 error = FT_New_Face_From_Resource( library, pathname, face_index, aface ); 1519 if ( error || *aface ) 1520 return error; 1521 1522 /* fallback to datafork font */ 1523 args.flags = FT_OPEN_PATHNAME; 1524 args.pathname = (char*)pathname; 1525 return FT_Open_Face( library, &args, face_index, aface ); 1526 1527 #else 1528 1529 FT_UNUSED( library ); 1530 FT_UNUSED( spec ); 1531 FT_UNUSED( face_index ); 1532 FT_UNUSED( aface ); 1533 1534 return FT_THROW( Unimplemented_Feature ); 1535 1536 #endif /* HAVE_FSREF, HAVE_FSSPEC */ 1537 1538 } 1539 1540 #endif /* FT_MACINTOSH */ 1541 1542 1543 /* END */ 1544