blob: a2395fe109ed12c193064306c4f852b30ff6ab9c [file] [log] [blame]
Just van Rossumae4bcee2000-07-28 01:10:35 +00001/***************************************************************************/
2/* */
3/* ftmac.c */
4/* */
Werner Lemberg05c21b82000-07-29 20:38:19 +00005/* Mac FOND support. Written by just@letterror.com. */
Just van Rossumae4bcee2000-07-28 01:10:35 +00006/* */
Werner Lemberg415235d2001-06-28 17:49:10 +00007/* Copyright 1996-2001 by */
Just van Rossumae4bcee2000-07-28 01:10:35 +00008/* 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 Warning: although the FOND driver sets face->num_faces field to the
26 number of available fonts, but the Type 1 driver sets it to 1 anyway.
27 So this field is currently not reliable, and I don't see a clean way
28 to resolve that. The face_index argument translates to
29 Get1IndResource( 'FOND', face_index + 1 );
30 so clients should figure out the resource index of the FOND.
31 (I'll try to provide some example code for this at some point.)
32
33
34 The Mac FOND support works roughly like this:
35
36 - Check whether the offered stream points to a Mac suitcase file.
37 This is done by checking the file type: it has to be 'FFIL' or 'tfil'.
38 The stream that gets passed to our init_face() routine is a stdio
39 stream, which isn't usable for us, since the FOND resources live
40 in the resource fork. So we just grab the stream->pathname field.
41
42 - Read the FOND resource into memory, then check whether there is
43 a TrueType font and/or (!) a Type 1 font available.
44
45 - If there is a Type 1 font available (as a separate 'LWFN' file),
46 read its data into memory, massage it slightly so it becomes
47 PFB data, wrap it into a memory stream, load the Type 1 driver
48 and delegate the rest of the work to it by calling FT_Open_Face().
49 (XXX TODO: after this has been done, the kerning data from the FOND
50 resource should be appended to the face: on the Mac there are usually
51 no AFM files available. However, this is tricky since we need to map
52 Mac char codes to ps glyph names to glyph ID's...)
53
54 - If there is a TrueType font (an 'sfnt' resource), read it into
55 memory, wrap it into a memory stream, load the TrueType driver
56 and delegate the rest of the work to it, by calling FT_Open_Face().
57 */
58
Werner Lembergcc069be2000-12-08 16:17:16 +000059
60#include <ft2build.h>
61#include FT_FREETYPE_H
62#include FT_INTERNAL_STREAM_H
David Turner8d3a4012001-03-20 11:14:24 +000063#include "truetype/ttobjs.h"
64#include "type1/t1objs.h"
Just van Rossumae4bcee2000-07-28 01:10:35 +000065
66#include <Resources.h>
67#include <Fonts.h>
68#include <Errors.h>
69
70#include <ctype.h> /* for isupper() and isalnum() */
71
David Turner19ed8af2000-12-08 02:42:29 +000072#include FT_MAC_H
Just van Rossumae4bcee2000-07-28 01:10:35 +000073
74
75
76 /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
77 TrueType in case *both* are available (this is not common,
78 but it *is* possible). */
79#ifndef PREFER_LWFN
80#define PREFER_LWFN 1
81#endif
82
83
84
Werner Lemberg05c21b82000-07-29 20:38:19 +000085 /* Quick'n'dirty Pascal string to C string converter.
Just van Rossumae4bcee2000-07-28 01:10:35 +000086 Warning: this call is not thread safe! Use with caution. */
Werner Lembergf814d0f2001-06-27 16:18:10 +000087 static char*
88 p2c_str( unsigned char* pstr )
Just van Rossumae4bcee2000-07-28 01:10:35 +000089 {
Werner Lemberg05c21b82000-07-29 20:38:19 +000090 static char cstr[256];
Just van Rossumae4bcee2000-07-28 01:10:35 +000091
92
Werner Lemberg05c21b82000-07-29 20:38:19 +000093 strncpy( cstr, (char*)pstr + 1, pstr[0] );
Just van Rossumae4bcee2000-07-28 01:10:35 +000094 cstr[pstr[0]] = '\0';
95 return cstr;
96 }
97
98
99 /* Given a pathname, fill in a file spec. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000100 static int
101 file_spec_from_path( const char* pathname,
102 FSSpec* spec )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000103 {
104 Str255 p_path;
105 FT_ULong path_len;
106
107
108 /* convert path to a pascal string */
109 path_len = strlen( pathname );
110 if ( path_len > 255 )
111 return -1;
112 p_path[0] = (unsigned char)path_len;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000113 strncpy( (char*)p_path + 1, pathname, path_len );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000114
115 if ( FSMakeFSSpec( 0, 0, p_path, spec ) != noErr )
116 return -1;
117 else
118 return 0;
119 }
120
121
122 /* Return the file type of the file specified by spec. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000123 static OSType
124 get_file_type( FSSpec* spec )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000125 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000126 FInfo finfo;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000127
128
129 if ( FSpGetFInfo( spec, &finfo ) != noErr )
130 return 0; /* file might not exist */
Werner Lemberg05c21b82000-07-29 20:38:19 +0000131
Just van Rossumae4bcee2000-07-28 01:10:35 +0000132 return finfo.fdType;
133 }
134
135
136 /* Given a PostScript font name, create the Macintosh LWFN file name. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000137 static void
138 create_lwfn_name( char* ps_name,
139 Str255 lwfn_file_name )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000140 {
141 int max = 5, count = 0;
142 FT_Byte* p = lwfn_file_name;
143 FT_Byte* q = (FT_Byte*)ps_name;
144
145
146 lwfn_file_name[0] = 0;
147
148 while ( *q )
149 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000150 if ( isupper( *q ) )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000151 {
152 if ( count )
153 max = 3;
154 count = 0;
155 }
Werner Lemberg05c21b82000-07-29 20:38:19 +0000156 if ( count < max && ( isalnum( *q ) || *q == '_' ) )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000157 {
158 *++p = *q;
159 lwfn_file_name[0]++;
160 count++;
161 }
162 q++;
163 }
164 }
165
166
167 /* Given a file reference, answer its location as a vRefNum
168 and a dirID. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000169 static FT_Error
170 get_file_location( short ref_num,
171 short* v_ref_num,
172 long* dir_id,
173 unsigned char* file_name )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000174 {
175 FCBPBRec pb;
176 OSErr error;
177
Just van Rossumae4bcee2000-07-28 01:10:35 +0000178 pb.ioNamePtr = file_name;
179 pb.ioVRefNum = 0;
180 pb.ioRefNum = ref_num;
181 pb.ioFCBIndx = 0;
182
Werner Lemberg05c21b82000-07-29 20:38:19 +0000183
Just van Rossumae4bcee2000-07-28 01:10:35 +0000184 error = PBGetFCBInfoSync( &pb );
185 if ( error == noErr )
186 {
187 *v_ref_num = pb.ioFCBVRefNum;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000188 *dir_id = pb.ioFCBParID;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000189 }
190 return error;
191 }
192
193
194 /* Make a file spec for an LWFN file from a FOND resource and
195 a file name. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000196 static FT_Error
197 make_lwfn_spec( Handle fond,
198 unsigned char* file_name,
199 FSSpec* spec )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000200 {
201 FT_Error error;
202 short ref_num, v_ref_num;
203 long dir_id;
204 Str255 fond_file_name;
205
206
207 ref_num = HomeResFile( fond );
Werner Lemberg05c21b82000-07-29 20:38:19 +0000208
Just van Rossumae4bcee2000-07-28 01:10:35 +0000209 error = ResError();
210 if ( !error )
Werner Lemberg05c21b82000-07-29 20:38:19 +0000211 error = get_file_location( ref_num, &v_ref_num,
212 &dir_id, fond_file_name );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000213 if ( !error )
214 error = FSMakeFSSpec( v_ref_num, dir_id, file_name, spec );
215
216 return error;
217 }
218
219
220 /* Look inside the FOND data, answer whether there should be an SFNT
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000221 resource, and answer the name of a possible LWFN Type 1 file.
222
223 Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
224 to load a face OTHER than the first one in the FOND!
225 */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000226 static void
227 parse_fond( char* fond_data,
228 short* have_sfnt,
229 short* sfnt_id,
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000230 Str255 lwfn_file_name,
231 short face_index )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000232 {
233 AsscEntry* assoc;
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000234 AsscEntry* base_assoc;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000235 FamRec* fond;
236
237
238 *sfnt_id = 0;
239 *have_sfnt = 0;
240 lwfn_file_name[0] = 0;
241
Werner Lembergc3b21602001-12-05 01:22:05 +0000242 fond = (FamRec*)fond_data;
243 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000244 base_assoc = assoc;
Werner Lembergc3b21602001-12-05 01:22:05 +0000245 assoc += face_index; /* add on the face_index! */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000246
Werner Lembergc3b21602001-12-05 01:22:05 +0000247 /* if the face at this index is not scalable,
248 fall back to the first one (old behavior) */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000249 if ( assoc->fontSize == 0 )
250 {
251 *have_sfnt = 1;
Werner Lembergc3b21602001-12-05 01:22:05 +0000252 *sfnt_id = assoc->fontID;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000253 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000254 else if ( base_assoc->fontSize == 0 )
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000255 {
256 *have_sfnt = 1;
Werner Lembergc3b21602001-12-05 01:22:05 +0000257 *sfnt_id = base_assoc->fontID;
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000258 }
Just van Rossumae4bcee2000-07-28 01:10:35 +0000259
260 if ( fond->ffStylOff )
261 {
262 unsigned char* p = (unsigned char*)fond_data;
263 StyleTable* style;
264 unsigned short string_count;
265 unsigned char* name_table = 0;
266 char ps_name[256];
267 unsigned char* names[64];
268 int i;
269
Werner Lemberg05c21b82000-07-29 20:38:19 +0000270
Just van Rossumae4bcee2000-07-28 01:10:35 +0000271 p += fond->ffStylOff;
272 style = (StyleTable*)p;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000273 p += sizeof ( StyleTable );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000274 string_count = *(unsigned short*)(p);
Werner Lemberg05c21b82000-07-29 20:38:19 +0000275 p += sizeof ( short );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000276
277 for ( i = 0 ; i < string_count && i < 64; i++ )
278 {
279 names[i] = p;
280 p += names[i][0];
281 p++;
282 }
Werner Lemberg05c21b82000-07-29 20:38:19 +0000283 strcpy( ps_name, p2c_str( names[0] ) ); /* Family name */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000284
285 if ( style->indexes[0] > 1 )
286 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000287 unsigned char* suffixes = names[style->indexes[0] - 1];
288
289
Just van Rossumae4bcee2000-07-28 01:10:35 +0000290 for ( i=1; i<=suffixes[0]; i++ )
Werner Lemberg05c21b82000-07-29 20:38:19 +0000291 strcat( ps_name, p2c_str( names[suffixes[i] - 1 ] ) );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000292 }
293 create_lwfn_name( ps_name, lwfn_file_name );
294 }
295 }
296
297
298 /* Read Type 1 data from the POST resources inside the LWFN file,
299 return a PFB buffer. This is somewhat convoluted because the FT2
300 PFB parser wants the ASCII header as one chunk, and the LWFN
301 chunks are often not organized that way, so we'll glue chunks
302 of the same type together. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000303 static FT_Error
304 read_lwfn( FT_Memory memory,
305 FSSpec* lwfn_spec,
306 FT_Byte** pfb_data,
307 FT_ULong* size )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000308 {
309 FT_Error error = FT_Err_Ok;
310 short res_ref, res_id;
311 unsigned char *buffer, *p, *size_p;
312 FT_ULong total_size = 0;
313 FT_ULong post_size, pfb_chunk_size;
314 Handle post_data;
315 char code, last_code;
316
317
318 res_ref = FSpOpenResFile( lwfn_spec, fsRdPerm );
319 if ( ResError() )
320 return FT_Err_Out_Of_Memory;
321 UseResFile( res_ref );
322
323 /* First pass: load all POST resources, and determine the size of
324 the output buffer. */
325 res_id = 501;
326 last_code = -1;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000327
Just van Rossumae4bcee2000-07-28 01:10:35 +0000328 for (;;)
329 {
330 post_data = Get1Resource( 'POST', res_id++ );
331 if ( post_data == NULL )
332 break; /* we're done */
333
334 code = (*post_data)[0];
335
336 if ( code != last_code )
337 {
338 if ( code == 5 )
339 total_size += 2; /* just the end code */
340 else
341 total_size += 6; /* code + 4 bytes chunk length */
342 }
343
344 total_size += GetHandleSize( post_data ) - 2;
345 last_code = code;
346 }
347
348 if ( ALLOC( buffer, (FT_Long)total_size ) )
349 goto Error;
350
351 /* Second pass: append all POST data to the buffer, add PFB fields.
Werner Lemberg05c21b82000-07-29 20:38:19 +0000352 Glue all consecutive chunks of the same type together. */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000353 p = buffer;
354 res_id = 501;
355 last_code = -1;
356 pfb_chunk_size = 0;
357
358 for (;;)
359 {
360 post_data = Get1Resource( 'POST', res_id++ );
361 if ( post_data == NULL )
362 break; /* we're done */
363
364 post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
365 code = (*post_data)[0];
366
367 if ( code != last_code )
368 {
369
370 if ( last_code != -1 )
371 {
372 /* we're done adding a chunk, fill in the size field */
Werner Lemberg05c21b82000-07-29 20:38:19 +0000373 *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF );
374 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF );
375 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
376 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000377 pfb_chunk_size = 0;
378 }
379
380 *p++ = 0x80;
381 if ( code == 5 )
382 *p++ = 0x03; /* the end */
383 else if ( code == 2 )
384 *p++ = 0x02; /* binary segment */
385 else
386 *p++ = 0x01; /* ASCII segment */
387
388 if ( code != 5 )
389 {
390 size_p = p; /* save for later */
391 p += 4; /* make space for size field */
392 }
393 }
394
395 memcpy( p, *post_data + 2, post_size );
396 pfb_chunk_size += post_size;
397 p += post_size;
398 last_code = code;
399 }
400
401 *pfb_data = buffer;
402 *size = total_size;
403
Werner Lemberg05c21b82000-07-29 20:38:19 +0000404 Error:
Just van Rossumae4bcee2000-07-28 01:10:35 +0000405 CloseResFile( res_ref );
406 return error;
407 }
408
409
410 /* Finalizer for a memory stream; gets called by FT_Done_Face().
411 It frees the memory it uses. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000412 static void
413 memory_stream_close( FT_Stream stream )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000414 {
415 FT_Memory memory = stream->memory;
416
417
418 FREE( stream->base );
Werner Lemberg05c21b82000-07-29 20:38:19 +0000419
420 stream->size = 0;
421 stream->base = 0;
422 stream->close = 0;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000423 }
424
425
426 /* Create a new memory stream from a buffer and a size. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000427 static FT_Error
428 new_memory_stream( FT_Library library,
429 FT_Byte* base,
430 FT_ULong size,
431 FT_Stream_Close close,
432 FT_Stream* astream )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000433 {
434 FT_Error error;
435 FT_Memory memory;
436 FT_Stream stream;
437
438
439 if ( !library )
440 return FT_Err_Invalid_Library_Handle;
441
442 if ( !base )
443 return FT_Err_Invalid_Argument;
444
445 *astream = 0;
446 memory = library->memory;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000447 if ( ALLOC( stream, sizeof ( *stream ) ) )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000448 goto Exit;
449
450 FT_New_Memory_Stream( library,
451 base,
452 size,
453 stream );
454
455 stream->close = close;
456
457 *astream = stream;
458
459 Exit:
460 return error;
461 }
462
463
464 /* Create a new FT_Face given a buffer and a driver name. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000465 static FT_Error
466 open_face_from_buffer( FT_Library library,
467 FT_Byte* base,
468 FT_ULong size,
469 FT_Long face_index,
470 char* driver_name,
471 FT_Face* aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000472 {
473 FT_Open_Args args;
474 FT_Error error;
475 FT_Stream stream;
476 FT_Memory memory = library->memory;
477
478
479 error = new_memory_stream( library,
480 base,
481 size,
482 memory_stream_close,
483 &stream );
484 if ( error )
485 {
486 FREE( base );
487 return error;
488 }
489
490 args.flags = ft_open_stream;
491 args.stream = stream;
492 if ( driver_name )
493 {
494 args.flags = args.flags | ft_open_driver;
495 args.driver = FT_Get_Module( library, driver_name );
496 }
Werner Lemberg05c21b82000-07-29 20:38:19 +0000497
Just van Rossumae4bcee2000-07-28 01:10:35 +0000498 error = FT_Open_Face( library, &args, face_index, aface );
Just van Rossum5fe94ff2000-07-28 02:25:23 +0000499 if ( error == FT_Err_Ok )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000500 (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
Just van Rossum5fe94ff2000-07-28 02:25:23 +0000501 else
502 {
503 FT_Done_Stream( stream );
504 FREE( stream );
505 }
Just van Rossumae4bcee2000-07-28 01:10:35 +0000506 return error;
507 }
508
509
510 /* Create a new FT_Face from a file spec to an LWFN file. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000511 static FT_Error
512 FT_New_Face_From_LWFN( FT_Library library,
513 FSSpec* spec,
514 FT_Long face_index,
515 FT_Face* aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000516 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000517 FT_Byte* pfb_data;
518 FT_ULong pfb_size;
519 FT_Error error;
520 FT_Memory memory = library->memory;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000521
522
523 error = read_lwfn( library->memory, spec, &pfb_data, &pfb_size );
524 if ( error )
525 return error;
526
527#if 0
528 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000529 FILE* f;
530 char* path;
531
Just van Rossumae4bcee2000-07-28 01:10:35 +0000532
533 path = p2c_str( spec->name );
534 strcat( path, ".PFB" );
Werner Lemberg05c21b82000-07-29 20:38:19 +0000535 f = fopen( path, "wb" );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000536 if ( f )
537 {
538 fwrite( pfb_data, 1, pfb_size, f );
539 fclose( f );
540 }
541 }
542#endif
543
544 return open_face_from_buffer( library,
545 pfb_data,
546 pfb_size,
547 face_index,
548 "type1",
549 aface );
550 }
551
552
553 /* Create a new FT_Face from an SFNT resource, specified by res ID. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000554 static FT_Error
555 FT_New_Face_From_SFNT( FT_Library library,
556 short sfnt_id,
557 FT_Long face_index,
558 FT_Face* aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000559 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000560 Handle sfnt = NULL;
561 FT_Byte* sfnt_data;
562 size_t sfnt_size;
563 FT_Stream stream = NULL;
564 FT_Error error = 0;
565 FT_Memory memory = library->memory;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000566
567
568 sfnt = GetResource( 'sfnt', sfnt_id );
569 if ( ResError() )
570 return FT_Err_Invalid_Handle;
571
572 sfnt_size = (FT_ULong)GetHandleSize( sfnt );
573 if ( ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
574 {
575 ReleaseResource( sfnt );
576 return error;
577 }
578
579 HLock( sfnt );
Werner Lemberg05c21b82000-07-29 20:38:19 +0000580 memcpy( sfnt_data, *sfnt, sfnt_size );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000581 HUnlock( sfnt );
582 ReleaseResource( sfnt );
583
584 return open_face_from_buffer( library,
585 sfnt_data,
586 sfnt_size,
587 face_index,
588 "truetype",
589 aface );
590 }
591
592
593 /* Create a new FT_Face from a file spec to a suitcase file. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000594 static FT_Error
595 FT_New_Face_From_Suitcase( FT_Library library,
596 FSSpec* spec,
597 FT_Long face_index,
598 FT_Face* aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000599 {
600 FT_Error error = FT_Err_Ok;
601 short res_ref, res_index;
602 Handle fond;
603
604
605 res_ref = FSpOpenResFile( spec, fsRdPerm );
606 if ( ResError() )
607 return FT_Err_Cannot_Open_Resource;
608 UseResFile( res_ref );
609
610 /* face_index may be -1, in which case we
611 just need to do a sanity check */
Werner Lemberg05c21b82000-07-29 20:38:19 +0000612 if ( face_index < 0 )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000613 res_index = 1;
614 else
615 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000616 res_index = (short)( face_index + 1 );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000617 face_index = 0;
618 }
619 fond = Get1IndResource( 'FOND', res_index );
620 if ( ResError() )
621 {
622 error = FT_Err_Cannot_Open_Resource;
623 goto Error;
624 }
625
626 error = FT_New_Face_From_FOND( library, fond, face_index, aface );
627
Werner Lemberg05c21b82000-07-29 20:38:19 +0000628 Error:
Just van Rossumae4bcee2000-07-28 01:10:35 +0000629 CloseResFile( res_ref );
630 return error;
631 }
632
633
Werner Lemberg90a03302000-11-07 17:21:11 +0000634 /* documentation in ftmac.h */
635
Werner Lembergf814d0f2001-06-27 16:18:10 +0000636 FT_EXPORT_DEF( FT_Error )
637 FT_New_Face_From_FOND( FT_Library library,
638 Handle fond,
639 FT_Long face_index,
640 FT_Face *aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000641 {
642 short sfnt_id, have_sfnt, have_lwfn = 0;
643 Str255 lwfn_file_name;
644 short fond_id;
645 OSType fond_type;
646 Str255 fond_name;
647 FSSpec lwfn_spec;
648 FT_Error error = FT_Err_Unknown_File_Format;
649
650
Werner Lembergc3b21602001-12-05 01:22:05 +0000651 GetResInfo( fond, &fond_id, &fond_type, fond_name );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000652 if ( ResError() != noErr || fond_type != 'FOND' )
653 return FT_Err_Invalid_File_Format;
654
655 HLock( fond );
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000656 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000657 HUnlock( fond );
658
659 if ( lwfn_file_name[0] )
660 {
661 if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok )
662 have_lwfn = 1; /* yeah, we got one! */
663 else
664 have_lwfn = 0; /* no LWFN file found */
665 }
666
667 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
668 return FT_New_Face_From_LWFN( library,
669 &lwfn_spec,
670 face_index,
671 aface );
672 else if ( have_sfnt )
673 return FT_New_Face_From_SFNT( library,
674 sfnt_id,
675 face_index,
676 aface );
677
678 return FT_Err_Unknown_File_Format;
679 }
680
681
682 /*************************************************************************/
683 /* */
684 /* <Function> */
685 /* FT_New_Face */
686 /* */
687 /* <Description> */
688 /* This is the Mac-specific implementation of FT_New_Face. In */
Werner Lemberg05c21b82000-07-29 20:38:19 +0000689 /* addition to the standard FT_New_Face() functionality, it also */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000690 /* accepts pathnames to Mac suitcase files. For further */
Werner Lemberg90a03302000-11-07 17:21:11 +0000691 /* documentation see the original FT_New_Face() in freetype.h. */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000692 /* */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000693 FT_EXPORT_DEF( FT_Error )
694 FT_New_Face( FT_Library library,
695 const char* pathname,
696 FT_Long face_index,
697 FT_Face *aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000698 {
699 FT_Open_Args args;
700 FSSpec spec;
701 OSType file_type;
702
703
704 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
705 if ( !pathname )
706 return FT_Err_Invalid_Argument;
707
708 if ( file_spec_from_path( pathname, &spec ) )
709 return FT_Err_Invalid_Argument;
710
711 file_type = get_file_type( &spec );
712 if ( file_type == 'FFIL' || file_type == 'tfil' )
713 return FT_New_Face_From_Suitcase( library, &spec, face_index, aface );
714 else if ( file_type == 'LWFN' )
715 return FT_New_Face_From_LWFN( library, &spec, face_index, aface );
716 else
717 {
718 args.flags = ft_open_pathname;
719 args.pathname = (char*)pathname;
720
721 return FT_Open_Face( library, &args, face_index, aface );
722 }
723 }
724
Werner Lemberg05c21b82000-07-29 20:38:19 +0000725
726/* END */