📄 ftmac.c
字号:
/***************************************************************************/
/* */
/* ftmac.c */
/* */
/* Mac FOND support. Written by just@letterror.com. */
/* Heavily modified by mpsuzuki, George Williams, and Sean McBride. */
/* */
/* This file is for Mac OS X only; see builds/mac/ftoldmac.c for */
/* classic platforms built by MPW. */
/* */
/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 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
/* This is for Mac OS X. Without redefinition, OS_INLINE */
/* expands to `static inline' which doesn't survive the */
/* -ansi compilation flag of GCC. */
#if !HAVE_ANSI_OS_INLINE
#undef OS_INLINE
#define OS_INLINE static __inline__
#endif
#include <Carbon/Carbon.h>
#ifndef HFS_MAXPATHLEN
#define HFS_MAXPATHLEN 1024
#endif
#define FT_DEPRECATED_ATTRIBUTE
#include FT_MAC_H
/* undefine blocking-macros in ftmac.h */
#undef FT_GetFile_From_Mac_Name( a, b, c )
#undef FT_GetFile_From_Mac_ATS_Name( a, b, c )
#undef FT_New_Face_From_FSSpec( a, b, c, d )
/* 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
FT_EXPORT_DEF( FT_Error )
FT_GetFile_From_Mac_Name( const char* fontName,
FSSpec* pathSpec,
FT_Long* face_index )
{
return FT_Err_Unimplemented_Feature;
}
/* Private function. */
/* The FSSpec type has been discouraged for a long time, */
/* but for some reason, there is no FSRef version of */
/* ATSFontGetFileSpecification(), so we made our own. */
/* Apple will provide one eventually. */
static OSStatus
FT_ATSFontGetFileReference( ATSFontRef ats_font_id,
FSRef* ats_font_ref )
{
OSStatus err;
FSSpec spec;
err = ATSFontGetFileSpecification( ats_font_id, &spec );
if ( noErr == err )
err = FSpMakeFSRef( &spec, ats_font_ref );
return err;
}
static FT_Error
FT_GetFileRef_From_Mac_ATS_Name( const char* fontName,
FSRef* ats_font_ref,
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 );
CFRelease( cf_fontName );
if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL )
return FT_Err_Unknown_File_Format;
if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) )
return FT_Err_Unknown_File_Format;
/* face_index calculation by searching preceding fontIDs */
/* with same FSRef */
{
ATSFontRef id2 = ats_font_id - 1;
FSRef ref2;
while ( id2 > 0 )
{
if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) )
break;
if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) )
break;
id2 --;
}
*face_index = ats_font_id - ( id2 + 1 );
}
return FT_Err_Ok;
}
FT_EXPORT_DEF( FT_Error )
FT_GetFilePath_From_Mac_ATS_Name( const char* fontName,
UInt8* path,
UInt32 maxPathSize,
FT_Long* face_index )
{
FSRef ref;
FT_Error err;
err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
if ( FT_Err_Ok != err )
return err;
if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) )
return FT_Err_Unknown_File_Format;
return FT_Err_Ok;
}
/* This function is deprecated because FSSpec is deprecated in Mac OS X */
FT_EXPORT_DEF( FT_Error )
FT_GetFile_From_Mac_ATS_Name( const char* fontName,
FSSpec* pathSpec,
FT_Long* face_index )
{
#if __LP64__
return FT_Err_Unimplemented_Feature;
#else
FSRef ref;
FT_Error err;
err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
if ( FT_Err_Ok != err )
return err;
if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL,
pathSpec, NULL ) )
return FT_Err_Unknown_File_Format;
return FT_Err_Ok;
#endif
}
static OSErr
FT_FSPathMakeRes( const UInt8* pathname,
short* res )
{
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();
return err;
}
/* Return the file type for given pathname */
static OSType
get_file_type_from_path( const UInt8* pathname )
{
FSRef ref;
FSCatalogInfo info;
if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
return ( OSType ) 0;
if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info,
NULL, NULL, NULL ) )
return ( OSType ) 0;
return ((FInfo *)(info.finderInfo))->fdType;
}
/* Given a PostScript font name, create the Macintosh LWFN file name. */
static void
create_lwfn_name( char* ps_name,
Str255 lwfn_file_name )
{
int max = 5, count = 0;
FT_Byte* p = lwfn_file_name;
FT_Byte* q = (FT_Byte*)ps_name;
lwfn_file_name[0] = 0;
while ( *q )
{
if ( ft_isupper( *q ) )
{
if ( count )
max = 3;
count = 0;
}
if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
{
*++p = *q;
lwfn_file_name[0]++;
count++;
}
q++;
}
}
static short
count_faces_sfnt( char* fond_data )
{
/* The count is 1 greater than the value in the FOND. */
/* Isn't that cute? :-) */
return EndianS16_BtoN( *( (short*)( fond_data +
sizeof ( FamRec ) ) ) ) + 1;
}
static short
count_faces_scalable( char* fond_data )
{
AsscEntry* assoc;
FamRec* fond;
short i, face, face_all;
fond = (FamRec*)fond_data;
face_all = EndianS16_BtoN( *( (short *)( fond_data +
sizeof ( FamRec ) ) ) ) + 1;
assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
face = 0;
for ( i = 0; i < face_all; i++ )
{
if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) )
face++;
}
return face;
}
/* 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,
short* sfnt_id,
Str255 lwfn_file_name,
short face_index )
{
AsscEntry* assoc;
AsscEntry* base_assoc;
FamRec* fond;
*sfnt_id = 0;
*have_sfnt = 0;
lwfn_file_name[0] = 0;
fond = (FamRec*)fond_data;
assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -