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

Last change on this file since 251 was 251, checked in by Eugene Romanenko, 13 years ago

PDF plugin: freetype library updated to version 2.3.5

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