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