ref: 04aa800ce982d340befbec799ed9d3735eb6bd64
parent: 3581d06464d3c964c112aeb9b28678f88fefed87
author: David Turner <[email protected]>
date: Wed May 31 23:27:48 EDT 2000
added a CID-keyed font driver in "src/cid" fixed two bugs in the smooth renderer
--- 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..)
--- 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 );
--- 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;
--- a/demos/src/ftview.c
+++ b/demos/src/ftview.c
@@ -74,7 +74,7 @@
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 @@
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 @@
}
#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 @@
error = FT_New_Face( library, filename, 0, &face );
if (error) goto Display_Font;
+ Success:
file_loaded++;
error = Reset_Scale( ptsize );
--- 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)
--- 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 */
--- 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 */
@@ -954,7 +959,6 @@
/* if it is a fixed-width one. The nature of the last */
/* loaded glyph can be retrieved through the result value */
/* returned by FT_Load_Glyph(). */
- /* */
/* */
enum
--- a/include/freetype/internal/t1types.h
+++ b/include/freetype/internal/t1types.h
@@ -344,7 +344,14 @@
} T1_Font;
+ typedef struct CID_Subrs_
+ {
+ FT_UInt num_subrs;
+ FT_Byte** code;
+
+ } CID_Subrs;
+
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
@@ -372,8 +379,8 @@
typedef struct T1_FaceRec_* T1_Face;
+ typedef struct CID_FaceRec_* CID_Face;
-
/***************************************************/
/* */
/* T1_Face : */
@@ -396,5 +403,14 @@
} T1_FaceRec;
+
+ typedef struct CID_FaceRec_
+ {
+ FT_FaceRec root;
+ void* psnames;
+ CID_Info cid;
+ CID_Subrs* subrs;
+
+ } CID_FaceRec;
#endif /* T1TYPES_H */
--- 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,8 +222,10 @@
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;
--- 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;
}
--- /dev/null
+++ b/src/cid/cidafm.c
@@ -1,0 +1,228 @@
+/***************************************************************************
+ *
+ * t1afm.c - support for reading Type 1 AFM files
+ *
+ *
+ ***************************************************************************/
+
+#include <cidafm.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/t1types.h>
+#include <stdlib.h> /* 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;
+ }
+
--- /dev/null
+++ b/src/cid/cidafm.h
@@ -1,0 +1,49 @@
+/***************************************************************************
+ *
+ * t1afm.h - support for reading Type 1 AFM files
+ *
+ *
+ ***************************************************************************/
+
+#ifndef T1AFM_H
+#define T1AFM_H
+
+#include <freetype/internal/ftobjs.h>
+
+/* 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 */
--- /dev/null
+++ b/src/cid/cidgload.c
@@ -1,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 <cidgload.h>
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+
+#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 *********/
+ /********** *********/
+ /********** *********/
+ /**********************************************************************/
+ /**********************************************************************/
+ /**********************************************************************/
+
+/*********************************************************************
+ *
+ * <Function>
+ * CID_Init_Builder
+ *
+ * <Description>
+ * Initialise a given glyph builder.
+ *
+ * <Input>
+ * 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;
+ }
+
+
+/*********************************************************************
+ *
+ * <Function>
+ * CID_Done_Builder
+ *
+ * <Description>
+ * 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.
+ *
+ * <Input>
+ * 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;
+ }
+ }
+
+
+
+/*********************************************************************
+ *
+ * <Function>
+ * CID_Init_Decoder
+ *
+ * <Description>
+ * Initialise a given Type 1 decoder for parsing
+ *
+ * <Input>
+ * 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
+/*********************************************************************
+ *
+ * <Function>
+ * lookup_glyph_by_stdcharcode
+ *
+ * <Description>
+ * Lookup a given glyph by its StandardEncoding charcode. Used
+ * to implement the SEAC Type 1 operator.
+ *
+ * <Input>
+ * face :: current face object
+ * charcode :: charcode to look for
+ *
+ * <Return>
+ * 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
+
+
+/*********************************************************************
+ *
+ * <Function>
+ * t1operator_seac
+ *
+ * <Description>
+ * Implements the "seac" Type 1 operator for a Type 1 decoder
+ *
+ * <Input>
+ * 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
+ *
+ * <Return>
+ * 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;
+ }
+
+/*********************************************************************
+ *
+ * <Function>
+ * CID_Parse_CharStrings
+ *
+ * <Description>
+ * Parses a given Type 1 charstrings program
+ *
+ * <Input>
+ * 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
+ *
+ * <Return>
+ * 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;
+ }
+
--- /dev/null
+++ b/src/cid/cidgload.h
@@ -1,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 <cidobjs.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+/*************************************************************************/
+/* */
+/* <Structure> CID_Builder */
+/* */
+/* <Description> */
+/* a structure used during glyph loading to store its outline. */
+/* */
+/* <Fields> */
+/* 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 */
--- /dev/null
+++ b/src/cid/cidload.c
@@ -1,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 <data> ....
+ *
+ * where <data> can be a number, a boolean, a string, or an
+ * array of numbers. There are a few exceptions, namely the
+ * encoding, font name, charstrings and subrs and they are
+ * handled with a special pattern-matching routine.
+ *
+ * All other common cases are handled very simply. The matching
+ * rules are defined in the file "t1tokens.h" through the use
+ * of several macros calls 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 <freetype/internal/ftdebug.h>
+#include <freetype/config/ftconfig.h>
+#include <freetype/ftmm.h>
+
+#include <freetype/internal/t1types.h>
+#include <t1errors.h>
+#include <cidload.h>
+#include <stdio.h>
+
+#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 <cidtokens.h>
+ { 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;
+ }
--- /dev/null
+++ b/src/cid/cidload.h
@@ -1,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 <freetype/internal/ftstream.h>
+#include <cidparse.h>
+
+#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 */
--- /dev/null
+++ b/src/cid/cidobjs.c
@@ -1,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 <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+
+#include <cidgload.h>
+#include <cidload.h>
+#include <freetype/internal/psnames.h>
+#include <cidafm.h>
+
+/* Required by tracing mode */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1objs
+
+/*******************************************************************
+ * *
+ * SIZE FUNCTIONS *
+ * *
+ * *
+ *******************************************************************/
+
+/*******************************************************************
+ *
+ * <Function> T1_Done_Size
+ *
+ * <Description>
+ * The TrueDoc instance object destructor. Used to discard
+ * a given instance object..
+ *
+ * <Input>
+ * instance :: handle to the target instance object
+ *
+ * <Return>
+ * TrueDoc error code. 0 means success
+ *
+ ******************************************************************/
+
+ LOCAL_FUNC
+ void T1_Done_Size( T1_Size size )
+ {
+ UNUSED(size);
+ }
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Init_Size
+ *
+ * <Description>
+ * The instance object constructor
+ *
+ * <Input>
+ * instance : handle to new instance object
+ * face : pointer to parent face object
+ *
+ * <Return>
+ * TrueDoc error code. 0 means success.
+ *
+ ******************************************************************/
+
+ LOCAL_DEF
+ FT_Error T1_Init_Size( T1_Size size )
+ {
+ size->valid = 0;
+ return T1_Err_Ok;
+ }
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Reset_Size
+ *
+ * <Description>
+ * 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..
+ *
+ * <Input>
+ * instance the instance object to destroy
+ *
+ * <Output>
+ * Error code.
+ *
+ ******************************************************************/
+
+ LOCAL_FUNC
+ FT_Error T1_Reset_Size( T1_Size size )
+ {
+ UNUSED(size);
+ return 0;
+ }
+
+
+/*******************************************************************
+ * *
+ * FACE FUNCTIONS *
+ * *
+ * *
+ *******************************************************************/
+
+/*******************************************************************
+ *
+ * <Function> T1_Done_Face
+ *
+ * <Description>
+ * The face object destructor.
+ *
+ * <Input>
+ * face :: typeless pointer to the face object to destroy
+ *
+ * <Return>
+ * 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;
+ }
+ }
+
+/*******************************************************************
+ *
+ * <Function> T1_Init_Face
+ *
+ * <Description>
+ * The face object constructor.
+ *
+ * <Input>
+ * face :: face record to build
+ * Input :: input stream where to load font data
+ *
+ * <Return>
+ * 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 );
+ }
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Init_Driver
+ *
+ * <Description>
+ * Initialise a given Type 1 driver object
+ *
+ * <Input>
+ * driver :: handle to target driver object
+ *
+ * <Return>
+ * Error code.
+ *
+ ******************************************************************/
+
+ LOCAL_FUNC
+ FT_Error T1_Init_Driver( T1_Driver driver )
+ {
+ UNUSED(driver);
+ return T1_Err_Ok;
+ }
+
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Done_Driver
+ *
+ * <Description>
+ * finalise a given Type 1 driver
+ *
+ * <Input>
+ * driver :: handle to target Type 1 driver
+ *
+ ******************************************************************/
+
+ LOCAL_DEF
+ void T1_Done_Driver( T1_Driver driver )
+ {
+ UNUSED(driver);
+ }
+
+
+/* END */
--- /dev/null
+++ b/src/cid/cidobjs.h
@@ -1,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 <freetype/internal/ftobjs.h>
+#include <freetype/config/ftconfig.h>
+#include <t1errors.h>
+#include <freetype/internal/t1types.h>
+
+#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;
+
+ /***********************************************************************/
+ /* */
+ /* <Type> T1_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 driver object. */
+ /* */
+ typedef struct T1_DriverRec_ *T1_Driver;
+
+
+ /***********************************************************************/
+ /* */
+ /* <Type> T1_Size */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 size object. */
+ /* */
+ typedef struct T1_SizeRec_* T1_Size;
+
+
+ /***********************************************************************/
+ /* */
+ /* <Type> T1_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 glyph slot object. */
+ /* */
+ typedef struct T1_GlyphSlotRec_* T1_GlyphSlot;
+
+
+ /***********************************************************************/
+ /* */
+ /* <Type> T1_CharMap */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 character mapping object. */
+ /* */
+ /* <Note> */
+ /* 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;
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Init_Face
+ *
+ * <Description>
+ * Initialise a given Type 1 face object
+ *
+ * <Input>
+ * face_index :: index of font face in resource
+ * resource :: source font resource
+ * face :: face record to build
+ *
+ * <Return>
+ * 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 );
+
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Done_Face
+ *
+ * <Description>
+ * Finalise a given face object
+ *
+ * <Input>
+ * face :: handle to the face object to destroy
+ *
+ ******************************************************************/
+
+ LOCAL_DEF
+ void T1_Done_Face( CID_Face face );
+
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Init_Size
+ *
+ * <Description>
+ * Initialise a new Type 1 size object
+ *
+ * <Input>
+ * size :: handle to size object
+ *
+ * <Return>
+ * Type 1 error code. 0 means success.
+ *
+ ******************************************************************/
+
+ LOCAL_DEF
+ FT_Error T1_Init_Size( T1_Size size );
+
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Done_Size
+ *
+ * <Description>
+ * The Type 1 size object finaliser.
+ *
+ * <Input>
+ * size :: handle to the target size object.
+ *
+ ******************************************************************/
+
+ LOCAL_DEF
+ void T1_Done_Size( T1_Size size );
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Reset_Size
+ *
+ * <Description>
+ * Reset a Type 1 size when resolutions and character dimensions
+ * have been changed..
+ *
+ * <Input>
+ * size :: handle to the target size object.
+ *
+ ******************************************************************/
+
+ LOCAL_DEF
+ FT_Error T1_Reset_Size( T1_Size size );
+
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Init_GlyphSlot
+ *
+ * <Description> The TrueType glyph slot initialiser
+ *
+ * <Input> glyph :: glyph record to build.
+ *
+ * <Output> Error code.
+ *
+ ******************************************************************/
+
+ LOCAL_DEF
+ FT_Error T1_Init_GlyphSlot( T1_GlyphSlot slot );
+
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Done_GlyphSlot
+ *
+ * <Description> The Type 1 glyph slot finaliser
+ *
+ * <Input> glyph :: handle to glyph slot object
+ *
+ * <Output> Error code.
+ *
+ ******************************************************************/
+
+ LOCAL_DEF
+ void T1_Done_GlyphSlot( T1_GlyphSlot slot );
+
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Init_Driver
+ *
+ * <Description>
+ * Initialise a given Type 1 driver object
+ *
+ * <Input>
+ * driver :: handle to target driver object
+ *
+ * <Return>
+ * Error code.
+ *
+ ******************************************************************/
+
+ LOCAL_DEF
+ FT_Error T1_Init_Driver( T1_Driver driver );
+
+
+
+/*******************************************************************
+ *
+ * <Function> T1_Done_Driver
+ *
+ * <Description>
+ * finalise a given Type 1 driver
+ *
+ * <Input>
+ * driver :: handle to target Type 1 driver
+ *
+ ******************************************************************/
+
+ LOCAL_DEF
+ void T1_Done_Driver( T1_Driver driver );
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* T1OBJS_H */
+
+
+/* END */
--- /dev/null
+++ b/src/cid/cidparse.c
@@ -1,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 <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftcalc.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/internal/ftstream.h>
+#include <t1errors.h>
+#include <cidparse.h>
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1load
+
+#if 0
+/*************************************************************************/
+/*************************************************************************/
+/*************************************************************************/
+/***** *****/
+/***** IMPLEMENTATION OF T1_TABLE OBJECT *****/
+/***** *****/
+/***** *****/
+/*************************************************************************/
+/*************************************************************************/
+/*************************************************************************/
+
+
+/*************************************************************************/
+/* */
+/* <Function> T1_New_Table */
+/* */
+/* <Description> */
+/* Initialise a T1_Table. */
+/* */
+/* <Input> */
+/* table :: address of target table */
+/* count :: table size = maximum number of elements */
+/* memory :: memory object to use for all subsequent reallocations */
+/* */
+/* <Return> */
+/* 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;
+ }
+
+
+
+/*************************************************************************/
+/* */
+/* <Function> T1_Add_Table */
+/* */
+/* <Description> */
+/* Adds an object to a T1_Table, possibly growing its memory block */
+/* */
+/* <Input> */
+/* table :: target table */
+/* index :: index of object in table */
+/* object :: address of object to copy in memory */
+/* length :: length in bytes of source object */
+/* */
+/* <Return> */
+/* 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;
+ }
+
+
+/*************************************************************************/
+/* */
+/* <Function> T1_Done_Table */
+/* */
+/* <Description> */
+/* Finalise a T1_Table. (realloc it to its current cursor). */
+/* */
+/* <Input> */
+/* table :: target table */
+/* */
+/* <Note> */
+/* 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 );
+ }
+ }
+
--- /dev/null
+++ b/src/cid/cidparse.h
@@ -1,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 <freetype/internal/t1types.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+
+#if 0
+/*************************************************************************
+ *
+ * <Struct> T1_Table
+ *
+ * <Description>
+ * A T1_Table is a simple object used to store an array of objects
+ * in a single memory block.
+ *
+ * <Fields>
+ * 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
+
+/*************************************************************************
+ *
+ * <Struct> CID_Parser
+ *
+ * <Description>
+ * A CID_Parser is an object used to parse a Type 1 fonts very
+ * quickly.
+ *
+ * <Fields>
+ * 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 */
+
--- /dev/null
+++ b/src/cid/cidriver.c
@@ -1,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 <cidriver.h>
+#include <cidgload.h>
+#include <cidafm.h>
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/psnames.h>
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1driver
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Interface */
+ /* */
+ /* <Description> */
+ /* 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). */
+ /* */
+ /* <InOut> */
+ /* driver :: A handle to a driver object. */
+ /* */
+ /* <Input> */
+ /* interface :: A string designing the interface. Examples are */
+ /* `sfnt', `post_names', `charmaps', etc. */
+ /* */
+ /* <Return> */
+ /* 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
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Kerning */
+ /* */
+ /* <Description> */
+ /* A driver method used to return the kerning vector between two */
+ /* glyphs of the same face. */
+ /* */
+ /* <Input> */
+ /* 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. */
+ /* */
+ /* <Output> */
+ /* kerning :: The kerning vector. This is in font units for */
+ /* scalable formats, and in pixels for fixed-sizes */
+ /* formats. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* 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
+
+ /******************************************************************/
+ /* */
+ /* <Function> Set_Char_Sizes */
+ /* */
+ /* <Description> */
+ /* A driver method used to reset a size's character sizes */
+ /* (horizontal and vertical) expressed in fractional points. */
+ /* */
+ /* <Input> */
+ /* size :: handle to target size object */
+ /* char_width :: character width expressed in 26.6 points */
+ /* char_height :: character height expressed in 26.6 points */
+ /* */
+ /* <Return> */
+ /* 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 );
+ }
+
+
+ /******************************************************************/
+ /* */
+ /* <Function> Set_Pixel_Sizes */
+ /* */
+ /* <Description> */
+ /* A driver method used to reset a size's character sizes */
+ /* (horizontal and vertical) expressed in integer pixels. */
+ /* */
+ /* <Input> */
+ /* 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 !) */
+ /* <Return> */
+ /* 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);
+ }
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Char_Index */
+ /* */
+ /* <Description> */
+ /* Uses a charmap to return a given character code's glyph index. */
+ /* */
+ /* <Input> */
+ /* charmap :: A handle to the source charmap object. */
+ /* charcode :: The character code. */
+ /* */
+ /* <Return> */
+ /* 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;
+ }
+
+
+ /******************************************************************/
+ /* */
+ /* <Struct> FT_DriverInterface */
+ /* */
+ /* <Description> */
+ /* 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 .. */
+ /* */
+ /* */
+ /* <Fields> */
+ /* */
+ /* 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,
+ };
+
+
+ /******************************************************************/
+ /* */
+ /* <Function> Get_FreeType_Driver_Interface */
+ /* */
+ /* <Description> */
+ /* 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. */
+ /* */
+ /* <Return> */
+ /* 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 */
+
+
--- /dev/null
+++ b/src/cid/cidriver.h
@@ -1,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 <cidobjs.h>
+#include <t1errors.h>
+
+ FT_EXPORT_VAR(const FT_DriverInterface) t1cid_driver_interface;
+
+#endif /* T1DRIVER_H */
+
--- /dev/null
+++ b/src/cid/cidtokens.h
@@ -1,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 )
+
+
--- /dev/null
+++ b/src/cid/module.mk
@@ -1,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
--- /dev/null
+++ b/src/cid/rules.mk
@@ -1,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
--- /dev/null
+++ b/src/cid/t1errors.h
@@ -1,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 <freetype/fterrors.h>
+
+ /************************ 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 */
--- /dev/null
+++ b/src/cid/type1cid.c
@@ -1,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 <cidparse.c>
+#include <cidload.c>
+#include <cidobjs.c>
+#include <cidriver.c>
+#include <cidgload.c>
+
+#if 0
+#include <cidafm.c>
+#endif
+
--- 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;
/************************************************************************/
--- 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;
}
--- 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;
--- 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