[FREETYPE] Update to v2.6.3. CORE-10964
[reactos.git] / reactos / lib / 3rdparty / freetype / src / base / ftmac.c
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-2016 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 /***************************************************************************/
21
22
23 /*
24 Notes
25
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.
29
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.
35
36 The Mac FOND support works roughly like this:
37
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.
43
44 - Read the FOND resource into memory, then check whether there is a
45 TrueType font and/or(!) a Type 1 font available.
46
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...)
55
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().
59
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.
65 */
66
67
68 #include <ft2build.h>
69 #include FT_FREETYPE_H
70 #include FT_TRUETYPE_TAGS_H
71 #include FT_INTERNAL_STREAM_H
72 #include "ftbase.h"
73
74 /* This is for Mac OS X. Without redefinition, OS_INLINE */
75 /* expands to `static inline' which doesn't survive the */
76 /* -ansi compilation flag of GCC. */
77 #if !HAVE_ANSI_OS_INLINE
78 #undef OS_INLINE
79 #define OS_INLINE static __inline__
80 #endif
81
82 /* `configure' checks the availability of `ResourceIndex' strictly */
83 /* and sets HAVE_TYPE_RESOURCE_INDEX 1 or 0 always. If it is */
84 /* not set (e.g., a build without `configure'), the availability */
85 /* is guessed from the SDK version. */
86 #ifndef HAVE_TYPE_RESOURCE_INDEX
87 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
88 ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 )
89 #define HAVE_TYPE_RESOURCE_INDEX 0
90 #else
91 #define HAVE_TYPE_RESOURCE_INDEX 1
92 #endif
93 #endif /* !HAVE_TYPE_RESOURCE_INDEX */
94
95 #if ( HAVE_TYPE_RESOURCE_INDEX == 0 )
96 typedef short ResourceIndex;
97 #endif
98
99 #include <CoreServices/CoreServices.h>
100 #include <ApplicationServices/ApplicationServices.h>
101 #include <sys/syslimits.h> /* PATH_MAX */
102
103 /* Don't want warnings about our own use of deprecated functions. */
104 #define FT_DEPRECATED_ATTRIBUTE
105
106 #include FT_MAC_H
107
108 #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */
109 #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault
110 #endif
111
112
113 /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
114 TrueType in case *both* are available (this is not common,
115 but it *is* possible). */
116 #ifndef PREFER_LWFN
117 #define PREFER_LWFN 1
118 #endif
119
120
121 #ifdef FT_MACINTOSH
122
123 /* This function is deprecated because FSSpec is deprecated in Mac OS X */
124 FT_EXPORT_DEF( FT_Error )
125 FT_GetFile_From_Mac_Name( const char* fontName,
126 FSSpec* pathSpec,
127 FT_Long* face_index )
128 {
129 FT_UNUSED( fontName );
130 FT_UNUSED( pathSpec );
131 FT_UNUSED( face_index );
132
133 return FT_THROW( Unimplemented_Feature );
134 }
135
136
137 /* Private function. */
138 /* The FSSpec type has been discouraged for a long time, */
139 /* unfortunately an FSRef replacement API for */
140 /* ATSFontGetFileSpecification() is only available in */
141 /* Mac OS X 10.5 and later. */
142 static OSStatus
143 FT_ATSFontGetFileReference( ATSFontRef ats_font_id,
144 FSRef* ats_font_ref )
145 {
146 #if defined( MAC_OS_X_VERSION_10_5 ) && \
147 ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
148
149 OSStatus err;
150
151 err = ATSFontGetFileReference( ats_font_id, ats_font_ref );
152
153 return err;
154 #elif __LP64__ /* No 64bit Carbon API on legacy platforms */
155 FT_UNUSED( ats_font_id );
156 FT_UNUSED( ats_font_ref );
157
158
159 return fnfErr;
160 #else /* 32bit Carbon API on legacy platforms */
161 OSStatus err;
162 FSSpec spec;
163
164
165 err = ATSFontGetFileSpecification( ats_font_id, &spec );
166 if ( noErr == err )
167 err = FSpMakeFSRef( &spec, ats_font_ref );
168
169 return err;
170 #endif
171 }
172
173
174 static FT_Error
175 FT_GetFileRef_From_Mac_ATS_Name( const char* fontName,
176 FSRef* ats_font_ref,
177 FT_Long* face_index )
178 {
179 CFStringRef cf_fontName;
180 ATSFontRef ats_font_id;
181
182
183 *face_index = 0;
184
185 cf_fontName = CFStringCreateWithCString( NULL, fontName,
186 kCFStringEncodingMacRoman );
187 ats_font_id = ATSFontFindFromName( cf_fontName,
188 kATSOptionFlagsUnRestrictedScope );
189 CFRelease( cf_fontName );
190
191 if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL )
192 return FT_THROW( Unknown_File_Format );
193
194 if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) )
195 return FT_THROW( Unknown_File_Format );
196
197 /* face_index calculation by searching preceding fontIDs */
198 /* with same FSRef */
199 {
200 ATSFontRef id2 = ats_font_id - 1;
201 FSRef ref2;
202
203
204 while ( id2 > 0 )
205 {
206 if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) )
207 break;
208 if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) )
209 break;
210
211 id2 --;
212 }
213 *face_index = ats_font_id - ( id2 + 1 );
214 }
215
216 return FT_Err_Ok;
217 }
218
219
220 FT_EXPORT_DEF( FT_Error )
221 FT_GetFilePath_From_Mac_ATS_Name( const char* fontName,
222 UInt8* path,
223 UInt32 maxPathSize,
224 FT_Long* face_index )
225 {
226 FSRef ref;
227 FT_Error err;
228
229
230 if ( !fontName || !face_index )
231 return FT_THROW( Invalid_Argument) ;
232
233 err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
234 if ( err )
235 return err;
236
237 if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) )
238 return FT_THROW( Unknown_File_Format );
239
240 return FT_Err_Ok;
241 }
242
243
244 /* This function is deprecated because FSSpec is deprecated in Mac OS X */
245 FT_EXPORT_DEF( FT_Error )
246 FT_GetFile_From_Mac_ATS_Name( const char* fontName,
247 FSSpec* pathSpec,
248 FT_Long* face_index )
249 {
250 #if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \
251 ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) )
252 FT_UNUSED( fontName );
253 FT_UNUSED( pathSpec );
254 FT_UNUSED( face_index );
255
256 return FT_THROW( Unimplemented_Feature );
257 #else
258 FSRef ref;
259 FT_Error err;
260
261
262 if ( !fontName || !face_index )
263 return FT_THROW( Invalid_Argument );
264
265 err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
266 if ( err )
267 return err;
268
269 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL,
270 pathSpec, NULL ) )
271 return FT_THROW( Unknown_File_Format );
272
273 return FT_Err_Ok;
274 #endif
275 }
276
277
278 static OSErr
279 FT_FSPathMakeRes( const UInt8* pathname,
280 ResFileRefNum* res )
281 {
282 OSErr err;
283 FSRef ref;
284
285
286 if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
287 return FT_THROW( Cannot_Open_Resource );
288
289 /* at present, no support for dfont format */
290 err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res );
291 if ( noErr == err )
292 return err;
293
294 /* fallback to original resource-fork font */
295 *res = FSOpenResFile( &ref, fsRdPerm );
296 err = ResError();
297
298 return err;
299 }
300
301
302 /* Return the file type for given pathname */
303 static OSType
304 get_file_type_from_path( const UInt8* pathname )
305 {
306 FSRef ref;
307 FSCatalogInfo info;
308
309
310 if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
311 return ( OSType ) 0;
312
313 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info,
314 NULL, NULL, NULL ) )
315 return ( OSType ) 0;
316
317 return ((FInfo *)(info.finderInfo))->fdType;
318 }
319
320
321 /* Given a PostScript font name, create the Macintosh LWFN file name. */
322 static void
323 create_lwfn_name( char* ps_name,
324 Str255 lwfn_file_name )
325 {
326 int max = 5, count = 0;
327 FT_Byte* p = lwfn_file_name;
328 FT_Byte* q = (FT_Byte*)ps_name;
329
330
331 lwfn_file_name[0] = 0;
332
333 while ( *q )
334 {
335 if ( ft_isupper( *q ) )
336 {
337 if ( count )
338 max = 3;
339 count = 0;
340 }
341 if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
342 {
343 *++p = *q;
344 lwfn_file_name[0]++;
345 count++;
346 }
347 q++;
348 }
349 }
350
351
352 static short
353 count_faces_sfnt( char* fond_data )
354 {
355 /* The count is 1 greater than the value in the FOND. */
356 /* Isn't that cute? :-) */
357
358 return EndianS16_BtoN( *( (short*)( fond_data +
359 sizeof ( FamRec ) ) ) ) + 1;
360 }
361
362
363 static short
364 count_faces_scalable( char* fond_data )
365 {
366 AsscEntry* assoc;
367 short i, face, face_all;
368
369
370 face_all = EndianS16_BtoN( *( (short *)( fond_data +
371 sizeof ( FamRec ) ) ) ) + 1;
372 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
373 face = 0;
374
375 for ( i = 0; i < face_all; i++ )
376 {
377 if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) )
378 face++;
379 }
380 return face;
381 }
382
383
384 /* Look inside the FOND data, answer whether there should be an SFNT
385 resource, and answer the name of a possible LWFN Type 1 file.
386
387 Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
388 to load a face OTHER than the first one in the FOND!
389 */
390
391
392 static void
393 parse_fond( char* fond_data,
394 short* have_sfnt,
395 ResID* sfnt_id,
396 Str255 lwfn_file_name,
397 short face_index )
398 {
399 AsscEntry* assoc;
400 AsscEntry* base_assoc;
401 FamRec* fond;
402
403
404 *sfnt_id = 0;
405 *have_sfnt = 0;
406 lwfn_file_name[0] = 0;
407
408 fond = (FamRec*)fond_data;
409 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
410 base_assoc = assoc;
411
412 /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */
413 if ( 47 < face_index )
414 return;
415
416 /* Let's do a little range checking before we get too excited here */
417 if ( face_index < count_faces_sfnt( fond_data ) )
418 {
419 assoc += face_index; /* add on the face_index! */
420
421 /* if the face at this index is not scalable,
422 fall back to the first one (old behavior) */
423 if ( EndianS16_BtoN( assoc->fontSize ) == 0 )
424 {
425 *have_sfnt = 1;
426 *sfnt_id = EndianS16_BtoN( assoc->fontID );
427 }
428 else if ( base_assoc->fontSize == 0 )
429 {
430 *have_sfnt = 1;
431 *sfnt_id = EndianS16_BtoN( base_assoc->fontID );
432 }
433 }
434
435 if ( EndianS32_BtoN( fond->ffStylOff ) )
436 {
437 unsigned char* p = (unsigned char*)fond_data;
438 StyleTable* style;
439 unsigned short string_count;
440 char ps_name[256];
441 unsigned char* names[64];
442 int i;
443
444
445 p += EndianS32_BtoN( fond->ffStylOff );
446 style = (StyleTable*)p;
447 p += sizeof ( StyleTable );
448 string_count = EndianS16_BtoN( *(short*)(p) );
449 string_count = FT_MIN( 64, string_count );
450 p += sizeof ( short );
451
452 for ( i = 0; i < string_count; i++ )
453 {
454 names[i] = p;
455 p += names[i][0];
456 p++;
457 }
458
459 {
460 size_t ps_name_len = (size_t)names[0][0];
461
462
463 if ( ps_name_len != 0 )
464 {
465 ft_memcpy(ps_name, names[0] + 1, ps_name_len);
466 ps_name[ps_name_len] = 0;
467 }
468 if ( style->indexes[face_index] > 1 &&
469 style->indexes[face_index] <= string_count )
470 {
471 unsigned char* suffixes = names[style->indexes[face_index] - 1];
472
473
474 for ( i = 1; i <= suffixes[0]; i++ )
475 {
476 unsigned char* s;
477 size_t j = suffixes[i] - 1;
478
479
480 if ( j < string_count && ( s = names[j] ) != NULL )
481 {
482 size_t s_len = (size_t)s[0];
483
484
485 if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
486 {
487 ft_memcpy( ps_name + ps_name_len, s + 1, s_len );
488 ps_name_len += s_len;
489 ps_name[ps_name_len] = 0;
490 }
491 }
492 }
493 }
494 }
495
496 create_lwfn_name( ps_name, lwfn_file_name );
497 }
498 }
499
500
501 static FT_Error
502 lookup_lwfn_by_fond( const UInt8* path_fond,
503 ConstStr255Param base_lwfn,
504 UInt8* path_lwfn,
505 size_t path_size )
506 {
507 FSRef ref, par_ref;
508 size_t dirname_len;
509
510
511 /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */
512 /* We should not extract parent directory by string manipulation. */
513
514 if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) )
515 return FT_THROW( Invalid_Argument );
516
517 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
518 NULL, NULL, NULL, &par_ref ) )
519 return FT_THROW( Invalid_Argument );
520
521 if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) )
522 return FT_THROW( Invalid_Argument );
523
524 if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size )
525 return FT_THROW( Invalid_Argument );
526
527 /* now we have absolute dirname in path_lwfn */
528 ft_strcat( (char *)path_lwfn, "/" );
529 dirname_len = ft_strlen( (char *)path_lwfn );
530 ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 );
531 path_lwfn[dirname_len + base_lwfn[0]] = '\0';
532
533 if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) )
534 return FT_THROW( Cannot_Open_Resource );
535
536 if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
537 NULL, NULL, NULL, NULL ) )
538 return FT_THROW( Cannot_Open_Resource );
539
540 return FT_Err_Ok;
541 }
542
543
544 static short
545 count_faces( Handle fond,
546 const UInt8* pathname )
547 {
548 ResID sfnt_id;
549 short have_sfnt, have_lwfn;
550 Str255 lwfn_file_name;
551 UInt8 buff[PATH_MAX];
552 FT_Error err;
553 short num_faces;
554
555
556 have_sfnt = have_lwfn = 0;
557
558 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 );
559
560 if ( lwfn_file_name[0] )
561 {
562 err = lookup_lwfn_by_fond( pathname, lwfn_file_name,
563 buff, sizeof ( buff ) );
564 if ( !err )
565 have_lwfn = 1;
566 }
567
568 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
569 num_faces = 1;
570 else
571 num_faces = count_faces_scalable( *fond );
572
573 return num_faces;
574 }
575
576
577 /* Read Type 1 data from the POST resources inside the LWFN file,
578 return a PFB buffer. This is somewhat convoluted because the FT2
579 PFB parser wants the ASCII header as one chunk, and the LWFN
580 chunks are often not organized that way, so we glue chunks
581 of the same type together. */
582 static FT_Error
583 read_lwfn( FT_Memory memory,
584 ResFileRefNum res,
585 FT_Byte** pfb_data,
586 FT_ULong* size )
587 {
588 FT_Error error = FT_Err_Ok;
589 ResID res_id;
590 unsigned char *buffer, *p, *size_p = NULL;
591 FT_ULong total_size = 0;
592 FT_ULong old_total_size = 0;
593 FT_ULong post_size, pfb_chunk_size;
594 Handle post_data;
595 char code, last_code;
596
597
598 UseResFile( res );
599
600 /* First pass: load all POST resources, and determine the size of */
601 /* the output buffer. */
602 res_id = 501;
603 last_code = -1;
604
605 for (;;)
606 {
607 post_data = Get1Resource( TTAG_POST, res_id++ );
608 if ( post_data == NULL )
609 break; /* we are done */
610
611 code = (*post_data)[0];
612
613 if ( code != last_code )
614 {
615 if ( code == 5 )
616 total_size += 2; /* just the end code */
617 else
618 total_size += 6; /* code + 4 bytes chunk length */
619 }
620
621 total_size += (FT_ULong)GetHandleSize( post_data ) - 2;
622 last_code = code;
623
624 /* detect resource fork overflow */
625 if ( FT_MAC_RFORK_MAX_LEN < total_size )
626 {
627 error = FT_THROW( Array_Too_Large );
628 goto Error;
629 }
630
631 old_total_size = total_size;
632 }
633
634 if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
635 goto Error;
636
637 /* Second pass: append all POST data to the buffer, add PFB fields. */
638 /* Glue all consecutive chunks of the same type together. */
639 p = buffer;
640 res_id = 501;
641 last_code = -1;
642 pfb_chunk_size = 0;
643
644 for (;;)
645 {
646 post_data = Get1Resource( TTAG_POST, res_id++ );
647 if ( post_data == NULL )
648 break; /* we are done */
649
650 post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
651 code = (*post_data)[0];
652
653 if ( code != last_code )
654 {
655 if ( last_code != -1 )
656 {
657 /* we are done adding a chunk, fill in the size field */
658 if ( size_p != NULL )
659 {
660 *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF );
661 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF );
662 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
663 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
664 }
665 pfb_chunk_size = 0;
666 }
667
668 *p++ = 0x80;
669 if ( code == 5 )
670 *p++ = 0x03; /* the end */
671 else if ( code == 2 )
672 *p++ = 0x02; /* binary segment */
673 else
674 *p++ = 0x01; /* ASCII segment */
675
676 if ( code != 5 )
677 {
678 size_p = p; /* save for later */
679 p += 4; /* make space for size field */
680 }
681 }
682
683 ft_memcpy( p, *post_data + 2, post_size );
684 pfb_chunk_size += post_size;
685 p += post_size;
686 last_code = code;
687 }
688
689 *pfb_data = buffer;
690 *size = total_size;
691
692 Error:
693 CloseResFile( res );
694 return error;
695 }
696
697
698 /* Create a new FT_Face from a file path to an LWFN file. */
699 static FT_Error
700 FT_New_Face_From_LWFN( FT_Library library,
701 const UInt8* pathname,
702 FT_Long face_index,
703 FT_Face* aface )
704 {
705 FT_Byte* pfb_data;
706 FT_ULong pfb_size;
707 FT_Error error;
708 ResFileRefNum res;
709
710
711 if ( noErr != FT_FSPathMakeRes( pathname, &res ) )
712 return FT_THROW( Cannot_Open_Resource );
713
714 pfb_data = NULL;
715 pfb_size = 0;
716 error = read_lwfn( library->memory, res, &pfb_data, &pfb_size );
717 CloseResFile( res ); /* PFB is already loaded, useless anymore */
718 if ( error )
719 return error;
720
721 return open_face_from_buffer( library,
722 pfb_data,
723 pfb_size,
724 face_index,
725 "type1",
726 aface );
727 }
728
729
730 /* Create a new FT_Face from an SFNT resource, specified by res ID. */
731 static FT_Error
732 FT_New_Face_From_SFNT( FT_Library library,
733 ResID sfnt_id,
734 FT_Long face_index,
735 FT_Face* aface )
736 {
737 Handle sfnt = NULL;
738 FT_Byte* sfnt_data;
739 size_t sfnt_size;
740 FT_Error error = FT_Err_Ok;
741 FT_Memory memory = library->memory;
742 int is_cff, is_sfnt_ps;
743
744
745 sfnt = GetResource( TTAG_sfnt, sfnt_id );
746 if ( sfnt == NULL )
747 return FT_THROW( Invalid_Handle );
748
749 sfnt_size = (FT_ULong)GetHandleSize( sfnt );
750
751 /* detect resource fork overflow */
752 if ( FT_MAC_RFORK_MAX_LEN < sfnt_size )
753 return FT_THROW( Array_Too_Large );
754
755 if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
756 {
757 ReleaseResource( sfnt );
758 return error;
759 }
760
761 ft_memcpy( sfnt_data, *sfnt, sfnt_size );
762 ReleaseResource( sfnt );
763
764 is_cff = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
765 is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 );
766
767 if ( is_sfnt_ps )
768 {
769 FT_Stream stream;
770
771
772 if ( FT_NEW( stream ) )
773 goto Try_OpenType;
774
775 FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size );
776 if ( !open_face_PS_from_sfnt_stream( library,
777 stream,
778 face_index,
779 0, NULL,
780 aface ) )
781 {
782 FT_Stream_Close( stream );
783 FT_FREE( stream );
784 FT_FREE( sfnt_data );
785 goto Exit;
786 }
787
788 FT_FREE( stream );
789 }
790 Try_OpenType:
791 error = open_face_from_buffer( library,
792 sfnt_data,
793 sfnt_size,
794 face_index,
795 is_cff ? "cff" : "truetype",
796 aface );
797 Exit:
798 return error;
799 }
800
801
802 /* Create a new FT_Face from a file path to a suitcase file. */
803 static FT_Error
804 FT_New_Face_From_Suitcase( FT_Library library,
805 const UInt8* pathname,
806 FT_Long face_index,
807 FT_Face* aface )
808 {
809 FT_Error error = FT_ERR( Cannot_Open_Resource );
810 ResFileRefNum res_ref;
811 ResourceIndex res_index;
812 Handle fond;
813 short num_faces_in_res;
814
815
816 if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) )
817 return FT_THROW( Cannot_Open_Resource );
818
819 UseResFile( res_ref );
820 if ( ResError() )
821 return FT_THROW( Cannot_Open_Resource );
822
823 num_faces_in_res = 0;
824 for ( res_index = 1; ; ++res_index )
825 {
826 short num_faces_in_fond;
827
828
829 fond = Get1IndResource( TTAG_FOND, res_index );
830 if ( ResError() )
831 break;
832
833 num_faces_in_fond = count_faces( fond, pathname );
834 num_faces_in_res += num_faces_in_fond;
835
836 if ( 0 <= face_index && face_index < num_faces_in_fond && error )
837 error = FT_New_Face_From_FOND( library, fond, face_index, aface );
838
839 face_index -= num_faces_in_fond;
840 }
841
842 CloseResFile( res_ref );
843 if ( !error && aface && *aface )
844 (*aface)->num_faces = num_faces_in_res;
845 return error;
846 }
847
848
849 /* documentation is in ftmac.h */
850
851 FT_EXPORT_DEF( FT_Error )
852 FT_New_Face_From_FOND( FT_Library library,
853 Handle fond,
854 FT_Long face_index,
855 FT_Face* aface )
856 {
857 short have_sfnt, have_lwfn = 0;
858 ResID sfnt_id, fond_id;
859 OSType fond_type;
860 Str255 fond_name;
861 Str255 lwfn_file_name;
862 UInt8 path_lwfn[PATH_MAX];
863 OSErr err;
864 FT_Error error = FT_Err_Ok;
865
866
867 /* check of `library' and `aface' delayed to `FT_New_Face_From_XXX' */
868
869 GetResInfo( fond, &fond_id, &fond_type, fond_name );
870 if ( ResError() != noErr || fond_type != TTAG_FOND )
871 return FT_THROW( Invalid_File_Format );
872
873 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
874
875 if ( lwfn_file_name[0] )
876 {
877 ResFileRefNum res;
878
879
880 res = HomeResFile( fond );
881 if ( noErr != ResError() )
882 goto found_no_lwfn_file;
883
884 {
885 UInt8 path_fond[PATH_MAX];
886 FSRef ref;
887
888
889 err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum,
890 NULL, NULL, NULL, &ref, NULL );
891 if ( noErr != err )
892 goto found_no_lwfn_file;
893
894 err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) );
895 if ( noErr != err )
896 goto found_no_lwfn_file;
897
898 error = lookup_lwfn_by_fond( path_fond, lwfn_file_name,
899 path_lwfn, sizeof ( path_lwfn ) );
900 if ( !error )
901 have_lwfn = 1;
902 }
903 }
904
905 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
906 error = FT_New_Face_From_LWFN( library,
907 path_lwfn,
908 face_index,
909 aface );
910 else
911 error = FT_THROW( Unknown_File_Format );
912
913 found_no_lwfn_file:
914 if ( have_sfnt && error )
915 error = FT_New_Face_From_SFNT( library,
916 sfnt_id,
917 face_index,
918 aface );
919
920 return error;
921 }
922
923
924 /* Common function to load a new FT_Face from a resource file. */
925 static FT_Error
926 FT_New_Face_From_Resource( FT_Library library,
927 const UInt8* pathname,
928 FT_Long face_index,
929 FT_Face* aface )
930 {
931 OSType file_type;
932 FT_Error error;
933
934
935 /* LWFN is a (very) specific file format, check for it explicitly */
936 file_type = get_file_type_from_path( pathname );
937 if ( file_type == TTAG_LWFN )
938 return FT_New_Face_From_LWFN( library, pathname, face_index, aface );
939
940 /* Otherwise the file type doesn't matter (there are more than */
941 /* `FFIL' and `tfil'). Just try opening it as a font suitcase; */
942 /* if it works, fine. */
943
944 error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface );
945 if ( error == 0 )
946 return error;
947
948 /* let it fall through to normal loader (.ttf, .otf, etc.); */
949 /* we signal this by returning no error and no FT_Face */
950 *aface = NULL;
951 return 0;
952 }
953
954
955 /*************************************************************************/
956 /* */
957 /* <Function> */
958 /* FT_New_Face */
959 /* */
960 /* <Description> */
961 /* This is the Mac-specific implementation of FT_New_Face. In */
962 /* addition to the standard FT_New_Face() functionality, it also */
963 /* accepts pathnames to Mac suitcase files. For further */
964 /* documentation see the original FT_New_Face() in freetype.h. */
965 /* */
966 FT_EXPORT_DEF( FT_Error )
967 FT_New_Face( FT_Library library,
968 const char* pathname,
969 FT_Long face_index,
970 FT_Face* aface )
971 {
972 FT_Open_Args args;
973 FT_Error error;
974
975
976 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
977 if ( !pathname )
978 return FT_THROW( Invalid_Argument );
979
980 *aface = NULL;
981
982 /* try resourcefork based font: LWFN, FFIL */
983 error = FT_New_Face_From_Resource( library, (UInt8 *)pathname,
984 face_index, aface );
985 if ( error != 0 || *aface != NULL )
986 return error;
987
988 /* let it fall through to normal loader (.ttf, .otf, etc.) */
989 args.flags = FT_OPEN_PATHNAME;
990 args.pathname = (char*)pathname;
991 return FT_Open_Face( library, &args, face_index, aface );
992 }
993
994
995 /*************************************************************************/
996 /* */
997 /* <Function> */
998 /* FT_New_Face_From_FSRef */
999 /* */
1000 /* <Description> */
1001 /* FT_New_Face_From_FSRef is identical to FT_New_Face except it */
1002 /* accepts an FSRef instead of a path. */
1003 /* */
1004 /* This function is deprecated because Carbon data types (FSRef) */
1005 /* are not cross-platform, and thus not suitable for the freetype API. */
1006 FT_EXPORT_DEF( FT_Error )
1007 FT_New_Face_From_FSRef( FT_Library library,
1008 const FSRef* ref,
1009 FT_Long face_index,
1010 FT_Face* aface )
1011 {
1012 FT_Error error;
1013 FT_Open_Args args;
1014
1015 OSErr err;
1016 UInt8 pathname[PATH_MAX];
1017
1018
1019 /* check of `library' and `aface' delayed to */
1020 /* `FT_New_Face_From_Resource' */
1021
1022 if ( !ref )
1023 return FT_THROW( Invalid_Argument );
1024
1025 err = FSRefMakePath( ref, pathname, sizeof ( pathname ) );
1026 if ( err )
1027 error = FT_THROW( Cannot_Open_Resource );
1028
1029 error = FT_New_Face_From_Resource( library, pathname, face_index, aface );
1030 if ( error != 0 || *aface != NULL )
1031 return error;
1032
1033 /* fallback to datafork font */
1034 args.flags = FT_OPEN_PATHNAME;
1035 args.pathname = (char*)pathname;
1036 return FT_Open_Face( library, &args, face_index, aface );
1037 }
1038
1039
1040 /*************************************************************************/
1041 /* */
1042 /* <Function> */
1043 /* FT_New_Face_From_FSSpec */
1044 /* */
1045 /* <Description> */
1046 /* FT_New_Face_From_FSSpec is identical to FT_New_Face except it */
1047 /* accepts an FSSpec instead of a path. */
1048 /* */
1049 /* This function is deprecated because FSSpec is deprecated in Mac OS X */
1050 FT_EXPORT_DEF( FT_Error )
1051 FT_New_Face_From_FSSpec( FT_Library library,
1052 const FSSpec* spec,
1053 FT_Long face_index,
1054 FT_Face* aface )
1055 {
1056 #if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \
1057 ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) )
1058 FT_UNUSED( library );
1059 FT_UNUSED( spec );
1060 FT_UNUSED( face_index );
1061 FT_UNUSED( aface );
1062
1063 return FT_THROW( Unimplemented_Feature );
1064 #else
1065 FSRef ref;
1066
1067
1068 /* check of `library' and `aface' delayed to `FT_New_Face_From_FSRef' */
1069
1070 if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr )
1071 return FT_THROW( Invalid_Argument );
1072 else
1073 return FT_New_Face_From_FSRef( library, &ref, face_index, aface );
1074 #endif
1075 }
1076
1077 #endif /* FT_MACINTOSH */
1078
1079
1080 /* END */