📄 ftmac.c
字号:
} 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; 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;#else FSSpec spec; FInfo finfo; if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) ) return ( OSType ) 0; if ( noErr != FSpGetFInfo( &spec, &finfo ) ) return ( OSType ) 0; return finfo.fdType;#endif /* HAVE_FSREF */ } /* 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 ); 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 ( EndianS16_BtoN( assoc->fontSize ) == 0 ) { *have_sfnt = 1; *sfnt_id = EndianS16_BtoN( assoc->fontID ); } else if ( base_assoc->fontSize == 0 ) { *have_sfnt = 1; *sfnt_id = EndianS16_BtoN( base_assoc->fontID ); } } if ( EndianS32_BtoN( 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 += EndianS32_BtoN( fond->ffStylOff ); style = (StyleTable*)p; p += sizeof ( StyleTable ); string_count = EndianS16_BtoN( *(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++ ) { unsigned char* s; size_t j = suffixes[i] - 1; if ( j < string_count && ( s = names[j] ) != NULL ) { size_t s_len = (size_t)s[0]; if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) ) { ft_memcpy( ps_name + ps_name_len, s + 1, s_len ); ps_name_len += s_len; ps_name[ps_name_len] = 0; } } } } } create_lwfn_name( ps_name, lwfn_file_name ); } } static FT_Error lookup_lwfn_by_fond( const UInt8* path_fond, const StringPtr base_lwfn, UInt8* path_lwfn, int path_size ) {#if HAVE_FSREF FSRef ref, par_ref; int dirname_len; /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */ /* We should not extract parent directory by string manipulation. */ if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) ) return FT_Err_Invalid_Argument; if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, NULL, &par_ref ) ) return FT_Err_Invalid_Argument; if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) ) return FT_Err_Invalid_Argument; if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size ) return FT_Err_Invalid_Argument; /* now we have absolute dirname in lookup_path */ if ( path_lwfn[0] == '/' ) ft_strcat( (char *)path_lwfn, "/" ); else ft_strcat( (char *)path_lwfn, ":" ); dirname_len = ft_strlen( (char *)path_lwfn ); ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 ); path_lwfn[dirname_len + base_lwfn[0]] = '\0'; if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) ) return FT_Err_Cannot_Open_Resource; if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, NULL, NULL ) ) return FT_Err_Cannot_Open_Resource; return FT_Err_Ok;#else int i; FSSpec spec; /* pathname for FSSpec is always HFS format */ if ( ft_strlen( (char *)path_fond ) > path_size ) return FT_Err_Invalid_Argument; ft_strcpy( (char *)path_lwfn, (char *)path_fond ); i = ft_strlen( (char *)path_lwfn ) - 1; while ( i > 0 && ':' != path_lwfn[i] ) i--; if ( i + 1 + base_lwfn[0] > path_size ) return FT_Err_Invalid_Argument; if ( ':' == path_lwfn[i] ) { ft_strcpy( (char *)path_lwfn + i + 1, (char *)base_lwfn + 1 ); path_lwfn[i + 1 + base_lwfn[0]] = '\0'; } else { ft_strcpy( (char *)path_lwfn, (char *)base_lwfn + 1 ); path_lwfn[base_lwfn[0]] = '\0'; } if ( noErr != FT_FSPathMakeSpec( path_lwfn, &spec, FALSE ) ) return FT_Err_Cannot_Open_Resource; return FT_Err_Ok;#endif /* HAVE_FSREF */ } static short count_faces( Handle fond, const UInt8* pathname ) { short sfnt_id; short have_sfnt, have_lwfn; Str255 lwfn_file_name; UInt8 buff[HFS_MAXPATHLEN]; FT_Error err; short num_faces; have_sfnt = have_lwfn = 0; HLock( fond ); parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 ); if ( lwfn_file_name[0] ) { err = lookup_lwfn_by_fond( pathname, lwfn_file_name, buff, sizeof ( buff ) ); if ( FT_Err_Ok == err ) have_lwfn = 1; } if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) num_faces = 1; else num_faces = count_faces_scalable( *fond ); HUnlock( fond ); return num_faces; } /* 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 chunks are often not organized that way, so we glue chunks of the same type together. */ static FT_Error read_lwfn( FT_Memory memory, short res, FT_Byte** pfb_data, FT_ULong* size ) { FT_Error error = FT_Err_Ok; short res_id; unsigned char *buffer, *p, *size_p = NULL; FT_ULong total_size = 0; FT_ULong old_total_size = 0; FT_ULong post_size, pfb_chunk_size; Handle post_data; char code, last_code; UseResFile( res ); /* First pass: load all POST resources, and determine the size of */ /* the output buffer. */ res_id = 501; last_code = -1; for (;;) { post_data = Get1Resource( 'POST', res_id++ ); if ( post_data == NULL ) break; /* we are done */ code = (*post_data)[0]; if ( code != last_code ) { if ( code == 5 ) total_size += 2; /* just the end code */ else total_size += 6; /* code + 4 bytes chunk length */ } total_size += GetHandleSize( post_data ) - 2; last_code = code; /* detect integer overflows */ if ( total_size < old_total_size ) { error = FT_Err_Array_Too_Large; goto Error; } old_total_size = total_size; } 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. */ p = buffer; res_id = 501; last_code = -1; pfb_chunk_size = 0; for (;;) { post_data = Get1Resource( 'POST', res_id++ ); if ( post_data == NULL ) break; /* we are done */ post_size = (FT_ULong)GetHandleSize( post_data ) - 2; code = (*post_data)[0]; if ( code != last_code ) { if ( last_code != -1 ) { /* we are done adding a chunk, fill in the size field */ if ( size_p != NULL ) { *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF ); *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF ); *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF ); *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF ); } pfb_chunk_size = 0; } *p++ = 0x80; if ( code == 5 ) *p++ = 0x03; /* the end */ else if ( code == 2 ) *p++ = 0x02; /* binary segment */ else *p++ = 0x01; /* ASCII segment */ if ( code != 5 ) { size_p = p; /* save for later */ p += 4; /* make space for size field */ } } ft_memcpy( p, *post_data + 2, post_size ); pfb_chunk_size += post_size; p += post_size; last_code = code; } *pfb_data = buffer; *size = total_size; Error: CloseResFile( res ); return error; } /* Finalizer for a memory stream; gets called by FT_Done_Face(). It frees the memory it uses. */ static void memory_stream_close( FT_Stream stream ) { FT_Memory memory = stream->memory;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -