source: trunk/poppler/freetype2/src/base/ftmac.c @ 262

Last change on this file since 262 was 262, checked in by Eugene Romanenko, 12 years ago

PDF plugin: freetype library updated to version 2.3.8

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