📄 ftmac.c
字号:
/***************************************************************************/
/* */
/* ftmac.c */
/* */
/* Mac FOND support. Written by just@letterror.com. */
/* */
/* 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, */
/* 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: Although the FOND driver sets face->num_faces field to the
number of available fonts, but the Type 1 driver sets it to 1 anyway.
So this field is currently not reliable, and I don't see a clean way
to resolve that. The face_index argument translates to
Get1IndResource( 'FOND', face_index + 1 );
so clients should figure out the resource index of the FOND.
(I'll try to provide some example code for this at some point.)
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().
*/
#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. */
#define OS_INLINE static __inline__
#include <Carbon/Carbon.h>
#else
#include <Resources.h>
#include <Fonts.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
/* 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 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 !TARGET_API_MAC_OS8 && \
!( defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO )
OSErr e;
FSRef ref;
e = FSPathMakeRef( (UInt8 *)pathname, &ref, false /* not a directory */ );
if ( e == noErr )
e = FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, spec, NULL );
return ( e == noErr ) ? 0 : (-1);
#else
Str255 p_path;
FT_ULong path_len;
/* convert path to a pascal string */
path_len = ft_strlen( pathname );
if ( path_len > 255 )
return -1;
p_path[0] = (unsigned char)path_len;
ft_strncpy( (char*)p_path + 1, pathname, path_len );
if ( FSMakeFSSpec( 0, 0, p_path, spec ) != noErr )
return -1;
else
return 0;
#endif
}
/* Return the file type of the file specified by spec. */
static OSType
get_file_type( const FSSpec* spec )
{
FInfo finfo;
if ( FSpGetFInfo( spec, &finfo ) != noErr )
return 0; /* file might not exist */
return finfo.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++;
}
}
/* Given a file reference, answer its location as a vRefNum
and a dirID. */
static FT_Error
get_file_location( short ref_num,
short* v_ref_num,
long* dir_id,
unsigned char* file_name )
{
FCBPBRec pb;
OSErr error;
pb.ioNamePtr = file_name;
pb.ioVRefNum = 0;
pb.ioRefNum = ref_num;
pb.ioFCBIndx = 0;
error = PBGetFCBInfoSync( &pb );
if ( error == noErr )
{
*v_ref_num = pb.ioFCBVRefNum;
*dir_id = pb.ioFCBParID;
}
return error;
}
/* Make a file spec for an LWFN file from a FOND resource and
a file name. */
static FT_Error
make_lwfn_spec( Handle fond,
const unsigned char* file_name,
FSSpec* spec )
{
FT_Error error;
short ref_num, v_ref_num;
long dir_id;
Str255 fond_file_name;
ref_num = HomeResFile( fond );
error = ResError();
if ( !error )
error = get_file_location( ref_num, &v_ref_num,
&dir_id, fond_file_name );
if ( !error )
error = FSMakeFSSpec( v_ref_num, dir_id, file_name, spec );
return error;
}
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,
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 );
base_assoc = assoc;
/* Let's do a little range checking before we get too excited here */
if ( face_index < count_faces_sfnt( fond_data ) )
{
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 )
{
unsigned char* p = (unsigned char*)fond_data;
StyleTable* style;
unsigned short string_count;
char ps_name[256];
unsigned char* names[64];
int i;
p += fond->ffStylOff;
style = (StyleTable*)p;
p += sizeof ( StyleTable );
string_count = *(unsigned short*)(p);
p += sizeof ( short );
for ( i = 0 ; i < string_count && i < 64; i++ )
{
names[i] = p;
p += names[i][0];
p++;
}
{
size_t ps_name_len = (size_t)names[0][0];
if ( ps_name_len != 0 )
{
ft_memcpy(ps_name, names[0] + 1, ps_name_len);
ps_name[ps_name_len] = 0;
}
if ( style->indexes[0] > 1 )
{
unsigned char* suffixes = names[style->indexes[0] - 1];
for ( i = 1; i <= suffixes[0]; i++ )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -