📄 ftmac.c
字号:
/***************************************************************************/
/* */
/* ftmac.c */
/* */
/* Mac FOND support. Written by just@letterror.com. */
/* Heavily Fixed by mpsuzuki, George Williams and Sean McBride */
/* */
/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006 by */
/* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
/* modified, and distributed under the terms of the FreeType project */
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */
/* understand and accept it fully. */
/* */
/***************************************************************************/
/*
Notes
Mac suitcase files can (and often do!) contain multiple fonts. To
support this I use the face_index argument of FT_(Open|New)_Face()
functions, and pretend the suitcase file is a collection.
Warning: fbit and NFNT bitmap resources are not supported yet. In old
sfnt fonts, bitmap glyph data for each size is stored in each `NFNT'
resources instead of the `bdat' table in the sfnt resource. Therefore,
face->num_fixed_sizes is set to 0, because bitmap data in `NFNT'
resource is unavailable at present.
The Mac FOND support works roughly like this:
- Check whether the offered stream points to a Mac suitcase file. This
is done by checking the file type: it has to be 'FFIL' or 'tfil'. The
stream that gets passed to our init_face() routine is a stdio stream,
which isn't usable for us, since the FOND resources live in the
resource fork. So we just grab the stream->pathname field.
- Read the FOND resource into memory, then check whether there is a
TrueType font and/or(!) a Type 1 font available.
- If there is a Type 1 font available (as a separate `LWFN' file), read
its data into memory, massage it slightly so it becomes PFB data, wrap
it into a memory stream, load the Type 1 driver and delegate the rest
of the work to it by calling FT_Open_Face(). (XXX TODO: after this
has been done, the kerning data from the FOND resource should be
appended to the face: On the Mac there are usually no AFM files
available. However, this is tricky since we need to map Mac char
codes to ps glyph names to glyph ID's...)
- If there is a TrueType font (an `sfnt' resource), read it into memory,
wrap it into a memory stream, load the TrueType driver and delegate
the rest of the work to it, by calling FT_Open_Face().
- Some suitcase fonts (notably Onyx) might point the `LWFN' file to
itself, even though it doesn't contains `POST' resources. To handle
this special case without opening the file an extra time, we just
ignore errors from the `LWFN' and fallback to the `sfnt' if both are
available.
*/
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_INTERNAL_STREAM_H
#if defined( __GNUC__ ) || defined( __IBMC__ )
/* This is for Mac OS X. Without redefinition, OS_INLINE */
/* expands to `static inline' which doesn't survive the */
/* -ansi compilation flag of GCC. */
#undef OS_INLINE
#define OS_INLINE static __inline__
#include <Carbon/Carbon.h>
#else
#include <Resources.h>
#include <Fonts.h>
#include <Endian.h>
#include <Errors.h>
#include <Files.h>
#include <TextUtils.h>
#endif
#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
#include <FSp_fopen.h>
#endif
#include FT_MAC_H
#undef FT_GetFile_From_Mac_Name
#undef FT_GetFile_From_Mac_ATS_Name
#undef FT_New_Face_From_FSSpec
/* FSSpec functions are deprecated since Mac OS X 10.4 */
#ifndef HAVE_FSSPEC
#if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
#define HAVE_FSSPEC 1
#else
#define HAVE_FSSPEC 0
#endif
#endif
/* most FSRef functions were introduced since Mac OS 9 */
#ifndef HAVE_FSREF
#if TARGET_API_MAC_OSX
#define HAVE_FSREF 1
#else
#define HAVE_FSREF 0
#endif
#endif
#ifndef HFS_MAXPATHLEN
#define HFS_MAXPATHLEN 1024
#endif
/* QuickDraw is deprecated since Mac OS X 10.4 */
#ifndef HAVE_QUICKDRAW_CARBON
#if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
#define HAVE_QUICKDRAW_CARBON 1
#else
#define HAVE_QUICKDRAW_CARBON 0
#endif
#endif
/* AppleTypeService is available since Mac OS X */
#ifndef HAVE_ATS
#if TARGET_API_MAC_OSX
#define HAVE_ATS 1
#else
#define HAVE_ATS 0
#endif
#endif
/* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
TrueType in case *both* are available (this is not common,
but it *is* possible). */
#ifndef PREFER_LWFN
#define PREFER_LWFN 1
#endif
#if !HAVE_QUICKDRAW_CARBON /* QuickDraw is deprecated since Mac OS X 10.4 */
FT_EXPORT_DEF( FT_Error )
FT_GetFile_From_Mac_Name( const char* fontName,
FSSpec* pathSpec,
FT_Long* face_index )
{
return FT_Err_Unimplemented_Feature;
}
#else
FT_EXPORT_DEF( FT_Error )
FT_GetFile_From_Mac_Name( const char* fontName,
FSSpec* pathSpec,
FT_Long* face_index )
{
OptionBits options = kFMUseGlobalScopeOption;
FMFontFamilyIterator famIter;
OSStatus status = FMCreateFontFamilyIterator( NULL, NULL,
options,
&famIter );
FMFont the_font = 0;
FMFontFamily family = 0;
*face_index = 0;
while ( status == 0 && !the_font )
{
status = FMGetNextFontFamily( &famIter, &family );
if ( status == 0 )
{
int stat2;
FMFontFamilyInstanceIterator instIter;
Str255 famNameStr;
char famName[256];
/* get the family name */
FMGetFontFamilyName( family, famNameStr );
CopyPascalStringToC( famNameStr, famName );
/* iterate through the styles */
FMCreateFontFamilyInstanceIterator( family, &instIter );
*face_index = 0;
stat2 = 0;
while ( stat2 == 0 && !the_font )
{
FMFontStyle style;
FMFontSize size;
FMFont font;
stat2 = FMGetNextFontFamilyInstance( &instIter, &font,
&style, &size );
if ( stat2 == 0 && size == 0 )
{
char fullName[256];
/* build up a complete face name */
ft_strcpy( fullName, famName );
if ( style & bold )
ft_strcat( fullName, " Bold" );
if ( style & italic )
ft_strcat( fullName, " Italic" );
/* compare with the name we are looking for */
if ( ft_strcmp( fullName, fontName ) == 0 )
{
/* found it! */
the_font = font;
}
else
++(*face_index);
}
}
FMDisposeFontFamilyInstanceIterator( &instIter );
}
}
FMDisposeFontFamilyIterator( &famIter );
if ( the_font )
{
FMGetFontContainer( the_font, pathSpec );
return FT_Err_Ok;
}
else
return FT_Err_Unknown_File_Format;
}
#endif /* HAVE_QUICKDRAW_CARBON */
#if !HAVE_ATS
FT_EXPORT_DEF( FT_Error )
FT_GetFile_From_Mac_ATS_Name( const char* fontName,
FSSpec* pathSpec,
FT_Long* face_index )
{
return FT_Err_Unimplemented_Feature;
}
#else
FT_EXPORT_DEF( FT_Error )
FT_GetFile_From_Mac_ATS_Name( const char* fontName,
FSSpec* pathSpec,
FT_Long* face_index )
{
CFStringRef cf_fontName;
ATSFontRef ats_font_id;
*face_index = 0;
cf_fontName = CFStringCreateWithCString( NULL, fontName,
kCFStringEncodingMacRoman );
ats_font_id = ATSFontFindFromName( cf_fontName,
kATSOptionFlagsUnRestrictedScope );
if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL )
return FT_Err_Unknown_File_Format;
if ( 0 != ATSFontGetFileSpecification( ats_font_id, pathSpec ) )
return FT_Err_Unknown_File_Format;
/* face_index calculation by searching preceding fontIDs */
/* with same FSRef */
{
int i;
FSSpec f;
for ( i = 1; i < ats_font_id; i++ )
{
if ( 0 != ATSFontGetFileSpecification( ats_font_id - i,
&f ) ||
f.vRefNum != pathSpec->vRefNum ||
f.parID != pathSpec->parID ||
f.name[0] != pathSpec->name[0] ||
0 != ft_strncmp( (char *)f.name + 1,
(char *)pathSpec->name + 1,
f.name[0] ) )
break;
}
*face_index = ( i - 1 );
}
return FT_Err_Ok;
}
#endif /* HAVE_ATS */
#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
#define STREAM_FILE( stream ) ( (FT_FILE*)stream->descriptor.pointer )
FT_CALLBACK_DEF( void )
ft_FSp_stream_close( FT_Stream stream )
{
ft_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 )
{
FT_FILE* file;
file = STREAM_FILE( stream );
ft_fseek( file, offset, SEEK_SET );
return (unsigned long)ft_fread( buffer, 1, count, file );
}
#endif /* __MWERKS__ && !TARGET_RT_MAC_MACHO */
#if HAVE_FSSPEC && !HAVE_FSREF
static OSErr
FT_FSPathMakeSpec( const UInt8* pathname,
FSSpec* spec_p,
Boolean isDirectory )
{
const char *p, *q;
short vRefNum;
long dirID;
Str255 nodeName;
OSErr err;
p = q = (const char *)pathname;
dirID = 0;
vRefNum = 0;
while ( 1 )
{
q = p + FT_MIN( 255, ft_strlen( p ) );
if ( q == p )
return 0;
if ( 255 < ft_strlen( (char *)pathname ) )
{
while ( p < q && *q != ':' )
q--;
}
if ( p < q )
*(char *)nodeName = q - p;
else if ( ft_strlen( p ) < 256 )
*(char *)nodeName = ft_strlen( p );
else
return errFSNameTooLong;
ft_strncpy( (char *)nodeName + 1, (char *)p, *(char *)nodeName );
err = FSMakeFSSpec( vRefNum, dirID, nodeName, spec_p );
if ( err || '\0' == *q )
return err;
vRefNum = spec_p->vRefNum;
dirID = spec_p->parID;
p = q;
}
}
static OSErr
FT_FSpMakePath( const FSSpec* spec_p,
UInt8* path,
UInt32 maxPathSize )
{
OSErr err;
FSSpec spec = *spec_p;
short vRefNum;
long dirID;
Str255 parDir_name;
FT_MEM_SET( path, 0, maxPathSize );
while ( 1 )
{
int child_namelen = ft_strlen( (char *)path );
unsigned char node_namelen = spec.name[0];
unsigned char* node_name = spec.name + 1;
if ( node_namelen + child_namelen > maxPathSize )
return errFSNameTooLong;
FT_MEM_MOVE( path + node_namelen + 1, path, child_namelen );
FT_MEM_COPY( path, node_name, node_namelen );
if ( child_namelen > 0 )
path[node_namelen] = ':';
vRefNum = spec.vRefNum;
dirID = spec.parID;
parDir_name[0] = '\0';
err = FSMakeFSSpec( vRefNum, dirID, parDir_name, &spec );
if ( noErr != err || dirID == spec.parID )
break;
}
return noErr;
}
#endif /* HAVE_FSSPEC && !HAVE_FSREF */
static OSErr
FT_FSPathMakeRes( const UInt8* pathname,
short* res )
{
#if HAVE_FSREF
OSErr err;
FSRef ref;
if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
return FT_Err_Cannot_Open_Resource;
/* at present, no support for dfont format */
err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res );
if ( noErr == err )
return err;
/* fallback to original resource-fork font */
*res = FSOpenResFile( &ref, fsRdPerm );
err = ResError();
#else
OSErr err;
FSSpec spec;
if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) )
return FT_Err_Cannot_Open_Resource;
/* at present, no support for dfont format without FSRef */
/* (see above), try original resource-fork font */
*res = FSpOpenResFile( &spec, fsRdPerm );
err = ResError();
#endif /* HAVE_FSREF */
return err;
}
/* Return the file type for given pathname */
static OSType
get_file_type_from_path( const UInt8* pathname )
{
#if HAVE_FSREF
FSRef ref;
FSCatalogInfo info;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -