blob: f56c42961654b9e8795a232d74187a9b94cb724c [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>
Leonard Rosenthol70133732001-12-06 17:52:06 +000069#include <Files.h>
70#include <TextUtils.h>
Just van Rossumae4bcee2000-07-28 01:10:35 +000071
72#include <ctype.h> /* for isupper() and isalnum() */
73
David Turner19ed8af2000-12-08 02:42:29 +000074#include FT_MAC_H
Just van Rossumae4bcee2000-07-28 01:10:35 +000075
76
77
78 /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
79 TrueType in case *both* are available (this is not common,
80 but it *is* possible). */
81#ifndef PREFER_LWFN
82#define PREFER_LWFN 1
83#endif
84
85
86
Werner Lemberg05c21b82000-07-29 20:38:19 +000087 /* Quick'n'dirty Pascal string to C string converter.
Just van Rossumae4bcee2000-07-28 01:10:35 +000088 Warning: this call is not thread safe! Use with caution. */
Werner Lembergf814d0f2001-06-27 16:18:10 +000089 static char*
90 p2c_str( unsigned char* pstr )
Just van Rossumae4bcee2000-07-28 01:10:35 +000091 {
Werner Lemberg05c21b82000-07-29 20:38:19 +000092 static char cstr[256];
Just van Rossumae4bcee2000-07-28 01:10:35 +000093
94
Werner Lemberg05c21b82000-07-29 20:38:19 +000095 strncpy( cstr, (char*)pstr + 1, pstr[0] );
Just van Rossumae4bcee2000-07-28 01:10:35 +000096 cstr[pstr[0]] = '\0';
97 return cstr;
98 }
99
100
101 /* Given a pathname, fill in a file spec. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000102 static int
103 file_spec_from_path( const char* pathname,
104 FSSpec* spec )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000105 {
106 Str255 p_path;
107 FT_ULong path_len;
108
109
110 /* convert path to a pascal string */
111 path_len = strlen( pathname );
112 if ( path_len > 255 )
113 return -1;
114 p_path[0] = (unsigned char)path_len;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000115 strncpy( (char*)p_path + 1, pathname, path_len );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000116
117 if ( FSMakeFSSpec( 0, 0, p_path, spec ) != noErr )
118 return -1;
119 else
120 return 0;
121 }
122
123
124 /* Return the file type of the file specified by spec. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000125 static OSType
126 get_file_type( FSSpec* spec )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000127 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000128 FInfo finfo;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000129
130
131 if ( FSpGetFInfo( spec, &finfo ) != noErr )
132 return 0; /* file might not exist */
Werner Lemberg05c21b82000-07-29 20:38:19 +0000133
Just van Rossumae4bcee2000-07-28 01:10:35 +0000134 return finfo.fdType;
135 }
136
Leonard Rosenthol70133732001-12-06 17:52:06 +0000137 /* is this a Mac OS X .dfont file */
138 static Boolean is_dfont( FSSpec* spec )
139 {
140 int nameLen = spec->name[0];
141
142 if ( spec->name[nameLen-5] == '.' &&
143 spec->name[nameLen-4] == 'd' &&
144 spec->name[nameLen-3] == 'f' &&
145 spec->name[nameLen-2] == 'o' &&
146 spec->name[nameLen-1] == 'n' &&
147 spec->name[nameLen] == 't')
148 return true;
149 else
150 return false;
151 }
152
Just van Rossumae4bcee2000-07-28 01:10:35 +0000153
154 /* Given a PostScript font name, create the Macintosh LWFN file name. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000155 static void
156 create_lwfn_name( char* ps_name,
157 Str255 lwfn_file_name )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000158 {
159 int max = 5, count = 0;
160 FT_Byte* p = lwfn_file_name;
161 FT_Byte* q = (FT_Byte*)ps_name;
162
163
164 lwfn_file_name[0] = 0;
165
166 while ( *q )
167 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000168 if ( isupper( *q ) )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000169 {
170 if ( count )
171 max = 3;
172 count = 0;
173 }
Werner Lemberg05c21b82000-07-29 20:38:19 +0000174 if ( count < max && ( isalnum( *q ) || *q == '_' ) )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000175 {
176 *++p = *q;
177 lwfn_file_name[0]++;
178 count++;
179 }
180 q++;
181 }
182 }
183
184
185 /* Given a file reference, answer its location as a vRefNum
186 and a dirID. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000187 static FT_Error
188 get_file_location( short ref_num,
189 short* v_ref_num,
190 long* dir_id,
191 unsigned char* file_name )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000192 {
193 FCBPBRec pb;
194 OSErr error;
195
Just van Rossumae4bcee2000-07-28 01:10:35 +0000196 pb.ioNamePtr = file_name;
197 pb.ioVRefNum = 0;
198 pb.ioRefNum = ref_num;
199 pb.ioFCBIndx = 0;
200
Werner Lemberg05c21b82000-07-29 20:38:19 +0000201
Just van Rossumae4bcee2000-07-28 01:10:35 +0000202 error = PBGetFCBInfoSync( &pb );
203 if ( error == noErr )
204 {
205 *v_ref_num = pb.ioFCBVRefNum;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000206 *dir_id = pb.ioFCBParID;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000207 }
208 return error;
209 }
210
211
212 /* Make a file spec for an LWFN file from a FOND resource and
213 a file name. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000214 static FT_Error
215 make_lwfn_spec( Handle fond,
216 unsigned char* file_name,
217 FSSpec* spec )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000218 {
219 FT_Error error;
220 short ref_num, v_ref_num;
221 long dir_id;
222 Str255 fond_file_name;
223
224
225 ref_num = HomeResFile( fond );
Werner Lemberg05c21b82000-07-29 20:38:19 +0000226
Just van Rossumae4bcee2000-07-28 01:10:35 +0000227 error = ResError();
228 if ( !error )
Werner Lemberg05c21b82000-07-29 20:38:19 +0000229 error = get_file_location( ref_num, &v_ref_num,
230 &dir_id, fond_file_name );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000231 if ( !error )
232 error = FSMakeFSSpec( v_ref_num, dir_id, file_name, spec );
233
234 return error;
235 }
236
237
238 /* Look inside the FOND data, answer whether there should be an SFNT
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000239 resource, and answer the name of a possible LWFN Type 1 file.
240
241 Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
242 to load a face OTHER than the first one in the FOND!
243 */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000244 static void
245 parse_fond( char* fond_data,
246 short* have_sfnt,
247 short* sfnt_id,
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000248 Str255 lwfn_file_name,
249 short face_index )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000250 {
251 AsscEntry* assoc;
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000252 AsscEntry* base_assoc;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000253 FamRec* fond;
254
255
256 *sfnt_id = 0;
257 *have_sfnt = 0;
258 lwfn_file_name[0] = 0;
259
Werner Lembergc3b21602001-12-05 01:22:05 +0000260 fond = (FamRec*)fond_data;
261 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000262 base_assoc = assoc;
Werner Lembergc3b21602001-12-05 01:22:05 +0000263 assoc += face_index; /* add on the face_index! */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000264
Werner Lembergc3b21602001-12-05 01:22:05 +0000265 /* if the face at this index is not scalable,
266 fall back to the first one (old behavior) */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000267 if ( assoc->fontSize == 0 )
268 {
269 *have_sfnt = 1;
Werner Lembergc3b21602001-12-05 01:22:05 +0000270 *sfnt_id = assoc->fontID;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000271 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000272 else if ( base_assoc->fontSize == 0 )
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000273 {
274 *have_sfnt = 1;
Werner Lembergc3b21602001-12-05 01:22:05 +0000275 *sfnt_id = base_assoc->fontID;
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000276 }
Just van Rossumae4bcee2000-07-28 01:10:35 +0000277
278 if ( fond->ffStylOff )
279 {
280 unsigned char* p = (unsigned char*)fond_data;
281 StyleTable* style;
282 unsigned short string_count;
283 unsigned char* name_table = 0;
284 char ps_name[256];
285 unsigned char* names[64];
286 int i;
287
Werner Lemberg05c21b82000-07-29 20:38:19 +0000288
Just van Rossumae4bcee2000-07-28 01:10:35 +0000289 p += fond->ffStylOff;
290 style = (StyleTable*)p;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000291 p += sizeof ( StyleTable );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000292 string_count = *(unsigned short*)(p);
Werner Lemberg05c21b82000-07-29 20:38:19 +0000293 p += sizeof ( short );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000294
295 for ( i = 0 ; i < string_count && i < 64; i++ )
296 {
297 names[i] = p;
298 p += names[i][0];
299 p++;
300 }
Werner Lemberg05c21b82000-07-29 20:38:19 +0000301 strcpy( ps_name, p2c_str( names[0] ) ); /* Family name */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000302
303 if ( style->indexes[0] > 1 )
304 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000305 unsigned char* suffixes = names[style->indexes[0] - 1];
306
307
Just van Rossumae4bcee2000-07-28 01:10:35 +0000308 for ( i=1; i<=suffixes[0]; i++ )
Werner Lemberg05c21b82000-07-29 20:38:19 +0000309 strcat( ps_name, p2c_str( names[suffixes[i] - 1 ] ) );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000310 }
311 create_lwfn_name( ps_name, lwfn_file_name );
312 }
313 }
314
315
316 /* Read Type 1 data from the POST resources inside the LWFN file,
317 return a PFB buffer. This is somewhat convoluted because the FT2
318 PFB parser wants the ASCII header as one chunk, and the LWFN
319 chunks are often not organized that way, so we'll glue chunks
320 of the same type together. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000321 static FT_Error
322 read_lwfn( FT_Memory memory,
323 FSSpec* lwfn_spec,
324 FT_Byte** pfb_data,
325 FT_ULong* size )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000326 {
327 FT_Error error = FT_Err_Ok;
328 short res_ref, res_id;
329 unsigned char *buffer, *p, *size_p;
330 FT_ULong total_size = 0;
331 FT_ULong post_size, pfb_chunk_size;
332 Handle post_data;
333 char code, last_code;
334
335
336 res_ref = FSpOpenResFile( lwfn_spec, fsRdPerm );
337 if ( ResError() )
338 return FT_Err_Out_Of_Memory;
339 UseResFile( res_ref );
340
341 /* First pass: load all POST resources, and determine the size of
342 the output buffer. */
343 res_id = 501;
344 last_code = -1;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000345
Just van Rossumae4bcee2000-07-28 01:10:35 +0000346 for (;;)
347 {
348 post_data = Get1Resource( 'POST', res_id++ );
349 if ( post_data == NULL )
350 break; /* we're done */
351
352 code = (*post_data)[0];
353
354 if ( code != last_code )
355 {
356 if ( code == 5 )
357 total_size += 2; /* just the end code */
358 else
359 total_size += 6; /* code + 4 bytes chunk length */
360 }
361
362 total_size += GetHandleSize( post_data ) - 2;
363 last_code = code;
364 }
365
366 if ( ALLOC( buffer, (FT_Long)total_size ) )
367 goto Error;
368
369 /* Second pass: append all POST data to the buffer, add PFB fields.
Werner Lemberg05c21b82000-07-29 20:38:19 +0000370 Glue all consecutive chunks of the same type together. */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000371 p = buffer;
372 res_id = 501;
373 last_code = -1;
374 pfb_chunk_size = 0;
375
376 for (;;)
377 {
378 post_data = Get1Resource( 'POST', res_id++ );
379 if ( post_data == NULL )
380 break; /* we're done */
381
382 post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
383 code = (*post_data)[0];
384
385 if ( code != last_code )
386 {
387
388 if ( last_code != -1 )
389 {
390 /* we're done adding a chunk, fill in the size field */
Werner Lemberg05c21b82000-07-29 20:38:19 +0000391 *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF );
392 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF );
393 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
394 *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000395 pfb_chunk_size = 0;
396 }
397
398 *p++ = 0x80;
399 if ( code == 5 )
400 *p++ = 0x03; /* the end */
401 else if ( code == 2 )
402 *p++ = 0x02; /* binary segment */
403 else
404 *p++ = 0x01; /* ASCII segment */
405
406 if ( code != 5 )
407 {
408 size_p = p; /* save for later */
409 p += 4; /* make space for size field */
410 }
411 }
412
413 memcpy( p, *post_data + 2, post_size );
414 pfb_chunk_size += post_size;
415 p += post_size;
416 last_code = code;
417 }
418
419 *pfb_data = buffer;
420 *size = total_size;
421
Werner Lemberg05c21b82000-07-29 20:38:19 +0000422 Error:
Just van Rossumae4bcee2000-07-28 01:10:35 +0000423 CloseResFile( res_ref );
424 return error;
425 }
426
427
428 /* Finalizer for a memory stream; gets called by FT_Done_Face().
429 It frees the memory it uses. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000430 static void
431 memory_stream_close( FT_Stream stream )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000432 {
433 FT_Memory memory = stream->memory;
434
435
436 FREE( stream->base );
Werner Lemberg05c21b82000-07-29 20:38:19 +0000437
438 stream->size = 0;
439 stream->base = 0;
440 stream->close = 0;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000441 }
442
443
444 /* Create a new memory stream from a buffer and a size. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000445 static FT_Error
446 new_memory_stream( FT_Library library,
447 FT_Byte* base,
448 FT_ULong size,
449 FT_Stream_Close close,
450 FT_Stream* astream )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000451 {
452 FT_Error error;
453 FT_Memory memory;
454 FT_Stream stream;
455
456
457 if ( !library )
458 return FT_Err_Invalid_Library_Handle;
459
460 if ( !base )
461 return FT_Err_Invalid_Argument;
462
463 *astream = 0;
464 memory = library->memory;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000465 if ( ALLOC( stream, sizeof ( *stream ) ) )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000466 goto Exit;
467
468 FT_New_Memory_Stream( library,
469 base,
470 size,
471 stream );
472
473 stream->close = close;
474
475 *astream = stream;
476
477 Exit:
478 return error;
479 }
480
481
482 /* Create a new FT_Face given a buffer and a driver name. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000483 static FT_Error
484 open_face_from_buffer( FT_Library library,
485 FT_Byte* base,
486 FT_ULong size,
487 FT_Long face_index,
488 char* driver_name,
489 FT_Face* aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000490 {
491 FT_Open_Args args;
492 FT_Error error;
493 FT_Stream stream;
494 FT_Memory memory = library->memory;
495
496
497 error = new_memory_stream( library,
498 base,
499 size,
500 memory_stream_close,
501 &stream );
502 if ( error )
503 {
504 FREE( base );
505 return error;
506 }
507
508 args.flags = ft_open_stream;
509 args.stream = stream;
510 if ( driver_name )
511 {
512 args.flags = args.flags | ft_open_driver;
513 args.driver = FT_Get_Module( library, driver_name );
514 }
Werner Lemberg05c21b82000-07-29 20:38:19 +0000515
Just van Rossumae4bcee2000-07-28 01:10:35 +0000516 error = FT_Open_Face( library, &args, face_index, aface );
Just van Rossum5fe94ff2000-07-28 02:25:23 +0000517 if ( error == FT_Err_Ok )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000518 (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
Just van Rossum5fe94ff2000-07-28 02:25:23 +0000519 else
520 {
521 FT_Done_Stream( stream );
522 FREE( stream );
523 }
Just van Rossumae4bcee2000-07-28 01:10:35 +0000524 return error;
525 }
526
527
528 /* Create a new FT_Face from a file spec to an LWFN file. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000529 static FT_Error
530 FT_New_Face_From_LWFN( FT_Library library,
531 FSSpec* spec,
532 FT_Long face_index,
533 FT_Face* aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000534 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000535 FT_Byte* pfb_data;
536 FT_ULong pfb_size;
537 FT_Error error;
538 FT_Memory memory = library->memory;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000539
540
541 error = read_lwfn( library->memory, spec, &pfb_data, &pfb_size );
542 if ( error )
543 return error;
544
545#if 0
546 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000547 FILE* f;
548 char* path;
549
Just van Rossumae4bcee2000-07-28 01:10:35 +0000550
551 path = p2c_str( spec->name );
552 strcat( path, ".PFB" );
Werner Lemberg05c21b82000-07-29 20:38:19 +0000553 f = fopen( path, "wb" );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000554 if ( f )
555 {
556 fwrite( pfb_data, 1, pfb_size, f );
557 fclose( f );
558 }
559 }
560#endif
561
562 return open_face_from_buffer( library,
563 pfb_data,
564 pfb_size,
565 face_index,
566 "type1",
567 aface );
568 }
569
570
571 /* Create a new FT_Face from an SFNT resource, specified by res ID. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000572 static FT_Error
573 FT_New_Face_From_SFNT( FT_Library library,
574 short sfnt_id,
575 FT_Long face_index,
576 FT_Face* aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000577 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000578 Handle sfnt = NULL;
579 FT_Byte* sfnt_data;
580 size_t sfnt_size;
581 FT_Stream stream = NULL;
582 FT_Error error = 0;
583 FT_Memory memory = library->memory;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000584
585
586 sfnt = GetResource( 'sfnt', sfnt_id );
587 if ( ResError() )
588 return FT_Err_Invalid_Handle;
589
590 sfnt_size = (FT_ULong)GetHandleSize( sfnt );
591 if ( ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
592 {
593 ReleaseResource( sfnt );
594 return error;
595 }
596
597 HLock( sfnt );
Werner Lemberg05c21b82000-07-29 20:38:19 +0000598 memcpy( sfnt_data, *sfnt, sfnt_size );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000599 HUnlock( sfnt );
600 ReleaseResource( sfnt );
601
602 return open_face_from_buffer( library,
603 sfnt_data,
604 sfnt_size,
605 face_index,
606 "truetype",
607 aface );
608 }
609
610
611 /* Create a new FT_Face from a file spec to a suitcase file. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000612 static FT_Error
613 FT_New_Face_From_Suitcase( FT_Library library,
614 FSSpec* spec,
615 FT_Long face_index,
616 FT_Face* aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000617 {
618 FT_Error error = FT_Err_Ok;
619 short res_ref, res_index;
620 Handle fond;
621
622
623 res_ref = FSpOpenResFile( spec, fsRdPerm );
624 if ( ResError() )
625 return FT_Err_Cannot_Open_Resource;
626 UseResFile( res_ref );
627
628 /* face_index may be -1, in which case we
629 just need to do a sanity check */
Werner Lemberg05c21b82000-07-29 20:38:19 +0000630 if ( face_index < 0 )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000631 res_index = 1;
632 else
633 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000634 res_index = (short)( face_index + 1 );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000635 face_index = 0;
636 }
637 fond = Get1IndResource( 'FOND', res_index );
638 if ( ResError() )
639 {
640 error = FT_Err_Cannot_Open_Resource;
641 goto Error;
642 }
643
644 error = FT_New_Face_From_FOND( library, fond, face_index, aface );
645
Werner Lemberg05c21b82000-07-29 20:38:19 +0000646 Error:
Just van Rossumae4bcee2000-07-28 01:10:35 +0000647 CloseResFile( res_ref );
648 return error;
649 }
650
Leonard Rosenthol70133732001-12-06 17:52:06 +0000651 /* Create a new FT_Face from a file spec to a suitcase file. */
652 static FT_Error
653 FT_New_Face_From_dfont( FT_Library library,
654 FSSpec* spec,
655 FT_Long face_index,
656 FT_Face* aface )
657 {
658 FT_Error error = FT_Err_Ok;
659 short res_ref, res_index;
660 Handle fond;
661 FSRef hostContainerRef;
662
663 error = FSpMakeFSRef( spec, &hostContainerRef );
664 if ( error == noErr )
665 error = FSOpenResourceFile( &hostContainerRef, 0, NULL, fsRdPerm, &res_ref );
666
667 if ( error != noErr )
668 return FT_Err_Cannot_Open_Resource;
669
670 UseResFile( res_ref );
671
672 /* face_index may be -1, in which case we
673 just need to do a sanity check */
674 if ( face_index < 0 )
675 res_index = 1;
676 else
677 {
678 res_index = (short)( face_index + 1 );
679 face_index = 0;
680 }
681 fond = Get1IndResource( 'FOND', res_index );
682 if ( ResError() )
683 {
684 error = FT_Err_Cannot_Open_Resource;
685 goto Error;
686 }
687
688 error = FT_New_Face_From_FOND( library, fond, face_index, aface );
689
690Error:
691 CloseResFile( res_ref );
692 return error;
693 }
694
Just van Rossumae4bcee2000-07-28 01:10:35 +0000695
Werner Lemberg90a03302000-11-07 17:21:11 +0000696 /* documentation in ftmac.h */
697
Werner Lembergf814d0f2001-06-27 16:18:10 +0000698 FT_EXPORT_DEF( FT_Error )
699 FT_New_Face_From_FOND( FT_Library library,
700 Handle fond,
701 FT_Long face_index,
702 FT_Face *aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000703 {
704 short sfnt_id, have_sfnt, have_lwfn = 0;
705 Str255 lwfn_file_name;
706 short fond_id;
707 OSType fond_type;
708 Str255 fond_name;
709 FSSpec lwfn_spec;
710 FT_Error error = FT_Err_Unknown_File_Format;
711
712
Werner Lembergc3b21602001-12-05 01:22:05 +0000713 GetResInfo( fond, &fond_id, &fond_type, fond_name );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000714 if ( ResError() != noErr || fond_type != 'FOND' )
715 return FT_Err_Invalid_File_Format;
716
717 HLock( fond );
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000718 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000719 HUnlock( fond );
720
721 if ( lwfn_file_name[0] )
722 {
723 if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok )
724 have_lwfn = 1; /* yeah, we got one! */
725 else
726 have_lwfn = 0; /* no LWFN file found */
727 }
728
729 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
730 return FT_New_Face_From_LWFN( library,
731 &lwfn_spec,
732 face_index,
733 aface );
734 else if ( have_sfnt )
735 return FT_New_Face_From_SFNT( library,
736 sfnt_id,
737 face_index,
738 aface );
739
740 return FT_Err_Unknown_File_Format;
741 }
742
Leonard Rosenthol70133732001-12-06 17:52:06 +0000743 /* documentation in ftmac.h */
744 FT_EXPORT_DEF( FT_Error )
745 FT_GetFile_From_Mac_Name( char* fontName, FSSpec* pathSpec, FT_Long* face_index )
746{
747 OptionBits options = kFMUseGlobalScopeOption;
748 FMFontFamilyIterator famIter;
749 OSStatus status = FMCreateFontFamilyIterator(NULL, NULL, options, &famIter);
750 FMFont the_font = NULL;
751 FMFontFamily family = NULL;
752 *face_index = 0;
753 while (status == 0 && !the_font)
754 {
755 status = FMGetNextFontFamily(&famIter, &family);
756 if (status == 0)
757 {
758 int stat2;
759 FMFontFamilyInstanceIterator instIter;
760
761 /* get the family name */
762 Str255 famNameStr;
763 char famName[256];
764 FMGetFontFamilyName(family, famNameStr);
765 CopyPascalStringToC(famNameStr, famName);
766
767 /* iterate through the styles */
768 FMCreateFontFamilyInstanceIterator(family, &instIter);
769 *face_index = 0;
770 stat2 = 0;
771 while (stat2 == 0 && !the_font)
772 {
773 FMFontStyle style;
774 FMFontSize size;
775 FMFont font;
776 stat2 = FMGetNextFontFamilyInstance(&instIter, &font, &style, &size);
777 if (stat2 == 0 && size == 0)
778 {
779 /* build up a complete face name */
780 char fullName[256];
781 strcpy( fullName, famName );
782 if (style & bold)
783 strcat( fullName, " Bold" );
784 if (style & italic)
785 strcat( fullName, " Italic" );
786
787 /* compare with the name we are looking for */
788 if (strcmp( fullName, fontName ) == 0 )
789 {
790 /* found it! */
791 the_font = font;
792 }
793 else
794 ++(*face_index);
795 }
796 }
797 FMDisposeFontFamilyInstanceIterator(&instIter);
798 }
799 }
800 FMDisposeFontFamilyIterator(&famIter);
801
802 if ( the_font ) {
803 FMGetFontContainer(the_font, pathSpec);
804 return FT_Err_Ok;
805 } else
806 return FT_Err_Unknown_File_Format;
807
808}
Just van Rossumae4bcee2000-07-28 01:10:35 +0000809
810 /*************************************************************************/
811 /* */
812 /* <Function> */
813 /* FT_New_Face */
814 /* */
815 /* <Description> */
816 /* This is the Mac-specific implementation of FT_New_Face. In */
Werner Lemberg05c21b82000-07-29 20:38:19 +0000817 /* addition to the standard FT_New_Face() functionality, it also */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000818 /* accepts pathnames to Mac suitcase files. For further */
Werner Lemberg90a03302000-11-07 17:21:11 +0000819 /* documentation see the original FT_New_Face() in freetype.h. */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000820 /* */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000821 FT_EXPORT_DEF( FT_Error )
822 FT_New_Face( FT_Library library,
823 const char* pathname,
824 FT_Long face_index,
825 FT_Face *aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000826 {
827 FT_Open_Args args;
828 FSSpec spec;
829 OSType file_type;
830
831
832 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
833 if ( !pathname )
834 return FT_Err_Invalid_Argument;
835
836 if ( file_spec_from_path( pathname, &spec ) )
837 return FT_Err_Invalid_Argument;
838
839 file_type = get_file_type( &spec );
840 if ( file_type == 'FFIL' || file_type == 'tfil' )
841 return FT_New_Face_From_Suitcase( library, &spec, face_index, aface );
842 else if ( file_type == 'LWFN' )
843 return FT_New_Face_From_LWFN( library, &spec, face_index, aface );
Leonard Rosenthol70133732001-12-06 17:52:06 +0000844 else if ( is_dfont( &spec ) )
845 return FT_New_Face_From_dfont( library, &spec, face_index, aface );
846 else /* let it fall through to normal loader (.ttf, .otf, etc.) */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000847 {
848 args.flags = ft_open_pathname;
849 args.pathname = (char*)pathname;
850
851 return FT_Open_Face( library, &args, face_index, aface );
852 }
853 }
854
Werner Lemberg05c21b82000-07-29 20:38:19 +0000855
856/* END */