* 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.
This commit is contained in:
Werner Lemberg 2004-02-26 21:56:27 +00:00
parent 50aedae2be
commit e2455bad12
4 changed files with 381 additions and 156 deletions

View File

@ -1,3 +1,36 @@
2004-02-25 Werner Lemberg <wl@gnu.org>
* docs/CHANGES: Updated.
2004-02-25 Garrick Meeker <garrick@digitalanarchy.com>
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 <mtaylor@clear.net.nz>
* src/autohint/ahhint.c (ah_hinter_load) <FT_GLYPH_FORMAT_OUTLINE>:

View File

@ -67,6 +67,10 @@ LATEST CHANGES BETWEEN 2.1.8 and 2.1.7
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.

View File

@ -112,9 +112,43 @@ FT_BEGIN_HEADER
/* 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 );
/* */

View File

@ -4,7 +4,7 @@
/* */
/* Mac FOND support. Written by just@letterror.com. */
/* */
/* 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,12 +91,50 @@
#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,12 +267,24 @@
}
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.
Thanks to Paul Miller (paulm@profoundeffects.com) 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,19 +304,24 @@
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;
}
else if ( base_assoc->fontSize == 0 )
{
*have_sfnt = 1;
*sfnt_id = base_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;
}
}
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,19 +619,59 @@
}
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;
@ -624,34 +732,34 @@
/* 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;
num_faces = count_faces( fond );
if ( face_index < num_faces )
break;
face_index -= num_faces;
}
error = FT_New_Face_From_FOND( library, fond, face_index, aface );
@ -662,57 +770,6 @@
}
#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;
}
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 );
Error:
CloseResFile( res_ref );
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,27 +934,29 @@
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 );
/* 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. */
result = FT_New_Face_From_Suitcase( library, res_ref,
face_index, aface );
if ( result == 0 )
return result;
/* else forget about the resource fork and fall through to */
/* data fork formats */
CloseResFile( res_ref );
}
#ifdef TARGET_API_MAC_CARBON
if ( is_dfont( &spec ) )
return FT_New_Face_From_dfont( library, &spec, face_index, aface );
#endif
/* let it fall through to normal loader (.ttf, .otf, etc.) */
args.flags = FT_OPEN_PATHNAME;
args.pathname = (char*)pathname;
@ -922,4 +964,116 @@
}
/*************************************************************************/
/* */
/* <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;
}
/* END */