1 /***************************************************************************/
5 /* Mac FOND support. Written by just@letterror.com. */
6 /* Heavily Fixed by mpsuzuki, George Williams and Sean McBride */
8 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by */
9 /* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
17 /***************************************************************************/
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.
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.
33 The Mac FOND support works roughly like this:
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.
41 - Read the FOND resource into memory, then check whether there is a
42 TrueType font and/or(!) a Type 1 font available.
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...)
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().
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
66 #include FT_FREETYPE_H
67 #include FT_INTERNAL_STREAM_H
69 #if defined( __GNUC__ ) || defined( __IBMC__ )
70 /* This is for Mac OS X. Without redefinition, OS_INLINE */
71 /* expands to `static inline' which doesn't survive the */
72 /* -ansi compilation flag of GCC. */
73 #if !HAVE_ANSI_OS_INLINE
75 #define OS_INLINE static __inline__
77 #include <CoreServices/CoreServices.h>
78 #include <ApplicationServices/ApplicationServices.h>
79 #include <sys/syslimits.h> /* PATH_MAX */
81 #include <Resources.h>
86 #include <TextUtils.h>
90 #define PATH_MAX 1024 /* same with Mac OS X's syslimits.h */
93 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
94 #include <FSp_fopen.h>
97 #define FT_DEPRECATED_ATTRIBUTE
101 /* undefine blocking-macros in ftmac.h */
102 #undef FT_GetFile_From_Mac_Name
103 #undef FT_GetFile_From_Mac_ATS_Name
104 #undef FT_New_Face_From_FOND
105 #undef FT_New_Face_From_FSSpec
106 #undef FT_New_Face_From_FSRef
109 /* FSSpec functions are deprecated since Mac OS X 10.4 */
111 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
112 #define HAVE_FSSPEC 1
114 #define HAVE_FSSPEC 0
118 /* most FSRef functions were introduced since Mac OS 9 */
120 #if TARGET_API_MAC_OSX
127 /* QuickDraw is deprecated since Mac OS X 10.4 */
128 #ifndef HAVE_QUICKDRAW_CARBON
129 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
130 #define HAVE_QUICKDRAW_CARBON 1
132 #define HAVE_QUICKDRAW_CARBON 0
136 /* AppleTypeService is available since Mac OS X */
138 #if TARGET_API_MAC_OSX
140 #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */
141 #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault
148 /* Some portable types are unavailable on legacy SDKs */
149 #ifndef MAC_OS_X_VERSION_10_5
150 typedef short ResourceIndex
;
153 /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
154 TrueType in case *both* are available (this is not common,
155 but it *is* possible). */
157 #define PREFER_LWFN 1
161 #if !HAVE_QUICKDRAW_CARBON /* QuickDraw is deprecated since Mac OS X 10.4 */
163 FT_EXPORT_DEF( FT_Error
)
164 FT_GetFile_From_Mac_Name( const char* fontName
,
166 FT_Long
* face_index
)
168 FT_UNUSED( fontName
);
169 FT_UNUSED( pathSpec
);
170 FT_UNUSED( face_index
);
172 return FT_Err_Unimplemented_Feature
;
177 FT_EXPORT_DEF( FT_Error
)
178 FT_GetFile_From_Mac_Name( const char* fontName
,
180 FT_Long
* face_index
)
182 OptionBits options
= kFMUseGlobalScopeOption
;
184 FMFontFamilyIterator famIter
;
185 OSStatus status
= FMCreateFontFamilyIterator( NULL
, NULL
,
189 FMFontFamily family
= 0;
193 while ( status
== 0 && !the_font
)
195 status
= FMGetNextFontFamily( &famIter
, &family
);
199 FMFontFamilyInstanceIterator instIter
;
204 /* get the family name */
205 FMGetFontFamilyName( family
, famNameStr
);
206 CopyPascalStringToC( famNameStr
, famName
);
208 /* iterate through the styles */
209 FMCreateFontFamilyInstanceIterator( family
, &instIter
);
214 while ( stat2
== 0 && !the_font
)
221 stat2
= FMGetNextFontFamilyInstance( &instIter
, &font
,
223 if ( stat2
== 0 && size
== 0 )
228 /* build up a complete face name */
229 ft_strcpy( fullName
, famName
);
231 ft_strcat( fullName
, " Bold" );
232 if ( style
& italic
)
233 ft_strcat( fullName
, " Italic" );
235 /* compare with the name we are looking for */
236 if ( ft_strcmp( fullName
, fontName
) == 0 )
246 FMDisposeFontFamilyInstanceIterator( &instIter
);
250 FMDisposeFontFamilyIterator( &famIter
);
254 FMGetFontContainer( the_font
, pathSpec
);
258 return FT_Err_Unknown_File_Format
;
261 #endif /* HAVE_QUICKDRAW_CARBON */
266 /* Private function. */
267 /* The FSSpec type has been discouraged for a long time, */
268 /* unfortunately an FSRef replacement API for */
269 /* ATSFontGetFileSpecification() is only available in */
270 /* Mac OS X 10.5 and later. */
272 FT_ATSFontGetFileReference( ATSFontRef ats_font_id
,
273 FSRef
* ats_font_ref
)
277 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
278 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
282 err
= ATSFontGetFileSpecification( ats_font_id
, &spec
);
284 err
= FSpMakeFSRef( &spec
, ats_font_ref
);
286 err
= ATSFontGetFileReference( ats_font_id
, ats_font_ref
);
294 FT_GetFileRef_From_Mac_ATS_Name( const char* fontName
,
296 FT_Long
* face_index
)
298 CFStringRef cf_fontName
;
299 ATSFontRef ats_font_id
;
304 cf_fontName
= CFStringCreateWithCString( NULL
, fontName
,
305 kCFStringEncodingMacRoman
);
306 ats_font_id
= ATSFontFindFromName( cf_fontName
,
307 kATSOptionFlagsUnRestrictedScope
);
308 CFRelease( cf_fontName
);
310 if ( ats_font_id
== 0 || ats_font_id
== 0xFFFFFFFFUL
)
311 return FT_Err_Unknown_File_Format
;
313 if ( noErr
!= FT_ATSFontGetFileReference( ats_font_id
, ats_font_ref
) )
314 return FT_Err_Unknown_File_Format
;
316 /* face_index calculation by searching preceding fontIDs */
317 /* with same FSRef */
319 ATSFontRef id2
= ats_font_id
- 1;
325 if ( noErr
!= FT_ATSFontGetFileReference( id2
, &ref2
) )
327 if ( noErr
!= FSCompareFSRefs( ats_font_ref
, &ref2
) )
332 *face_index
= ats_font_id
- ( id2
+ 1 );
342 FT_EXPORT_DEF( FT_Error
)
343 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName
,
346 FT_Long
* face_index
)
348 FT_UNUSED( fontName
);
350 FT_UNUSED( maxPathSize
);
351 FT_UNUSED( face_index
);
353 return FT_Err_Unimplemented_Feature
;
358 FT_EXPORT_DEF( FT_Error
)
359 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName
,
362 FT_Long
* face_index
)
368 err
= FT_GetFileRef_From_Mac_ATS_Name( fontName
, &ref
, face_index
);
369 if ( FT_Err_Ok
!= err
)
372 if ( noErr
!= FSRefMakePath( &ref
, path
, maxPathSize
) )
373 return FT_Err_Unknown_File_Format
;
378 #endif /* HAVE_ATS */
381 #if !HAVE_FSSPEC || !HAVE_ATS
383 FT_EXPORT_DEF( FT_Error
)
384 FT_GetFile_From_Mac_ATS_Name( const char* fontName
,
386 FT_Long
* face_index
)
388 FT_UNUSED( fontName
);
389 FT_UNUSED( pathSpec
);
390 FT_UNUSED( face_index
);
392 return FT_Err_Unimplemented_Feature
;
397 /* This function is deprecated because FSSpec is deprecated in Mac OS X. */
398 FT_EXPORT_DEF( FT_Error
)
399 FT_GetFile_From_Mac_ATS_Name( const char* fontName
,
401 FT_Long
* face_index
)
407 err
= FT_GetFileRef_From_Mac_ATS_Name( fontName
, &ref
, face_index
);
408 if ( FT_Err_Ok
!= err
)
411 if ( noErr
!= FSGetCatalogInfo( &ref
, kFSCatInfoNone
, NULL
, NULL
,
413 return FT_Err_Unknown_File_Format
;
421 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
423 #define STREAM_FILE( stream ) ( (FT_FILE*)stream->descriptor.pointer )
426 FT_CALLBACK_DEF( void )
427 ft_FSp_stream_close( FT_Stream stream
)
429 ft_fclose( STREAM_FILE( stream
) );
431 stream
->descriptor
.pointer
= NULL
;
437 FT_CALLBACK_DEF( unsigned long )
438 ft_FSp_stream_io( FT_Stream stream
,
439 unsigned long offset
,
440 unsigned char* buffer
,
441 unsigned long count
)
446 file
= STREAM_FILE( stream
);
448 ft_fseek( file
, offset
, SEEK_SET
);
450 return (unsigned long)ft_fread( buffer
, 1, count
, file
);
453 #endif /* __MWERKS__ && !TARGET_RT_MAC_MACHO */
456 #if HAVE_FSSPEC && !HAVE_FSREF
458 /* isDirectory is a dummy to synchronize API with FSPathMakeRef() */
460 FT_FSPathMakeSpec( const UInt8
* pathname
,
462 Boolean isDirectory
)
469 FT_UNUSED( isDirectory
);
472 p
= q
= (const char *)pathname
;
478 int len
= ft_strlen( p
);
489 if ( 255 < ft_strlen( (char *)pathname
) )
491 while ( p
< q
&& *q
!= ':' )
496 *(char *)nodeName
= q
- p
;
497 else if ( ft_strlen( p
) < 256 )
498 *(char *)nodeName
= ft_strlen( p
);
500 return errFSNameTooLong
;
502 ft_strncpy( (char *)nodeName
+ 1, (char *)p
, *(char *)nodeName
);
503 err
= FSMakeFSSpec( vRefNum
, dirID
, nodeName
, spec_p
);
504 if ( err
|| '\0' == *q
)
507 vRefNum
= spec_p
->vRefNum
;
508 dirID
= spec_p
->parID
;
516 FT_FSpMakePath( const FSSpec
* spec_p
,
521 FSSpec spec
= *spec_p
;
527 FT_MEM_SET( path
, 0, maxPathSize
);
530 int child_namelen
= ft_strlen( (char *)path
);
531 unsigned char node_namelen
= spec
.name
[0];
532 unsigned char* node_name
= spec
.name
+ 1;
535 if ( node_namelen
+ child_namelen
> maxPathSize
)
536 return errFSNameTooLong
;
538 FT_MEM_MOVE( path
+ node_namelen
+ 1, path
, child_namelen
);
539 FT_MEM_COPY( path
, node_name
, node_namelen
);
540 if ( child_namelen
> 0 )
541 path
[node_namelen
] = ':';
543 vRefNum
= spec
.vRefNum
;
545 parDir_name
[0] = '\0';
546 err
= FSMakeFSSpec( vRefNum
, dirID
, parDir_name
, &spec
);
547 if ( noErr
!= err
|| dirID
== spec
.parID
)
553 #endif /* HAVE_FSSPEC && !HAVE_FSREF */
557 FT_FSPathMakeRes( const UInt8
* pathname
,
567 if ( noErr
!= FSPathMakeRef( pathname
, &ref
, FALSE
) )
568 return FT_Err_Cannot_Open_Resource
;
570 /* at present, no support for dfont format */
571 err
= FSOpenResourceFile( &ref
, 0, NULL
, fsRdPerm
, res
);
575 /* fallback to original resource-fork font */
576 *res
= FSOpenResFile( &ref
, fsRdPerm
);
585 if ( noErr
!= FT_FSPathMakeSpec( pathname
, &spec
, FALSE
) )
586 return FT_Err_Cannot_Open_Resource
;
588 /* at present, no support for dfont format without FSRef */
589 /* (see above), try original resource-fork font */
590 *res
= FSpOpenResFile( &spec
, fsRdPerm
);
593 #endif /* HAVE_FSREF */
599 /* Return the file type for given pathname */
601 get_file_type_from_path( const UInt8
* pathname
)
610 if ( noErr
!= FSPathMakeRef( pathname
, &ref
, FALSE
) )
613 if ( noErr
!= FSGetCatalogInfo( &ref
, kFSCatInfoFinderInfo
, &info
,
617 return ((FInfo
*)(info
.finderInfo
))->fdType
;
625 if ( noErr
!= FT_FSPathMakeSpec( pathname
, &spec
, FALSE
) )
628 if ( noErr
!= FSpGetFInfo( &spec
, &finfo
) )
633 #endif /* HAVE_FSREF */
638 /* Given a PostScript font name, create the Macintosh LWFN file name. */
640 create_lwfn_name( char* ps_name
,
641 Str255 lwfn_file_name
)
643 int max
= 5, count
= 0;
644 FT_Byte
* p
= lwfn_file_name
;
645 FT_Byte
* q
= (FT_Byte
*)ps_name
;
648 lwfn_file_name
[0] = 0;
652 if ( ft_isupper( *q
) )
658 if ( count
< max
&& ( ft_isalnum( *q
) || *q
== '_' ) )
670 count_faces_sfnt( char* fond_data
)
672 /* The count is 1 greater than the value in the FOND. */
673 /* Isn't that cute? :-) */
675 return EndianS16_BtoN( *( (short*)( fond_data
+
676 sizeof ( FamRec
) ) ) ) + 1;
681 count_faces_scalable( char* fond_data
)
685 short i
, face
, face_all
;
688 fond
= (FamRec
*)fond_data
;
689 face_all
= EndianS16_BtoN( *( (short *)( fond_data
+
690 sizeof ( FamRec
) ) ) ) + 1;
691 assoc
= (AsscEntry
*)( fond_data
+ sizeof ( FamRec
) + 2 );
694 for ( i
= 0; i
< face_all
; i
++ )
696 if ( 0 == EndianS16_BtoN( assoc
[i
].fontSize
) )
703 /* Look inside the FOND data, answer whether there should be an SFNT
704 resource, and answer the name of a possible LWFN Type 1 file.
706 Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
707 to load a face OTHER than the first one in the FOND!
711 parse_fond( char* fond_data
,
714 Str255 lwfn_file_name
,
718 AsscEntry
* base_assoc
;
724 lwfn_file_name
[0] = 0;
726 fond
= (FamRec
*)fond_data
;
727 assoc
= (AsscEntry
*)( fond_data
+ sizeof ( FamRec
) + 2 );
730 /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */
731 if ( 47 < face_index
)
734 /* Let's do a little range checking before we get too excited here */
735 if ( face_index
< count_faces_sfnt( fond_data
) )
737 assoc
+= face_index
; /* add on the face_index! */
739 /* if the face at this index is not scalable,
740 fall back to the first one (old behavior) */
741 if ( EndianS16_BtoN( assoc
->fontSize
) == 0 )
744 *sfnt_id
= EndianS16_BtoN( assoc
->fontID
);
746 else if ( base_assoc
->fontSize
== 0 )
749 *sfnt_id
= EndianS16_BtoN( base_assoc
->fontID
);
753 if ( EndianS32_BtoN( fond
->ffStylOff
) )
755 unsigned char* p
= (unsigned char*)fond_data
;
757 unsigned short string_count
;
759 unsigned char* names
[64];
763 p
+= EndianS32_BtoN( fond
->ffStylOff
);
764 style
= (StyleTable
*)p
;
765 p
+= sizeof ( StyleTable
);
766 string_count
= EndianS16_BtoN( *(short*)(p
) );
767 p
+= sizeof ( short );
769 for ( i
= 0; i
< string_count
&& i
< 64; i
++ )
777 size_t ps_name_len
= (size_t)names
[0][0];
780 if ( ps_name_len
!= 0 )
782 ft_memcpy(ps_name
, names
[0] + 1, ps_name_len
);
783 ps_name
[ps_name_len
] = 0;
785 if ( style
->indexes
[face_index
] > 1 &&
786 style
->indexes
[face_index
] <= FT_MIN( string_count
, 64 ) )
788 unsigned char* suffixes
= names
[style
->indexes
[face_index
] - 1];
791 for ( i
= 1; i
<= suffixes
[0]; i
++ )
794 size_t j
= suffixes
[i
] - 1;
797 if ( j
< string_count
&& ( s
= names
[j
] ) != NULL
)
799 size_t s_len
= (size_t)s
[0];
802 if ( s_len
!= 0 && ps_name_len
+ s_len
< sizeof ( ps_name
) )
804 ft_memcpy( ps_name
+ ps_name_len
, s
+ 1, s_len
);
805 ps_name_len
+= s_len
;
806 ps_name
[ps_name_len
] = 0;
813 create_lwfn_name( ps_name
, lwfn_file_name
);
819 lookup_lwfn_by_fond( const UInt8
* path_fond
,
820 ConstStr255Param base_lwfn
,
831 /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */
832 /* We should not extract parent directory by string manipulation. */
834 if ( noErr
!= FSPathMakeRef( path_fond
, &ref
, FALSE
) )
835 return FT_Err_Invalid_Argument
;
837 if ( noErr
!= FSGetCatalogInfo( &ref
, kFSCatInfoNone
,
838 NULL
, NULL
, NULL
, &par_ref
) )
839 return FT_Err_Invalid_Argument
;
841 if ( noErr
!= FSRefMakePath( &par_ref
, path_lwfn
, path_size
) )
842 return FT_Err_Invalid_Argument
;
844 if ( ft_strlen( (char *)path_lwfn
) + 1 + base_lwfn
[0] > path_size
)
845 return FT_Err_Invalid_Argument
;
847 /* now we have absolute dirname in path_lwfn */
848 if ( path_lwfn
[0] == '/' )
849 ft_strcat( (char *)path_lwfn
, "/" );
851 ft_strcat( (char *)path_lwfn
, ":" );
853 dirname_len
= ft_strlen( (char *)path_lwfn
);
854 ft_strcat( (char *)path_lwfn
, (char *)base_lwfn
+ 1 );
855 path_lwfn
[dirname_len
+ base_lwfn
[0]] = '\0';
857 if ( noErr
!= FSPathMakeRef( path_lwfn
, &ref
, FALSE
) )
858 return FT_Err_Cannot_Open_Resource
;
860 if ( noErr
!= FSGetCatalogInfo( &ref
, kFSCatInfoNone
,
861 NULL
, NULL
, NULL
, NULL
) )
862 return FT_Err_Cannot_Open_Resource
;
872 /* pathname for FSSpec is always HFS format */
873 if ( ft_strlen( (char *)path_fond
) > path_size
)
874 return FT_Err_Invalid_Argument
;
876 ft_strcpy( (char *)path_lwfn
, (char *)path_fond
);
878 i
= ft_strlen( (char *)path_lwfn
) - 1;
879 while ( i
> 0 && ':' != path_lwfn
[i
] )
882 if ( i
+ 1 + base_lwfn
[0] > path_size
)
883 return FT_Err_Invalid_Argument
;
885 if ( ':' == path_lwfn
[i
] )
887 ft_strcpy( (char *)path_lwfn
+ i
+ 1, (char *)base_lwfn
+ 1 );
888 path_lwfn
[i
+ 1 + base_lwfn
[0]] = '\0';
892 ft_strcpy( (char *)path_lwfn
, (char *)base_lwfn
+ 1 );
893 path_lwfn
[base_lwfn
[0]] = '\0';
896 if ( noErr
!= FT_FSPathMakeSpec( path_lwfn
, &spec
, FALSE
) )
897 return FT_Err_Cannot_Open_Resource
;
901 #endif /* HAVE_FSREF */
907 count_faces( Handle fond
,
908 const UInt8
* pathname
)
911 short have_sfnt
, have_lwfn
;
912 Str255 lwfn_file_name
;
913 UInt8 buff
[PATH_MAX
];
918 have_sfnt
= have_lwfn
= 0;
921 parse_fond( *fond
, &have_sfnt
, &sfnt_id
, lwfn_file_name
, 0 );
923 if ( lwfn_file_name
[0] )
925 err
= lookup_lwfn_by_fond( pathname
, lwfn_file_name
,
926 buff
, sizeof ( buff
) );
927 if ( FT_Err_Ok
== err
)
931 if ( have_lwfn
&& ( !have_sfnt
|| PREFER_LWFN
) )
934 num_faces
= count_faces_scalable( *fond
);
941 /* Read Type 1 data from the POST resources inside the LWFN file,
942 return a PFB buffer. This is somewhat convoluted because the FT2
943 PFB parser wants the ASCII header as one chunk, and the LWFN
944 chunks are often not organized that way, so we glue chunks
945 of the same type together. */
947 read_lwfn( FT_Memory memory
,
952 FT_Error error
= FT_Err_Ok
;
954 unsigned char *buffer
, *p
, *size_p
= NULL
;
955 FT_ULong total_size
= 0;
956 FT_ULong old_total_size
= 0;
957 FT_ULong post_size
, pfb_chunk_size
;
959 char code
, last_code
;
964 /* First pass: load all POST resources, and determine the size of */
965 /* the output buffer. */
971 post_data
= Get1Resource( FT_MAKE_TAG( 'P', 'O', 'S', 'T' ),
973 if ( post_data
== NULL
)
974 break; /* we are done */
976 code
= (*post_data
)[0];
978 if ( code
!= last_code
)
981 total_size
+= 2; /* just the end code */
983 total_size
+= 6; /* code + 4 bytes chunk length */
986 total_size
+= GetHandleSize( post_data
) - 2;
989 /* detect integer overflows */
990 if ( total_size
< old_total_size
)
992 error
= FT_Err_Array_Too_Large
;
996 old_total_size
= total_size
;
999 if ( FT_ALLOC( buffer
, (FT_Long
)total_size
) )
1002 /* Second pass: append all POST data to the buffer, add PFB fields. */
1003 /* Glue all consecutive chunks of the same type together. */
1011 post_data
= Get1Resource( FT_MAKE_TAG( 'P', 'O', 'S', 'T' ),
1013 if ( post_data
== NULL
)
1014 break; /* we are done */
1016 post_size
= (FT_ULong
)GetHandleSize( post_data
) - 2;
1017 code
= (*post_data
)[0];
1019 if ( code
!= last_code
)
1021 if ( last_code
!= -1 )
1023 /* we are done adding a chunk, fill in the size field */
1024 if ( size_p
!= NULL
)
1026 *size_p
++ = (FT_Byte
)( pfb_chunk_size
& 0xFF );
1027 *size_p
++ = (FT_Byte
)( ( pfb_chunk_size
>> 8 ) & 0xFF );
1028 *size_p
++ = (FT_Byte
)( ( pfb_chunk_size
>> 16 ) & 0xFF );
1029 *size_p
++ = (FT_Byte
)( ( pfb_chunk_size
>> 24 ) & 0xFF );
1036 *p
++ = 0x03; /* the end */
1037 else if ( code
== 2 )
1038 *p
++ = 0x02; /* binary segment */
1040 *p
++ = 0x01; /* ASCII segment */
1044 size_p
= p
; /* save for later */
1045 p
+= 4; /* make space for size field */
1049 ft_memcpy( p
, *post_data
+ 2, post_size
);
1050 pfb_chunk_size
+= post_size
;
1059 CloseResFile( res
);
1064 /* Finalizer for a memory stream; gets called by FT_Done_Face().
1065 It frees the memory it uses. */
1067 memory_stream_close( FT_Stream stream
)
1069 FT_Memory memory
= stream
->memory
;
1072 FT_FREE( stream
->base
);
1080 /* Create a new memory stream from a buffer and a size. */
1082 new_memory_stream( FT_Library library
,
1085 FT_Stream_CloseFunc close
,
1086 FT_Stream
* astream
)
1094 return FT_Err_Invalid_Library_Handle
;
1097 return FT_Err_Invalid_Argument
;
1100 memory
= library
->memory
;
1101 if ( FT_NEW( stream
) )
1104 FT_Stream_OpenMemory( stream
, base
, size
);
1106 stream
->close
= close
;
1115 /* Create a new FT_Face given a buffer and a driver name. */
1117 open_face_from_buffer( FT_Library library
,
1127 FT_Memory memory
= library
->memory
;
1130 error
= new_memory_stream( library
,
1133 memory_stream_close
,
1141 args
.flags
= FT_OPEN_STREAM
;
1142 args
.stream
= stream
;
1145 args
.flags
= args
.flags
| FT_OPEN_DRIVER
;
1146 args
.driver
= FT_Get_Module( library
, driver_name
);
1149 /* At this point, face_index has served its purpose; */
1150 /* whoever calls this function has already used it to */
1151 /* locate the correct font data. We should not propagate */
1152 /* this index to FT_Open_Face() (unless it is negative). */
1154 if ( face_index
> 0 )
1157 error
= FT_Open_Face( library
, &args
, face_index
, aface
);
1158 if ( error
== FT_Err_Ok
)
1159 (*aface
)->face_flags
&= ~FT_FACE_FLAG_EXTERNAL_STREAM
;
1161 FT_Stream_Free( stream
, 0 );
1167 /* Create a new FT_Face from a file spec to an LWFN file. */
1169 FT_New_Face_From_LWFN( FT_Library library
,
1170 const UInt8
* pathname
,
1180 if ( noErr
!= FT_FSPathMakeRes( pathname
, &res
) )
1181 return FT_Err_Cannot_Open_Resource
;
1185 error
= read_lwfn( library
->memory
, res
, &pfb_data
, &pfb_size
);
1186 CloseResFile( res
); /* PFB is already loaded, useless anymore */
1190 return open_face_from_buffer( library
,
1199 /* Create a new FT_Face from an SFNT resource, specified by res ID. */
1201 FT_New_Face_From_SFNT( FT_Library library
,
1209 FT_Error error
= FT_Err_Ok
;
1210 FT_Memory memory
= library
->memory
;
1214 sfnt
= GetResource( FT_MAKE_TAG( 's', 'f', 'n', 't' ), sfnt_id
);
1216 return FT_Err_Invalid_Handle
;
1218 sfnt_size
= (FT_ULong
)GetHandleSize( sfnt
);
1219 if ( FT_ALLOC( sfnt_data
, (FT_Long
)sfnt_size
) )
1221 ReleaseResource( sfnt
);
1226 ft_memcpy( sfnt_data
, *sfnt
, sfnt_size
);
1228 ReleaseResource( sfnt
);
1230 is_cff
= sfnt_size
> 4 && sfnt_data
[0] == 'O' &&
1231 sfnt_data
[1] == 'T' &&
1232 sfnt_data
[2] == 'T' &&
1233 sfnt_data
[3] == 'O';
1235 return open_face_from_buffer( library
,
1239 is_cff
? "cff" : "truetype",
1244 /* Create a new FT_Face from a file spec to a suitcase file. */
1246 FT_New_Face_From_Suitcase( FT_Library library
,
1247 const UInt8
* pathname
,
1251 FT_Error error
= FT_Err_Cannot_Open_Resource
;
1252 ResFileRefNum res_ref
;
1253 ResourceIndex res_index
;
1255 short num_faces_in_res
, num_faces_in_fond
;
1258 if ( noErr
!= FT_FSPathMakeRes( pathname
, &res_ref
) )
1259 return FT_Err_Cannot_Open_Resource
;
1261 UseResFile( res_ref
);
1263 return FT_Err_Cannot_Open_Resource
;
1265 num_faces_in_res
= 0;
1266 for ( res_index
= 1; ; ++res_index
)
1268 fond
= Get1IndResource( FT_MAKE_TAG( 'F', 'O', 'N', 'D' ),
1273 num_faces_in_fond
= count_faces( fond
, pathname
);
1274 num_faces_in_res
+= num_faces_in_fond
;
1276 if ( 0 <= face_index
&& face_index
< num_faces_in_fond
&& error
)
1277 error
= FT_New_Face_From_FOND( library
, fond
, face_index
, aface
);
1279 face_index
-= num_faces_in_fond
;
1282 CloseResFile( res_ref
);
1283 if ( FT_Err_Ok
== error
&& NULL
!= aface
)
1284 (*aface
)->num_faces
= num_faces_in_res
;
1289 /* documentation is in ftmac.h */
1291 FT_EXPORT_DEF( FT_Error
)
1292 FT_New_Face_From_FOND( FT_Library library
,
1297 short have_sfnt
, have_lwfn
= 0;
1298 ResID sfnt_id
, fond_id
;
1301 Str255 lwfn_file_name
;
1302 UInt8 path_lwfn
[PATH_MAX
];
1304 FT_Error error
= FT_Err_Ok
;
1307 GetResInfo( fond
, &fond_id
, &fond_type
, fond_name
);
1308 if ( ResError() != noErr
||
1309 fond_type
!= FT_MAKE_TAG( 'F', 'O', 'N', 'D' ) )
1310 return FT_Err_Invalid_File_Format
;
1313 parse_fond( *fond
, &have_sfnt
, &sfnt_id
, lwfn_file_name
, face_index
);
1316 if ( lwfn_file_name
[0] )
1321 res
= HomeResFile( fond
);
1322 if ( noErr
!= ResError() )
1323 goto found_no_lwfn_file
;
1328 UInt8 path_fond
[PATH_MAX
];
1332 err
= FSGetForkCBInfo( res
, kFSInvalidVolumeRefNum
,
1333 NULL
, NULL
, NULL
, &ref
, NULL
);
1335 goto found_no_lwfn_file
;
1337 err
= FSRefMakePath( &ref
, path_fond
, sizeof ( path_fond
) );
1339 goto found_no_lwfn_file
;
1341 error
= lookup_lwfn_by_fond( path_fond
, lwfn_file_name
,
1342 path_lwfn
, sizeof ( path_lwfn
) );
1343 if ( FT_Err_Ok
== error
)
1350 UInt8 path_fond
[PATH_MAX
];
1352 Str255 fond_file_name
;
1356 FT_MEM_SET( &spec
, 0, sizeof ( FSSpec
) );
1357 FT_MEM_SET( &pb
, 0, sizeof ( FCBPBRec
) );
1359 pb
.ioNamePtr
= fond_file_name
;
1364 err
= PBGetFCBInfoSync( &pb
);
1366 goto found_no_lwfn_file
;
1368 err
= FSMakeFSSpec( pb
.ioFCBVRefNum
, pb
.ioFCBParID
,
1369 fond_file_name
, &spec
);
1371 goto found_no_lwfn_file
;
1373 err
= FT_FSpMakePath( &spec
, path_fond
, sizeof ( path_fond
) );
1375 goto found_no_lwfn_file
;
1377 error
= lookup_lwfn_by_fond( path_fond
, lwfn_file_name
,
1378 path_lwfn
, sizeof ( path_lwfn
) );
1379 if ( FT_Err_Ok
== error
)
1383 #endif /* HAVE_FSREF, HAVE_FSSPEC */
1387 if ( have_lwfn
&& ( !have_sfnt
|| PREFER_LWFN
) )
1388 error
= FT_New_Face_From_LWFN( library
,
1393 error
= FT_Err_Unknown_File_Format
;
1396 if ( have_sfnt
&& FT_Err_Ok
!= error
)
1397 error
= FT_New_Face_From_SFNT( library
,
1406 /* Common function to load a new FT_Face from a resource file. */
1408 FT_New_Face_From_Resource( FT_Library library
,
1409 const UInt8
* pathname
,
1417 /* LWFN is a (very) specific file format, check for it explicitly */
1418 file_type
= get_file_type_from_path( pathname
);
1419 if ( file_type
== FT_MAKE_TAG( 'L', 'W', 'F', 'N' ) )
1420 return FT_New_Face_From_LWFN( library
, pathname
, face_index
, aface
);
1422 /* Otherwise the file type doesn't matter (there are more than */
1423 /* `FFIL' and `tfil'). Just try opening it as a font suitcase; */
1424 /* if it works, fine. */
1426 error
= FT_New_Face_From_Suitcase( library
, pathname
, face_index
, aface
);
1430 /* let it fall through to normal loader (.ttf, .otf, etc.); */
1431 /* we signal this by returning no error and no FT_Face */
1437 /*************************************************************************/
1443 /* This is the Mac-specific implementation of FT_New_Face. In */
1444 /* addition to the standard FT_New_Face() functionality, it also */
1445 /* accepts pathnames to Mac suitcase files. For further */
1446 /* documentation see the original FT_New_Face() in freetype.h. */
1448 FT_EXPORT_DEF( FT_Error
)
1449 FT_New_Face( FT_Library library
,
1450 const char* pathname
,
1458 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
1460 return FT_Err_Invalid_Argument
;
1465 /* try resourcefork based font: LWFN, FFIL */
1466 error
= FT_New_Face_From_Resource( library
, (UInt8
*)pathname
,
1467 face_index
, aface
);
1468 if ( error
!= 0 || *aface
!= NULL
)
1471 /* let it fall through to normal loader (.ttf, .otf, etc.) */
1472 args
.flags
= FT_OPEN_PATHNAME
;
1473 args
.pathname
= (char*)pathname
;
1474 return FT_Open_Face( library
, &args
, face_index
, aface
);
1478 /*************************************************************************/
1481 /* FT_New_Face_From_FSRef */
1484 /* FT_New_Face_From_FSRef is identical to FT_New_Face except it */
1485 /* accepts an FSRef instead of a path. */
1487 /* This function is deprecated because Carbon data types (FSRef) */
1488 /* are not cross-platform, and thus not suitable for the freetype API. */
1489 FT_EXPORT_DEF( FT_Error
)
1490 FT_New_Face_From_FSRef( FT_Library library
,
1498 FT_UNUSED( library
);
1500 FT_UNUSED( face_index
);
1503 return FT_Err_Unimplemented_Feature
;
1510 UInt8 pathname
[PATH_MAX
];
1514 return FT_Err_Invalid_Argument
;
1516 err
= FSRefMakePath( ref
, pathname
, sizeof ( pathname
) );
1518 error
= FT_Err_Cannot_Open_Resource
;
1520 error
= FT_New_Face_From_Resource( library
, pathname
, face_index
, aface
);
1521 if ( error
!= 0 || *aface
!= NULL
)
1524 /* fallback to datafork font */
1525 args
.flags
= FT_OPEN_PATHNAME
;
1526 args
.pathname
= (char*)pathname
;
1527 return FT_Open_Face( library
, &args
, face_index
, aface
);
1529 #endif /* HAVE_FSREF */
1534 /*************************************************************************/
1537 /* FT_New_Face_From_FSSpec */
1540 /* FT_New_Face_From_FSSpec is identical to FT_New_Face except it */
1541 /* accepts an FSSpec instead of a path. */
1543 /* This function is deprecated because Carbon data types (FSSpec) */
1544 /* are not cross-platform, and thus not suitable for the freetype API. */
1545 FT_EXPORT_DEF( FT_Error
)
1546 FT_New_Face_From_FSSpec( FT_Library library
,
1557 if ( !spec
|| FSpMakeFSRef( spec
, &ref
) != noErr
)
1558 return FT_Err_Invalid_Argument
;
1560 return FT_New_Face_From_FSRef( library
, &ref
, face_index
, aface
);
1567 UInt8 pathname
[PATH_MAX
];
1571 return FT_Err_Invalid_Argument
;
1573 err
= FT_FSpMakePath( spec
, pathname
, sizeof ( pathname
) );
1575 error
= FT_Err_Cannot_Open_Resource
;
1577 error
= FT_New_Face_From_Resource( library
, pathname
, face_index
, aface
);
1578 if ( error
!= 0 || *aface
!= NULL
)
1581 /* fallback to datafork font */
1582 args
.flags
= FT_OPEN_PATHNAME
;
1583 args
.pathname
= (char*)pathname
;
1584 return FT_Open_Face( library
, &args
, face_index
, aface
);
1588 FT_UNUSED( library
);
1590 FT_UNUSED( face_index
);
1593 return FT_Err_Unimplemented_Feature
;
1595 #endif /* HAVE_FSREF, HAVE_FSSPEC */