diff --git a/CHANGES b/CHANGES index 5c1b7ae4a..6d38c4b1a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,12 @@ LATEST_CHANGES + - added the CID-keyed Type 1 driver in "src/cid". Works pretty well for + only 13 Kb of code ;-) Doesn't read AFM files though, nor the really + useful CMAP files.. + + - fixed two bugs in the smooth renderer (src/base/ftgrays.c). Thanks to + Boris Letocha for spotting them and providing a fix.. + - fixed potential "divide by zero" bugs in ftcalc.c.. my god.. - added source code for the OpenType/CFF driver (still incomplete though..) diff --git a/demos/src/ftlint.c b/demos/src/ftlint.c index 3df69e05e..f442c201d 100644 --- a/demos/src/ftlint.c +++ b/demos/src/ftlint.c @@ -81,6 +81,20 @@ for ( file_index = 2; file_index < argc; file_index++ ) { fname = argv[file_index]; + + /* try to open the file with no extra extension first */ + error = FT_New_Face( library, fname, 0, &face ); + if (!error) goto Success; + + if ( error == FT_Err_Unknown_File_Format ) + { + printf( "unknown format\n" ); + continue; + } + + /* ok, we could not load the file, try to add an extension to */ + /* its name if possible.. */ + i = strlen( fname ); while ( i > 0 && fname[i] != '\\' && fname[i] != '/' ) { @@ -124,7 +138,7 @@ error = FT_New_Face( library, filename, 0, &face ); if (error) { - if (error == FT_Err_Invalid_File_Format) + if (error == FT_Err_Unknown_File_Format) printf( "unknown format\n" ); else printf( "could not find/open file (error: %d)\n", error ); @@ -132,6 +146,7 @@ } if (error) Panic( "Could not open file" ); + Success: num_glyphs = face->num_glyphs; error = FT_Set_Char_Size( face, ptsize << 6, ptsize << 6, 72, 72 ); diff --git a/demos/src/ftstring.c b/demos/src/ftstring.c index 502d527be..1a2d46a3e 100644 --- a/demos/src/ftstring.c +++ b/demos/src/ftstring.c @@ -59,9 +59,9 @@ static grColor fore_color = { 255 }; - static int graph_init = 0; + static int graph_init = 0; static int render_mode = 1; - static int use_grays = 0; + static int use_grays = 1; /* the standard raster's interface */ static FT_Raster_Funcs std_raster; diff --git a/demos/src/ftview.c b/demos/src/ftview.c index c3613cab5..a26598ace 100644 --- a/demos/src/ftview.c +++ b/demos/src/ftview.c @@ -74,7 +74,7 @@ $\243^\250*\265\371%!\247:/;.,?<>"; int graph_init = 0; int render_mode = 1; - int use_grays = 0; + int use_grays = 1; /* the standard raster's interface */ FT_Raster_Funcs std_raster; @@ -618,6 +618,16 @@ $\243^\250*\265\371%!\247:/;.,?<>"; hinted = 1; file_loaded = 0; + filename[128] = '\0'; + alt_filename[128] = '\0'; + + strncpy( filename, argv[file], 128 ); + strncpy( alt_filename, argv[file], 128 ); + + /* try to load the file name as is, first */ + error = FT_New_Face( library, argv[file], 0, &face ); + if (!error) goto Success; + #ifndef macintosh i = strlen( argv[file] ); while ( i > 0 && argv[file][i] != '\\' && argv[file][i] != '/' ) @@ -628,12 +638,6 @@ $\243^\250*\265\371%!\247:/;.,?<>"; } #endif - filename[128] = '\0'; - alt_filename[128] = '\0'; - - strncpy( filename, argv[file], 128 ); - strncpy( alt_filename, argv[file], 128 ); - #ifndef macintosh if ( i >= 0 ) { @@ -647,6 +651,7 @@ $\243^\250*\265\371%!\247:/;.,?<>"; error = FT_New_Face( library, filename, 0, &face ); if (error) goto Display_Font; + Success: file_loaded++; error = Reset_Scale( ptsize ); diff --git a/include/freetype/config/ftmodule.h b/include/freetype/config/ftmodule.h index d5e4d0741..910866330 100644 --- a/include/freetype/config/ftmodule.h +++ b/include/freetype/config/ftmodule.h @@ -1,4 +1,5 @@ FT_DRIVER(cff_driver_interface) +FT_DRIVER(t1cid_driver_interface) FT_DRIVER(psnames_driver_interface) FT_DRIVER(sfnt_driver_interface) FT_DRIVER(tt_driver_interface) diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h index 3c6bb46b3..efadfc72d 100644 --- a/include/freetype/config/ftoption.h +++ b/include/freetype/config/ftoption.h @@ -394,6 +394,12 @@ /* */ #undef T1_CONFIG_OPTION_NO_AFM - +/*******************************************************************/ +/* Define this configuration macro if you want to prevent the */ +/* compilation of the multiple-masters support in the Type 1 driver*/ +/* AFM files into an existing face. Note that when set, the T1 */ +/* driver will be unable to produce kerning distances.. */ +/* */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT #endif /* FTOPTION_H */ diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h index ca99034c0..42ef50595 100644 --- a/include/freetype/freetype.h +++ b/include/freetype/freetype.h @@ -612,6 +612,7 @@ FT_CharMap charmap; FT_ListRec sizes_list; + void* autohint_globals; void* extensions; FT_UShort max_points; @@ -934,11 +935,15 @@ /* FT_Load_Glyph() API function) and can be expressed */ /* either in 26.6 fractional pixels or font units. */ /* */ - /* metrics2 :: This field can be used to return alternate glyph */ - /* metrics after a single load. It can contain either */ - /* the glyph's metrics in font units, or the scaled but */ - /* unhinted ones. See the load flags that apply when */ - /* calling the API function FT_Load_Glyph(). */ + /* metrics2 :: This field is used to return alternate glyph metrics */ + /* for scalable formats. Only four fields in it are */ + /* valid: horiBearingX, horiAdvance, vertBearingY and */ + /* vertAdvance. All other fields should be ignored. */ + /* By default, it contains the glyph metrics expressed */ + /* in font units. However, when FT_Load_Glyph() is called */ + /* with FT_LOAD_LINEAR set, the metrics are expressed */ + /* in 16.16 unhinted pixel values.. This can be useful */ + /* to perform WYSIWYG glyph layout.. */ /* */ /* generic :: A typeless pointer which is unused by the FreeType */ /* library or any of its drivers. It can be used by */ @@ -955,7 +960,6 @@ /* loaded glyph can be retrieved through the result value */ /* returned by FT_Load_Glyph(). */ /* */ - /* */ enum { diff --git a/include/freetype/internal/t1types.h b/include/freetype/internal/t1types.h index c1cf24135..e089aec32 100644 --- a/include/freetype/internal/t1types.h +++ b/include/freetype/internal/t1types.h @@ -344,6 +344,13 @@ } T1_Font; + typedef struct CID_Subrs_ + { + FT_UInt num_subrs; + FT_Byte** code; + + } CID_Subrs; + /*************************************************************************/ /*************************************************************************/ @@ -372,7 +379,7 @@ typedef struct T1_FaceRec_* T1_Face; - + typedef struct CID_FaceRec_* CID_Face; /***************************************************/ /* */ @@ -397,4 +404,13 @@ } T1_FaceRec; + typedef struct CID_FaceRec_ + { + FT_FaceRec root; + void* psnames; + CID_Info cid; + CID_Subrs* subrs; + + } CID_FaceRec; + #endif /* T1TYPES_H */ diff --git a/include/freetype/t1tables.h b/include/freetype/t1tables.h index 61187a287..479c2d587 100644 --- a/include/freetype/t1tables.h +++ b/include/freetype/t1tables.h @@ -69,7 +69,7 @@ FT_Int unique_id; FT_Int lenIV; - FT_Byte num_blues; + FT_Byte num_blue_values; FT_Byte num_other_blues; FT_Byte num_family_blues; FT_Byte num_family_other_blues; @@ -92,8 +92,8 @@ FT_Bool force_bold; FT_Bool round_stem_up; - FT_Short stem_snap_widths [13]; /* reserve one place for the std */ - FT_Short stem_snap_heights[13]; /* reserve one place for the std */ + FT_Short snap_widths [13]; /* reserve one place for the std */ + FT_Short snap_heights[13]; /* reserve one place for the std */ FT_Long language_group; FT_Long password; @@ -181,9 +181,17 @@ typedef struct CID_FontDict_ { - T1_FontInfo font_info; T1_Private private_dict; + FT_UInt len_buildchar; + FT_Fixed forcebold_threshold; + FT_Pos stroke_width; + FT_Fixed expansion_factor; + + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_UInt num_subrs; FT_ULong subrmap_offset; FT_Int sd_bytes; @@ -201,6 +209,8 @@ FT_String* ordering; FT_Int supplement; + T1_FontInfo font_info; + FT_BBox font_bbox; FT_ULong uid_base; FT_Int num_xuid; @@ -212,9 +222,11 @@ FT_Int gd_bytes; FT_ULong cid_count; - FT_Int num_font_dicts; + FT_Int num_dicts; CID_FontDict* font_dicts; + FT_ULong data_offset; + } CID_Info; diff --git a/src/base/ftgrays.c b/src/base/ftgrays.c index a3003915e..2ebf2481e 100644 --- a/src/base/ftgrays.c +++ b/src/base/ftgrays.c @@ -300,7 +300,7 @@ /* in during the render phase. This means that: */ /* */ /* . the new vertical position must be within min_ey..max_ey - 1. */ - /* . the new horizontal position must be strictly less than max_ey */ + /* . the new horizontal position must be strictly less than max_ex */ /* */ /* Note that if a cell is to the left of the clipping region, it is */ /* actually set to the (min_ex-1) horizontal position. */ @@ -1198,7 +1198,7 @@ coverage = -coverage; while ( coverage >= 512 ) - coverage -= 512; + coverage = 512-coverage; if ( coverage > 256 ) coverage = 0; @@ -1216,6 +1216,7 @@ } y += ras.min_ey; + x += ras.min_ex; if ( coverage ) { @@ -1330,9 +1331,9 @@ else { /* draw a gray span until the end of the clipping region */ - if ( cover && x < ras.max_ex ) + if ( cover && x < ras.max_ex - ras.min_ex ) grays_hline( RAS_VAR_ x, y, - cover * ( ONE_PIXEL * 2 ), ras.max_ex - x ); + cover * ( ONE_PIXEL * 2 ), ras.max_ex - x - ras.min_ex ); cover = 0; } diff --git a/src/cid/cidafm.c b/src/cid/cidafm.c new file mode 100644 index 000000000..48282f991 --- /dev/null +++ b/src/cid/cidafm.c @@ -0,0 +1,228 @@ +/*************************************************************************** + * + * t1afm.c - support for reading Type 1 AFM files + * + * + ***************************************************************************/ + +#include +#include +#include +#include /* for qsort */ + + LOCAL_FUNC + void CID_Done_AFM( FT_Memory memory, T1_AFM* afm ) + { + FREE( afm->kern_pairs ); + afm->num_pairs = 0; + } + +#undef IS_KERN_PAIR +#define IS_KERN_PAIR(p) ( p[0] == 'K' && p[1] == 'P' ) + +#define IS_ALPHANUM(c) ( (c >= 'A' && c <= 'Z') || \ + (c >= 'a' && c <= 'z') || \ + (c >= '0' && c <= '9') || \ + (c == '_' && c == '.') ) + + /* read a glyph name and return the equivalent glyph index */ + static + FT_UInt afm_atoindex( FT_Byte* *start, FT_Byte* limit, T1_Font* type1 ) + { + FT_Byte* p = *start; + FT_Int len; + FT_UInt result = 0; + char temp[64]; + + /* skip whitespace */ + while ( (*p == ' ' || *p == '\t' || *p == ':' || *p == ';') && p < limit ) + p++; + *start = p; + + /* now, read glyph name */ + while ( IS_ALPHANUM(*p) && p < limit ) p++; + len = p - *start; + if (len > 0 && len < 64) + { + FT_Int n; + + /* copy glyph name to intermediate array */ + MEM_Copy( temp, *start, len ); + temp[len] = 0; + + /* lookup glyph name in face array */ + for ( n = 0; n < type1->num_glyphs; n++ ) + { + char* gname = (char*)type1->glyph_names[n]; + + if ( gname && gname[0] == temp[0] && strcmp(gname,temp) == 0 ) + { + result = n; + break; + } + } + } + *start = p; + return result; + } + + + /* read an integer */ + static + int afm_atoi( FT_Byte** start, FT_Byte* limit ) + { + FT_Byte* p = *start; + int sum = 0; + int sign = 1; + + /* skip everything that is not a number */ + while ( p < limit && (*p < '0' || *p > '9') ) + { + sign = 1; + if (*p == '-') + sign = -1; + + p++; + } + + while ( p < limit && (*p >= '0' && *p < '9') ) + { + sum = sum*10 + (*p - '0'); + p++; + } + *start = p; + return sum*sign; + } + + +#undef KERN_INDEX +#define KERN_INDEX(g1,g2) (((FT_ULong)g1 << 16) | g2) + + /* compare two kerning pairs */ + static + int compare_kern_pairs( const void* a, const void* b ) + { + T1_Kern_Pair* pair1 = (T1_Kern_Pair*)a; + T1_Kern_Pair* pair2 = (T1_Kern_Pair*)b; + + FT_ULong index1 = KERN_INDEX(pair1->glyph1,pair1->glyph2); + FT_ULong index2 = KERN_INDEX(pair2->glyph1,pair2->glyph2); + + return ( index1 - index2 ); + } + + + /* parse an AFM file - for now, only read the kerning pairs */ + LOCAL_FUNC + FT_Error CID_Read_AFM( FT_Face t1_face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* p; + FT_Int count = 0; + T1_Kern_Pair* pair; + T1_Font* type1 = &((T1_Face)t1_face)->type1; + T1_AFM* afm = 0; + + if ( ACCESS_Frame(stream->size) ) + return error; + + start = (FT_Byte*)stream->cursor; + limit = (FT_Byte*)stream->limit; + p = start; + + /* we are now going to count the occurences of "KP" or "KPX" in */ + /* the AFM file.. */ + count = 0; + for ( p = start; p < limit-3; p++ ) + { + if ( IS_KERN_PAIR(p) ) + count++; + } + + /* Actually, kerning pairs are simply optional !! */ + if (count == 0) + goto Exit; + + /* allocate the pairs */ + if ( ALLOC( afm, sizeof(*afm ) ) || + ALLOC_ARRAY( afm->kern_pairs, count, T1_Kern_Pair ) ) + goto Exit; + + /* now, read each kern pair */ + pair = afm->kern_pairs; + afm->num_pairs = count; + + /* save in face object */ + ((T1_Face)t1_face)->afm_data = afm; + + for ( p = start; p < limit-3; p++ ) + { + if ( IS_KERN_PAIR(p) ) + { + FT_Byte* q; + + /* skip keyword (KP or KPX) */ + q = p+2; + if (*q == 'X') q++; + + pair->glyph1 = afm_atoindex( &q, limit, type1 ); + pair->glyph2 = afm_atoindex( &q, limit, type1 ); + pair->kerning.x = afm_atoi( &q, limit ); + + pair->kerning.y = 0; + if ( p[2] != 'X' ) + pair->kerning.y = afm_atoi( &q, limit ); + + pair++; + } + } + + /* now, sort the kern pairs according to their glyph indices */ + qsort( afm->kern_pairs, count, sizeof(T1_Kern_Pair), compare_kern_pairs ); + + Exit: + if (error) + FREE( afm ); + + FORGET_Frame(); + return error; + } + + + /* find the kerning for a given glyph pair */ + LOCAL_FUNC + void CID_Get_Kerning( T1_AFM* afm, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + T1_Kern_Pair *min, *mid, *max; + FT_ULong index = KERN_INDEX(glyph1,glyph2); + + /* simple binary search */ + min = afm->kern_pairs; + max = min + afm->num_pairs-1; + + while (min <= max) + { + FT_ULong midi; + + mid = min + (max-min)/2; + midi = KERN_INDEX(mid->glyph1,mid->glyph2); + if ( midi == index ) + { + *kerning = mid->kerning; + return; + } + + if ( midi < index ) min = mid+1; + else max = mid-1; + } + kerning->x = 0; + kerning->y = 0; + } + diff --git a/src/cid/cidafm.h b/src/cid/cidafm.h new file mode 100644 index 000000000..ad4fe2fe4 --- /dev/null +++ b/src/cid/cidafm.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * + * t1afm.h - support for reading Type 1 AFM files + * + * + ***************************************************************************/ + +#ifndef T1AFM_H +#define T1AFM_H + +#include + +/* In this version, we only read the kerning table from the */ +/* AFM file. We may add support for ligatures a bit later.. */ + +typedef struct T1_Kern_Pair_ +{ + FT_UInt glyph1; + FT_UInt glyph2; + FT_Vector kerning; + +} T1_Kern_Pair; + + +typedef struct T1_AFM_ +{ + FT_Int num_pairs; + T1_Kern_Pair* kern_pairs; + +} T1_AFM; + +#if 0 + +LOCAL_DEF +FT_Error CID_Read_AFM( FT_Face face, + FT_Stream stream ); + +LOCAL_DEF +void CID_Done_AFM( FT_Memory memory, + T1_AFM* afm ); + +LOCAL_DEF +void CID_Get_Kerning( T1_AFM* afm, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); +#endif + +#endif /* T1AFM_H */ diff --git a/src/cid/cidgload.c b/src/cid/cidgload.c new file mode 100644 index 000000000..03a61d25c --- /dev/null +++ b/src/cid/cidgload.c @@ -0,0 +1,1484 @@ +/******************************************************************* + * + * cidgload.c 1.0 + * + * CID-Keyed Type1 Glyph Loader. + * + * Copyright 1996-1999 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. + * + ******************************************************************/ + +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1gload + + /* forward */ + static + FT_Error cid_load_glyph( CID_Decoder* decoder, FT_UInt glyph_index ); + + + typedef enum T1_Operator_ + { + op_none = 0, + op_endchar, + op_hsbw, + op_seac, + op_sbw, + op_closepath, + op_hlineto, + op_hmoveto, + op_hvcurveto, + op_rlineto, + op_rmoveto, + op_rrcurveto, + op_vhcurveto, + op_vlineto, + op_vmoveto, + op_dotsection, + op_hstem, + op_hstem3, + op_vstem, + op_vstem3, + op_div, + op_callothersubr, + op_callsubr, + op_pop, + op_return, + op_setcurrentpoint, + + op_max /* never remove this one */ + + } T1_Operator; + + static const FT_Int t1_args_count[ op_max ] = + { + 0, /* none */ + 0, /* endchar */ + 2, /* hsbw */ + 5, /* seac */ + 4, /* sbw */ + 0, /* closepath */ + 1, /* hlineto */ + 1, /* hmoveto */ + 4, /* hvcurveto */ + 2, /* rlineto */ + 2, /* rmoveto */ + 6, /* rrcurveto */ + 4, /* vhcurveto */ + 1, /* vlineto */ + 1, /* vmoveto */ + 0, /* dotsection */ + 2, /* hstem */ + 6, /* hstem3 */ + 2, /* vstem */ + 6, /* vstem3 */ + 2, /* div */ + -1, /* callothersubr */ + 1, /* callsubr */ + 0, /* pop */ + 0, /* return */ + 2 /* setcurrentpoint */ + }; + + + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + /********** *********/ + /********** *********/ + /********** GENERIC CHARSTRINGS PARSING *********/ + /********** *********/ + /********** *********/ + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + +/********************************************************************* + * + * + * CID_Init_Builder + * + * + * Initialise a given glyph builder. + * + * + * builder :: glyph builder to initialise + * face :: current face object + * size :: current size object + * glyph :: current glyph object + * + *********************************************************************/ + + LOCAL_FUNC + void CID_Init_Builder( CID_Builder* builder, + CID_Face face, + T1_Size size, + T1_GlyphSlot glyph ) + { + builder->path_begun = 0; + builder->load_points = 1; + + builder->face = face; + builder->glyph = glyph; + builder->memory = face->root.memory; + + if (glyph) + { + builder->base = glyph->root.outline; + builder->max_points = glyph->max_points; + builder->max_contours = glyph->max_contours; + } + + if (size) + { + builder->scale_x = size->root.metrics.x_scale; + builder->scale_y = size->root.metrics.y_scale; + } + + builder->pos_x = 0; + builder->pos_y = 0; + + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + + builder->base.n_points = 0; + builder->base.n_contours = 0; + builder->current = builder->base; + } + + +/********************************************************************* + * + * + * CID_Done_Builder + * + * + * Finalise a given glyph builder. Its content can still be + * used after the call, but the function saves important information + * within the corresponding glyph slot. + * + * + * builder :: glyph builder to initialise + * + *********************************************************************/ + + LOCAL_FUNC + void CID_Done_Builder( CID_Builder* builder ) + { + T1_GlyphSlot glyph = builder->glyph; + + if (glyph) + { + glyph->root.outline = builder->base; + glyph->max_points = builder->max_points; + glyph->max_contours = builder->max_contours; + } + } + + + +/********************************************************************* + * + * + * CID_Init_Decoder + * + * + * Initialise a given Type 1 decoder for parsing + * + * + * decoder :: Type 1 decoder to initialise + * funcs :: hinter functions interface + * + *********************************************************************/ + + LOCAL_FUNC + void CID_Init_Decoder( CID_Decoder* decoder ) + { + MEM_Set( decoder, 0, sizeof(*decoder) ); + decoder->font_matrix.xx = 0x10000; + decoder->font_matrix.yy = 0x10000; + } + + + + /* check that there is enough room for "count" more points */ + static + FT_Error check_points( CID_Builder* builder, + FT_Int count ) + { + FT_Outline* base = &builder->base; + FT_Outline* outline = &builder->current; + + if (!builder->load_points) + return T1_Err_Ok; + + count += base->n_points + outline->n_points; + + /* realloc points table if necessary */ + if ( count >= builder->max_points ) + { + FT_Error error; + FT_Memory memory = builder->memory; + FT_Int increment = outline->points - base->points; + FT_Int current = builder->max_points; + + while ( builder->max_points < count ) + builder->max_points += 8; + + if ( REALLOC_ARRAY( base->points, current, + builder->max_points, T1_Vector ) || + + REALLOC_ARRAY( base->tags, current, + builder->max_points, FT_Byte ) ) + { + builder->error = error; + return error; + } + + outline->points = base->points + increment; + outline->tags = base->tags + increment; + } + return T1_Err_Ok; + } + + + /* add a new point, do not check room */ + static + void add_point( CID_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = &builder->current; + + if (builder->load_points) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + + point->x = x; + point->y = y; + *control = ( flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic ); + + builder->last = *point; + } + + outline->n_points++; + } + + + /* check room for a new on-curve point, then add it */ + static + FT_Error add_point1( CID_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + + error = check_points(builder,1); + if (!error) + add_point( builder, x, y, 1 ); + + return error; + } + + + /* check room for a new contour, then add it */ + static + FT_Error add_contour( CID_Builder* builder ) + { + FT_Outline* base = &builder->base; + FT_Outline* outline = &builder->current; + + if (!builder->load_points) + { + outline->n_contours++; + return T1_Err_Ok; + } + + /* realloc contours array if necessary */ + if ( base->n_contours + outline->n_contours >= builder->max_contours && + builder->load_points ) + { + FT_Error error; + FT_Memory memory = builder->memory; + FT_Int increment = outline->contours - base->contours; + FT_Int current = builder->max_contours; + + builder->max_contours += 4; + + if ( REALLOC_ARRAY( base->contours, + current, builder->max_contours, FT_Short ) ) + { + builder->error = error; + return error; + } + + outline->contours = base->contours + increment; + } + + if (outline->n_contours > 0) + outline->contours[ outline->n_contours-1 ] = outline->n_points-1; + + outline->n_contours++; + return T1_Err_Ok; + } + + /* if a path was begun, add its first on-curve point */ + static + FT_Error start_point( CID_Builder* builder, + T1_Pos x, + T1_Pos y ) + { + /* test wether we're building a new contour */ + if (!builder->path_begun) + { + FT_Error error; + + builder->path_begun = 1; + error = add_contour( builder ); + if (error) return error; + } + return add_point1( builder, x, y ); + } + + + /* close the current contour */ + static + void close_contour( CID_Builder* builder ) + { + FT_Outline* outline = &builder->current; + + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours-1] = outline->n_points-1; + } + +#if 0 +/********************************************************************* + * + * + * lookup_glyph_by_stdcharcode + * + * + * Lookup a given glyph by its StandardEncoding charcode. Used + * to implement the SEAC Type 1 operator. + * + * + * face :: current face object + * charcode :: charcode to look for + * + * + * glyph index in font face. Returns -1 if the corresponding + * glyph wasn't found. + * + *********************************************************************/ + + static + FT_Int lookup_glyph_by_stdcharcode( CID_Face face, + FT_Int charcode ) + { + FT_Int n; + const FT_String* glyph_name; + PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; + + /* check range of standard char code */ + if (charcode < 0 || charcode > 255) + return -1; + + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode]); + + for ( n = 0; n < face->cid.cid_count; n++ ) + { + T1_String* name = (T1_String*)face->type1.glyph_names[n]; + + if ( name && strcmp(name,glyph_name) == 0 ) + return n; + } + + return -1; + } +#endif + + +/********************************************************************* + * + * + * t1operator_seac + * + * + * Implements the "seac" Type 1 operator for a Type 1 decoder + * + * + * decoder :: current Type 1 decoder + * asb :: accent's side bearing + * adx :: horizontal position of accent + * ady :: vertical position of accent + * bchar :: base character's StandardEncoding charcode + * achar :: accent character's StandardEncoding charcode + * + * + * Error code. 0 means success. + * + *********************************************************************/ + + static + FT_Error t1operator_seac( CID_Decoder* decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + FT_Int bchar_index, achar_index, n_base_points; + FT_Outline* cur = &decoder->builder.current; + FT_Outline* base = &decoder->builder.base; + FT_Vector left_bearing, advance; + + bchar_index = bchar; + achar_index = achar; + + if (bchar_index < 0 || achar_index < 0) + { + FT_ERROR(( "T1.Parse_Seac : invalid seac character code arguments\n" )); + return T1_Err_Syntax_Error; + } + + /* First load "bchar" in builder */ + /* now load the unscaled outline */ + cur->n_points = 0; + cur->n_contours = 0; + cur->points = base->points + base->n_points; + cur->tags = base->tags + base->n_points; + cur->contours = base->contours + base->n_contours; + + error = cid_load_glyph( decoder, bchar_index ); + if (error) return error; + + n_base_points = cur->n_points; + + if ( decoder->builder.no_recurse ) + { + /* if we're trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs.. */ + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_SubGlyph* subg; + + /* reallocate subglyph array if necessary */ + if (glyph->max_subglyphs < 2) + { + FT_Memory memory = decoder->builder.face->root.memory; + + if ( REALLOC_ARRAY( glyph->subglyphs, glyph->max_subglyphs, + 2, FT_SubGlyph ) ) + return error; + + glyph->max_subglyphs = 2; + } + + subg = glyph->subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = adx - asb; + subg->arg2 = ady; + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->format = ft_glyph_format_composite; + } + else + { + /* save the left bearing and width of the base character */ + /* as they will be erase by the next load.. */ + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + + decoder->builder.left_bearing.x = 0; + decoder->builder.left_bearing.y = 0; + + /* Now load "achar" on top of */ + /* the base outline */ + /* */ + cur->n_points = 0; + cur->n_contours = 0; + cur->points = base->points + base->n_points; + cur->tags = base->tags + base->n_points; + cur->contours = base->contours + base->n_contours; + + error = cid_load_glyph( decoder, achar_index ); + if (error) return error; + + /* adjust contours in accented character outline */ + if (decoder->builder.load_points) + { + FT_Int n; + + for ( n = 0; n < cur->n_contours; n++ ) + cur->contours[n] += n_base_points; + } + + /* restore the left side bearing and */ + /* advance width of the base character */ + decoder->builder.left_bearing = left_bearing; + decoder->builder.advance = advance; + + /* Finally, move the accent */ + if (decoder->builder.load_points) + FT_Outline_Translate( cur, adx - asb, ady ); + } + return T1_Err_Ok; + } + +/********************************************************************* + * + * + * CID_Parse_CharStrings + * + * + * Parses a given Type 1 charstrings program + * + * + * decoder :: current Type 1 decoder + * charstring_base :: base of the charstring stream + * charstring_len :: length in bytes of the charstring stream + * num_subrs :: number of sub-routines + * subrs_base :: array of sub-routines addresses + * subrs_len :: array of sub-routines lengths + * + * + * Error code. 0 means success. + * + *********************************************************************/ + +#define USE_ARGS(n) top -= n; if (top < decoder->stack) goto Stack_Underflow + + LOCAL_FUNC + FT_Error CID_Parse_CharStrings( CID_Decoder* decoder, + FT_Byte* charstring_base, + FT_Int charstring_len ) + { + FT_Error error; + CID_Decoder_Zone* zone; + FT_Byte* ip; + FT_Byte* limit; + CID_Builder* builder = &decoder->builder; + FT_Outline* outline; + T1_Pos x, y; + + /* First of all, initialise the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->path_begun = 0; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = T1_Err_Ok; + outline = &builder->current; + + x = builder->pos_x; + y = builder->pos_y; + + /* now, execute loop */ + while ( ip < limit ) + { + FT_Int* top = decoder->top; + T1_Operator op = op_none; + FT_Long value = 0; + + /********************************************************************/ + /* */ + /* Decode operator or operand */ + /* */ + /* */ + + /* First of all, decompress operator or value */ + switch (*ip++) + { + case 1: op = op_hstem; break; + + case 3: op = op_vstem; break; + case 4: op = op_vmoveto; break; + case 5: op = op_rlineto; break; + case 6: op = op_hlineto; break; + case 7: op = op_vlineto; break; + case 8: op = op_rrcurveto; break; + case 9: op = op_closepath; break; + case 10: op = op_callsubr; break; + case 11: op = op_return; break; + + case 13: op = op_hsbw; break; + case 14: op = op_endchar; break; + + case 21: op = op_rmoveto; break; + case 22: op = op_hmoveto; break; + + case 30: op = op_vhcurveto; break; + case 31: op = op_hvcurveto; break; + + case 12: + { + if (ip > limit) + { + FT_ERROR(( "T1.Parse_CharStrings : invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch (*ip++) + { + case 0: op = op_dotsection; break; + case 1: op = op_vstem3; break; + case 2: op = op_hstem3; break; + case 6: op = op_seac; break; + case 7: op = op_sbw; break; + case 12: op = op_div; break; + case 16: op = op_callothersubr; break; + case 17: op = op_pop; break; + case 33: op = op_setcurrentpoint; break; + + default: + FT_ERROR(( "T1.Parse_CharStrings : invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + } + break; + + case 255: /* four bytes integer */ + { + if (ip+4 > limit) + { + FT_ERROR(( "T1.Parse_CharStrings : unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = ((long)ip[0] << 24) | + ((long)ip[1] << 16) | + ((long)ip[2] << 8) | + ip[3]; + ip += 4; + } + break; + + default: + if (ip[-1] >= 32) + { + if (ip[-1] < 247) + value = (long)ip[-1] - 139; + else + { + if (++ip > limit) + { + FT_ERROR(( "T1.Parse_CharStrings : unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if (ip[-2] < 251) + value = ((long)(ip[-2]-247) << 8) + ip[-1] + 108; + else + value = -((((long)ip[-2]-251) << 8) + ip[-1] + 108 ); + } + } + else + { + FT_ERROR(( "T1.Parse_CharStrings : invalid byte (%d)\n", + ip[-1] )); + goto Syntax_Error; + } + } + + /********************************************************************/ + /* */ + /* Push value on stack, or process operator */ + /* */ + /* */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "T1.Parse_CharStrings : Stack overflow !!\n" )); + goto Syntax_Error; + } + + FT_TRACE4(( " %ld", value )); + *top++ = value; + decoder->top = top; + } + else if ( op == op_callothersubr ) /* callothersubr */ + { + FT_TRACE4(( " callothersubr" )); + if ( top - decoder->stack < 2 ) + goto Stack_Underflow; + + top -= 2; + switch ( top[1] ) + { + case 1: /* start flex feature ---------------------- */ + { + if ( top[0] != 0 ) goto Unexpected_OtherSubr; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + if ( start_point(builder, x, y) || + check_points(builder,6) ) goto Memory_Error; + } + break; + + case 2: /* add flex vectors ------------------------ */ + { + FT_Int index; + + if ( top[0] != 0 ) goto Unexpected_OtherSubr; + + /* note that we should not add a point for index 0 */ + /* this will move our current position to the flex */ + /* point without adding any point to the outline */ + index = decoder->num_flex_vectors++; + if (index > 0 && index < 7) + add_point( builder, + x, + y, + (FT_Byte)( index==3 || index==6 ) ); + } + break; + + case 0: /* end flex feature ------------------------- */ + { + if ( top[0] != 3 ) goto Unexpected_OtherSubr; + + if ( decoder->flex_state == 0 || + decoder->num_flex_vectors != 7 ) + { + FT_ERROR(( "T1.Parse_CharStrings: unexpected flex end\n" )); + goto Syntax_Error; + } + + /* now consume the remaining "pop pop setcurpoint" */ + if ( ip+6 > limit || + ip[0] != 12 || ip[1] != 17 || /* pop */ + ip[2] != 12 || ip[3] != 17 || /* pop */ + ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */ + { + FT_ERROR(( "T1.Parse_CharStrings: invalid flex charstring\n" )); + goto Syntax_Error; + } + + ip += 6; + decoder->flex_state = 0; + break; + } + + case 3: /* change hints ---------------------------- */ + { + if ( top[0] != 1 ) goto Unexpected_OtherSubr; + + /* eat the following "pop" */ + if (ip+2 > limit) + { + FT_ERROR(( "T1.Parse_CharStrings: invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + + if (ip[0] != 12 || ip[1] != 17) + { + FT_ERROR(( "T1.Parse_CharStrings: 'pop' expected, found (%d %d)\n", + ip[0], ip[1] )); + goto Syntax_Error; + } + ip += 2; + break;; + } + + case 12: + case 13: + { + /* counter control hints, clear stack */ + top = decoder->stack; + break; + } +#if 0 + case 14: + case 15: + case 16: + case 17: + case 18: /* multiple masters */ + { + T1_Blend* blend = decoder->blend; + FT_UInt num_points, nn, mm; + FT_Int* delta; + FT_Int* values; + + if (!blend) + { + FT_ERROR(( "T1.Parse_CharStrings: unexpected multiple masters operator !!\n" )); + goto Syntax_Error; + } + + num_points = top[1] - 13 + (top[1] == 18); + if (top[0] != num_points*blend->num_designs) + { + FT_ERROR(( "T1.Parse_CharStrings: incorrect number of mm arguments\n" )); + goto Syntax_Error; + } + + top -= blend->num_designs*num_points; + if (top < decoder->stack) + goto Stack_Underflow; + + /* we want to compute: */ + /* */ + /* a0*w0 + a1*w1 + ... + ak*wk */ + /* */ + /* but we only have the a0, a1-a0, a2-a0, .. ak-a0 */ + /* however, given that w0 + w1 + ... + wk == 1, we can */ + /* rewrite it easily as: */ + /* */ + /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */ + /* */ + /* where k == num_designs-1 */ + /* */ + /* I guess that's why it's written in this "compact" */ + /* form.. */ + /* */ + /* */ + delta = top + num_points; + values = top; + for ( nn = 0; nn < num_points; nn++ ) + { + FT_Int x = values[0]; + for ( mm = 1; mm < blend->num_designs; mm++ ) + x += FT_MulFix( *delta++, blend->weight_vector[mm] ); + + *values++ = x; + } + /* note that "top" will be incremented later by calls to "pop" */ + break; + } +#endif + default: + Unexpected_OtherSubr: + FT_ERROR(( "T1.Parse_CharStrings: invalid othersubr [%d %d]!!\n", + top[0], top[1] )); + goto Syntax_Error; + } + decoder->top = top; + } + else /* general operator */ + { + FT_Int num_args = t1_args_count[op]; + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + + top -= num_args; + + switch (op) + { + case op_endchar: /*************************************************/ + { + FT_TRACE4(( " endchar" )); + close_contour( builder ); + + /* add current outline to the glyph slot */ + builder->base.n_points += builder->current.n_points; + builder->base.n_contours += builder->current.n_contours; + + /* return now !! */ + FT_TRACE4(( "\n\n" )); + return T1_Err_Ok; + } + + + case op_hsbw: /****************************************************/ + { + FT_TRACE4(( " hsbw" )); + builder->left_bearing.x += top[0]; + builder->advance.x = top[1]; + builder->advance.y = 0; + + builder->last.x = x = top[0]; + builder->last.y = y = 0; + + /* the "metrics_only" indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it.. so exit immediately */ + if (builder->metrics_only) + return T1_Err_Ok; + + break; + } + + + case op_seac: /****************************************************/ + /* return immediately after the processing */ + return t1operator_seac( decoder, top[0], top[1], + top[2], top[3], top[4] ); + + case op_sbw: /****************************************************/ + { + FT_TRACE4(( " sbw" )); + builder->left_bearing.x += top[0]; + builder->left_bearing.y += top[1]; + builder->advance.x = top[2]; + builder->advance.y = top[3]; + + builder->last.x = x = top[0]; + builder->last.y = y = top[1]; + + /* the "metrics_only" indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it.. so exit immediately */ + if (builder->metrics_only) + return T1_Err_Ok; + + break; + } + + + case op_closepath: /**********************************************/ + { + FT_TRACE4(( " closepath" )); + close_contour( builder ); + builder->path_begun = 0; + } + break; + + + case op_hlineto: /************************************************/ + { + FT_TRACE4(( " hlineto" )); + if ( start_point( builder, x, y ) ) goto Memory_Error; + + x += top[0]; + goto Add_Line; + } + + + case op_hmoveto: /************************************************/ + { + FT_TRACE4(( " hmoveto" )); + x += top[0]; + break; + } + + + case op_hvcurveto: /**********************************************/ + { + FT_TRACE4(( " hvcurveto" )); + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) goto Memory_Error; + + x += top[0]; + add_point( builder, x, y, 0 ); + x += top[1]; + y += top[2]; + add_point( builder, x, y, 0 ); + y += top[3]; + add_point( builder, x, y, 1 ); + break; + } + + + case op_rlineto: /*************************************************/ + { + FT_TRACE4(( " rlineto" )); + if ( start_point( builder, x, y ) ) goto Memory_Error; + + x += top[0]; + y += top[1]; + Add_Line: + if (add_point1( builder, x, y )) goto Memory_Error; + break; + } + + + case op_rmoveto: /*************************************************/ + { + FT_TRACE4(( " rmoveto" )); + x += top[0]; + y += top[1]; + break; + } + + case op_rrcurveto: /***********************************************/ + { + FT_TRACE4(( " rcurveto" )); + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) goto Memory_Error; + + x += top[0]; + y += top[1]; + add_point( builder, x, y, 0 ); + + x += top[2]; + y += top[3]; + add_point( builder, x, y, 0 ); + + x += top[4]; + y += top[5]; + add_point( builder, x, y, 1 ); + break; + } + + + case op_vhcurveto: /**********************************************/ + { + FT_TRACE4(( " vhcurveto" )); + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) goto Memory_Error; + + y += top[0]; + add_point( builder, x, y, 0 ); + x += top[1]; + y += top[2]; + add_point( builder, x, y, 0 ); + x += top[3]; + add_point( builder, x, y, 1 ); + break; + } + + + case op_vlineto: /************************************************/ + { + FT_TRACE4(( " vlineto" )); + if ( start_point( builder, x, y ) ) goto Memory_Error; + + y += top[0]; + goto Add_Line; + } + + + case op_vmoveto: /************************************************/ + { + FT_TRACE4(( " vmoveto" )); + y += top[0]; + break; + } + + + case op_div: /****************************************************/ + { + FT_TRACE4(( " div" )); + if (top[1]) + *top++ = top[0] / top[1]; + else + { + FT_ERROR(( "T1.Parse_CharStrings : division by 0\n" )); + goto Syntax_Error; + } + break; + } + + + case op_callsubr: /***********************************************/ + { + FT_Int index; + + FT_TRACE4(( " callsubr" )); + index = top[0]; + if ( index < 0 || index >= decoder->subrs->num_subrs ) + { + FT_ERROR(( "T1.Parse_CharStrings : invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "T1.Parse_CharStrings : too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->subrs->code[index] + decoder->lenIV; + zone->limit = decoder->subrs->code[index+1]; + zone->cursor = zone->base; + + if (!zone->base) + { + FT_ERROR(( "T1.Parse_CharStrings : invoking empty subrs !!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + break; + } + + + case op_pop: /****************************************************/ + { + FT_TRACE4(( " pop" )); + /* theorically, the arguments are already on the stack */ + top++; + break; + } + + + case op_return: /************************************************/ + { + FT_TRACE4(( " return" )); + if ( zone <= decoder->zones ) + { + FT_ERROR(( "T1.Parse_CharStrings : unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + } + + case op_dotsection: /*********************************************/ + { + FT_TRACE4(( " dotsection" )); + break; + } + + case op_hstem: /**************************************************/ + { + FT_TRACE4(( " hstem" )); + break; + } + + case op_hstem3: /*************************************************/ + { + FT_TRACE4(( " hstem3" )); + break; + } + + case op_vstem: /**************************************************/ + { + FT_TRACE4(( " vstem" )); + break; + } + + case op_vstem3: /*************************************************/ + { + FT_TRACE4(( " vstem3" )); + break; + } + + case op_setcurrentpoint: /*****************************************/ + { + FT_TRACE4(( " setcurrentpoint" )); + FT_ERROR(( "T1.Parse_CharStrings : unexpected SETCURRENTPOINT\n" )); + goto Syntax_Error; + } + + default: + FT_ERROR(( "T1.Parse_CharStrings : unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + decoder->top = top; + + } /* general operator processing */ + + + } /* while ip < limit */ + FT_TRACE4(( "..end..\n\n" )); + return error; + + Syntax_Error: + return T1_Err_Syntax_Error; + + Stack_Underflow: + return T1_Err_Stack_Underflow; + + Memory_Error: + return builder->error; + } + + + + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + /********** *********/ + /********** *********/ + /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ + /********** *********/ + /********** The following code is in charge of computing *********/ + /********** the maximum advance width of the font. It *********/ + /********** quickly process each glyph charstring to *********/ + /********** extract the value from either a "sbw" or "seac" *********/ + /********** operator. *********/ + /********** *********/ + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + +#if 0 + LOCAL_FUNC + FT_Error CID_Compute_Max_Advance( CID_Face face, + FT_Int *max_advance ) + { + FT_Error error; + CID_Decoder decoder; + FT_Int glyph_index; + + *max_advance = 0; + + /* Initialise load decoder */ + CID_Init_Decoder( &decoder ); + CID_Init_Builder( &decoder.builder, face, 0, 0 ); + + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + + /* For each glyph, parse the glyph charstring and extract */ + /* the advance width.. */ + for ( glyph_index = 0; glyph_index < face->root.num_glyphs; glyph_index++ ) + { + /* now get load the unscaled outline */ + error = cid_load_glyph( &decoder, glyph_index ); + /* ignore the error if one occured - skip to next glyph */ + } + + *max_advance = decoder.builder.advance.x; + return T1_Err_Ok; + } +#endif + + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + /********** *********/ + /********** *********/ + /********** UNHINTED GLYPH LOADER *********/ + /********** *********/ + /********** The following code is in charge of loading a *********/ + /********** single outline. It completely ignores hinting *********/ + /********** and is used when FT_LOAD_NO_HINTING is set. *********/ + /********** *********/ + /**********************************************************************/ + /**********************************************************************/ + /**********************************************************************/ + + static + FT_Error cid_load_glyph( CID_Decoder* decoder, FT_UInt glyph_index ) + { + CID_Face face = decoder->builder.face; + CID_Info* cid = &face->cid; + FT_Byte* p; + FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes; + FT_UInt fd_select; + FT_ULong off1, glyph_len; + FT_Stream stream = face->root.stream; + FT_Error error = 0; + + /* read the CID font dict index and charstring offset from the CIDMap */ + if ( FILE_Seek( cid->data_offset + cid->cidmap_offset + + glyph_index * entry_len) || + ACCESS_Frame( 2*entry_len ) ) + goto Exit; + + p = (FT_Byte*)stream->cursor; + fd_select = (FT_UInt) cid_get_offset( &p, cid->fd_bytes ); + off1 = (FT_ULong)cid_get_offset( &p, cid->gd_bytes ); + p += cid->fd_bytes; + glyph_len = cid_get_offset( &p, cid->gd_bytes ) - off1; + + FORGET_Frame(); + + /* now, if the glyph is not empty, set up the subrs array, and parse */ + /* the charstrings */ + if (glyph_len > 0) + { + CID_FontDict* dict; + FT_Byte* charstring; + FT_UInt lenIV; + FT_Memory memory = face->root.memory; + + /* setup subrs */ + decoder->subrs = face->subrs + fd_select; + + /* setup font matrix */ + dict = cid->font_dicts + fd_select; + decoder->font_matrix = dict->font_matrix; + lenIV = dict->private_dict.lenIV; + decoder->lenIV = lenIV; + + /* the charstrings are encoded (stupid !!) */ + /* load the charstrings, then execute it */ + + if ( ALLOC( charstring, glyph_len ) ) + goto Exit; + + if ( !FILE_Read_At( cid->data_offset + off1, charstring, glyph_len ) ) + { + cid_decrypt( charstring, glyph_len, 4330 ); + error = CID_Parse_CharStrings( decoder, + charstring + lenIV, + glyph_len - lenIV ); + } + + FREE( charstring ); + } + + Exit: + return error; + } + + + + LOCAL_FUNC + FT_Error CID_Load_Glyph( T1_GlyphSlot glyph, + T1_Size size, + FT_Int glyph_index, + FT_Int load_flags ) + { + FT_Error error; + CID_Decoder decoder; + CID_Face face = (CID_Face)glyph->root.face; + T1_Bool hinting; + + if (load_flags & FT_LOAD_NO_RECURSE) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + + hinting = ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0; + + glyph->root.format = ft_glyph_format_none; + + { + CID_Init_Decoder( &decoder ); + CID_Init_Builder( &decoder.builder, face, size, glyph ); + + /* set up the decoder */ + decoder.builder.no_recurse = (FT_Bool)!!(load_flags & FT_LOAD_NO_RECURSE); + + error = cid_load_glyph( &decoder, glyph_index ); + + /* save new glyph tables */ + CID_Done_Builder( &decoder.builder ); + } + + /* Now, set the metrics.. - this is rather simple, as : */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax.. */ + if (!error) + { + /* for composite glyphs, return only the left side bearing and the */ + /* advance width.. */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + { + glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; + glyph->root.metrics.horiAdvance = decoder.builder.advance.x; + } + else + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &glyph->root.metrics; + + /* copy the _unscaled_ advance width */ + metrics->horiAdvance = decoder.builder.advance.x; + + /* make up vertical metrics */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; + metrics->vertAdvance = 0; + + glyph->root.format = ft_glyph_format_outline; + + glyph->root.outline.flags &= ft_outline_owner; + if ( size && size->root.metrics.y_ppem < 24 ) + glyph->root.outline.flags |= ft_outline_high_precision; + + glyph->root.outline.flags |= ft_outline_reverse_fill; + + /* + glyph->root.outline.second_pass = TRUE; + glyph->root.outline.high_precision = ( size->root.metrics.y_ppem < 24 ); + glyph->root.outline.dropout_mode = 2; + */ + + if ( (load_flags & FT_LOAD_NO_SCALE) == 0 ) + { + /* scale the outline and the metrics */ + FT_Int n; + FT_Outline* cur = &decoder.builder.base; + T1_Vector* vec = cur->points; + T1_Fixed x_scale = glyph->x_scale; + T1_Fixed y_scale = glyph->y_scale; + + /* First of all, scale the points */ + for ( n = cur->n_points; n > 0; n--, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + /* Then scale the metrics */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + + metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); + metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, x_scale ); + } + + /* apply the font matrix */ + FT_Outline_Transform( &glyph->root.outline, &decoder.font_matrix ); + + /* compute the other metrics */ + FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); + + /* grid fit the bounding box if necessary */ + if (hinting) + { + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = ( cbox.xMax+63 ) & -64; + cbox.yMax = ( cbox.yMax+63 ) & -64; + } + + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax; + } + } + return error; + } + diff --git a/src/cid/cidgload.h b/src/cid/cidgload.h new file mode 100644 index 000000000..ac6ab0b47 --- /dev/null +++ b/src/cid/cidgload.h @@ -0,0 +1,188 @@ +/******************************************************************* + * + * cidgload.h 1.0 + * + * CID-Keyed Type1 Glyph Loader. + * + * Copyright 1996-1998 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. + * + * + * The Type 1 glyph loader uses three distinct objects to build + * scaled and hinted outlines from a charstrings program. These are : + * + * - a glyph builder, CID_Builder, used to store the built outline + * + * - a glyph hinter, T1_Hinter, used to record and apply the stem + * hints + * + * - a charstrings interpreter, CID_Decoder, used to parse the + * Type 1 charstrings stream, manage a stack and call the builder + * and/or hinter depending on the opcodes. + * + * Ideally, a Type 2 glyph loader would only need to have its own + * T2_Decoder object (assuming the hinter is able to manage all + * kinds of hints). + * + ******************************************************************/ + +#ifndef CIDGLOAD_H +#define CIDGLOAD_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + +/*************************************************************************/ +/* */ +/* CID_Builder */ +/* */ +/* */ +/* a structure used during glyph loading to store its outline. */ +/* */ +/* */ +/* system :: current system object */ +/* face :: current face object */ +/* glyph :: current glyph slot */ +/* */ +/* current :: current glyph outline */ +/* base :: base glyph outline */ +/* */ +/* max_points :: maximum points in builder outline */ +/* max_contours :: maximum contours in builder outline */ +/* */ +/* last :: last point position */ +/* */ +/* scale_x :: horizontal scale ( FUnits to sub-pixels ) */ +/* scale_y :: vertical scale ( FUnits to sub-pixels ) */ +/* pos_x :: horizontal translation (composite glyphs) */ +/* pos_y :: vertical translation (composite glyph) */ +/* */ +/* left_bearing :: left side bearing point */ +/* advance :: horizontal advance vector */ +/* */ +/* path_begun :: flag, indicates that a new path has begun */ +/* load_points :: flag, if not set, no points are loaded */ +/* */ +/* error :: an error code that is only used to report */ +/* memory allocation problems.. */ +/* */ +/* metrics_only :: a boolean indicating that we only want to */ +/* compute the metrics of a given glyph, not load */ +/* all of its points.. */ +/* */ + + typedef struct CID_Builder_ + { + FT_Memory memory; + CID_Face face; + T1_GlyphSlot glyph; + + FT_Outline current; /* the current glyph outline */ + FT_Outline base; /* the composite glyph outline */ + + FT_Int max_points; /* capacity of base outline in points */ + FT_Int max_contours; /* capacity of base outline in contours */ + + T1_Vector last; + + T1_Fixed scale_x; + T1_Fixed scale_y; + + T1_Pos pos_x; + T1_Pos pos_y; + + T1_Vector left_bearing; + T1_Vector advance; + + T1_BBox bbox; /* bounding box */ + T1_Bool path_begun; + T1_Bool load_points; + T1_Bool no_recurse; + + FT_Error error; /* only used for memory errors */ + T1_Bool metrics_only; + + } CID_Builder; + + + /* execution context charstring zone */ + typedef struct CID_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + + } CID_Decoder_Zone; + + + typedef struct CID_Decoder_ + { + CID_Builder builder; + + FT_Int stack[ T1_MAX_CHARSTRINGS_OPERANDS ]; + FT_Int* top; + + CID_Decoder_Zone zones[ T1_MAX_SUBRS_CALLS+1 ]; + CID_Decoder_Zone* zone; + + FT_Matrix font_matrix; + CID_Subrs* subrs; + FT_UInt lenIV; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + } CID_Decoder; + + + + LOCAL_DEF + void CID_Init_Builder( CID_Builder* builder, + CID_Face face, + T1_Size size, + T1_GlyphSlot glyph ); + + LOCAL_DEF + void CID_Done_Builder( CID_Builder* builder ); + + + LOCAL_DEF + void CID_Init_Decoder( CID_Decoder* decoder ); + + +#if 0 + /* Compute the maximum advance width of a font through quick parsing */ + LOCAL_DEF + FT_Error CID_Compute_Max_Advance( CID_Face face, + FT_Int *max_advance ); +#endif + + /* This function is exported, because it is used by the T1Dump utility */ + LOCAL_DEF + FT_Error CID_Parse_CharStrings( CID_Decoder* decoder, + FT_Byte* charstring_base, + FT_Int charstring_len ); + + LOCAL_DEF + FT_Error CID_Load_Glyph( T1_GlyphSlot glyph, + T1_Size size, + FT_Int glyph_index, + FT_Int load_flags ); + + +#ifdef __cplusplus + } +#endif + +#endif /* T1GLOAD_H */ diff --git a/src/cid/cidload.c b/src/cid/cidload.c new file mode 100644 index 000000000..3ed7c62a5 --- /dev/null +++ b/src/cid/cidload.c @@ -0,0 +1,503 @@ +/******************************************************************* + * + * cidload.h 2.0 + * + * CID-keyed foint loader + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + * + * This is the new and improved Type 1 data loader for FreeType 2. + * The old loader has several problems: it is slow, complex, difficult + * to maintain, and contains incredible hacks to make it accept some + * ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% + * of the Type 1 fonts on my machine still aren't loaded correctly + * with it. + * + * This version is much simpler, much faster and also easier to + * read and maintain by a great order of magnitude. The idea behind + * it is to _not_ try to read the Type 1 token stream with a state + * machine (i.e. a Postscript-like interpreter) but rather to perform + * simple pattern-matching. + * + * Indeed, nearly all data definitions follow a simple pattern + * like : + * + * ..... /Field .... + * + * where can be a number, a boolean, a string, or an + * array of numbers. There are a few exceptions, namely the + * encoding, font name, charstrings and subrs and they are + * handled with a special pattern-matching routine. + * + * All other common cases are handled very simply. The matching + * rules are defined in the file "t1tokens.h" through the use + * of several macros calls T1_FIELD_XXX + * + * The function "parse_dict" simply scans *linearly* a given + * dictionary (either the top-level or private one) and calls + * the appropriate callback when it encounters an immediate + * keyword. + * + * This is by far the fastest way one can find to parse and read + * all data :-) + * + * This led to tremendous code size reduction. Note that later, + * the glyph loader will also be _greatly_ simplified, and the + * automatic hinter will replace the clumsy "t1hinter".. + * + ******************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1load + + /* reads a single offset */ + LOCAL_FUNC + FT_Long cid_get_offset( FT_Byte** start, FT_Byte offsize ) + { + FT_Long result; + FT_Byte* p = *start; + + for ( result = 0; offsize > 0; offsize-- ) + result = (result << 8) | *p++; + + *start = p; + return result; + } + + + LOCAL_FUNC + void cid_decrypt( FT_Byte* buffer, + FT_Int length, + FT_UShort seed ) + { + while ( length > 0 ) + { + FT_Byte plain; + + plain = (*buffer ^ (seed >> 8)); + seed = (*buffer+seed)*52845+22719; + *buffer++ = plain; + length--; + } + } + + + + /***************************************************************************/ + /***************************************************************************/ + /***** *****/ + /***** TYPE 1 SYMBOL PARSING *****/ + /***** *****/ + /***************************************************************************/ + /***************************************************************************/ + + + static FT_Error cid_load_keyword( CID_Face face, + CID_Loader* loader, + const T1_Field_Rec* keyword ) + { + FT_Error error; + CID_Parser* parser = &loader->parser; + FT_Byte* object; + CID_Info* cid = &face->cid; + + /* if the keyword has a dedicated callback, call it */ + if (keyword->type == t1_field_callback) + { + error = keyword->reader( face, parser ); + goto Exit; + } + + /* we must now compute the address of our target object */ + switch (keyword->location) + { + case t1_field_cid_info: + object = (FT_Byte*)cid; + break; + + case t1_field_font_info: + object = (FT_Byte*)&cid->font_info; + break; + + default: + { + CID_FontDict* dict; + + if ( parser->num_dict < 0 ) + { + FT_ERROR(( "CID.Load_Keyword: invalid use of '%s' !!\n", keyword->ident )); + error = T1_Err_Syntax_Error; + goto Exit; + } + + dict = cid->font_dicts + parser->num_dict; + switch (keyword->location) + { + case t1_field_private: + object = (FT_Byte*)&dict->private_dict; + break; + + default: + object = (FT_Byte*)dict; + } + } + } + + /* now, load the keyword data in the object's field(s) */ + if ( keyword->type == t1_field_integer_array || + keyword->type == t1_field_fixed_array ) + error = CID_Load_Field_Table( parser, keyword, object ); + else + error = CID_Load_Field( parser, keyword, object ); + + Exit: + return error; + } + + + static + FT_Error parse_font_bbox( CID_Face face, CID_Parser* parser ) + { + FT_Short temp[4]; + T1_BBox* bbox = &face->cid.font_bbox; + + (void)CID_ToCoordArray( parser, 4, temp ); + bbox->xMin = temp[0]; + bbox->yMin = temp[1]; + bbox->xMax = temp[2]; + bbox->yMax = temp[3]; + + return 0; + } + + static + FT_Error parse_font_matrix( CID_Face face, CID_Parser* parser ) + { + FT_Matrix* matrix; + CID_FontDict* dict; + T1_Fixed temp[4]; + + if (parser->num_dict >= 0) + { + dict = face->cid.font_dicts + parser->num_dict; + matrix = &dict->font_matrix; + + (void)CID_ToFixedArray( parser, 4, temp, 3 ); + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + } + return 0; + } + + static + FT_Error parse_fd_array( CID_Face face, CID_Parser* parser ) + { + CID_Info* cid = &face->cid; + FT_Memory memory = face->root.memory; + FT_Error error; + FT_Long num_dicts; + + num_dicts = CID_ToInt(parser); + if ( !cid->font_dicts ) + { + FT_Int n; + + if ( ALLOC_ARRAY( cid->font_dicts, num_dicts, CID_FontDict ) ) + goto Exit; + + cid->num_dicts = (FT_UInt)num_dicts; + + /* don't forget to set a few defauts !! */ + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_FontDict* dict = cid->font_dicts + n; + + /* default value for lenIV !! */ + dict->private_dict.lenIV = 4; + } + } + + Exit: + return error; + } + + + + static + const T1_Field_Rec t1_field_records[] = + { + #include + { 0, 0, 0, 0, 0, 0 } + }; + + + static + int is_space( char c ) + { + return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ); + } + + static + int is_alpha( char c ) + { + return ( (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + (c == '.') || + (c == '_') ); + } + + static + void skip_whitespace( CID_Parser* parser ) + { + FT_Byte* cur = parser->cursor; + + while ( cur < parser->limit && is_space(*cur) ) + cur++; + + parser->cursor = cur; + } + + + + static + FT_Error parse_dict( CID_Face face, + CID_Loader* loader, + FT_Byte* base, + FT_Long size ) + { + CID_Parser* parser = &loader->parser; + + parser->cursor = base; + parser->limit = base + size; + parser->error = 0; + + { + FT_Byte* cur = base; + FT_Byte* limit = cur + size; + + for ( ;cur < limit; cur++ ) + { + /* look for %ADOBegin... */ + if ( *cur == '%' && cur + 20 < limit && + strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) + { + cur += 17; + + /* if /FDArray was found, then cid->num_dicts is > 0, and */ + /* we can start increasing parser->num_dict */ + if ( face->cid.num_dicts > 0 ) + parser->num_dict++; + } + /* look for immediates */ + else if (*cur == '/' && cur+2 < limit) + { + FT_Byte* cur2; + FT_Int len; + + cur ++; + cur2 = cur; + while (cur2 < limit && is_alpha(*cur2)) cur2++; + len = cur2-cur; + + if (len > 0 && len < 22) + { + /* now, compare the immediate name to the keyword table */ + const T1_Field_Rec* keyword = t1_field_records; + + for (;;) + { + FT_Byte* name; + + name = (FT_Byte*)keyword->ident; + if (!name) break; + + if ( cur[0] == name[0] && + len == (FT_Int)strlen((const char*)name) ) + { + FT_Int n; + for ( n = 1; n < len; n++ ) + if (cur[n] != name[n]) + break; + + if (n >= len) + { + /* we found it - run the parsing callback !! */ + parser->cursor = cur2; + skip_whitespace( parser ); + parser->error = cid_load_keyword( face, loader, keyword ); + if (parser->error) + return parser->error; + + cur = parser->cursor; + break; + } + } + keyword++; + } + } + } + } + } + return parser->error; + } + + + + /* read the subrmap and the subrs of each font dict */ + static + FT_Error cid_read_subrs( CID_Face face ) + { + CID_Info* cid = &face->cid; + FT_Memory memory = face->root.memory; + FT_Stream stream = face->root.stream; + FT_Error error; + FT_UInt n; + CID_Subrs* subr; + FT_UInt max_offsets = 0; + FT_ULong* offsets = 0; + + if ( ALLOC_ARRAY( face->subrs, cid->num_dicts, CID_Subrs ) ) + goto Exit; + + subr = face->subrs; + for ( n = 0; n < cid->num_dicts; n++, subr++ ) + { + CID_FontDict* dict = cid->font_dicts + n; + FT_UInt count, num_subrs = dict->num_subrs; + FT_ULong data_len; + FT_Byte* p; + + /* reallocate offsets array if needed */ + if ( num_subrs+1 > max_offsets ) + { + FT_UInt new_max = (num_subrs+1+3) & -4; + if ( REALLOC_ARRAY( offsets, max_offsets, new_max, FT_ULong ) ) + goto Fail; + + max_offsets = new_max; + } + + /* read the subrmap's offsets */ + if ( FILE_Seek( cid->data_offset + dict->subrmap_offset ) || + ACCESS_Frame( (num_subrs+1) * dict->sd_bytes ) ) + goto Fail; + + p = (FT_Byte*)stream->cursor; + for ( count = 0; count <= num_subrs; count++ ) + offsets[count] = cid_get_offset( &p, dict->sd_bytes ); + + FORGET_Frame(); + + /* now, compute the size of subrs charstrings, allocate and read them */ + data_len = offsets[num_subrs] - offsets[0]; + + if ( ALLOC_ARRAY( subr->code, num_subrs+1, FT_Byte* ) || + ALLOC( subr->code[0], data_len ) ) + goto Fail; + + if ( FILE_Seek( cid->data_offset + offsets[0] ) || + FILE_Read( subr->code[0], data_len ) ) + goto Exit; + + /* set up pointers */ + for ( count = 1; count <= num_subrs; count++ ) + { + FT_UInt len; + + len = offsets[count] - offsets[count-1]; + subr->code[count] = subr->code[count-1] + len; + } + + /* decrypt subroutines */ + for ( count = 0; count < num_subrs; count++ ) + { + FT_UInt len; + + len = offsets[count+1] - offsets[count]; + cid_decrypt( subr->code[count], len, 4330 ); + } + + subr->num_subrs = num_subrs; + } + + Exit: + FREE( offsets ); + return error; + + Fail: + if (face->subrs) + { + for ( n = 0; n < cid->num_dicts; n++ ) + { + if (face->subrs[n].code) + FREE( face->subrs[n].code[0] ); + + FREE( face->subrs[n].code ); + } + FREE( face->subrs ); + } + goto Exit; + } + + static + void t1_init_loader( CID_Loader* loader, CID_Face face ) + { + UNUSED(face); + + MEM_Set( loader, 0, sizeof(*loader) ); + } + + static + void t1_done_loader( CID_Loader* loader ) + { + CID_Parser* parser = &loader->parser; + + /* finalize parser */ + CID_Done_Parser( parser ); + } + + LOCAL_FUNC + FT_Error T1_Open_Face( CID_Face face ) + { + CID_Loader loader; + CID_Parser* parser; + FT_Error error; + + t1_init_loader( &loader, face ); + + parser = &loader.parser; + error = CID_New_Parser( parser, face->root.stream, face->root.memory ); + if (error) goto Exit; + + error = parse_dict( face, &loader, + parser->postscript, + parser->postscript_len ); + if (error) goto Exit; + + face->cid.data_offset = loader.parser.data_offset; + error = cid_read_subrs( face ); + + Exit: + t1_done_loader( &loader ); + return error; + } diff --git a/src/cid/cidload.h b/src/cid/cidload.h new file mode 100644 index 000000000..b96b7ce1f --- /dev/null +++ b/src/cid/cidload.h @@ -0,0 +1,54 @@ +/******************************************************************* + * + * t1load.h 2.0 + * + * Type1 Loader. + * + * Copyright 1996-2000 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + ******************************************************************/ + +#ifndef T1LOAD_H +#define T1LOAD_H + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + typedef struct CID_Loader_ + { + CID_Parser parser; /* parser used to read the stream */ + + FT_Int num_chars; /* number of characters in encoding */ + + } CID_Loader; + + LOCAL_DEF + FT_Long cid_get_offset( FT_Byte** start, FT_Byte offsize ); + + LOCAL_DEF + void cid_decrypt( FT_Byte* buffer, + FT_Int length, + FT_UShort seed ); + + LOCAL_DEF + FT_Error T1_Open_Face( CID_Face face ); + +#ifdef __cplusplus + } +#endif + +#endif /* T1LOAD_H */ + + +/* END */ diff --git a/src/cid/cidobjs.c b/src/cid/cidobjs.c new file mode 100644 index 000000000..9430f7a54 --- /dev/null +++ b/src/cid/cidobjs.c @@ -0,0 +1,473 @@ +/******************************************************************* + * + * t1objs.c 1.0 + * + * Type1 Objects manager. + * + * Copyright 1996-1998 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. + * + ******************************************************************/ + +#include +#include + +#include +#include +#include +#include + +/* Required by tracing mode */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1objs + +/******************************************************************* + * * + * SIZE FUNCTIONS * + * * + * * + *******************************************************************/ + +/******************************************************************* + * + * T1_Done_Size + * + * + * The TrueDoc instance object destructor. Used to discard + * a given instance object.. + * + * + * instance :: handle to the target instance object + * + * + * TrueDoc error code. 0 means success + * + ******************************************************************/ + + LOCAL_FUNC + void T1_Done_Size( T1_Size size ) + { + UNUSED(size); + } + + +/******************************************************************* + * + * T1_Init_Size + * + * + * The instance object constructor + * + * + * instance : handle to new instance object + * face : pointer to parent face object + * + * + * TrueDoc error code. 0 means success. + * + ******************************************************************/ + + LOCAL_DEF + FT_Error T1_Init_Size( T1_Size size ) + { + size->valid = 0; + return T1_Err_Ok; + } + + +/******************************************************************* + * + * T1_Reset_Size + * + * + * Resets an instance to a new pointsize/transform. + * This function is in charge of resetting the blue zones, + * As well as the stem snap tables for a given size.. + * + * + * instance the instance object to destroy + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_FUNC + FT_Error T1_Reset_Size( T1_Size size ) + { + UNUSED(size); + return 0; + } + + +/******************************************************************* + * * + * FACE FUNCTIONS * + * * + * * + *******************************************************************/ + +/******************************************************************* + * + * T1_Done_Face + * + * + * The face object destructor. + * + * + * face :: typeless pointer to the face object to destroy + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_FUNC + void T1_Done_Face( CID_Face face ) + { + FT_Memory memory; + + if (face) + { + CID_Info* cid = &face->cid; + T1_FontInfo* info = &cid->font_info; + + memory = face->root.memory; + + /* release FontInfo strings */ + FREE( info->version ); + FREE( info->notice ); + FREE( info->full_name ); + FREE( info->family_name ); + FREE( info->weight ); + + /* release font dictionaries */ + FREE( cid->font_dicts ); + cid->num_dicts = 0; + + /* release other strings */ + FREE( cid->cid_font_name ); + FREE( cid->registry ); + FREE( cid->ordering ); + + face->root.family_name = 0; + face->root.style_name = 0; + } + } + +/******************************************************************* + * + * T1_Init_Face + * + * + * The face object constructor. + * + * + * face :: face record to build + * Input :: input stream where to load font data + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_FUNC + FT_Error T1_Init_Face( FT_Stream stream, + CID_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + PSNames_Interface* psnames; + + UNUSED(num_params); + UNUSED(params); + UNUSED(face_index); + UNUSED(stream); + + face->root.num_faces = 1; + + psnames = (PSNames_Interface*)face->psnames; + if (!psnames) + { + /* look-up the PSNames driver */ + FT_Driver psnames_driver; + + psnames_driver = FT_Get_Driver( face->root.driver->library, "psnames" ); + if (psnames_driver) + face->psnames = (PSNames_Interface*) + (psnames_driver->interface.format_interface); + } + + /* open the tokenizer, this will also check the font format */ + if ( FILE_Seek(0) ) + goto Exit; + + error = T1_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(( "T1.Init_Face : invalid face index\n" )); + error = T1_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 */ + { + FT_Face root = (FT_Face)&face->root; + + root->num_glyphs = face->cid.cid_count; + root->num_charmaps = 0; + + root->face_index = face_index; + root->face_flags = FT_FACE_FLAG_SCALABLE; + + root->face_flags |= FT_FACE_FLAG_HORIZONTAL; + + if ( face->cid.font_info.is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + + /* XXX : TO DO - add kerning with .afm support */ + + /* get style name - be careful, some broken fonts only */ + /* have a /FontName dictionary entry .. !! */ + root->family_name = face->cid.font_info.family_name; + if (root->family_name) + { + char* full = face->cid.font_info.full_name; + char* family = root->family_name; + + while ( *family && *full == *family ) + { + family++; + full++; + } + + root->style_name = ( *full == ' ' ? full+1 : "Regular" ); + } + else + { + /* do we have a /FontName ?? */ + if (face->cid.cid_font_name) + { + root->family_name = face->cid.cid_font_name; + root->style_name = "Regular"; + } + } + + /* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = 0; + + root->bbox = face->cid.font_bbox; + root->units_per_EM = 1000; + root->ascender = (FT_Short)face->cid.font_bbox.yMax; + root->descender = -(FT_Short)face->cid.font_bbox.yMin; + root->height = ((root->ascender + root->descender)*12)/10; + +#if 0 + /* now compute the maximum advance width */ + + root->max_advance_width = face->type1.private_dict.standard_width[0]; + + /* compute max advance width for proportional fonts */ + if (!face->type1.font_info.is_fixed_pitch) + { + FT_Int max_advance; + + error = T1_Compute_Max_Advance( face, &max_advance ); + + /* in case of error, keep the standard width */ + if (!error) + root->max_advance_width = max_advance; + else + error = 0; /* clear error */ + } + + root->max_advance_height = root->height; +#endif + root->underline_position = face->cid.font_info.underline_position; + root->underline_thickness = face->cid.font_info.underline_thickness; + + root->max_points = 0; + root->max_contours = 0; + } + } + +#if 0 + /* charmap support - synthetize unicode charmap when possible */ + { + FT_Face root = &face->root; + FT_CharMap charmap = face->charmaprecs; + + /* synthesize a Unicode charmap if there is support in the "psnames" */ + /* module.. */ + if (face->psnames) + { + PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; + if (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++; + } + + /* simply clear the error in case of failure (which really) */ + /* means that out of memory or no unicode glyph names */ + error = 0; + } + } + + /* now, support either the standard, expert, or custom encodings */ + charmap->face = (FT_Face)face; + charmap->platform_id = 7; /* a new platform id for Adobe fonts ?? */ + + switch (face->type1.encoding_type) + { + case t1_encoding_standard: + charmap->encoding = ft_encoding_adobe_standard; + charmap->encoding_id = 0; + break; + + case t1_encoding_expert: + charmap->encoding = ft_encoding_adobe_expert; + charmap->encoding_id = 1; + break; + + default: + charmap->encoding = ft_encoding_adobe_custom; + charmap->encoding_id = 2; + break; + } + + root->charmaps = face->charmaps; + root->num_charmaps = charmap - face->charmaprecs + 1; + face->charmaps[0] = &face->charmaprecs[0]; + face->charmaps[1] = &face->charmaprecs[1]; + } +#endif + Exit: + return error; + } + + +/******************************************************************* + * + * Function : Glyph_Destroy + * + * Description : The glyph object destructor. + * + * Input : _glyph typeless pointer to the glyph record to destroy + * + * Output : Error code. + * + ******************************************************************/ + + LOCAL_FUNC + void T1_Done_GlyphSlot( T1_GlyphSlot glyph ) + { + FT_Memory memory = glyph->root.face->memory; + FT_Library library = glyph->root.face->driver->library; + + /* the bitmaps are created on demand */ + FREE( glyph->root.bitmap.buffer ); + FT_Outline_Done( library, &glyph->root.outline ); + return; + } + + +/******************************************************************* + * + * Function : Glyph_Create + * + * Description : The glyph object constructor. + * + * Input : glyph glyph record to build. + * face the glyph's parent face. + * + * Output : Error code. + * + ******************************************************************/ + + LOCAL_FUNC + FT_Error T1_Init_GlyphSlot( T1_GlyphSlot glyph ) + { + FT_Library library = glyph->root.face->driver->library; + + glyph->max_points = 0; + glyph->max_contours = 0; + glyph->root.bitmap.buffer = 0; + + return FT_Outline_New( library, 0, 0, &glyph->root.outline ); + } + + +/******************************************************************* + * + * T1_Init_Driver + * + * + * Initialise a given Type 1 driver object + * + * + * driver :: handle to target driver object + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_FUNC + FT_Error T1_Init_Driver( T1_Driver driver ) + { + UNUSED(driver); + return T1_Err_Ok; + } + + + +/******************************************************************* + * + * T1_Done_Driver + * + * + * finalise a given Type 1 driver + * + * + * driver :: handle to target Type 1 driver + * + ******************************************************************/ + + LOCAL_DEF + void T1_Done_Driver( T1_Driver driver ) + { + UNUSED(driver); + } + + +/* END */ diff --git a/src/cid/cidobjs.h b/src/cid/cidobjs.h new file mode 100644 index 000000000..d31cb5a6d --- /dev/null +++ b/src/cid/cidobjs.h @@ -0,0 +1,304 @@ +/******************************************************************* + * + * t1objs.h 1.0 + * + * Type1 objects definition. + * + * Copyright 1996-1999 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 T1OBJS_H +#define T1OBJS_H + +#include +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + /* The following structures must be defined by the hinter */ + typedef struct T1_Size_Hints_ T1_Size_Hints; + typedef struct T1_Glyph_Hints_ T1_Glyph_Hints; + + /***********************************************************************/ + /* */ + /* T1_Driver */ + /* */ + /* */ + /* A handle to a Type 1 driver object. */ + /* */ + typedef struct T1_DriverRec_ *T1_Driver; + + + /***********************************************************************/ + /* */ + /* T1_Size */ + /* */ + /* */ + /* A handle to a Type 1 size object. */ + /* */ + typedef struct T1_SizeRec_* T1_Size; + + + /***********************************************************************/ + /* */ + /* T1_GlyphSlot */ + /* */ + /* */ + /* A handle to a Type 1 glyph slot object. */ + /* */ + typedef struct T1_GlyphSlotRec_* T1_GlyphSlot; + + + /***********************************************************************/ + /* */ + /* T1_CharMap */ + /* */ + /* */ + /* A handle to a Type 1 character mapping object. */ + /* */ + /* */ + /* The Type 1 format doesn't use a charmap but an encoding table. */ + /* The driver is responsible for making up charmap objects */ + /* corresponding to these tables.. */ + /* */ + typedef struct T1_CharMapRec_* T1_CharMap; + + + + /**************************************************************************/ + /* */ + /* NOW BEGINS THE TYPE1 SPECIFIC STUFF .............................. */ + /* */ + /**************************************************************************/ + + + /***************************************************/ + /* */ + /* T1_Size : */ + /* */ + /* Type 1 size record.. */ + /* */ + + typedef struct T1_SizeRec_ + { + FT_SizeRec root; + T1_Bool valid; + T1_Size_Hints* hints; /* defined in the hinter. This allows */ + /* us to experiment with different */ + /* hinting schemes without having to */ + /* change 't1objs' each time.. */ + } T1_SizeRec; + + + + /***************************************************/ + /* */ + /* T1_GlyphSlot : */ + /* */ + /* TrueDoc glyph record.. */ + /* */ + + typedef struct T1_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + + T1_Bool hint; + T1_Bool scaled; + + FT_Int max_points; + FT_Int max_contours; + + FT_Fixed x_scale; + FT_Fixed y_scale; + + T1_Glyph_Hints* hints; /* defined in the hinter */ + + } T1_GlyphSlotRec; + + +/******************************************************************* + * + * T1_Init_Face + * + * + * Initialise a given Type 1 face object + * + * + * face_index :: index of font face in resource + * resource :: source font resource + * face :: face record to build + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_DEF + FT_Error T1_Init_Face( FT_Stream stream, + CID_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + + + +/******************************************************************* + * + * T1_Done_Face + * + * + * Finalise a given face object + * + * + * face :: handle to the face object to destroy + * + ******************************************************************/ + + LOCAL_DEF + void T1_Done_Face( CID_Face face ); + + + +/******************************************************************* + * + * T1_Init_Size + * + * + * Initialise a new Type 1 size object + * + * + * size :: handle to size object + * + * + * Type 1 error code. 0 means success. + * + ******************************************************************/ + + LOCAL_DEF + FT_Error T1_Init_Size( T1_Size size ); + + + +/******************************************************************* + * + * T1_Done_Size + * + * + * The Type 1 size object finaliser. + * + * + * size :: handle to the target size object. + * + ******************************************************************/ + + LOCAL_DEF + void T1_Done_Size( T1_Size size ); + + +/******************************************************************* + * + * T1_Reset_Size + * + * + * Reset a Type 1 size when resolutions and character dimensions + * have been changed.. + * + * + * size :: handle to the target size object. + * + ******************************************************************/ + + LOCAL_DEF + FT_Error T1_Reset_Size( T1_Size size ); + + + +/******************************************************************* + * + * T1_Init_GlyphSlot + * + * The TrueType glyph slot initialiser + * + * glyph :: glyph record to build. + * + * Error code. + * + ******************************************************************/ + + LOCAL_DEF + FT_Error T1_Init_GlyphSlot( T1_GlyphSlot slot ); + + + +/******************************************************************* + * + * T1_Done_GlyphSlot + * + * The Type 1 glyph slot finaliser + * + * glyph :: handle to glyph slot object + * + * Error code. + * + ******************************************************************/ + + LOCAL_DEF + void T1_Done_GlyphSlot( T1_GlyphSlot slot ); + + + +/******************************************************************* + * + * T1_Init_Driver + * + * + * Initialise a given Type 1 driver object + * + * + * driver :: handle to target driver object + * + * + * Error code. + * + ******************************************************************/ + + LOCAL_DEF + FT_Error T1_Init_Driver( T1_Driver driver ); + + + +/******************************************************************* + * + * T1_Done_Driver + * + * + * finalise a given Type 1 driver + * + * + * driver :: handle to target Type 1 driver + * + ******************************************************************/ + + LOCAL_DEF + void T1_Done_Driver( T1_Driver driver ); + +#ifdef __cplusplus + } +#endif + +#endif /* T1OBJS_H */ + + +/* END */ diff --git a/src/cid/cidparse.c b/src/cid/cidparse.c new file mode 100644 index 000000000..c400b7b4a --- /dev/null +++ b/src/cid/cidparse.c @@ -0,0 +1,936 @@ +/******************************************************************* + * + * cidparse.c 2.0 + * + * CID-keyed Type1 parser. + * + * Copyright 1996-1998 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. + * + * The Type 1 parser is in charge of the following: + * + * - provide an implementation of a growing sequence of + * objects called a T1_Table (used to build various tables + * needed by the loader). + * + * - opening .pfb and .pfa files to extract their top-level + * and private dictionaries + * + * - read numbers, arrays & strings from any dictionary + * + * See "t1load.c" to see how data is loaded from the font file + * + ******************************************************************/ + +#include +#include +#include +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1load + +#if 0 +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** IMPLEMENTATION OF T1_TABLE OBJECT *****/ +/***** *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + + +/*************************************************************************/ +/* */ +/* T1_New_Table */ +/* */ +/* */ +/* Initialise a T1_Table. */ +/* */ +/* */ +/* table :: address of target table */ +/* count :: table size = maximum number of elements */ +/* memory :: memory object to use for all subsequent reallocations */ +/* */ +/* */ +/* Error code. 0 means success */ +/* */ + + LOCAL_FUNC + FT_Error T1_New_Table( T1_Table* table, + FT_Int count, + FT_Memory memory ) + { + FT_Error error; + + table->memory = memory; + if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) || + ALLOC_ARRAY( table->lengths, count, FT_Byte* ) ) + goto Exit; + + table->max_elems = count; + table->init = 0xdeadbeef; + table->num_elems = 0; + table->block = 0; + table->capacity = 0; + table->cursor = 0; + + Exit: + if (error) FREE(table->elements); + + return error; + } + + + +/*************************************************************************/ +/* */ +/* T1_Add_Table */ +/* */ +/* */ +/* Adds an object to a T1_Table, possibly growing its memory block */ +/* */ +/* */ +/* table :: target table */ +/* index :: index of object in table */ +/* object :: address of object to copy in memory */ +/* length :: length in bytes of source object */ +/* */ +/* */ +/* Error code. 0 means success. An error is returned when a */ +/* realloc failed.. */ +/* */ + + + static void shift_elements( T1_Table* table, FT_Byte* old_base ) + { + FT_Long delta = table->block - old_base; + FT_Byte** offset = table->elements; + FT_Byte** limit = offset + table->max_elems; + + if (delta) + for ( ; offset < limit; offset++ ) + { + if (offset[0]) + offset[0] += delta; + } + } + + static + FT_Error reallocate_t1_table( T1_Table* table, + FT_Int new_size ) + { + FT_Memory memory = table->memory; + FT_Byte* old_base = table->block; + FT_Error error; + + /* realloc the base block */ + if ( REALLOC( table->block, table->capacity, new_size ) ) + return error; + + table->capacity = new_size; + + /* shift all offsets when needed */ + if (old_base) + shift_elements( table, old_base ); + + return T1_Err_Ok; + } + + + + LOCAL_FUNC + FT_Error T1_Add_Table( T1_Table* table, + FT_Int index, + void* object, + FT_Int length ) + { + if (index < 0 || index > table->max_elems) + { + FT_ERROR(( "T1.Add_Table: invalid index\n" )); + return T1_Err_Syntax_Error; + } + + /* grow the base block if needed */ + if ( table->cursor + length > table->capacity ) + { + FT_Error error; + FT_Int new_size = table->capacity; + + while ( new_size < table->cursor+length ) + new_size += 1024; + + error = reallocate_t1_table( table, new_size ); + if (error) return error; + } + + /* add the object to the base block and adjust offset */ + table->elements[ index ] = table->block + table->cursor; + table->lengths [ index ] = length; + MEM_Copy( table->block + table->cursor, object, length ); + + table->cursor += length; + return T1_Err_Ok; + } + + +/*************************************************************************/ +/* */ +/* T1_Done_Table */ +/* */ +/* */ +/* Finalise a T1_Table. (realloc it to its current cursor). */ +/* */ +/* */ +/* table :: target table */ +/* */ +/* */ +/* This function does NOT release the heap's memory block. It is up */ +/* to the caller to clean it, or reference it in its own structures. */ +/* */ +#if 0 + LOCAL_FUNC + void T1_Done_Table( T1_Table* table ) + { + FT_Memory memory = table->memory; + FT_Error error; + FT_Byte* old_base; + + /* should never fail, as rec.cursor <= rec.size */ + old_base = table->block; + if (!old_base) + return; + + (void)REALLOC( table->block, table->capacity, table->cursor ); + table->capacity = table->cursor; + + if (old_base != table->block) + shift_elements( table, old_base ); + } +#endif + + LOCAL_FUNC + void T1_Release_Table( T1_Table* table ) + { + FT_Memory memory = table->memory; + + if (table->init == (FT_Long)0xdeadbeef) + { + FREE( table->block ); + FREE( table->elements ); + FREE( table->lengths ); + table->init = 0; + } + } + +#endif + +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** INPUT STREAM PARSER *****/ +/***** *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + + #define IS_T1_WHITESPACE(c) ( (c) == ' ' || (c) == '\t' ) + #define IS_T1_LINESPACE(c) ( (c) == '\r' || (c) == '\n' ) + + #define IS_T1_SPACE(c) ( IS_T1_WHITESPACE(c) || IS_T1_LINESPACE(c) ) + + LOCAL_FUNC + void CID_Skip_Spaces( CID_Parser* parser ) + { + FT_Byte* cur = parser->cursor; + FT_Byte* limit = parser->limit; + + while (cur < limit) + { + FT_Byte c = *cur; + if (!IS_T1_SPACE(c)) + break; + cur++; + } + parser->cursor = cur; + } + + LOCAL_FUNC + void CID_ToToken( CID_Parser* parser, + T1_Token_Rec* token ) + { + FT_Byte* cur; + FT_Byte* limit; + FT_Byte starter, ender; + FT_Int embed; + + token->type = t1_token_none; + token->start = 0; + token->limit = 0; + + /* first of all, skip space */ + CID_Skip_Spaces(parser); + + cur = parser->cursor; + limit = parser->limit; + + if ( cur < limit ) + { + switch (*cur) + { + /************* check for strings ***********************/ + case '(': + token->type = t1_token_string; + ender = ')'; + goto Lookup_Ender; + + /************* check for programs/array ****************/ + case '{': + token->type = t1_token_array; + ender = '}'; + goto Lookup_Ender; + + /************* check for table/array ******************/ + case '[': + token->type = t1_token_array; + ender = ']'; + + Lookup_Ender: + embed = 1; + starter = *cur++; + token->start = cur; + while (cur < limit) + { + if (*cur == starter) + embed++; + else if (*cur == ender) + { + embed--; + if (embed <= 0) + { + token->limit = cur++; + break; + } + } + cur++; + } + break; + + /* **************** otherwise, it's any token **********/ + default: + token->start = cur++; + token->type = t1_token_any; + while (cur < limit && !IS_T1_SPACE(*cur)) + cur++; + + token->limit = cur; + } + + if (!token->limit) + { + token->start = 0; + token->type = t1_token_none; + } + + parser->cursor = cur; + } + } + + + LOCAL_FUNC + void CID_ToTokenArray( CID_Parser* parser, + T1_Token_Rec* tokens, + FT_UInt max_tokens, + FT_Int *pnum_tokens ) + { + T1_Token_Rec master; + + *pnum_tokens = -1; + + CID_ToToken( parser, &master ); + if (master.type == t1_token_array) + { + FT_Byte* old_cursor = parser->cursor; + FT_Byte* old_limit = parser->limit; + T1_Token_Rec* cur = tokens; + T1_Token_Rec* limit = cur + max_tokens; + + parser->cursor = master.start; + parser->limit = master.limit; + + while (parser->cursor < parser->limit) + { + T1_Token_Rec token; + + CID_ToToken( parser, &token ); + if (!token.type) + break; + + if (cur < limit) + *cur = token; + + cur++; + } + + *pnum_tokens = cur - tokens; + + parser->cursor = old_cursor; + parser->limit = old_limit; + } + } + + + static + FT_Long t1_toint( FT_Byte* *cursor, + FT_Byte* limit ) + { + FT_Long result = 0; + FT_Byte* cur = *cursor; + FT_Byte c, d; + + for (; cur < limit; cur++) + { + c = *cur; + d = (FT_Byte)(c - '0'); + if (d < 10) break; + + if ( c=='-' ) + { + cur++; + break; + } + } + + if (cur < limit) + { + do + { + d = (FT_Byte)(cur[0] - '0'); + if (d >= 10) + break; + + result = result*10 + d; + cur++; + + } while (cur < limit); + + if (c == '-') + result = -result; + } + + *cursor = cur; + return result; + } + + + static + FT_Long t1_tofixed( FT_Byte* *cursor, + FT_Byte* limit, + FT_Long power_ten ) + { + FT_Byte* cur = *cursor; + FT_Long num, divider, result; + FT_Int sign = 0; + FT_Byte d; + + if (cur >= limit) return 0; + + /* first of all, read the integer part */ + result = t1_toint( &cur, limit ) << 16; + num = 0; + divider = 1; + + if (result < 0) + { + sign = 1; + result = -result; + } + if (cur >= limit) goto Exit; + + /* read decimal part, if any */ + if (*cur == '.' && cur+1 < limit) + { + cur++; + + for (;;) + { + d = (FT_Byte)(*cur - '0'); + if (d >= 10) break; + + if (divider < 10000000L) + { + num = num*10 + d; + divider *= 10; + } + cur++; + if (cur >= limit) break; + } + } + + /* read exponent, if any */ + if ( cur+1 < limit && (*cur == 'e' || *cur == 'E')) + { + cur++; + power_ten += t1_toint( &cur, limit ); + } + + Exit: + /* raise to power of ten if needed */ + while (power_ten > 0) + { + result = result*10; + num = num*10; + power_ten--; + } + + while (power_ten < 0) + { + result = result/10; + divider = divider*10; + power_ten++; + } + + if (num) + result += FT_DivFix( num, divider ); + + if (sign) + result = -result; + + *cursor = cur; + return result; + } + + + static + int t1_tobool( FT_Byte* *cursor, FT_Byte* limit ) + { + FT_Byte* cur = *cursor; + T1_Bool result = 0; + + /* return 1 if we find a "true", 0 otherwise */ + if ( cur+3 < limit && + cur[0] == 't' && + cur[1] == 'r' && + cur[2] == 'u' && + cur[3] == 'e' ) + { + result = 1; + cur += 5; + } + else if ( cur+4 < limit && + cur[0] == 'f' && + cur[1] == 'a' && + cur[2] == 'l' && + cur[3] == 's' && + cur[4] == 'e' ) + { + result = 0; + cur += 6; + } + *cursor = cur; + return result; + } + + + static + FT_Int t1_tocoordarray( FT_Byte* *cursor, + FT_Byte* limit, + FT_Int max_coords, + FT_Short* coords ) + { + FT_Byte* cur = *cursor; + FT_Int count = 0; + FT_Byte c, ender; + + if (cur >= limit) goto Exit; + + /* check for the beginning of an array. If not, only one number will be read */ + c = *cur; + ender = 0; + + if (c == '[') + ender = ']'; + + if (c == '{') + ender = '}'; + + if (ender) + cur++; + + /* now, read the coordinates */ + for ( ; cur < limit; ) + { + /* skip whitespace in front of data */ + for (;;) + { + c = *cur; + if ( c != ' ' && c != '\t' ) break; + + cur++; + if (cur >= limit) goto Exit; + } + + if (count >= max_coords || c == ender) + break; + + coords[count] = (T1_Short)(t1_tofixed(&cur,limit,0) >> 16); + count++; + + if (!ender) + break; + } + + Exit: + *cursor = cur; + return count; + } + + + + static + FT_Int t1_tofixedarray( FT_Byte* *cursor, + FT_Byte* limit, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + FT_Byte* cur = *cursor; + FT_Int count = 0; + FT_Byte c, ender; + + if (cur >= limit) goto Exit; + + /* check for the beginning of an array. If not, only one number will be read */ + c = *cur; + ender = 0; + + if (c == '[') + ender = ']'; + + if (c == '{') + ender = '}'; + + if (ender) + cur++; + + /* now, read the values */ + for ( ; cur < limit; ) + { + /* skip whitespace in front of data */ + for (;;) + { + c = *cur; + if ( c != ' ' && c != '\t' ) break; + + cur++; + if (cur >= limit) goto Exit; + } + + if (count >= max_values || c == ender) + break; + + values[count] = t1_tofixed(&cur,limit,power_ten); + count++; + + if (!ender) + break; + } + + Exit: + *cursor = cur; + return count; + } + + + + /* Loads a simple field (i.e. non-table) into the current list of objects */ + LOCAL_FUNC + FT_Error CID_Load_Field( CID_Parser* parser, + const T1_Field_Rec* field, + void* object ) + { + T1_Token_Rec token; + FT_Byte* cur; + FT_Byte* limit; + FT_UInt count; + FT_UInt index; + FT_Error error; + + CID_ToToken( parser, &token ); + if (!token.type) + goto Fail; + + count = 1; + index = 0; + cur = token.start; + limit = token.limit; + + { + FT_Byte* q = (FT_Byte*)object + field->offset; + FT_Long val; + T1_String* string; + + switch (field->type) + { + case t1_field_bool: + { + val = t1_tobool( &cur, limit ); + goto Store_Integer; + } + + case t1_field_fixed: + { + val = t1_tofixed( &cur, limit, 0 ); + goto Store_Integer; + } + + case t1_field_integer: + { + val = t1_toint( &cur, limit ); + Store_Integer: + switch (field->size) + { + case 1: *(FT_Byte*) q = (FT_Byte)val; break; + case 2: *(FT_UShort*)q = (FT_UShort)val; break; + default: *(FT_Long*) q = val; + } + } + break; + + case t1_field_string: + { + FT_Memory memory = parser->memory; + FT_UInt len = limit-cur; + + if ( ALLOC( string, len+1 ) ) + goto Exit; + + MEM_Copy( string, cur, len ); + string[len] = 0; + + *(T1_String**)q = string; + } + break; + + default: + /* an error occured */ + goto Fail; + } + } + error = 0; + + Exit: + return error; + Fail: + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + +#define CID_MAX_TABLE_ELEMENTS 32 + + LOCAL_FUNC + FT_Error CID_Load_Field_Table( CID_Parser* parser, + const T1_Field_Rec* field, + void* object ) + { + T1_Token_Rec elements[CID_MAX_TABLE_ELEMENTS]; + T1_Token_Rec* token; + FT_Int num_elements; + FT_Error error = 0; + FT_Byte* old_cursor; + FT_Byte* old_limit; + T1_Field_Rec fieldrec = *(T1_Field_Rec*)field; + + fieldrec.type = t1_field_integer; + if (field->type == t1_field_fixed_array ) + fieldrec.type = t1_field_fixed; + + CID_ToTokenArray( parser, elements, 32, &num_elements ); + if (num_elements < 0) + goto Fail; + + if (num_elements > CID_MAX_TABLE_ELEMENTS) + num_elements = CID_MAX_TABLE_ELEMENTS; + + old_cursor = parser->cursor; + old_limit = parser->limit; + + /* we store the elements count */ + if (field->count_offset) + *(FT_Byte*)((FT_Byte*)object + field->count_offset) = num_elements; + + /* we now load each element, adjusting the field.offset on each one */ + token = elements; + for ( ; num_elements > 0; num_elements--, token++ ) + { + parser->cursor = token->start; + parser->limit = token->limit; + CID_Load_Field( parser, &fieldrec, object ); + fieldrec.offset += fieldrec.size; + } + + parser->cursor = old_cursor; + parser->limit = old_limit; + + Exit: + return error; + Fail: + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + + + + + + + LOCAL_FUNC + FT_Long CID_ToInt ( CID_Parser* parser ) + { + return t1_toint( &parser->cursor, parser->limit ); + } + + + LOCAL_FUNC + FT_Int CID_ToCoordArray( CID_Parser* parser, + FT_Int max_coords, + FT_Short* coords ) + { + return t1_tocoordarray( &parser->cursor, parser->limit, max_coords, coords ); + } + + + LOCAL_FUNC + FT_Int CID_ToFixedArray( CID_Parser* parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + return t1_tofixedarray( &parser->cursor, parser->limit, max_values, values, power_ten ); + } + + +#if 0 + /* return the value of an hexadecimal digit */ + static + int hexa_value( char c ) + { + unsigned int d; + + d = (unsigned int)(c-'0'); + if ( d <= 9 ) return (int)d; + + d = (unsigned int)(c-'a'); + if ( d <= 5 ) return (int)(d+10); + + d = (unsigned int)(c-'A'); + if ( d <= 5 ) return (int)(d+10); + + return -1; + } +#endif + + + LOCAL_FUNC + FT_Error CID_New_Parser( CID_Parser* parser, + FT_Stream stream, + FT_Memory memory ) + { + FT_Error error; + FT_ULong base_offset, offset, ps_len; + FT_Byte buffer[ 256 + 10 ]; + FT_Int buff_len; + + MEM_Set( parser, 0, sizeof(*parser ) ); + parser->stream = stream; + parser->memory = memory; + + base_offset = FILE_Pos(); + + /* first of all, check the font format in the header */ + if ( ACCESS_Frame(31) ) + goto Exit; + + if ( strncmp( stream->cursor, "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) + { + FT_ERROR(( "Not a valid CID-keyed font\n" )); + error = FT_Err_Unknown_File_Format; + } + + FORGET_Frame(); + if (error) goto Exit; + + /* now, read the rest of the file, until we find a "StartData" */ + buff_len = 256; + for (;;) + { + FT_Byte *p, *limit = buffer + 256; + + /* fill input buffer */ + buff_len -= 256; + if (buff_len > 0) + MEM_Move( buffer, limit, buff_len ); + + if ( FILE_Read( buffer, 256+10-buff_len ) ) + goto Exit; + + buff_len = 256+10; + + /* look for "StartData" */ + for ( p = buffer; p < limit; p++ ) + { + if ( p[0] == 'S' && strncmp( (char*)p, "StartData", 9 ) == 0 ) + { + /* save offset of binary data after "StartData" */ + offset = FILE_Pos() - ( limit-p ) + 10; + goto Found; + } + } + } + + Found: + /* all right, we found the start of the binary data. We will now rewind */ + /* and extract the frame of corresponding to the Postscript section */ + ps_len = offset - base_offset; + if ( FILE_Seek( base_offset ) || + EXTRACT_Frame( ps_len, parser->postscript ) ) + goto Exit; + + parser->data_offset = offset; + parser->postscript_len = ps_len; + parser->cursor = parser->postscript; + parser->limit = parser->cursor + ps_len; + parser->num_dict = -1; + + Exit: + return error; + } + + + + LOCAL_FUNC + void CID_Done_Parser( CID_Parser* parser ) + { + /* always free the private dictionary */ + if (parser->postscript) + { + FT_Stream stream = parser->stream; + RELEASE_Frame( parser->postscript ); + } + } + diff --git a/src/cid/cidparse.h b/src/cid/cidparse.h new file mode 100644 index 000000000..b249fe916 --- /dev/null +++ b/src/cid/cidparse.h @@ -0,0 +1,347 @@ +/******************************************************************* + * + * cidparse.h 2.0 + * + * CID-Keyed Type1 parser. + * + * Copyright 1996-1998 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. + * + * The Type 1 parser is in charge of the following: + * + * - provide an implementation of a growing sequence of + * objects called a T1_Table (used to build various tables + * needed by the loader). + * + * - opening .pfb and .pfa files to extract their top-level + * and private dictionaries + * + * - read numbers, arrays & strings from any dictionary + * + * See "t1load.c" to see how data is loaded from the font file + * + ******************************************************************/ + +#ifndef CIDPARSE_H +#define CIDPARSE_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + + +#if 0 +/************************************************************************* + * + * T1_Table + * + * + * A T1_Table is a simple object used to store an array of objects + * in a single memory block. + * + * + * block :: address in memory of the growheap's block. This + * can change between two object adds, due to the use + * of 'realloc'. + * + * cursor :: current top of the grow heap within its block + * + * capacity :: current size of the heap block. Increments by 1 Kb + * + * init :: boolean. set when the table has been initialized + * (the table user should set this field) + * + * max_elems :: maximum number of elements in table + * num_elems :: current number of elements in table + * + * elements :: table of element addresses within the block + * lengths :: table of element sizes within the block + * + * memory :: memory object used for memory operations (alloc/realloc) + */ + + typedef struct T1_Table_ + { + FT_Byte* block; /* current memory block */ + FT_Int cursor; /* current cursor in memory block */ + FT_Int capacity; /* current size of memory block */ + FT_Long init; + + FT_Int max_elems; + FT_Int num_elems; + FT_Byte** elements; /* addresses of table elements */ + FT_Int* lengths; /* lengths of table elements */ + + FT_Memory memory; + + } T1_Table; + + + LOCAL_DEF + FT_Error T1_New_Table( T1_Table* table, + FT_Int count, + FT_Memory memory ); + + + LOCAL_DEF + FT_Error T1_Add_Table( T1_Table* table, + FT_Int index, + void* object, + FT_Int length ); + + LOCAL_DEF + void T1_Release_Table( T1_Table* table ); +#endif + +/************************************************************************* + * + * CID_Parser + * + * + * A CID_Parser is an object used to parse a Type 1 fonts very + * quickly. + * + * + * stream :: current input stream + * memory :: current memory object + * + * base_dict :: pointer to top-level dictionary + * base_len :: length in bytes of top dict + * + * private_dict :: pointer to private dictionary + * private_len :: length in bytes of private dict + * + * in_pfb :: boolean. Indicates that we're in a .pfb file + * in_memory :: boolean. Indicates a memory-based stream + * single_block :: boolean. Indicates that the private dict + * is stored in lieu of the base dict + * + * cursor :: current parser cursor + * limit :: current parser limit (first byte after current + * dictionary). + * + * error :: current parsing error + */ + + typedef struct CID_Parser_ + { + FT_Stream stream; + FT_Memory memory; + + FT_Byte* postscript; + FT_Int postscript_len; + + FT_ULong data_offset; + + FT_Byte* cursor; + FT_Byte* limit; + FT_Error error; + + CID_Info* cid; + FT_Int num_dict; + + } CID_Parser; + + + LOCAL_DEF + FT_Error CID_New_Parser( CID_Parser* parser, + FT_Stream stream, + FT_Memory memory ); + + LOCAL_DEF + void CID_Done_Parser( CID_Parser* parser ); + + + /************************************************************************* + * + * PARSING ROUTINES + * + *************************************************************************/ + + LOCAL_DEF + FT_Long CID_ToInt ( CID_Parser* parser ); + + LOCAL_DEF + FT_Int CID_ToCoordArray( CID_Parser* parser, + FT_Int max_coords, + FT_Short* coords ); + + LOCAL_DEF + FT_Int CID_ToFixedArray( CID_Parser* parser, + FT_Int max_values, + T1_Fixed* values, + FT_Int power_ten ); + + LOCAL_DEF + void CID_Skip_Spaces( CID_Parser* parser ); + + + + /* simple enumeration type used to identify token types */ + typedef enum T1_Token_Type_ + { + t1_token_none = 0, + t1_token_any, + t1_token_string, + t1_token_array, + + /* do not remove */ + t1_token_max + + } T1_Token_Type; + + /* a simple structure used to identify tokens */ + typedef struct T1_Token_Rec_ + { + FT_Byte* start; /* first character of token in input stream */ + FT_Byte* limit; /* first character after the token */ + T1_Token_Type type; /* type of token.. */ + + } T1_Token_Rec; + + + LOCAL_DEF + void CID_ToToken( CID_Parser* parser, + T1_Token_Rec* token ); + + + + + + + + /* enumeration type used to identify object fields */ + typedef enum T1_Field_Type_ + { + t1_field_none = 0, + t1_field_bool, + t1_field_integer, + t1_field_fixed, + t1_field_string, + t1_field_integer_array, + t1_field_fixed_array, + t1_field_callback, + + /* do not remove */ + t1_field_max + + } T1_Field_Type; + + typedef enum T1_Field_Location_ + { + t1_field_cid_info, + t1_field_font_dict, + t1_field_font_info, + t1_field_private, + + /* do not remove */ + t1_field_location_max + + } T1_Field_Location; + + + typedef FT_Error (*CID_Field_Parser)( CID_Face face, + CID_Parser* parser ); + + /* structure type used to model object fields */ + typedef struct T1_Field_Rec_ + { + const char* ident; /* field identifier */ + T1_Field_Location location; + T1_Field_Type type; /* type of field */ + CID_Field_Parser reader; + T1_UInt offset; /* offset of field in object */ + FT_UInt size; /* size of field in bytes */ + FT_UInt array_max; /* maximum number of elements for array */ + FT_UInt count_offset; /* offset of element count for arrays */ + + } T1_Field_Rec; + +#define T1_FIELD_REF(s,f) (((s*)0)->f) + +#define T1_NEW_SIMPLE_FIELD( _ident, _type, _fname ) \ + { _ident, T1CODE, _type, \ + 0, \ + (FT_UInt)(char*)&T1_FIELD_REF(T1TYPE,_fname), \ + sizeof(T1_FIELD_REF(T1TYPE,_fname)), \ + 0, 0 }, + +#define T1_NEW_CALLBACK_FIELD( _ident, _reader ) \ + { _ident, T1CODE, t1_field_callback, \ + _reader, \ + 0, 0, 0, 0 }, + +#define T1_NEW_TABLE_FIELD( _ident, _type, _fname, _max ) \ + { _ident, T1CODE, _type, \ + 0, \ + (FT_UInt)(char*)&T1_FIELD_REF(T1TYPE,_fname), \ + sizeof(T1_FIELD_REF(T1TYPE,_fname)[0]), \ + _max, \ + (FT_UInt)(char*)&T1_FIELD_REF(T1TYPE,num_ ## _fname) }, + +#define T1_NEW_TABLE_FIELD2( _ident, _type, _fname, _max ) \ + { _ident, T1CODE, _type, \ + 0, \ + (FT_UInt)(char*)&T1_FIELD_REF(T1TYPE,_fname), \ + sizeof(T1_FIELD_REF(T1TYPE,_fname)[0]), \ + _max, 0 }, + + +#define T1_FIELD_BOOL( _ident, _fname ) \ + T1_NEW_SIMPLE_FIELD( _ident, t1_field_bool, _fname ) + +#define T1_FIELD_NUM( _ident, _fname ) \ + T1_NEW_SIMPLE_FIELD( _ident, t1_field_integer, _fname ) + +#define T1_FIELD_FIXED( _ident, _fname ) \ + T1_NEW_SIMPLE_FIELD( _ident, t1_field_fixed, _fname ) + +#define T1_FIELD_STRING( _ident, _fname ) \ + T1_NEW_SIMPLE_FIELD( _ident, t1_field_string, _fname ) + +#define T1_FIELD_NUM_TABLE( _ident, _fname, _fmax ) \ + T1_NEW_TABLE_FIELD( _ident, t1_field_integer_array, _fname, _fmax ) + +#define T1_FIELD_FIXED_TABLE( _ident, _fname, _fmax ) \ + T1_NEW_TABLE_FIELD( _ident, t1_field_fixed_array, _fname, _fmax ) + +#define T1_FIELD_NUM_TABLE2( _ident, _fname, _fmax ) \ + T1_NEW_TABLE_FIELD2( _ident, t1_field_integer_array, _fname, _fmax ) + +#define T1_FIELD_FIXED_TABLE2( _ident, _fname, _fmax ) \ + T1_NEW_TABLE_FIELD2( _ident, t1_field_fixed_array, _fname, _fmax ) + +#define T1_FIELD_CALLBACK( _ident, _name ) \ + T1_NEW_CALLBACK_FIELD( _ident, parse_ ## _name ) + + LOCAL_DEF + FT_Error CID_Load_Field( CID_Parser* parser, + const T1_Field_Rec* field, + void* object ); + + LOCAL_DEF + FT_Error CID_Load_Field_Table( CID_Parser* parser, + const T1_Field_Rec* field, + void* object ); + + + + +#ifdef __cplusplus + } +#endif + +#endif /* CIDPARSE_H */ + + +/* END */ + diff --git a/src/cid/cidriver.c b/src/cid/cidriver.c new file mode 100644 index 000000000..5bbd26053 --- /dev/null +++ b/src/cid/cidriver.c @@ -0,0 +1,428 @@ +/******************************************************************* + * + * t1driver.c + * + * High-level Type1 driver interface for FreeType 2.0 + * + * Copyright 1996-1998 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. + * + ******************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1driver + + /*************************************************************************/ + /* */ + /* */ + /* Get_Interface */ + /* */ + /* */ + /* Each driver can provide one or more extensions to the base */ + /* FreeType API. These can be used to access format specific */ + /* features (e.g., all TrueType/OpenType resources share a common */ + /* file structure and common tables which can be accessed through the */ + /* `sfnt' interface), or more simply generic ones (e.g., the */ + /* `postscript names' interface which can be used to retrieve the */ + /* PostScript name of a given glyph index). */ + /* */ + /* */ + /* driver :: A handle to a driver object. */ + /* */ + /* */ + /* interface :: A string designing the interface. Examples are */ + /* `sfnt', `post_names', `charmaps', etc. */ + /* */ + /* */ + /* A typeless pointer to the extension's interface (normally a table */ + /* of function pointers). Returns NULL if the requested extension */ + /* isn't available (i.e., wasn't compiled in the driver at build */ + /* time). */ + /* */ + static + FTDriver_Interface Get_Interface( FT_Driver driver, + const FT_String* interface ) + { + UNUSED(driver); + UNUSED(interface); + + return 0; + } + + +#ifdef xxxT1_CONFIG_OPTION_NO_AFM + /*************************************************************************/ + /* */ + /* */ + /* Get_Kerning */ + /* */ + /* */ + /* A driver method used to return the kerning vector between two */ + /* glyphs of the same face. */ + /* */ + /* */ + /* face :: A handle to the source face object. */ + /* */ + /* left_glyph :: The index of the left glyph in the kern pair. */ + /* */ + /* right_glyph :: The index of the right glyph in the kern pair. */ + /* */ + /* */ + /* kerning :: The kerning vector. This is in font units for */ + /* scalable formats, and in pixels for fixed-sizes */ + /* formats. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* Only horizontal layouts (left-to-right & right-to-left) are */ + /* supported by this function. Other layouts, or more sophisticated */ + /* kernings are out of scope of this method (the basic driver */ + /* interface is meant to be simple). */ + /* */ + /* They can be implemented by format-specific interfaces. */ + /* */ + static + FT_Error Get_Kerning( T1_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + T1_Vector* kerning ) + { + T1_AFM* afm; + + kerning->x = 0; + kerning->y = 0; + + afm = (T1_AFM*)face->afm_data; + if (afm) + CID_Get_Kerning( afm, left_glyph, right_glyph, kerning ); + + return T1_Err_Ok; + } +#endif + + /******************************************************************/ + /* */ + /* Set_Char_Sizes */ + /* */ + /* */ + /* A driver method used to reset a size's character sizes */ + /* (horizontal and vertical) expressed in fractional points. */ + /* */ + /* */ + /* size :: handle to target size object */ + /* char_width :: character width expressed in 26.6 points */ + /* char_height :: character height expressed in 26.6 points */ + /* */ + /* */ + /* FreeType error code. 0 means success */ + /* */ + static + FT_Error Set_Char_Sizes( T1_Size size, + T1_F26Dot6 char_width, + T1_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ) + { + UNUSED(char_width); + UNUSED(char_height); + UNUSED(horz_resolution); + UNUSED(vert_resolution); + + size->valid = FALSE; + return T1_Reset_Size( size ); + } + + + /******************************************************************/ + /* */ + /* Set_Pixel_Sizes */ + /* */ + /* */ + /* A driver method used to reset a size's character sizes */ + /* (horizontal and vertical) expressed in integer pixels. */ + /* */ + /* */ + /* size :: handle to target size object */ + /* */ + /* pixel_width :: character width expressed in 26.6 points */ + /* */ + /* pixel_height :: character height expressed in 26.6 points */ + /* */ + /* char_size :: the corresponding character size in points */ + /* This value is only sent to the TrueType */ + /* bytecode interpreter, even though 99% of */ + /* glyph programs will simply ignore it. A */ + /* safe value there is the maximum of the */ + /* pixel width and height (multiplied by */ + /* 64 to make it a 26.6 fixed float !) */ + /* */ + /* FreeType error code. 0 means success */ + /* */ + static + FT_Error Set_Pixel_Sizes( T1_Size size, + FT_Int pixel_width, + FT_Int pixel_height ) + { + UNUSED(pixel_width); + UNUSED(pixel_height); + + size->valid = FALSE; + return T1_Reset_Size(size); + } + + /*************************************************************************/ + /* */ + /* */ + /* 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 ) + { + T1_Face face; + FT_UInt result = 0; + PSNames_Interface* psnames; + + face = (T1_Face)charmap->face; + psnames = (PSNames_Interface*)face->psnames; + if (psnames) + switch (charmap->encoding) + { + /********************************************************************/ + /* */ + /* Unicode encoding support */ + /* */ + case ft_encoding_unicode: + { + /* use the "psnames" module to synthetize the Unicode charmap */ + result = psnames->lookup_unicode( &face->unicode_map, + (FT_ULong)charcode ); + + /* the function returns 0xFFFF when the Unicode charcode has */ + /* no corresponding glyph.. */ + if (result == 0xFFFF) + 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) + { + result = encoding->char_index[charcode]; + } + 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 && gname[0] == glyph_name[0] && + strcmp( gname, glyph_name ) == 0 ) + { + result = n; + break; + } + } + } + } + Exit: + return result; + } + + + /******************************************************************/ + /* */ + /* FT_DriverInterface */ + /* */ + /* */ + /* A structure used to hold a font driver's basic interface */ + /* used by the high-level parts of FreeType (or other apps) */ + /* */ + /* Most scalable drivers provide a specialized interface to */ + /* access format-specific features. It can be retrieved with */ + /* a call to the "get_format_interface", and should be defined */ + /* in each font driver header (e.g. ttdriver.h, t1driver.h,..) */ + /* */ + /* All fields are function pointers .. */ + /* */ + /* */ + /* */ + /* */ + /* new_engine :: */ + /* used to create and initialise a new driver object */ + /* */ + /* done_engine :: */ + /* used to finalise and destroy a given driver object */ + /* */ + /* get_format_interface :: */ + /* return a typeless pointer to the format-specific */ + /* driver interface. */ + /* */ + /* new_face :: */ + /* create a new face object from a resource */ + /* */ + /* done_face :: */ + /* discards a face object, as well as all child objects */ + /* ( sizes, charmaps, glyph slots ) */ + /* */ + /* get_face_properties :: */ + /* return generic face properties */ + /* */ + /* get_kerning :: */ + /* return the kerning vector corresponding to a pair */ + /* of glyphs, expressed in unscaled font units. */ + /* */ + /* new_size :: */ + /* create and initialise a new scalable size object. */ + /* */ + /* new_fixed_size :: */ + /* create and initialise a new fixed-size object. */ + /* */ + /* done_size :: */ + /* finalize a given face size object. */ + /* */ + /* set_size_resolutions :: */ + /* reset a scalable size object's output resolutions */ + /* */ + /* set_size_char_sizes :: */ + /* reset a scalable size object's character size */ + /* */ + /* set_pixel_sizes :: */ + /* reset a face size object's pixel dimensions. Applies */ + /* to both scalable and fixed faces. */ + /* */ + /* new_glyph_slot :: */ + /* create and initialise a new glyph slot */ + /* */ + /* done_glyph_slot :: */ + /* discard a given glyph slot */ + /* */ + /* load_glyph :: */ + /* load a given glyph into a given slot */ + /* */ + /* get_glyph_metrics :: */ + /* return a loaded glyph's metrics. */ + /* */ + + const FT_DriverInterface t1cid_driver_interface = + { + sizeof( FT_DriverRec ), + sizeof( CID_FaceRec ), + sizeof( T1_SizeRec ), + sizeof( T1_GlyphSlotRec ), + + "type1", + 100, + 200, + + 0, /* format interface */ + + (FTDriver_initDriver) T1_Init_Driver, + (FTDriver_doneDriver) T1_Done_Driver, + + (FTDriver_getInterface) Get_Interface, + + (FTDriver_initFace) T1_Init_Face, + (FTDriver_doneFace) T1_Done_Face, + +#ifndef xxxxT1_CONFIG_OPTION_NO_AFM + (FTDriver_getKerning) 0, +#else + (FTDriver_getKerning) Get_Kerning, +#endif + + (FTDriver_initSize) T1_Init_Size, + (FTDriver_doneSize) T1_Done_Size, + (FTDriver_setCharSizes) Set_Char_Sizes, + (FTDriver_setPixelSizes) Set_Pixel_Sizes, + + (FTDriver_initGlyphSlot) T1_Init_GlyphSlot, + (FTDriver_doneGlyphSlot) T1_Done_GlyphSlot, + (FTDriver_loadGlyph) CID_Load_Glyph, + + (FTDriver_getCharIndex) Get_Char_Index, + }; + + + /******************************************************************/ + /* */ + /* Get_FreeType_Driver_Interface */ + /* */ + /* */ + /* This function is used when compiling the TrueType driver */ + /* as a shared library (.DLL or .so). It will be used by the */ + /* high-level library of FreeType to retrieve the address of */ + /* the driver's generic interface. */ + /* */ + /* It shouldn't be implemented in a static build, as each */ + /* driver must have the same function as an exported entry */ + /* point. */ + /* */ + /* */ + /* address of TrueType's driver generic interface. The */ + /* forma-specific interface can then be retrieved through */ + /* the method interface->get_format_interface.. */ + /* */ + +#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS + + EXPORT_FUNC(FT_DriverInterface*) getDriverInterface( void ) + { + return &t1cid_driver_interface; + } + +#endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */ + + diff --git a/src/cid/cidriver.h b/src/cid/cidriver.h new file mode 100644 index 000000000..42c330891 --- /dev/null +++ b/src/cid/cidriver.h @@ -0,0 +1,27 @@ +/******************************************************************* + * + * t1driver.h + * + * High-level Type1 driver interface for FreeType 2.0 + * + * Copyright 1996-1998 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 T1DRIVER_H +#define T1DRIVER_H + +#include +#include + + FT_EXPORT_VAR(const FT_DriverInterface) t1cid_driver_interface; + +#endif /* T1DRIVER_H */ + diff --git a/src/cid/cidtokens.h b/src/cid/cidtokens.h new file mode 100644 index 000000000..65d5752b9 --- /dev/null +++ b/src/cid/cidtokens.h @@ -0,0 +1,94 @@ +/******************************************************************* + * + * t1tokens.h + * + * Type 1 tokens definition + * + * Copyright 2000 David Turner, Robert Wilhelm and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used + * modified and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + * This file only contains macros that are expanded when compiling + * the "t1load.c" source file. + * + ******************************************************************/ + +#define T1TYPE CID_Info +#define T1CODE t1_field_cid_info + + T1_FIELD_STRING ( "CIDFontName", cid_font_name ) + T1_FIELD_NUM ( "CIDFontVersion", cid_version ) + T1_FIELD_NUM ( "CIDFontType", cid_font_type ) + T1_FIELD_STRING ( "Registry", registry ) + T1_FIELD_STRING ( "Ordering", ordering ) + T1_FIELD_NUM ( "Supplement", supplement ) + T1_FIELD_CALLBACK( "FontBBox", font_bbox ) + T1_FIELD_NUM ( "UIDBase", uid_base ) + T1_FIELD_CALLBACK( "FDArray", fd_array ) + T1_FIELD_NUM ( "CIDMapOffset", cidmap_offset ) + T1_FIELD_NUM ( "FDBytes", fd_bytes ) + T1_FIELD_NUM ( "GDBytes", gd_bytes ) + T1_FIELD_NUM ( "CIDCount", cid_count ) + +#undef T1TYPE +#undef T1CODE +#define T1TYPE T1_FontInfo +#define T1CODE t1_field_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_FIXED ( "ItalicAngle", italic_angle ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness ) + +#undef T1TYPE +#undef T1CODE +#define T1TYPE CID_FontDict +#define T1CODE t1_field_font_dict + + T1_FIELD_CALLBACK( "FontMatrix", font_matrix ) + T1_FIELD_NUM ( "PaintType", paint_type ) + T1_FIELD_NUM ( "FontType", font_type ) + T1_FIELD_NUM ( "SubrMapOffset", subrmap_offset ) + T1_FIELD_NUM ( "SDBytes", sd_bytes ) + T1_FIELD_NUM ( "SubrCount", num_subrs ) + T1_FIELD_NUM ( "lenBuildCharArray", len_buildchar ) + T1_FIELD_FIXED ( "ForceBoldThreshold", forcebold_threshold ) + T1_FIELD_FIXED ( "ExpansionFactor", expansion_factor ) + T1_FIELD_NUM ( "StrokeWidth", stroke_width ) + +#undef T1TYPE +#undef T1CODE +#define T1TYPE T1_Private +#define T1CODE t1_field_private + + T1_FIELD_NUM ( "UniqueID", unique_id ) + T1_FIELD_NUM ( "lenIV", lenIV ) + T1_FIELD_NUM ( "LanguageGroup", language_group ) + T1_FIELD_NUM ( "password", password ) + + T1_FIELD_FIXED( "BlueScale", blue_scale ) + T1_FIELD_NUM ( "BlueShift", blue_shift ) + T1_FIELD_NUM ( "BlueFuzz", blue_fuzz ) + + T1_FIELD_NUM_TABLE( "BlueValues", blue_values, 14 ) + T1_FIELD_NUM_TABLE( "OtherBlues", other_blues, 10 ) + T1_FIELD_NUM_TABLE( "FamilyBlues", family_blues, 14 ) + T1_FIELD_NUM_TABLE( "FamilyOtherBlues", family_other_blues, 10 ) + + T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1 ) + T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1 ) + T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2 ) + + T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12 ) + T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12 ) + + diff --git a/src/cid/module.mk b/src/cid/module.mk new file mode 100644 index 000000000..ce6551417 --- /dev/null +++ b/src/cid/module.mk @@ -0,0 +1,6 @@ +make_module_list: add_type1cid_driver + +add_type1cid_driver: + $(OPEN_DRIVER)t1cid_driver_interface$(CLOSE_DRIVER) + $(ECHO_DRIVER)cid $(ECHO_DRIVER_DESC)Postscript CID-keyed fonts, no known extension$(ECHO_DRIVER_DONE) +# EOF diff --git a/src/cid/rules.mk b/src/cid/rules.mk new file mode 100644 index 000000000..b08481a7d --- /dev/null +++ b/src/cid/rules.mk @@ -0,0 +1,97 @@ +# +# FreeType 2 driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used modified +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +#**************************************************************************** +#* * +#* The "Type1z" driver is an experimental replacement for the current * +#* Type 1 driver. It features a very different loading mechanism that * +#* is much faster than the one used by the `normal' driver, and also * +#* deals nicely with nearly broken Type 1 font files. It is also * +#* much smaller... * +#* * +#* Note that it may become a permanent replacement of the current * +#* "src/type1" driver in the future.. * +#* * +#**************************************************************************** + +# Type1z driver directory +# +CID_DIR := $(SRC_)cid +CID_DIR_ := $(CID_DIR)$(SEP) + + +# additional include flags used when compiling the driver +# +CID_INCLUDE := $(SHARED) $(CID_DIR) +CID_COMPILE := $(FT_COMPILE) $(CID_INCLUDE:%=$I%) + + +# Type1 driver sources (i.e., C files) +# +CID_DRV_SRC := $(CID_DIR_)cidparse.c \ + $(CID_DIR_)cidload.c \ + $(CID_DIR_)cidriver.c \ + $(CID_DIR_)cidgload.c \ + $(CID_DIR_)cidafm.c + +# Type1 driver headers +# +CID_DRV_H := $(CID_DIR_)t1errors.h \ + $(CID_DIR_)cidtokens.h \ + $(T1SHARED_H) \ + $(CID_DRV_SRC:%.c=%.h) + + +# driver object(s) +# +# CID_DRV_OBJ_M is used during `debug' builds +# CID_DRV_OBJ_S is used during `release' builds +# +CID_DRV_OBJ_M := $(CID_DRV_SRC:$(CID_DIR_)%.c=$(OBJ_)%.$O) \ + $(T1SHARED:$(T1SHARED_DIR_)%.c=$(OBJ_)%.$O) +CID_DRV_OBJ_S := $(OBJ_)type1cid.$O + + +# driver source file(s) +# +CID_DRV_SRC_M := $(CID_DRV_SRC) $(T1SHARED_SRC) +CID_DRV_SRC_S := $(CID_DIR_)type1cid.c + + +# driver - single object +# +# the driver is recompiled if any of the header or source files is changed +# +$(CID_DRV_OBJ_S): $(BASE_H) $(CID_DRV_H) $(CID_DRV_SRC) $(CID_DRV_SRC_S) + $(CID_COMPILE) $T$@ $(CID_DRV_SRC_S) + + +# driver - multiple objects +# +# All objects are recompiled if any of the header files is changed +# +$(OBJ_)t1%.$O: $(CID_DIR_)t1%.c $(BASE_H) $(CID_DRV_H) + $(CID_COMPILE) $T$@ $< + +$(OBJ_)t1%.$O: $(T1SHARED_DIR_)t1%.c $(BASE_H) $(T1SHARED_H) + $(CID_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(CID_DRV_OBJ_S) +DRV_OBJS_M += $(CID_DRV_OBJ_M) + +# EOF diff --git a/src/cid/t1errors.h b/src/cid/t1errors.h new file mode 100644 index 000000000..a799115a8 --- /dev/null +++ b/src/cid/t1errors.h @@ -0,0 +1,75 @@ +/******************************************************************* + * + * t1errors.h + * + * Type1 Error ID definitions + * + * Copyright 1996-1998 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 T1ERRORS_H +#define T1ERRORS_H + +#include + + /************************ error codes declaration **************/ + + /* The error codes are grouped in 'classes' used to indicate the */ + /* 'level' at which the error happened. */ + /* The class is given by an error code's high byte. */ + + +/* ------------- Success is always 0 -------- */ + +#define T1_Err_Ok FT_Err_Ok + +/* ----------- high level API errors -------- */ + +#define T1_Err_Invalid_File_Format FT_Err_Invalid_File_Format +#define T1_Err_Invalid_Argument FT_Err_Invalid_Argument +#define T1_Err_Invalid_Driver_Handle FT_Err_Invalid_Driver_Handle +#define T1_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle +#define T1_Err_Invalid_Size_Handle FT_Err_Invalid_Size_Handle +#define T1_Err_Invalid_Glyph_Handle FT_Err_Invalid_Slot_Handle +#define T1_Err_Invalid_CharMap_Handle FT_Err_Invalid_CharMap_Handle +#define T1_Err_Invalid_Glyph_Index FT_Err_Invalid_Glyph_Index + +#define T1_Err_Unimplemented_Feature FT_Err_Unimplemented_Feature +#define T1_Err_Unavailable_Outline FT_Err_Unavailable_Outline +#define T1_Err_Unavailable_Bitmap FT_Err_Unavailable_Bitmap +#define T1_Err_Unavailable_Pixmap FT_Err_Unavailable_Pixmap +#define T1_Err_File_Is_Not_Collection FT_Err_File_Is_Not_Collection + +#define T1_Err_Invalid_Engine FT_Err_Invalid_Driver_Handle + +/* ------------- internal errors ------------ */ + +#define T1_Err_Out_Of_Memory FT_Err_Out_Of_Memory +#define T1_Err_Unlisted_Object FT_Err_Unlisted_Object + +/* ------------ general glyph outline errors ------ */ + +#define T1_Err_Too_Many_Points FT_Err_Too_Many_Points +#define T1_Err_Too_Many_Contours FT_Err_Too_Many_Contours +#define T1_Err_Too_Many_Hints FT_Err_Too_Many_Hints +#define T1_Err_Invalid_Composite FT_Err_Invalid_Composite +#define T1_Err_Too_Many_Edges FT_Err_Too_Many_Edges +#define T1_Err_Too_Many_Strokes FT_Err_Too_Many_Strokes + + +#define T1_Err_Syntax_Error FT_Err_Invalid_File_Format +#define T1_Err_Stack_Underflow FT_Err_Invalid_File_Format +#define T1_Err_Stack_Overflow FT_Err_Invalid_File_Format + +#endif /* TDERRORS_H */ + + +/* END */ diff --git a/src/cid/type1cid.c b/src/cid/type1cid.c new file mode 100644 index 000000000..371830f4e --- /dev/null +++ b/src/cid/type1cid.c @@ -0,0 +1,41 @@ +/***************************************************************************/ +/* */ +/* type1.c */ +/* */ +/* FreeType Type 1 driver component */ +/* */ +/* Copyright 1996-1998 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used */ +/* modified and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/* */ +/* This file is used to compile the FreeType Type 1 font driver. */ +/* It relies on all components included in the "base" layer (see */ +/* the file "ftbase.c"). Source code is located in "freetype/ttlib" */ +/* and contains : */ +/* */ +/* - a driver interface */ +/* - an object manager */ +/* - a table loader */ +/* - a glyph loader */ +/* - a glyph hinter */ +/* */ +/***************************************************************************/ + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include +#include +#include +#include +#include + +#if 0 +#include +#endif + diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index f7be82916..2a5ebee10 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -993,13 +993,12 @@ for ( u = 0; u < num_points + 2; u++ ) { glyph->outline.points[u] = loader->base.cur[u]; - glyph->outline.tags [u] = loader->base.tags[u]; + glyph->outline.tags [u] = loader->base.tags[u]; } for ( u = 0; u < num_contours; u++ ) glyph->outline.contours[u] = loader->base.contours[u]; - /* glyph->outline.second_pass = TRUE; */ glyph->outline.flags &= ~ft_outline_single_pass; glyph->outline.n_points = num_points; glyph->outline.n_contours = num_contours; @@ -1029,6 +1028,8 @@ { TT_Pos left_bearing; TT_Pos advance; + + TT_Pos lsb2, adv2; left_bearing = loader->left_bearing; advance = loader->advance; @@ -1042,14 +1043,22 @@ (loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH) == 0 ) advance = face->horizontal.advance_Width_Max; - if ( !(loader->load_flags & FT_LOAD_NO_SCALE) ) + lsb2 = left_bearing; + adv2 = advance; + + /* if necessary, scale the horizontal left bearing and advance */ + /* to get their values in 16.16 format.. */ + if ( !(loader->load_flags & FT_LOAD_NO_SCALE) && + loader->load_flags & FT_LOAD_LINEAR ) { - left_bearing = FT_MulFix( left_bearing, x_scale ); - advance = FT_MulFix( advance, x_scale ); + FT_Pos em_size = face->root.units_per_EM; + FT_Pos pixel_size = (FT_Pos)face->root.size->metrics.x_ppem << 16; + + lsb2 = FT_MulDiv( lsb2, pixel_size, em_size ); + adv2 = FT_MulDiv( adv2, pixel_size, em_size ); } - - glyph->metrics2.horiBearingX = left_bearing; - glyph->metrics2.horiAdvance = advance; + glyph->metrics2.horiBearingX = lsb2; + glyph->metrics2.horiAdvance = adv2; } glyph->metrics.horiBearingX = bbox.xMin; @@ -1131,8 +1140,25 @@ advance = advance_height; } - glyph->metrics2.vertBearingY = Top; - glyph->metrics2.vertAdvance = advance; + /* compute metrics2 fields */ + { + FT_Pos vtb2 = top_bearing; + FT_Pos adv2 = advance_height; + + /* scale to 16.16 format if required */ + if ( !(loader->load_flags & FT_LOAD_NO_SCALE) && + loader->load_flags & FT_LOAD_LINEAR ) + { + FT_Pos em_size = face->root.units_per_EM; + FT_Pos pixel_size = face->root.size->metrics.y_ppem; + + vtb2 = FT_MulDiv( vtb2, pixel_size, em_size ); + adv2 = FT_MulDiv( adv2, pixel_size, em_size ); + } + + glyph->metrics2.vertBearingY = vtb2; + glyph->metrics2.vertAdvance = adv2; + } /* XXX: for now, we have no better algorithm for the lsb, but it */ /* should work fine. */ @@ -1306,7 +1332,7 @@ /* clear all outline flags, except the "owner" one */ glyph->outline.flags &= ft_outline_owner; - if (size && size->root.metrics.y_ppem < 24 ) + if ( size && size->root.metrics.y_ppem < 24 ) glyph->outline.flags |= ft_outline_high_precision; /************************************************************************/ diff --git a/src/type1/t1hinter.c b/src/type1/t1hinter.c index 970a07cda..bdae693ad 100644 --- a/src/type1/t1hinter.c +++ b/src/type1/t1hinter.c @@ -127,7 +127,7 @@ /* First of all, check the sizes of the /BlueValues and /OtherBlues */ /* tables. They all must contain an even number of arguments */ if ( priv->num_other_blues & 1 || - priv->num_blues & 1 ) + priv->num_blue_values & 1 ) { FT_ERROR(( "T1.Copy_Blues : odd number of blue values\n" )); return T1_Err_Syntax_Error; @@ -141,7 +141,7 @@ blues[n] = priv->other_blues[n]; /* Add the first blue zone in /BlueValues to the table */ - num_top = priv->num_blues - 2; + num_top = priv->num_blue_values - 2; if ( num_top >= 0 ) { blues[ num_bottom ] = priv->blue_values[0]; @@ -294,7 +294,7 @@ standard_width = priv->standard_width[0]; n_zones = priv->num_snap_widths; base_zone = hints->snap_widths; - orgs = priv->stem_snap_widths; + orgs = priv->snap_widths; scale = size->root.metrics.x_scale; while (direction < 2) @@ -461,7 +461,7 @@ standard_width = priv->standard_height[0]; n_zones = priv->num_snap_heights; base_zone = hints->snap_heights; - orgs = priv->stem_snap_heights; + orgs = priv->snap_heights; scale = size->root.metrics.y_scale; } diff --git a/src/type1/t1load.c b/src/type1/t1load.c index 823cd08e6..bbacf1543 100644 --- a/src/type1/t1load.c +++ b/src/type1/t1load.c @@ -428,7 +428,7 @@ case imm_BlueValues: - CopyArray( parser, &priv->num_blues, + CopyArray( parser, &priv->num_blue_values, priv->blue_values, 14 ); break; @@ -478,13 +478,13 @@ case imm_StemSnapH: CopyArray( parser, &priv->num_snap_widths, - priv->stem_snap_widths, 12 ); + priv->snap_widths, 12 ); break; case imm_StemSnapV: CopyArray( parser, &priv->num_snap_heights, - priv->stem_snap_heights, 12 ); + priv->snap_heights, 12 ); break; diff --git a/src/type1z/t1tokens.h b/src/type1z/t1tokens.h index ceff4e14e..98f552841 100644 --- a/src/type1z/t1tokens.h +++ b/src/type1z/t1tokens.h @@ -43,7 +43,7 @@ T1_PRIVATE_NUM ( "BlueShift", blue_shift ) T1_PRIVATE_NUM ( "BlueFuzz", blue_fuzz ) - T1_PRIVATE_NUM_TABLE( "BlueValues", blue_values, 14, num_blues ) + T1_PRIVATE_NUM_TABLE( "BlueValues", blue_values, 14, num_blue_values ) T1_PRIVATE_NUM_TABLE( "OtherBlues", other_blues, 10, num_other_blues ) T1_PRIVATE_NUM_TABLE( "FamilyBlues", family_blues, 14, num_family_blues ) T1_PRIVATE_NUM_TABLE( "FamilyOtherBlues", family_other_blues, 10, num_family_other_blues ) @@ -52,8 +52,8 @@ T1_PRIVATE_NUM_TABLE2( "StdVW", standard_height, 1 ) T1_PRIVATE_NUM_TABLE2( "MinFeature", min_feature, 2 ) - T1_PRIVATE_NUM_TABLE ( "StemSnapH", stem_snap_widths, 12, num_snap_widths ) - T1_PRIVATE_NUM_TABLE ( "StemSnapV", stem_snap_heights, 12, num_snap_heights ) + T1_PRIVATE_NUM_TABLE ( "StemSnapH", snap_widths, 12, num_snap_widths ) + T1_PRIVATE_NUM_TABLE ( "StemSnapV", snap_heights, 12, num_snap_heights ) #undef T1TYPE #define T1TYPE T1_Font