1 /****************************************************************************
5 * Mac FOND support. Written by just@letterror.com.
6 * Heavily modified by mpsuzuki, George Williams, and Sean McBride.
8 * This file is for Mac OS X only; see builds/mac/ftoldmac.c for
9 * classic platforms built by MPW.
11 * Copyright (C) 1996-2023 by
12 * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.
14 * This file is part of the FreeType project, and may only be used,
15 * modified, and distributed under the terms of the FreeType project
16 * license, LICENSE.TXT. By continuing to use, modify, or distribute
17 * this file you indicate that you have read the license and
18 * understand and accept it fully.
26 Mac suitcase files can (and often do!) contain multiple fonts. To
27 support this I use the face_index argument of FT_(Open|New)_Face()
28 functions, and pretend the suitcase file is a collection.
30 Warning: fbit and NFNT bitmap resources are not supported yet. In old
31 sfnt fonts, bitmap glyph data for each size is stored in each `NFNT'
32 resources instead of the `bdat' table in the sfnt resource. Therefore,
33 face->num_fixed_sizes is set to 0, because bitmap data in `NFNT'
34 resource is unavailable at present.
36 The Mac FOND support works roughly like this:
38 - Check whether the offered stream points to a Mac suitcase file. This
39 is done by checking the file type: it has to be 'FFIL' or 'tfil'. The
40 stream that gets passed to our init_face() routine is a stdio stream,
41 which isn't usable for us, since the FOND resources live in the
42 resource fork. So we just grab the stream->pathname field.
44 - Read the FOND resource into memory, then check whether there is a
45 TrueType font and/or(!) a Type 1 font available.
47 - If there is a Type 1 font available (as a separate `LWFN' file), read
48 its data into memory, massage it slightly so it becomes PFB data, wrap
49 it into a memory stream, load the Type 1 driver and delegate the rest
50 of the work to it by calling FT_Open_Face(). (XXX TODO: after this
51 has been done, the kerning data from the FOND resource should be
52 appended to the face: On the Mac there are usually no AFM files
53 available. However, this is tricky since we need to map Mac char
54 codes to ps glyph names to glyph ID's...)
56 - If there is a TrueType font (an `sfnt' resource), read it into memory,
57 wrap it into a memory stream, load the TrueType driver and delegate
58 the rest of the work to it, by calling FT_Open_Face().
60 - Some suitcase fonts (notably Onyx) might point the `LWFN' file to
61 itself, even though it doesn't contains `POST' resources. To handle
62 this special case without opening the file an extra time, we just
63 ignore errors from the `LWFN' and fallback to the `sfnt' if both are
68 #include <freetype/freetype.h>
69 #include <freetype/tttags.h>
70 #include <freetype/internal/ftdebug.h>
71 #include <freetype/internal/ftstream.h>
77 /* This is for Mac OS X. Without redefinition, OS_INLINE */
78 /* expands to `static inline' which doesn't survive the */
79 /* -ansi compilation flag of GCC. */
80 #if !HAVE_ANSI_OS_INLINE
82 #define OS_INLINE static __inline__
85 /* `configure' checks the availability of `ResourceIndex' strictly */
86 /* and sets HAVE_TYPE_RESOURCE_INDEX 1 or 0 always. If it is */
87 /* not set (e.g., a build without `configure'), the availability */
88 /* is guessed from the SDK version. */
89 #ifndef HAVE_TYPE_RESOURCE_INDEX
90 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
91 ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 )
92 #define HAVE_TYPE_RESOURCE_INDEX 0
94 #define HAVE_TYPE_RESOURCE_INDEX 1
96 #endif /* !HAVE_TYPE_RESOURCE_INDEX */
98 #if ( HAVE_TYPE_RESOURCE_INDEX == 0 )
99 typedef short ResourceIndex;
102 #include <CoreServices/CoreServices.h>
103 #include <ApplicationServices/ApplicationServices.h>
104 #include <sys/syslimits.h> /* PATH_MAX */
106 /* Don't want warnings about our own use of deprecated functions. */
107 #define FT_DEPRECATED_ATTRIBUTE
109 #include <freetype/ftmac.h>
111 #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */
112 #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault
116 /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
117 TrueType in case *both* are available (this is not common,
118 but it *is* possible). */
120 #define PREFER_LWFN 1
124 /* This function is deprecated because FSSpec is deprecated in Mac OS X */
125 FT_EXPORT_DEF( FT_Error )
126 FT_GetFile_From_Mac_Name( const char* fontName,
128 FT_Long* face_index )
130 FT_UNUSED( fontName );
131 FT_UNUSED( pathSpec );
132 FT_UNUSED( face_index );
134 return FT_THROW( Unimplemented_Feature );
138 /* Private function. */
139 /* The FSSpec type has been discouraged for a long time, */
140 /* unfortunately an FSRef replacement API for */
141 /* ATSFontGetFileSpecification() is only available in */
142 /* Mac OS X 10.5 and later. */
144 FT_ATSFontGetFileReference( ATSFontRef ats_font_id,
145 FSRef* ats_font_ref )
147 #if defined( MAC_OS_X_VERSION_10_5 ) && \
148 ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
152 err = ATSFontGetFileReference( ats_font_id, ats_font_ref );
155 #elif __LP64__ /* No 64bit Carbon API on legacy platforms */
156 FT_UNUSED( ats_font_id );
157 FT_UNUSED( ats_font_ref );
161 #else /* 32bit Carbon API on legacy platforms */
166 err = ATSFontGetFileSpecification( ats_font_id, &spec );
168 err = FSpMakeFSRef( &spec, ats_font_ref );
176 FT_GetFileRef_From_Mac_ATS_Name( const char* fontName,
178 FT_Long* face_index )
180 CFStringRef cf_fontName;
181 ATSFontRef ats_font_id;
186 cf_fontName = CFStringCreateWithCString( NULL, fontName,
187 kCFStringEncodingMacRoman );
188 ats_font_id = ATSFontFindFromName( cf_fontName,
189 kATSOptionFlagsUnRestrictedScope );
190 CFRelease( cf_fontName );
192 if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL )
193 return FT_THROW( Unknown_File_Format );
195 if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) )
196 return FT_THROW( Unknown_File_Format );
198 /* face_index calculation by searching preceding fontIDs */
199 /* with same FSRef */
201 ATSFontRef id2 = ats_font_id - 1;
207 if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) )
209 if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) )
214 *face_index = ats_font_id - ( id2 + 1 );
221 FT_EXPORT_DEF( FT_Error )
222 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName,
225 FT_Long* face_index )
231 if ( !fontName || !face_index )
232 return FT_THROW( Invalid_Argument);
234 err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
238 if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) )
239 return FT_THROW( Unknown_File_Format );
245 /* This function is deprecated because FSSpec is deprecated in Mac OS X */
246 FT_EXPORT_DEF( FT_Error )
247 FT_GetFile_From_Mac_ATS_Name( const char* fontName,
249 FT_Long* face_index )
251 #if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \
252 ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) )
253 FT_UNUSED( fontName );
254 FT_UNUSED( pathSpec );
255 FT_UNUSED( face_index );
257 return FT_THROW( Unimplemented_Feature );
263 if ( !fontName || !face_index )
264 return FT_THROW( Invalid_Argument );
266 err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
270 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL,
272 return FT_THROW( Unknown_File_Format );
280 FT_FSPathMakeRes( const UInt8* pathname,
287 if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
288 return FT_THROW( Cannot_Open_Resource );
290 /* at present, no support for dfont format */
291 err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res );
295 /* fallback to original resource-fork font */
296 *res = FSOpenResFile( &ref, fsRdPerm );
303 /* Return the file type for given pathname */
305 get_file_type_from_path( const UInt8* pathname )
311 if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
314 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info,
318 return ( (FInfo *)( info.finderInfo ) )->fdType;
322 /* Given a PostScript font name, create the Macintosh LWFN file name. */
324 create_lwfn_name( char* ps_name,
325 Str255 lwfn_file_name )
327 int max = 5, count = 0;
328 FT_Byte* p = lwfn_file_name;
329 FT_Byte* q = (FT_Byte*)ps_name;
332 lwfn_file_name[0] = 0;
336 if ( ft_isupper( *q ) )
342 if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
354 count_faces_sfnt( char* fond_data )
356 /* The count is 1 greater than the value in the FOND. */
357 /* Isn't that cute? :-) */
359 return EndianS16_BtoN( *( (short*)( fond_data +
360 sizeof ( FamRec ) ) ) ) + 1;
365 count_faces_scalable( char* fond_data )
368 short i, face, face_all;
371 face_all = EndianS16_BtoN( *( (short *)( fond_data +
372 sizeof ( FamRec ) ) ) ) + 1;
373 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
376 for ( i = 0; i < face_all; i++ )
378 if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) )
385 /* Look inside the FOND data, answer whether there should be an SFNT
386 resource, and answer the name of a possible LWFN Type 1 file.
388 Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
389 to load a face OTHER than the first one in the FOND!
394 parse_fond( char* fond_data,
397 Str255 lwfn_file_name,
401 AsscEntry* base_assoc;
407 lwfn_file_name[0] = 0;
409 fond = (FamRec*)fond_data;
410 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
413 /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */
414 if ( 47 < face_index )
417 /* Let's do a little range checking before we get too excited here */
418 if ( face_index < count_faces_sfnt( fond_data ) )
420 assoc += face_index; /* add on the face_index! */
422 /* if the face at this index is not scalable,
423 fall back to the first one (old behavior) */
424 if ( EndianS16_BtoN( assoc->fontSize ) == 0 )
427 *sfnt_id = EndianS16_BtoN( assoc->fontID );
429 else if ( base_assoc->fontSize == 0 )
432 *sfnt_id = EndianS16_BtoN( base_assoc->fontID );
436 if ( EndianS32_BtoN( fond->ffStylOff ) )
438 unsigned char* p = (unsigned char*)fond_data;
440 unsigned short string_count;
442 unsigned char* names[64];
446 p += EndianS32_BtoN( fond->ffStylOff );
447 style = (StyleTable*)p;
448 p += sizeof ( StyleTable );
449 string_count = EndianS16_BtoN( *(short*)(p) );
450 string_count = FT_MIN( 64, string_count );
451 p += sizeof ( short );
453 for ( i = 0; i < string_count; i++ )
461 size_t ps_name_len = (size_t)names[0][0];
464 if ( ps_name_len != 0 )
466 ft_memcpy( ps_name, names[0] + 1, ps_name_len );
467 ps_name[ps_name_len] = 0;
469 if ( style->indexes[face_index] > 1 &&
470 style->indexes[face_index] <= string_count )
472 unsigned char* suffixes = names[style->indexes[face_index] - 1];
475 for ( i = 1; i <= suffixes[0]; i++ )
478 size_t j = suffixes[i] - 1;
481 if ( j < string_count && ( s = names[j] ) != NULL )
483 size_t s_len = (size_t)s[0];
486 if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
488 ft_memcpy( ps_name + ps_name_len, s + 1, s_len );
489 ps_name_len += s_len;
490 ps_name[ps_name_len] = 0;
497 create_lwfn_name( ps_name, lwfn_file_name );
503 lookup_lwfn_by_fond( const UInt8* path_fond,
504 ConstStr255Param base_lwfn,
512 /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */
513 /* We should not extract parent directory by string manipulation. */
515 if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) )
516 return FT_THROW( Invalid_Argument );
518 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
519 NULL, NULL, NULL, &par_ref ) )
520 return FT_THROW( Invalid_Argument );
522 if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) )
523 return FT_THROW( Invalid_Argument );
525 if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size )
526 return FT_THROW( Invalid_Argument );
528 /* now we have absolute dirname in path_lwfn */
529 ft_strcat( (char *)path_lwfn, "/" );
530 dirname_len = ft_strlen( (char *)path_lwfn );
531 ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 );
532 path_lwfn[dirname_len + base_lwfn[0]] = '\0';
534 if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) )
535 return FT_THROW( Cannot_Open_Resource );
537 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
538 NULL, NULL, NULL, NULL ) )
539 return FT_THROW( Cannot_Open_Resource );
546 count_faces( Handle fond,
547 const UInt8* pathname )
550 short have_sfnt, have_lwfn;
551 Str255 lwfn_file_name;
552 UInt8 buff[PATH_MAX];
557 have_sfnt = have_lwfn = 0;
559 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 );
561 if ( lwfn_file_name[0] )
563 err = lookup_lwfn_by_fond( pathname, lwfn_file_name,
564 buff, sizeof ( buff ) );
569 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
572 num_faces = count_faces_scalable( *fond );
578 /* Read Type 1 data from the POST resources inside the LWFN file,
579 return a PFB buffer. This is somewhat convoluted because the FT2
580 PFB parser wants the ASCII header as one chunk, and the LWFN
581 chunks are often not organized that way, so we glue chunks
582 of the same type together. */
584 read_lwfn( FT_Memory memory,
589 FT_Error error = FT_Err_Ok;
591 unsigned char *buffer, *p, *size_p = NULL;
592 FT_ULong total_size = 0;
593 FT_ULong old_total_size = 0;
594 FT_ULong post_size, pfb_chunk_size;
596 char code, last_code;
601 /* First pass: load all POST resources, and determine the size of */
602 /* the output buffer. */
608 post_data = Get1Resource( TTAG_POST, res_id++ );
610 break; /* we are done */
612 code = (*post_data)[0];
614 if ( code != last_code )
617 total_size += 2; /* just the end code */
619 total_size += 6; /* code + 4 bytes chunk length */
622 total_size += (FT_ULong)GetHandleSize( post_data ) - 2;
625 /* detect resource fork overflow */
626 if ( FT_MAC_RFORK_MAX_LEN < total_size )
628 error = FT_THROW( Array_Too_Large );
632 old_total_size = total_size;
635 if ( FT_QALLOC( buffer, (FT_Long)total_size ) )
638 /* Second pass: append all POST data to the buffer, add PFB fields. */
639 /* Glue all consecutive chunks of the same type together. */
647 post_data = Get1Resource( TTAG_POST, res_id++ );
649 break; /* we are done */
651 post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
652 code = (*post_data)[0];
654 if ( code != last_code )
656 if ( last_code != -1 )
658 /* we are done adding a chunk, fill in the size field */
661 *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF );
662 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF );
663 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
664 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
671 *p++ = 0x03; /* the end */
672 else if ( code == 2 )
673 *p++ = 0x02; /* binary segment */
675 *p++ = 0x01; /* ASCII segment */
679 size_p = p; /* save for later */
680 p += 4; /* make space for size field */
684 ft_memcpy( p, *post_data + 2, post_size );
685 pfb_chunk_size += post_size;
699 /* Create a new FT_Face from a file path to an LWFN file. */
701 FT_New_Face_From_LWFN( FT_Library library,
702 const UInt8* pathname,
712 if ( noErr != FT_FSPathMakeRes( pathname, &res ) )
713 return FT_THROW( Cannot_Open_Resource );
717 error = read_lwfn( library->memory, res, &pfb_data, &pfb_size );
718 CloseResFile( res ); /* PFB is already loaded, useless anymore */
722 return open_face_from_buffer( library,
731 /* Create a new FT_Face from an SFNT resource, specified by res ID. */
733 FT_New_Face_From_SFNT( FT_Library library,
741 FT_Error error = FT_Err_Ok;
742 FT_Memory memory = library->memory;
743 int is_cff, is_sfnt_ps;
746 sfnt = GetResource( TTAG_sfnt, sfnt_id );
748 return FT_THROW( Invalid_Handle );
750 sfnt_size = (FT_ULong)GetHandleSize( sfnt );
752 /* detect resource fork overflow */
753 if ( FT_MAC_RFORK_MAX_LEN < sfnt_size )
754 return FT_THROW( Array_Too_Large );
756 if ( FT_QALLOC( sfnt_data, (FT_Long)sfnt_size ) )
758 ReleaseResource( sfnt );
762 ft_memcpy( sfnt_data, *sfnt, sfnt_size );
763 ReleaseResource( sfnt );
765 is_cff = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
766 is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 );
773 if ( FT_NEW( stream ) )
776 FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size );
777 if ( !open_face_PS_from_sfnt_stream( library,
783 FT_Stream_Close( stream );
785 FT_FREE( sfnt_data );
792 error = open_face_from_buffer( library,
796 is_cff ? "cff" : "truetype",
803 /* Create a new FT_Face from a file path to a suitcase file. */
805 FT_New_Face_From_Suitcase( FT_Library library,
806 const UInt8* pathname,
810 FT_Error error = FT_ERR( Cannot_Open_Resource );
811 ResFileRefNum res_ref;
812 ResourceIndex res_index;
814 short num_faces_in_res;
817 if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) )
818 return FT_THROW( Cannot_Open_Resource );
820 UseResFile( res_ref );
822 return FT_THROW( Cannot_Open_Resource );
824 num_faces_in_res = 0;
825 for ( res_index = 1; ; res_index++ )
827 short num_faces_in_fond;
830 fond = Get1IndResource( TTAG_FOND, res_index );
834 num_faces_in_fond = count_faces( fond, pathname );
835 num_faces_in_res += num_faces_in_fond;
837 if ( 0 <= face_index && face_index < num_faces_in_fond && error )
838 error = FT_New_Face_From_FOND( library, fond, face_index, aface );
840 face_index -= num_faces_in_fond;
843 CloseResFile( res_ref );
844 if ( !error && aface && *aface )
845 (*aface)->num_faces = num_faces_in_res;
850 /* documentation is in ftmac.h */
852 FT_EXPORT_DEF( FT_Error )
853 FT_New_Face_From_FOND( FT_Library library,
858 short have_sfnt, have_lwfn = 0;
859 ResID sfnt_id, fond_id;
862 Str255 lwfn_file_name;
863 UInt8 path_lwfn[PATH_MAX];
865 FT_Error error = FT_Err_Ok;
868 /* check of `library' and `aface' delayed to `FT_New_Face_From_XXX' */
870 GetResInfo( fond, &fond_id, &fond_type, fond_name );
871 if ( ResError() != noErr || fond_type != TTAG_FOND )
872 return FT_THROW( Invalid_File_Format );
874 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
876 if ( lwfn_file_name[0] )
881 res = HomeResFile( fond );
882 if ( noErr != ResError() )
883 goto found_no_lwfn_file;
886 UInt8 path_fond[PATH_MAX];
890 err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum,
891 NULL, NULL, NULL, &ref, NULL );
893 goto found_no_lwfn_file;
895 err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) );
897 goto found_no_lwfn_file;
899 error = lookup_lwfn_by_fond( path_fond, lwfn_file_name,
900 path_lwfn, sizeof ( path_lwfn ) );
906 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
907 error = FT_New_Face_From_LWFN( library,
912 error = FT_THROW( Unknown_File_Format );
915 if ( have_sfnt && error )
916 error = FT_New_Face_From_SFNT( library,
925 /* Common function to load a new FT_Face from a resource file. */
927 FT_New_Face_From_Resource( FT_Library library,
928 const UInt8* pathname,
936 /* LWFN is a (very) specific file format, check for it explicitly */
937 file_type = get_file_type_from_path( pathname );
938 if ( file_type == TTAG_LWFN )
939 return FT_New_Face_From_LWFN( library, pathname, face_index, aface );
941 /* Otherwise the file type doesn't matter (there are more than */
942 /* `FFIL' and `tfil'). Just try opening it as a font suitcase; */
943 /* if it works, fine. */
945 error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface );
948 /* let it fall through to normal loader (.ttf, .otf, etc.); */
949 /* we signal this by returning no error and no FT_Face */
957 /**************************************************************************
963 * This is the Mac-specific implementation of FT_New_Face. In
964 * addition to the standard FT_New_Face() functionality, it also
965 * accepts pathnames to Mac suitcase files. For further
966 * documentation see the original FT_New_Face() in freetype.h.
968 FT_EXPORT_DEF( FT_Error )
969 FT_New_Face( FT_Library library,
970 const char* pathname,
978 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
980 return FT_THROW( Invalid_Argument );
984 /* try resourcefork based font: LWFN, FFIL */
985 error = FT_New_Face_From_Resource( library, (UInt8 *)pathname,
987 if ( error || *aface )
990 /* let it fall through to normal loader (.ttf, .otf, etc.) */
991 args.flags = FT_OPEN_PATHNAME;
992 args.pathname = (char*)pathname;
994 return FT_Open_Face( library, &args, face_index, aface );
998 /**************************************************************************
1001 * FT_New_Face_From_FSRef
1004 * FT_New_Face_From_FSRef is identical to FT_New_Face except it
1005 * accepts an FSRef instead of a path.
1007 * This function is deprecated because Carbon data types (FSRef)
1008 * are not cross-platform, and thus not suitable for the FreeType API.
1010 FT_EXPORT_DEF( FT_Error )
1011 FT_New_Face_From_FSRef( FT_Library library,
1020 UInt8 pathname[PATH_MAX];
1023 /* check of `library' and `aface' delayed to */
1024 /* `FT_New_Face_From_Resource' */
1027 return FT_THROW( Invalid_Argument );
1029 err = FSRefMakePath( ref, pathname, sizeof ( pathname ) );
1031 error = FT_THROW( Cannot_Open_Resource );
1033 error = FT_New_Face_From_Resource( library, pathname, face_index, aface );
1034 if ( error || *aface )
1037 /* fallback to datafork font */
1038 args.flags = FT_OPEN_PATHNAME;
1039 args.pathname = (char*)pathname;
1040 return FT_Open_Face( library, &args, face_index, aface );
1044 /**************************************************************************
1047 * FT_New_Face_From_FSSpec
1050 * FT_New_Face_From_FSSpec is identical to FT_New_Face except it
1051 * accepts an FSSpec instead of a path.
1053 * This function is deprecated because FSSpec is deprecated in Mac OS X
1055 FT_EXPORT_DEF( FT_Error )
1056 FT_New_Face_From_FSSpec( FT_Library library,
1061 #if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \
1062 ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) )
1063 FT_UNUSED( library );
1065 FT_UNUSED( face_index );
1068 return FT_THROW( Unimplemented_Feature );
1073 /* check of `library' and `aface' delayed to `FT_New_Face_From_FSRef' */
1075 if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr )
1076 return FT_THROW( Invalid_Argument );
1078 return FT_New_Face_From_FSRef( library, &ref, face_index, aface );
1082 #else /* !FT_MACINTOSH */
1084 /* ANSI C doesn't like empty source files */
1085 typedef int ft_mac_dummy_;
1087 #endif /* !FT_MACINTOSH */