misc/libfreetype/builds/mac/ftmac.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  ftmac.c                                                                */
       
     4 /*                                                                         */
       
     5 /*    Mac FOND support.  Written by just@letterror.com.                    */
       
     6 /*  Heavily Fixed by mpsuzuki, George Williams and Sean McBride            */
       
     7 /*                                                                         */
       
     8 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by       */
       
     9 /*  Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.     */
       
    10 /*                                                                         */
       
    11 /*  This file is part of the FreeType project, and may only be used,       */
       
    12 /*  modified, and distributed under the terms of the FreeType project      */
       
    13 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
       
    14 /*  this file you indicate that you have read the license and              */
       
    15 /*  understand and accept it fully.                                        */
       
    16 /*                                                                         */
       
    17 /***************************************************************************/
       
    18 
       
    19 
       
    20   /*
       
    21     Notes
       
    22 
       
    23     Mac suitcase files can (and often do!) contain multiple fonts.  To
       
    24     support this I use the face_index argument of FT_(Open|New)_Face()
       
    25     functions, and pretend the suitcase file is a collection.
       
    26 
       
    27     Warning: fbit and NFNT bitmap resources are not supported yet.  In old
       
    28     sfnt fonts, bitmap glyph data for each size is stored in each `NFNT'
       
    29     resources instead of the `bdat' table in the sfnt resource.  Therefore,
       
    30     face->num_fixed_sizes is set to 0, because bitmap data in `NFNT'
       
    31     resource is unavailable at present.
       
    32 
       
    33     The Mac FOND support works roughly like this:
       
    34 
       
    35     - Check whether the offered stream points to a Mac suitcase file.  This
       
    36       is done by checking the file type: it has to be 'FFIL' or 'tfil'.  The
       
    37       stream that gets passed to our init_face() routine is a stdio stream,
       
    38       which isn't usable for us, since the FOND resources live in the
       
    39       resource fork.  So we just grab the stream->pathname field.
       
    40 
       
    41     - Read the FOND resource into memory, then check whether there is a
       
    42       TrueType font and/or(!) a Type 1 font available.
       
    43 
       
    44     - If there is a Type 1 font available (as a separate `LWFN' file), read
       
    45       its data into memory, massage it slightly so it becomes PFB data, wrap
       
    46       it into a memory stream, load the Type 1 driver and delegate the rest
       
    47       of the work to it by calling FT_Open_Face().  (XXX TODO: after this
       
    48       has been done, the kerning data from the FOND resource should be
       
    49       appended to the face: On the Mac there are usually no AFM files
       
    50       available.  However, this is tricky since we need to map Mac char
       
    51       codes to ps glyph names to glyph ID's...)
       
    52 
       
    53     - If there is a TrueType font (an `sfnt' resource), read it into memory,
       
    54       wrap it into a memory stream, load the TrueType driver and delegate
       
    55       the rest of the work to it, by calling FT_Open_Face().
       
    56 
       
    57     - Some suitcase fonts (notably Onyx) might point the `LWFN' file to
       
    58       itself, even though it doesn't contains `POST' resources.  To handle
       
    59       this special case without opening the file an extra time, we just
       
    60       ignore errors from the `LWFN' and fallback to the `sfnt' if both are
       
    61       available.
       
    62   */
       
    63 
       
    64 
       
    65 #include <ft2build.h>
       
    66 #include FT_FREETYPE_H
       
    67 #include FT_TRUETYPE_TAGS_H
       
    68 #include FT_INTERNAL_STREAM_H
       
    69 #include "ftbase.h"
       
    70 
       
    71 #if defined( __GNUC__ ) || defined( __IBMC__ )
       
    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 #include <CoreServices/CoreServices.h>
       
    80 #include <ApplicationServices/ApplicationServices.h>
       
    81 #include <sys/syslimits.h> /* PATH_MAX */
       
    82 #else
       
    83 #include <Resources.h>
       
    84 #include <Fonts.h>
       
    85 #include <Endian.h>
       
    86 #include <Errors.h>
       
    87 #include <Files.h>
       
    88 #include <TextUtils.h>
       
    89 #endif
       
    90 
       
    91 #ifndef PATH_MAX
       
    92 #define PATH_MAX 1024 /* same with Mac OS X's syslimits.h */
       
    93 #endif
       
    94 
       
    95 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
       
    96 #include <FSp_fopen.h>
       
    97 #endif
       
    98 
       
    99 #define FT_DEPRECATED_ATTRIBUTE
       
   100 
       
   101 #include FT_MAC_H
       
   102 
       
   103   /* undefine blocking-macros in ftmac.h */
       
   104 #undef FT_GetFile_From_Mac_Name
       
   105 #undef FT_GetFile_From_Mac_ATS_Name
       
   106 #undef FT_New_Face_From_FOND
       
   107 #undef FT_New_Face_From_FSSpec
       
   108 #undef FT_New_Face_From_FSRef
       
   109 
       
   110 
       
   111   /* FSSpec functions are deprecated since Mac OS X 10.4 */
       
   112 #ifndef HAVE_FSSPEC
       
   113 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
       
   114 #define HAVE_FSSPEC  1
       
   115 #else
       
   116 #define HAVE_FSSPEC  0
       
   117 #endif
       
   118 #endif
       
   119 
       
   120   /* most FSRef functions were introduced since Mac OS 9 */
       
   121 #ifndef HAVE_FSREF
       
   122 #if TARGET_API_MAC_OSX
       
   123 #define HAVE_FSREF  1
       
   124 #else
       
   125 #define HAVE_FSREF  0
       
   126 #endif
       
   127 #endif
       
   128 
       
   129   /* QuickDraw is deprecated since Mac OS X 10.4 */
       
   130 #ifndef HAVE_QUICKDRAW_CARBON
       
   131 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
       
   132 #define HAVE_QUICKDRAW_CARBON  1
       
   133 #else
       
   134 #define HAVE_QUICKDRAW_CARBON  0
       
   135 #endif
       
   136 #endif
       
   137 
       
   138   /* AppleTypeService is available since Mac OS X */
       
   139 #ifndef HAVE_ATS
       
   140 #if TARGET_API_MAC_OSX
       
   141 #define HAVE_ATS  1
       
   142 #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */
       
   143 #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault
       
   144 #endif
       
   145 #else
       
   146 #define HAVE_ATS  0
       
   147 #endif
       
   148 #endif
       
   149 
       
   150   /* `configure' checks the availability of `ResourceIndex' strictly */
       
   151   /* and sets HAVE_TYPE_RESOURCE_INDEX to 1 or 0 always.  If it is   */
       
   152   /* not set (e.g., a build without `configure'), the availability   */
       
   153   /* is guessed from the SDK version.                                */
       
   154 #ifndef HAVE_TYPE_RESOURCE_INDEX
       
   155 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
       
   156     ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 )
       
   157 #define HAVE_TYPE_RESOURCE_INDEX 0
       
   158 #else
       
   159 #define HAVE_TYPE_RESOURCE_INDEX 1
       
   160 #endif
       
   161 #endif /* !HAVE_TYPE_RESOURCE_INDEX */
       
   162 
       
   163 #if ( HAVE_TYPE_RESOURCE_INDEX == 0 )
       
   164 typedef short ResourceIndex;
       
   165 #endif
       
   166 
       
   167   /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
       
   168      TrueType in case *both* are available (this is not common,
       
   169      but it *is* possible). */
       
   170 #ifndef PREFER_LWFN
       
   171 #define PREFER_LWFN  1
       
   172 #endif
       
   173 
       
   174 
       
   175 #if !HAVE_QUICKDRAW_CARBON  /* QuickDraw is deprecated since Mac OS X 10.4 */
       
   176 
       
   177   FT_EXPORT_DEF( FT_Error )
       
   178   FT_GetFile_From_Mac_Name( const char*  fontName,
       
   179                             FSSpec*      pathSpec,
       
   180                             FT_Long*     face_index )
       
   181   {
       
   182     FT_UNUSED( fontName );
       
   183     FT_UNUSED( pathSpec );
       
   184     FT_UNUSED( face_index );
       
   185 
       
   186     return FT_Err_Unimplemented_Feature;
       
   187   }
       
   188 
       
   189 #else
       
   190 
       
   191   FT_EXPORT_DEF( FT_Error )
       
   192   FT_GetFile_From_Mac_Name( const char*  fontName,
       
   193                             FSSpec*      pathSpec,
       
   194                             FT_Long*     face_index )
       
   195   {
       
   196     OptionBits            options = kFMUseGlobalScopeOption;
       
   197 
       
   198     FMFontFamilyIterator  famIter;
       
   199     OSStatus              status = FMCreateFontFamilyIterator( NULL, NULL,
       
   200                                                                options,
       
   201                                                                &famIter );
       
   202     FMFont                the_font = 0;
       
   203     FMFontFamily          family   = 0;
       
   204 
       
   205 
       
   206     *face_index = 0;
       
   207     while ( status == 0 && !the_font )
       
   208     {
       
   209       status = FMGetNextFontFamily( &famIter, &family );
       
   210       if ( status == 0 )
       
   211       {
       
   212         int                           stat2;
       
   213         FMFontFamilyInstanceIterator  instIter;
       
   214         Str255                        famNameStr;
       
   215         char                          famName[256];
       
   216 
       
   217 
       
   218         /* get the family name */
       
   219         FMGetFontFamilyName( family, famNameStr );
       
   220         CopyPascalStringToC( famNameStr, famName );
       
   221 
       
   222         /* iterate through the styles */
       
   223         FMCreateFontFamilyInstanceIterator( family, &instIter );
       
   224 
       
   225         *face_index = 0;
       
   226         stat2       = 0;
       
   227 
       
   228         while ( stat2 == 0 && !the_font )
       
   229         {
       
   230           FMFontStyle  style;
       
   231           FMFontSize   size;
       
   232           FMFont       font;
       
   233 
       
   234 
       
   235           stat2 = FMGetNextFontFamilyInstance( &instIter, &font,
       
   236                                                &style, &size );
       
   237           if ( stat2 == 0 && size == 0 )
       
   238           {
       
   239             char  fullName[256];
       
   240 
       
   241 
       
   242             /* build up a complete face name */
       
   243             ft_strcpy( fullName, famName );
       
   244             if ( style & bold )
       
   245               ft_strcat( fullName, " Bold" );
       
   246             if ( style & italic )
       
   247               ft_strcat( fullName, " Italic" );
       
   248 
       
   249             /* compare with the name we are looking for */
       
   250             if ( ft_strcmp( fullName, fontName ) == 0 )
       
   251             {
       
   252               /* found it! */
       
   253               the_font = font;
       
   254             }
       
   255             else
       
   256               ++(*face_index);
       
   257           }
       
   258         }
       
   259 
       
   260         FMDisposeFontFamilyInstanceIterator( &instIter );
       
   261       }
       
   262     }
       
   263 
       
   264     FMDisposeFontFamilyIterator( &famIter );
       
   265 
       
   266     if ( the_font )
       
   267     {
       
   268       FMGetFontContainer( the_font, pathSpec );
       
   269       return FT_Err_Ok;
       
   270     }
       
   271     else
       
   272       return FT_Err_Unknown_File_Format;
       
   273   }
       
   274 
       
   275 #endif /* HAVE_QUICKDRAW_CARBON */
       
   276 
       
   277 
       
   278 #if HAVE_ATS
       
   279 
       
   280   /* Private function.                                         */
       
   281   /* The FSSpec type has been discouraged for a long time,     */
       
   282   /* unfortunately an FSRef replacement API for                */
       
   283   /* ATSFontGetFileSpecification() is only available in        */
       
   284   /* Mac OS X 10.5 and later.                                  */
       
   285   static OSStatus
       
   286   FT_ATSFontGetFileReference( ATSFontRef  ats_font_id,
       
   287                               FSRef*      ats_font_ref )
       
   288   {
       
   289     OSStatus  err;
       
   290 
       
   291 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
       
   292     MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
       
   293     FSSpec    spec;
       
   294 
       
   295 
       
   296     err = ATSFontGetFileSpecification( ats_font_id, &spec );
       
   297     if ( noErr == err )
       
   298       err = FSpMakeFSRef( &spec, ats_font_ref );
       
   299 #else
       
   300     err = ATSFontGetFileReference( ats_font_id, ats_font_ref );
       
   301 #endif
       
   302 
       
   303     return err;
       
   304   }
       
   305 
       
   306 
       
   307   static FT_Error
       
   308   FT_GetFileRef_From_Mac_ATS_Name( const char*  fontName,
       
   309                                    FSRef*       ats_font_ref,
       
   310                                    FT_Long*     face_index )
       
   311   {
       
   312     CFStringRef  cf_fontName;
       
   313     ATSFontRef   ats_font_id;
       
   314 
       
   315 
       
   316     *face_index = 0;
       
   317 
       
   318     cf_fontName = CFStringCreateWithCString( NULL, fontName,
       
   319                                              kCFStringEncodingMacRoman );
       
   320     ats_font_id = ATSFontFindFromName( cf_fontName,
       
   321                                        kATSOptionFlagsUnRestrictedScope );
       
   322     CFRelease( cf_fontName );
       
   323 
       
   324     if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL )
       
   325       return FT_Err_Unknown_File_Format;
       
   326 
       
   327     if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) )
       
   328       return FT_Err_Unknown_File_Format;
       
   329 
       
   330     /* face_index calculation by searching preceding fontIDs */
       
   331     /* with same FSRef                                       */
       
   332     {
       
   333       ATSFontRef  id2 = ats_font_id - 1;
       
   334       FSRef       ref2;
       
   335 
       
   336 
       
   337       while ( id2 > 0 )
       
   338       {
       
   339         if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) )
       
   340           break;
       
   341         if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) )
       
   342           break;
       
   343 
       
   344         id2--;
       
   345       }
       
   346       *face_index = ats_font_id - ( id2 + 1 );
       
   347     }
       
   348 
       
   349     return FT_Err_Ok;
       
   350   }
       
   351 
       
   352 #endif
       
   353 
       
   354 #if !HAVE_ATS
       
   355 
       
   356   FT_EXPORT_DEF( FT_Error )
       
   357   FT_GetFilePath_From_Mac_ATS_Name( const char*  fontName,
       
   358                                     UInt8*       path,
       
   359                                     UInt32       maxPathSize,
       
   360                                     FT_Long*     face_index )
       
   361   {
       
   362     FT_UNUSED( fontName );
       
   363     FT_UNUSED( path );
       
   364     FT_UNUSED( maxPathSize );
       
   365     FT_UNUSED( face_index );
       
   366 
       
   367     return FT_Err_Unimplemented_Feature;
       
   368   }
       
   369 
       
   370 #else
       
   371 
       
   372   FT_EXPORT_DEF( FT_Error )
       
   373   FT_GetFilePath_From_Mac_ATS_Name( const char*  fontName,
       
   374                                     UInt8*       path,
       
   375                                     UInt32       maxPathSize,
       
   376                                     FT_Long*     face_index )
       
   377   {
       
   378     FSRef     ref;
       
   379     FT_Error  err;
       
   380 
       
   381 
       
   382     err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
       
   383     if ( FT_Err_Ok != err )
       
   384       return err;
       
   385 
       
   386     if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) )
       
   387       return FT_Err_Unknown_File_Format;
       
   388 
       
   389     return FT_Err_Ok;
       
   390   }
       
   391 
       
   392 #endif /* HAVE_ATS */
       
   393 
       
   394 
       
   395 #if !HAVE_FSSPEC || !HAVE_ATS
       
   396 
       
   397   FT_EXPORT_DEF( FT_Error )
       
   398   FT_GetFile_From_Mac_ATS_Name( const char*  fontName,
       
   399                                 FSSpec*      pathSpec,
       
   400                                 FT_Long*     face_index )
       
   401   {
       
   402     FT_UNUSED( fontName );
       
   403     FT_UNUSED( pathSpec );
       
   404     FT_UNUSED( face_index );
       
   405 
       
   406     return FT_Err_Unimplemented_Feature;
       
   407   }
       
   408 
       
   409 #else
       
   410 
       
   411   /* This function is deprecated because FSSpec is deprecated in Mac OS X. */
       
   412   FT_EXPORT_DEF( FT_Error )
       
   413   FT_GetFile_From_Mac_ATS_Name( const char*  fontName,
       
   414                                 FSSpec*      pathSpec,
       
   415                                 FT_Long*     face_index )
       
   416   {
       
   417     FSRef     ref;
       
   418     FT_Error  err;
       
   419 
       
   420 
       
   421     err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
       
   422     if ( FT_Err_Ok != err )
       
   423       return err;
       
   424 
       
   425     if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL,
       
   426                                     pathSpec, NULL ) )
       
   427       return FT_Err_Unknown_File_Format;
       
   428 
       
   429     return FT_Err_Ok;
       
   430   }
       
   431 
       
   432 #endif
       
   433 
       
   434 
       
   435 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
       
   436 
       
   437 #define STREAM_FILE( stream )  ( (FT_FILE*)stream->descriptor.pointer )
       
   438 
       
   439 
       
   440   FT_CALLBACK_DEF( void )
       
   441   ft_FSp_stream_close( FT_Stream  stream )
       
   442   {
       
   443     ft_fclose( STREAM_FILE( stream ) );
       
   444 
       
   445     stream->descriptor.pointer = NULL;
       
   446     stream->size               = 0;
       
   447     stream->base               = 0;
       
   448   }
       
   449 
       
   450 
       
   451   FT_CALLBACK_DEF( unsigned long )
       
   452   ft_FSp_stream_io( FT_Stream       stream,
       
   453                     unsigned long   offset,
       
   454                     unsigned char*  buffer,
       
   455                     unsigned long   count )
       
   456   {
       
   457     FT_FILE*  file;
       
   458 
       
   459 
       
   460     file = STREAM_FILE( stream );
       
   461 
       
   462     ft_fseek( file, offset, SEEK_SET );
       
   463 
       
   464     return (unsigned long)ft_fread( buffer, 1, count, file );
       
   465   }
       
   466 
       
   467 #endif  /* __MWERKS__ && !TARGET_RT_MAC_MACHO */
       
   468 
       
   469 
       
   470 #if HAVE_FSSPEC && !HAVE_FSREF
       
   471 
       
   472   /* isDirectory is a dummy to synchronize API with FSPathMakeRef() */
       
   473   static OSErr
       
   474   FT_FSPathMakeSpec( const UInt8*  pathname,
       
   475                      FSSpec*       spec_p,
       
   476                      Boolean       isDirectory )
       
   477   {
       
   478     const char  *p, *q;
       
   479     short       vRefNum;
       
   480     long        dirID;
       
   481     Str255      nodeName;
       
   482     OSErr       err;
       
   483     FT_UNUSED( isDirectory );
       
   484 
       
   485 
       
   486     p = q = (const char *)pathname;
       
   487     dirID   = 0;
       
   488     vRefNum = 0;
       
   489 
       
   490     while ( 1 )
       
   491     {
       
   492       int  len = ft_strlen( p );
       
   493 
       
   494 
       
   495       if ( len > 255 )
       
   496         len = 255;
       
   497 
       
   498       q = p + len;
       
   499 
       
   500       if ( q == p )
       
   501         return 0;
       
   502 
       
   503       if ( 255 < ft_strlen( (char *)pathname ) )
       
   504       {
       
   505         while ( p < q && *q != ':' )
       
   506           q--;
       
   507       }
       
   508 
       
   509       if ( p < q )
       
   510         *(char *)nodeName = q - p;
       
   511       else if ( ft_strlen( p ) < 256 )
       
   512         *(char *)nodeName = ft_strlen( p );
       
   513       else
       
   514         return errFSNameTooLong;
       
   515 
       
   516       ft_strncpy( (char *)nodeName + 1, (char *)p, *(char *)nodeName );
       
   517       err = FSMakeFSSpec( vRefNum, dirID, nodeName, spec_p );
       
   518       if ( err || '\0' == *q )
       
   519         return err;
       
   520 
       
   521       vRefNum = spec_p->vRefNum;
       
   522       dirID   = spec_p->parID;
       
   523 
       
   524       p = q;
       
   525     }
       
   526   }
       
   527 
       
   528 
       
   529   static OSErr
       
   530   FT_FSpMakePath( const FSSpec*  spec_p,
       
   531                   UInt8*         path,
       
   532                   UInt32         maxPathSize )
       
   533   {
       
   534     OSErr   err;
       
   535     FSSpec  spec = *spec_p;
       
   536     short   vRefNum;
       
   537     long    dirID;
       
   538     Str255  parDir_name;
       
   539 
       
   540 
       
   541     FT_MEM_SET( path, 0, maxPathSize );
       
   542     while ( 1 )
       
   543     {
       
   544       int             child_namelen = ft_strlen( (char *)path );
       
   545       unsigned char   node_namelen  = spec.name[0];
       
   546       unsigned char*  node_name     = spec.name + 1;
       
   547 
       
   548 
       
   549       if ( node_namelen + child_namelen > maxPathSize )
       
   550         return errFSNameTooLong;
       
   551 
       
   552       FT_MEM_MOVE( path + node_namelen + 1, path, child_namelen );
       
   553       FT_MEM_COPY( path, node_name, node_namelen );
       
   554       if ( child_namelen > 0 )
       
   555         path[node_namelen] = ':';
       
   556 
       
   557       vRefNum        = spec.vRefNum;
       
   558       dirID          = spec.parID;
       
   559       parDir_name[0] = '\0';
       
   560       err = FSMakeFSSpec( vRefNum, dirID, parDir_name, &spec );
       
   561       if ( noErr != err || dirID == spec.parID )
       
   562         break;
       
   563     }
       
   564     return noErr;
       
   565   }
       
   566 
       
   567 #endif /* HAVE_FSSPEC && !HAVE_FSREF */
       
   568 
       
   569 
       
   570   static OSErr
       
   571   FT_FSPathMakeRes( const UInt8*    pathname,
       
   572                     ResFileRefNum*  res )
       
   573   {
       
   574 
       
   575 #if HAVE_FSREF
       
   576 
       
   577     OSErr  err;
       
   578     FSRef  ref;
       
   579 
       
   580 
       
   581     if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
       
   582       return FT_Err_Cannot_Open_Resource;
       
   583 
       
   584     /* at present, no support for dfont format */
       
   585     err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res );
       
   586     if ( noErr == err )
       
   587       return err;
       
   588 
       
   589     /* fallback to original resource-fork font */
       
   590     *res = FSOpenResFile( &ref, fsRdPerm );
       
   591     err  = ResError();
       
   592 
       
   593 #else
       
   594 
       
   595     OSErr   err;
       
   596     FSSpec  spec;
       
   597 
       
   598 
       
   599     if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) )
       
   600       return FT_Err_Cannot_Open_Resource;
       
   601 
       
   602     /* at present, no support for dfont format without FSRef */
       
   603     /* (see above), try original resource-fork font          */
       
   604     *res = FSpOpenResFile( &spec, fsRdPerm );
       
   605     err  = ResError();
       
   606 
       
   607 #endif /* HAVE_FSREF */
       
   608 
       
   609     return err;
       
   610   }
       
   611 
       
   612 
       
   613   /* Return the file type for given pathname */
       
   614   static OSType
       
   615   get_file_type_from_path( const UInt8*  pathname )
       
   616   {
       
   617 
       
   618 #if HAVE_FSREF
       
   619 
       
   620     FSRef          ref;
       
   621     FSCatalogInfo  info;
       
   622 
       
   623 
       
   624     if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
       
   625       return ( OSType ) 0;
       
   626 
       
   627     if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info,
       
   628                                     NULL, NULL, NULL ) )
       
   629       return ( OSType ) 0;
       
   630 
       
   631     return ((FInfo *)(info.finderInfo))->fdType;
       
   632 
       
   633 #else
       
   634 
       
   635     FSSpec  spec;
       
   636     FInfo   finfo;
       
   637 
       
   638 
       
   639     if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) )
       
   640       return ( OSType ) 0;
       
   641 
       
   642     if ( noErr != FSpGetFInfo( &spec, &finfo ) )
       
   643       return ( OSType ) 0;
       
   644 
       
   645     return finfo.fdType;
       
   646 
       
   647 #endif /* HAVE_FSREF */
       
   648 
       
   649   }
       
   650 
       
   651 
       
   652   /* Given a PostScript font name, create the Macintosh LWFN file name. */
       
   653   static void
       
   654   create_lwfn_name( char*   ps_name,
       
   655                     Str255  lwfn_file_name )
       
   656   {
       
   657     int       max = 5, count = 0;
       
   658     FT_Byte*  p = lwfn_file_name;
       
   659     FT_Byte*  q = (FT_Byte*)ps_name;
       
   660 
       
   661 
       
   662     lwfn_file_name[0] = 0;
       
   663 
       
   664     while ( *q )
       
   665     {
       
   666       if ( ft_isupper( *q ) )
       
   667       {
       
   668         if ( count )
       
   669           max = 3;
       
   670         count = 0;
       
   671       }
       
   672       if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
       
   673       {
       
   674         *++p = *q;
       
   675         lwfn_file_name[0]++;
       
   676         count++;
       
   677       }
       
   678       q++;
       
   679     }
       
   680   }
       
   681 
       
   682 
       
   683   static short
       
   684   count_faces_sfnt( char*  fond_data )
       
   685   {
       
   686     /* The count is 1 greater than the value in the FOND.  */
       
   687     /* Isn't that cute? :-)                                */
       
   688 
       
   689     return EndianS16_BtoN( *( (short*)( fond_data +
       
   690                                         sizeof ( FamRec ) ) ) ) + 1;
       
   691   }
       
   692 
       
   693 
       
   694   static short
       
   695   count_faces_scalable( char*  fond_data )
       
   696   {
       
   697     AsscEntry*  assoc;
       
   698     FamRec*     fond;
       
   699     short       i, face, face_all;
       
   700 
       
   701 
       
   702     fond     = (FamRec*)fond_data;
       
   703     face_all = EndianS16_BtoN( *( (short *)( fond_data +
       
   704                                              sizeof ( FamRec ) ) ) ) + 1;
       
   705     assoc    = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
       
   706     face     = 0;
       
   707 
       
   708     for ( i = 0; i < face_all; i++ )
       
   709     {
       
   710       if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) )
       
   711         face++;
       
   712     }
       
   713     return face;
       
   714   }
       
   715 
       
   716 
       
   717   /* Look inside the FOND data, answer whether there should be an SFNT
       
   718      resource, and answer the name of a possible LWFN Type 1 file.
       
   719 
       
   720      Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
       
   721      to load a face OTHER than the first one in the FOND!
       
   722   */
       
   723 
       
   724   static void
       
   725   parse_fond( char*   fond_data,
       
   726               short*  have_sfnt,
       
   727               ResID*  sfnt_id,
       
   728               Str255  lwfn_file_name,
       
   729               short   face_index )
       
   730   {
       
   731     AsscEntry*  assoc;
       
   732     AsscEntry*  base_assoc;
       
   733     FamRec*     fond;
       
   734 
       
   735 
       
   736     *sfnt_id          = 0;
       
   737     *have_sfnt        = 0;
       
   738     lwfn_file_name[0] = 0;
       
   739 
       
   740     fond       = (FamRec*)fond_data;
       
   741     assoc      = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
       
   742     base_assoc = assoc;
       
   743 
       
   744     /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */
       
   745     if ( 47 < face_index )
       
   746       return;
       
   747 
       
   748     /* Let's do a little range checking before we get too excited here */
       
   749     if ( face_index < count_faces_sfnt( fond_data ) )
       
   750     {
       
   751       assoc += face_index;        /* add on the face_index! */
       
   752 
       
   753       /* if the face at this index is not scalable,
       
   754          fall back to the first one (old behavior) */
       
   755       if ( EndianS16_BtoN( assoc->fontSize ) == 0 )
       
   756       {
       
   757         *have_sfnt = 1;
       
   758         *sfnt_id   = EndianS16_BtoN( assoc->fontID );
       
   759       }
       
   760       else if ( base_assoc->fontSize == 0 )
       
   761       {
       
   762         *have_sfnt = 1;
       
   763         *sfnt_id   = EndianS16_BtoN( base_assoc->fontID );
       
   764       }
       
   765     }
       
   766 
       
   767     if ( EndianS32_BtoN( fond->ffStylOff ) )
       
   768     {
       
   769       unsigned char*  p = (unsigned char*)fond_data;
       
   770       StyleTable*     style;
       
   771       unsigned short  string_count;
       
   772       char            ps_name[256];
       
   773       unsigned char*  names[64];
       
   774       int             i;
       
   775 
       
   776 
       
   777       p += EndianS32_BtoN( fond->ffStylOff );
       
   778       style = (StyleTable*)p;
       
   779       p += sizeof ( StyleTable );
       
   780       string_count = EndianS16_BtoN( *(short*)(p) );
       
   781       p += sizeof ( short );
       
   782 
       
   783       for ( i = 0; i < string_count && i < 64; i++ )
       
   784       {
       
   785         names[i] = p;
       
   786         p       += names[i][0];
       
   787         p++;
       
   788       }
       
   789 
       
   790       {
       
   791         size_t  ps_name_len = (size_t)names[0][0];
       
   792 
       
   793 
       
   794         if ( ps_name_len != 0 )
       
   795         {
       
   796           ft_memcpy(ps_name, names[0] + 1, ps_name_len);
       
   797           ps_name[ps_name_len] = 0;
       
   798         }
       
   799         if ( style->indexes[face_index] > 1 &&
       
   800              style->indexes[face_index] <= FT_MIN( string_count, 64 ) )
       
   801         {
       
   802           unsigned char*  suffixes = names[style->indexes[face_index] - 1];
       
   803 
       
   804 
       
   805           for ( i = 1; i <= suffixes[0]; i++ )
       
   806           {
       
   807             unsigned char*  s;
       
   808             size_t          j = suffixes[i] - 1;
       
   809 
       
   810 
       
   811             if ( j < string_count && ( s = names[j] ) != NULL )
       
   812             {
       
   813               size_t  s_len = (size_t)s[0];
       
   814 
       
   815 
       
   816               if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
       
   817               {
       
   818                 ft_memcpy( ps_name + ps_name_len, s + 1, s_len );
       
   819                 ps_name_len += s_len;
       
   820                 ps_name[ps_name_len] = 0;
       
   821               }
       
   822             }
       
   823           }
       
   824         }
       
   825       }
       
   826 
       
   827       create_lwfn_name( ps_name, lwfn_file_name );
       
   828     }
       
   829   }
       
   830 
       
   831 
       
   832   static  FT_Error
       
   833   lookup_lwfn_by_fond( const UInt8*      path_fond,
       
   834                        ConstStr255Param  base_lwfn,
       
   835                        UInt8*            path_lwfn,
       
   836                        int               path_size )
       
   837   {
       
   838 
       
   839 #if HAVE_FSREF
       
   840 
       
   841     FSRef  ref, par_ref;
       
   842     int    dirname_len;
       
   843 
       
   844 
       
   845     /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */
       
   846     /* We should not extract parent directory by string manipulation.      */
       
   847 
       
   848     if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) )
       
   849       return FT_Err_Invalid_Argument;
       
   850 
       
   851     if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
       
   852                                     NULL, NULL, NULL, &par_ref ) )
       
   853       return FT_Err_Invalid_Argument;
       
   854 
       
   855     if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) )
       
   856       return FT_Err_Invalid_Argument;
       
   857 
       
   858     if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size )
       
   859       return FT_Err_Invalid_Argument;
       
   860 
       
   861     /* now we have absolute dirname in path_lwfn */
       
   862     if ( path_lwfn[0] == '/' )
       
   863       ft_strcat( (char *)path_lwfn, "/" );
       
   864     else
       
   865       ft_strcat( (char *)path_lwfn, ":" );
       
   866 
       
   867     dirname_len = ft_strlen( (char *)path_lwfn );
       
   868     ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 );
       
   869     path_lwfn[dirname_len + base_lwfn[0]] = '\0';
       
   870 
       
   871     if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) )
       
   872       return FT_Err_Cannot_Open_Resource;
       
   873 
       
   874     if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
       
   875                                     NULL, NULL, NULL, NULL ) )
       
   876       return FT_Err_Cannot_Open_Resource;
       
   877 
       
   878     return FT_Err_Ok;
       
   879 
       
   880 #else
       
   881 
       
   882     int     i;
       
   883     FSSpec  spec;
       
   884 
       
   885 
       
   886     /* pathname for FSSpec is always HFS format */
       
   887     if ( ft_strlen( (char *)path_fond ) > path_size )
       
   888       return FT_Err_Invalid_Argument;
       
   889 
       
   890     ft_strcpy( (char *)path_lwfn, (char *)path_fond );
       
   891 
       
   892     i = ft_strlen( (char *)path_lwfn ) - 1;
       
   893     while ( i > 0 && ':' != path_lwfn[i] )
       
   894       i--;
       
   895 
       
   896     if ( i + 1 + base_lwfn[0] > path_size )
       
   897       return FT_Err_Invalid_Argument;
       
   898 
       
   899     if ( ':' == path_lwfn[i] )
       
   900     {
       
   901       ft_strcpy( (char *)path_lwfn + i + 1, (char *)base_lwfn + 1 );
       
   902       path_lwfn[i + 1 + base_lwfn[0]] = '\0';
       
   903     }
       
   904     else
       
   905     {
       
   906       ft_strcpy( (char *)path_lwfn, (char *)base_lwfn + 1 );
       
   907       path_lwfn[base_lwfn[0]] = '\0';
       
   908     }
       
   909 
       
   910     if ( noErr != FT_FSPathMakeSpec( path_lwfn, &spec, FALSE ) )
       
   911       return FT_Err_Cannot_Open_Resource;
       
   912 
       
   913     return FT_Err_Ok;
       
   914 
       
   915 #endif /* HAVE_FSREF */
       
   916 
       
   917   }
       
   918 
       
   919 
       
   920   static short
       
   921   count_faces( Handle        fond,
       
   922                const UInt8*  pathname )
       
   923   {
       
   924     ResID     sfnt_id;
       
   925     short     have_sfnt, have_lwfn;
       
   926     Str255    lwfn_file_name;
       
   927     UInt8     buff[PATH_MAX];
       
   928     FT_Error  err;
       
   929     short     num_faces;
       
   930 
       
   931 
       
   932     have_sfnt = have_lwfn = 0;
       
   933 
       
   934     HLock( fond );
       
   935     parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 );
       
   936 
       
   937     if ( lwfn_file_name[0] )
       
   938     {
       
   939       err = lookup_lwfn_by_fond( pathname, lwfn_file_name,
       
   940                                  buff, sizeof ( buff )  );
       
   941       if ( FT_Err_Ok == err )
       
   942         have_lwfn = 1;
       
   943     }
       
   944 
       
   945     if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
       
   946       num_faces = 1;
       
   947     else
       
   948       num_faces = count_faces_scalable( *fond );
       
   949 
       
   950     HUnlock( fond );
       
   951     return num_faces;
       
   952   }
       
   953 
       
   954 
       
   955   /* Read Type 1 data from the POST resources inside the LWFN file,
       
   956      return a PFB buffer.  This is somewhat convoluted because the FT2
       
   957      PFB parser wants the ASCII header as one chunk, and the LWFN
       
   958      chunks are often not organized that way, so we glue chunks
       
   959      of the same type together. */
       
   960   static FT_Error
       
   961   read_lwfn( FT_Memory      memory,
       
   962              ResFileRefNum  res,
       
   963              FT_Byte**      pfb_data,
       
   964              FT_ULong*      size )
       
   965   {
       
   966     FT_Error       error = FT_Err_Ok;
       
   967     ResID          res_id;
       
   968     unsigned char  *buffer, *p, *size_p = NULL;
       
   969     FT_ULong       total_size = 0;
       
   970     FT_ULong       old_total_size = 0;
       
   971     FT_ULong       post_size, pfb_chunk_size;
       
   972     Handle         post_data;
       
   973     char           code, last_code;
       
   974 
       
   975 
       
   976     UseResFile( res );
       
   977 
       
   978     /* First pass: load all POST resources, and determine the size of */
       
   979     /* the output buffer.                                             */
       
   980     res_id    = 501;
       
   981     last_code = -1;
       
   982 
       
   983     for (;;)
       
   984     {
       
   985       post_data = Get1Resource( TTAG_POST, res_id++ );
       
   986       if ( post_data == NULL )
       
   987         break;  /* we are done */
       
   988 
       
   989       code = (*post_data)[0];
       
   990 
       
   991       if ( code != last_code )
       
   992       {
       
   993         if ( code == 5 )
       
   994           total_size += 2; /* just the end code */
       
   995         else
       
   996           total_size += 6; /* code + 4 bytes chunk length */
       
   997       }
       
   998 
       
   999       total_size += GetHandleSize( post_data ) - 2;
       
  1000       last_code = code;
       
  1001 
       
  1002       /* detect integer overflows */
       
  1003       if ( total_size < old_total_size )
       
  1004       {
       
  1005         error = FT_Err_Array_Too_Large;
       
  1006         goto Error;
       
  1007       }
       
  1008 
       
  1009       old_total_size = total_size;
       
  1010     }
       
  1011 
       
  1012     if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
       
  1013       goto Error;
       
  1014 
       
  1015     /* Second pass: append all POST data to the buffer, add PFB fields. */
       
  1016     /* Glue all consecutive chunks of the same type together.           */
       
  1017     p              = buffer;
       
  1018     res_id         = 501;
       
  1019     last_code      = -1;
       
  1020     pfb_chunk_size = 0;
       
  1021 
       
  1022     for (;;)
       
  1023     {
       
  1024       post_data = Get1Resource( TTAG_POST, res_id++ );
       
  1025       if ( post_data == NULL )
       
  1026         break;  /* we are done */
       
  1027 
       
  1028       post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
       
  1029       code = (*post_data)[0];
       
  1030 
       
  1031       if ( code != last_code )
       
  1032       {
       
  1033         if ( last_code != -1 )
       
  1034         {
       
  1035           /* we are done adding a chunk, fill in the size field */
       
  1036           if ( size_p != NULL )
       
  1037           {
       
  1038             *size_p++ = (FT_Byte)(   pfb_chunk_size         & 0xFF );
       
  1039             *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8  ) & 0xFF );
       
  1040             *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
       
  1041             *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
       
  1042           }
       
  1043           pfb_chunk_size = 0;
       
  1044         }
       
  1045 
       
  1046         *p++ = 0x80;
       
  1047         if ( code == 5 )
       
  1048           *p++ = 0x03;  /* the end */
       
  1049         else if ( code == 2 )
       
  1050           *p++ = 0x02;  /* binary segment */
       
  1051         else
       
  1052           *p++ = 0x01;  /* ASCII segment */
       
  1053 
       
  1054         if ( code != 5 )
       
  1055         {
       
  1056           size_p = p;   /* save for later */
       
  1057           p += 4;       /* make space for size field */
       
  1058         }
       
  1059       }
       
  1060 
       
  1061       ft_memcpy( p, *post_data + 2, post_size );
       
  1062       pfb_chunk_size += post_size;
       
  1063       p += post_size;
       
  1064       last_code = code;
       
  1065     }
       
  1066 
       
  1067     *pfb_data = buffer;
       
  1068     *size = total_size;
       
  1069 
       
  1070   Error:
       
  1071     CloseResFile( res );
       
  1072     return error;
       
  1073   }
       
  1074 
       
  1075 
       
  1076   /* Create a new FT_Face from a file spec to an LWFN file. */
       
  1077   static FT_Error
       
  1078   FT_New_Face_From_LWFN( FT_Library    library,
       
  1079                          const UInt8*  pathname,
       
  1080                          FT_Long       face_index,
       
  1081                          FT_Face*      aface )
       
  1082   {
       
  1083     FT_Byte*       pfb_data;
       
  1084     FT_ULong       pfb_size;
       
  1085     FT_Error       error;
       
  1086     ResFileRefNum  res;
       
  1087 
       
  1088 
       
  1089     if ( noErr != FT_FSPathMakeRes( pathname, &res ) )
       
  1090       return FT_Err_Cannot_Open_Resource;
       
  1091 
       
  1092     pfb_data = NULL;
       
  1093     pfb_size = 0;
       
  1094     error = read_lwfn( library->memory, res, &pfb_data, &pfb_size );
       
  1095     CloseResFile( res ); /* PFB is already loaded, useless anymore */
       
  1096     if ( error )
       
  1097       return error;
       
  1098 
       
  1099     return open_face_from_buffer( library,
       
  1100                                   pfb_data,
       
  1101                                   pfb_size,
       
  1102                                   face_index,
       
  1103                                   "type1",
       
  1104                                   aface );
       
  1105   }
       
  1106 
       
  1107 
       
  1108   /* Create a new FT_Face from an SFNT resource, specified by res ID. */
       
  1109   static FT_Error
       
  1110   FT_New_Face_From_SFNT( FT_Library  library,
       
  1111                          ResID       sfnt_id,
       
  1112                          FT_Long     face_index,
       
  1113                          FT_Face*    aface )
       
  1114   {
       
  1115     Handle     sfnt = NULL;
       
  1116     FT_Byte*   sfnt_data;
       
  1117     size_t     sfnt_size;
       
  1118     FT_Error   error  = FT_Err_Ok;
       
  1119     FT_Memory  memory = library->memory;
       
  1120     int        is_cff, is_sfnt_ps;
       
  1121 
       
  1122 
       
  1123     sfnt = GetResource( TTAG_sfnt, sfnt_id );
       
  1124     if ( sfnt == NULL )
       
  1125       return FT_Err_Invalid_Handle;
       
  1126 
       
  1127     sfnt_size = (FT_ULong)GetHandleSize( sfnt );
       
  1128     if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
       
  1129     {
       
  1130       ReleaseResource( sfnt );
       
  1131       return error;
       
  1132     }
       
  1133 
       
  1134     HLock( sfnt );
       
  1135     ft_memcpy( sfnt_data, *sfnt, sfnt_size );
       
  1136     HUnlock( sfnt );
       
  1137     ReleaseResource( sfnt );
       
  1138 
       
  1139     is_cff     = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
       
  1140     is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 );
       
  1141 
       
  1142     if ( is_sfnt_ps )
       
  1143     {
       
  1144       FT_Stream  stream;
       
  1145 
       
  1146 
       
  1147       if ( FT_NEW( stream ) )
       
  1148         goto Try_OpenType;
       
  1149 
       
  1150       FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size );
       
  1151       if ( !open_face_PS_from_sfnt_stream( library,
       
  1152                                            stream,
       
  1153                                            face_index,
       
  1154                                            0, NULL,
       
  1155                                            aface ) )
       
  1156       {
       
  1157         FT_Stream_Close( stream );
       
  1158         FT_FREE( stream );
       
  1159         FT_FREE( sfnt_data );
       
  1160         goto Exit;
       
  1161       }
       
  1162 
       
  1163       FT_FREE( stream );
       
  1164     }
       
  1165   Try_OpenType:
       
  1166     error = open_face_from_buffer( library,
       
  1167                                    sfnt_data,
       
  1168                                    sfnt_size,
       
  1169                                    face_index,
       
  1170                                    is_cff ? "cff" : "truetype",
       
  1171                                    aface );
       
  1172   Exit:
       
  1173     return error;
       
  1174   }
       
  1175 
       
  1176 
       
  1177   /* Create a new FT_Face from a file spec to a suitcase file. */
       
  1178   static FT_Error
       
  1179   FT_New_Face_From_Suitcase( FT_Library    library,
       
  1180                              const UInt8*  pathname,
       
  1181                              FT_Long       face_index,
       
  1182                              FT_Face*      aface )
       
  1183   {
       
  1184     FT_Error       error = FT_Err_Cannot_Open_Resource;
       
  1185     ResFileRefNum  res_ref;
       
  1186     ResourceIndex  res_index;
       
  1187     Handle         fond;
       
  1188     short          num_faces_in_res, num_faces_in_fond;
       
  1189 
       
  1190 
       
  1191     if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) )
       
  1192       return FT_Err_Cannot_Open_Resource;
       
  1193 
       
  1194     UseResFile( res_ref );
       
  1195     if ( ResError() )
       
  1196       return FT_Err_Cannot_Open_Resource;
       
  1197 
       
  1198     num_faces_in_res = 0;
       
  1199     for ( res_index = 1; ; ++res_index )
       
  1200     {
       
  1201       fond = Get1IndResource( TTAG_FOND, res_index );
       
  1202       if ( ResError() )
       
  1203         break;
       
  1204 
       
  1205       num_faces_in_fond  = count_faces( fond, pathname );
       
  1206       num_faces_in_res  += num_faces_in_fond;
       
  1207 
       
  1208       if ( 0 <= face_index && face_index < num_faces_in_fond && error )
       
  1209         error = FT_New_Face_From_FOND( library, fond, face_index, aface );
       
  1210 
       
  1211       face_index -= num_faces_in_fond;
       
  1212     }
       
  1213 
       
  1214     CloseResFile( res_ref );
       
  1215     if ( FT_Err_Ok == error && NULL != aface )
       
  1216       (*aface)->num_faces = num_faces_in_res;
       
  1217     return error;
       
  1218   }
       
  1219 
       
  1220 
       
  1221   /* documentation is in ftmac.h */
       
  1222 
       
  1223   FT_EXPORT_DEF( FT_Error )
       
  1224   FT_New_Face_From_FOND( FT_Library  library,
       
  1225                          Handle      fond,
       
  1226                          FT_Long     face_index,
       
  1227                          FT_Face*    aface )
       
  1228   {
       
  1229     short     have_sfnt, have_lwfn = 0;
       
  1230     ResID     sfnt_id, fond_id;
       
  1231     OSType    fond_type;
       
  1232     Str255    fond_name;
       
  1233     Str255    lwfn_file_name;
       
  1234     UInt8     path_lwfn[PATH_MAX];
       
  1235     OSErr     err;
       
  1236     FT_Error  error = FT_Err_Ok;
       
  1237 
       
  1238 
       
  1239     GetResInfo( fond, &fond_id, &fond_type, fond_name );
       
  1240     if ( ResError() != noErr || fond_type != TTAG_FOND )
       
  1241       return FT_Err_Invalid_File_Format;
       
  1242 
       
  1243     HLock( fond );
       
  1244     parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
       
  1245     HUnlock( fond );
       
  1246 
       
  1247     if ( lwfn_file_name[0] )
       
  1248     {
       
  1249       ResFileRefNum  res;
       
  1250 
       
  1251 
       
  1252       res = HomeResFile( fond );
       
  1253       if ( noErr != ResError() )
       
  1254         goto found_no_lwfn_file;
       
  1255 
       
  1256 #if HAVE_FSREF
       
  1257 
       
  1258       {
       
  1259         UInt8  path_fond[PATH_MAX];
       
  1260         FSRef  ref;
       
  1261 
       
  1262 
       
  1263         err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum,
       
  1264                                NULL, NULL, NULL, &ref, NULL );
       
  1265         if ( noErr != err )
       
  1266           goto found_no_lwfn_file;
       
  1267 
       
  1268         err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) );
       
  1269         if ( noErr != err )
       
  1270           goto found_no_lwfn_file;
       
  1271 
       
  1272         error = lookup_lwfn_by_fond( path_fond, lwfn_file_name,
       
  1273                                      path_lwfn, sizeof ( path_lwfn ) );
       
  1274         if ( FT_Err_Ok == error )
       
  1275           have_lwfn = 1;
       
  1276       }
       
  1277 
       
  1278 #elif HAVE_FSSPEC
       
  1279 
       
  1280       {
       
  1281         UInt8     path_fond[PATH_MAX];
       
  1282         FCBPBRec  pb;
       
  1283         Str255    fond_file_name;
       
  1284         FSSpec    spec;
       
  1285 
       
  1286 
       
  1287         FT_MEM_SET( &spec, 0, sizeof ( FSSpec ) );
       
  1288         FT_MEM_SET( &pb,   0, sizeof ( FCBPBRec ) );
       
  1289 
       
  1290         pb.ioNamePtr = fond_file_name;
       
  1291         pb.ioVRefNum = 0;
       
  1292         pb.ioRefNum  = res;
       
  1293         pb.ioFCBIndx = 0;
       
  1294 
       
  1295         err = PBGetFCBInfoSync( &pb );
       
  1296         if ( noErr != err )
       
  1297           goto found_no_lwfn_file;
       
  1298 
       
  1299         err = FSMakeFSSpec( pb.ioFCBVRefNum, pb.ioFCBParID,
       
  1300                             fond_file_name, &spec );
       
  1301         if ( noErr != err )
       
  1302           goto found_no_lwfn_file;
       
  1303 
       
  1304         err = FT_FSpMakePath( &spec, path_fond, sizeof ( path_fond ) );
       
  1305         if ( noErr != err )
       
  1306           goto found_no_lwfn_file;
       
  1307 
       
  1308         error = lookup_lwfn_by_fond( path_fond, lwfn_file_name,
       
  1309                                      path_lwfn, sizeof ( path_lwfn ) );
       
  1310         if ( FT_Err_Ok == error )
       
  1311           have_lwfn = 1;
       
  1312       }
       
  1313 
       
  1314 #endif /* HAVE_FSREF, HAVE_FSSPEC */
       
  1315 
       
  1316     }
       
  1317 
       
  1318     if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
       
  1319       error = FT_New_Face_From_LWFN( library,
       
  1320                                      path_lwfn,
       
  1321                                      face_index,
       
  1322                                      aface );
       
  1323     else
       
  1324       error = FT_Err_Unknown_File_Format;
       
  1325 
       
  1326   found_no_lwfn_file:
       
  1327     if ( have_sfnt && FT_Err_Ok != error )
       
  1328       error = FT_New_Face_From_SFNT( library,
       
  1329                                      sfnt_id,
       
  1330                                      face_index,
       
  1331                                      aface );
       
  1332 
       
  1333     return error;
       
  1334   }
       
  1335 
       
  1336 
       
  1337   /* Common function to load a new FT_Face from a resource file. */
       
  1338   static FT_Error
       
  1339   FT_New_Face_From_Resource( FT_Library    library,
       
  1340                              const UInt8*  pathname,
       
  1341                              FT_Long       face_index,
       
  1342                              FT_Face*      aface )
       
  1343   {
       
  1344     OSType    file_type;
       
  1345     FT_Error  error;
       
  1346 
       
  1347 
       
  1348     /* LWFN is a (very) specific file format, check for it explicitly */
       
  1349     file_type = get_file_type_from_path( pathname );
       
  1350     if ( file_type == TTAG_LWFN )
       
  1351       return FT_New_Face_From_LWFN( library, pathname, face_index, aface );
       
  1352 
       
  1353     /* Otherwise the file type doesn't matter (there are more than  */
       
  1354     /* `FFIL' and `tfil').  Just try opening it as a font suitcase; */
       
  1355     /* if it works, fine.                                           */
       
  1356 
       
  1357     error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface );
       
  1358     if ( error == 0 )
       
  1359       return error;
       
  1360 
       
  1361     /* let it fall through to normal loader (.ttf, .otf, etc.); */
       
  1362     /* we signal this by returning no error and no FT_Face      */
       
  1363     *aface = NULL;
       
  1364     return 0;
       
  1365   }
       
  1366 
       
  1367 
       
  1368   /*************************************************************************/
       
  1369   /*                                                                       */
       
  1370   /* <Function>                                                            */
       
  1371   /*    FT_New_Face                                                        */
       
  1372   /*                                                                       */
       
  1373   /* <Description>                                                         */
       
  1374   /*    This is the Mac-specific implementation of FT_New_Face.  In        */
       
  1375   /*    addition to the standard FT_New_Face() functionality, it also      */
       
  1376   /*    accepts pathnames to Mac suitcase files.  For further              */
       
  1377   /*    documentation see the original FT_New_Face() in freetype.h.        */
       
  1378   /*                                                                       */
       
  1379   FT_EXPORT_DEF( FT_Error )
       
  1380   FT_New_Face( FT_Library   library,
       
  1381                const char*  pathname,
       
  1382                FT_Long      face_index,
       
  1383                FT_Face*     aface )
       
  1384   {
       
  1385     FT_Open_Args  args;
       
  1386     FT_Error      error;
       
  1387 
       
  1388 
       
  1389     /* test for valid `library' and `aface' delayed to FT_Open_Face() */
       
  1390     if ( !pathname )
       
  1391       return FT_Err_Invalid_Argument;
       
  1392 
       
  1393     error  = FT_Err_Ok;
       
  1394     *aface = NULL;
       
  1395 
       
  1396     /* try resourcefork based font: LWFN, FFIL */
       
  1397     error = FT_New_Face_From_Resource( library, (UInt8 *)pathname,
       
  1398                                        face_index, aface );
       
  1399     if ( error != 0 || *aface != NULL )
       
  1400       return error;
       
  1401 
       
  1402     /* let it fall through to normal loader (.ttf, .otf, etc.) */
       
  1403     args.flags    = FT_OPEN_PATHNAME;
       
  1404     args.pathname = (char*)pathname;
       
  1405     return FT_Open_Face( library, &args, face_index, aface );
       
  1406   }
       
  1407 
       
  1408 
       
  1409   /*************************************************************************/
       
  1410   /*                                                                       */
       
  1411   /* <Function>                                                            */
       
  1412   /*    FT_New_Face_From_FSRef                                             */
       
  1413   /*                                                                       */
       
  1414   /* <Description>                                                         */
       
  1415   /*    FT_New_Face_From_FSRef is identical to FT_New_Face except it       */
       
  1416   /*    accepts an FSRef instead of a path.                                */
       
  1417   /*                                                                       */
       
  1418   /* This function is deprecated because Carbon data types (FSRef)         */
       
  1419   /* are not cross-platform, and thus not suitable for the freetype API.   */
       
  1420   FT_EXPORT_DEF( FT_Error )
       
  1421   FT_New_Face_From_FSRef( FT_Library    library,
       
  1422                           const FSRef*  ref,
       
  1423                           FT_Long       face_index,
       
  1424                           FT_Face*      aface )
       
  1425   {
       
  1426 
       
  1427 #if !HAVE_FSREF
       
  1428 
       
  1429     FT_UNUSED( library );
       
  1430     FT_UNUSED( ref );
       
  1431     FT_UNUSED( face_index );
       
  1432     FT_UNUSED( aface );
       
  1433 
       
  1434     return FT_Err_Unimplemented_Feature;
       
  1435 
       
  1436 #else
       
  1437 
       
  1438     FT_Error      error;
       
  1439     FT_Open_Args  args;
       
  1440     OSErr   err;
       
  1441     UInt8   pathname[PATH_MAX];
       
  1442 
       
  1443 
       
  1444     if ( !ref )
       
  1445       return FT_Err_Invalid_Argument;
       
  1446 
       
  1447     err = FSRefMakePath( ref, pathname, sizeof ( pathname ) );
       
  1448     if ( err )
       
  1449       error = FT_Err_Cannot_Open_Resource;
       
  1450 
       
  1451     error = FT_New_Face_From_Resource( library, pathname, face_index, aface );
       
  1452     if ( error != 0 || *aface != NULL )
       
  1453       return error;
       
  1454 
       
  1455     /* fallback to datafork font */
       
  1456     args.flags    = FT_OPEN_PATHNAME;
       
  1457     args.pathname = (char*)pathname;
       
  1458     return FT_Open_Face( library, &args, face_index, aface );
       
  1459 
       
  1460 #endif /* HAVE_FSREF */
       
  1461 
       
  1462   }
       
  1463 
       
  1464 
       
  1465   /*************************************************************************/
       
  1466   /*                                                                       */
       
  1467   /* <Function>                                                            */
       
  1468   /*    FT_New_Face_From_FSSpec                                            */
       
  1469   /*                                                                       */
       
  1470   /* <Description>                                                         */
       
  1471   /*    FT_New_Face_From_FSSpec is identical to FT_New_Face except it      */
       
  1472   /*    accepts an FSSpec instead of a path.                               */
       
  1473   /*                                                                       */
       
  1474   /* This function is deprecated because Carbon data types (FSSpec)        */
       
  1475   /* are not cross-platform, and thus not suitable for the freetype API.   */
       
  1476   FT_EXPORT_DEF( FT_Error )
       
  1477   FT_New_Face_From_FSSpec( FT_Library     library,
       
  1478                            const FSSpec*  spec,
       
  1479                            FT_Long        face_index,
       
  1480                            FT_Face*       aface )
       
  1481   {
       
  1482 
       
  1483 #if HAVE_FSREF
       
  1484 
       
  1485     FSRef  ref;
       
  1486 
       
  1487 
       
  1488     if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr )
       
  1489       return FT_Err_Invalid_Argument;
       
  1490     else
       
  1491       return FT_New_Face_From_FSRef( library, &ref, face_index, aface );
       
  1492 
       
  1493 #elif HAVE_FSSPEC
       
  1494 
       
  1495     FT_Error      error;
       
  1496     FT_Open_Args  args;
       
  1497     OSErr         err;
       
  1498     UInt8         pathname[PATH_MAX];
       
  1499 
       
  1500 
       
  1501     if ( !spec )
       
  1502       return FT_Err_Invalid_Argument;
       
  1503 
       
  1504     err = FT_FSpMakePath( spec, pathname, sizeof ( pathname ) );
       
  1505     if ( err )
       
  1506       error = FT_Err_Cannot_Open_Resource;
       
  1507 
       
  1508     error = FT_New_Face_From_Resource( library, pathname, face_index, aface );
       
  1509     if ( error != 0 || *aface != NULL )
       
  1510       return error;
       
  1511 
       
  1512     /* fallback to datafork font */
       
  1513     args.flags    = FT_OPEN_PATHNAME;
       
  1514     args.pathname = (char*)pathname;
       
  1515     return FT_Open_Face( library, &args, face_index, aface );
       
  1516 
       
  1517 #else
       
  1518 
       
  1519     FT_UNUSED( library );
       
  1520     FT_UNUSED( spec );
       
  1521     FT_UNUSED( face_index );
       
  1522     FT_UNUSED( aface );
       
  1523 
       
  1524     return FT_Err_Unimplemented_Feature;
       
  1525 
       
  1526 #endif /* HAVE_FSREF, HAVE_FSSPEC */
       
  1527 
       
  1528   }
       
  1529 
       
  1530 
       
  1531 /* END */