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

Last change on this file since 182 was 182, checked in by Eugene Romanenko, 15 years ago

freetype update to version 2.3.0

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