mgh: fix for default HDD DMA mode, that wasn't correctly set
[open-ps2-loader.git] / thirdparty / freetype-2.3.12 / builds / mac / ftmac.c
blobc974f670f2dbf7b439653872df05584556058428
1 /***************************************************************************/
2 /* */
3 /* ftmac.c */
4 /* */
5 /* Mac FOND support. Written by just@letterror.com. */
6 /* Heavily Fixed by mpsuzuki, George Williams and Sean McBride */
7 /* */
8 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by */
9 /* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* */
11 /* This file is part of the FreeType project, and may only be used, */
12 /* modified, and distributed under the terms of the FreeType project */
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14 /* this file you indicate that you have read the license and */
15 /* understand and accept it fully. */
16 /* */
17 /***************************************************************************/
21 Notes
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
61 available.
65 #include <ft2build.h>
66 #include FT_FREETYPE_H
67 #include FT_TRUETYPE_TAGS_H
68 #include FT_INTERNAL_STREAM_H
69 #include "ftbase.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
76 #undef OS_INLINE
77 #define OS_INLINE static __inline__
78 #endif
79 #include <CoreServices/CoreServices.h>
80 #include <ApplicationServices/ApplicationServices.h>
81 #include <sys/syslimits.h> /* PATH_MAX */
82 #else
83 #include <Resources.h>
84 #include <Fonts.h>
85 #include <Endian.h>
86 #include <Errors.h>
87 #include <Files.h>
88 #include <TextUtils.h>
89 #endif
91 #ifndef PATH_MAX
92 #define PATH_MAX 1024 /* same with Mac OS X's syslimits.h */
93 #endif
95 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
96 #include <FSp_fopen.h>
97 #endif
99 #define FT_DEPRECATED_ATTRIBUTE
101 #include FT_MAC_H
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 */
112 #ifndef HAVE_FSSPEC
113 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
114 #define HAVE_FSSPEC 1
115 #else
116 #define HAVE_FSSPEC 0
117 #endif
118 #endif
120 /* most FSRef functions were introduced since Mac OS 9 */
121 #ifndef HAVE_FSREF
122 #if TARGET_API_MAC_OSX
123 #define HAVE_FSREF 1
124 #else
125 #define HAVE_FSREF 0
126 #endif
127 #endif
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
133 #else
134 #define HAVE_QUICKDRAW_CARBON 0
135 #endif
136 #endif
138 /* AppleTypeService is available since Mac OS X */
139 #ifndef HAVE_ATS
140 #if TARGET_API_MAC_OSX
141 #define HAVE_ATS 1
142 #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */
143 #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault
144 #endif
145 #else
146 #define HAVE_ATS 0
147 #endif
148 #endif
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
158 #else
159 #define HAVE_TYPE_RESOURCE_INDEX 1
160 #endif
161 #endif /* !HAVE_TYPE_RESOURCE_INDEX */
163 #if ( HAVE_TYPE_RESOURCE_INDEX == 0 )
164 typedef short ResourceIndex;
165 #endif
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). */
170 #ifndef PREFER_LWFN
171 #define PREFER_LWFN 1
172 #endif
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,
179 FSSpec* pathSpec,
180 FT_Long* face_index )
182 FT_UNUSED( fontName );
183 FT_UNUSED( pathSpec );
184 FT_UNUSED( face_index );
186 return FT_Err_Unimplemented_Feature;
189 #else
191 FT_EXPORT_DEF( FT_Error )
192 FT_GetFile_From_Mac_Name( const char* fontName,
193 FSSpec* pathSpec,
194 FT_Long* face_index )
196 OptionBits options = kFMUseGlobalScopeOption;
198 FMFontFamilyIterator famIter;
199 OSStatus status = FMCreateFontFamilyIterator( NULL, NULL,
200 options,
201 &famIter );
202 FMFont the_font = 0;
203 FMFontFamily family = 0;
206 *face_index = 0;
207 while ( status == 0 && !the_font )
209 status = FMGetNextFontFamily( &famIter, &family );
210 if ( status == 0 )
212 int stat2;
213 FMFontFamilyInstanceIterator instIter;
214 Str255 famNameStr;
215 char famName[256];
218 /* get the family name */
219 FMGetFontFamilyName( family, famNameStr );
220 CopyPascalStringToC( famNameStr, famName );
222 /* iterate through the styles */
223 FMCreateFontFamilyInstanceIterator( family, &instIter );
225 *face_index = 0;
226 stat2 = 0;
228 while ( stat2 == 0 && !the_font )
230 FMFontStyle style;
231 FMFontSize size;
232 FMFont font;
235 stat2 = FMGetNextFontFamilyInstance( &instIter, &font,
236 &style, &size );
237 if ( stat2 == 0 && size == 0 )
239 char fullName[256];
242 /* build up a complete face name */
243 ft_strcpy( fullName, famName );
244 if ( style & bold )
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 )
252 /* found it! */
253 the_font = font;
255 else
256 ++(*face_index);
260 FMDisposeFontFamilyInstanceIterator( &instIter );
264 FMDisposeFontFamilyIterator( &famIter );
266 if ( the_font )
268 FMGetFontContainer( the_font, pathSpec );
269 return FT_Err_Ok;
271 else
272 return FT_Err_Unknown_File_Format;
275 #endif /* HAVE_QUICKDRAW_CARBON */
278 #if HAVE_ATS
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. */
285 static OSStatus
286 FT_ATSFontGetFileReference( ATSFontRef ats_font_id,
287 FSRef* ats_font_ref )
289 OSStatus err;
291 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
292 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
293 FSSpec spec;
296 err = ATSFontGetFileSpecification( ats_font_id, &spec );
297 if ( noErr == err )
298 err = FSpMakeFSRef( &spec, ats_font_ref );
299 #else
300 err = ATSFontGetFileReference( ats_font_id, ats_font_ref );
301 #endif
303 return err;
307 static FT_Error
308 FT_GetFileRef_From_Mac_ATS_Name( const char* fontName,
309 FSRef* ats_font_ref,
310 FT_Long* face_index )
312 CFStringRef cf_fontName;
313 ATSFontRef ats_font_id;
316 *face_index = 0;
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;
334 FSRef ref2;
337 while ( id2 > 0 )
339 if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) )
340 break;
341 if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) )
342 break;
344 id2--;
346 *face_index = ats_font_id - ( id2 + 1 );
349 return FT_Err_Ok;
352 #endif
354 #if !HAVE_ATS
356 FT_EXPORT_DEF( FT_Error )
357 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName,
358 UInt8* path,
359 UInt32 maxPathSize,
360 FT_Long* face_index )
362 FT_UNUSED( fontName );
363 FT_UNUSED( path );
364 FT_UNUSED( maxPathSize );
365 FT_UNUSED( face_index );
367 return FT_Err_Unimplemented_Feature;
370 #else
372 FT_EXPORT_DEF( FT_Error )
373 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName,
374 UInt8* path,
375 UInt32 maxPathSize,
376 FT_Long* face_index )
378 FSRef ref;
379 FT_Error err;
382 err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
383 if ( FT_Err_Ok != err )
384 return err;
386 if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) )
387 return FT_Err_Unknown_File_Format;
389 return FT_Err_Ok;
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,
399 FSSpec* pathSpec,
400 FT_Long* face_index )
402 FT_UNUSED( fontName );
403 FT_UNUSED( pathSpec );
404 FT_UNUSED( face_index );
406 return FT_Err_Unimplemented_Feature;
409 #else
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,
414 FSSpec* pathSpec,
415 FT_Long* face_index )
417 FSRef ref;
418 FT_Error err;
421 err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
422 if ( FT_Err_Ok != err )
423 return err;
425 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL,
426 pathSpec, NULL ) )
427 return FT_Err_Unknown_File_Format;
429 return FT_Err_Ok;
432 #endif
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;
446 stream->size = 0;
447 stream->base = 0;
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 )
457 FT_FILE* file;
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() */
473 static OSErr
474 FT_FSPathMakeSpec( const UInt8* pathname,
475 FSSpec* spec_p,
476 Boolean isDirectory )
478 const char *p, *q;
479 short vRefNum;
480 long dirID;
481 Str255 nodeName;
482 OSErr err;
483 FT_UNUSED( isDirectory );
486 p = q = (const char *)pathname;
487 dirID = 0;
488 vRefNum = 0;
490 while ( 1 )
492 int len = ft_strlen( p );
495 if ( len > 255 )
496 len = 255;
498 q = p + len;
500 if ( q == p )
501 return 0;
503 if ( 255 < ft_strlen( (char *)pathname ) )
505 while ( p < q && *q != ':' )
506 q--;
509 if ( p < q )
510 *(char *)nodeName = q - p;
511 else if ( ft_strlen( p ) < 256 )
512 *(char *)nodeName = ft_strlen( p );
513 else
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 )
519 return err;
521 vRefNum = spec_p->vRefNum;
522 dirID = spec_p->parID;
524 p = q;
529 static OSErr
530 FT_FSpMakePath( const FSSpec* spec_p,
531 UInt8* path,
532 UInt32 maxPathSize )
534 OSErr err;
535 FSSpec spec = *spec_p;
536 short vRefNum;
537 long dirID;
538 Str255 parDir_name;
541 FT_MEM_SET( path, 0, maxPathSize );
542 while ( 1 )
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;
558 dirID = spec.parID;
559 parDir_name[0] = '\0';
560 err = FSMakeFSSpec( vRefNum, dirID, parDir_name, &spec );
561 if ( noErr != err || dirID == spec.parID )
562 break;
564 return noErr;
567 #endif /* HAVE_FSSPEC && !HAVE_FSREF */
570 static OSErr
571 FT_FSPathMakeRes( const UInt8* pathname,
572 ResFileRefNum* res )
575 #if HAVE_FSREF
577 OSErr err;
578 FSRef ref;
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 );
586 if ( noErr == err )
587 return err;
589 /* fallback to original resource-fork font */
590 *res = FSOpenResFile( &ref, fsRdPerm );
591 err = ResError();
593 #else
595 OSErr err;
596 FSSpec spec;
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 );
605 err = ResError();
607 #endif /* HAVE_FSREF */
609 return err;
613 /* Return the file type for given pathname */
614 static OSType
615 get_file_type_from_path( const UInt8* pathname )
618 #if HAVE_FSREF
620 FSRef ref;
621 FSCatalogInfo info;
624 if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
625 return ( OSType ) 0;
627 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info,
628 NULL, NULL, NULL ) )
629 return ( OSType ) 0;
631 return ((FInfo *)(info.finderInfo))->fdType;
633 #else
635 FSSpec spec;
636 FInfo finfo;
639 if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) )
640 return ( OSType ) 0;
642 if ( noErr != FSpGetFInfo( &spec, &finfo ) )
643 return ( OSType ) 0;
645 return finfo.fdType;
647 #endif /* HAVE_FSREF */
652 /* Given a PostScript font name, create the Macintosh LWFN file name. */
653 static void
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;
664 while ( *q )
666 if ( ft_isupper( *q ) )
668 if ( count )
669 max = 3;
670 count = 0;
672 if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
674 *++p = *q;
675 lwfn_file_name[0]++;
676 count++;
678 q++;
683 static short
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;
694 static short
695 count_faces_scalable( char* fond_data )
697 AsscEntry* assoc;
698 FamRec* fond;
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 );
706 face = 0;
708 for ( i = 0; i < face_all; i++ )
710 if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) )
711 face++;
713 return face;
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!
724 static void
725 parse_fond( char* fond_data,
726 short* have_sfnt,
727 ResID* sfnt_id,
728 Str255 lwfn_file_name,
729 short face_index )
731 AsscEntry* assoc;
732 AsscEntry* base_assoc;
733 FamRec* fond;
736 *sfnt_id = 0;
737 *have_sfnt = 0;
738 lwfn_file_name[0] = 0;
740 fond = (FamRec*)fond_data;
741 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
742 base_assoc = assoc;
744 /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */
745 if ( 47 < face_index )
746 return;
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 )
757 *have_sfnt = 1;
758 *sfnt_id = EndianS16_BtoN( assoc->fontID );
760 else if ( base_assoc->fontSize == 0 )
762 *have_sfnt = 1;
763 *sfnt_id = EndianS16_BtoN( base_assoc->fontID );
767 if ( EndianS32_BtoN( fond->ffStylOff ) )
769 unsigned char* p = (unsigned char*)fond_data;
770 StyleTable* style;
771 unsigned short string_count;
772 char ps_name[256];
773 unsigned char* names[64];
774 int i;
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++ )
785 names[i] = p;
786 p += names[i][0];
787 p++;
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++ )
807 unsigned char* s;
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 );
832 static FT_Error
833 lookup_lwfn_by_fond( const UInt8* path_fond,
834 ConstStr255Param base_lwfn,
835 UInt8* path_lwfn,
836 int path_size )
839 #if HAVE_FSREF
841 FSRef ref, par_ref;
842 int dirname_len;
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, "/" );
864 else
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;
878 return FT_Err_Ok;
880 #else
882 int i;
883 FSSpec spec;
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] )
894 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';
904 else
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;
913 return FT_Err_Ok;
915 #endif /* HAVE_FSREF */
920 static short
921 count_faces( Handle fond,
922 const UInt8* pathname )
924 ResID sfnt_id;
925 short have_sfnt, have_lwfn;
926 Str255 lwfn_file_name;
927 UInt8 buff[PATH_MAX];
928 FT_Error err;
929 short num_faces;
932 have_sfnt = have_lwfn = 0;
934 HLock( fond );
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 )
942 have_lwfn = 1;
945 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
946 num_faces = 1;
947 else
948 num_faces = count_faces_scalable( *fond );
950 HUnlock( fond );
951 return num_faces;
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. */
960 static FT_Error
961 read_lwfn( FT_Memory memory,
962 ResFileRefNum res,
963 FT_Byte** pfb_data,
964 FT_ULong* size )
966 FT_Error error = FT_Err_Ok;
967 ResID res_id;
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;
972 Handle post_data;
973 char code, last_code;
976 UseResFile( res );
978 /* First pass: load all POST resources, and determine the size of */
979 /* the output buffer. */
980 res_id = 501;
981 last_code = -1;
983 for (;;)
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 )
993 if ( code == 5 )
994 total_size += 2; /* just the end code */
995 else
996 total_size += 6; /* code + 4 bytes chunk length */
999 total_size += GetHandleSize( post_data ) - 2;
1000 last_code = code;
1002 /* detect integer overflows */
1003 if ( total_size < old_total_size )
1005 error = FT_Err_Array_Too_Large;
1006 goto Error;
1009 old_total_size = total_size;
1012 if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
1013 goto Error;
1015 /* Second pass: append all POST data to the buffer, add PFB fields. */
1016 /* Glue all consecutive chunks of the same type together. */
1017 p = buffer;
1018 res_id = 501;
1019 last_code = -1;
1020 pfb_chunk_size = 0;
1022 for (;;)
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 );
1043 pfb_chunk_size = 0;
1046 *p++ = 0x80;
1047 if ( code == 5 )
1048 *p++ = 0x03; /* the end */
1049 else if ( code == 2 )
1050 *p++ = 0x02; /* binary segment */
1051 else
1052 *p++ = 0x01; /* ASCII segment */
1054 if ( code != 5 )
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;
1063 p += post_size;
1064 last_code = code;
1067 *pfb_data = buffer;
1068 *size = total_size;
1070 Error:
1071 CloseResFile( res );
1072 return error;
1076 /* Create a new FT_Face from a file spec to an LWFN file. */
1077 static FT_Error
1078 FT_New_Face_From_LWFN( FT_Library library,
1079 const UInt8* pathname,
1080 FT_Long face_index,
1081 FT_Face* aface )
1083 FT_Byte* pfb_data;
1084 FT_ULong pfb_size;
1085 FT_Error error;
1086 ResFileRefNum res;
1089 if ( noErr != FT_FSPathMakeRes( pathname, &res ) )
1090 return FT_Err_Cannot_Open_Resource;
1092 pfb_data = NULL;
1093 pfb_size = 0;
1094 error = read_lwfn( library->memory, res, &pfb_data, &pfb_size );
1095 CloseResFile( res ); /* PFB is already loaded, useless anymore */
1096 if ( error )
1097 return error;
1099 return open_face_from_buffer( library,
1100 pfb_data,
1101 pfb_size,
1102 face_index,
1103 "type1",
1104 aface );
1108 /* Create a new FT_Face from an SFNT resource, specified by res ID. */
1109 static FT_Error
1110 FT_New_Face_From_SFNT( FT_Library library,
1111 ResID sfnt_id,
1112 FT_Long face_index,
1113 FT_Face* aface )
1115 Handle sfnt = NULL;
1116 FT_Byte* sfnt_data;
1117 size_t sfnt_size;
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 );
1124 if ( sfnt == NULL )
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 );
1131 return error;
1134 HLock( sfnt );
1135 ft_memcpy( sfnt_data, *sfnt, sfnt_size );
1136 HUnlock( sfnt );
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 );
1142 if ( is_sfnt_ps )
1144 FT_Stream stream;
1147 if ( FT_NEW( stream ) )
1148 goto Try_OpenType;
1150 FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size );
1151 if ( !open_face_PS_from_sfnt_stream( library,
1152 stream,
1153 face_index,
1154 0, NULL,
1155 aface ) )
1157 FT_Stream_Close( stream );
1158 FT_FREE( stream );
1159 FT_FREE( sfnt_data );
1160 goto Exit;
1163 FT_FREE( stream );
1165 Try_OpenType:
1166 error = open_face_from_buffer( library,
1167 sfnt_data,
1168 sfnt_size,
1169 face_index,
1170 is_cff ? "cff" : "truetype",
1171 aface );
1172 Exit:
1173 return error;
1177 /* Create a new FT_Face from a file spec to a suitcase file. */
1178 static FT_Error
1179 FT_New_Face_From_Suitcase( FT_Library library,
1180 const UInt8* pathname,
1181 FT_Long face_index,
1182 FT_Face* aface )
1184 FT_Error error = FT_Err_Cannot_Open_Resource;
1185 ResFileRefNum res_ref;
1186 ResourceIndex res_index;
1187 Handle fond;
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 );
1195 if ( ResError() )
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 );
1202 if ( ResError() )
1203 break;
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;
1217 return error;
1221 /* documentation is in ftmac.h */
1223 FT_EXPORT_DEF( FT_Error )
1224 FT_New_Face_From_FOND( FT_Library library,
1225 Handle fond,
1226 FT_Long face_index,
1227 FT_Face* aface )
1229 short have_sfnt, have_lwfn = 0;
1230 ResID sfnt_id, fond_id;
1231 OSType fond_type;
1232 Str255 fond_name;
1233 Str255 lwfn_file_name;
1234 UInt8 path_lwfn[PATH_MAX];
1235 OSErr err;
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;
1243 HLock( fond );
1244 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
1245 HUnlock( fond );
1247 if ( lwfn_file_name[0] )
1249 ResFileRefNum res;
1252 res = HomeResFile( fond );
1253 if ( noErr != ResError() )
1254 goto found_no_lwfn_file;
1256 #if HAVE_FSREF
1259 UInt8 path_fond[PATH_MAX];
1260 FSRef ref;
1263 err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum,
1264 NULL, NULL, NULL, &ref, NULL );
1265 if ( noErr != err )
1266 goto found_no_lwfn_file;
1268 err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) );
1269 if ( noErr != err )
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 )
1275 have_lwfn = 1;
1278 #elif HAVE_FSSPEC
1281 UInt8 path_fond[PATH_MAX];
1282 FCBPBRec pb;
1283 Str255 fond_file_name;
1284 FSSpec spec;
1287 FT_MEM_SET( &spec, 0, sizeof ( FSSpec ) );
1288 FT_MEM_SET( &pb, 0, sizeof ( FCBPBRec ) );
1290 pb.ioNamePtr = fond_file_name;
1291 pb.ioVRefNum = 0;
1292 pb.ioRefNum = res;
1293 pb.ioFCBIndx = 0;
1295 err = PBGetFCBInfoSync( &pb );
1296 if ( noErr != err )
1297 goto found_no_lwfn_file;
1299 err = FSMakeFSSpec( pb.ioFCBVRefNum, pb.ioFCBParID,
1300 fond_file_name, &spec );
1301 if ( noErr != err )
1302 goto found_no_lwfn_file;
1304 err = FT_FSpMakePath( &spec, path_fond, sizeof ( path_fond ) );
1305 if ( noErr != err )
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 )
1311 have_lwfn = 1;
1314 #endif /* HAVE_FSREF, HAVE_FSSPEC */
1318 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
1319 error = FT_New_Face_From_LWFN( library,
1320 path_lwfn,
1321 face_index,
1322 aface );
1323 else
1324 error = FT_Err_Unknown_File_Format;
1326 found_no_lwfn_file:
1327 if ( have_sfnt && FT_Err_Ok != error )
1328 error = FT_New_Face_From_SFNT( library,
1329 sfnt_id,
1330 face_index,
1331 aface );
1333 return error;
1337 /* Common function to load a new FT_Face from a resource file. */
1338 static FT_Error
1339 FT_New_Face_From_Resource( FT_Library library,
1340 const UInt8* pathname,
1341 FT_Long face_index,
1342 FT_Face* aface )
1344 OSType file_type;
1345 FT_Error error;
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 );
1358 if ( error == 0 )
1359 return error;
1361 /* let it fall through to normal loader (.ttf, .otf, etc.); */
1362 /* we signal this by returning no error and no FT_Face */
1363 *aface = NULL;
1364 return 0;
1368 /*************************************************************************/
1369 /* */
1370 /* <Function> */
1371 /* FT_New_Face */
1372 /* */
1373 /* <Description> */
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. */
1378 /* */
1379 FT_EXPORT_DEF( FT_Error )
1380 FT_New_Face( FT_Library library,
1381 const char* pathname,
1382 FT_Long face_index,
1383 FT_Face* aface )
1385 FT_Open_Args args;
1386 FT_Error error;
1389 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
1390 if ( !pathname )
1391 return FT_Err_Invalid_Argument;
1393 error = FT_Err_Ok;
1394 *aface = NULL;
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 )
1400 return error;
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 /*************************************************************************/
1410 /* */
1411 /* <Function> */
1412 /* FT_New_Face_From_FSRef */
1413 /* */
1414 /* <Description> */
1415 /* FT_New_Face_From_FSRef is identical to FT_New_Face except it */
1416 /* accepts an FSRef instead of a path. */
1417 /* */
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,
1422 const FSRef* ref,
1423 FT_Long face_index,
1424 FT_Face* aface )
1427 #if !HAVE_FSREF
1429 FT_UNUSED( library );
1430 FT_UNUSED( ref );
1431 FT_UNUSED( face_index );
1432 FT_UNUSED( aface );
1434 return FT_Err_Unimplemented_Feature;
1436 #else
1438 FT_Error error;
1439 FT_Open_Args args;
1440 OSErr err;
1441 UInt8 pathname[PATH_MAX];
1444 if ( !ref )
1445 return FT_Err_Invalid_Argument;
1447 err = FSRefMakePath( ref, pathname, sizeof ( pathname ) );
1448 if ( err )
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 )
1453 return error;
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 /*************************************************************************/
1466 /* */
1467 /* <Function> */
1468 /* FT_New_Face_From_FSSpec */
1469 /* */
1470 /* <Description> */
1471 /* FT_New_Face_From_FSSpec is identical to FT_New_Face except it */
1472 /* accepts an FSSpec instead of a path. */
1473 /* */
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,
1478 const FSSpec* spec,
1479 FT_Long face_index,
1480 FT_Face* aface )
1483 #if HAVE_FSREF
1485 FSRef ref;
1488 if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr )
1489 return FT_Err_Invalid_Argument;
1490 else
1491 return FT_New_Face_From_FSRef( library, &ref, face_index, aface );
1493 #elif HAVE_FSSPEC
1495 FT_Error error;
1496 FT_Open_Args args;
1497 OSErr err;
1498 UInt8 pathname[PATH_MAX];
1501 if ( !spec )
1502 return FT_Err_Invalid_Argument;
1504 err = FT_FSpMakePath( spec, pathname, sizeof ( pathname ) );
1505 if ( err )
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 )
1510 return error;
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 );
1517 #else
1519 FT_UNUSED( library );
1520 FT_UNUSED( spec );
1521 FT_UNUSED( face_index );
1522 FT_UNUSED( aface );
1524 return FT_Err_Unimplemented_Feature;
1526 #endif /* HAVE_FSREF, HAVE_FSSPEC */
1531 /* END */