📄 t42parse.c
字号:
/***************************************************************************//* *//* t42parse.c *//* *//* Type 42 font parser (body). *//* *//* Copyright 2002, 2003 by Roberto Alameda. *//* *//* 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. *//* *//***************************************************************************/#include "t42parse.h"#include "t42error.h"#include FT_INTERNAL_DEBUG_H#include FT_INTERNAL_STREAM_H#include FT_LIST_H#include FT_INTERNAL_POSTSCRIPT_AUX_H /*************************************************************************/ /* */ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ /* messages during execution. */ /* */#undef FT_COMPONENT#define FT_COMPONENT trace_t42 static void t42_parse_font_matrix( T42_Face face, T42_Loader loader ); static void t42_parse_encoding( T42_Face face, T42_Loader loader ); static void t42_parse_charstrings( T42_Face face, T42_Loader loader ); static void t42_parse_sfnts( T42_Face face, T42_Loader loader ); static const T1_FieldRec t42_keywords[] = {#undef FT_STRUCTURE#define FT_STRUCTURE T1_FontInfo#undef T1CODE#define T1CODE T1_FIELD_LOCATION_FONT_INFO T1_FIELD_STRING( "version", version ) T1_FIELD_STRING( "Notice", notice ) T1_FIELD_STRING( "FullName", full_name ) T1_FIELD_STRING( "FamilyName", family_name ) T1_FIELD_STRING( "Weight", weight ) T1_FIELD_NUM ( "ItalicAngle", italic_angle ) T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch ) T1_FIELD_NUM ( "UnderlinePosition", underline_position ) T1_FIELD_NUM ( "UnderlineThickness", underline_thickness )#undef FT_STRUCTURE#define FT_STRUCTURE T1_FontRec#undef T1CODE#define T1CODE T1_FIELD_LOCATION_FONT_DICT T1_FIELD_KEY ( "FontName", font_name ) T1_FIELD_NUM ( "PaintType", paint_type ) T1_FIELD_NUM ( "FontType", font_type ) T1_FIELD_FIXED( "StrokeWidth", stroke_width )#undef FT_STRUCTURE#define FT_STRUCTURE FT_BBox#undef T1CODE#define T1CODE T1_FIELD_LOCATION_BBOX T1_FIELD_BBOX("FontBBox", xMin ) T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix ) T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding ) T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings ) T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts ) { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 } };#define T42_KEYWORD_COUNT \ ( sizeof ( t42_keywords ) / sizeof ( t42_keywords[0] ) )#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )#define T1_Done_Table( p ) \ do \ { \ if ( (p)->funcs.done ) \ (p)->funcs.done( p ); \ } while ( 0 )#define T1_Release_Table( p ) \ do \ { \ if ( (p)->funcs.release ) \ (p)->funcs.release( p ); \ } while ( 0 )#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )#define T1_Skip_Alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root )#define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root )#define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t )#define T1_ToCoordArray( p, m, c ) \ (p)->root.funcs.to_coord_array( &(p)->root, m, c )#define T1_ToFixedArray( p, m, f, t ) \ (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )#define T1_ToToken( p, t ) \ (p)->root.funcs.to_token( &(p)->root, t )#define T1_ToTokenArray( p, t, m, c ) \ (p)->root.funcs.to_token_array( &(p)->root, t, m, c )#define T1_Load_Field( p, f, o, m, pf ) \ (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )#define T1_Load_Field_Table( p, f, o, m, pf ) \ (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) /********************* Parsing Functions ******************/ FT_LOCAL_DEF( FT_Error ) t42_parser_init( T42_Parser parser, FT_Stream stream, FT_Memory memory, PSAux_Service psaux ) { FT_Error error = T42_Err_Ok; FT_Long size; psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); parser->stream = stream; parser->base_len = 0; parser->base_dict = 0; parser->in_memory = 0; /*******************************************************************/ /* */ /* Here a short summary of what is going on: */ /* */ /* When creating a new Type 42 parser, we try to locate and load */ /* the base dictionary, loading the whole font into memory. */ /* */ /* When `loading' the base dictionary, we only setup pointers in */ /* the case of a memory-based stream. Otherwise, we allocate */ /* and load the base dictionary in it. */ /* */ /* parser->in_memory is set if we have a memory stream. */ /* */ if ( FT_STREAM_SEEK( 0L ) ) goto Exit; size = stream->size; /* now, try to load `size' bytes of the `base' dictionary we */ /* found previously */ /* if it is a memory-based resource, set up pointers */ if ( !stream->read ) { parser->base_dict = (FT_Byte*)stream->base + stream->pos; parser->base_len = size; parser->in_memory = 1; /* check that the `size' field is valid */ if ( FT_STREAM_SKIP( size ) ) goto Exit; } else { /* read segment in memory */ if ( FT_ALLOC( parser->base_dict, size ) || FT_STREAM_READ( parser->base_dict, size ) ) goto Exit; parser->base_len = size; } /* Now check font format; we must see `%!PS-TrueTypeFont' */ if (size <= 17 || ( ft_strncmp( (const char*)parser->base_dict, "%!PS-TrueTypeFont", 17) ) ) error = T42_Err_Unknown_File_Format; else { parser->root.base = parser->base_dict; parser->root.cursor = parser->base_dict; parser->root.limit = parser->root.cursor + parser->base_len; } Exit: if ( error && !parser->in_memory ) FT_FREE( parser->base_dict ); return error; } FT_LOCAL_DEF( void ) t42_parser_done( T42_Parser parser ) { FT_Memory memory = parser->root.memory; /* free the base dictionary only when we have a disk stream */ if ( !parser->in_memory ) FT_FREE( parser->base_dict ); parser->root.funcs.done( &parser->root ); } static int t42_is_alpha( FT_Byte c ) { /* Note: we must accept "+" as a valid character, as it is used in */ /* embedded type1 fonts in PDF documents. */ /* */ return ( ft_isalnum( c ) || c == '.' || c == '_' || c == '-' || c == '+' ); } static int t42_is_space( FT_Byte c ) { return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ); } static void t42_parse_font_matrix( T42_Face face, T42_Loader loader ) { T42_Parser parser = &loader->parser; FT_Matrix* matrix = &face->type1.font_matrix; FT_Vector* offset = &face->type1.font_offset; FT_Face root = (FT_Face)&face->root; FT_Fixed temp[6]; FT_Fixed temp_scale; (void)T1_ToFixedArray( parser, 6, temp, 3 ); temp_scale = ABS( temp[3] ); /* Set Units per EM based on FontMatrix values. We set the value to */ /* 1000 / temp_scale, because temp_scale was already multiplied by */ /* 1000 (in t1_tofixed, from psobjs.c). */ root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, temp_scale ) >> 16 ); /* we need to scale the values by 1.0/temp_scale */ if ( temp_scale != 0x10000L ) { temp[0] = FT_DivFix( temp[0], temp_scale ); temp[1] = FT_DivFix( temp[1], temp_scale ); temp[2] = FT_DivFix( temp[2], temp_scale ); temp[4] = FT_DivFix( temp[4], temp_scale ); temp[5] = FT_DivFix( temp[5], temp_scale ); temp[3] = 0x10000L; } matrix->xx = temp[0]; matrix->yx = temp[1]; matrix->xy = temp[2]; matrix->yy = temp[3]; /* note that the offsets must be expressed in integer font units */ offset->x = temp[4] >> 16; offset->y = temp[5] >> 16; } static void t42_parse_encoding( T42_Face face, T42_Loader loader ) { T42_Parser parser = &loader->parser; FT_Byte* cur = parser->root.cursor; FT_Byte* limit = parser->root.limit; PSAux_Service psaux = (PSAux_Service)face->psaux; /* skip whitespace */ while ( t42_is_space( *cur ) ) { cur++; if ( cur >= limit ) { FT_ERROR(( "t42_parse_encoding: out of bounds!\n" )); parser->root.error = T42_Err_Invalid_File_Format; return; } } /* if we have a number, then the encoding is an array, */ /* and we must load it now */ if ( (FT_Byte)( *cur - '0' ) < 10 ) { T1_Encoding encode = &face->type1.encoding; FT_Int count, n; PS_Table char_table = &loader->encoding_table; FT_Memory memory = parser->root.memory; FT_Error error; /* read the number of entries in the encoding, should be 256 */ count = (FT_Int)T1_ToInt( parser ); if ( parser->root.error ) return; /* we use a T1_Table to store our charnames */ loader->num_chars = encode->num_chars = count; if ( FT_NEW_ARRAY( encode->char_index, count ) || FT_NEW_ARRAY( encode->char_name, count ) || FT_SET_ERROR( psaux->ps_table_funcs->init( char_table, count, memory ) ) ) { parser->root.error = error; return; } /* We need to `zero' out encoding_table.elements */ for ( n = 0; n < count; n++ ) { char* notdef = (char *)".notdef"; T1_Add_Table( char_table, n, notdef, 8 ); } /* Now, we will need to read a record of the form */ /* ... charcode /charname ... for each entry in our table */ /* */ /* We simply look for a number followed by an immediate */ /* name. Note that this ignores correctly the sequence */ /* that is often seen in type1 fonts: */ /* */ /* 0 1 255 { 1 index exch /.notdef put } for dup */ /* */ /* used to clean the encoding array before anything else. */ /* */ /* We stop when we encounter a `def'. */ cur = parser->root.cursor; limit = parser->root.limit; n = 0; for ( ; cur < limit; ) { FT_Byte c; c = *cur; /* we stop when we encounter a `def' */ if ( c == 'd' && cur + 3 < limit ) { if ( cur[1] == 'e' && cur[2] == 'f' && t42_is_space( cur[-1] ) && t42_is_space( cur[3] ) ) { FT_TRACE6(( "encoding end\n" )); break; } } /* otherwise, we must find a number before anything else */ if ( (FT_Byte)( c - '0' ) < 10 ) { FT_Int charcode; parser->root.cursor = cur; charcode = (FT_Int)T1_ToInt( parser ); cur = parser->root.cursor; /* skip whitespace */ while ( cur < limit && t42_is_space( *cur ) ) cur++; if ( cur < limit && *cur == '/' ) { /* bingo, we have an immediate name -- it must be a */ /* character name */ FT_Byte* cur2 = cur + 1; FT_Int len; while ( cur2 < limit && t42_is_alpha( *cur2 ) ) cur2++; len = (FT_Int)( cur2 - cur - 1 ); parser->root.error = T1_Add_Table( char_table, charcode, cur + 1, len + 1 ); char_table->elements[charcode][len] = '\0'; if ( parser->root.error ) return; cur = cur2; } } else cur++; } face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; parser->root.cursor = cur; } /* Otherwise, we should have either `StandardEncoding', */ /* `ExpertEncoding', or `ISOLatin1Encoding' */ else { if ( cur + 17 < limit && ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; else if ( cur + 15 < limit && ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; else if ( cur + 18 < limit && ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; else { FT_ERROR(( "t42_parse_encoding: invalid token!\n" )); parser->root.error = T42_Err_Invalid_File_Format; } } } static FT_UInt t42_hexval( FT_Byte v ) { FT_UInt d; d = (FT_UInt)( v - 'A' ); if ( d < 6 ) { d += 10; goto Exit; } d = (FT_UInt)( v - 'a' ); if ( d < 6 ) { d += 10; goto Exit; } d = (FT_UInt)( v - '0' ); if ( d < 10 ) goto Exit;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -