PageRenderTime 73ms CodeModel.GetById 19ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 0ms

/src/freetype/src/base/ftmac.c

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