~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/freetype/src/base/ftmac.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

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