Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / modules / freetype2 / src / base / ftmac.c
blob4f4ab9d8ee755b7c36a7caaa986a97738810b60d
1 /***************************************************************************/
2 /* */
3 /* ftmac.c */
4 /* */
5 /* Mac FOND support. Written by just@letterror.com. */
6 /* Heavily modified by mpsuzuki, George Williams, and Sean McBride. */
7 /* */
8 /* This file is for Mac OS X only; see builds/mac/ftoldmac.c for */
9 /* classic platforms built by MPW. */
10 /* */
11 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by */
12 /* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */
13 /* */
14 /* This file is part of the FreeType project, and may only be used, */
15 /* modified, and distributed under the terms of the FreeType project */
16 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
17 /* this file you indicate that you have read the license and */
18 /* understand and accept it fully. */
19 /* */
20 /***************************************************************************/
24 Notes
26 Mac suitcase files can (and often do!) contain multiple fonts. To
27 support this I use the face_index argument of FT_(Open|New)_Face()
28 functions, and pretend the suitcase file is a collection.
30 Warning: fbit and NFNT bitmap resources are not supported yet. In old
31 sfnt fonts, bitmap glyph data for each size is stored in each `NFNT'
32 resources instead of the `bdat' table in the sfnt resource. Therefore,
33 face->num_fixed_sizes is set to 0, because bitmap data in `NFNT'
34 resource is unavailable at present.
36 The Mac FOND support works roughly like this:
38 - Check whether the offered stream points to a Mac suitcase file. This
39 is done by checking the file type: it has to be 'FFIL' or 'tfil'. The
40 stream that gets passed to our init_face() routine is a stdio stream,
41 which isn't usable for us, since the FOND resources live in the
42 resource fork. So we just grab the stream->pathname field.
44 - Read the FOND resource into memory, then check whether there is a
45 TrueType font and/or(!) a Type 1 font available.
47 - If there is a Type 1 font available (as a separate `LWFN' file), read
48 its data into memory, massage it slightly so it becomes PFB data, wrap
49 it into a memory stream, load the Type 1 driver and delegate the rest
50 of the work to it by calling FT_Open_Face(). (XXX TODO: after this
51 has been done, the kerning data from the FOND resource should be
52 appended to the face: On the Mac there are usually no AFM files
53 available. However, this is tricky since we need to map Mac char
54 codes to ps glyph names to glyph ID's...)
56 - If there is a TrueType font (an `sfnt' resource), read it into memory,
57 wrap it into a memory stream, load the TrueType driver and delegate
58 the rest of the work to it, by calling FT_Open_Face().
60 - Some suitcase fonts (notably Onyx) might point the `LWFN' file to
61 itself, even though it doesn't contains `POST' resources. To handle
62 this special case without opening the file an extra time, we just
63 ignore errors from the `LWFN' and fallback to the `sfnt' if both are
64 available.
68 #include <ft2build.h>
69 #include FT_FREETYPE_H
70 #include FT_INTERNAL_STREAM_H
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
80 /* The ResourceIndex type was available SDKs on 10.5 */
81 #ifndef HAVE_TYPE_RESOURCE_INDEX
82 typedef short ResourceIndex;
83 #endif
85 #include <CoreServices/CoreServices.h>
86 #include <ApplicationServices/ApplicationServices.h>
87 #include <sys/syslimits.h> /* PATH_MAX */
89 #define FT_DEPRECATED_ATTRIBUTE
91 #include FT_MAC_H
93 /* undefine blocking-macros in ftmac.h */
94 #undef FT_GetFile_From_Mac_Name( a, b, c )
95 #undef FT_GetFile_From_Mac_ATS_Name( a, b, c )
96 #undef FT_New_Face_From_FOND( a, b, c, d )
97 #undef FT_New_Face_From_FSSpec( a, b, c, d )
98 #undef FT_New_Face_From_FSRef( a, b, c, d )
100 #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */
101 #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault
102 #endif
105 /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
106 TrueType in case *both* are available (this is not common,
107 but it *is* possible). */
108 #ifndef PREFER_LWFN
109 #define PREFER_LWFN 1
110 #endif
113 /* This function is deprecated because FSSpec is deprecated in Mac OS X */
114 FT_EXPORT_DEF( FT_Error )
115 FT_GetFile_From_Mac_Name( const char* fontName,
116 FSSpec* pathSpec,
117 FT_Long* face_index )
119 FT_UNUSED( fontName );
120 FT_UNUSED( pathSpec );
121 FT_UNUSED( face_index );
123 return FT_Err_Unimplemented_Feature;
127 /* Private function. */
128 /* The FSSpec type has been discouraged for a long time, */
129 /* unfortunately an FSRef replacement API for */
130 /* ATSFontGetFileSpecification() is only available in */
131 /* Mac OS X 10.5 and later. */
132 static OSStatus
133 FT_ATSFontGetFileReference( ATSFontRef ats_font_id,
134 FSRef* ats_font_ref )
136 #if defined( MAC_OS_X_VERSION_10_5 ) && \
137 ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
139 OSStatus err;
141 err = ATSFontGetFileReference( ats_font_id, ats_font_ref );
143 return err;
144 #elif __LP64__ /* No 64bit Carbon API on legacy platforms */
145 FT_UNUSED( ats_font_id );
146 FT_UNUSED( ats_font_ref );
149 return fnfErr;
150 #else /* 32bit Carbon API on legacy platforms */
151 OSStatus err;
152 FSSpec spec;
155 err = ATSFontGetFileSpecification( ats_font_id, &spec );
156 if ( noErr == err )
157 err = FSpMakeFSRef( &spec, ats_font_ref );
159 return err;
160 #endif
164 static FT_Error
165 FT_GetFileRef_From_Mac_ATS_Name( const char* fontName,
166 FSRef* ats_font_ref,
167 FT_Long* face_index )
169 CFStringRef cf_fontName;
170 ATSFontRef ats_font_id;
173 *face_index = 0;
175 cf_fontName = CFStringCreateWithCString( NULL, fontName,
176 kCFStringEncodingMacRoman );
177 ats_font_id = ATSFontFindFromName( cf_fontName,
178 kATSOptionFlagsUnRestrictedScope );
179 CFRelease( cf_fontName );
181 if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL )
182 return FT_Err_Unknown_File_Format;
184 if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) )
185 return FT_Err_Unknown_File_Format;
187 /* face_index calculation by searching preceding fontIDs */
188 /* with same FSRef */
190 ATSFontRef id2 = ats_font_id - 1;
191 FSRef ref2;
194 while ( id2 > 0 )
196 if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) )
197 break;
198 if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) )
199 break;
201 id2 --;
203 *face_index = ats_font_id - ( id2 + 1 );
206 return FT_Err_Ok;
210 FT_EXPORT_DEF( FT_Error )
211 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName,
212 UInt8* path,
213 UInt32 maxPathSize,
214 FT_Long* face_index )
216 FSRef ref;
217 FT_Error err;
220 err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
221 if ( FT_Err_Ok != err )
222 return err;
224 if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) )
225 return FT_Err_Unknown_File_Format;
227 return FT_Err_Ok;
231 /* This function is deprecated because FSSpec is deprecated in Mac OS X */
232 FT_EXPORT_DEF( FT_Error )
233 FT_GetFile_From_Mac_ATS_Name( const char* fontName,
234 FSSpec* pathSpec,
235 FT_Long* face_index )
237 #if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \
238 ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) )
239 FT_UNUSED( fontName );
240 FT_UNUSED( pathSpec );
241 FT_UNUSED( face_index );
243 return FT_Err_Unimplemented_Feature;
244 #else
245 FSRef ref;
246 FT_Error err;
249 err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
250 if ( FT_Err_Ok != err )
251 return err;
253 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL,
254 pathSpec, NULL ) )
255 return FT_Err_Unknown_File_Format;
257 return FT_Err_Ok;
258 #endif
262 static OSErr
263 FT_FSPathMakeRes( const UInt8* pathname,
264 ResFileRefNum* res )
266 OSErr err;
267 FSRef ref;
270 if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
271 return FT_Err_Cannot_Open_Resource;
273 /* at present, no support for dfont format */
274 err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res );
275 if ( noErr == err )
276 return err;
278 /* fallback to original resource-fork font */
279 *res = FSOpenResFile( &ref, fsRdPerm );
280 err = ResError();
282 return err;
286 /* Return the file type for given pathname */
287 static OSType
288 get_file_type_from_path( const UInt8* pathname )
290 FSRef ref;
291 FSCatalogInfo info;
294 if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
295 return ( OSType ) 0;
297 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info,
298 NULL, NULL, NULL ) )
299 return ( OSType ) 0;
301 return ((FInfo *)(info.finderInfo))->fdType;
305 /* Given a PostScript font name, create the Macintosh LWFN file name. */
306 static void
307 create_lwfn_name( char* ps_name,
308 Str255 lwfn_file_name )
310 int max = 5, count = 0;
311 FT_Byte* p = lwfn_file_name;
312 FT_Byte* q = (FT_Byte*)ps_name;
315 lwfn_file_name[0] = 0;
317 while ( *q )
319 if ( ft_isupper( *q ) )
321 if ( count )
322 max = 3;
323 count = 0;
325 if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
327 *++p = *q;
328 lwfn_file_name[0]++;
329 count++;
331 q++;
336 static short
337 count_faces_sfnt( char* fond_data )
339 /* The count is 1 greater than the value in the FOND. */
340 /* Isn't that cute? :-) */
342 return EndianS16_BtoN( *( (short*)( fond_data +
343 sizeof ( FamRec ) ) ) ) + 1;
347 static short
348 count_faces_scalable( char* fond_data )
350 AsscEntry* assoc;
351 FamRec* fond;
352 short i, face, face_all;
355 fond = (FamRec*)fond_data;
356 face_all = EndianS16_BtoN( *( (short *)( fond_data +
357 sizeof ( FamRec ) ) ) ) + 1;
358 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
359 face = 0;
361 for ( i = 0; i < face_all; i++ )
363 if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) )
364 face++;
366 return face;
370 /* Look inside the FOND data, answer whether there should be an SFNT
371 resource, and answer the name of a possible LWFN Type 1 file.
373 Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
374 to load a face OTHER than the first one in the FOND!
378 static void
379 parse_fond( char* fond_data,
380 short* have_sfnt,
381 ResID* sfnt_id,
382 Str255 lwfn_file_name,
383 short face_index )
385 AsscEntry* assoc;
386 AsscEntry* base_assoc;
387 FamRec* fond;
390 *sfnt_id = 0;
391 *have_sfnt = 0;
392 lwfn_file_name[0] = 0;
394 fond = (FamRec*)fond_data;
395 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
396 base_assoc = assoc;
398 /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */
399 if ( 47 < face_index )
400 return;
402 /* Let's do a little range checking before we get too excited here */
403 if ( face_index < count_faces_sfnt( fond_data ) )
405 assoc += face_index; /* add on the face_index! */
407 /* if the face at this index is not scalable,
408 fall back to the first one (old behavior) */
409 if ( EndianS16_BtoN( assoc->fontSize ) == 0 )
411 *have_sfnt = 1;
412 *sfnt_id = EndianS16_BtoN( assoc->fontID );
414 else if ( base_assoc->fontSize == 0 )
416 *have_sfnt = 1;
417 *sfnt_id = EndianS16_BtoN( base_assoc->fontID );
421 if ( EndianS32_BtoN( fond->ffStylOff ) )
423 unsigned char* p = (unsigned char*)fond_data;
424 StyleTable* style;
425 unsigned short string_count;
426 char ps_name[256];
427 unsigned char* names[64];
428 int i;
431 p += EndianS32_BtoN( fond->ffStylOff );
432 style = (StyleTable*)p;
433 p += sizeof ( StyleTable );
434 string_count = EndianS16_BtoN( *(short*)(p) );
435 p += sizeof ( short );
437 for ( i = 0; i < string_count && i < 64; i++ )
439 names[i] = p;
440 p += names[i][0];
441 p++;
445 size_t ps_name_len = (size_t)names[0][0];
448 if ( ps_name_len != 0 )
450 ft_memcpy(ps_name, names[0] + 1, ps_name_len);
451 ps_name[ps_name_len] = 0;
453 if ( style->indexes[face_index] > 1 &&
454 style->indexes[face_index] <= FT_MIN( string_count, 64 ) )
456 unsigned char* suffixes = names[style->indexes[face_index] - 1];
459 for ( i = 1; i <= suffixes[0]; i++ )
461 unsigned char* s;
462 size_t j = suffixes[i] - 1;
465 if ( j < string_count && ( s = names[j] ) != NULL )
467 size_t s_len = (size_t)s[0];
470 if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
472 ft_memcpy( ps_name + ps_name_len, s + 1, s_len );
473 ps_name_len += s_len;
474 ps_name[ps_name_len] = 0;
481 create_lwfn_name( ps_name, lwfn_file_name );
486 static FT_Error
487 lookup_lwfn_by_fond( const UInt8* path_fond,
488 ConstStr255Param base_lwfn,
489 UInt8* path_lwfn,
490 size_t path_size )
492 FSRef ref, par_ref;
493 size_t dirname_len;
496 /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */
497 /* We should not extract parent directory by string manipulation. */
499 if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) )
500 return FT_Err_Invalid_Argument;
502 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
503 NULL, NULL, NULL, &par_ref ) )
504 return FT_Err_Invalid_Argument;
506 if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) )
507 return FT_Err_Invalid_Argument;
509 if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size )
510 return FT_Err_Invalid_Argument;
512 /* now we have absolute dirname in path_lwfn */
513 ft_strcat( (char *)path_lwfn, "/" );
514 dirname_len = ft_strlen( (char *)path_lwfn );
515 ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 );
516 path_lwfn[dirname_len + base_lwfn[0]] = '\0';
518 if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) )
519 return FT_Err_Cannot_Open_Resource;
521 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
522 NULL, NULL, NULL, NULL ) )
523 return FT_Err_Cannot_Open_Resource;
525 return FT_Err_Ok;
529 static short
530 count_faces( Handle fond,
531 const UInt8* pathname )
533 ResID sfnt_id;
534 short have_sfnt, have_lwfn;
535 Str255 lwfn_file_name;
536 UInt8 buff[PATH_MAX];
537 FT_Error err;
538 short num_faces;
541 have_sfnt = have_lwfn = 0;
543 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 );
545 if ( lwfn_file_name[0] )
547 err = lookup_lwfn_by_fond( pathname, lwfn_file_name,
548 buff, sizeof ( buff ) );
549 if ( FT_Err_Ok == err )
550 have_lwfn = 1;
553 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
554 num_faces = 1;
555 else
556 num_faces = count_faces_scalable( *fond );
558 return num_faces;
562 /* Read Type 1 data from the POST resources inside the LWFN file,
563 return a PFB buffer. This is somewhat convoluted because the FT2
564 PFB parser wants the ASCII header as one chunk, and the LWFN
565 chunks are often not organized that way, so we glue chunks
566 of the same type together. */
567 static FT_Error
568 read_lwfn( FT_Memory memory,
569 ResFileRefNum res,
570 FT_Byte** pfb_data,
571 FT_ULong* size )
573 FT_Error error = FT_Err_Ok;
574 ResID res_id;
575 unsigned char *buffer, *p, *size_p = NULL;
576 FT_ULong total_size = 0;
577 FT_ULong old_total_size = 0;
578 FT_ULong post_size, pfb_chunk_size;
579 Handle post_data;
580 char code, last_code;
583 UseResFile( res );
585 /* First pass: load all POST resources, and determine the size of */
586 /* the output buffer. */
587 res_id = 501;
588 last_code = -1;
590 for (;;)
592 post_data = Get1Resource( FT_MAKE_TAG( 'P', 'O', 'S', 'T' ),
593 res_id++ );
594 if ( post_data == NULL )
595 break; /* we are done */
597 code = (*post_data)[0];
599 if ( code != last_code )
601 if ( code == 5 )
602 total_size += 2; /* just the end code */
603 else
604 total_size += 6; /* code + 4 bytes chunk length */
607 total_size += GetHandleSize( post_data ) - 2;
608 last_code = code;
610 /* detect integer overflows */
611 if ( total_size < old_total_size )
613 error = FT_Err_Array_Too_Large;
614 goto Error;
617 old_total_size = total_size;
620 if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
621 goto Error;
623 /* Second pass: append all POST data to the buffer, add PFB fields. */
624 /* Glue all consecutive chunks of the same type together. */
625 p = buffer;
626 res_id = 501;
627 last_code = -1;
628 pfb_chunk_size = 0;
630 for (;;)
632 post_data = Get1Resource( FT_MAKE_TAG( 'P', 'O', 'S', 'T' ),
633 res_id++ );
634 if ( post_data == NULL )
635 break; /* we are done */
637 post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
638 code = (*post_data)[0];
640 if ( code != last_code )
642 if ( last_code != -1 )
644 /* we are done adding a chunk, fill in the size field */
645 if ( size_p != NULL )
647 *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF );
648 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF );
649 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
650 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
652 pfb_chunk_size = 0;
655 *p++ = 0x80;
656 if ( code == 5 )
657 *p++ = 0x03; /* the end */
658 else if ( code == 2 )
659 *p++ = 0x02; /* binary segment */
660 else
661 *p++ = 0x01; /* ASCII segment */
663 if ( code != 5 )
665 size_p = p; /* save for later */
666 p += 4; /* make space for size field */
670 ft_memcpy( p, *post_data + 2, post_size );
671 pfb_chunk_size += post_size;
672 p += post_size;
673 last_code = code;
676 *pfb_data = buffer;
677 *size = total_size;
679 Error:
680 CloseResFile( res );
681 return error;
685 /* Finalizer for a memory stream; gets called by FT_Done_Face().
686 It frees the memory it uses. */
687 static void
688 memory_stream_close( FT_Stream stream )
690 FT_Memory memory = stream->memory;
693 FT_FREE( stream->base );
695 stream->size = 0;
696 stream->base = 0;
697 stream->close = 0;
701 /* Create a new memory stream from a buffer and a size. */
702 static FT_Error
703 new_memory_stream( FT_Library library,
704 FT_Byte* base,
705 FT_ULong size,
706 FT_Stream_CloseFunc close,
707 FT_Stream* astream )
709 FT_Error error;
710 FT_Memory memory;
711 FT_Stream stream;
714 if ( !library )
715 return FT_Err_Invalid_Library_Handle;
717 if ( !base )
718 return FT_Err_Invalid_Argument;
720 *astream = 0;
721 memory = library->memory;
722 if ( FT_NEW( stream ) )
723 goto Exit;
725 FT_Stream_OpenMemory( stream, base, size );
727 stream->close = close;
729 *astream = stream;
731 Exit:
732 return error;
736 /* Create a new FT_Face given a buffer and a driver name. */
737 static FT_Error
738 open_face_from_buffer( FT_Library library,
739 FT_Byte* base,
740 FT_ULong size,
741 FT_Long face_index,
742 const char* driver_name,
743 FT_Face* aface )
745 FT_Open_Args args;
746 FT_Error error;
747 FT_Stream stream;
748 FT_Memory memory = library->memory;
751 error = new_memory_stream( library,
752 base,
753 size,
754 memory_stream_close,
755 &stream );
756 if ( error )
758 FT_FREE( base );
759 return error;
762 args.flags = FT_OPEN_STREAM;
763 args.stream = stream;
764 if ( driver_name )
766 args.flags = args.flags | FT_OPEN_DRIVER;
767 args.driver = FT_Get_Module( library, driver_name );
770 /* At this point, face_index has served its purpose; */
771 /* whoever calls this function has already used it to */
772 /* locate the correct font data. We should not propagate */
773 /* this index to FT_Open_Face() (unless it is negative). */
775 if ( face_index > 0 )
776 face_index = 0;
778 error = FT_Open_Face( library, &args, face_index, aface );
779 if ( error == FT_Err_Ok )
780 (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
781 else
782 FT_Stream_Free( stream, 0 );
784 return error;
788 /* Create a new FT_Face from a file spec to an LWFN file. */
789 static FT_Error
790 FT_New_Face_From_LWFN( FT_Library library,
791 const UInt8* pathname,
792 FT_Long face_index,
793 FT_Face* aface )
795 FT_Byte* pfb_data;
796 FT_ULong pfb_size;
797 FT_Error error;
798 ResFileRefNum res;
801 if ( noErr != FT_FSPathMakeRes( pathname, &res ) )
802 return FT_Err_Cannot_Open_Resource;
804 pfb_data = NULL;
805 pfb_size = 0;
806 error = read_lwfn( library->memory, res, &pfb_data, &pfb_size );
807 CloseResFile( res ); /* PFB is already loaded, useless anymore */
808 if ( error )
809 return error;
811 return open_face_from_buffer( library,
812 pfb_data,
813 pfb_size,
814 face_index,
815 "type1",
816 aface );
820 /* Create a new FT_Face from an SFNT resource, specified by res ID. */
821 static FT_Error
822 FT_New_Face_From_SFNT( FT_Library library,
823 ResID sfnt_id,
824 FT_Long face_index,
825 FT_Face* aface )
827 Handle sfnt = NULL;
828 FT_Byte* sfnt_data;
829 size_t sfnt_size;
830 FT_Error error = FT_Err_Ok;
831 FT_Memory memory = library->memory;
832 int is_cff;
835 sfnt = GetResource( FT_MAKE_TAG( 's', 'f', 'n', 't' ), sfnt_id );
836 if ( sfnt == NULL )
837 return FT_Err_Invalid_Handle;
839 sfnt_size = (FT_ULong)GetHandleSize( sfnt );
840 if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
842 ReleaseResource( sfnt );
843 return error;
846 ft_memcpy( sfnt_data, *sfnt, sfnt_size );
847 ReleaseResource( sfnt );
849 is_cff = sfnt_size > 4 && sfnt_data[0] == 'O' &&
850 sfnt_data[1] == 'T' &&
851 sfnt_data[2] == 'T' &&
852 sfnt_data[3] == 'O';
854 return open_face_from_buffer( library,
855 sfnt_data,
856 sfnt_size,
857 face_index,
858 is_cff ? "cff" : "truetype",
859 aface );
863 /* Create a new FT_Face from a file spec to a suitcase file. */
864 static FT_Error
865 FT_New_Face_From_Suitcase( FT_Library library,
866 const UInt8* pathname,
867 FT_Long face_index,
868 FT_Face* aface )
870 FT_Error error = FT_Err_Cannot_Open_Resource;
871 ResFileRefNum res_ref;
872 ResourceIndex res_index;
873 Handle fond;
874 short num_faces_in_res, num_faces_in_fond;
877 if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) )
878 return FT_Err_Cannot_Open_Resource;
880 UseResFile( res_ref );
881 if ( ResError() )
882 return FT_Err_Cannot_Open_Resource;
884 num_faces_in_res = 0;
885 for ( res_index = 1; ; ++res_index )
887 fond = Get1IndResource( FT_MAKE_TAG( 'F', 'O', 'N', 'D' ),
888 res_index );
889 if ( ResError() )
890 break;
892 num_faces_in_fond = count_faces( fond, pathname );
893 num_faces_in_res += num_faces_in_fond;
895 if ( 0 <= face_index && face_index < num_faces_in_fond && error )
896 error = FT_New_Face_From_FOND( library, fond, face_index, aface );
898 face_index -= num_faces_in_fond;
901 CloseResFile( res_ref );
902 if ( FT_Err_Ok == error && NULL != aface && NULL != *aface )
903 (*aface)->num_faces = num_faces_in_res;
904 return error;
908 /* documentation is in ftmac.h */
910 FT_EXPORT_DEF( FT_Error )
911 FT_New_Face_From_FOND( FT_Library library,
912 Handle fond,
913 FT_Long face_index,
914 FT_Face* aface )
916 short have_sfnt, have_lwfn = 0;
917 ResID sfnt_id, fond_id;
918 OSType fond_type;
919 Str255 fond_name;
920 Str255 lwfn_file_name;
921 UInt8 path_lwfn[PATH_MAX];
922 OSErr err;
923 FT_Error error = FT_Err_Ok;
926 GetResInfo( fond, &fond_id, &fond_type, fond_name );
927 if ( ResError() != noErr || fond_type != FT_MAKE_TAG( 'F', 'O', 'N', 'D' ) )
928 return FT_Err_Invalid_File_Format;
930 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
932 if ( lwfn_file_name[0] )
934 ResFileRefNum res;
937 res = HomeResFile( fond );
938 if ( noErr != ResError() )
939 goto found_no_lwfn_file;
942 UInt8 path_fond[PATH_MAX];
943 FSRef ref;
946 err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum,
947 NULL, NULL, NULL, &ref, NULL );
948 if ( noErr != err )
949 goto found_no_lwfn_file;
951 err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) );
952 if ( noErr != err )
953 goto found_no_lwfn_file;
955 error = lookup_lwfn_by_fond( path_fond, lwfn_file_name,
956 path_lwfn, sizeof ( path_lwfn ) );
957 if ( FT_Err_Ok == error )
958 have_lwfn = 1;
962 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
963 error = FT_New_Face_From_LWFN( library,
964 path_lwfn,
965 face_index,
966 aface );
967 else
968 error = FT_Err_Unknown_File_Format;
970 found_no_lwfn_file:
971 if ( have_sfnt && FT_Err_Ok != error )
972 error = FT_New_Face_From_SFNT( library,
973 sfnt_id,
974 face_index,
975 aface );
977 return error;
981 /* Common function to load a new FT_Face from a resource file. */
982 static FT_Error
983 FT_New_Face_From_Resource( FT_Library library,
984 const UInt8* pathname,
985 FT_Long face_index,
986 FT_Face* aface )
988 OSType file_type;
989 FT_Error error;
992 /* LWFN is a (very) specific file format, check for it explicitly */
993 file_type = get_file_type_from_path( pathname );
994 if ( file_type == FT_MAKE_TAG( 'L', 'W', 'F', 'N' ) )
995 return FT_New_Face_From_LWFN( library, pathname, face_index, aface );
997 /* Otherwise the file type doesn't matter (there are more than */
998 /* `FFIL' and `tfil'). Just try opening it as a font suitcase; */
999 /* if it works, fine. */
1001 error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface );
1002 if ( error == 0 )
1003 return error;
1005 /* let it fall through to normal loader (.ttf, .otf, etc.); */
1006 /* we signal this by returning no error and no FT_Face */
1007 *aface = NULL;
1008 return 0;
1012 /*************************************************************************/
1013 /* */
1014 /* <Function> */
1015 /* FT_New_Face */
1016 /* */
1017 /* <Description> */
1018 /* This is the Mac-specific implementation of FT_New_Face. In */
1019 /* addition to the standard FT_New_Face() functionality, it also */
1020 /* accepts pathnames to Mac suitcase files. For further */
1021 /* documentation see the original FT_New_Face() in freetype.h. */
1022 /* */
1023 FT_EXPORT_DEF( FT_Error )
1024 FT_New_Face( FT_Library library,
1025 const char* pathname,
1026 FT_Long face_index,
1027 FT_Face* aface )
1029 FT_Open_Args args;
1030 FT_Error error;
1033 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
1034 if ( !pathname )
1035 return FT_Err_Invalid_Argument;
1037 error = FT_Err_Ok;
1038 *aface = NULL;
1040 /* try resourcefork based font: LWFN, FFIL */
1041 error = FT_New_Face_From_Resource( library, (UInt8 *)pathname,
1042 face_index, aface );
1043 if ( error != 0 || *aface != NULL )
1044 return error;
1046 /* let it fall through to normal loader (.ttf, .otf, etc.) */
1047 args.flags = FT_OPEN_PATHNAME;
1048 args.pathname = (char*)pathname;
1049 return FT_Open_Face( library, &args, face_index, aface );
1053 /*************************************************************************/
1054 /* */
1055 /* <Function> */
1056 /* FT_New_Face_From_FSRef */
1057 /* */
1058 /* <Description> */
1059 /* FT_New_Face_From_FSRef is identical to FT_New_Face except it */
1060 /* accepts an FSRef instead of a path. */
1061 /* */
1062 /* This function is deprecated because Carbon data types (FSRef) */
1063 /* are not cross-platform, and thus not suitable for the freetype API. */
1064 FT_EXPORT_DEF( FT_Error )
1065 FT_New_Face_From_FSRef( FT_Library library,
1066 const FSRef* ref,
1067 FT_Long face_index,
1068 FT_Face* aface )
1070 FT_Error error;
1071 FT_Open_Args args;
1072 OSErr err;
1073 UInt8 pathname[PATH_MAX];
1076 if ( !ref )
1077 return FT_Err_Invalid_Argument;
1079 err = FSRefMakePath( ref, pathname, sizeof ( pathname ) );
1080 if ( err )
1081 error = FT_Err_Cannot_Open_Resource;
1083 error = FT_New_Face_From_Resource( library, pathname, face_index, aface );
1084 if ( error != 0 || *aface != NULL )
1085 return error;
1087 /* fallback to datafork font */
1088 args.flags = FT_OPEN_PATHNAME;
1089 args.pathname = (char*)pathname;
1090 return FT_Open_Face( library, &args, face_index, aface );
1094 /*************************************************************************/
1095 /* */
1096 /* <Function> */
1097 /* FT_New_Face_From_FSSpec */
1098 /* */
1099 /* <Description> */
1100 /* FT_New_Face_From_FSSpec is identical to FT_New_Face except it */
1101 /* accepts an FSSpec instead of a path. */
1102 /* */
1103 /* This function is deprecated because FSSpec is deprecated in Mac OS X */
1104 FT_EXPORT_DEF( FT_Error )
1105 FT_New_Face_From_FSSpec( FT_Library library,
1106 const FSSpec* spec,
1107 FT_Long face_index,
1108 FT_Face* aface )
1110 #if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \
1111 ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) )
1112 FT_UNUSED( library );
1113 FT_UNUSED( spec );
1114 FT_UNUSED( face_index );
1115 FT_UNUSED( aface );
1117 return FT_Err_Unimplemented_Feature;
1118 #else
1119 FSRef ref;
1122 if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr )
1123 return FT_Err_Invalid_Argument;
1124 else
1125 return FT_New_Face_From_FSRef( library, &ref, face_index, aface );
1126 #endif
1130 /* END */