From 9f95babf3e1be13c2f7ecda60938698b7e2da7f6 Mon Sep 17 00:00:00 2001 From: David Turner Date: Fri, 7 Jun 2002 07:23:06 +0000 Subject: [PATCH] * src/type42/t42drivr.c, src/type42/t42drivr.h, src/type42/t42parse.c, src/type42/t42parse.h, src/type42/t42objs.h, src/type42/t42objs.c, src/type42/type42.c: updated the Type42 driver by splitting it into several files since it makes the code easier to read and maintain. Also fixed the bug that prevented the correct display of fonts with "ftview" --- ChangeLog | 10 + src/type42/Jamfile | 4 +- src/type42/descrip.mms | 2 +- src/type42/rules.mk | 8 +- src/type42/t42drivr.c | 1973 +--------------------------------------- src/type42/t42drivr.h | 38 + src/type42/t42objs.c | 881 ++++++++++++++++++ src/type42/t42objs.h | 130 +++ src/type42/t42parse.c | 1083 ++++++++++++++++++++++ src/type42/t42parse.h | 66 ++ src/type42/type42.c | 17 + 11 files changed, 2250 insertions(+), 1962 deletions(-) create mode 100644 src/type42/t42drivr.h create mode 100644 src/type42/t42objs.c create mode 100644 src/type42/t42objs.h create mode 100644 src/type42/t42parse.c create mode 100644 src/type42/t42parse.h create mode 100644 src/type42/type42.c diff --git a/ChangeLog b/ChangeLog index db3dc9fac..6c8ed0d2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2002-06-07 David Turner + + * src/type42/t42drivr.c, src/type42/t42drivr.h, src/type42/t42parse.c, + src/type42/t42parse.h, src/type42/t42objs.h, src/type42/t42objs.c, + src/type42/type42.c: + + updated the Type42 driver by splitting it into several files since + it makes the code easier to read and maintain. Also fixed the bug + that prevented the correct display of fonts with "ftview" + 2002-06-03 Werner Lemberg Add 8bpp support. diff --git a/src/type42/Jamfile b/src/type42/Jamfile index 1832955fc..e133e6d86 100644 --- a/src/type42/Jamfile +++ b/src/type42/Jamfile @@ -10,11 +10,11 @@ SubDirHdrs [ FT2_SubDir src type42 ] ; if $(FT2_MULTI) { - _sources = t42drivr ; + _sources = t42objs t42parse t42drivr ; } else { - _sources = t42drivr ; + _sources = type42 ; } Library $(FT2_LIB) : $(_sources).c ; diff --git a/src/type42/descrip.mms b/src/type42/descrip.mms index ec75d3bc7..a52ba06fb 100644 --- a/src/type42/descrip.mms +++ b/src/type42/descrip.mms @@ -15,7 +15,7 @@ CFLAGS=$(COMP_FLAGS)$(DEBUG)/include=([--.include],[--.src.type42]) -OBJS=t42drivr.obj +OBJS=type42.obj all : $(OBJS) library [--.lib]freetype.olb $(OBJS) diff --git a/src/type42/rules.mk b/src/type42/rules.mk index a55f42e3a..3e8ea9d78 100644 --- a/src/type42/rules.mk +++ b/src/type42/rules.mk @@ -26,11 +26,13 @@ T42_COMPILE := $(FT_COMPILE) $I$(T42_DIR) # Type42 driver source # -T42_DRV_SRC := $(T42_DIR_)t42drivr.c +T42_DRV_SRC := $(T42_DIR_)t42objs.c \ + $(T42_DIR_)t42parse.c \ + $(T42_DIR_)t42drivr.c # Type42 driver headers # -T42_DRV_H := +T42_DRV_H := $(T42_DRV_SRC:%.c=%.h) # Type42 driver object(s) @@ -39,7 +41,7 @@ T42_DRV_H := # T42_DRV_OBJ_S is used during `single' builds # T42_DRV_OBJ_M := $(T42_DRV_SRC:$(T42_DIR_)%.c=$(OBJ_)%.$O) -T42_DRV_OBJ_S := $(OBJ_)t42drivr.$O +T42_DRV_OBJ_S := $(OBJ_)type42.$O # Type42 driver source file for single build # diff --git a/src/type42/t42drivr.c b/src/type42/t42drivr.c index c062b0bc6..398367767 100644 --- a/src/type42/t42drivr.c +++ b/src/type42/t42drivr.c @@ -1,1948 +1,10 @@ -/***************************************************************************/ -/* */ -/* t42drivr.c */ -/* */ -/* FreeType font driver for Type 42 fonts (body only). */ -/* */ -/* Copyright 2002 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 -#define FT_ERR_PREFIX T42_Err_ -#define FT_ERR_BASE FT_Mod_Err_Type42 - -#include FT_CONFIG_STANDARD_LIBRARY_H - +#include "t42drivr.h" +#include "t42objs.h" #include FT_INTERNAL_DEBUG_H -#include FT_CONFIG_CONFIG_H -#include FT_ERRORS_H -#include FT_FREETYPE_H -#include FT_TYPE1_TABLES_H -#include FT_LIST_H - -#include FT_INTERNAL_DRIVER_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_TYPE1_TYPES_H -#include FT_INTERNAL_TYPE42_TYPES_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_INTERNAL_STREAM_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 - - /********************* Data Definitions ******************/ - - typedef struct T42_DriverRec_ - { - FT_DriverRec root; - FT_Driver_Class ttclazz; - void* extension_component; - - } T42_DriverRec, *T42_Driver; - - - typedef struct T42_SizeRec_ - { - FT_SizeRec root; - FT_Size ttsize; - - } T42_SizeRec, *T42_Size; - - - typedef struct T42_GlyphSlotRec_ - { - FT_GlyphSlotRec root; - FT_GlyphSlot ttslot; - - } T42_GlyphSlotRec, *T42_GlyphSlot; - - - /*********** Parser definitions *************/ - - typedef struct T42_ParserRec_ - { - PS_ParserRec root; - FT_Stream stream; - - FT_Byte* base_dict; - FT_Int base_len; - - FT_Byte in_memory; - - } T42_ParserRec, *T42_Parser; - - - typedef struct T42_Loader_ - { - T42_ParserRec parser; /* parser used to read the stream */ - - FT_Int num_chars; /* number of characters in encoding */ - PS_TableRec encoding_table; /* PS_Table used to store the */ - /* encoding character names */ - - FT_Int num_glyphs; - PS_TableRec glyph_names; - PS_TableRec charstrings; - - } T42_LoaderRec, *T42_Loader; - - - /*********************** Prototypes *********************/ - - static void - parse_font_name( T42_Face face, - T42_Loader loader ); - static void - parse_font_bbox( T42_Face face, - T42_Loader loader ); - static void - parse_font_matrix( T42_Face face, - T42_Loader loader ); - static void - parse_encoding( T42_Face face, - T42_Loader loader ); - static void - parse_charstrings( T42_Face face, - T42_Loader loader ); - static void - 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_TYPE_BOOL( "isFixedPitch", is_fixed_pitch ) - T1_FIELD_NUM ( "UnderlinePosition", underline_position ) - T1_FIELD_NUM ( "UnderlineThickness", underline_thickness ) - -#undef FT_STRUCTURE -#define FT_STRUCTURE T42_FontRec -#undef T1CODE -#define T1CODE T1_FIELD_LOCATION_FONT_DICT - - T1_FIELD_NUM( "PaintType", paint_type ) - T1_FIELD_NUM( "FontType", font_type ) - T1_FIELD_NUM( "StrokeWidth", stroke_width ) - - T1_FIELD_CALLBACK( "FontName", parse_font_name ) - T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox ) - T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix ) - T1_FIELD_CALLBACK( "Encoding", parse_encoding ) - T1_FIELD_CALLBACK( "CharStrings", parse_charstrings ) - T1_FIELD_CALLBACK( "sfnts", parse_sfnts ) - - { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 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 ******************/ - - static FT_Error - T42_New_Parser( 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; - } - - - static void - T42_Finalize_Parser( 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 - 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 - is_space( FT_Byte c ) - { - return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ); - } - - - static void - parse_font_name( T42_Face face, - T42_Loader loader ) - { - T42_Parser parser = &loader->parser; - FT_Error error; - FT_Memory memory = parser->root.memory; - FT_Int len; - FT_Byte* cur; - FT_Byte* cur2; - FT_Byte* limit; - - - T1_Skip_Spaces( parser ); - - cur = parser->root.cursor; - limit = parser->root.limit; - - if ( cur >= limit - 1 || - ( *cur != '/' && *cur != '(') ) - return; - - cur++; - cur2 = cur; - while ( cur2 < limit && is_alpha( *cur2 ) ) - cur2++; - - len = (FT_Int)( cur2 - cur ); - if ( len > 0 ) - { - if ( FT_ALLOC( face->type42.font_name, len + 1 ) ) - { - parser->root.error = error; - return; - } - - FT_MEM_COPY( face->type42.font_name, cur, len ); - face->type42.font_name[len] = '\0'; - } - parser->root.cursor = cur2; - } - - - static void - parse_font_bbox( T42_Face face, - T42_Loader loader ) - { - T42_Parser parser = &loader->parser; - FT_BBox* bbox = &face->type42.font_bbox; - - bbox->xMin = T1_ToInt( parser ); - bbox->yMin = T1_ToInt( parser ); - bbox->xMax = T1_ToInt( parser ); - bbox->yMax = T1_ToInt( parser ); - } - - - static void - parse_font_matrix( T42_Face face, - T42_Loader loader ) - { - T42_Parser parser = &loader->parser; - FT_Matrix* matrix = &face->type42.font_matrix; - FT_Vector* offset = &face->type42.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 - 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 ( is_space( *cur ) ) - { - cur++; - if ( cur >= limit ) - { - FT_ERROR(( "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->type42.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 = 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' && - is_space( cur[-1] ) && - 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 = T1_ToInt( parser ); - cur = parser->root.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; - FT_Int len; - - - while ( cur2 < limit && 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->type42.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->type42.encoding_type = T1_ENCODING_TYPE_STANDARD; - - else if ( cur + 15 < limit && - ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) - face->type42.encoding_type = T1_ENCODING_TYPE_EXPERT; - - else if ( cur + 18 < limit && - ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) - face->type42.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; - - else { - FT_ERROR(( "parse_encoding: invalid token!\n" )); - parser->root.error = T42_Err_Invalid_File_Format; - } - } - } - - - static FT_UInt - 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; - - d = 0; - - Exit: - return d; - } - - - static void - parse_sfnts( T42_Face face, - T42_Loader loader ) - { - T42_Parser parser = &loader->parser; - FT_Memory memory = parser->root.memory; - FT_Byte* cur = parser->root.cursor; - FT_Byte* limit = parser->root.limit; - FT_Error error; - FT_Int num_tables = 0, status; - FT_ULong count, ttf_size = 0, string_size = 0; - FT_Bool in_string = 0; - FT_Byte v = 0; - - - /* The format is `/sfnts [ <...> <...> ... ] def' */ - - while ( is_space( *cur ) ) - cur++; - - if (*cur++ == '[') - { - status = 0; - count = 0; - } - else - { - FT_ERROR(( "parse_sfnts: can't find begin of sfnts vector!\n" )); - error = T42_Err_Invalid_File_Format; - goto Fail; - } - - while ( cur < limit - 2 ) - { - while ( is_space( *cur ) ) - cur++; - - switch ( *cur ) - { - case ']': - parser->root.cursor = cur++; - return; - - case '<': - in_string = 1; - string_size = 0; - cur++; - continue; - - case '>': - if ( !in_string ) - { - FT_ERROR(( "parse_sfnts: found unpaired `>'!\n" )); - error = T42_Err_Invalid_File_Format; - goto Fail; - } - - /* A string can have, as a last byte, */ - /* a zero byte for padding. If so, ignore it */ - if ( ( v == 0 ) && ( string_size % 2 == 1 ) ) - count--; - in_string = 0; - cur++; - continue; - - case '%': - if ( !in_string ) - { - /* Comment found; skip till end of line */ - while ( *cur != '\n' ) - cur++; - continue; - } - else - { - FT_ERROR(( "parse_sfnts: found `%' in string!\n" )); - error = T42_Err_Invalid_File_Format; - goto Fail; - } - - default: - if ( !ft_xdigit( *cur ) || !ft_xdigit( *(cur + 1) ) ) - { - FT_ERROR(( "parse_sfnts: found non-hex characters in string" )); - error = T42_Err_Invalid_File_Format; - goto Fail; - } - - v = (FT_Byte)( 16 * hexval( *cur++ ) + hexval( *cur++ ) ); - string_size++; - } - - switch ( status ) - { - case 0: /* The '[' was read, so load offset table, 12 bytes */ - if ( count < 12 ) - { - face->ttf_data[count++] = v; - continue; - } - else - { - num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; - status = 1; - ttf_size = 12 + 16 * num_tables; - - if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) ) - goto Fail; - } - /* No break, fall-through */ - - case 1: /* The offset table is read; read now the table directory */ - if ( count < ttf_size ) - { - face->ttf_data[count++] = v; - continue; - } - else - { - int i; - FT_ULong len; - - - for ( i = 0; i < num_tables; i++ ) - { - len = face->ttf_data[12 + 16*i + 12 + 0] << 24; - len += face->ttf_data[12 + 16*i + 12 + 1] << 16; - len += face->ttf_data[12 + 16*i + 12 + 2] << 8; - len += face->ttf_data[12 + 16*i + 12 + 3]; - - /* Pad to a 4-byte boundary length */ - ttf_size += ( len + 3 ) & ~3; - } - - status = 2; - face->ttf_size = ttf_size; - - if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, - ttf_size + 1 ) ) - goto Fail; - } - /* No break, fall-through */ - - case 2: /* We are reading normal tables; just swallow them */ - face->ttf_data[count++] = v; - - } - } - - /* If control reaches this point, the format was not valid */ - error = T42_Err_Invalid_File_Format; - - Fail: - parser->root.error = error; - } - - - static void - parse_charstrings( T42_Face face, - T42_Loader loader ) - { - T42_Parser parser = &loader->parser; - PS_Table code_table = &loader->charstrings; - PS_Table name_table = &loader->glyph_names; - FT_Memory memory = parser->root.memory; - FT_Error error; - - PSAux_Service psaux = (PSAux_Service)face->psaux; - - FT_Byte* cur; - FT_Byte* limit = parser->root.limit; - FT_Int n; - - - loader->num_glyphs = T1_ToInt( parser ); - if ( parser->root.error ) - return; - - /* initialize tables */ - - error = psaux->ps_table_funcs->init( code_table, - loader->num_glyphs, - memory ); - if ( error ) - goto Fail; - - error = psaux->ps_table_funcs->init( name_table, - loader->num_glyphs, - memory ); - if ( error ) - goto Fail; - - n = 0; - - for (;;) - { - /* the format is simple: */ - /* `/glyphname' + index + def */ - /* */ - /* note that we stop when we find an `end' */ - /* */ - T1_Skip_Spaces( parser ); - - cur = parser->root.cursor; - if ( cur >= limit ) - break; - - /* we stop when we find an `end' keyword */ - if ( *cur == 'e' && - cur + 3 < limit && - cur[1] == 'n' && - cur[2] == 'd' ) - break; - - if ( *cur != '/' ) - T1_Skip_Alpha( parser ); - else - { - FT_Byte* cur2 = cur + 1; - FT_Int len; - - - while ( cur2 < limit && is_alpha( *cur2 ) ) - cur2++; - len = (FT_Int)( cur2 - cur - 1 ); - - error = T1_Add_Table( name_table, n, cur + 1, len + 1 ); - if ( error ) - goto Fail; - - /* add a trailing zero to the name table */ - name_table->elements[n][len] = '\0'; - - parser->root.cursor = cur2; - T1_Skip_Spaces( parser ); - - cur2 = cur = parser->root.cursor; - if ( cur >= limit ) - break; - - while ( cur2 < limit && is_alpha( *cur2 ) ) - cur2++; - len = (FT_Int)( cur2 - cur ); - - error = T1_Add_Table( code_table, n, cur, len + 1 ); - if ( error ) - goto Fail; - - code_table->elements[n][len] = '\0'; - - n++; - if ( n >= loader->num_glyphs ) - break; - } - } - - /* Index 0 must be a .notdef element */ - if ( ft_strcmp( (char *)name_table->elements[0], ".notdef" ) ) - { - FT_ERROR(( "parse_charstrings: Index 0 is not `.notdef'!\n" )); - error = T42_Err_Invalid_File_Format; - goto Fail; - } - - loader->num_glyphs = n; - return; - - Fail: - parser->root.error = error; - } - - - static FT_Error - t42_load_keyword( T42_Face face, - T42_Loader loader, - T1_Field field ) - { - FT_Error error; - void* dummy_object; - void** objects; - FT_UInt max_objects = 0; - - - /* if the keyword has a dedicated callback, call it */ - if ( field->type == T1_FIELD_TYPE_CALLBACK ) { - field->reader( (FT_Face)face, loader ); - error = loader->parser.root.error; - goto Exit; - } - - /* now, the keyword is either a simple field, or a table of fields; */ - /* we are now going to take care of it */ - switch ( field->location ) - { - case T1_FIELD_LOCATION_FONT_INFO: - dummy_object = &face->type42.font_info; - objects = &dummy_object; - break; - - default: - dummy_object = &face->type42; - objects = &dummy_object; - } - - if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || - field->type == T1_FIELD_TYPE_FIXED_ARRAY ) - error = T1_Load_Field_Table( &loader->parser, field, - objects, max_objects, 0 ); - else - error = T1_Load_Field( &loader->parser, field, - objects, max_objects, 0 ); - - Exit: - return error; - } - - - static FT_Error - parse_dict( T42_Face face, - T42_Loader loader, - FT_Byte* base, - FT_Long size ) - { - T42_Parser parser = &loader->parser; - FT_Byte* cur = base; - FT_Byte* limit = cur + size; - FT_UInt n_keywords = sizeof ( t42_keywords ) / - sizeof ( t42_keywords[0] ); - - - parser->root.cursor = base; - parser->root.limit = base + size; - parser->root.error = 0; - - for ( ; cur < limit; cur++ ) - { - /* look for `FontDirectory', which causes problems on some fonts */ - if ( *cur == 'F' && cur + 25 < limit && - ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) - { - FT_Byte* cur2; - - - /* skip the `FontDirectory' keyword */ - cur += 13; - cur2 = cur; - - /* lookup the `known' keyword */ - while ( cur < limit && *cur != 'k' && - ft_strncmp( (char*)cur, "known", 5 ) ) - cur++; - - if ( cur < limit ) - { - T1_TokenRec token; - - - /* skip the `known' keyword and the token following it */ - cur += 5; - loader->parser.root.cursor = cur; - T1_ToToken( &loader->parser, &token ); - - /* if the last token was an array, skip it! */ - if ( token.type == T1_TOKEN_TYPE_ARRAY ) - cur2 = parser->root.cursor; - } - cur = cur2; - } - /* look for immediates */ - else if ( *cur == '/' && cur + 2 < limit ) - { - FT_Byte* cur2; - FT_UInt i, len; - - - cur++; - cur2 = cur; - while ( cur2 < limit && is_alpha( *cur2 ) ) - cur2++; - - len = (FT_UInt)( cur2 - cur ); - if ( len > 0 && len < 22 ) /* XXX What shall it this 22? */ - { - /* now, compare the immediate name to the keyword table */ - - /* Loop through all known keywords */ - for ( i = 0; i < n_keywords; i++ ) - { - T1_Field keyword = (T1_Field)&t42_keywords[i]; - FT_Byte *name = (FT_Byte*)keyword->ident; - - - if ( !name ) - continue; - - if ( ( len == ft_strlen( (const char *)name ) ) && - ( ft_memcmp( cur, name, len ) == 0 ) ) - { - /* we found it -- run the parsing callback! */ - parser->root.cursor = cur2; - T1_Skip_Spaces( parser ); - parser->root.error = t42_load_keyword(face, - loader, - keyword ); - if ( parser->root.error ) - return parser->root.error; - cur = parser->root.cursor; - break; - } - } - } - } - } - return parser->root.error; - } - - - static void - t42_init_loader( T42_Loader loader, - T42_Face face ) - { - FT_UNUSED( face ); - - FT_MEM_SET( loader, 0, sizeof ( *loader ) ); - loader->num_glyphs = 0; - loader->num_chars = 0; - - /* initialize the tables -- simply set their `init' field to 0 */ - loader->encoding_table.init = 0; - loader->charstrings.init = 0; - loader->glyph_names.init = 0; - } - - - static void - t42_done_loader( T42_Loader loader ) - { - T42_Parser parser = &loader->parser; - - - /* finalize tables */ - T1_Release_Table( &loader->encoding_table ); - T1_Release_Table( &loader->charstrings ); - T1_Release_Table( &loader->glyph_names ); - - /* finalize parser */ - T42_Finalize_Parser( parser ); - } - - - static FT_Error - T42_Open_Face( T42_Face face ) - { - T42_LoaderRec loader; - T42_Parser parser; - T42_Font type42 = &face->type42; - FT_Memory memory = face->root.memory; - FT_Error error; - - PSAux_Service psaux = (PSAux_Service)face->psaux; - - - t42_init_loader( &loader, face ); - - parser = &loader.parser; - - if ( FT_ALLOC( face->ttf_data, 12 ) ) - goto Exit; - - error = T42_New_Parser( parser, - face->root.stream, - memory, - psaux); - if ( error ) - goto Exit; - - error = parse_dict( face, &loader, parser->base_dict, parser->base_len ); - - if ( type42->font_type != 42 ) - { - error = T42_Err_Unknown_File_Format; - goto Exit; - } - - /* now, propagate the charstrings and glyphnames tables */ - /* to the Type42 data */ - type42->num_glyphs = loader.num_glyphs; - - if ( !loader.charstrings.init ) { - FT_ERROR(( "T42_Open_Face: no charstrings array in face!\n" )); - error = T42_Err_Invalid_File_Format; - } - - loader.charstrings.init = 0; - type42->charstrings_block = loader.charstrings.block; - type42->charstrings = loader.charstrings.elements; - type42->charstrings_len = loader.charstrings.lengths; - - /* we copy the glyph names `block' and `elements' fields; */ - /* the `lengths' field must be released later */ - type42->glyph_names_block = loader.glyph_names.block; - type42->glyph_names = (FT_String**)loader.glyph_names.elements; - loader.glyph_names.block = 0; - loader.glyph_names.elements = 0; - - /* we must now build type42.encoding when we have a custom array */ - if ( type42->encoding_type == T1_ENCODING_TYPE_ARRAY ) - { - FT_Int charcode, idx, min_char, max_char; - FT_Byte* char_name; - FT_Byte* glyph_name; - - - /* OK, we do the following: for each element in the encoding */ - /* table, look up the index of the glyph having the same name */ - /* as defined in the CharStrings array. */ - /* The index is then stored in type42.encoding.char_index, and */ - /* the name in type42.encoding.char_name */ - - min_char = +32000; - max_char = -32000; - - charcode = 0; - for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) - { - type42->encoding.char_index[charcode] = 0; - type42->encoding.char_name [charcode] = (char *)".notdef"; - - char_name = loader.encoding_table.elements[charcode]; - if ( char_name ) - for ( idx = 0; idx < type42->num_glyphs; idx++ ) - { - glyph_name = (FT_Byte*)type42->glyph_names[idx]; - if ( ft_strcmp( (const char*)char_name, - (const char*)glyph_name ) == 0 ) - { - type42->encoding.char_index[charcode] = (FT_UShort)idx; - type42->encoding.char_name [charcode] = (char*)glyph_name; - - /* Change min/max encoded char only if glyph name is */ - /* not /.notdef */ - if ( ft_strcmp( (const char*)".notdef", - (const char*)glyph_name ) != 0 ) - { - if ( charcode < min_char ) min_char = charcode; - if ( charcode > max_char ) max_char = charcode; - } - break; - } - } - } - type42->encoding.code_first = min_char; - type42->encoding.code_last = max_char; - type42->encoding.num_chars = loader.num_chars; - } - - Exit: - t42_done_loader( &loader ); - return error; - } - - - /***************** Driver Functions *************/ - - - /*************************************************************************/ - /* */ - /* */ - /* The face object constructor. */ - /* */ - /* */ - /* stream :: input stream where to load font data. */ - /* */ - /* face_index :: The index of the font face in the resource. */ - /* */ - /* num_params :: Number of additional generic parameters. Ignored. */ - /* */ - /* params :: Additional generic parameters. Ignored. */ - /* */ - /* */ - /* face :: The face record to build. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - static FT_Error - T42_Face_Init( FT_Stream stream, - T42_Face face, - FT_Int face_index, - FT_Int num_params, - FT_Parameter* params) - { - FT_Error error; - PSNames_Service psnames; - PSAux_Service psaux; - FT_Face root = (FT_Face)&face->root; - FT_CharMap charmap = face->charmaprecs; - - FT_UNUSED( num_params ); - FT_UNUSED( params ); - FT_UNUSED( face_index ); - FT_UNUSED( stream ); - - - face->ttf_face = NULL; - face->root.num_faces = 1; - - /* XXX */ - psnames = (PSNames_Service)face->psnames; - if ( !psnames ) - { - psnames = (PSNames_Service) - FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), - "psnames" ); - face->psnames = psnames; - } - - psaux = (PSAux_Service)face->psaux; - if ( !psaux ) - { - psaux = (PSAux_Service) - FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), - "psaux" ); - face->psaux = psaux; - } - - /* open the tokenizer, this will also check the font format */ - error = T42_Open_Face( face ); - if ( error ) - goto Exit; - - /* if we just wanted to check the format, leave successfully now */ - if ( face_index < 0 ) - goto Exit; - - /* check the face index */ - if ( face_index != 0 ) - { - FT_ERROR(( "T42_Face_Init: invalid face index\n" )); - error = T42_Err_Invalid_Argument; - goto Exit; - } - - /* Now, load the font program into the face object */ - - /* Init the face object fields */ - /* Now set up root face fields */ - - root->num_glyphs = face->type42.num_glyphs; - root->num_charmaps = 1; - root->face_index = face_index; - - root->face_flags = FT_FACE_FLAG_SCALABLE; - root->face_flags |= FT_FACE_FLAG_HORIZONTAL; - root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; - - if ( face->type42.font_info.is_fixed_pitch ) - root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; - - /* XXX: TODO -- add kerning with .afm support */ - - /* get style name -- be careful, some broken fonts only */ - /* have a `/FontName' dictionary entry! */ - root->family_name = face->type42.font_info.family_name; - if ( root->family_name ) - { - char* full = face->type42.font_info.full_name; - char* family = root->family_name; - - - if ( full ) - { - while ( *family && *full == *family ) - { - family++; - full++; - } - - root->style_name = ( *full == ' ' ? full + 1 - : (char *)"Regular" ); - } - else - root->style_name = (char *)"Regular"; - } - else - { - /* do we have a `/FontName'? */ - if ( face->type42.font_name ) - { - root->family_name = face->type42.font_name; - root->style_name = (char *)"Regular"; - } - } - - /* no embedded bitmap support */ - root->num_fixed_sizes = 0; - root->available_sizes = 0; - - /* Load the TTF font embedded in the T42 font */ - error = FT_New_Memory_Face( FT_FACE_LIBRARY( face ), - face->ttf_data, - face->ttf_size, - 0, - &face->ttf_face ); - if ( error ) - goto Exit; - - /* Ignore info in FontInfo dictionary and use the info from the */ - /* loaded TTF font. The PostScript interpreter also ignores it. */ - root->bbox = face->ttf_face->bbox; - root->units_per_EM = face->ttf_face->units_per_EM; - - root->ascender = face->ttf_face->ascender; - root->descender = face->ttf_face->descender; - root->height = face->ttf_face->height; - - root->max_advance_width = face->ttf_face->max_advance_width; - root->max_advance_height = face->ttf_face->max_advance_height; - - root->underline_position = face->type42.font_info.underline_position; - root->underline_thickness = face->type42.font_info.underline_thickness; - - root->internal->max_points = 0; - root->internal->max_contours = 0; - - /* compute style flags */ - root->style_flags = 0; - if ( face->type42.font_info.italic_angle ) - root->style_flags |= FT_STYLE_FLAG_ITALIC; - - if ( face->ttf_face->style_flags & FT_STYLE_FLAG_BOLD ) - root->style_flags |= FT_STYLE_FLAG_BOLD; - - if ( face->ttf_face->face_flags & FT_FACE_FLAG_VERTICAL ) - root->face_flags |= FT_FACE_FLAG_VERTICAL; - - /* XXX: Add support for new cmaps code in FT 2.1.0 */ - - /* charmap support -- synthetize unicode charmap if possible */ - - /* synthesize a Unicode charmap if there is support in the `PSNames' */ - /* module */ - if ( psnames && psnames->unicode_value ) - { - error = psnames->build_unicodes( root->memory, - face->type42.num_glyphs, - (const char**)face->type42.glyph_names, - &face->unicode_map ); - if ( !error ) - { - root->charmap = charmap; - charmap->face = (FT_Face)face; - charmap->encoding = ft_encoding_unicode; - charmap->platform_id = 3; - charmap->encoding_id = 1; - charmap++; - } - - /* XXX: Is the following code correct? It is used in t1objs.c */ - - /* simply clear the error in case of failure (which really) */ - /* means that out of memory or no unicode glyph names */ - error = T42_Err_Ok; - } - - /* now, support either the standard, expert, or custom encoding */ - charmap->face = (FT_Face)face; - charmap->platform_id = 7; /* a new platform id for Adobe fonts? */ - - switch ( face->type42.encoding_type ) - { - case T1_ENCODING_TYPE_STANDARD: - charmap->encoding = ft_encoding_adobe_standard; - charmap->encoding_id = 0; - break; - - case T1_ENCODING_TYPE_EXPERT: - charmap->encoding = ft_encoding_adobe_expert; - charmap->encoding_id = 1; - break; - - case T1_ENCODING_TYPE_ARRAY: - charmap->encoding = ft_encoding_adobe_custom; - charmap->encoding_id = 2; - break; - - case T1_ENCODING_TYPE_ISOLATIN1: - charmap->encoding = ft_encoding_latin_1; - charmap->encoding_id = 3; - break; - - default: - FT_ERROR(( "T42_Face_Init: invalid encoding\n" )); - error = T42_Err_Invalid_File_Format; - goto Exit; - } - - root->charmaps = face->charmaps; - root->num_charmaps = charmap - face->charmaprecs + 1; - face->charmaps[0] = &face->charmaprecs[0]; - face->charmaps[1] = &face->charmaprecs[1]; - - Exit: - return error; - } - - - /*************************************************************************/ - /* */ - /* */ - /* T42_Face_Done */ - /* */ - /* */ - /* The face object destructor. */ - /* */ - /* */ - /* face :: A typeless pointer to the face object to destroy. */ - /* */ - static void - T42_Face_Done( T42_Face face ) - { - T42_Font type42; - PS_FontInfo info; - FT_Memory memory; - - - if ( face ) - { - type42 = &face->type42; - info = &type42->font_info; - memory = face->root.memory; - - /* delete internal ttf face prior to freeing face->ttf_data */ - if ( face->ttf_face ) - FT_Done_Face( face->ttf_face ); - - /* release font info strings */ - FT_FREE( info->version ); - FT_FREE( info->notice ); - FT_FREE( info->full_name ); - FT_FREE( info->family_name ); - FT_FREE( info->weight ); - - /* release top dictionary */ - FT_FREE( type42->charstrings_len ); - FT_FREE( type42->charstrings ); - FT_FREE( type42->glyph_names ); - - FT_FREE( type42->charstrings_block ); - FT_FREE( type42->glyph_names_block ); - - FT_FREE( type42->encoding.char_index ); - FT_FREE( type42->encoding.char_name ); - FT_FREE( type42->font_name ); - - FT_FREE( face->ttf_data ); - -#if 0 - /* release afm data if present */ - if ( face->afm_data ) - T1_Done_AFM( memory, (T1_AFM*)face->afm_data ); -#endif - - /* release unicode map, if any */ - FT_FREE( face->unicode_map.maps ); - face->unicode_map.num_maps = 0; - - face->root.family_name = 0; - face->root.style_name = 0; - } - } - - /*************************************************************************/ - /* */ - /* */ - /* T42_Driver_Init */ - /* */ - /* */ - /* Initializes a given Type 42 driver object. */ - /* */ - /* */ - /* driver :: A handle to the target driver object. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - static FT_Error - T42_Driver_Init( T42_Driver driver ) - { - FT_Module ttmodule; - - - ttmodule = FT_Get_Module( driver->root.root.library, "truetype" ); - driver->ttclazz = (FT_Driver_Class)ttmodule->clazz; - - return T42_Err_Ok; - } - - - static void - T42_Driver_Done( T42_Driver driver ) - { - FT_UNUSED( driver ); - } - - - /*************************************************************************/ - /* */ - /* */ - /* Get_Char_Index */ - /* */ - /* */ - /* Uses a charmap to return a given character code's glyph index. */ - /* */ - /* */ - /* charmap :: A handle to the source charmap object. */ - /* */ - /* charcode :: The character code. */ - /* */ - /* */ - /* Glyph index. 0 means `undefined character code'. */ - /* */ - static FT_UInt - Get_Char_Index( FT_CharMap charmap, - FT_Long charcode ) - { - T42_Face face; - FT_UInt result = 0; - PSNames_Service psnames; - - - face = (T42_Face)charmap->face; - psnames = (PSNames_Service)face->psnames; - if (!psnames ) - goto Exit; - - switch ( charmap->encoding ) - { - /*******************************************************************/ - /* */ - /* Unicode encoding support */ - /* */ - case ft_encoding_unicode: - /* if this charmap is used, we ignore the encoding of the font and */ - /* use the `PSNames' module to synthetize the Unicode charmap */ - result = psnames->lookup_unicode( &face->unicode_map, - (FT_ULong)charcode ); - - /* the function returns 0xFFFF if the Unicode charcode has */ - /* no corresponding glyph */ - if ( result == 0xFFFFU ) - result = 0; - - /* The result returned is the index (position)in the CharStrings */ - /* array. This must be used now to get the value associated to */ - /* that glyph_name, which is the real index within the truetype */ - /* structure. */ - result = ft_atoi( (const char*)face->type42.charstrings[result] ); - goto Exit; - - /*******************************************************************/ - /* */ - /* ISOLatin1 encoding support */ - /* */ - case ft_encoding_latin_1: - /* ISOLatin1 is the first page of Unicode */ - if ( charcode < 256 && psnames->unicode_value ) - { - result = psnames->lookup_unicode( &face->unicode_map, - (FT_ULong)charcode ); - - /* the function returns 0xFFFF if the Unicode charcode has */ - /* no corresponding glyph */ - if ( result == 0xFFFFU ) - result = 0; - } - goto Exit; - - /*******************************************************************/ - /* */ - /* Custom Type 1 encoding */ - /* */ - case ft_encoding_adobe_custom: - { - T1_Encoding encoding = &face->type42.encoding; - - - if ( charcode >= encoding->code_first && - charcode <= encoding->code_last ) - { - FT_UInt idx = encoding->char_index[charcode]; - - - result = ft_atoi( (const char *)face->type42.charstrings[idx] ); - } - goto Exit; - } - - /*******************************************************************/ - /* */ - /* Adobe Standard & Expert encoding support */ - /* */ - default: - if ( charcode < 256 ) - { - FT_UInt code; - FT_Int n; - const char* glyph_name; - - - code = psnames->adobe_std_encoding[charcode]; - if ( charmap->encoding == ft_encoding_adobe_expert ) - code = psnames->adobe_expert_encoding[charcode]; - - glyph_name = psnames->adobe_std_strings( code ); - if ( !glyph_name ) - break; - - for ( n = 0; n < face->type42.num_glyphs; n++ ) - { - const char* gname = face->type42.glyph_names[n]; - - if ( gname && ( ft_strcmp( gname, glyph_name ) == 0 ) ) - { - result = ft_atoi( (const char *)face->type42.charstrings[n] ); - break; - } - } - } - } - - Exit: - return result; - } - - - static FT_Error - T42_Size_Init( T42_Size size ) - { - FT_Face face = size->root.face; - T42_Face t42face = (T42_Face)face; - FT_Size ttsize; - FT_Error error = T42_Err_Ok; - - - if ( face->size == NULL ) - { - /* First size for this face */ - size->ttsize = t42face->ttf_face->size; - } - else - { - error = FT_New_Size( t42face->ttf_face, &ttsize ); - size->ttsize = ttsize; - } - - return error; - } - - - static void - T42_Size_Done( T42_Size size ) - { - FT_Face face = size->root.face; - T42_Face t42face = (T42_Face)face; - FT_ListNode node; - - - node = FT_List_Find( &t42face->ttf_face->sizes_list, size->ttsize ); - if ( node ) - FT_Done_Size( size->ttsize ); - } - - - static FT_Error - T42_GlyphSlot_Init( T42_GlyphSlot slot ) - { - FT_Face face = slot->root.face; - T42_Face t42face = (T42_Face)face; - FT_GlyphSlot ttslot; - FT_Error error = T42_Err_Ok; - - - if ( face->glyph == NULL ) - { - /* First glyph slot for this face */ - slot->ttslot = t42face->ttf_face->glyph; - } - else - { - error = FT_New_GlyphSlot( t42face->ttf_face, &ttslot ); - slot->ttslot = ttslot; - } - - return error; - } - - - static void - T42_GlyphSlot_Done( T42_GlyphSlot slot ) - { - FT_Face face = slot->root.face; - T42_Face t42face = (T42_Face)face; - FT_GlyphSlot cur = t42face->ttf_face->glyph; - - - while ( cur ) - { - if ( cur == slot->ttslot ) - { - FT_Done_GlyphSlot( slot->ttslot ); - break; - } - - cur = cur->next; - } - } - - - static FT_Error - T42_Char_Size( T42_Size size, - FT_F26Dot6 char_width, - FT_F26Dot6 char_height, - FT_UInt horz_resolution, - FT_UInt vert_resolution ) - { - FT_Face face = size->root.face; - T42_Face t42face = (T42_Face)face; - - - return FT_Set_Char_Size( t42face->ttf_face, - char_width, - char_height, - horz_resolution, - vert_resolution ); - } - - - static FT_Error - T42_Pixel_Size( T42_Size size, - FT_UInt pixel_width, - FT_UInt pixel_height ) - { - FT_Face face = size->root.face; - T42_Face t42face = (T42_Face)face; - - - return FT_Set_Pixel_Sizes( t42face->ttf_face, - pixel_width, - pixel_height ); - } - - - static void - ft_glyphslot_clear( FT_GlyphSlot slot ) - { - /* free bitmap if needed */ - if ( slot->flags & FT_GLYPH_OWN_BITMAP ) - { - FT_Memory memory = FT_FACE_MEMORY( slot->face ); - - - FT_FREE( slot->bitmap.buffer ); - slot->flags &= ~FT_GLYPH_OWN_BITMAP; - } - - /* clear all public fields in the glyph slot */ - FT_MEM_SET( &slot->metrics, 0, sizeof ( slot->metrics ) ); - FT_MEM_SET( &slot->outline, 0, sizeof ( slot->outline ) ); - FT_MEM_SET( &slot->bitmap, 0, sizeof ( slot->bitmap ) ); - - slot->bitmap_left = 0; - slot->bitmap_top = 0; - slot->num_subglyphs = 0; - slot->subglyphs = 0; - slot->control_data = 0; - slot->control_len = 0; - slot->other = 0; - slot->format = ft_glyph_format_none; - - slot->linearHoriAdvance = 0; - slot->linearVertAdvance = 0; - } - - - static FT_Error - T42_Load_Glyph( FT_GlyphSlot glyph, - FT_Size size, - FT_Int glyph_index, - FT_Int load_flags ) - { - FT_Error error; - T42_GlyphSlot t42slot = (T42_GlyphSlot)glyph; - T42_Size t42size = (T42_Size)size; - FT_Driver_Class ttclazz = ((T42_Driver)glyph->face->driver)->ttclazz; - - - ft_glyphslot_clear( t42slot->ttslot ); - error = ttclazz->load_glyph( t42slot->ttslot, - t42size->ttsize, - glyph_index, - load_flags | FT_LOAD_NO_BITMAP ); - - if ( !error ) - { - glyph->metrics = t42slot->ttslot->metrics; - - glyph->linearHoriAdvance = t42slot->ttslot->linearHoriAdvance; - glyph->linearVertAdvance = t42slot->ttslot->linearVertAdvance; - - glyph->format = t42slot->ttslot->format; - glyph->outline = t42slot->ttslot->outline; - - glyph->bitmap = t42slot->ttslot->bitmap; - glyph->bitmap_left = t42slot->ttslot->bitmap_left; - glyph->bitmap_top = t42slot->ttslot->bitmap_top; - } - - return error; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Get_Next_Char */ - /* */ - /* */ - /* Uses a charmap to return the next encoded char. */ - /* */ - /* */ - /* charmap :: A handle to the source charmap object. */ - /* */ - /* charcode :: The character code. */ - /* */ - /* */ - /* Next char code. 0 means `no more char codes'. */ - /* */ - static FT_Long - Get_Next_Char( FT_CharMap charmap, - FT_Long charcode ) - { - T42_Face face; - PSNames_Service psnames; - - - face = (T42_Face)charmap->face; - psnames = (PSNames_Service)face->psnames; - - if ( psnames ) - switch ( charmap->encoding ) - { - /*******************************************************************/ - /* */ - /* Unicode encoding support */ - /* */ - case ft_encoding_unicode: - /* use the `PSNames' module to synthetize the Unicode charmap */ - return psnames->next_unicode( &face->unicode_map, - (FT_ULong)charcode ); - - /*******************************************************************/ - /* */ - /* ISOLatin1 encoding support */ - /* */ - case ft_encoding_latin_1: - { - FT_ULong code; - - - /* use the `PSNames' module to synthetize the Unicode charmap */ - code = psnames->next_unicode( &face->unicode_map, - (FT_ULong)charcode ); - if ( code < 256 ) - return code; - break; - } - - /*******************************************************************/ - /* */ - /* Custom Type 1 encoding */ - /* */ - case ft_encoding_adobe_custom: - { - T1_Encoding encoding = &face->type42.encoding; - - - charcode++; - if ( charcode < encoding->code_first ) - charcode = encoding->code_first; - while ( charcode <= encoding->code_last ) { - if ( encoding->char_index[charcode] ) - return charcode; - charcode++; - } - } - - - /*******************************************************************/ - /* */ - /* Adobe Standard & Expert encoding support */ - /* */ - default: - while ( ++charcode < 256 ) - { - FT_UInt code; - FT_Int n; - const char* glyph_name; - - - code = psnames->adobe_std_encoding[charcode]; - if ( charmap->encoding == ft_encoding_adobe_expert ) - code = psnames->adobe_expert_encoding[charcode]; - - glyph_name = psnames->adobe_std_strings( code ); - if ( !glyph_name ) - continue; - - for ( n = 0; n < face->type42.num_glyphs; n++ ) - { - const char* gname = face->type42.glyph_names[n]; - - - if ( gname && gname[0] == glyph_name[0] && - ft_strcmp( gname, glyph_name ) == 0 ) - return charcode; - } - } - } - - return 0; - } - - static FT_Error t42_get_glyph_name( T42_Face face, FT_UInt glyph_index, @@ -1952,7 +14,7 @@ FT_String* gname; - gname = face->type42.glyph_names[glyph_index]; + gname = face->type1.glyph_names[glyph_index]; if ( buffer_max > 0 ) { @@ -1961,18 +23,19 @@ if ( len >= buffer_max ) len = buffer_max - 1; + FT_MEM_COPY( buffer, gname, len ); ((FT_Byte*)buffer)[len] = 0; } - return T42_Err_Ok; + return FT_Err_Ok; } static const char* t42_get_ps_name( T42_Face face ) { - return (const char*)face->type42.font_name; + return (const char*)face->type1.font_name; } @@ -1984,12 +47,12 @@ FT_String* gname; - for ( i = 0; i < face->type42.num_glyphs; i++ ) + for ( i = 0; i < face->type1.num_glyphs; i++ ) { - gname = face->type42.glyph_names[i]; + gname = face->type1.glyph_names[i]; if ( !ft_strcmp( glyph_name, gname ) ) - return ft_atoi( (const char *)face->type42.charstrings[i] ); + return ft_atoi( (const char *)face->type1.charstrings[i] ); } return 0; @@ -1997,8 +60,8 @@ static FT_Module_Interface - Get_Interface( FT_Driver driver, - const FT_String* t42_interface ) + T42_Get_Interface( FT_Driver driver, + const FT_String* t42_interface ) { FT_UNUSED( driver ); @@ -2037,7 +100,7 @@ (FT_Module_Constructor)T42_Driver_Init, (FT_Module_Destructor) T42_Driver_Done, - (FT_Module_Requester) Get_Interface, + (FT_Module_Requester) T42_Get_Interface, }, sizeof ( T42_FaceRec ), @@ -2051,18 +114,16 @@ (FT_Slot_InitFunc) T42_GlyphSlot_Init, (FT_Slot_DoneFunc) T42_GlyphSlot_Done, - (FT_Size_ResetPointsFunc) T42_Char_Size, - (FT_Size_ResetPixelsFunc) T42_Pixel_Size, - (FT_Slot_LoadFunc) T42_Load_Glyph, - (FT_CharMap_CharIndexFunc)Get_Char_Index, + (FT_Size_ResetPointsFunc) T42_Size_SetChars, + (FT_Size_ResetPixelsFunc) T42_Size_SetPixels, + (FT_Slot_LoadFunc) T42_GlyphSlot_Load, + (FT_CharMap_CharIndexFunc)T42_CMap_CharIndex, (FT_Face_GetKerningFunc) 0, (FT_Face_AttachFunc) 0, (FT_Face_GetAdvancesFunc) 0, - (FT_CharMap_CharNextFunc) Get_Next_Char + (FT_CharMap_CharNextFunc) T42_CMap_CharNext, }; - -/* END */ diff --git a/src/type42/t42drivr.h b/src/type42/t42drivr.h new file mode 100644 index 000000000..cfa8fcf94 --- /dev/null +++ b/src/type42/t42drivr.h @@ -0,0 +1,38 @@ +/***************************************************************************/ +/* */ +/* t42drivr.h */ +/* */ +/* High-level Type 42 driver interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __T42DRIVER_H__ +#define __T42DRIVER_H__ + + +#include +#include FT_INTERNAL_DRIVER_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Driver_ClassRec ) t42_driver_class; + + +FT_END_HEADER + +#endif /* __T42DRIVER_H__ */ + + +/* END */ diff --git a/src/type42/t42objs.c b/src/type42/t42objs.c new file mode 100644 index 000000000..bb9f4bab7 --- /dev/null +++ b/src/type42/t42objs.c @@ -0,0 +1,881 @@ +#include "t42objs.h" +#include "t42parse.h" +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_LIST_H + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t42 + + + static FT_Error + T42_Open_Face( T42_Face face ) + { + T42_LoaderRec loader; + T42_Parser parser; + T1_Font type1 = &face->type1; + FT_Memory memory = face->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + t42_loader_init( &loader, face ); + + parser = &loader.parser; + + if ( FT_ALLOC( face->ttf_data, 12 ) ) + goto Exit; + + error = t42_parser_init( parser, + face->root.stream, + memory, + psaux); + if ( error ) + goto Exit; + + error = t42_parse_dict( face, &loader, parser->base_dict, parser->base_len ); + + if ( type1->font_type != 42 ) + { + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + /* now, propagate the charstrings and glyphnames tables */ + /* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + + if ( !loader.charstrings.init ) { + FT_ERROR(( "T42_Open_Face: no charstrings array in face!\n" )); + error = FT_Err_Invalid_File_Format; + } + + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; + + /* we copy the glyph names `block' and `elements' fields; */ + /* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = 0; + loader.glyph_names.elements = 0; + + /* we must now build type1.encoding when we have a custom array */ + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) + { + FT_Int charcode, idx, min_char, max_char; + FT_Byte* char_name; + FT_Byte* glyph_name; + + + /* OK, we do the following: for each element in the encoding */ + /* table, look up the index of the glyph having the same name */ + /* as defined in the CharStrings array. */ + /* The index is then stored in type1.encoding.char_index, and */ + /* the name in type1.encoding.char_name */ + + min_char = +32000; + max_char = -32000; + + charcode = 0; + for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) + { + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = (char *)".notdef"; + + char_name = loader.encoding_table.elements[charcode]; + if ( char_name ) + for ( idx = 0; idx < type1->num_glyphs; idx++ ) + { + glyph_name = (FT_Byte*)type1->glyph_names[idx]; + if ( ft_strcmp( (const char*)char_name, + (const char*)glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = (FT_UShort)idx; + type1->encoding.char_name [charcode] = (char*)glyph_name; + + /* Change min/max encoded char only if glyph name is */ + /* not /.notdef */ + if ( ft_strcmp( (const char*)".notdef", + (const char*)glyph_name ) != 0 ) + { + if ( charcode < min_char ) min_char = charcode; + if ( charcode > max_char ) max_char = charcode; + } + break; + } + } + } + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + + Exit: + t42_loader_done( &loader ); + return error; + } + + + /***************** Driver Functions *************/ + + + FT_LOCAL_DEF( FT_Error ) + T42_Face_Init( FT_Stream stream, + T42_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params) + { + FT_Error error; + PSNames_Service psnames; + PSAux_Service psaux; + FT_Face root = (FT_Face)&face->root; + + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + FT_UNUSED( stream ); + + + face->ttf_face = NULL; + face->root.num_faces = 1; + + face->psnames = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psnames" ); + psnames = (PSNames_Service)face->psnames; + + face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psaux" ); + psaux = (PSAux_Service)face->psaux; + + /* open the tokenizer, this will also check the font format */ + error = T42_Open_Face( face ); + if ( error ) + goto Exit; + + /* if we just wanted to check the format, leave successfully now */ + if ( face_index < 0 ) + goto Exit; + + /* check the face index */ + if ( face_index != 0 ) + { + FT_ERROR(( "T42_Face_Init: invalid face index\n" )); + error = FT_Err_Invalid_Argument; + goto Exit; + } + + /* Now, load the font program into the face object */ + + /* Init the face object fields */ + /* Now set up root face fields */ + + root->num_glyphs = face->type1.num_glyphs; + root->num_charmaps = 0; + root->face_index = face_index; + + root->face_flags = FT_FACE_FLAG_SCALABLE; + root->face_flags |= FT_FACE_FLAG_HORIZONTAL; + root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; + + if ( face->type1.font_info.is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* XXX: TODO -- add kerning with .afm support */ + + /* get style name -- be careful, some broken fonts only */ + /* have a `/FontName' dictionary entry! */ + root->family_name = face->type1.font_info.family_name; + if ( root->family_name ) + { + char* full = face->type1.font_info.full_name; + char* family = root->family_name; + + + if ( full ) + { + while ( *family && *full == *family ) + { + family++; + full++; + } + + root->style_name = ( *full == ' ' ? full + 1 + : (char *)"Regular" ); + } + else + root->style_name = (char *)"Regular"; + } + else + { + /* do we have a `/FontName'? */ + if ( face->type1.font_name ) + { + root->family_name = face->type1.font_name; + root->style_name = (char *)"Regular"; + } + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = 0; + + /* Load the TTF font embedded in the T42 font */ + error = FT_New_Memory_Face( FT_FACE_LIBRARY( face ), + face->ttf_data, + face->ttf_size, + 0, + &face->ttf_face ); + if ( error ) + goto Exit; + + /* Ignore info in FontInfo dictionary and use the info from the */ + /* loaded TTF font. The PostScript interpreter also ignores it. */ + root->bbox = face->ttf_face->bbox; + root->units_per_EM = face->ttf_face->units_per_EM; + + root->ascender = face->ttf_face->ascender; + root->descender = face->ttf_face->descender; + root->height = face->ttf_face->height; + + root->max_advance_width = face->ttf_face->max_advance_width; + root->max_advance_height = face->ttf_face->max_advance_height; + + root->underline_position = face->type1.font_info.underline_position; + root->underline_thickness = face->type1.font_info.underline_thickness; + + root->internal->max_points = 0; + root->internal->max_contours = 0; + + /* compute style flags */ + root->style_flags = 0; + if ( face->type1.font_info.italic_angle ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + + if ( face->ttf_face->style_flags & FT_STYLE_FLAG_BOLD ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + + if ( face->ttf_face->face_flags & FT_FACE_FLAG_VERTICAL ) + root->face_flags |= FT_FACE_FLAG_VERTICAL; + +#ifdef FT_CONFIG_OPTION_USE_CMAPS + + { + if ( psnames && psaux ) + { + FT_CharMapRec charmap; + T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes; + FT_CMap_Class clazz; + + + charmap.face = root; + + /* first of all, try to synthetize a Unicode charmap */ + charmap.platform_id = 3; + charmap.encoding_id = 1; + charmap.encoding = ft_encoding_unicode; + + FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL ); + + /* now, generate an Adobe Standard encoding when appropriate */ + charmap.platform_id = 7; + clazz = NULL; + + switch ( face->type1.encoding_type ) + { + case T1_ENCODING_TYPE_STANDARD: + charmap.encoding = ft_encoding_adobe_standard; + charmap.encoding_id = 0; + clazz = cmap_classes->standard; + break; + + case T1_ENCODING_TYPE_EXPERT: + charmap.encoding = ft_encoding_adobe_expert; + charmap.encoding_id = 1; + clazz = cmap_classes->expert; + break; + + case T1_ENCODING_TYPE_ARRAY: + charmap.encoding = ft_encoding_adobe_custom; + charmap.encoding_id = 2; + clazz = cmap_classes->custom; + break; + + case T1_ENCODING_TYPE_ISOLATIN1: + charmap.encoding = ft_encoding_latin_1; + charmap.encoding_id = 3; + clazz = cmap_classes->unicode; + break; + + default: + ; + } + + if ( clazz ) + FT_CMap_New( clazz, NULL, &charmap, NULL ); + + /* Select default charmap */ + if (root->num_charmaps) + root->charmap = root->charmaps[0]; + } + } + +#else /* !FT_CONFIG_OPTION_USE_CMAPS */ + + /* charmap support -- synthetize unicode charmap if possible */ + { + FT_CharMap charmap = face->charmaprecs; + + /* synthesize a Unicode charmap if there is support in the `PSNames' */ + /* module */ + if ( psnames && psnames->unicode_value ) + { + error = psnames->build_unicodes( root->memory, + face->type1.num_glyphs, + (const char**)face->type1.glyph_names, + &face->unicode_map ); + if ( !error ) + { + root->charmap = charmap; + charmap->face = (FT_Face)face; + charmap->encoding = ft_encoding_unicode; + charmap->platform_id = 3; + charmap->encoding_id = 1; + charmap++; + } + + /* XXX: Is the following code correct? It is used in t1objs.c */ + + /* simply clear the error in case of failure (which really) */ + /* means that out of memory or no unicode glyph names */ + error = FT_Err_Ok; + } + + /* now, support either the standard, expert, or custom encoding */ + charmap->face = (FT_Face)face; + charmap->platform_id = 7; /* a new platform id for Adobe fonts? */ + + switch ( face->type1.encoding_type ) + { + case T1_ENCODING_TYPE_STANDARD: + charmap->encoding = ft_encoding_adobe_standard; + charmap->encoding_id = 0; + break; + + case T1_ENCODING_TYPE_EXPERT: + charmap->encoding = ft_encoding_adobe_expert; + charmap->encoding_id = 1; + break; + + case T1_ENCODING_TYPE_ARRAY: + charmap->encoding = ft_encoding_adobe_custom; + charmap->encoding_id = 2; + break; + + case T1_ENCODING_TYPE_ISOLATIN1: + charmap->encoding = ft_encoding_latin_1; + charmap->encoding_id = 3; + break; + + default: + FT_ERROR(( "T42_Face_Init: invalid encoding\n" )); + error = FT_Err_Invalid_File_Format; + goto Exit; + } + + root->charmaps = face->charmaps; + root->num_charmaps = charmap - face->charmaprecs + 1; + face->charmaps[0] = &face->charmaprecs[0]; + face->charmaps[1] = &face->charmaprecs[1]; + } + +#endif /* !FT_CONFIG_OPTION_USE_CMAPS */ + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + T42_Face_Done( T42_Face face ) + { + T1_Font type1; + PS_FontInfo info; + FT_Memory memory; + + + if ( face ) + { + type1 = &face->type1; + info = &type1->font_info; + memory = face->root.memory; + + /* delete internal ttf face prior to freeing face->ttf_data */ + if ( face->ttf_face ) + FT_Done_Face( face->ttf_face ); + + /* release font info strings */ + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + + /* release top dictionary */ + FT_FREE( type1->charstrings_len ); + FT_FREE( type1->charstrings ); + FT_FREE( type1->glyph_names ); + + FT_FREE( type1->charstrings_block ); + FT_FREE( type1->glyph_names_block ); + + FT_FREE( type1->encoding.char_index ); + FT_FREE( type1->encoding.char_name ); + FT_FREE( type1->font_name ); + + FT_FREE( face->ttf_data ); + +#if 0 + /* release afm data if present */ + if ( face->afm_data ) + T1_Done_AFM( memory, (T1_AFM*)face->afm_data ); +#endif + + /* release unicode map, if any */ + FT_FREE( face->unicode_map.maps ); + face->unicode_map.num_maps = 0; + + face->root.family_name = 0; + face->root.style_name = 0; + } + } + + /*************************************************************************/ + /* */ + /* */ + /* T42_Driver_Init */ + /* */ + /* */ + /* Initializes a given Type 42 driver object. */ + /* */ + /* */ + /* driver :: A handle to the target driver object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + T42_Driver_Init( T42_Driver driver ) + { + FT_Module ttmodule; + + + ttmodule = FT_Get_Module( FT_MODULE(driver)->library, "truetype" ); + driver->ttclazz = (FT_Driver_Class)ttmodule->clazz; + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + T42_Driver_Done( T42_Driver driver ) + { + FT_UNUSED( driver ); + } + + + FT_LOCAL_DEF( FT_UInt ) + T42_CMap_CharIndex( FT_CharMap charmap, + FT_Long charcode ) + { + T42_Face face; + FT_UInt result = 0; + PSNames_Service psnames; + + + face = (T42_Face)charmap->face; + psnames = (PSNames_Service)face->psnames; + if (!psnames ) + goto Exit; + + switch ( charmap->encoding ) + { + /*******************************************************************/ + /* */ + /* Unicode encoding support */ + /* */ + case ft_encoding_unicode: + /* if this charmap is used, we ignore the encoding of the font and */ + /* use the `PSNames' module to synthetize the Unicode charmap */ + result = psnames->lookup_unicode( &face->unicode_map, + (FT_ULong)charcode ); + + /* the function returns 0xFFFF if the Unicode charcode has */ + /* no corresponding glyph */ + if ( result == 0xFFFFU ) + result = 0; + + /* The result returned is the index (position)in the CharStrings */ + /* array. This must be used now to get the value associated to */ + /* that glyph_name, which is the real index within the truetype */ + /* structure. */ + result = ft_atoi( (const char*)face->type1.charstrings[result] ); + goto Exit; + + /*******************************************************************/ + /* */ + /* ISOLatin1 encoding support */ + /* */ + case ft_encoding_latin_1: + /* ISOLatin1 is the first page of Unicode */ + if ( charcode < 256 && psnames->unicode_value ) + { + result = psnames->lookup_unicode( &face->unicode_map, + (FT_ULong)charcode ); + + /* the function returns 0xFFFF if the Unicode charcode has */ + /* no corresponding glyph */ + if ( result == 0xFFFFU ) + result = 0; + } + goto Exit; + + /*******************************************************************/ + /* */ + /* Custom Type 1 encoding */ + /* */ + case ft_encoding_adobe_custom: + { + T1_Encoding encoding = &face->type1.encoding; + + + if ( charcode >= encoding->code_first && + charcode <= encoding->code_last ) + { + FT_UInt idx = encoding->char_index[charcode]; + + + result = ft_atoi( (const char *)face->type1.charstrings[idx] ); + } + goto Exit; + } + + /*******************************************************************/ + /* */ + /* Adobe Standard & Expert encoding support */ + /* */ + default: + if ( charcode < 256 ) + { + FT_UInt code; + FT_Int n; + const char* glyph_name; + + + code = psnames->adobe_std_encoding[charcode]; + if ( charmap->encoding == ft_encoding_adobe_expert ) + code = psnames->adobe_expert_encoding[charcode]; + + glyph_name = psnames->adobe_std_strings( code ); + if ( !glyph_name ) + break; + + for ( n = 0; n < face->type1.num_glyphs; n++ ) + { + const char* gname = face->type1.glyph_names[n]; + + if ( gname && ( ft_strcmp( gname, glyph_name ) == 0 ) ) + { + result = ft_atoi( (const char *)face->type1.charstrings[n] ); + break; + } + } + } + } + + Exit: + return result; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_Init( T42_Size size ) + { + FT_Face face = size->root.face; + T42_Face t42face = (T42_Face)face; + FT_Size ttsize; + FT_Error error = FT_Err_Ok; + + + error = FT_New_Size( t42face->ttf_face, &ttsize ); + size->ttsize = ttsize; + + return error; + } + + + FT_LOCAL_DEF( void ) + T42_Size_Done( T42_Size size ) + { + FT_Face face = size->root.face; + T42_Face t42face = (T42_Face)face; + FT_ListNode node; + + + node = FT_List_Find( &t42face->ttf_face->sizes_list, size->ttsize ); + if ( node ) + { + FT_Done_Size( size->ttsize ); + size->ttsize = NULL; + } + } + + + FT_LOCAL_DEF( FT_Error ) + T42_GlyphSlot_Init( T42_GlyphSlot slot ) + { + FT_Face face = slot->root.face; + T42_Face t42face = (T42_Face)face; + FT_GlyphSlot ttslot; + FT_Error error = FT_Err_Ok; + + + if ( face->glyph == NULL ) + { + /* First glyph slot for this face */ + slot->ttslot = t42face->ttf_face->glyph; + } + else + { + error = FT_New_GlyphSlot( t42face->ttf_face, &ttslot ); + slot->ttslot = ttslot; + } + + return error; + } + + + FT_LOCAL_DEF( void ) + T42_GlyphSlot_Done( T42_GlyphSlot slot ) + { + FT_Face face = slot->root.face; + T42_Face t42face = (T42_Face)face; + FT_GlyphSlot cur = t42face->ttf_face->glyph; + + + while ( cur ) + { + if ( cur == slot->ttslot ) + { + FT_Done_GlyphSlot( slot->ttslot ); + break; + } + + cur = cur->next; + } + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_SetChars( T42_Size size, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ) + { + FT_Face face = size->root.face; + T42_Face t42face = (T42_Face)face; + + + return FT_Set_Char_Size( t42face->ttf_face, + char_width, + char_height, + horz_resolution, + vert_resolution ); + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Size_SetPixels( T42_Size size, + FT_UInt pixel_width, + FT_UInt pixel_height ) + { + FT_Face face = size->root.face; + T42_Face t42face = (T42_Face)face; + + + return FT_Set_Pixel_Sizes( t42face->ttf_face, + pixel_width, + pixel_height ); + } + + + static void + ft_glyphslot_clear( FT_GlyphSlot slot ) + { + /* free bitmap if needed */ + if ( slot->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + + + FT_FREE( slot->bitmap.buffer ); + slot->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + /* clear all public fields in the glyph slot */ + FT_MEM_SET( &slot->metrics, 0, sizeof ( slot->metrics ) ); + FT_MEM_SET( &slot->outline, 0, sizeof ( slot->outline ) ); + FT_MEM_SET( &slot->bitmap, 0, sizeof ( slot->bitmap ) ); + + slot->bitmap_left = 0; + slot->bitmap_top = 0; + slot->num_subglyphs = 0; + slot->subglyphs = 0; + slot->control_data = 0; + slot->control_len = 0; + slot->other = 0; + slot->format = ft_glyph_format_none; + + slot->linearHoriAdvance = 0; + slot->linearVertAdvance = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + T42_GlyphSlot_Load( FT_GlyphSlot glyph, + FT_Size size, + FT_Int glyph_index, + FT_Int load_flags ) + { + FT_Error error; + T42_GlyphSlot t42slot = (T42_GlyphSlot)glyph; + T42_Size t42size = (T42_Size)size; + FT_Driver_Class ttclazz = ((T42_Driver)glyph->face->driver)->ttclazz; + + + ft_glyphslot_clear( t42slot->ttslot ); + error = ttclazz->load_glyph( t42slot->ttslot, + t42size->ttsize, + glyph_index, + load_flags | FT_LOAD_NO_BITMAP ); + + if ( !error ) + { + glyph->metrics = t42slot->ttslot->metrics; + + glyph->linearHoriAdvance = t42slot->ttslot->linearHoriAdvance; + glyph->linearVertAdvance = t42slot->ttslot->linearVertAdvance; + + glyph->format = t42slot->ttslot->format; + glyph->outline = t42slot->ttslot->outline; + + glyph->bitmap = t42slot->ttslot->bitmap; + glyph->bitmap_left = t42slot->ttslot->bitmap_left; + glyph->bitmap_top = t42slot->ttslot->bitmap_top; + } + + return error; + } + + + + FT_LOCAL_DEF( FT_Long ) + T42_CMap_CharNext( FT_CharMap charmap, + FT_Long charcode ) + { + T42_Face face; + PSNames_Service psnames; + + + face = (T42_Face)charmap->face; + psnames = (PSNames_Service)face->psnames; + + if ( psnames ) + switch ( charmap->encoding ) + { + /*******************************************************************/ + /* */ + /* Unicode encoding support */ + /* */ + case ft_encoding_unicode: + /* use the `PSNames' module to synthetize the Unicode charmap */ + return psnames->next_unicode( &face->unicode_map, + (FT_ULong)charcode ); + + /*******************************************************************/ + /* */ + /* ISOLatin1 encoding support */ + /* */ + case ft_encoding_latin_1: + { + FT_ULong code; + + + /* use the `PSNames' module to synthetize the Unicode charmap */ + code = psnames->next_unicode( &face->unicode_map, + (FT_ULong)charcode ); + if ( code < 256 ) + return code; + break; + } + + /*******************************************************************/ + /* */ + /* Custom Type 1 encoding */ + /* */ + case ft_encoding_adobe_custom: + { + T1_Encoding encoding = &face->type1.encoding; + + + charcode++; + if ( charcode < encoding->code_first ) + charcode = encoding->code_first; + while ( charcode <= encoding->code_last ) { + if ( encoding->char_index[charcode] ) + return charcode; + charcode++; + } + } + + + /*******************************************************************/ + /* */ + /* Adobe Standard & Expert encoding support */ + /* */ + default: + while ( ++charcode < 256 ) + { + FT_UInt code; + FT_Int n; + const char* glyph_name; + + + code = psnames->adobe_std_encoding[charcode]; + if ( charmap->encoding == ft_encoding_adobe_expert ) + code = psnames->adobe_expert_encoding[charcode]; + + glyph_name = psnames->adobe_std_strings( code ); + if ( !glyph_name ) + continue; + + for ( n = 0; n < face->type1.num_glyphs; n++ ) + { + const char* gname = face->type1.glyph_names[n]; + + + if ( gname && gname[0] == glyph_name[0] && + ft_strcmp( gname, glyph_name ) == 0 ) + return charcode; + } + } + } + + return 0; + } + diff --git a/src/type42/t42objs.h b/src/type42/t42objs.h new file mode 100644 index 000000000..04db2cd9a --- /dev/null +++ b/src/type42/t42objs.h @@ -0,0 +1,130 @@ +#ifndef __TYPE42_OBJS_H__ +#define __TYPE42_OBJS_H__ + +#include +#include FT_FREETYPE_H +#include FT_TYPE1_TABLES_H +#include FT_INTERNAL_TYPE1_TYPES_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DRIVER_H +#include FT_INTERNAL_POSTSCRIPT_NAMES_H +#include FT_INTERNAL_POSTSCRIPT_HINTS_H + +FT_BEGIN_HEADER + + /* Type42 face */ + typedef struct T42_FaceRec_ + { + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; + const void* afm_data; + + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; + PS_Unicodes unicode_map; + + FT_Byte* ttf_data; + FT_ULong ttf_size; + FT_Face ttf_face; + + } T42_FaceRec, *T42_Face; + + + + /* Type42 size */ + typedef struct T42_SizeRec_ + { + FT_SizeRec root; + FT_Size ttsize; + + } T42_SizeRec, *T42_Size; + + + /* Type42 slot */ + typedef struct T42_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + FT_GlyphSlot ttslot; + + } T42_GlyphSlotRec, *T42_GlyphSlot; + + + /* Type 42 driver */ + typedef struct T42_DriverRec_ + { + FT_DriverRec root; + FT_Driver_Class ttclazz; + void* extension_component; + + } T42_DriverRec, *T42_Driver; + + /* */ + + FT_LOCAL( FT_Error ) + T42_Face_Init( FT_Stream stream, + T42_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + FT_LOCAL( void ) + T42_Face_Done( T42_Face face ); + + + FT_LOCAL( FT_Error ) + T42_Size_Init( T42_Size size ); + + + FT_LOCAL( FT_Error ) + T42_Size_SetChars( T42_Size size, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); + + FT_LOCAL( FT_Error ) + T42_Size_SetPixels( T42_Size size, + FT_UInt pixel_width, + FT_UInt pixel_height ); + + FT_LOCAL( void ) + T42_Size_Done( T42_Size size ); + + + FT_LOCAL( FT_Error ) + T42_GlyphSlot_Init( T42_GlyphSlot slot ); + + + FT_LOCAL( FT_Error ) + T42_GlyphSlot_Load( FT_GlyphSlot glyph, + FT_Size size, + FT_Int glyph_index, + FT_Int load_flags ); + + FT_LOCAL( void ) + T42_GlyphSlot_Done( T42_GlyphSlot slot ); + + + FT_LOCAL( FT_UInt ) + T42_CMap_CharIndex( FT_CharMap charmap, + FT_Long charcode ); + + FT_LOCAL( FT_Long ) + T42_CMap_CharNext( FT_CharMap charmap, + FT_Long charcode ); + + + FT_LOCAL( FT_Error ) + T42_Driver_Init( T42_Driver driver ); + + FT_LOCAL( void ) + T42_Driver_Done( T42_Driver driver ); + + /* */ + +FT_END_HEADER + +#endif /* __TYPE42_OBJS_H__ */ diff --git a/src/type42/t42parse.c b/src/type42/t42parse.c new file mode 100644 index 000000000..f2806e2ed --- /dev/null +++ b/src/type42/t42parse.c @@ -0,0 +1,1083 @@ +#include "t42parse.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_name( T42_Face face, + T42_Loader loader ); + + static void + t42_parse_font_bbox( T42_Face face, + T42_Loader loader ); + + 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_TYPE_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_NUM( "PaintType", paint_type ) + T1_FIELD_NUM( "FontType", font_type ) + T1_FIELD_NUM( "StrokeWidth", stroke_width ) + + T1_FIELD_CALLBACK( "FontName", t42_parse_font_name ) + T1_FIELD_CALLBACK( "FontBBox", t42_parse_font_bbox ) + 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 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 = FT_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 = FT_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_name( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + FT_Error error; + FT_Memory memory = parser->root.memory; + FT_Int len; + FT_Byte* cur; + FT_Byte* cur2; + FT_Byte* limit; + + + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + limit = parser->root.limit; + + if ( cur >= limit - 1 || + ( *cur != '/' && *cur != '(') ) + return; + + cur++; + cur2 = cur; + while ( cur2 < limit && t42_is_alpha( *cur2 ) ) + cur2++; + + len = (FT_Int)( cur2 - cur ); + if ( len > 0 ) + { + if ( FT_ALLOC( face->type1.font_name, len + 1 ) ) + { + parser->root.error = error; + return; + } + + FT_MEM_COPY( face->type1.font_name, cur, len ); + face->type1.font_name[len] = '\0'; + } + parser->root.cursor = cur2; + } + + + static void + t42_parse_font_bbox( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + FT_BBox* bbox = &face->type1.font_bbox; + + bbox->xMin = T1_ToInt( parser ); + bbox->yMin = T1_ToInt( parser ); + bbox->xMax = T1_ToInt( parser ); + bbox->yMax = T1_ToInt( parser ); + } + + + 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 = FT_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 = 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 = 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 = FT_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; + + d = 0; + + Exit: + return d; + } + + + static void + t42_parse_sfnts( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + FT_Memory memory = parser->root.memory; + FT_Byte* cur = parser->root.cursor; + FT_Byte* limit = parser->root.limit; + FT_Error error; + FT_Int num_tables = 0, status; + FT_ULong count, ttf_size = 0, string_size = 0; + FT_Bool in_string = 0; + FT_Byte v = 0; + + + /* The format is `/sfnts [ <...> <...> ... ] def' */ + + while ( t42_is_space( *cur ) ) + cur++; + + if (*cur++ == '[') + { + status = 0; + count = 0; + } + else + { + FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" )); + error = FT_Err_Invalid_File_Format; + goto Fail; + } + + while ( cur < limit - 2 ) + { + while ( t42_is_space( *cur ) ) + cur++; + + switch ( *cur ) + { + case ']': + parser->root.cursor = cur++; + return; + + case '<': + in_string = 1; + string_size = 0; + cur++; + continue; + + case '>': + if ( !in_string ) + { + FT_ERROR(( "t42_parse_sfnts: found unpaired `>'!\n" )); + error = FT_Err_Invalid_File_Format; + goto Fail; + } + + /* A string can have, as a last byte, */ + /* a zero byte for padding. If so, ignore it */ + if ( ( v == 0 ) && ( string_size % 2 == 1 ) ) + count--; + in_string = 0; + cur++; + continue; + + case '%': + if ( !in_string ) + { + /* Comment found; skip till end of line */ + while ( *cur != '\n' ) + cur++; + continue; + } + else + { + FT_ERROR(( "t42_parse_sfnts: found `%' in string!\n" )); + error = FT_Err_Invalid_File_Format; + goto Fail; + } + + default: + if ( !ft_xdigit( *cur ) || !ft_xdigit( *(cur + 1) ) ) + { + FT_ERROR(( "t42_parse_sfnts: found non-hex characters in string" )); + error = FT_Err_Invalid_File_Format; + goto Fail; + } + + v = (FT_Byte)( 16 * t42_hexval( *cur++ ) + t42_hexval( *cur++ ) ); + string_size++; + } + + switch ( status ) + { + case 0: /* The '[' was read, so load offset table, 12 bytes */ + if ( count < 12 ) + { + face->ttf_data[count++] = v; + continue; + } + else + { + num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; + status = 1; + ttf_size = 12 + 16 * num_tables; + + if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) ) + goto Fail; + } + /* No break, fall-through */ + + case 1: /* The offset table is read; read now the table directory */ + if ( count < ttf_size ) + { + face->ttf_data[count++] = v; + continue; + } + else + { + int i; + FT_ULong len; + + + for ( i = 0; i < num_tables; i++ ) + { + FT_Byte* p = face->ttf_data + 12 + 16*i + 12; + + len = FT_PEEK_ULONG( p ); + + /* Pad to a 4-byte boundary length */ + ttf_size += ( len + 3 ) & ~3; + } + + status = 2; + face->ttf_size = ttf_size; + + if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, + ttf_size + 1 ) ) + goto Fail; + } + /* No break, fall-through */ + + case 2: /* We are reading normal tables; just swallow them */ + face->ttf_data[count++] = v; + + } + } + + /* If control reaches this point, the format was not valid */ + error = FT_Err_Invalid_File_Format; + + Fail: + parser->root.error = error; + } + + + static void + t42_parse_charstrings( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + PS_Table code_table = &loader->charstrings; + PS_Table name_table = &loader->glyph_names; + FT_Memory memory = parser->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_Int n; + + + loader->num_glyphs = T1_ToInt( parser ); + if ( parser->root.error ) + return; + + /* initialize tables */ + + error = psaux->ps_table_funcs->init( code_table, + loader->num_glyphs, + memory ); + if ( error ) + goto Fail; + + error = psaux->ps_table_funcs->init( name_table, + loader->num_glyphs, + memory ); + if ( error ) + goto Fail; + + n = 0; + + for (;;) + { + /* the format is simple: */ + /* `/glyphname' + index + def */ + /* */ + /* note that we stop when we find an `end' */ + /* */ + T1_Skip_Spaces( parser ); + + cur = parser->root.cursor; + if ( cur >= limit ) + break; + + /* we stop when we find an `end' keyword */ + if ( *cur == 'e' && + cur + 3 < limit && + cur[1] == 'n' && + cur[2] == 'd' ) + break; + + if ( *cur != '/' ) + T1_Skip_Alpha( parser ); + else + { + FT_Byte* cur2 = cur + 1; + FT_Int len; + + + while ( cur2 < limit && t42_is_alpha( *cur2 ) ) + cur2++; + len = (FT_Int)( cur2 - cur - 1 ); + + error = T1_Add_Table( name_table, n, cur + 1, len + 1 ); + if ( error ) + goto Fail; + + /* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; + + parser->root.cursor = cur2; + T1_Skip_Spaces( parser ); + + cur2 = cur = parser->root.cursor; + if ( cur >= limit ) + break; + + while ( cur2 < limit && t42_is_alpha( *cur2 ) ) + cur2++; + len = (FT_Int)( cur2 - cur ); + + error = T1_Add_Table( code_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + + code_table->elements[n][len] = '\0'; + + n++; + if ( n >= loader->num_glyphs ) + break; + } + } + + /* Index 0 must be a .notdef element */ + if ( ft_strcmp( (char *)name_table->elements[0], ".notdef" ) ) + { + FT_ERROR(( "t42_parse_charstrings: Index 0 is not `.notdef'!\n" )); + error = FT_Err_Invalid_File_Format; + goto Fail; + } + + loader->num_glyphs = n; + return; + + Fail: + parser->root.error = error; + } + + + static FT_Error + t42_load_keyword( T42_Face face, + T42_Loader loader, + T1_Field field ) + { + FT_Error error; + void* dummy_object; + void** objects; + FT_UInt max_objects = 0; + + + /* if the keyword has a dedicated callback, call it */ + if ( field->type == T1_FIELD_TYPE_CALLBACK ) { + field->reader( (FT_Face)face, loader ); + error = loader->parser.root.error; + goto Exit; + } + + /* now, the keyword is either a simple field, or a table of fields; */ + /* we are now going to take care of it */ + switch ( field->location ) + { + case T1_FIELD_LOCATION_FONT_INFO: + dummy_object = &face->type1.font_info; + objects = &dummy_object; + break; + + default: + dummy_object = &face->type1; + objects = &dummy_object; + } + + if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || + field->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = T1_Load_Field_Table( &loader->parser, field, + objects, max_objects, 0 ); + else + error = T1_Load_Field( &loader->parser, field, + objects, max_objects, 0 ); + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + t42_parse_dict( T42_Face face, + T42_Loader loader, + FT_Byte* base, + FT_Long size ) + { + T42_Parser parser = &loader->parser; + FT_Byte* cur = base; + FT_Byte* limit = cur + size; + FT_UInt n_keywords = sizeof ( t42_keywords ) / + sizeof ( t42_keywords[0] ); + + + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = 0; + + for ( ; cur < limit; cur++ ) + { + /* look for `FontDirectory', which causes problems on some fonts */ + if ( *cur == 'F' && cur + 25 < limit && + ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) + { + FT_Byte* cur2; + + + /* skip the `FontDirectory' keyword */ + cur += 13; + cur2 = cur; + + /* lookup the `known' keyword */ + while ( cur < limit && *cur != 'k' && + ft_strncmp( (char*)cur, "known", 5 ) ) + cur++; + + if ( cur < limit ) + { + T1_TokenRec token; + + + /* skip the `known' keyword and the token following it */ + cur += 5; + loader->parser.root.cursor = cur; + T1_ToToken( &loader->parser, &token ); + + /* if the last token was an array, skip it! */ + if ( token.type == T1_TOKEN_TYPE_ARRAY ) + cur2 = parser->root.cursor; + } + cur = cur2; + } + /* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_Byte* cur2; + FT_UInt i, len; + + + cur++; + cur2 = cur; + while ( cur2 < limit && t42_is_alpha( *cur2 ) ) + cur2++; + + len = (FT_UInt)( cur2 - cur ); + if ( len > 0 && len < 22 ) /* XXX What shall it this 22? */ + { + /* now, compare the immediate name to the keyword table */ + + /* Loop through all known keywords */ + for ( i = 0; i < n_keywords; i++ ) + { + T1_Field keyword = (T1_Field)&t42_keywords[i]; + FT_Byte *name = (FT_Byte*)keyword->ident; + + + if ( !name ) + continue; + + if ( ( len == ft_strlen( (const char *)name ) ) && + ( ft_memcmp( cur, name, len ) == 0 ) ) + { + /* we found it -- run the parsing callback! */ + parser->root.cursor = cur2; + T1_Skip_Spaces( parser ); + parser->root.error = t42_load_keyword(face, + loader, + keyword ); + if ( parser->root.error ) + return parser->root.error; + cur = parser->root.cursor; + break; + } + } + } + } + } + return parser->root.error; + } + + + FT_LOCAL_DEF( void ) + t42_loader_init( T42_Loader loader, + T42_Face face ) + { + FT_UNUSED( face ); + + FT_MEM_SET( loader, 0, sizeof ( *loader ) ); + loader->num_glyphs = 0; + loader->num_chars = 0; + + /* initialize the tables -- simply set their `init' field to 0 */ + loader->encoding_table.init = 0; + loader->charstrings.init = 0; + loader->glyph_names.init = 0; + } + + + FT_LOCAL_DEF( void ) + t42_loader_done( T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + + + /* finalize tables */ + T1_Release_Table( &loader->encoding_table ); + T1_Release_Table( &loader->charstrings ); + T1_Release_Table( &loader->glyph_names ); + + /* finalize parser */ + t42_parser_done( parser ); + } + + + FT_LOCAL_DEF( FT_Error ) + T42_Open_Face( T42_Face face ) + { + T42_LoaderRec loader; + T42_Parser parser; + T1_Font type1 = &face->type1; + FT_Memory memory = face->root.memory; + FT_Error error; + + PSAux_Service psaux = (PSAux_Service)face->psaux; + + + t42_loader_init( &loader, face ); + + parser = &loader.parser; + + if ( FT_ALLOC( face->ttf_data, 12 ) ) + goto Exit; + + error = t42_parser_init( parser, + face->root.stream, + memory, + psaux); + if ( error ) + goto Exit; + + error = t42_parse_dict( face, &loader, parser->base_dict, parser->base_len ); + + if ( type1->font_type != 42 ) + { + error = FT_Err_Unknown_File_Format; + goto Exit; + } + + /* now, propagate the charstrings and glyphnames tables */ + /* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + + if ( !loader.charstrings.init ) { + FT_ERROR(( "T42_Open_Face: no charstrings array in face!\n" )); + error = FT_Err_Invalid_File_Format; + } + + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; + + /* we copy the glyph names `block' and `elements' fields; */ + /* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = 0; + loader.glyph_names.elements = 0; + + /* we must now build type1.encoding when we have a custom array */ + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) + { + FT_Int charcode, idx, min_char, max_char; + FT_Byte* char_name; + FT_Byte* glyph_name; + + + /* OK, we do the following: for each element in the encoding */ + /* table, look up the index of the glyph having the same name */ + /* as defined in the CharStrings array. */ + /* The index is then stored in type1.encoding.char_index, and */ + /* the name in type1.encoding.char_name */ + + min_char = +32000; + max_char = -32000; + + charcode = 0; + for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) + { + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = (char *)".notdef"; + + char_name = loader.encoding_table.elements[charcode]; + if ( char_name ) + for ( idx = 0; idx < type1->num_glyphs; idx++ ) + { + glyph_name = (FT_Byte*)type1->glyph_names[idx]; + if ( ft_strcmp( (const char*)char_name, + (const char*)glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = (FT_UShort)idx; + type1->encoding.char_name [charcode] = (char*)glyph_name; + + /* Change min/max encoded char only if glyph name is */ + /* not /.notdef */ + if ( ft_strcmp( (const char*)".notdef", + (const char*)glyph_name ) != 0 ) + { + if ( charcode < min_char ) min_char = charcode; + if ( charcode > max_char ) max_char = charcode; + } + break; + } + } + } + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + + Exit: + t42_loader_done( &loader ); + return error; + } + diff --git a/src/type42/t42parse.h b/src/type42/t42parse.h new file mode 100644 index 000000000..342298f66 --- /dev/null +++ b/src/type42/t42parse.h @@ -0,0 +1,66 @@ +#ifndef __TYPE42_PARSE_H__ +#define __TYPE42_PARSE_H__ + +#include "t42objs.h" +#include FT_INTERNAL_POSTSCRIPT_AUX_H + +FT_BEGIN_HEADER + + typedef struct T42_ParserRec_ + { + PS_ParserRec root; + FT_Stream stream; + + FT_Byte* base_dict; + FT_Int base_len; + + FT_Byte in_memory; + + } T42_ParserRec, *T42_Parser; + + + typedef struct T42_Loader_ + { + T42_ParserRec parser; /* parser used to read the stream */ + + FT_Int num_chars; /* number of characters in encoding */ + PS_TableRec encoding_table; /* PS_Table used to store the */ + /* encoding character names */ + + FT_Int num_glyphs; + PS_TableRec glyph_names; + PS_TableRec charstrings; + + } T42_LoaderRec, *T42_Loader; + + + FT_LOCAL( FT_Error ) + t42_parser_init( T42_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + + FT_LOCAL( void ) + t42_parser_done( T42_Parser parser ); + + + FT_LOCAL( FT_Error ) + t42_parse_dict( T42_Face face, + T42_Loader loader, + FT_Byte* base, + FT_Long size ); + + + FT_LOCAL( void ) + t42_loader_init( T42_Loader loader, + T42_Face face ); + + FT_LOCAL( void ) + t42_loader_done( T42_Loader loader ); + + + /* */ + +FT_END_HEADER + +#endif /* __TYPE42_PARSE_H__ */ diff --git a/src/type42/type42.c b/src/type42/type42.c new file mode 100644 index 000000000..46d08edb3 --- /dev/null +++ b/src/type42/type42.c @@ -0,0 +1,17 @@ +/***************************************************************************/ +/* */ +/* type42c */ +/* */ +/* FreeType Type 42 driver component */ +/* */ +/***************************************************************************/ + + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include +#include "t42objs.c" +#include "t42parse.c" +#include "t42drivr.c" + +/* END */