source: trunk/poppler/freetype-2.1.10/src/base/ftmac.c @ 2

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

First import

File size: 30.4 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  ftmac.c                                                                */
4/*                                                                         */
5/*    Mac FOND support.  Written by just@letterror.com.                    */
6/*                                                                         */
7/*  Copyright 1996-2001, 2002, 2003, 2004 by                               */
8/*  Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.     */
9/*                                                                         */
10/*  This file is part of the FreeType project, and may only be used,       */
11/*  modified, and distributed under the terms of the FreeType project      */
12/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13/*  this file you indicate that you have read the license and              */
14/*  understand and accept it fully.                                        */
15/*                                                                         */
16/***************************************************************************/
17
18
19  /*
20    Notes
21
22    Mac suitcase files can (and often do!) contain multiple fonts.  To
23    support this I use the face_index argument of FT_(Open|New)_Face()
24    functions, and pretend the suitcase file is a collection.
25
26    Warning: Although the FOND driver sets face->num_faces field to the
27    number of available fonts, but the Type 1 driver sets it to 1 anyway.
28    So this field is currently not reliable, and I don't see a clean way
29    to  resolve that.  The face_index argument translates to
30
31      Get1IndResource( 'FOND', face_index + 1 );
32
33    so clients should figure out the resource index of the FOND.
34    (I'll try to provide some example code for this at some point.)
35
36    The Mac FOND support works roughly like this:
37
38    - Check whether the offered stream points to a Mac suitcase file.
39      This is done by checking the file type: it has to be 'FFIL' or 'tfil'.
40      The stream that gets passed to our init_face() routine is a stdio
41      stream, which isn't usable for us, since the FOND resources live
42      in the resource fork.  So we just grab the stream->pathname field.
43
44    - Read the FOND resource into memory, then check whether there is
45      a TrueType font and/or(!) a Type 1 font available.
46
47    - If there is a Type 1 font available (as a separate 'LWFN' file),
48      read its data into memory, massage it slightly so it becomes
49      PFB data, wrap it into a memory stream, load the Type 1 driver
50      and delegate the rest of the work to it by calling FT_Open_Face().
51      (XXX TODO: after this has been done, the kerning data from the FOND
52      resource should be appended to the face: On the Mac there are usually
53      no AFM files available.  However, this is tricky since we need to map
54      Mac char codes to ps glyph names to glyph ID's...)
55
56    - If there is a TrueType font (an 'sfnt' resource), read it into
57      memory, wrap it into a memory stream, load the TrueType driver
58      and delegate the rest of the work to it, by calling FT_Open_Face().
59  */
60
61
62#include <ft2build.h>
63#include FT_FREETYPE_H
64#include FT_INTERNAL_STREAM_H
65
66#if defined( __GNUC__ ) || defined( __IBMC__ )
67  /* This is for Mac OS X.  Without redefinition, OS_INLINE */
68  /* expands to `static inline' which doesn't survive the   */
69  /* -ansi compilation flag of GCC.                         */
70#define OS_INLINE  static __inline__
71#include <Carbon/Carbon.h>
72#else
73#include <Resources.h>
74#include <Fonts.h>
75#include <Errors.h>
76#include <Files.h>
77#include <TextUtils.h>
78#endif
79
80#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
81#include <FSp_fopen.h>
82#endif
83
84#include FT_MAC_H
85
86
87  /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
88     TrueType in case *both* are available (this is not common,
89     but it *is* possible). */
90#ifndef PREFER_LWFN
91#define PREFER_LWFN 1
92#endif
93
94
95#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
96
97#define STREAM_FILE( stream )  ( (FILE*)stream->descriptor.pointer )
98
99
100  FT_CALLBACK_DEF( void )
101  ft_FSp_stream_close( FT_Stream  stream )
102  {
103    fclose( STREAM_FILE( stream ) );
104
105    stream->descriptor.pointer = NULL;
106    stream->size               = 0;
107    stream->base               = 0;
108  }
109
110
111  FT_CALLBACK_DEF( unsigned long )
112  ft_FSp_stream_io( FT_Stream       stream,
113                    unsigned long   offset,
114                    unsigned char*  buffer,
115                    unsigned long   count )
116  {
117    FILE*  file;
118
119
120    file = STREAM_FILE( stream );
121
122    fseek( file, offset, SEEK_SET );
123
124    return (unsigned long)fread( buffer, 1, count, file );
125  }
126
127#endif  /* __MWERKS__ && !TARGET_RT_MAC_MACHO */
128
129
130  /* Given a pathname, fill in a file spec. */
131  static int
132  file_spec_from_path( const char*  pathname,
133                       FSSpec*      spec )
134  {
135
136#if !TARGET_API_MAC_OS8 && \
137    !( defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO )
138
139    OSErr  e;
140    FSRef  ref;
141
142
143    e = FSPathMakeRef( (UInt8 *)pathname, &ref, false /* not a directory */ );
144    if ( e == noErr )
145      e = FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, spec, NULL );
146
147    return ( e == noErr ) ? 0 : (-1);
148
149#else
150
151    Str255    p_path;
152    FT_ULong  path_len;
153
154
155    /* convert path to a pascal string */
156    path_len = ft_strlen( pathname );
157    if ( path_len > 255 )
158      return -1;
159    p_path[0] = (unsigned char)path_len;
160    ft_strncpy( (char*)p_path + 1, pathname, path_len );
161
162    if ( FSMakeFSSpec( 0, 0, p_path, spec ) != noErr )
163      return -1;
164    else
165      return 0;
166
167#endif
168
169  }
170
171
172  /* Return the file type of the file specified by spec. */
173  static OSType
174  get_file_type( const FSSpec*  spec )
175  {
176    FInfo  finfo;
177
178
179    if ( FSpGetFInfo( spec, &finfo ) != noErr )
180      return 0;  /* file might not exist */
181
182    return finfo.fdType;
183  }
184
185
186  /* Given a PostScript font name, create the Macintosh LWFN file name. */
187  static void
188  create_lwfn_name( char*   ps_name,
189                    Str255  lwfn_file_name )
190  {
191    int       max = 5, count = 0;
192    FT_Byte*  p = lwfn_file_name;
193    FT_Byte*  q = (FT_Byte*)ps_name;
194
195
196    lwfn_file_name[0] = 0;
197
198    while ( *q )
199    {
200      if ( ft_isupper( *q ) )
201      {
202        if ( count )
203          max = 3;
204        count = 0;
205      }
206      if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
207      {
208        *++p = *q;
209        lwfn_file_name[0]++;
210        count++;
211      }
212      q++;
213    }
214  }
215
216
217  /* Given a file reference, answer its location as a vRefNum
218     and a dirID. */
219  static FT_Error
220  get_file_location( short           ref_num,
221                     short*          v_ref_num,
222                     long*           dir_id,
223                     unsigned char*  file_name )
224  {
225    FCBPBRec  pb;
226    OSErr     error;
227
228
229    pb.ioNamePtr = file_name;
230    pb.ioVRefNum = 0;
231    pb.ioRefNum  = ref_num;
232    pb.ioFCBIndx = 0;
233
234    error = PBGetFCBInfoSync( &pb );
235    if ( error == noErr )
236    {
237      *v_ref_num = pb.ioFCBVRefNum;
238      *dir_id    = pb.ioFCBParID;
239    }
240    return error;
241  }
242
243
244  /* Make a file spec for an LWFN file from a FOND resource and
245     a file name. */
246  static FT_Error
247  make_lwfn_spec( Handle               fond,
248                  const unsigned char* file_name,
249                  FSSpec*              spec )
250  {
251    FT_Error  error;
252    short     ref_num, v_ref_num;
253    long      dir_id;
254    Str255    fond_file_name;
255
256
257    ref_num = HomeResFile( fond );
258
259    error = ResError();
260    if ( !error )
261      error = get_file_location( ref_num, &v_ref_num,
262                                 &dir_id, fond_file_name );
263    if ( !error )
264      error = FSMakeFSSpec( v_ref_num, dir_id, file_name, spec );
265
266    return error;
267  }
268
269
270  static short
271  count_faces_sfnt( char *fond_data )
272  {
273    /* The count is 1 greater than the value in the FOND.  */
274    /* Isn't that cute? :-)                                */
275
276    return 1 + *( (short *)( fond_data + sizeof ( FamRec ) ) );
277  }
278
279
280  /* Look inside the FOND data, answer whether there should be an SFNT
281     resource, and answer the name of a possible LWFN Type 1 file.
282
283     Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
284     to load a face OTHER than the first one in the FOND!
285  */
286
287
288  static void
289  parse_fond( char*   fond_data,
290              short*  have_sfnt,
291              short*  sfnt_id,
292              Str255  lwfn_file_name,
293              short   face_index )
294  {
295    AsscEntry*  assoc;
296    AsscEntry*  base_assoc;
297    FamRec*     fond;
298
299
300    *sfnt_id          = 0;
301    *have_sfnt        = 0;
302    lwfn_file_name[0] = 0;
303
304    fond       = (FamRec*)fond_data;
305    assoc      = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
306    base_assoc = assoc;
307
308    /* Let's do a little range checking before we get too excited here */
309    if ( face_index < count_faces_sfnt( fond_data ) )
310    {
311      assoc += face_index;        /* add on the face_index! */
312
313      /* if the face at this index is not scalable,
314         fall back to the first one (old behavior) */
315      if ( assoc->fontSize == 0 )
316      {
317        *have_sfnt = 1;
318        *sfnt_id   = assoc->fontID;
319      }
320      else if ( base_assoc->fontSize == 0 )
321      {
322        *have_sfnt = 1;
323        *sfnt_id   = base_assoc->fontID;
324      }
325    }
326
327    if ( fond->ffStylOff )
328    {
329      unsigned char*  p = (unsigned char*)fond_data;
330      StyleTable*     style;
331      unsigned short  string_count;
332      char            ps_name[256];
333      unsigned char*  names[64];
334      int             i;
335
336
337      p += fond->ffStylOff;
338      style = (StyleTable*)p;
339      p += sizeof ( StyleTable );
340      string_count = *(unsigned short*)(p);
341      p += sizeof ( short );
342
343      for ( i = 0 ; i < string_count && i < 64; i++ )
344      {
345        names[i] = p;
346        p += names[i][0];
347        p++;
348      }
349
350      {
351        size_t  ps_name_len = (size_t)names[0][0];
352
353
354        if ( ps_name_len != 0 )
355        {
356          ft_memcpy(ps_name, names[0] + 1, ps_name_len);
357          ps_name[ps_name_len] = 0;
358        }
359        if ( style->indexes[0] > 1 )
360        {
361          unsigned char*  suffixes = names[style->indexes[0] - 1];
362
363
364          for ( i = 1; i <= suffixes[0]; i++ )
365          {
366            unsigned char*  s;
367            size_t          j = suffixes[i] - 1;
368
369
370            if ( j < string_count && ( s = names[j] ) != NULL )
371            {
372              size_t  s_len = (size_t)s[0];
373
374
375              if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
376              {
377                ft_memcpy( ps_name + ps_name_len, s + 1, s_len );
378                ps_name_len += s_len;
379                ps_name[ps_name_len] = 0;
380              }
381            }
382          }
383        }
384      }
385
386      create_lwfn_name( ps_name, lwfn_file_name );
387    }
388  }
389
390
391  static short
392  count_faces( Handle  fond )
393  {
394    short   sfnt_id, have_sfnt, have_lwfn = 0;
395    Str255  lwfn_file_name;
396    FSSpec  lwfn_spec;
397
398
399    HLock( fond );
400    parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 );
401    HUnlock( fond );
402
403    if ( lwfn_file_name[0] )
404    {
405      if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok )
406        have_lwfn = 1;  /* yeah, we got one! */
407      else
408        have_lwfn = 0;  /* no LWFN file found */
409    }
410
411    if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
412      return 1;
413    else
414      return count_faces_sfnt( *fond );
415  }
416
417
418  /* Read Type 1 data from the POST resources inside the LWFN file,
419     return a PFB buffer. This is somewhat convoluted because the FT2
420     PFB parser wants the ASCII header as one chunk, and the LWFN
421     chunks are often not organized that way, so we'll glue chunks
422     of the same type together. */
423  static FT_Error
424  read_lwfn( FT_Memory  memory,
425             short      res_ref,
426             FT_Byte**  pfb_data,
427             FT_ULong*  size )
428  {
429    FT_Error       error = FT_Err_Ok;
430    short          res_id;
431    unsigned char  *buffer, *p, *size_p = NULL;
432    FT_ULong       total_size = 0;
433    FT_ULong       post_size, pfb_chunk_size;
434    Handle         post_data;
435    char           code, last_code;
436
437
438    UseResFile( res_ref );
439
440    /* First pass: load all POST resources, and determine the size of */
441    /* the output buffer.                                             */
442    res_id    = 501;
443    last_code = -1;
444
445    for (;;)
446    {
447      post_data = Get1Resource( 'POST', res_id++ );
448      if ( post_data == NULL )
449        break;  /* we're done */
450
451      code = (*post_data)[0];
452
453      if ( code != last_code )
454      {
455        if ( code == 5 )
456          total_size += 2; /* just the end code */
457        else
458          total_size += 6; /* code + 4 bytes chunk length */
459      }
460
461      total_size += GetHandleSize( post_data ) - 2;
462      last_code = code;
463    }
464
465    if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
466      goto Error;
467
468    /* Second pass: append all POST data to the buffer, add PFB fields. */
469    /* Glue all consecutive chunks of the same type together.           */
470    p              = buffer;
471    res_id         = 501;
472    last_code      = -1;
473    pfb_chunk_size = 0;
474
475    for (;;)
476    {
477      post_data = Get1Resource( 'POST', res_id++ );
478      if ( post_data == NULL )
479        break;  /* we're done */
480
481      post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
482      code = (*post_data)[0];
483
484      if ( code != last_code )
485      {
486        if ( last_code != -1 )
487        {
488          /* we're done adding a chunk, fill in the size field */
489          if ( size_p != NULL )
490          {
491            *size_p++ = (FT_Byte)(   pfb_chunk_size         & 0xFF );
492            *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8  ) & 0xFF );
493            *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
494            *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
495          }
496          pfb_chunk_size = 0;
497        }
498
499        *p++ = 0x80;
500        if ( code == 5 )
501          *p++ = 0x03;  /* the end */
502        else if ( code == 2 )
503          *p++ = 0x02;  /* binary segment */
504        else
505          *p++ = 0x01;  /* ASCII segment */
506
507        if ( code != 5 )
508        {
509          size_p = p;   /* save for later */
510          p += 4;       /* make space for size field */
511        }
512      }
513
514      ft_memcpy( p, *post_data + 2, post_size );
515      pfb_chunk_size += post_size;
516      p += post_size;
517      last_code = code;
518    }
519
520    *pfb_data = buffer;
521    *size = total_size;
522
523  Error:
524    CloseResFile( res_ref );
525    return error;
526  }
527
528
529  /* Finalizer for a memory stream; gets called by FT_Done_Face().
530     It frees the memory it uses. */
531  static void
532  memory_stream_close( FT_Stream  stream )
533  {
534    FT_Memory  memory = stream->memory;
535
536
537    FT_FREE( stream->base );
538
539    stream->size  = 0;
540    stream->base  = 0;
541    stream->close = 0;
542  }
543
544
545  /* Create a new memory stream from a buffer and a size. */
546  static FT_Error
547  new_memory_stream( FT_Library           library,
548                     FT_Byte*             base,
549                     FT_ULong             size,
550                     FT_Stream_CloseFunc  close,
551                     FT_Stream           *astream )
552  {
553    FT_Error   error;
554    FT_Memory  memory;
555    FT_Stream  stream;
556
557
558    if ( !library )
559      return FT_Err_Invalid_Library_Handle;
560
561    if ( !base )
562      return FT_Err_Invalid_Argument;
563
564    *astream = 0;
565    memory = library->memory;
566    if ( FT_NEW( stream ) )
567      goto Exit;
568
569    FT_Stream_OpenMemory( stream, base, size );
570
571    stream->close = close;
572
573    *astream = stream;
574
575  Exit:
576    return error;
577  }
578
579
580  /* Create a new FT_Face given a buffer and a driver name. */
581  static FT_Error
582  open_face_from_buffer( FT_Library  library,
583                         FT_Byte*    base,
584                         FT_ULong    size,
585                         FT_Long     face_index,
586                         char*       driver_name,
587                         FT_Face    *aface )
588  {
589    FT_Open_Args  args;
590    FT_Error      error;
591    FT_Stream     stream;
592    FT_Memory     memory = library->memory;
593
594
595    error = new_memory_stream( library,
596                               base,
597                               size,
598                               memory_stream_close,
599                               &stream );
600    if ( error )
601    {
602      FT_FREE( base );
603      return error;
604    }
605
606    args.flags = FT_OPEN_STREAM;
607    args.stream = stream;
608    if ( driver_name )
609    {
610      args.flags = args.flags | FT_OPEN_DRIVER;
611      args.driver = FT_Get_Module( library, driver_name );
612    }
613
614    /* At this point, face_index has served its purpose;      */
615    /* whoever calls this function has already used it to     */
616    /* locate the correct font data.  We should not propagate */
617    /* this index to FT_Open_Face() (unless it is negative).  */
618
619    if ( face_index > 0 )
620      face_index = 0;
621
622    error = FT_Open_Face( library, &args, face_index, aface );
623    if ( error == FT_Err_Ok )
624      (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
625
626    return error;
627  }
628
629
630  static FT_Error
631  OpenFileAsResource( const FSSpec*  spec,
632                      short         *p_res_ref )
633  {
634    FT_Error  error;
635
636#if !TARGET_API_MAC_OS8
637
638    FSRef     hostContainerRef;
639
640
641    error = FSpMakeFSRef( spec, &hostContainerRef );
642    if ( error == noErr )
643      error = FSOpenResourceFile( &hostContainerRef,
644                                  0, NULL, fsRdPerm, p_res_ref );
645
646    /* If the above fails, then it is probably not a resource file       */
647    /* However, it has been reported that FSOpenResourceFile() sometimes */
648    /* fails on some old resource-fork files, which FSpOpenResFile() can */
649    /* open.  So, just try again with FSpOpenResFile() and see what      */
650    /* happens :-)                                                       */
651
652    if ( error != noErr )
653
654#endif  /* !TARGET_API_MAC_OS8 */
655
656    {
657      *p_res_ref = FSpOpenResFile( spec, fsRdPerm );
658      error = ResError();
659    }
660
661    return error ? FT_Err_Cannot_Open_Resource : FT_Err_Ok;
662  }
663
664
665  /* Create a new FT_Face from a file spec to an LWFN file. */
666  static FT_Error
667  FT_New_Face_From_LWFN( FT_Library     library,
668                         const FSSpec*  lwfn_spec,
669                         FT_Long        face_index,
670                         FT_Face       *aface )
671  {
672    FT_Byte*  pfb_data;
673    FT_ULong  pfb_size;
674    FT_Error  error;
675    short     res_ref;
676
677
678    error = OpenFileAsResource( lwfn_spec, &res_ref );
679    if ( error )
680      return error;
681
682    error = read_lwfn( library->memory, res_ref, &pfb_data, &pfb_size );
683    if ( error )
684      return error;
685
686    return open_face_from_buffer( library,
687                                  pfb_data,
688                                  pfb_size,
689                                  face_index,
690                                  "type1",
691                                  aface );
692  }
693
694
695  /* Create a new FT_Face from an SFNT resource, specified by res ID. */
696  static FT_Error
697  FT_New_Face_From_SFNT( FT_Library  library,
698                         short       sfnt_id,
699                         FT_Long     face_index,
700                         FT_Face    *aface )
701  {
702    Handle     sfnt = NULL;
703    FT_Byte*   sfnt_data;
704    size_t     sfnt_size;
705    FT_Error   error = 0;
706    FT_Memory  memory = library->memory;
707    int        is_cff;
708
709
710    sfnt = GetResource( 'sfnt', sfnt_id );
711    if ( ResError() )
712      return FT_Err_Invalid_Handle;
713
714    sfnt_size = (FT_ULong)GetHandleSize( sfnt );
715    if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
716    {
717      ReleaseResource( sfnt );
718      return error;
719    }
720
721    HLock( sfnt );
722    ft_memcpy( sfnt_data, *sfnt, sfnt_size );
723    HUnlock( sfnt );
724    ReleaseResource( sfnt );
725
726    is_cff = sfnt_size > 4 && sfnt_data[0] == 'O' &&
727                              sfnt_data[1] == 'T' &&
728                              sfnt_data[2] == 'T' &&
729                              sfnt_data[3] == 'O';
730
731    return open_face_from_buffer( library,
732                                  sfnt_data,
733                                  sfnt_size,
734                                  face_index,
735                                  is_cff ? "cff" : "truetype",
736                                  aface );
737  }
738
739
740  /* Create a new FT_Face from a file spec to a suitcase file. */
741  static FT_Error
742  FT_New_Face_From_Suitcase( FT_Library  library,
743                             short       res_ref,
744                             FT_Long     face_index,
745                             FT_Face    *aface )
746  {
747    FT_Error  error = FT_Err_Ok;
748    short     res_index;
749    Handle    fond;
750    short     num_faces;
751
752
753    UseResFile( res_ref );
754
755    for ( res_index = 1; ; ++res_index )
756    {
757      fond = Get1IndResource( 'FOND', res_index );
758      if ( ResError() )
759      {
760        error = FT_Err_Cannot_Open_Resource;
761        goto Error;
762      }
763      if ( face_index < 0 )
764        break;
765
766      num_faces = count_faces( fond );
767      if ( face_index < num_faces )
768        break;
769
770      face_index -= num_faces;
771    }
772
773    error = FT_New_Face_From_FOND( library, fond, face_index, aface );
774
775  Error:
776    CloseResFile( res_ref );
777    return error;
778  }
779
780
781  /* documentation is in ftmac.h */
782
783  FT_EXPORT_DEF( FT_Error )
784  FT_New_Face_From_FOND( FT_Library  library,
785                         Handle      fond,
786                         FT_Long     face_index,
787                         FT_Face    *aface )
788  {
789    short   sfnt_id, have_sfnt, have_lwfn = 0;
790    Str255  lwfn_file_name;
791    short   fond_id;
792    OSType  fond_type;
793    Str255  fond_name;
794    FSSpec  lwfn_spec;
795
796
797    GetResInfo( fond, &fond_id, &fond_type, fond_name );
798    if ( ResError() != noErr || fond_type != 'FOND' )
799      return FT_Err_Invalid_File_Format;
800
801    HLock( fond );
802    parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
803    HUnlock( fond );
804
805    if ( lwfn_file_name[0] )
806    {
807      if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok )
808        have_lwfn = 1;  /* yeah, we got one! */
809      else
810        have_lwfn = 0;  /* no LWFN file found */
811    }
812
813    if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
814      return FT_New_Face_From_LWFN( library,
815                                    &lwfn_spec,
816                                    face_index,
817                                    aface );
818    else if ( have_sfnt )
819      return FT_New_Face_From_SFNT( library,
820                                    sfnt_id,
821                                    face_index,
822                                    aface );
823
824    return FT_Err_Unknown_File_Format;
825  }
826
827
828  /* documentation is in ftmac.h */
829
830  FT_EXPORT_DEF( FT_Error )
831  FT_GetFile_From_Mac_Name( const char* fontName,
832                            FSSpec*     pathSpec,
833                            FT_Long*    face_index )
834  {
835    OptionBits            options = kFMUseGlobalScopeOption;
836
837    FMFontFamilyIterator  famIter;
838    OSStatus              status = FMCreateFontFamilyIterator( NULL, NULL,
839                                                               options,
840                                                               &famIter );
841    FMFont                the_font = NULL;
842    FMFontFamily          family   = NULL;
843
844
845    *face_index = 0;
846    while ( status == 0 && !the_font )
847    {
848      status = FMGetNextFontFamily( &famIter, &family );
849      if ( status == 0 )
850      {
851        int                           stat2;
852        FMFontFamilyInstanceIterator  instIter;
853        Str255                        famNameStr;
854        char                          famName[256];
855
856
857        /* get the family name */
858        FMGetFontFamilyName( family, famNameStr );
859        CopyPascalStringToC( famNameStr, famName );
860
861        /* iterate through the styles */
862        FMCreateFontFamilyInstanceIterator( family, &instIter );
863
864        *face_index = 0;
865        stat2 = 0;
866        while ( stat2 == 0 && !the_font )
867        {
868          FMFontStyle  style;
869          FMFontSize   size;
870          FMFont       font;
871
872
873          stat2 = FMGetNextFontFamilyInstance( &instIter, &font,
874                                               &style, &size );
875          if ( stat2 == 0 && size == 0 )
876          {
877            char  fullName[256];
878
879
880            /* build up a complete face name */
881            ft_strcpy( fullName, famName );
882            if ( style & bold )
883              strcat( fullName, " Bold" );
884            if ( style & italic )
885              strcat( fullName, " Italic" );
886
887            /* compare with the name we are looking for */
888            if ( ft_strcmp( fullName, fontName ) == 0 )
889            {
890              /* found it! */
891              the_font = font;
892            }
893            else
894              ++(*face_index);
895          }
896        }
897
898        FMDisposeFontFamilyInstanceIterator( &instIter );
899      }
900    }
901
902    FMDisposeFontFamilyIterator( &famIter );
903
904    if ( the_font )
905    {
906      FMGetFontContainer( the_font, pathSpec );
907      return FT_Err_Ok;
908    }
909    else
910      return FT_Err_Unknown_File_Format;
911  }
912
913  /* Common function to load a new FT_Face from a resource file. */
914
915  static FT_Error
916  FT_New_Face_From_Resource( FT_Library     library,
917                             const FSSpec  *spec,
918                             FT_Long        face_index,
919                             FT_Face       *aface )
920  {
921    OSType    file_type;
922    short     res_ref;
923    FT_Error  error;
924
925
926    if ( OpenFileAsResource( spec, &res_ref ) == FT_Err_Ok )
927    {
928      /* LWFN is a (very) specific file format, check for it explicitly */
929
930      file_type = get_file_type( spec );
931      if ( file_type == 'LWFN' )
932        return FT_New_Face_From_LWFN( library, spec, face_index, aface );
933   
934      /* Otherwise the file type doesn't matter (there are more than  */
935      /* `FFIL' and `tfil').  Just try opening it as a font suitcase; */
936      /* if it works, fine.                                           */
937
938      error = FT_New_Face_From_Suitcase( library, res_ref,
939                                         face_index, aface );
940      if ( error == 0 )
941        return error;
942
943      /* else forget about the resource fork and fall through to */
944      /* data fork formats                                       */
945
946      CloseResFile( res_ref );
947    }
948
949    /* let it fall through to normal loader (.ttf, .otf, etc.); */
950    /* we signal this by returning no error and no FT_Face      */
951    *aface = NULL;
952    return 0;
953  }
954
955
956  /*************************************************************************/
957  /*                                                                       */
958  /* <Function>                                                            */
959  /*    FT_New_Face                                                        */
960  /*                                                                       */
961  /* <Description>                                                         */
962  /*    This is the Mac-specific implementation of FT_New_Face.  In        */
963  /*    addition to the standard FT_New_Face() functionality, it also      */
964  /*    accepts pathnames to Mac suitcase files.  For further              */
965  /*    documentation see the original FT_New_Face() in freetype.h.        */
966  /*                                                                       */
967  FT_EXPORT_DEF( FT_Error )
968  FT_New_Face( FT_Library   library,
969               const char*  pathname,
970               FT_Long      face_index,
971               FT_Face     *aface )
972  {
973    FT_Open_Args  args;
974    FSSpec        spec;
975    FT_Error      error;
976
977
978    /* test for valid `library' and `aface' delayed to FT_Open_Face() */
979    if ( !pathname )
980      return FT_Err_Invalid_Argument;
981
982    if ( file_spec_from_path( pathname, &spec ) )
983      return FT_Err_Invalid_Argument;
984
985    error = FT_New_Face_From_Resource( library, &spec, face_index, aface );
986    if ( error != 0 || *aface != NULL )
987      return error;
988
989    /* let it fall through to normal loader (.ttf, .otf, etc.) */
990    args.flags    = FT_OPEN_PATHNAME;
991    args.pathname = (char*)pathname;
992    return FT_Open_Face( library, &args, face_index, aface );
993  }
994
995
996  /*************************************************************************/
997  /*                                                                       */
998  /* <Function>                                                            */
999  /*    FT_New_Face_From_FSSpec                                            */
1000  /*                                                                       */
1001  /* <Description>                                                         */
1002  /*    FT_New_Face_From_FSSpec is identical to FT_New_Face except it      */
1003  /*    accepts an FSSpec instead of a path.                               */
1004  /*                                                                       */
1005  FT_EXPORT_DEF( FT_Error )
1006  FT_New_Face_From_FSSpec( FT_Library    library,
1007                           const FSSpec *spec,
1008                           FT_Long       face_index,
1009                           FT_Face      *aface )
1010  {
1011#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
1012    FT_Open_Args  args;
1013    FT_Stream     stream;
1014    FILE*         file;
1015    FT_Memory     memory;
1016#endif
1017    FT_Error      error;
1018
1019
1020    /* test for valid `library' and `aface' delayed to FT_Open_Face() */
1021    if ( !spec )
1022      return FT_Err_Invalid_Argument;
1023
1024    error = FT_New_Face_From_Resource( library, spec, face_index, aface );
1025    if ( error != 0 || *aface != NULL )
1026      return error;
1027
1028    /* let it fall through to normal loader (.ttf, .otf, etc.) */
1029
1030#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
1031
1032    /* Codewarrior's C library can open a FILE from a FSSpec */
1033    /* but we must compile with FSp_fopen.c in addition to   */
1034    /* runtime libraries.                                    */
1035
1036    memory = library->memory;
1037
1038    if ( FT_NEW( stream ) )
1039      return error;
1040    stream->memory = memory;
1041
1042    file = FSp_fopen( spec, "rb" );
1043    if ( !file )
1044      return FT_Err_Cannot_Open_Resource;
1045
1046    fseek( file, 0, SEEK_END );
1047    stream->size = ftell( file );
1048    fseek( file, 0, SEEK_SET );
1049
1050    stream->descriptor.pointer = file;
1051    stream->pathname.pointer   = NULL;
1052    stream->pos                = 0;
1053
1054    stream->read  = ft_FSp_stream_io;
1055    stream->close = ft_FSp_stream_close;
1056
1057    args.flags    = FT_OPEN_STREAM;
1058    args.stream   = stream;
1059
1060    error = FT_Open_Face( library, &args, face_index, aface );
1061    if ( error == FT_Err_Ok )
1062      (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
1063
1064#else  /* !(__MWERKS__ && !TARGET_RT_MAC_MACHO) */
1065
1066    {
1067      FSRef  ref;
1068      UInt8  path[256];
1069      OSErr  err;
1070
1071
1072      err = FSpMakeFSRef(spec, &ref);
1073      if ( !err )
1074      {
1075        err = FSRefMakePath( &ref, path, sizeof ( path ) );
1076        if ( !err )
1077          error = FT_New_Face( library, (const char*)path,
1078                               face_index, aface );
1079      }
1080      if ( err )
1081        error = FT_Err_Cannot_Open_Resource;
1082    }
1083
1084#endif  /* !(__MWERKS__ && !TARGET_RT_MAC_MACHO) */
1085
1086    return error;
1087  }
1088
1089
1090/* END */
Note: See TracBrowser for help on using the repository browser.