📄 t1load.c
字号:
/******************************************************************* * * t1load.h 2.0 * * Type1 Loader. * * Copyright 1996-2000 by * 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. * * * This is the new and improved Type 1 data loader for FreeType 2. * The old loader has several problems: it is slow, complex, difficult * to maintain, and contains incredible hacks to make it accept some * ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% * of the Type 1 fonts on my machine still aren't loaded correctly * by it. * * This version is much simpler, much faster and also easier to * read and maintain by a great order of magnitude. The idea behind * it is to _not_ try to read the Type 1 token stream with a state * machine (i.e. a Postscript-like interpreter) but rather to perform * simple pattern-matching. * * Indeed, nearly all data definitions follow a simple pattern * like : * * ..... /Field <data> .... * * where <data> can be a number, a boolean, a string, or an * array of numbers. There are a few exceptions, namely the * encoding, font name, charstrings and subrs and they are * handled with a special pattern-matching routine. * * All other common cases are handled very simply. The matching * rules are defined in the file "t1tokens.h" through the use * of several macros calls PARSE_XXXX * * This file is included twice here, the first time to generate * parsing callback functions, the second to generate a table * of keywords (with pointers to the associated callback). * * The function "parse_dict" simply scans *linearly* a given * dictionary (either the top-level or private one) and calls * the appropriate callback when it encounters an immediate * keyword. * * This is by far the fastest way one can find to parse and read * all data :-) * * This led to tremendous code size reduction. Note that later, * the glyph loader will also be _greatly_ simplified, and the * automatic hinter will replace the clumsy "t1hinter".. * ******************************************************************/#include <ftdebug.h>#include <ftconfig.h>#include <t1types.h>#include <t1errors.h>#include <t1load.h>#include <stdio.h>#undef FT_COMPONENT#define FT_COMPONENT trace_t1load typedef void (*T1_Parse_Func)( T1_Face face, T1_Loader* loader ); typedef struct T1_KeyWord_ { const char* name; T1_Parse_Func parsing; } T1_KeyWord; /* some handy macros used to easily define parsing callback functions */ /* each callback is in charge of loading a value and storing it in a */ /* given field of the Type 1 face.. */ #define PARSE_(x) static void parse_##x##( T1_Face face, T1_Loader* loader )#define PARSE_STRING(s,x) PARSE_(x) \ { \ FACE.##x = T1_ToString(&loader->parser); \ FT_TRACE2(( "type1.parse_##x##: \"%s\"\n", FACE.##x )); \ }#define PARSE_NUM(s,x,t) PARSE_(x) \ { \ FACE.##x = (t)T1_ToInt(&loader->parser); \ FT_TRACE2(( "type1.parse_##x##: \"%d\"\n", FACE.##x )); \ } #define PARSE_INT(s,x) PARSE_(x) \ { \ FACE.##x = T1_ToInt(&loader->parser); \ FT_TRACE2(( "type1.parse_##x##: \"%d\"\n", FACE.##x )); \ }#define PARSE_BOOL(s,x) PARSE_(x) \ { \ FACE.##x = T1_ToBool(&loader->parser); \ FT_TRACE2(( "type1.parse_##x##: \"%s\"\n", \ FACE.##x ? "true" : "false" )); \ } #define PARSE_FIXED(s,x) PARSE_(x) \ { \ FACE.##x = T1_ToFixed(&loader->parser,3); \ FT_TRACE2(( "type1.parse_##x##: \"%f\"\n", FACE.##x/65536.0 )); \ } #define PARSE_COORDS(s,c,m,x) PARSE_(x) \ { \ FACE.##c = T1_ToCoordArray(&loader->parser, m, (T1_Short*)FACE.##x ); \ FT_TRACE2(( "type1.parse_##x##\n" )); \ } #define PARSE_FIXEDS(s,c,m,x) PARSE_(x) \ { \ FACE.##c = T1_ToFixedArray(&loader->parser, m, (T1_Fixed*)FACE.##x, 3 ); \ FT_TRACE2(( "type1.parse_##x##\n" )); \ }#define PARSE_COORDS2(s,m,x) PARSE_(x) \ { \ (void)T1_ToCoordArray( &loader->parser, m, (T1_Short*)&FACE.##x ); \ FT_TRACE2(( "type1.parse_##x##\n" )); \ }#define PARSE_FIXEDS2(s,m,x) PARSE_(x) \ { \ (void)T1_ToFixedArray(&loader->parser, m, (T1_Fixed*)&FACE.##x, 3 ); \ FT_TRACE2(( "type1.parse_##x##\n" )); \ }/* define all parsing callbacks */#include <t1tokens.h> static int is_space( char c ) { return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ); } static int is_alpha( char c ) { return ( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '.') || (c == '_') ); } static void skip_whitespace( T1_Parser* parser ) { T1_Byte* cur = parser->cursor; while ( cur < parser->limit && is_space(*cur) ) cur++; parser->cursor = cur; } static void skip_blackspace( T1_Parser* parser ) { T1_Byte* cur = parser->cursor; while ( cur < parser->limit && !is_space(*cur) ) cur++; parser->cursor = cur; } static int read_binary_data( T1_Parser* parser, T1_Int *size, T1_Byte* *base ) { T1_Byte* cur; T1_Byte* limit = parser->limit; /* the binary data has the following format */ /* */ /* "size" [white*] RD white ....... ND */ /* */ skip_whitespace(parser); cur = parser->cursor; if ( cur < limit && (T1_Byte)(*cur-'0') < 10 ) { *size = T1_ToInt(parser); skip_whitespace(parser); skip_blackspace(parser); /* "RD" or "-|" or something else */ /* there is only one whitespace char after the */ /* "RD" or "-|" token */ *base = parser->cursor + 1; parser->cursor += *size+1; return 1; } FT_ERROR(( "type1.read_binary_data: invalid size field\n" )); parser->error = FT_Err_Invalid_File_Format; return 0; } /* we will now define the routines used to handle */ /* the /Encoding, /Subrs and /CharStrings */ /* dictionaries.. */ static void parse_font_name( T1_Face face, T1_Loader* loader ) { T1_Parser* parser = &loader->parser; FT_Error error; FT_Memory memory = parser->memory; T1_Int len; T1_Byte* cur; T1_Byte* cur2; T1_Byte* limit; skip_whitespace(parser); cur = parser->cursor; limit = parser->limit; if ( cur >= limit-1 || *cur != '/' ) return; cur++; cur2 = cur; while (cur2 < limit && is_alpha(*cur2)) cur2++; len = cur2-cur; if (len > 0) { if ( ALLOC( face->type1.font_name, len+1 ) ) { parser->error = error; return; } MEM_Copy( face->type1.font_name, cur, len ); face->type1.font_name[len] = '\0'; } parser->cursor = cur2; } static void parse_font_bbox( T1_Face face, T1_Loader* loader ) { T1_Parser* parser = &loader->parser; T1_Short temp[4]; T1_BBox* bbox = &face->type1.font_bbox; (void)T1_ToCoordArray( parser, 4, temp ); bbox->xMin = temp[0]; bbox->yMin = temp[1]; bbox->xMax = temp[2]; bbox->yMax = temp[3]; } static void parse_encoding( T1_Face face, T1_Loader* loader ) { T1_Parser* parser = &loader->parser; T1_Byte* cur = parser->cursor; T1_Byte* limit = parser->limit; /* skip whitespace */ while (is_space(*cur)) { cur++; if (cur >= limit) { FT_ERROR(( "type1.parse_encoding: out of bounds !!\n" )); parser->error = FT_Err_Invalid_File_Format; return; } } /* if we have a number, then the encoding is an array, */ /* and we must load it now */ if ((T1_Byte)(*cur - '0') < 10) { T1_Encoding* encode = &face->type1.encoding; T1_Int count, n; T1_Table* char_table = &loader->encoding_table; FT_Memory memory = parser->memory; FT_Error error; /* read the number of entries in the encoding, should be 256 */ count = T1_ToInt( parser ); if (parser->error) return; /* we use a T1_Table to store our charnames */ encode->num_chars = count; if ( ALLOC_ARRAY( encode->char_index, count, T1_Short ) || ALLOC_ARRAY( encode->char_name, count, T1_String* ) || (error = T1_New_Table( char_table, count, memory )) != 0 ) { parser->error = error; return; } /* 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->cursor; limit = parser->limit; n = 0; for ( ; cur < limit; ) { T1_Byte c; c = *cur; /* we stop when we encounter a 'def' */ if ( c == 'd' && cur+3 < limit ) { if ( cur[1] == 'e' && cur[2] == 'f' && is_space(cur[-1]) && is_space(cur[3]) ) { FT_TRACE6(( "encoding end\n" )); break; } } /* otherwise, we must find a number before anything else */ if ( (T1_Byte)(c-'0') < 10 ) { T1_Int charcode; parser->cursor = cur; charcode = T1_ToInt(parser); cur = parser->cursor; /* skip whitespace */ while (cur < limit && 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; T1_Int len; while (cur2 < limit && is_alpha(*cur2)) cur2++; len = cur2-cur-1; parser->error = T1_Add_Table( char_table, charcode, cur+1, len+1 ); char_table->elements[charcode][len] = '\0'; if (parser->error) return; cur = cur2; } } else cur++; } face->type1.encoding_type = t1_encoding_array; parser->cursor = cur; } /* Otherwise, we should have either "StandardEncoding" or */ /* "ExpertEncoding" */ else { if ( cur+17 < limit && strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -