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 */