blob: 0c9611644e4e916710fc9d373e8b00e106e1a595 [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
Just van Rossumae4bcee2000-07-28 01:10:35 +000077 /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
78 TrueType in case *both* are available (this is not common,
79 but it *is* possible). */
80#ifndef PREFER_LWFN
81#define PREFER_LWFN 1
82#endif
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
Werner Lemberge9e130c2001-12-07 21:56:32 +0000135
136 /* is this a Mac OS X .dfont file */
137 static Boolean
138 is_dfont( FSSpec* spec )
139 {
140 int nameLen = spec->name[0];
141
142
143 if ( spec->name[nameLen - 5] == '.' &&
144 spec->name[nameLen - 4] == 'd' &&
145 spec->name[nameLen - 3] == 'f' &&
146 spec->name[nameLen - 2] == 'o' &&
147 spec->name[nameLen - 1] == 'n' &&
148 spec->name[nameLen ] == 't' )
149 return true;
150 else
151 return false;
152 }
153
Just van Rossumae4bcee2000-07-28 01:10:35 +0000154
155 /* Given a PostScript font name, create the Macintosh LWFN file name. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000156 static void
157 create_lwfn_name( char* ps_name,
158 Str255 lwfn_file_name )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000159 {
160 int max = 5, count = 0;
161 FT_Byte* p = lwfn_file_name;
162 FT_Byte* q = (FT_Byte*)ps_name;
163
164
165 lwfn_file_name[0] = 0;
166
167 while ( *q )
168 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000169 if ( isupper( *q ) )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000170 {
171 if ( count )
172 max = 3;
173 count = 0;
174 }
Werner Lemberg05c21b82000-07-29 20:38:19 +0000175 if ( count < max && ( isalnum( *q ) || *q == '_' ) )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000176 {
177 *++p = *q;
178 lwfn_file_name[0]++;
179 count++;
180 }
181 q++;
182 }
183 }
184
185
186 /* Given a file reference, answer its location as a vRefNum
187 and a dirID. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000188 static FT_Error
189 get_file_location( short ref_num,
190 short* v_ref_num,
191 long* dir_id,
192 unsigned char* file_name )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000193 {
194 FCBPBRec pb;
195 OSErr error;
196
Just van Rossumae4bcee2000-07-28 01:10:35 +0000197 pb.ioNamePtr = file_name;
198 pb.ioVRefNum = 0;
199 pb.ioRefNum = ref_num;
200 pb.ioFCBIndx = 0;
201
Werner Lemberg05c21b82000-07-29 20:38:19 +0000202
Just van Rossumae4bcee2000-07-28 01:10:35 +0000203 error = PBGetFCBInfoSync( &pb );
204 if ( error == noErr )
205 {
206 *v_ref_num = pb.ioFCBVRefNum;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000207 *dir_id = pb.ioFCBParID;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000208 }
209 return error;
210 }
211
212
213 /* Make a file spec for an LWFN file from a FOND resource and
214 a file name. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000215 static FT_Error
216 make_lwfn_spec( Handle fond,
217 unsigned char* file_name,
218 FSSpec* spec )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000219 {
220 FT_Error error;
221 short ref_num, v_ref_num;
222 long dir_id;
223 Str255 fond_file_name;
224
225
226 ref_num = HomeResFile( fond );
Werner Lemberg05c21b82000-07-29 20:38:19 +0000227
Just van Rossumae4bcee2000-07-28 01:10:35 +0000228 error = ResError();
229 if ( !error )
Werner Lemberg05c21b82000-07-29 20:38:19 +0000230 error = get_file_location( ref_num, &v_ref_num,
231 &dir_id, fond_file_name );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000232 if ( !error )
233 error = FSMakeFSSpec( v_ref_num, dir_id, file_name, spec );
234
235 return error;
236 }
237
238
239 /* Look inside the FOND data, answer whether there should be an SFNT
Werner Lemberge9e130c2001-12-07 21:56:32 +0000240 resource, and answer the name of a possible LWFN Type 1 file.
241
242 Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000243 to load a face OTHER than the first one in the FOND!
244 */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000245 static void
246 parse_fond( char* fond_data,
247 short* have_sfnt,
248 short* sfnt_id,
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000249 Str255 lwfn_file_name,
250 short face_index )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000251 {
252 AsscEntry* assoc;
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000253 AsscEntry* base_assoc;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000254 FamRec* fond;
255
256
257 *sfnt_id = 0;
258 *have_sfnt = 0;
259 lwfn_file_name[0] = 0;
260
Werner Lembergc3b21602001-12-05 01:22:05 +0000261 fond = (FamRec*)fond_data;
262 assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000263 base_assoc = assoc;
Werner Lembergc3b21602001-12-05 01:22:05 +0000264 assoc += face_index; /* add on the face_index! */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000265
Werner Lembergc3b21602001-12-05 01:22:05 +0000266 /* if the face at this index is not scalable,
267 fall back to the first one (old behavior) */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000268 if ( assoc->fontSize == 0 )
269 {
270 *have_sfnt = 1;
Werner Lembergc3b21602001-12-05 01:22:05 +0000271 *sfnt_id = assoc->fontID;
Just van Rossumae4bcee2000-07-28 01:10:35 +0000272 }
Werner Lembergc3b21602001-12-05 01:22:05 +0000273 else if ( base_assoc->fontSize == 0 )
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000274 {
275 *have_sfnt = 1;
Werner Lembergc3b21602001-12-05 01:22:05 +0000276 *sfnt_id = base_assoc->fontID;
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000277 }
Just van Rossumae4bcee2000-07-28 01:10:35 +0000278
279 if ( fond->ffStylOff )
280 {
281 unsigned char* p = (unsigned char*)fond_data;
282 StyleTable* style;
283 unsigned short string_count;
284 unsigned char* name_table = 0;
285 char ps_name[256];
286 unsigned char* names[64];
287 int i;
288
Werner Lemberg05c21b82000-07-29 20:38:19 +0000289
Just van Rossumae4bcee2000-07-28 01:10:35 +0000290 p += fond->ffStylOff;
291 style = (StyleTable*)p;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000292 p += sizeof ( StyleTable );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000293 string_count = *(unsigned short*)(p);
Werner Lemberg05c21b82000-07-29 20:38:19 +0000294 p += sizeof ( short );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000295
296 for ( i = 0 ; i < string_count && i < 64; i++ )
297 {
298 names[i] = p;
299 p += names[i][0];
300 p++;
301 }
Werner Lemberg05c21b82000-07-29 20:38:19 +0000302 strcpy( ps_name, p2c_str( names[0] ) ); /* Family name */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000303
304 if ( style->indexes[0] > 1 )
305 {
Werner Lemberg05c21b82000-07-29 20:38:19 +0000306 unsigned char* suffixes = names[style->indexes[0] - 1];
307
308
Werner Lemberge9e130c2001-12-07 21:56:32 +0000309 for ( i = 1; i <= suffixes[0]; i++ )
310 strcat( ps_name, p2c_str( names[suffixes[i] - 1] ) );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000311 }
312 create_lwfn_name( ps_name, lwfn_file_name );
313 }
314 }
315
316
317 /* Read Type 1 data from the POST resources inside the LWFN file,
318 return a PFB buffer. This is somewhat convoluted because the FT2
319 PFB parser wants the ASCII header as one chunk, and the LWFN
320 chunks are often not organized that way, so we'll glue chunks
321 of the same type together. */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000322 static FT_Error
323 read_lwfn( FT_Memory memory,
324 FSSpec* lwfn_spec,
325 FT_Byte** pfb_data,
326 FT_ULong* size )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000327 {
328 FT_Error error = FT_Err_Ok;
329 short res_ref, res_id;
330 unsigned char *buffer, *p, *size_p;
331 FT_ULong total_size = 0;
332 FT_ULong post_size, pfb_chunk_size;
333 Handle post_data;
334 char code, last_code;
335
336
337 res_ref = FSpOpenResFile( lwfn_spec, fsRdPerm );
338 if ( ResError() )
339 return FT_Err_Out_Of_Memory;
340 UseResFile( res_ref );
341
342 /* First pass: load all POST resources, and determine the size of
343 the output buffer. */
344 res_id = 501;
345 last_code = -1;
Werner Lemberg05c21b82000-07-29 20:38:19 +0000346
Just van Rossumae4bcee2000-07-28 01:10:35 +0000347 for (;;)
348 {
349 post_data = Get1Resource( 'POST', res_id++ );
350 if ( post_data == NULL )
351 break; /* we're done */
352
353 code = (*post_data)[0];
354
355 if ( code != last_code )
356 {
357 if ( code == 5 )
358 total_size += 2; /* just the end code */
359 else
360 total_size += 6; /* code + 4 bytes chunk length */
361 }
362
363 total_size += GetHandleSize( post_data ) - 2;
364 last_code = code;
365 }
366
367 if ( ALLOC( buffer, (FT_Long)total_size ) )
368 goto Error;
369
370 /* Second pass: append all POST data to the buffer, add PFB fields.
Werner Lemberg05c21b82000-07-29 20:38:19 +0000371 Glue all consecutive chunks of the same type together. */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000372 p = buffer;
373 res_id = 501;
374 last_code = -1;
375 pfb_chunk_size = 0;
376
377 for (;;)
378 {
379 post_data = Get1Resource( 'POST', res_id++ );
380 if ( post_data == NULL )
381 break; /* we're done */
382
383 post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
384 code = (*post_data)[0];
385
386 if ( code != last_code )
387 {
Just van Rossumae4bcee2000-07-28 01:10:35 +0000388 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
Werner Lemberge9e130c2001-12-07 21:56:32 +0000651
Leonard Rosenthol70133732001-12-06 17:52:06 +0000652 /* Create a new FT_Face from a file spec to a suitcase file. */
653 static FT_Error
654 FT_New_Face_From_dfont( FT_Library library,
Werner Lemberge9e130c2001-12-07 21:56:32 +0000655 FSSpec* spec,
656 FT_Long face_index,
657 FT_Face* aface )
Leonard Rosenthol70133732001-12-06 17:52:06 +0000658 {
Werner Lemberge9e130c2001-12-07 21:56:32 +0000659 FT_Error error = FT_Err_Ok;
660 short res_ref, res_index;
661 Handle fond;
662 FSRef hostContainerRef;
Leonard Rosenthol70133732001-12-06 17:52:06 +0000663
Leonard Rosenthol70133732001-12-06 17:52:06 +0000664
Werner Lemberge9e130c2001-12-07 21:56:32 +0000665 error = FSpMakeFSRef( spec, &hostContainerRef );
666 if ( error == noErr )
667 error = FSOpenResourceFile( &hostContainerRef,
668 0, NULL, fsRdPerm, &res_ref );
Leonard Rosenthol70133732001-12-06 17:52:06 +0000669
Werner Lemberge9e130c2001-12-07 21:56:32 +0000670 if ( error != noErr )
671 return FT_Err_Cannot_Open_Resource;
Leonard Rosenthol70133732001-12-06 17:52:06 +0000672
Werner Lemberge9e130c2001-12-07 21:56:32 +0000673 UseResFile( res_ref );
Leonard Rosenthol70133732001-12-06 17:52:06 +0000674
Werner Lemberge9e130c2001-12-07 21:56:32 +0000675 /* face_index may be -1, in which case we
676 just need to do a sanity check */
677 if ( face_index < 0 )
678 res_index = 1;
679 else
680 {
681 res_index = (short)( face_index + 1 );
682 face_index = 0;
683 }
684 fond = Get1IndResource( 'FOND', res_index );
685 if ( ResError() )
686 {
687 error = FT_Err_Cannot_Open_Resource;
688 goto Error;
689 }
690
691 error = FT_New_Face_From_FOND( library, fond, face_index, aface );
692
693 Error:
694 CloseResFile( res_ref );
695 return error;
Leonard Rosenthol70133732001-12-06 17:52:06 +0000696 }
697
Just van Rossumae4bcee2000-07-28 01:10:35 +0000698
Werner Lemberg90a03302000-11-07 17:21:11 +0000699 /* documentation in ftmac.h */
700
Werner Lembergf814d0f2001-06-27 16:18:10 +0000701 FT_EXPORT_DEF( FT_Error )
702 FT_New_Face_From_FOND( FT_Library library,
703 Handle fond,
704 FT_Long face_index,
705 FT_Face *aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000706 {
707 short sfnt_id, have_sfnt, have_lwfn = 0;
708 Str255 lwfn_file_name;
709 short fond_id;
710 OSType fond_type;
711 Str255 fond_name;
712 FSSpec lwfn_spec;
713 FT_Error error = FT_Err_Unknown_File_Format;
714
715
Werner Lembergc3b21602001-12-05 01:22:05 +0000716 GetResInfo( fond, &fond_id, &fond_type, fond_name );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000717 if ( ResError() != noErr || fond_type != 'FOND' )
718 return FT_Err_Invalid_File_Format;
719
720 HLock( fond );
Leonard Rosentholae340bb2001-10-26 13:24:39 +0000721 parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
Just van Rossumae4bcee2000-07-28 01:10:35 +0000722 HUnlock( fond );
723
724 if ( lwfn_file_name[0] )
725 {
726 if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok )
727 have_lwfn = 1; /* yeah, we got one! */
728 else
729 have_lwfn = 0; /* no LWFN file found */
730 }
731
732 if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
733 return FT_New_Face_From_LWFN( library,
734 &lwfn_spec,
735 face_index,
736 aface );
737 else if ( have_sfnt )
738 return FT_New_Face_From_SFNT( library,
739 sfnt_id,
740 face_index,
741 aface );
742
743 return FT_Err_Unknown_File_Format;
744 }
745
Werner Lemberge9e130c2001-12-07 21:56:32 +0000746
Leonard Rosenthol70133732001-12-06 17:52:06 +0000747 /* documentation in ftmac.h */
Werner Lemberge9e130c2001-12-07 21:56:32 +0000748
Leonard Rosenthol70133732001-12-06 17:52:06 +0000749 FT_EXPORT_DEF( FT_Error )
Werner Lemberge9e130c2001-12-07 21:56:32 +0000750 FT_GetFile_From_Mac_Name( char* fontName,
751 FSSpec* pathSpec,
752 FT_Long* face_index )
753 {
754 OptionBits options = kFMUseGlobalScopeOption;
755
756 FMFontFamilyIterator famIter;
757 OSStatus status = FMCreateFontFamilyIterator( NULL, NULL,
758 options,
759 &famIter );
760 FMFont the_font = NULL;
761 FMFontFamily family = NULL;
762
763
Leonard Rosenthol70133732001-12-06 17:52:06 +0000764 *face_index = 0;
Werner Lemberge9e130c2001-12-07 21:56:32 +0000765 while ( status == 0 && !the_font )
Leonard Rosenthol70133732001-12-06 17:52:06 +0000766 {
Werner Lemberge9e130c2001-12-07 21:56:32 +0000767 status = FMGetNextFontFamily( &famIter, &family );
768 if ( status == 0 )
769 {
770 int stat2;
771 FMFontFamilyInstanceIterator instIter;
772 Str255 famNameStr;
773 char famName[256];
774
775
776 /* get the family name */
777 FMGetFontFamilyName( family, famNameStr );
778 CopyPascalStringToC( famNameStr, famName );
779
780 /* iterate through the styles */
781 FMCreateFontFamilyInstanceIterator( family, &instIter );
782
783 *face_index = 0;
784 stat2 = 0;
785 while ( stat2 == 0 && !the_font )
786 {
787 FMFontStyle style;
788 FMFontSize size;
789 FMFont font;
790
791
792 stat2 = FMGetNextFontFamilyInstance( &instIter, &font,
793 &style, &size );
794 if ( stat2 == 0 && size == 0 )
795 {
796 char fullName[256];
797
798
799 /* build up a complete face name */
800 strcpy( fullName, famName );
801 if ( style & bold )
802 strcat( fullName, " Bold" );
803 if ( style & italic )
804 strcat( fullName, " Italic" );
805
806 /* compare with the name we are looking for */
807 if ( strcmp( fullName, fontName ) == 0 )
Leonard Rosenthol70133732001-12-06 17:52:06 +0000808 {
Werner Lemberge9e130c2001-12-07 21:56:32 +0000809 /* found it! */
810 the_font = font;
Leonard Rosenthol70133732001-12-06 17:52:06 +0000811 }
Werner Lemberge9e130c2001-12-07 21:56:32 +0000812 else
813 ++(*face_index);
814 }
815 }
816
817 FMDisposeFontFamilyInstanceIterator( &instIter );
818 }
Leonard Rosenthol70133732001-12-06 17:52:06 +0000819 }
Werner Lemberge9e130c2001-12-07 21:56:32 +0000820
821 FMDisposeFontFamilyIterator( &famIter );
822
823 if ( the_font )
824 {
825 FMGetFontContainer( the_font, pathSpec );
826 return FT_Err_Ok;
827 }
828 else
829 return FT_Err_Unknown_File_Format;
830 }
831
Just van Rossumae4bcee2000-07-28 01:10:35 +0000832
833 /*************************************************************************/
834 /* */
835 /* <Function> */
836 /* FT_New_Face */
837 /* */
838 /* <Description> */
839 /* This is the Mac-specific implementation of FT_New_Face. In */
Werner Lemberg05c21b82000-07-29 20:38:19 +0000840 /* addition to the standard FT_New_Face() functionality, it also */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000841 /* accepts pathnames to Mac suitcase files. For further */
Werner Lemberg90a03302000-11-07 17:21:11 +0000842 /* documentation see the original FT_New_Face() in freetype.h. */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000843 /* */
Werner Lembergf814d0f2001-06-27 16:18:10 +0000844 FT_EXPORT_DEF( FT_Error )
845 FT_New_Face( FT_Library library,
846 const char* pathname,
847 FT_Long face_index,
848 FT_Face *aface )
Just van Rossumae4bcee2000-07-28 01:10:35 +0000849 {
850 FT_Open_Args args;
851 FSSpec spec;
852 OSType file_type;
853
854
855 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
856 if ( !pathname )
857 return FT_Err_Invalid_Argument;
858
859 if ( file_spec_from_path( pathname, &spec ) )
860 return FT_Err_Invalid_Argument;
861
862 file_type = get_file_type( &spec );
863 if ( file_type == 'FFIL' || file_type == 'tfil' )
864 return FT_New_Face_From_Suitcase( library, &spec, face_index, aface );
865 else if ( file_type == 'LWFN' )
866 return FT_New_Face_From_LWFN( library, &spec, face_index, aface );
Leonard Rosenthol70133732001-12-06 17:52:06 +0000867 else if ( is_dfont( &spec ) )
868 return FT_New_Face_From_dfont( library, &spec, face_index, aface );
Werner Lemberge9e130c2001-12-07 21:56:32 +0000869 else /* let it fall through to normal loader (.ttf, .otf, etc.) */
Just van Rossumae4bcee2000-07-28 01:10:35 +0000870 {
871 args.flags = ft_open_pathname;
872 args.pathname = (char*)pathname;
873
874 return FT_Open_Face( library, &args, face_index, aface );
875 }
876 }
877
Werner Lemberg05c21b82000-07-29 20:38:19 +0000878
879/* END */