ref: e2455bad125fab422792340e41868ffb9d4c2fb3
parent: 50aedae2beb40f21f1a86194fdfb1609939ed987
author: Werner Lemberg <[email protected]>
date: Thu Feb 26 16:56:27 EST 2004
* docs/CHANGES: Updated. Improve MacOS fond support. Provide a new API `FT_New_Face_From_FSSpec' similar to `FT_New_Face'. * src/base/ftmac.c [__MWERKS__]: Include FSp_fpopen.h. STREAM_FILE [__MWERKS__]: New macro. (ft_FSp_stream_close, ft_FSp_stream_io) [__MWERKS__]: New functions. (file_spec_from_path) [__MWERKS__]: Updated #if statement. (get_file_type, make_lwfn_spec): Use `const' for argument. (is_dfont) [TARGET_API_MAC_CARBON]: Removed. (count_face_sfnt, count_faces): New functions. (parse_fond): Do some range checking. (read_lwfn): Change type of second argument. No longer call FSpOpenResFile. (OpenFileAsResource): New function. (FT_New_Face_From_LWFN): Use `const' for second argument. Use OpenFileAsResource. (FT_New_Face_From_Suitcase): Change type of second argument. No longer call FSpOpenResFile. Loop over all resource indices. (FT_New_Face_From_dfont) [TARGET_API_MAC_CARBON]: Removed. (FT_GetFile_From_Mac_Name): Use `const' for first argument. (ResourceForkSize): Removed. (FT_New_Face): Updated to use new functions. (FT_New_Face_From_FSSpec): New function. * include/freetype/ftmac.h: Updated.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2004-02-25 Werner Lemberg <[email protected]>
+
+ * docs/CHANGES: Updated.
+
+2004-02-25 Garrick Meeker <[email protected]>
+
+ Improve MacOS fond support. Provide a new API
+ `FT_New_Face_From_FSSpec' similar to `FT_New_Face'.
+
+ * src/base/ftmac.c [__MWERKS__]: Include FSp_fpopen.h.
+ STREAM_FILE [__MWERKS__]: New macro.
+ (ft_FSp_stream_close, ft_FSp_stream_io) [__MWERKS__]: New functions.
+ (file_spec_from_path) [__MWERKS__]: Updated #if statement.
+ (get_file_type, make_lwfn_spec): Use `const' for argument.
+ (is_dfont) [TARGET_API_MAC_CARBON]: Removed.
+ (count_face_sfnt, count_faces): New functions.
+ (parse_fond): Do some range checking.
+ (read_lwfn): Change type of second argument.
+ No longer call FSpOpenResFile.
+ (OpenFileAsResource): New function.
+ (FT_New_Face_From_LWFN): Use `const' for second argument.
+ Use OpenFileAsResource.
+ (FT_New_Face_From_Suitcase): Change type of second argument.
+ No longer call FSpOpenResFile.
+ Loop over all resource indices.
+ (FT_New_Face_From_dfont) [TARGET_API_MAC_CARBON]: Removed.
+ (FT_GetFile_From_Mac_Name): Use `const' for first argument.
+ (ResourceForkSize): Removed.
+ (FT_New_Face): Updated to use new functions.
+ (FT_New_Face_From_FSSpec): New function.
+
+ * include/freetype/ftmac.h: Updated.
+
2004-02-24 Malcolm Taylor <[email protected]>
* src/autohint/ahhint.c (ah_hinter_load) <FT_GLYPH_FORMAT_OUTLINE>:
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -67,6 +67,10 @@
forks on non-MacOS platforms (for example, Linux can mount MacOS
file systems).
+ - Support for MacOS has been improved; there is now a new function
+ `FT_New_Face_From_FSSpec' similar to `FT_New_Face' except that
+ it accepts an FSSpec instead of a path.
+
- The cache sub-system has been rewritten.
- There is now support for deinstallation of faces.
--- a/include/freetype/ftmac.h
+++ b/include/freetype/ftmac.h
@@ -112,9 +112,43 @@
/* FreeType error code. 0 means success. */
/* */
FT_EXPORT( FT_Error )
- FT_GetFile_From_Mac_Name( char* fontName,
- FSSpec* pathSpec,
- FT_Long* face_index );
+ FT_GetFile_From_Mac_Name( const char* fontName,
+ FSSpec* pathSpec,
+ FT_Long* face_index );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Face_From_FSSpec */
+ /* */
+ /* <Description> */
+ /* Creates a new face object from a given resource and typeface index */
+ /* using an FSSpec to the font file. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library resource. */
+ /* */
+ /* <Input> */
+ /* spec :: FSSpec to the font file. */
+ /* */
+ /* face_index :: The index of the face within the resource. The */
+ /* first face has index 0. */
+ /* <Output> */
+ /* aface :: A handle to a new face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* @FT_New_Face_From_FSSpec is identical to @FT_New_Face except */
+ /* it accepts an FSSpec instead of a path. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_New_Face_From_FSSpec( FT_Library library,
+ const FSSpec *spec,
+ FT_Long face_index,
+ FT_Face *aface );
/* */
--- a/src/base/ftmac.c
+++ b/src/base/ftmac.c
@@ -4,7 +4,7 @@
/* */
/* Mac FOND support. Written by [email protected]. */
/* */
-/* Copyright 1996-2001, 2002, 2003 by */
+/* Copyright 1996-2001, 2002, 2003, 2004 by */
/* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -77,6 +77,10 @@
#include <TextUtils.h>
#endif
+#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
+#include <FSp_fopen.h>
+#endif
+
#include FT_MAC_H
@@ -87,13 +91,51 @@
#define PREFER_LWFN 1
#endif
+
+#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
+
+#define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer )
+
+
+ FT_CALLBACK_DEF( void )
+ ft_FSp_stream_close( FT_Stream stream )
+ {
+ fclose( STREAM_FILE( stream ) );
+
+ stream->descriptor.pointer = NULL;
+ stream->size = 0;
+ stream->base = 0;
+ }
+
+
+ FT_CALLBACK_DEF( unsigned long )
+ ft_FSp_stream_io( FT_Stream stream,
+ unsigned long offset,
+ unsigned char* buffer,
+ unsigned long count )
+ {
+ FILE* file;
+
+
+ file = STREAM_FILE( stream );
+
+ fseek( file, offset, SEEK_SET );
+
+ return (unsigned long)fread( buffer, 1, count, file );
+ }
+
+#endif /* __MWERKS__ && !TARGET_RT_MAC_MACHO */
+
+
/* Given a pathname, fill in a file spec. */
static int
file_spec_from_path( const char* pathname,
FSSpec* spec )
{
-#if defined( TARGET_API_MAC_CARBON ) && !defined( __MWERKS__ )
+#if TARGET_API_MAC_CARBON && \
+ !( defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO )
+
OSErr e;
FSRef ref;
@@ -123,12 +165,13 @@
return 0;
#endif
+
}
/* Return the file type of the file specified by spec. */
static OSType
- get_file_type( FSSpec* spec )
+ get_file_type( const FSSpec* spec )
{
FInfo finfo;
@@ -140,22 +183,6 @@
}
-#ifdef TARGET_API_MAC_CARBON
-
- /* is this a Mac OS X .dfont file */
- static Boolean
- is_dfont( FSSpec* spec )
- {
- int nameLen = spec->name[0];
-
-
- return nameLen >= 6 &&
- !ft_memcmp( spec->name + nameLen - 5, ".dfont", 6 );
- }
-
-#endif
-
-
/* Given a PostScript font name, create the Macintosh LWFN file name. */
static void
create_lwfn_name( char* ps_name,
@@ -217,9 +244,9 @@
/* Make a file spec for an LWFN file from a FOND resource and
a file name. */
static FT_Error
- make_lwfn_spec( Handle fond,
- unsigned char* file_name,
- FSSpec* spec )
+ make_lwfn_spec( Handle fond,
+ const unsigned char* file_name,
+ FSSpec* spec )
{
FT_Error error;
short ref_num, v_ref_num;
@@ -240,6 +267,16 @@
}
+ static short
+ count_faces_sfnt( char *fond_data )
+ {
+ /* The count is 1 greater than the value in the FOND. */
+ /* Isn't that cute? :-) */
+
+ return 1 + *( (short *)( fond_data + sizeof ( FamRec ) ) );
+ }
+
+
/* Look inside the FOND data, answer whether there should be an SFNT
resource, and answer the name of a possible LWFN Type 1 file.
@@ -246,6 +283,8 @@
Thanks to Paul Miller ([email protected]) for the fix
to load a face OTHER than the first one in the FOND!
*/
+
+
static void
parse_fond( char* fond_data,
short* have_sfnt,
@@ -265,20 +304,25 @@
fond = (FamRec*)fond_data;
assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
base_assoc = assoc;
- assoc += face_index; /* add on the face_index! */
- /* if the face at this index is not scalable,
- fall back to the first one (old behavior) */
- if ( assoc->fontSize == 0 )
+ /* Let's do a little range checking before we get too excited here */
+ if ( face_index < count_faces_sfnt( fond_data ) )
{
- *have_sfnt = 1;
- *sfnt_id = assoc->fontID;
+ assoc += face_index; /* add on the face_index! */
+
+ /* if the face at this index is not scalable,
+ fall back to the first one (old behavior) */
+ if ( assoc->fontSize == 0 )
+ {
+ *have_sfnt = 1;
+ *sfnt_id = assoc->fontID;
+ }
+ else if ( base_assoc->fontSize == 0 )
+ {
+ *have_sfnt = 1;
+ *sfnt_id = base_assoc->fontID;
+ }
}
- else if ( base_assoc->fontSize == 0 )
- {
- *have_sfnt = 1;
- *sfnt_id = base_assoc->fontID;
- }
if ( fond->ffStylOff )
{
@@ -344,6 +388,33 @@
}
+ static short
+ count_faces( Handle fond )
+ {
+ short sfnt_id, have_sfnt, have_lwfn = 0;
+ Str255 lwfn_file_name;
+ FSSpec lwfn_spec;
+
+
+ HLock( fond );
+ parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 );
+ HUnlock( fond );
+
+ if ( lwfn_file_name[0] )
+ {
+ if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok )
+ have_lwfn = 1; /* yeah, we got one! */
+ else
+ have_lwfn = 0; /* no LWFN file found */
+ }
+
+ if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
+ return 1;
+ else
+ return count_faces_sfnt( *fond );
+ }
+
+
/* Read Type 1 data from the POST resources inside the LWFN file,
return a PFB buffer. This is somewhat convoluted because the FT2
PFB parser wants the ASCII header as one chunk, and the LWFN
@@ -351,12 +422,12 @@
of the same type together. */
static FT_Error
read_lwfn( FT_Memory memory,
- FSSpec* lwfn_spec,
+ short res_ref,
FT_Byte** pfb_data,
FT_ULong* size )
{
FT_Error error = FT_Err_Ok;
- short res_ref, res_id;
+ short res_id;
unsigned char *buffer, *p, *size_p = NULL;
FT_ULong total_size = 0;
FT_ULong post_size, pfb_chunk_size;
@@ -364,13 +435,10 @@
char code, last_code;
- res_ref = FSpOpenResFile( lwfn_spec, fsRdPerm );
- if ( ResError() )
- return FT_Err_Out_Of_Memory;
UseResFile( res_ref );
- /* First pass: load all POST resources, and determine the size of
- the output buffer. */
+ /* First pass: load all POST resources, and determine the size of */
+ /* the output buffer. */
res_id = 501;
last_code = -1;
@@ -397,8 +465,8 @@
if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
goto Error;
- /* Second pass: append all POST data to the buffer, add PFB fields.
- Glue all consecutive chunks of the same type together. */
+ /* Second pass: append all POST data to the buffer, add PFB fields. */
+ /* Glue all consecutive chunks of the same type together. */
p = buffer;
res_id = 501;
last_code = -1;
@@ -551,22 +619,62 @@
}
+ static FT_Error
+ OpenFileAsResource( const FSSpec* spec,
+ short *p_res_ref )
+ {
+ FT_Error error;
+
+#if TARGET_API_MAC_CARBON
+
+ FSRef hostContainerRef;
+
+
+ error = FSpMakeFSRef( spec, &hostContainerRef );
+ if ( error == noErr )
+ error = FSOpenResourceFile( &hostContainerRef,
+ 0, NULL, fsRdPerm, p_res_ref );
+
+ /* If the above fails, then it is probably not a resource file */
+ /* However, it has been reported that FSOpenResourceFile() sometimes */
+ /* fails on some old resource-fork files, which FSpOpenResFile() can */
+ /* open. So, just try again with FSpOpenResFile() and see what */
+ /* happens :-) */
+
+ if ( error != noErr )
+
+#endif /* TARGET_API_MAC_CARBON */
+
+ {
+ *p_res_ref = FSpOpenResFile( spec, fsRdPerm );
+ error = ResError();
+ }
+
+ return error ? FT_Err_Cannot_Open_Resource : FT_Err_Ok;
+ }
+
+
/* Create a new FT_Face from a file spec to an LWFN file. */
static FT_Error
- FT_New_Face_From_LWFN( FT_Library library,
- FSSpec* spec,
- FT_Long face_index,
- FT_Face *aface )
+ FT_New_Face_From_LWFN( FT_Library library,
+ const FSSpec* lwfn_spec,
+ FT_Long face_index,
+ FT_Face *aface )
{
FT_Byte* pfb_data;
FT_ULong pfb_size;
FT_Error error;
+ short res_ref;
- error = read_lwfn( library->memory, spec, &pfb_data, &pfb_size );
+ error = OpenFileAsResource( lwfn_spec, &res_ref );
if ( error )
return error;
+ error = read_lwfn( library->memory, res_ref, &pfb_data, &pfb_size );
+ if ( error )
+ return error;
+
return open_face_from_buffer( library,
pfb_data,
pfb_size,
@@ -624,84 +732,35 @@
/* Create a new FT_Face from a file spec to a suitcase file. */
static FT_Error
FT_New_Face_From_Suitcase( FT_Library library,
- FSSpec* spec,
+ short res_ref,
FT_Long face_index,
FT_Face *aface )
{
FT_Error error = FT_Err_Ok;
- short res_ref, res_index;
+ short res_index;
Handle fond;
+ short num_faces;
- res_ref = FSpOpenResFile( spec, fsRdPerm );
- if ( ResError() )
- return FT_Err_Cannot_Open_Resource;
UseResFile( res_ref );
- /* face_index may be -1, in which case we
- just need to do a sanity check */
- if ( face_index < 0 )
- res_index = 1;
- else
+ for ( res_index = 1; ; ++res_index )
{
- res_index = (short)( face_index + 1 );
- face_index = 0;
- }
- fond = Get1IndResource( 'FOND', res_index );
- if ( ResError() )
- {
- error = FT_Err_Cannot_Open_Resource;
- goto Error;
- }
+ fond = Get1IndResource( 'FOND', res_index );
+ if ( ResError() )
+ {
+ error = FT_Err_Cannot_Open_Resource;
+ goto Error;
+ }
+ if ( face_index < 0 )
+ break;
- error = FT_New_Face_From_FOND( library, fond, face_index, aface );
+ num_faces = count_faces( fond );
+ if ( face_index < num_faces )
+ break;
- Error:
- CloseResFile( res_ref );
- return error;
- }
-
-
-#ifdef TARGET_API_MAC_CARBON
-
- /* Create a new FT_Face from a file spec to a suitcase file. */
- static FT_Error
- FT_New_Face_From_dfont( FT_Library library,
- FSSpec* spec,
- FT_Long face_index,
- FT_Face* aface )
- {
- FT_Error error = FT_Err_Ok;
- short res_ref, res_index;
- Handle fond;
- FSRef hostContainerRef;
-
-
- error = FSpMakeFSRef( spec, &hostContainerRef );
- if ( error == noErr )
- error = FSOpenResourceFile( &hostContainerRef,
- 0, NULL, fsRdPerm, &res_ref );
-
- if ( error != noErr )
- return FT_Err_Cannot_Open_Resource;
-
- UseResFile( res_ref );
-
- /* face_index may be -1, in which case we
- just need to do a sanity check */
- if ( face_index < 0 )
- res_index = 1;
- else
- {
- res_index = (short)( face_index + 1 );
- face_index = 0;
+ face_index -= num_faces;
}
- fond = Get1IndResource( 'FOND', res_index );
- if ( ResError() )
- {
- error = FT_Err_Cannot_Open_Resource;
- goto Error;
- }
error = FT_New_Face_From_FOND( library, fond, face_index, aface );
@@ -710,9 +769,7 @@
return error;
}
-#endif
-
/* documentation is in ftmac.h */
FT_EXPORT_DEF( FT_Error )
@@ -763,9 +820,9 @@
/* documentation is in ftmac.h */
FT_EXPORT_DEF( FT_Error )
- FT_GetFile_From_Mac_Name( char* fontName,
- FSSpec* pathSpec,
- FT_Long* face_index )
+ FT_GetFile_From_Mac_Name( const char* fontName,
+ FSSpec* pathSpec,
+ FT_Long* face_index )
{
OptionBits options = kFMUseGlobalScopeOption;
@@ -846,25 +903,6 @@
}
- static long
- ResourceForkSize(FSSpec* spec)
- {
- long len;
- short refNum;
- OSErr e;
-
-
- e = FSpOpenRF( spec, fsRdPerm, &refNum ); /* I.M. Files 2-155 */
- if ( e == noErr )
- {
- e = GetEOF( refNum, &len );
- FSClose( refNum );
- }
-
- return ( e == noErr ) ? len : 0;
- }
-
-
/*************************************************************************/
/* */
/* <Function> */
@@ -885,6 +923,8 @@
FT_Open_Args args;
FSSpec spec;
OSType file_type;
+ short res_ref;
+ FT_Error result;
/* test for valid `library' and `aface' delayed to FT_Open_Face() */
@@ -894,31 +934,145 @@
if ( file_spec_from_path( pathname, &spec ) )
return FT_Err_Invalid_Argument;
- /* Regardless of type, don't try to use the resource fork if it is */
- /* empty. Some TTF fonts have type `FFIL', for example, but they */
- /* only have data forks. */
-
- if ( ResourceForkSize( &spec ) != 0 )
+ if ( OpenFileAsResource( &spec, &res_ref ) == FT_Err_Ok )
{
- file_type = get_file_type( &spec );
- if ( file_type == 'FFIL' || file_type == 'tfil' )
- return FT_New_Face_From_Suitcase( library, &spec, face_index, aface );
+ /* LWFN is a (very) specific file format, check for it explicitly */
+ file_type = get_file_type( &spec );
if ( file_type == 'LWFN' )
return FT_New_Face_From_LWFN( library, &spec, face_index, aface );
- }
-#ifdef TARGET_API_MAC_CARBON
+ /* Otherwise the file type doesn't matter (there are more than */
+ /* `FFIL' and `tfil') -- just try opening it as a font suitcase; */
+ /* if it works, fine. */
- if ( is_dfont( &spec ) )
- return FT_New_Face_From_dfont( library, &spec, face_index, aface );
+ result = FT_New_Face_From_Suitcase( library, res_ref,
+ face_index, aface );
+ if ( result == 0 )
+ return result;
-#endif
+ /* else forget about the resource fork and fall through to */
+ /* data fork formats */
+ CloseResFile( res_ref );
+ }
+
/* let it fall through to normal loader (.ttf, .otf, etc.) */
args.flags = FT_OPEN_PATHNAME;
args.pathname = (char*)pathname;
return FT_Open_Face( library, &args, face_index, aface );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Face_From_FSSpec */
+ /* */
+ /* <Description> */
+ /* FT_New_Face_From_FSSpec is identical to FT_New_Face except it */
+ /* accepts an FSSpec instead of a path. */
+ /* */
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Face_From_FSSpec( FT_Library library,
+ const FSSpec *spec,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+ OSType file_type;
+ short res_ref;
+ FT_Error error;
+ FT_Stream stream;
+ FILE* file;
+ FT_Memory memory;
+
+
+ /* test for valid `library' and `aface' delayed to FT_Open_Face() */
+ if ( !spec )
+ return FT_Err_Invalid_Argument;
+
+ if ( OpenFileAsResource( spec, &res_ref ) == FT_Err_Ok )
+ {
+ /* LWFN is a (very) specific file format, check for it explicitly */
+
+ file_type = get_file_type( spec );
+ if ( file_type == 'LWFN' )
+ return FT_New_Face_From_LWFN( library, spec, face_index, aface );
+
+ /* Otherwise the file type doesn't matter (there are more than */
+ /* `FFIL' and `tfil') -- just try opening it as a font suitcase; */
+ /* if it works, fine. */
+
+ error = FT_New_Face_From_Suitcase( library, res_ref,
+ face_index, aface );
+ if ( error == 0 )
+ return error;
+
+ /* else forget about the resource fork and fall through to */
+ /* data fork formats */
+
+ CloseResFile( res_ref );
+ }
+
+ /* let it fall through to normal loader (.ttf, .otf, etc.) */
+
+#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
+
+ /* Codewarrior's C library can open a FILE from a FSSpec */
+#include <FSp_fopen.h>
+
+ memory = library->memory;
+
+ if ( FT_NEW( stream ) )
+ return error;
+ stream->memory = memory;
+
+ file = FSp_fopen( spec, "rb" );
+ if ( !file )
+ return FT_Err_Cannot_Open_Resource;
+
+ fseek( file, 0, SEEK_END );
+ stream->size = ftell( file );
+ fseek( file, 0, SEEK_SET );
+
+ stream->descriptor.pointer = file;
+ stream->pathname.pointer = NULL;
+ stream->pos = 0;
+
+ stream->read = ft_FSp_stream_io;
+ stream->close = ft_FSp_stream_close;
+
+ args.flags = FT_OPEN_STREAM;
+ args.stream = stream;
+
+ error = FT_Open_Face( library, &args, face_index, aface );
+ if ( error == FT_Err_Ok )
+ (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
+
+#else /* !(__MWERKS__ && !TARGET_RT_MAC_MACHO) */
+
+ {
+ FSRef ref;
+ UInt8 path[256];
+ OSErr err;
+
+
+ err = FSpMakeFSRef(spec, &ref);
+ if ( !err )
+ {
+ err = FSRefMakePath( &ref, path, sizeof ( path ) );
+ if ( !err )
+ error = FT_New_Face( library, (const char*)path,
+ face_index, aface );
+ }
+ if ( err )
+ error = FT_Err_Cannot_Open_Resource;
+ }
+
+#endif /* !(__MWERKS__ && !TARGET_RT_MAC_MACHO) */
+
+ return error;
}