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_TRUETYPE_TAGS_H
68 #include FT_INTERNAL_STREAM_H
71 #if defined( __GNUC__ ) || defined( __IBMC__ )
72 /* This is for Mac OS X. Without redefinition, OS_INLINE */
73 /* expands to `static inline' which doesn't survive the */
74 /* -ansi compilation flag of GCC. */
75 #if !HAVE_ANSI_OS_INLINE
77 #define OS_INLINE static __inline__
79 #include <CoreServices/CoreServices.h>
80 #include <ApplicationServices/ApplicationServices.h>
81 #include <sys/syslimits.h> /* PATH_MAX */
83 #include <Resources.h>
88 #include <TextUtils.h>
92 #define PATH_MAX 1024 /* same with Mac OS X's syslimits.h */
95 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
96 #include <FSp_fopen.h>
99 #define FT_DEPRECATED_ATTRIBUTE
103 /* undefine blocking-macros in ftmac.h */
104 #undef FT_GetFile_From_Mac_Name
105 #undef FT_GetFile_From_Mac_ATS_Name
106 #undef FT_New_Face_From_FOND
107 #undef FT_New_Face_From_FSSpec
108 #undef FT_New_Face_From_FSRef
111 /* FSSpec functions are deprecated since Mac OS X 10.4 */
113 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
114 #define HAVE_FSSPEC 1
116 #define HAVE_FSSPEC 0
120 /* most FSRef functions were introduced since Mac OS 9 */
122 #if TARGET_API_MAC_OSX
129 /* QuickDraw is deprecated since Mac OS X 10.4 */
130 #ifndef HAVE_QUICKDRAW_CARBON
131 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
132 #define HAVE_QUICKDRAW_CARBON 1
134 #define HAVE_QUICKDRAW_CARBON 0
138 /* AppleTypeService is available since Mac OS X */
140 #if TARGET_API_MAC_OSX
142 #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */
143 #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault
150 /* `configure' checks the availability of `ResourceIndex' strictly */
151 /* and sets HAVE_TYPE_RESOURCE_INDEX to 1 or 0 always. If it is */
152 /* not set (e.g., a build without `configure'), the availability */
153 /* is guessed from the SDK version. */
154 #ifndef HAVE_TYPE_RESOURCE_INDEX
155 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
156 ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 )
157 #define HAVE_TYPE_RESOURCE_INDEX 0
159 #define HAVE_TYPE_RESOURCE_INDEX 1
161 #endif /* !HAVE_TYPE_RESOURCE_INDEX */
163 #if ( HAVE_TYPE_RESOURCE_INDEX == 0 )
164 typedef short ResourceIndex
;
167 /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
168 TrueType in case *both* are available (this is not common,
169 but it *is* possible). */
171 #define PREFER_LWFN 1
175 #if !HAVE_QUICKDRAW_CARBON /* QuickDraw is deprecated since Mac OS X 10.4 */
177 FT_EXPORT_DEF( FT_Error
)
178 FT_GetFile_From_Mac_Name( const char* fontName
,
180 FT_Long
* face_index
)
182 FT_UNUSED( fontName
);
183 FT_UNUSED( pathSpec
);
184 FT_UNUSED( face_index
);
186 return FT_Err_Unimplemented_Feature
;
191 FT_EXPORT_DEF( FT_Error
)
192 FT_GetFile_From_Mac_Name( const char* fontName
,
194 FT_Long
* face_index
)
196 OptionBits options
= kFMUseGlobalScopeOption
;
198 FMFontFamilyIterator famIter
;
199 OSStatus status
= FMCreateFontFamilyIterator( NULL
, NULL
,
203 FMFontFamily family
= 0;
207 while ( status
== 0 && !the_font
)
209 status
= FMGetNextFontFamily( &famIter
, &family
);
213 FMFontFamilyInstanceIterator instIter
;
218 /* get the family name */
219 FMGetFontFamilyName( family
, famNameStr
);
220 CopyPascalStringToC( famNameStr
, famName
);
222 /* iterate through the styles */
223 FMCreateFontFamilyInstanceIterator( family
, &instIter
);
228 while ( stat2
== 0 && !the_font
)
235 stat2
= FMGetNextFontFamilyInstance( &instIter
, &font
,
237 if ( stat2
== 0 && size
== 0 )
242 /* build up a complete face name */
243 ft_strcpy( fullName
, famName
);
245 ft_strcat( fullName
, " Bold" );
246 if ( style
& italic
)
247 ft_strcat( fullName
, " Italic" );
249 /* compare with the name we are looking for */
250 if ( ft_strcmp( fullName
, fontName
) == 0 )
260 FMDisposeFontFamilyInstanceIterator( &instIter
);
264 FMDisposeFontFamilyIterator( &famIter
);
268 FMGetFontContainer( the_font
, pathSpec
);
272 return FT_Err_Unknown_File_Format
;
275 #endif /* HAVE_QUICKDRAW_CARBON */
280 /* Private function. */
281 /* The FSSpec type has been discouraged for a long time, */
282 /* unfortunately an FSRef replacement API for */
283 /* ATSFontGetFileSpecification() is only available in */
284 /* Mac OS X 10.5 and later. */
286 FT_ATSFontGetFileReference( ATSFontRef ats_font_id
,
287 FSRef
* ats_font_ref
)
291 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
292 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
296 err
= ATSFontGetFileSpecification( ats_font_id
, &spec
);
298 err
= FSpMakeFSRef( &spec
, ats_font_ref
);
300 err
= ATSFontGetFileReference( ats_font_id
, ats_font_ref
);
308 FT_GetFileRef_From_Mac_ATS_Name( const char* fontName
,
310 FT_Long
* face_index
)
312 CFStringRef cf_fontName
;
313 ATSFontRef ats_font_id
;
318 cf_fontName
= CFStringCreateWithCString( NULL
, fontName
,
319 kCFStringEncodingMacRoman
);
320 ats_font_id
= ATSFontFindFromName( cf_fontName
,
321 kATSOptionFlagsUnRestrictedScope
);
322 CFRelease( cf_fontName
);
324 if ( ats_font_id
== 0 || ats_font_id
== 0xFFFFFFFFUL
)
325 return FT_Err_Unknown_File_Format
;
327 if ( noErr
!= FT_ATSFontGetFileReference( ats_font_id
, ats_font_ref
) )
328 return FT_Err_Unknown_File_Format
;
330 /* face_index calculation by searching preceding fontIDs */
331 /* with same FSRef */
333 ATSFontRef id2
= ats_font_id
- 1;
339 if ( noErr
!= FT_ATSFontGetFileReference( id2
, &ref2
) )
341 if ( noErr
!= FSCompareFSRefs( ats_font_ref
, &ref2
) )
346 *face_index
= ats_font_id
- ( id2
+ 1 );
356 FT_EXPORT_DEF( FT_Error
)
357 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName
,
360 FT_Long
* face_index
)
362 FT_UNUSED( fontName
);
364 FT_UNUSED( maxPathSize
);
365 FT_UNUSED( face_index
);
367 return FT_Err_Unimplemented_Feature
;
372 FT_EXPORT_DEF( FT_Error
)
373 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName
,
376 FT_Long
* face_index
)
382 err
= FT_GetFileRef_From_Mac_ATS_Name( fontName
, &ref
, face_index
);
383 if ( FT_Err_Ok
!= err
)
386 if ( noErr
!= FSRefMakePath( &ref
, path
, maxPathSize
) )
387 return FT_Err_Unknown_File_Format
;
392 #endif /* HAVE_ATS */
395 #if !HAVE_FSSPEC || !HAVE_ATS
397 FT_EXPORT_DEF( FT_Error
)
398 FT_GetFile_From_Mac_ATS_Name( const char* fontName
,
400 FT_Long
* face_index
)
402 FT_UNUSED( fontName
);
403 FT_UNUSED( pathSpec
);
404 FT_UNUSED( face_index
);
406 return FT_Err_Unimplemented_Feature
;
411 /* This function is deprecated because FSSpec is deprecated in Mac OS X. */
412 FT_EXPORT_DEF( FT_Error
)
413 FT_GetFile_From_Mac_ATS_Name( const char* fontName
,
415 FT_Long
* face_index
)
421 err
= FT_GetFileRef_From_Mac_ATS_Name( fontName
, &ref
, face_index
);
422 if ( FT_Err_Ok
!= err
)
425 if ( noErr
!= FSGetCatalogInfo( &ref
, kFSCatInfoNone
, NULL
, NULL
,
427 return FT_Err_Unknown_File_Format
;
435 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
437 #define STREAM_FILE( stream ) ( (FT_FILE*)stream->descriptor.pointer )
440 FT_CALLBACK_DEF( void )
441 ft_FSp_stream_close( FT_Stream stream
)
443 ft_fclose( STREAM_FILE( stream
) );
445 stream
->descriptor
.pointer
= NULL
;
451 FT_CALLBACK_DEF( unsigned long )
452 ft_FSp_stream_io( FT_Stream stream
,
453 unsigned long offset
,
454 unsigned char* buffer
,
455 unsigned long count
)
460 file
= STREAM_FILE( stream
);
462 ft_fseek( file
, offset
, SEEK_SET
);
464 return (unsigned long)ft_fread( buffer
, 1, count
, file
);
467 #endif /* __MWERKS__ && !TARGET_RT_MAC_MACHO */
470 #if HAVE_FSSPEC && !HAVE_FSREF
472 /* isDirectory is a dummy to synchronize API with FSPathMakeRef() */
474 FT_FSPathMakeSpec( const UInt8
* pathname
,
476 Boolean isDirectory
)
483 FT_UNUSED( isDirectory
);
486 p
= q
= (const char *)pathname
;
492 int len
= ft_strlen( p
);
503 if ( 255 < ft_strlen( (char *)pathname
) )
505 while ( p
< q
&& *q
!= ':' )
510 *(char *)nodeName
= q
- p
;
511 else if ( ft_strlen( p
) < 256 )
512 *(char *)nodeName
= ft_strlen( p
);
514 return errFSNameTooLong
;
516 ft_strncpy( (char *)nodeName
+ 1, (char *)p
, *(char *)nodeName
);
517 err
= FSMakeFSSpec( vRefNum
, dirID
, nodeName
, spec_p
);
518 if ( err
|| '\0' == *q
)
521 vRefNum
= spec_p
->vRefNum
;
522 dirID
= spec_p
->parID
;
530 FT_FSpMakePath( const FSSpec
* spec_p
,
535 FSSpec spec
= *spec_p
;
541 FT_MEM_SET( path
, 0, maxPathSize
);
544 int child_namelen
= ft_strlen( (char *)path
);
545 unsigned char node_namelen
= spec
.name
[0];
546 unsigned char* node_name
= spec
.name
+ 1;
549 if ( node_namelen
+ child_namelen
> maxPathSize
)
550 return errFSNameTooLong
;
552 FT_MEM_MOVE( path
+ node_namelen
+ 1, path
, child_namelen
);
553 FT_MEM_COPY( path
, node_name
, node_namelen
);
554 if ( child_namelen
> 0 )
555 path
[node_namelen
] = ':';
557 vRefNum
= spec
.vRefNum
;
559 parDir_name
[0] = '\0';
560 err
= FSMakeFSSpec( vRefNum
, dirID
, parDir_name
, &spec
);
561 if ( noErr
!= err
|| dirID
== spec
.parID
)
567 #endif /* HAVE_FSSPEC && !HAVE_FSREF */
571 FT_FSPathMakeRes( const UInt8
* pathname
,
581 if ( noErr
!= FSPathMakeRef( pathname
, &ref
, FALSE
) )
582 return FT_Err_Cannot_Open_Resource
;
584 /* at present, no support for dfont format */
585 err
= FSOpenResourceFile( &ref
, 0, NULL
, fsRdPerm
, res
);
589 /* fallback to original resource-fork font */
590 *res
= FSOpenResFile( &ref
, fsRdPerm
);
599 if ( noErr
!= FT_FSPathMakeSpec( pathname
, &spec
, FALSE
) )
600 return FT_Err_Cannot_Open_Resource
;
602 /* at present, no support for dfont format without FSRef */
603 /* (see above), try original resource-fork font */
604 *res
= FSpOpenResFile( &spec
, fsRdPerm
);
607 #endif /* HAVE_FSREF */
613 /* Return the file type for given pathname */
615 get_file_type_from_path( const UInt8
* pathname
)
624 if ( noErr
!= FSPathMakeRef( pathname
, &ref
, FALSE
) )
627 if ( noErr
!= FSGetCatalogInfo( &ref
, kFSCatInfoFinderInfo
, &info
,
631 return ((FInfo
*)(info
.finderInfo
))->fdType
;
639 if ( noErr
!= FT_FSPathMakeSpec( pathname
, &spec
, FALSE
) )
642 if ( noErr
!= FSpGetFInfo( &spec
, &finfo
) )
647 #endif /* HAVE_FSREF */
652 /* Given a PostScript font name, create the Macintosh LWFN file name. */
654 create_lwfn_name( char* ps_name
,
655 Str255 lwfn_file_name
)
657 int max
= 5, count
= 0;
658 FT_Byte
* p
= lwfn_file_name
;
659 FT_Byte
* q
= (FT_Byte
*)ps_name
;
662 lwfn_file_name
[0] = 0;
666 if ( ft_isupper( *q
) )
672 if ( count
< max
&& ( ft_isalnum( *q
) || *q
== '_' ) )
684 count_faces_sfnt( char* fond_data
)
686 /* The count is 1 greater than the value in the FOND. */
687 /* Isn't that cute? :-) */
689 return EndianS16_BtoN( *( (short*)( fond_data
+
690 sizeof ( FamRec
) ) ) ) + 1;
695 count_faces_scalable( char* fond_data
)
699 short i
, face
, face_all
;
702 fond
= (FamRec
*)fond_data
;
703 face_all
= EndianS16_BtoN( *( (short *)( fond_data
+
704 sizeof ( FamRec
) ) ) ) + 1;
705 assoc
= (AsscEntry
*)( fond_data
+ sizeof ( FamRec
) + 2 );
708 for ( i
= 0; i
< face_all
; i
++ )
710 if ( 0 == EndianS16_BtoN( assoc
[i
].fontSize
) )
717 /* Look inside the FOND data, answer whether there should be an SFNT
718 resource, and answer the name of a possible LWFN Type 1 file.
720 Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
721 to load a face OTHER than the first one in the FOND!
725 parse_fond( char* fond_data
,
728 Str255 lwfn_file_name
,
732 AsscEntry
* base_assoc
;
738 lwfn_file_name
[0] = 0;
740 fond
= (FamRec
*)fond_data
;
741 assoc
= (AsscEntry
*)( fond_data
+ sizeof ( FamRec
) + 2 );
744 /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */
745 if ( 47 < face_index
)
748 /* Let's do a little range checking before we get too excited here */
749 if ( face_index
< count_faces_sfnt( fond_data
) )
751 assoc
+= face_index
; /* add on the face_index! */
753 /* if the face at this index is not scalable,
754 fall back to the first one (old behavior) */
755 if ( EndianS16_BtoN( assoc
->fontSize
) == 0 )
758 *sfnt_id
= EndianS16_BtoN( assoc
->fontID
);
760 else if ( base_assoc
->fontSize
== 0 )
763 *sfnt_id
= EndianS16_BtoN( base_assoc
->fontID
);
767 if ( EndianS32_BtoN( fond
->ffStylOff
) )
769 unsigned char* p
= (unsigned char*)fond_data
;
771 unsigned short string_count
;
773 unsigned char* names
[64];
777 p
+= EndianS32_BtoN( fond
->ffStylOff
);
778 style
= (StyleTable
*)p
;
779 p
+= sizeof ( StyleTable
);
780 string_count
= EndianS16_BtoN( *(short*)(p
) );
781 p
+= sizeof ( short );
783 for ( i
= 0; i
< string_count
&& i
< 64; i
++ )
791 size_t ps_name_len
= (size_t)names
[0][0];
794 if ( ps_name_len
!= 0 )
796 ft_memcpy(ps_name
, names
[0] + 1, ps_name_len
);
797 ps_name
[ps_name_len
] = 0;
799 if ( style
->indexes
[face_index
] > 1 &&
800 style
->indexes
[face_index
] <= FT_MIN( string_count
, 64 ) )
802 unsigned char* suffixes
= names
[style
->indexes
[face_index
] - 1];
805 for ( i
= 1; i
<= suffixes
[0]; i
++ )
808 size_t j
= suffixes
[i
] - 1;
811 if ( j
< string_count
&& ( s
= names
[j
] ) != NULL
)
813 size_t s_len
= (size_t)s
[0];
816 if ( s_len
!= 0 && ps_name_len
+ s_len
< sizeof ( ps_name
) )
818 ft_memcpy( ps_name
+ ps_name_len
, s
+ 1, s_len
);
819 ps_name_len
+= s_len
;
820 ps_name
[ps_name_len
] = 0;
827 create_lwfn_name( ps_name
, lwfn_file_name
);
833 lookup_lwfn_by_fond( const UInt8
* path_fond
,
834 ConstStr255Param base_lwfn
,
845 /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */
846 /* We should not extract parent directory by string manipulation. */
848 if ( noErr
!= FSPathMakeRef( path_fond
, &ref
, FALSE
) )
849 return FT_Err_Invalid_Argument
;
851 if ( noErr
!= FSGetCatalogInfo( &ref
, kFSCatInfoNone
,
852 NULL
, NULL
, NULL
, &par_ref
) )
853 return FT_Err_Invalid_Argument
;
855 if ( noErr
!= FSRefMakePath( &par_ref
, path_lwfn
, path_size
) )
856 return FT_Err_Invalid_Argument
;
858 if ( ft_strlen( (char *)path_lwfn
) + 1 + base_lwfn
[0] > path_size
)
859 return FT_Err_Invalid_Argument
;
861 /* now we have absolute dirname in path_lwfn */
862 if ( path_lwfn
[0] == '/' )
863 ft_strcat( (char *)path_lwfn
, "/" );
865 ft_strcat( (char *)path_lwfn
, ":" );
867 dirname_len
= ft_strlen( (char *)path_lwfn
);
868 ft_strcat( (char *)path_lwfn
, (char *)base_lwfn
+ 1 );
869 path_lwfn
[dirname_len
+ base_lwfn
[0]] = '\0';
871 if ( noErr
!= FSPathMakeRef( path_lwfn
, &ref
, FALSE
) )
872 return FT_Err_Cannot_Open_Resource
;
874 if ( noErr
!= FSGetCatalogInfo( &ref
, kFSCatInfoNone
,
875 NULL
, NULL
, NULL
, NULL
) )
876 return FT_Err_Cannot_Open_Resource
;
886 /* pathname for FSSpec is always HFS format */
887 if ( ft_strlen( (char *)path_fond
) > path_size
)
888 return FT_Err_Invalid_Argument
;
890 ft_strcpy( (char *)path_lwfn
, (char *)path_fond
);
892 i
= ft_strlen( (char *)path_lwfn
) - 1;
893 while ( i
> 0 && ':' != path_lwfn
[i
] )
896 if ( i
+ 1 + base_lwfn
[0] > path_size
)
897 return FT_Err_Invalid_Argument
;
899 if ( ':' == path_lwfn
[i
] )
901 ft_strcpy( (char *)path_lwfn
+ i
+ 1, (char *)base_lwfn
+ 1 );
902 path_lwfn
[i
+ 1 + base_lwfn
[0]] = '\0';
906 ft_strcpy( (char *)path_lwfn
, (char *)base_lwfn
+ 1 );
907 path_lwfn
[base_lwfn
[0]] = '\0';
910 if ( noErr
!= FT_FSPathMakeSpec( path_lwfn
, &spec
, FALSE
) )
911 return FT_Err_Cannot_Open_Resource
;
915 #endif /* HAVE_FSREF */
921 count_faces( Handle fond
,
922 const UInt8
* pathname
)
925 short have_sfnt
, have_lwfn
;
926 Str255 lwfn_file_name
;
927 UInt8 buff
[PATH_MAX
];
932 have_sfnt
= have_lwfn
= 0;
935 parse_fond( *fond
, &have_sfnt
, &sfnt_id
, lwfn_file_name
, 0 );
937 if ( lwfn_file_name
[0] )
939 err
= lookup_lwfn_by_fond( pathname
, lwfn_file_name
,
940 buff
, sizeof ( buff
) );
941 if ( FT_Err_Ok
== err
)
945 if ( have_lwfn
&& ( !have_sfnt
|| PREFER_LWFN
) )
948 num_faces
= count_faces_scalable( *fond
);
955 /* Read Type 1 data from the POST resources inside the LWFN file,
956 return a PFB buffer. This is somewhat convoluted because the FT2
957 PFB parser wants the ASCII header as one chunk, and the LWFN
958 chunks are often not organized that way, so we glue chunks
959 of the same type together. */
961 read_lwfn( FT_Memory memory
,
966 FT_Error error
= FT_Err_Ok
;
968 unsigned char *buffer
, *p
, *size_p
= NULL
;
969 FT_ULong total_size
= 0;
970 FT_ULong old_total_size
= 0;
971 FT_ULong post_size
, pfb_chunk_size
;
973 char code
, last_code
;
978 /* First pass: load all POST resources, and determine the size of */
979 /* the output buffer. */
985 post_data
= Get1Resource( TTAG_POST
, res_id
++ );
986 if ( post_data
== NULL
)
987 break; /* we are done */
989 code
= (*post_data
)[0];
991 if ( code
!= last_code
)
994 total_size
+= 2; /* just the end code */
996 total_size
+= 6; /* code + 4 bytes chunk length */
999 total_size
+= GetHandleSize( post_data
) - 2;
1002 /* detect integer overflows */
1003 if ( total_size
< old_total_size
)
1005 error
= FT_Err_Array_Too_Large
;
1009 old_total_size
= total_size
;
1012 if ( FT_ALLOC( buffer
, (FT_Long
)total_size
) )
1015 /* Second pass: append all POST data to the buffer, add PFB fields. */
1016 /* Glue all consecutive chunks of the same type together. */
1024 post_data
= Get1Resource( TTAG_POST
, res_id
++ );
1025 if ( post_data
== NULL
)
1026 break; /* we are done */
1028 post_size
= (FT_ULong
)GetHandleSize( post_data
) - 2;
1029 code
= (*post_data
)[0];
1031 if ( code
!= last_code
)
1033 if ( last_code
!= -1 )
1035 /* we are done adding a chunk, fill in the size field */
1036 if ( size_p
!= NULL
)
1038 *size_p
++ = (FT_Byte
)( pfb_chunk_size
& 0xFF );
1039 *size_p
++ = (FT_Byte
)( ( pfb_chunk_size
>> 8 ) & 0xFF );
1040 *size_p
++ = (FT_Byte
)( ( pfb_chunk_size
>> 16 ) & 0xFF );
1041 *size_p
++ = (FT_Byte
)( ( pfb_chunk_size
>> 24 ) & 0xFF );
1048 *p
++ = 0x03; /* the end */
1049 else if ( code
== 2 )
1050 *p
++ = 0x02; /* binary segment */
1052 *p
++ = 0x01; /* ASCII segment */
1056 size_p
= p
; /* save for later */
1057 p
+= 4; /* make space for size field */
1061 ft_memcpy( p
, *post_data
+ 2, post_size
);
1062 pfb_chunk_size
+= post_size
;
1071 CloseResFile( res
);
1076 /* Create a new FT_Face from a file spec to an LWFN file. */
1078 FT_New_Face_From_LWFN( FT_Library library
,
1079 const UInt8
* pathname
,
1089 if ( noErr
!= FT_FSPathMakeRes( pathname
, &res
) )
1090 return FT_Err_Cannot_Open_Resource
;
1094 error
= read_lwfn( library
->memory
, res
, &pfb_data
, &pfb_size
);
1095 CloseResFile( res
); /* PFB is already loaded, useless anymore */
1099 return open_face_from_buffer( library
,
1108 /* Create a new FT_Face from an SFNT resource, specified by res ID. */
1110 FT_New_Face_From_SFNT( FT_Library library
,
1118 FT_Error error
= FT_Err_Ok
;
1119 FT_Memory memory
= library
->memory
;
1120 int is_cff
, is_sfnt_ps
;
1123 sfnt
= GetResource( TTAG_sfnt
, sfnt_id
);
1125 return FT_Err_Invalid_Handle
;
1127 sfnt_size
= (FT_ULong
)GetHandleSize( sfnt
);
1128 if ( FT_ALLOC( sfnt_data
, (FT_Long
)sfnt_size
) )
1130 ReleaseResource( sfnt
);
1135 ft_memcpy( sfnt_data
, *sfnt
, sfnt_size
);
1137 ReleaseResource( sfnt
);
1139 is_cff
= sfnt_size
> 4 && !ft_memcmp( sfnt_data
, "OTTO", 4 );
1140 is_sfnt_ps
= sfnt_size
> 4 && !ft_memcmp( sfnt_data
, "typ1", 4 );
1147 if ( FT_NEW( stream
) )
1150 FT_Stream_OpenMemory( stream
, sfnt_data
, sfnt_size
);
1151 if ( !open_face_PS_from_sfnt_stream( library
,
1157 FT_Stream_Close( stream
);
1159 FT_FREE( sfnt_data
);
1166 error
= open_face_from_buffer( library
,
1170 is_cff
? "cff" : "truetype",
1177 /* Create a new FT_Face from a file spec to a suitcase file. */
1179 FT_New_Face_From_Suitcase( FT_Library library
,
1180 const UInt8
* pathname
,
1184 FT_Error error
= FT_Err_Cannot_Open_Resource
;
1185 ResFileRefNum res_ref
;
1186 ResourceIndex res_index
;
1188 short num_faces_in_res
, num_faces_in_fond
;
1191 if ( noErr
!= FT_FSPathMakeRes( pathname
, &res_ref
) )
1192 return FT_Err_Cannot_Open_Resource
;
1194 UseResFile( res_ref
);
1196 return FT_Err_Cannot_Open_Resource
;
1198 num_faces_in_res
= 0;
1199 for ( res_index
= 1; ; ++res_index
)
1201 fond
= Get1IndResource( TTAG_FOND
, res_index
);
1205 num_faces_in_fond
= count_faces( fond
, pathname
);
1206 num_faces_in_res
+= num_faces_in_fond
;
1208 if ( 0 <= face_index
&& face_index
< num_faces_in_fond
&& error
)
1209 error
= FT_New_Face_From_FOND( library
, fond
, face_index
, aface
);
1211 face_index
-= num_faces_in_fond
;
1214 CloseResFile( res_ref
);
1215 if ( FT_Err_Ok
== error
&& NULL
!= aface
)
1216 (*aface
)->num_faces
= num_faces_in_res
;
1221 /* documentation is in ftmac.h */
1223 FT_EXPORT_DEF( FT_Error
)
1224 FT_New_Face_From_FOND( FT_Library library
,
1229 short have_sfnt
, have_lwfn
= 0;
1230 ResID sfnt_id
, fond_id
;
1233 Str255 lwfn_file_name
;
1234 UInt8 path_lwfn
[PATH_MAX
];
1236 FT_Error error
= FT_Err_Ok
;
1239 GetResInfo( fond
, &fond_id
, &fond_type
, fond_name
);
1240 if ( ResError() != noErr
|| fond_type
!= TTAG_FOND
)
1241 return FT_Err_Invalid_File_Format
;
1244 parse_fond( *fond
, &have_sfnt
, &sfnt_id
, lwfn_file_name
, face_index
);
1247 if ( lwfn_file_name
[0] )
1252 res
= HomeResFile( fond
);
1253 if ( noErr
!= ResError() )
1254 goto found_no_lwfn_file
;
1259 UInt8 path_fond
[PATH_MAX
];
1263 err
= FSGetForkCBInfo( res
, kFSInvalidVolumeRefNum
,
1264 NULL
, NULL
, NULL
, &ref
, NULL
);
1266 goto found_no_lwfn_file
;
1268 err
= FSRefMakePath( &ref
, path_fond
, sizeof ( path_fond
) );
1270 goto found_no_lwfn_file
;
1272 error
= lookup_lwfn_by_fond( path_fond
, lwfn_file_name
,
1273 path_lwfn
, sizeof ( path_lwfn
) );
1274 if ( FT_Err_Ok
== error
)
1281 UInt8 path_fond
[PATH_MAX
];
1283 Str255 fond_file_name
;
1287 FT_MEM_SET( &spec
, 0, sizeof ( FSSpec
) );
1288 FT_MEM_SET( &pb
, 0, sizeof ( FCBPBRec
) );
1290 pb
.ioNamePtr
= fond_file_name
;
1295 err
= PBGetFCBInfoSync( &pb
);
1297 goto found_no_lwfn_file
;
1299 err
= FSMakeFSSpec( pb
.ioFCBVRefNum
, pb
.ioFCBParID
,
1300 fond_file_name
, &spec
);
1302 goto found_no_lwfn_file
;
1304 err
= FT_FSpMakePath( &spec
, path_fond
, sizeof ( path_fond
) );
1306 goto found_no_lwfn_file
;
1308 error
= lookup_lwfn_by_fond( path_fond
, lwfn_file_name
,
1309 path_lwfn
, sizeof ( path_lwfn
) );
1310 if ( FT_Err_Ok
== error
)
1314 #endif /* HAVE_FSREF, HAVE_FSSPEC */
1318 if ( have_lwfn
&& ( !have_sfnt
|| PREFER_LWFN
) )
1319 error
= FT_New_Face_From_LWFN( library
,
1324 error
= FT_Err_Unknown_File_Format
;
1327 if ( have_sfnt
&& FT_Err_Ok
!= error
)
1328 error
= FT_New_Face_From_SFNT( library
,
1337 /* Common function to load a new FT_Face from a resource file. */
1339 FT_New_Face_From_Resource( FT_Library library
,
1340 const UInt8
* pathname
,
1348 /* LWFN is a (very) specific file format, check for it explicitly */
1349 file_type
= get_file_type_from_path( pathname
);
1350 if ( file_type
== TTAG_LWFN
)
1351 return FT_New_Face_From_LWFN( library
, pathname
, face_index
, aface
);
1353 /* Otherwise the file type doesn't matter (there are more than */
1354 /* `FFIL' and `tfil'). Just try opening it as a font suitcase; */
1355 /* if it works, fine. */
1357 error
= FT_New_Face_From_Suitcase( library
, pathname
, face_index
, aface
);
1361 /* let it fall through to normal loader (.ttf, .otf, etc.); */
1362 /* we signal this by returning no error and no FT_Face */
1368 /*************************************************************************/
1374 /* This is the Mac-specific implementation of FT_New_Face. In */
1375 /* addition to the standard FT_New_Face() functionality, it also */
1376 /* accepts pathnames to Mac suitcase files. For further */
1377 /* documentation see the original FT_New_Face() in freetype.h. */
1379 FT_EXPORT_DEF( FT_Error
)
1380 FT_New_Face( FT_Library library
,
1381 const char* pathname
,
1389 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
1391 return FT_Err_Invalid_Argument
;
1396 /* try resourcefork based font: LWFN, FFIL */
1397 error
= FT_New_Face_From_Resource( library
, (UInt8
*)pathname
,
1398 face_index
, aface
);
1399 if ( error
!= 0 || *aface
!= NULL
)
1402 /* let it fall through to normal loader (.ttf, .otf, etc.) */
1403 args
.flags
= FT_OPEN_PATHNAME
;
1404 args
.pathname
= (char*)pathname
;
1405 return FT_Open_Face( library
, &args
, face_index
, aface
);
1409 /*************************************************************************/
1412 /* FT_New_Face_From_FSRef */
1415 /* FT_New_Face_From_FSRef is identical to FT_New_Face except it */
1416 /* accepts an FSRef instead of a path. */
1418 /* This function is deprecated because Carbon data types (FSRef) */
1419 /* are not cross-platform, and thus not suitable for the freetype API. */
1420 FT_EXPORT_DEF( FT_Error
)
1421 FT_New_Face_From_FSRef( FT_Library library
,
1429 FT_UNUSED( library
);
1431 FT_UNUSED( face_index
);
1434 return FT_Err_Unimplemented_Feature
;
1441 UInt8 pathname
[PATH_MAX
];
1445 return FT_Err_Invalid_Argument
;
1447 err
= FSRefMakePath( ref
, pathname
, sizeof ( pathname
) );
1449 error
= FT_Err_Cannot_Open_Resource
;
1451 error
= FT_New_Face_From_Resource( library
, pathname
, face_index
, aface
);
1452 if ( error
!= 0 || *aface
!= NULL
)
1455 /* fallback to datafork font */
1456 args
.flags
= FT_OPEN_PATHNAME
;
1457 args
.pathname
= (char*)pathname
;
1458 return FT_Open_Face( library
, &args
, face_index
, aface
);
1460 #endif /* HAVE_FSREF */
1465 /*************************************************************************/
1468 /* FT_New_Face_From_FSSpec */
1471 /* FT_New_Face_From_FSSpec is identical to FT_New_Face except it */
1472 /* accepts an FSSpec instead of a path. */
1474 /* This function is deprecated because Carbon data types (FSSpec) */
1475 /* are not cross-platform, and thus not suitable for the freetype API. */
1476 FT_EXPORT_DEF( FT_Error
)
1477 FT_New_Face_From_FSSpec( FT_Library library
,
1488 if ( !spec
|| FSpMakeFSRef( spec
, &ref
) != noErr
)
1489 return FT_Err_Invalid_Argument
;
1491 return FT_New_Face_From_FSRef( library
, &ref
, face_index
, aface
);
1498 UInt8 pathname
[PATH_MAX
];
1502 return FT_Err_Invalid_Argument
;
1504 err
= FT_FSpMakePath( spec
, pathname
, sizeof ( pathname
) );
1506 error
= FT_Err_Cannot_Open_Resource
;
1508 error
= FT_New_Face_From_Resource( library
, pathname
, face_index
, aface
);
1509 if ( error
!= 0 || *aface
!= NULL
)
1512 /* fallback to datafork font */
1513 args
.flags
= FT_OPEN_PATHNAME
;
1514 args
.pathname
= (char*)pathname
;
1515 return FT_Open_Face( library
, &args
, face_index
, aface
);
1519 FT_UNUSED( library
);
1521 FT_UNUSED( face_index
);
1524 return FT_Err_Unimplemented_Feature
;
1526 #endif /* HAVE_FSREF, HAVE_FSSPEC */