📄 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 + -