ref: a4e2894e03de65c5e0cd14b11b6fa30b14ed6769
parent: 3a3ffedcb25e01fe6bef195fec6a5152e25777d7
author: David Turner <[email protected]>
date: Wed Oct 25 20:30:33 EDT 2000
simple renaming of directories: "type1z" -> "type1" "raster1" -> "raster" note that I didn't rename all files. We'll have to endure the "z1..." crazyness unless we perform a _big_ sed on the sources :-)
--- /dev/null
+++ b/src/raster/ftraster.c
@@ -1,0 +1,3293 @@
+/***************************************************************************/
+/* */
+/* ftraster.c */
+/* */
+/* The FreeType glyph rasterizer (body). */
+/* */
+/* 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 a rewrite of the FreeType 1.x scan-line converter */
+ /* */
+ /*************************************************************************/
+
+
+#ifdef FT_FLAT_COMPILE
+# include "ftraster.h"
+#else
+# include <raster/ftraster.h>
+#endif
+#include <freetype/internal/ftcalc.h> /* for FT_MulDiv() only */
+
+
+ /*************************************************************************/
+ /* */
+ /* A simple technical note on how the raster works */
+ /* ----------------------------------------------- */
+ /* */
+ /* Converting an outline into a bitmap is achieved in several steps: */
+ /* */
+ /* 1 - Decomposing the outline into successive `profiles'. Each */
+ /* profile is simply an array of scanline intersections on a given */
+ /* dimension. A profile's main attributes are */
+ /* */
+ /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */
+ /* */
+ /* o an array of intersection coordinates for each scanline */
+ /* between `Ymin' and `Ymax'. */
+ /* */
+ /* o a direction, indicating whether it was built going `up' or */
+ /* `down', as this is very important for filling rules. */
+ /* */
+ /* 2 - Sweeping the target map's scanlines in order to compute segment */
+ /* `spans' which are then filled. Additionally, this pass */
+ /* performs drop-out control. */
+ /* */
+ /* The outline data is parsed during step 1 only. The profiles are */
+ /* built from the bottom of the render pool, used as a stack. The */
+ /* following graphics shows the profile list under construction: */
+ /* */
+ /* ____________________________________________________________ _ _ */
+ /* | | | | | */
+ /* | profile | coordinates for | profile | coordinates for |--> */
+ /* | 1 | profile 1 | 2 | profile 2 |--> */
+ /* |_________|___________________|_________|_________________|__ _ _ */
+ /* */
+ /* ^ ^ */
+ /* | | */
+ /* start of render pool top */
+ /* */
+ /* The top of the profile stack is kept in the `top' variable. */
+ /* */
+ /* As you can see, a profile record is pushed on top of the render */
+ /* pool, which is then followed by its coordinates/intersections. If */
+ /* a change of direction is detected in the outline, a new profile is */
+ /* generated until the end of the outline. */
+ /* */
+ /* Note that when all profiles have been generated, the function */
+ /* Finalize_Profile_Table() is used to record, for each profile, its */
+ /* bottom-most scanline as well as the scanline above its upmost */
+ /* boundary. These positions are called `y-turns' because they (sort */
+ /* of) correspond to local extrema. They are stored in a sorted list */
+ /* built from the top of the render pool as a downwards stack: */
+ /* */
+ /* _ _ _______________________________________ */
+ /* | | */
+ /* <--| sorted list of | */
+ /* <--| extrema scanlines | */
+ /* _ _ __________________|____________________| */
+ /* */
+ /* ^ ^ */
+ /* | | */
+ /* maxBuff sizeBuff = end of pool */
+ /* */
+ /* This list is later used during the sweep phase in order to */
+ /* optimize performance (see technical note on the sweep below). */
+ /* */
+ /* Of course, the raster detects whether the two stacks collide and */
+ /* handles the situation propertly. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** CONFIGURATION MACROS **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* define DEBUG_RASTER if you want to compile a debugging version */
+#define xxxDEBUG_RASTER
+
+ /* The default render pool size in bytes */
+#define RASTER_RENDER_POOL 8192
+
+ /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */
+ /* 5-levels anti-aliasing */
+#ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS
+#define FT_RASTER_OPTION_ANTI_ALIASING
+#endif
+
+ /* The size of the two-lines intermediate bitmap used */
+ /* for anti-aliasing, in bytes. */
+#define RASTER_GRAY_LINES 2048
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** OTHER MACROS (do not change) **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_raster
+
+
+#ifdef _STANDALONE_
+
+
+ /* This macro is used to indicate that a function parameter is unused. */
+ /* Its purpose is simply to reduce compiler warnings. Note also that */
+ /* simply defining it as `(void)x' doesn't avoid warnings with certain */
+ /* ANSI compilers (e.g. LCC). */
+#define FT_UNUSED( x ) (x) = (x)
+
+ /* Disable the tracing mechanism for simplicity -- developers can */
+ /* activate it easily by redefining these two macros. */
+#ifndef FT_ERROR
+#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */
+#endif
+
+#ifndef FT_TRACE
+#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */
+#endif
+
+#define Raster_Err_None 0
+#define Raster_Err_Not_Ini -1
+#define Raster_Err_Overflow -2
+#define Raster_Err_Neg_Height -3
+#define Raster_Err_Invalid -4
+#define Raster_Err_Unsupported -5
+
+
+#else /* _STANDALONE_ */
+
+
+#include <freetype/internal/ftobjs.h>
+#include <freetype/internal/ftdebug.h> /* for FT_TRACE() and FT_ERROR() */
+
+#define Raster_Err_None FT_Err_Ok
+#define Raster_Err_Not_Ini FT_Err_Raster_Uninitialized
+#define Raster_Err_Overflow FT_Err_Raster_Overflow
+#define Raster_Err_Neg_Height FT_Err_Raster_Negative_Height
+#define Raster_Err_Invalid FT_Err_Invalid_Outline
+#define Raster_Err_Unsupported FT_Err_Cannot_Render_Glyph
+
+
+#endif /* _STANDALONE_ */
+
+
+ /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */
+ /* typically a small value and the result of a*b is known to fit into */
+ /* 32 bits. */
+#define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
+
+ /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
+ /* for clipping computations. It simply uses the FT_MulDiv() function */
+ /* defined in `ftcalc.h'. */
+#define SMulDiv FT_MulDiv
+
+ /* The rasterizer is a very general purpose component; please leave */
+ /* the following redefinitions there (you never know your target */
+ /* environment). */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef NULL
+#define NULL (void*)0
+#endif
+
+#ifndef SUCCESS
+#define SUCCESS 0
+#endif
+
+#ifndef FAILURE
+#define FAILURE 1
+#endif
+
+
+#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
+ /* Setting this constant to more than 32 is a */
+ /* pure waste of space. */
+
+#define Pixel_Bits 6 /* fractional bits of *input* coordinates */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** SIMPLE TYPE DECLARATIONS **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef int Int;
+ typedef unsigned int UInt;
+ typedef short Short;
+ typedef unsigned short UShort, *PUShort;
+ typedef long Long, *PLong;
+ typedef unsigned long ULong;
+
+ typedef unsigned char Byte, *PByte;
+ typedef char Bool;
+
+ typedef struct TPoint_
+ {
+ Long x;
+ Long y;
+
+ } TPoint;
+
+
+ typedef enum TFlow_
+ {
+ Flow_None = 0,
+ Flow_Up = 1,
+ Flow_Down = -1
+
+ } TFlow;
+
+
+ /* States of each line, arc, and profile */
+ typedef enum TStates_
+ {
+ Unknown,
+ Ascending,
+ Descending,
+ Flat
+
+ } TStates;
+
+
+ typedef struct TProfile_ TProfile;
+ typedef TProfile* PProfile;
+
+ struct TProfile_
+ {
+ FT_F26Dot6 X; /* current coordinate during sweep */
+ PProfile link; /* link to next profile - various purpose */
+ PLong offset; /* start of profile's data in render pool */
+ Int flow; /* Profile orientation: Asc/Descending */
+ Long height; /* profile's height in scanlines */
+ Long start; /* profile's starting scanline */
+
+ UShort countL; /* number of lines to step before this */
+ /* profile becomes drawable */
+
+ PProfile next; /* next profile in same contour, used */
+ /* during drop-out control */
+ };
+
+ typedef PProfile TProfileList;
+ typedef PProfile* PProfileList;
+
+
+ /* Simple record used to implement a stack of bands, required */
+ /* by the sub-banding mechanism */
+ typedef struct TBand_
+ {
+ Short y_min; /* band's minimum */
+ Short y_max; /* band's maximum */
+
+ } TBand;
+
+
+#define AlignProfileSize \
+ ( ( sizeof ( TProfile ) + sizeof ( long ) - 1 ) / sizeof ( long ) )
+
+
+#ifdef TT_STATIC_RASTER
+
+
+#define RAS_ARGS /* void */
+#define RAS_ARG /* void */
+
+#define RAS_VARS /* void */
+#define RAS_VAR /* void */
+
+#define FT_UNUSED_RASTER do ; while ( 0 )
+
+
+#else /* TT_STATIC_RASTER */
+
+
+#define RAS_ARGS TRaster_Instance* raster,
+#define RAS_ARG TRaster_Instance* raster
+
+#define RAS_VARS raster,
+#define RAS_VAR raster
+
+#define FT_UNUSED_RASTER FT_UNUSED( raster )
+
+
+#endif /* TT_STATIC_RASTER */
+
+
+ typedef struct TRaster_Instance_ TRaster_Instance;
+
+
+ /* prototypes used for sweep function dispatch */
+ typedef void Function_Sweep_Init( RAS_ARGS Short* min,
+ Short* max );
+
+ typedef void Function_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right );
+
+ typedef void Function_Sweep_Step( RAS_ARG );
+
+
+ /* NOTE: These operations are only valid on 2's complement processors */
+
+#define FLOOR( x ) ( (x) & -ras.precision )
+#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision )
+#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
+#define FRAC( x ) ( (x) & ( ras.precision - 1 ) )
+#define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half )
+
+ /* Note that I have moved the location of some fields in the */
+ /* structure to ensure that the most used variables are used */
+ /* at the top. Thus, their offset can be coded with less */
+ /* opcodes, and it results in a smaller executable. */
+
+ struct TRaster_Instance_
+ {
+ Int precision_bits; /* precision related variables */
+ Int precision;
+ Int precision_half;
+ Long precision_mask;
+ Int precision_shift;
+ Int precision_step;
+ Int precision_jitter;
+
+ Int scale_shift; /* == precision_shift for bitmaps */
+ /* == precision_shift+1 for pixmaps */
+
+ PLong buff; /* The profiles buffer */
+ PLong sizeBuff; /* Render pool size */
+ PLong maxBuff; /* Profiles buffer size */
+ PLong top; /* Current cursor in buffer */
+
+ FT_Error error;
+
+ Int numTurns; /* number of Y-turns in outline */
+
+ TPoint* arc; /* current Bezier arc pointer */
+
+ UShort bWidth; /* target bitmap width */
+ PByte bTarget; /* target bitmap buffer */
+ PByte gTarget; /* target pixmap buffer */
+
+ Long lastX, lastY, minY, maxY;
+
+ UShort num_Profs; /* current number of profiles */
+
+ Bool fresh; /* signals a fresh new profile which */
+ /* 'start' field must be completed */
+ Bool joint; /* signals that the last arc ended */
+ /* exactly on a scanline. Allows */
+ /* removal of doublets */
+ PProfile cProfile; /* current profile */
+ PProfile fProfile; /* head of linked list of profiles */
+ PProfile gProfile; /* contour's first profile in case */
+ /* of impact */
+
+ TStates state; /* rendering state */
+
+ FT_Bitmap target; /* description of target bit/pixmap */
+ FT_Outline outline;
+
+ Long traceOfs; /* current offset in target bitmap */
+ Long traceG; /* current offset in target pixmap */
+
+ Short traceIncr; /* sweep's increment in target bitmap */
+
+ Short gray_min_x; /* current min x during gray rendering */
+ Short gray_max_x; /* current max x during gray rendering */
+
+ /* dispatch variables */
+
+ Function_Sweep_Init* Proc_Sweep_Init;
+ Function_Sweep_Span* Proc_Sweep_Span;
+ Function_Sweep_Span* Proc_Sweep_Drop;
+ Function_Sweep_Step* Proc_Sweep_Step;
+
+ Byte dropOutControl; /* current drop_out control method */
+
+ Bool second_pass; /* indicates wether a horizontal pass */
+ /* should be performed to control */
+ /* drop-out accurately when calling */
+ /* Render_Glyph. Note that there is */
+ /* no horizontal pass during gray */
+ /* rendering. */
+
+ TPoint arcs[2 * MaxBezier + 1]; /* The Bezier stack */
+
+ TBand band_stack[16]; /* band stack used for sub-banding */
+ Int band_top; /* band stack top */
+
+ Int count_table[256]; /* Look-up table used to quickly count */
+ /* set bits in a gray 2x2 cell */
+
+ void* memory;
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+ Byte grays[5]; /* Palette of gray levels used for */
+ /* render. */
+
+ Byte gray_lines[RASTER_GRAY_LINES];
+ /* Intermediate table used to render the */
+ /* graylevels pixmaps. */
+ /* gray_lines is a buffer holding two */
+ /* monochrome scanlines */
+
+ Short gray_width; /* width in bytes of one monochrome */
+ /* intermediate scanline of gray_lines. */
+ /* Each gray pixel takes 2 bits long there */
+
+ /* The gray_lines must hold 2 lines, thus with size */
+ /* in bytes of at least `gray_width*2'. */
+
+#endif /* FT_RASTER_ANTI_ALIASING */
+
+#if 0
+ PByte flags; /* current flags table */
+ PUShort outs; /* current outlines table */
+ FT_Vector* coords;
+
+ UShort nPoints; /* number of points in current glyph */
+ Short nContours; /* number of contours in current glyph */
+#endif
+
+ };
+
+
+#ifdef FT_CONFIG_OPTION_STATIC_RASTER
+
+ static TRaster_Instance cur_ras;
+#define ras cur_ras
+
+#else
+
+#define ras (*raster)
+
+#endif /* FT_CONFIG_OPTION_STATIC_RASTER */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** PROFILES COMPUTATION **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Set_High_Precision */
+ /* */
+ /* <Description> */
+ /* Sets precision variables according to param flag. */
+ /* */
+ /* <Input> */
+ /* High :: Set to True for high precision (typically for ppem < 18), */
+ /* false otherwise. */
+ /* */
+ static
+ void Set_High_Precision( RAS_ARGS Int High )
+ {
+ if ( High )
+ {
+ ras.precision_bits = 10;
+ ras.precision_step = 128;
+ ras.precision_jitter = 24;
+ }
+ else
+ {
+ ras.precision_bits = 6;
+ ras.precision_step = 32;
+ ras.precision_jitter = 2;
+ }
+
+ FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
+
+ ras.precision = 1L << ras.precision_bits;
+ ras.precision_half = ras.precision / 2;
+ ras.precision_shift = ras.precision_bits - Pixel_Bits;
+ ras.precision_mask = -ras.precision;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* New_Profile */
+ /* */
+ /* <Description> */
+ /* Creates a new profile in the render pool. */
+ /* */
+ /* <Input> */
+ /* aState :: The state/orientation of the new profile. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow or of incoherent */
+ /* profile. */
+ /* */
+ static
+ Bool New_Profile( RAS_ARGS TStates aState )
+ {
+ if ( !ras.fProfile )
+ {
+ ras.cProfile = (PProfile)ras.top;
+ ras.fProfile = ras.cProfile;
+ ras.top += AlignProfileSize;
+ }
+
+ if ( ras.top >= ras.maxBuff )
+ {
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ switch ( aState )
+ {
+ case Ascending:
+ ras.cProfile->flow = Flow_Up;
+ FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
+ break;
+
+ case Descending:
+ ras.cProfile->flow = Flow_Down;
+ FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
+ break;
+
+ default:
+ FT_ERROR(( "New_Profile: invalid profile direction!\n" ));
+ ras.error = Raster_Err_Invalid;
+ return FAILURE;
+ }
+
+ ras.cProfile->start = 0;
+ ras.cProfile->height = 0;
+ ras.cProfile->offset = ras.top;
+ ras.cProfile->link = (PProfile)0;
+ ras.cProfile->next = (PProfile)0;
+
+ if ( !ras.gProfile )
+ ras.gProfile = ras.cProfile;
+
+ ras.state = aState;
+ ras.fresh = TRUE;
+ ras.joint = FALSE;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* End_Profile */
+ /* */
+ /* <Description> */
+ /* Finalizes the current profile. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow or incoherency. */
+ /* */
+ static
+ Bool End_Profile( RAS_ARG )
+ {
+ Long h;
+ PProfile oldProfile;
+
+
+ h = ras.top - ras.cProfile->offset;
+
+ if ( h < 0 )
+ {
+ FT_ERROR(( "End_Profile: negative height encountered!\n" ));
+ ras.error = Raster_Err_Neg_Height;
+ return FAILURE;
+ }
+
+ if ( h > 0 )
+ {
+ FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
+ (long)ras.cProfile, ras.cProfile->start, h ));
+
+ oldProfile = ras.cProfile;
+ ras.cProfile->height = h;
+ ras.cProfile = (PProfile)ras.top;
+
+ ras.top += AlignProfileSize;
+
+ ras.cProfile->height = 0;
+ ras.cProfile->offset = ras.top;
+ oldProfile->next = ras.cProfile;
+ ras.num_Profs++;
+ }
+
+ if ( ras.top >= ras.maxBuff )
+ {
+ FT_TRACE1(( "overflow in End_Profile\n" ));
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ ras.joint = FALSE;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Insert_Y_Turn */
+ /* */
+ /* <Description> */
+ /* Inserts a salient into the sorted list placed on top of the render */
+ /* pool. */
+ /* */
+ /* <Input> */
+ /* New y scanline position. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow. */
+ /* */
+ static
+ Bool Insert_Y_Turn( RAS_ARGS Int y )
+ {
+ PLong y_turns;
+ Int y2, n;
+
+
+ n = ras.numTurns - 1;
+ y_turns = ras.sizeBuff - ras.numTurns;
+
+ /* look for first y value that is <= */
+ while ( n >= 0 && y < y_turns[n] )
+ n--;
+
+ /* if it is <, simply insert it, ignore if == */
+ if ( n >= 0 && y > y_turns[n] )
+ while ( n >= 0 )
+ {
+ y2 = y_turns[n];
+ y_turns[n] = y;
+ y = y2;
+ n--;
+ }
+
+ if ( n < 0 )
+ {
+ if ( ras.maxBuff <= ras.top )
+ {
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+ ras.maxBuff--;
+ ras.numTurns++;
+ ras.sizeBuff[-ras.numTurns] = y;
+ }
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Finalize_Profile_Table */
+ /* */
+ /* <Description> */
+ /* Adjusts all links in the profiles list. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow. */
+ /* */
+ static
+ Bool Finalize_Profile_Table( RAS_ARG )
+ {
+ Int bottom, top;
+ UShort n;
+ PProfile p;
+
+
+ n = ras.num_Profs;
+
+ if ( n > 1 )
+ {
+ p = ras.fProfile;
+ while ( n > 0 )
+ {
+ if ( n > 1 )
+ p->link = (PProfile)( p->offset + p->height );
+ else
+ p->link = NULL;
+
+ switch ( p->flow )
+ {
+ case Flow_Down:
+ bottom = p->start - p->height+1;
+ top = p->start;
+ p->start = bottom;
+ p->offset += p->height - 1;
+ break;
+
+ case Flow_Up:
+ default:
+ bottom = p->start;
+ top = p->start + p->height - 1;
+ }
+
+ if ( Insert_Y_Turn( RAS_VARS bottom ) ||
+ Insert_Y_Turn( RAS_VARS top + 1 ) )
+ return FAILURE;
+
+ p = p->link;
+ n--;
+ }
+ }
+ else
+ ras.fProfile = NULL;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Split_Conic */
+ /* */
+ /* <Description> */
+ /* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */
+ /* stack. */
+ /* */
+ /* <Input> */
+ /* None (subdivided Bezier is taken from the top of the stack). */
+ /* */
+ /* <Note> */
+ /* This routine is the `beef' of this component. It is _the_ inner */
+ /* loop that should be optimized to hell to get the best performance. */
+ /* */
+ static
+ void Split_Conic( TPoint* base )
+ {
+ Long a, b;
+
+
+ base[4].x = base[2].x;
+ b = base[1].x;
+ a = base[3].x = ( base[2].x + b ) / 2;
+ b = base[1].x = ( base[0].x + b ) / 2;
+ base[2].x = ( a + b ) / 2;
+
+ base[4].y = base[2].y;
+ b = base[1].y;
+ a = base[3].y = ( base[2].y + b ) / 2;
+ b = base[1].y = ( base[0].y + b ) / 2;
+ base[2].y = ( a + b ) / 2;
+
+ /* hand optimized. gcc doesn't seem to be too good at common */
+ /* expression substitution and instruction scheduling ;-) */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Split_Cubic */
+ /* */
+ /* <Description> */
+ /* Subdivides a third-order Bezier arc into two joint sub-arcs in the */
+ /* Bezier stack. */
+ /* */
+ /* <Note> */
+ /* This routine is the `beef' of the component. It is one of _the_ */
+ /* inner loops that should be optimized like hell to get the best */
+ /* performance. */
+ /* */
+ static
+ void Split_Cubic( TPoint* base )
+ {
+ Long a, b, c, d;
+
+
+ base[6].x = base[3].x;
+ c = base[1].x;
+ d = base[2].x;
+ base[1].x = a = ( base[0].x + c + 1 ) >> 1;
+ base[5].x = b = ( base[3].x + d + 1 ) >> 1;
+ c = ( c + d + 1 ) >> 1;
+ base[2].x = a = ( a + c + 1 ) >> 1;
+ base[4].x = b = ( b + c + 1 ) >> 1;
+ base[3].x = ( a + b + 1 ) >> 1;
+
+ base[6].y = base[3].y;
+ c = base[1].y;
+ d = base[2].y;
+ base[1].y = a = ( base[0].y + c + 1 ) >> 1;
+ base[5].y = b = ( base[3].y + d + 1 ) >> 1;
+ c = ( c + d + 1 ) >> 1;
+ base[2].y = a = ( a + c + 1 ) >> 1;
+ base[4].y = b = ( b + c + 1 ) >> 1;
+ base[3].y = ( a + b + 1 ) >> 1;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Line_Up */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an ascending line segment and stores */
+ /* them in the render pool. */
+ /* */
+ /* <Input> */
+ /* x1 :: The x-coordinate of the segment's start point. */
+ /* */
+ /* y1 :: The y-coordinate of the segment's start point. */
+ /* */
+ /* x2 :: The x-coordinate of the segment's end point. */
+ /* */
+ /* y2 :: The y-coordinate of the segment's end point. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static
+ Bool Line_Up( RAS_ARGS Long x1,
+ Long y1,
+ Long x2,
+ Long y2,
+ Long miny,
+ Long maxy )
+ {
+ Long Dx, Dy;
+ Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */
+ Long Ix, Rx, Ax;
+
+ PLong top;
+
+
+ Dx = x2 - x1;
+ Dy = y2 - y1;
+
+ if ( Dy <= 0 || y2 < miny || y1 > maxy )
+ return SUCCESS;
+
+ if ( y1 < miny )
+ {
+ /* Take care: miny-y1 can be a very large value; we use */
+ /* a slow MulDiv function to avoid clipping bugs */
+ x1 += SMulDiv( Dx, miny - y1, Dy );
+ e1 = TRUNC( miny );
+ f1 = 0;
+ }
+ else
+ {
+ e1 = TRUNC( y1 );
+ f1 = FRAC( y1 );
+ }
+
+ if ( y2 > maxy )
+ {
+ /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
+ e2 = TRUNC( maxy );
+ f2 = 0;
+ }
+ else
+ {
+ e2 = TRUNC( y2 );
+ f2 = FRAC( y2 );
+ }
+
+ if ( f1 > 0 )
+ {
+ if ( e1 == e2 )
+ return SUCCESS;
+ else
+ {
+ x1 += FMulDiv( Dx, ras.precision - f1, Dy );
+ e1 += 1;
+ }
+ }
+ else
+ if ( ras.joint )
+ {
+ ras.top--;
+ ras.joint = FALSE;
+ }
+
+ ras.joint = ( f2 == 0 );
+
+ if ( ras.fresh )
+ {
+ ras.cProfile->start = e1;
+ ras.fresh = FALSE;
+ }
+
+ size = e2 - e1 + 1;
+ if ( ras.top + size >= ras.maxBuff )
+ {
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ if ( Dx > 0 )
+ {
+ Ix = ( ras.precision * Dx ) / Dy;
+ Rx = ( ras.precision * Dx ) % Dy;
+ Dx = 1;
+ }
+ else
+ {
+ Ix = -( ( ras.precision * -Dx ) / Dy );
+ Rx = ( ras.precision * -Dx ) % Dy;
+ Dx = -1;
+ }
+
+ Ax = -Dy;
+ top = ras.top;
+
+ while ( size > 0 )
+ {
+ *top++ = x1;
+
+ x1 += Ix;
+ Ax += Rx;
+ if ( Ax >= 0 )
+ {
+ Ax -= Dy;
+ x1 += Dx;
+ }
+ size--;
+ }
+
+ ras.top = top;
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Line_Down */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an descending line segment and */
+ /* stores them in the render pool. */
+ /* */
+ /* <Input> */
+ /* x1 :: The x-coordinate of the segment's start point. */
+ /* */
+ /* y1 :: The y-coordinate of the segment's start point. */
+ /* */
+ /* x2 :: The x-coordinate of the segment's end point. */
+ /* */
+ /* y2 :: The y-coordinate of the segment's end point. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static
+ Bool Line_Down( RAS_ARGS Long x1,
+ Long y1,
+ Long x2,
+ Long y2,
+ Long miny,
+ Long maxy )
+ {
+ Bool result, fresh;
+
+
+ fresh = ras.fresh;
+
+ result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
+
+ if ( fresh && !ras.fresh )
+ ras.cProfile->start = -ras.cProfile->start;
+
+ return result;
+ }
+
+
+ /* A function type describing the functions used to split Bezier arcs */
+ typedef void (*TSplitter)( TPoint* base );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Bezier_Up */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an ascending Bezier arc and stores */
+ /* them in the render pool. */
+ /* */
+ /* <Input> */
+ /* degree :: The degree of the Bezier arc (either 2 or 3). */
+ /* */
+ /* splitter :: The function to split Bezier arcs. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static
+ Bool Bezier_Up( RAS_ARGS Int degree,
+ TSplitter splitter,
+ Long miny,
+ Long maxy )
+ {
+ Long y1, y2, e, e2, e0;
+ Short f1;
+
+ TPoint* arc;
+ TPoint* start_arc;
+
+ PLong top;
+
+
+ arc = ras.arc;
+ y1 = arc[degree].y;
+ y2 = arc[0].y;
+ top = ras.top;
+
+ if ( y2 < miny || y1 > maxy )
+ goto Fin;
+
+ e2 = FLOOR( y2 );
+
+ if ( e2 > maxy )
+ e2 = maxy;
+
+ e0 = miny;
+
+ if ( y1 < miny )
+ e = miny;
+ else
+ {
+ e = CEILING( y1 );
+ f1 = FRAC( y1 );
+ e0 = e;
+
+ if ( f1 == 0 )
+ {
+ if ( ras.joint )
+ {
+ top--;
+ ras.joint = FALSE;
+ }
+
+ *top++ = arc[degree].x;
+
+ e += ras.precision;
+ }
+ }
+
+ if ( ras.fresh )
+ {
+ ras.cProfile->start = TRUNC( e0 );
+ ras.fresh = FALSE;
+ }
+
+ if ( e2 < e )
+ goto Fin;
+
+ if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
+ {
+ ras.top = top;
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ start_arc = arc;
+
+ while ( arc >= start_arc && e <= e2 )
+ {
+ ras.joint = FALSE;
+
+ y2 = arc[0].y;
+
+ if ( y2 > e )
+ {
+ y1 = arc[degree].y;
+ if ( y2 - y1 >= ras.precision_step )
+ {
+ splitter( arc );
+ arc += degree;
+ }
+ else
+ {
+ *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
+ e - y1, y2 - y1 );
+ arc -= degree;
+ e += ras.precision;
+ }
+ }
+ else
+ {
+ if ( y2 == e )
+ {
+ ras.joint = TRUE;
+ *top++ = arc[0].x;
+
+ e += ras.precision;
+ }
+ arc -= degree;
+ }
+ }
+
+ Fin:
+ ras.top = top;
+ ras.arc -= degree;
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Bezier_Down */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an descending Bezier arc and stores */
+ /* them in the render pool. */
+ /* */
+ /* <Input> */
+ /* degree :: The degree of the Bezier arc (either 2 or 3). */
+ /* */
+ /* splitter :: The function to split Bezier arcs. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static
+ Bool Bezier_Down( RAS_ARGS Int degree,
+ TSplitter splitter,
+ Long miny,
+ Long maxy )
+ {
+ TPoint* arc = ras.arc;
+ Bool result, fresh;
+
+
+ arc[0].y = -arc[0].y;
+ arc[1].y = -arc[1].y;
+ arc[2].y = -arc[2].y;
+ if ( degree > 2 )
+ arc[3].y = -arc[3].y;
+
+ fresh = ras.fresh;
+
+ result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
+
+ if ( fresh && !ras.fresh )
+ ras.cProfile->start = -ras.cProfile->start;
+
+ arc[0].y = -arc[0].y;
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Line_To */
+ /* */
+ /* <Description> */
+ /* Injects a new line segment and adjusts Profiles list. */
+ /* */
+ /* <Input> */
+ /* x :: The x-coordinate of the segment's end point (its start point */
+ /* is stored in `LastX'). */
+ /* */
+ /* y :: The y-coordinate of the segment's end point (its start point */
+ /* is stored in `LastY'). */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
+ /* profile. */
+ /* */
+ static
+ Bool Line_To( RAS_ARGS Long x,
+ Long y )
+ {
+ /* First, detect a change of direction */
+
+ switch ( ras.state )
+ {
+ case Unknown:
+ if ( y > ras.lastY )
+ {
+ if ( New_Profile( RAS_VARS Ascending ) )
+ return FAILURE;
+ }
+ else
+ {
+ if ( y < ras.lastY )
+ if ( New_Profile( RAS_VARS Descending ) )
+ return FAILURE;
+ }
+ break;
+
+ case Ascending:
+ if ( y < ras.lastY )
+ {
+ if ( End_Profile( RAS_VAR ) ||
+ New_Profile( RAS_VARS Descending ) )
+ return FAILURE;
+ }
+ break;
+
+ case Descending:
+ if ( y > ras.lastY )
+ {
+ if ( End_Profile( RAS_VAR ) ||
+ New_Profile( RAS_VARS Ascending ) )
+ return FAILURE;
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ /* Then compute the lines */
+
+ switch ( ras.state )
+ {
+ case Ascending:
+ if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
+ x, y, ras.minY, ras.maxY ) )
+ return FAILURE;
+ break;
+
+ case Descending:
+ if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
+ x, y, ras.minY, ras.maxY ) )
+ return FAILURE;
+ break;
+
+ default:
+ ;
+ }
+
+ ras.lastX = x;
+ ras.lastY = y;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Conic_To */
+ /* */
+ /* <Description> */
+ /* Injects a new conic arc and adjusts the profile list. */
+ /* */
+ /* <Input> */
+ /* cx :: The x-coordinate of the arc's new control point. */
+ /* */
+ /* cy :: The y-coordinate of the arc's new control point. */
+ /* */
+ /* x :: The x-coordinate of the arc's end point (its start point is */
+ /* stored in `LastX'). */
+ /* */
+ /* y :: The y-coordinate of the arc's end point (its start point is */
+ /* stored in `LastY'). */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
+ /* profile. */
+ /* */
+ static
+ Bool Conic_To( RAS_ARGS Long cx,
+ Long cy,
+ Long x,
+ Long y )
+ {
+ Long y1, y2, y3, x3, ymin, ymax;
+ TStates state_bez;
+
+
+ ras.arc = ras.arcs;
+ ras.arc[2].x = ras.lastX;
+ ras.arc[2].y = ras.lastY;
+ ras.arc[1].x = cx; ras.arc[1].y = cy;
+ ras.arc[0].x = x; ras.arc[0].y = y;
+
+ do
+ {
+ y1 = ras.arc[2].y;
+ y2 = ras.arc[1].y;
+ y3 = ras.arc[0].y;
+ x3 = ras.arc[0].x;
+
+ /* first, categorize the Bezier arc */
+
+ if ( y1 <= y3 )
+ {
+ ymin = y1;
+ ymax = y3;
+ }
+ else
+ {
+ ymin = y3;
+ ymax = y1;
+ }
+
+ if ( y2 < ymin || y2 > ymax )
+ {
+ /* this arc has no given direction, split it! */
+ Split_Conic( ras.arc );
+ ras.arc += 2;
+ }
+ else if ( y1 == y3 )
+ {
+ /* this arc is flat, ignore it and pop it from the Bezier stack */
+ ras.arc -= 2;
+ }
+ else
+ {
+ /* the arc is y-monotonous, either ascending or descending */
+ /* detect a change of direction */
+ state_bez = y1 < y3 ? Ascending : Descending;
+ if ( ras.state != state_bez )
+ {
+ /* finalize current profile if any */
+ if ( ras.state != Unknown &&
+ End_Profile( RAS_VAR ) )
+ goto Fail;
+
+ /* create a new profile */
+ if ( New_Profile( RAS_VARS state_bez ) )
+ goto Fail;
+ }
+
+ /* now call the appropriate routine */
+ if ( state_bez == Ascending )
+ {
+ if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+ else
+ if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+
+ } while ( ras.arc >= ras.arcs );
+
+ ras.lastX = x3;
+ ras.lastY = y3;
+
+ return SUCCESS;
+
+ Fail:
+ return FAILURE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Cubic_To */
+ /* */
+ /* <Description> */
+ /* Injects a new cubic arc and adjusts the profile list. */
+ /* */
+ /* <Input> */
+ /* cx1 :: The x-coordinate of the arc's first new control point. */
+ /* */
+ /* cy1 :: The y-coordinate of the arc's first new control point. */
+ /* */
+ /* cx2 :: The x-coordinate of the arc's second new control point. */
+ /* */
+ /* cy2 :: The y-coordinate of the arc's second new control point. */
+ /* */
+ /* x :: The x-coordinate of the arc's end point (its start point is */
+ /* stored in `LastX'). */
+ /* */
+ /* y :: The y-coordinate of the arc's end point (its start point is */
+ /* stored in `LastY'). */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
+ /* profile. */
+ /* */
+ static
+ Bool Cubic_To( RAS_ARGS Long cx1,
+ Long cy1,
+ Long cx2,
+ Long cy2,
+ Long x,
+ Long y )
+ {
+ Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
+ TStates state_bez;
+
+
+ ras.arc = ras.arcs;
+ ras.arc[3].x = ras.lastX;
+ ras.arc[3].y = ras.lastY;
+ ras.arc[2].x = cx1; ras.arc[2].y = cy1;
+ ras.arc[1].x = cx2; ras.arc[1].y = cy2;
+ ras.arc[0].x = x; ras.arc[0].y = y;
+
+ do
+ {
+ y1 = ras.arc[3].y;
+ y2 = ras.arc[2].y;
+ y3 = ras.arc[1].y;
+ y4 = ras.arc[0].y;
+ x4 = ras.arc[0].x;
+
+ /* first, categorize the Bezier arc */
+
+ if ( y1 <= y4 )
+ {
+ ymin1 = y1;
+ ymax1 = y4;
+ }
+ else
+ {
+ ymin1 = y4;
+ ymax1 = y1;
+ }
+
+ if ( y2 <= y3 )
+ {
+ ymin2 = y2;
+ ymax2 = y3;
+ }
+ else
+ {
+ ymin2 = y3;
+ ymax2 = y2;
+ }
+
+ if ( ymin2 < ymin1 || ymax2 > ymax1 )
+ {
+ /* this arc has no given direction, split it! */
+ Split_Cubic( ras.arc );
+ ras.arc += 3;
+ }
+ else if ( y1 == y4 )
+ {
+ /* this arc is flat, ignore it and pop it from the Bezier stack */
+ ras.arc -= 3;
+ }
+ else
+ {
+ state_bez = ( y1 <= y4 ) ? Ascending : Descending;
+
+ /* detect a change of direction */
+ if ( ras.state != state_bez )
+ {
+ if ( ras.state != Unknown &&
+ End_Profile( RAS_VAR ) )
+ goto Fail;
+
+ if ( New_Profile( RAS_VARS state_bez ) )
+ goto Fail;
+ }
+
+ /* compute intersections */
+ if ( state_bez == Ascending )
+ {
+ if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+ else
+ if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+
+ } while ( ras.arc >= ras.arcs );
+
+ ras.lastX = x4;
+ ras.lastY = y4;
+
+ return SUCCESS;
+
+ Fail:
+ return FAILURE;
+ }
+
+
+#undef SWAP_
+#define SWAP_( x, y ) do \
+ { \
+ Long swap = x; \
+ \
+ \
+ x = y; \
+ y = swap; \
+ } while ( 0 )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Decompose_Curve */
+ /* */
+ /* <Description> */
+ /* Scans the outline arays in order to emit individual segments and */
+ /* Beziers by calling Line_To() and Bezier_To(). It handles all */
+ /* weird cases, like when the first point is off the curve, or when */
+ /* there are simply no `on' points in the contour! */
+ /* */
+ /* <Input> */
+ /* first :: The index of the first point in the contour. */
+ /* */
+ /* last :: The index of the last point in the contour. */
+ /* */
+ /* flipped :: If set, flip the direction of the curve. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on error. */
+ /* */
+ static
+ Bool Decompose_Curve( RAS_ARGS UShort first,
+ UShort last,
+ int flipped )
+ {
+ FT_Vector v_last;
+ FT_Vector v_control;
+ FT_Vector v_start;
+
+ FT_Vector* points;
+ FT_Vector* point;
+ FT_Vector* limit;
+ char* tags;
+
+ char tag; /* current point's state */
+
+
+ points = ras.outline.points;
+ limit = points + last;
+
+ v_start.x = SCALED( points[first].x );
+ v_start.y = SCALED( points[first].y );
+ v_last.x = SCALED( points[last].x );
+ v_last.y = SCALED( points[last].y );
+
+ if ( flipped )
+ {
+ SWAP_( v_start.x, v_start.y );
+ SWAP_( v_last.x, v_last.y );
+ }
+
+ v_control = v_start;
+
+ point = points + first;
+ tags = ras.outline.tags + first;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ /* A contour cannot start with a cubic control point! */
+ if ( tag == FT_Curve_Tag_Cubic )
+ goto Invalid_Outline;
+
+ /* check first point to determine origin */
+ if ( tag == FT_Curve_Tag_Conic )
+ {
+ /* first point is conic control. Yes, this happens. */
+ if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_Curve_Tag_On )
+ {
+ /* start at last point if it is on the curve */
+ v_start = v_last;
+ limit--;
+ }
+ else
+ {
+ /* if both first and last points are conic, */
+ /* start at their middle and record its position */
+ /* for closure */
+ v_start.x = ( v_start.x + v_last.x ) / 2;
+ v_start.y = ( v_start.y + v_last.y ) / 2;
+
+ v_last = v_start;
+ }
+ point--;
+ tags--;
+ }
+
+ ras.lastX = v_start.x;
+ ras.lastY = v_start.y;
+
+ while ( point < limit )
+ {
+ point++;
+ tags++;
+
+ tag = FT_CURVE_TAG( tags[0] );
+
+ switch ( tag )
+ {
+ case FT_Curve_Tag_On: /* emit a single line_to */
+ {
+ Long x, y;
+
+
+ x = SCALED( point->x );
+ y = SCALED( point->y );
+ if ( flipped )
+ SWAP_( x, y );
+
+ if ( Line_To( RAS_VARS x, y ) )
+ goto Fail;
+ continue;
+ }
+
+ case FT_Curve_Tag_Conic: /* consume conic arcs */
+ v_control.x = SCALED( point[0].x );
+ v_control.y = SCALED( point[0].y );
+
+ if ( flipped )
+ SWAP_( v_control.x, v_control.y );
+
+ Do_Conic:
+ if ( point < limit )
+ {
+ FT_Vector v_middle;
+ Long x, y;
+
+
+ point++;
+ tags++;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ x = SCALED( point[0].x );
+ y = SCALED( point[0].y );
+
+ if ( flipped )
+ SWAP_( x, y );
+
+ if ( tag == FT_Curve_Tag_On )
+ {
+ if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
+ goto Fail;
+ continue;
+ }
+
+ if ( tag != FT_Curve_Tag_Conic )
+ goto Invalid_Outline;
+
+ v_middle.x = ( v_control.x + x ) / 2;
+ v_middle.y = ( v_control.y + y ) / 2;
+
+ if ( Conic_To( RAS_VARS v_control.x, v_control.y,
+ v_middle.x, v_middle.y ) )
+ goto Fail;
+
+ v_control.x = x;
+ v_control.y = y;
+
+ goto Do_Conic;
+ }
+
+ if ( Conic_To( RAS_VARS v_control.x, v_control.y,
+ v_start.x, v_start.y ) )
+ goto Fail;
+
+ goto Close;
+
+ default: /* FT_Curve_Tag_Cubic */
+ {
+ Long x1, y1, x2, y2, x3, y3;
+
+
+ if ( point + 1 > limit ||
+ FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
+ goto Invalid_Outline;
+
+ point += 2;
+ tags += 2;
+
+ x1 = SCALED( point[-2].x );
+ y1 = SCALED( point[-2].y );
+ x2 = SCALED( point[-1].x );
+ y2 = SCALED( point[-1].y );
+ x3 = SCALED( point[ 0].x );
+ y3 = SCALED( point[ 0].y );
+
+ if ( flipped )
+ {
+ SWAP_( x1, y1 );
+ SWAP_( x2, y2 );
+ SWAP_( x3, y3 );
+ }
+
+ if ( point <= limit )
+ {
+ if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
+ goto Fail;
+ continue;
+ }
+
+ if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
+ goto Fail;
+ goto Close;
+ }
+ }
+ }
+
+ /* close the contour with a line segment */
+ if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
+ goto Fail;
+
+ Close:
+ return SUCCESS;
+
+ Invalid_Outline:
+ ras.error = Raster_Err_Invalid;
+
+ Fail:
+ return FAILURE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Convert_Glyph */
+ /* */
+ /* <Description> */
+ /* Converts a glyph into a series of segments and arcs and makes a */
+ /* profiles list with them. */
+ /* */
+ /* <Input> */
+ /* flipped :: If set, flip the direction of curve. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE if any error was encountered during */
+ /* rendering. */
+ /* */
+ static
+ Bool Convert_Glyph( RAS_ARGS int flipped )
+ {
+ Short i;
+ UShort start;
+
+ PProfile lastProfile;
+
+
+ ras.fProfile = NULL;
+ ras.joint = FALSE;
+ ras.fresh = FALSE;
+
+ ras.maxBuff = ras.sizeBuff - AlignProfileSize;
+
+ ras.numTurns = 0;
+
+ ras.cProfile = (PProfile)ras.top;
+ ras.cProfile->offset = ras.top;
+ ras.num_Profs = 0;
+
+ start = 0;
+
+ for ( i = 0; i < ras.outline.n_contours; i++ )
+ {
+ ras.state = Unknown;
+ ras.gProfile = NULL;
+
+ if ( Decompose_Curve( RAS_VARS start, ras.outline.contours[i], flipped ) )
+ return FAILURE;
+
+ start = ras.outline.contours[i] + 1;
+
+ /* We must now see whether the extreme arcs join or not */
+ if ( FRAC( ras.lastY ) == 0 &&
+ ras.lastY >= ras.minY &&
+ ras.lastY <= ras.maxY )
+ if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow )
+ ras.top--;
+ /* Note that ras.gProfile can be nil if the contour was too small */
+ /* to be drawn. */
+
+ lastProfile = ras.cProfile;
+ if ( End_Profile( RAS_VAR ) )
+ return FAILURE;
+
+ /* close the `next profile in contour' linked list */
+ if ( ras.gProfile )
+ lastProfile->next = ras.gProfile;
+ }
+
+ if ( Finalize_Profile_Table( RAS_VAR ) )
+ return FAILURE;
+
+ return ( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** SCAN-LINE SWEEPS AND DRAWING **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Init_Linked */
+ /* */
+ /* Initializes an empty linked list. */
+ /* */
+ static
+ void Init_Linked( TProfileList* l )
+ {
+ *l = NULL;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* InsNew */
+ /* */
+ /* Inserts a new profile in a linked list. */
+ /* */
+ static
+ void InsNew( PProfileList list,
+ PProfile profile )
+ {
+ PProfile *old, current;
+ Long x;
+
+
+ old = list;
+ current = *old;
+ x = profile->X;
+
+ while ( current )
+ {
+ if ( x < current->X )
+ break;
+ old = ¤t->link;
+ current = *old;
+ }
+
+ profile->link = current;
+ *old = profile;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DelOld */
+ /* */
+ /* Removes an old profile from a linked list. */
+ /* */
+ static
+ void DelOld( PProfileList list,
+ PProfile profile )
+ {
+ PProfile *old, current;
+
+
+ old = list;
+ current = *old;
+
+ while ( current )
+ {
+ if ( current == profile )
+ {
+ *old = current->link;
+ return;
+ }
+
+ old = ¤t->link;
+ current = *old;
+ }
+
+ /* we should never get there, unless the profile was not part of */
+ /* the list. */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Update */
+ /* */
+ /* Update all X offsets of a drawing list. */
+ /* */
+ static
+ void Update( PProfile first )
+ {
+ PProfile current = first;
+
+
+ while ( current )
+ {
+ current->X = *current->offset;
+ current->offset += current->flow;
+ current->height--;
+ current = current->link;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Sort */
+ /* */
+ /* Sorts a trace list. In 95%, the list is already sorted. We need */
+ /* an algorithm which is fast in this case. Bubble sort is enough */
+ /* and simple. */
+ /* */
+ static
+ void Sort( PProfileList list )
+ {
+ PProfile *old, current, next;
+
+
+ /* First, set the new X coordinate of each profile */
+ Update( *list );
+
+ /* Then sort them */
+ old = list;
+ current = *old;
+
+ if ( !current )
+ return;
+
+ next = current->link;
+
+ while ( next )
+ {
+ if ( current->X <= next->X )
+ {
+ old = ¤t->link;
+ current = *old;
+
+ if ( !current )
+ return;
+ }
+ else
+ {
+ *old = next;
+ current->link = next->link;
+ next->link = current;
+
+ old = list;
+ current = *old;
+ }
+
+ next = current->link;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Vertical Sweep Procedure Set */
+ /* */
+ /* These four routines are used during the vertical black/white sweep */
+ /* phase by the generic Draw_Sweep() function. */
+ /* */
+ /*************************************************************************/
+
+ static
+ void Vertical_Sweep_Init( RAS_ARGS Short* min,
+ Short* max )
+ {
+ Long pitch = ras.target.pitch;
+
+ FT_UNUSED( max );
+
+
+ ras.traceIncr = (Short)-pitch;
+ ras.traceOfs = -*min * pitch;
+ if ( pitch > 0 )
+ ras.traceOfs += ( ras.target.rows - 1 ) * pitch;
+
+ ras.gray_min_x = 0;
+ ras.gray_max_x = 0;
+ }
+
+
+ static
+ void Vertical_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ Short c1, c2;
+ Byte f1, f2;
+ Byte* target;
+
+ FT_UNUSED( y );
+ FT_UNUSED( left );
+ FT_UNUSED( right );
+
+
+ /* Drop-out control */
+
+ e1 = TRUNC( CEILING( x1 ) );
+
+ if ( x2 - x1 - ras.precision <= ras.precision_jitter )
+ e2 = e1;
+ else
+ e2 = TRUNC( FLOOR( x2 ) );
+
+ if ( e2 >= 0 && e1 < ras.bWidth )
+ {
+ if ( e1 < 0 )
+ e1 = 0;
+ if ( e2 >= ras.bWidth )
+ e2 = ras.bWidth - 1;
+
+ c1 = (Short)( e1 >> 3 );
+ c2 = (Short)( e2 >> 3 );
+
+ f1 = (unsigned char)0xFF >> ( e1 & 7 );
+ f2 = ~( (unsigned char)0x7F >> ( e2 & 7 ) );
+
+ if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
+ if ( ras.gray_max_x < c2 ) ras.gray_max_x = c2;
+
+ target = ras.bTarget + ras.traceOfs + c1;
+ c2 -= c1;
+
+ if ( c2 > 0 )
+ {
+ target[0] |= f1;
+
+ /* memset() is slower than the following code on many platforms. */
+ /* This is due to the fact that, in the vast majority of cases, */
+ /* the span length in bytes is relatively small. */
+ c2--;
+ while ( c2 > 0 )
+ {
+ *(++target) = 0xFF;
+ c2--;
+ }
+ target[1] |= f2;
+ }
+ else
+ *target |= ( f1 & f2 );
+ }
+ }
+
+
+ static
+ void Vertical_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ Short c1, f1;
+
+
+ /* Drop-out control */
+
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 > e2 )
+ {
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
+
+ case 4:
+ e1 = CEILING( (x1 + x2 + 1) / 2 );
+ break;
+
+ case 2:
+ case 5:
+ /* Drop-out Control Rule #4 */
+
+ /* The spec is not very clear regarding rule #4. It */
+ /* presents a method that is way too costly to implement */
+ /* while the general idea seems to get rid of `stubs'. */
+ /* */
+ /* Here, we only get rid of stubs recognized if: */
+ /* */
+ /* upper stub: */
+ /* */
+ /* - P_Left and P_Right are in the same contour */
+ /* - P_Right is the successor of P_Left in that contour */
+ /* - y is the top of P_Left and P_Right */
+ /* */
+ /* lower stub: */
+ /* */
+ /* - P_Left and P_Right are in the same contour */
+ /* - P_Left is the successor of P_Right in that contour */
+ /* - y is the bottom of P_Left */
+ /* */
+
+ /* FIXXXME: uncommenting this line solves the disappearing */
+ /* bit problem in the `7' of verdana 10pts, but */
+ /* makes a new one in the `C' of arial 14pts */
+
+#if 0
+ if ( x2 - x1 < ras.precision_half )
+#endif
+ {
+ /* upper stub test */
+ if ( left->next == right && left->height <= 0 )
+ return;
+
+ /* lower stub test */
+ if ( right->next == left && left->start == y )
+ return;
+ }
+
+ /* check that the rightmost pixel isn't set */
+
+ e1 = TRUNC( e1 );
+
+ c1 = (Short)( e1 >> 3 );
+ f1 = e1 & 7;
+
+ if ( e1 >= 0 && e1 < ras.bWidth &&
+ ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
+ return;
+
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+ break;
+
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
+
+ e1 = TRUNC( e1 );
+
+ if ( e1 >= 0 && e1 < ras.bWidth )
+ {
+ c1 = (Short)( e1 >> 3 );
+ f1 = e1 & 7;
+
+ if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
+ if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
+
+ ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
+ }
+ }
+
+
+ static
+ void Vertical_Sweep_Step( RAS_ARG )
+ {
+ ras.traceOfs += ras.traceIncr;
+ }
+
+
+ /***********************************************************************/
+ /* */
+ /* Horizontal Sweep Procedure Set */
+ /* */
+ /* These four routines are used during the horizontal black/white */
+ /* sweep phase by the generic Draw_Sweep() function. */
+ /* */
+ /***********************************************************************/
+
+ static
+ void Horizontal_Sweep_Init( RAS_ARGS Short* min,
+ Short* max )
+ {
+ /* nothing, really */
+ FT_UNUSED( raster );
+ FT_UNUSED( min );
+ FT_UNUSED( max );
+ }
+
+
+ static
+ void Horizontal_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ PByte bits;
+ Byte f1;
+
+ FT_UNUSED( left );
+ FT_UNUSED( right );
+
+
+ if ( x2 - x1 < ras.precision )
+ {
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 == e2 )
+ {
+ bits = ras.bTarget + ( y >> 3 );
+ f1 = (Byte)( 0x80 >> ( y & 7 ) );
+
+ e1 = TRUNC( e1 );
+
+ if ( e1 >= 0 && e1 < ras.target.rows )
+ {
+ PByte p;
+
+
+ p = bits - e1*ras.target.pitch;
+ if ( ras.target.pitch > 0 )
+ p += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ p[0] |= f1;
+ }
+ }
+ }
+ }
+
+
+ static
+ void Horizontal_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ PByte bits;
+ Byte f1;
+
+
+ /* During the horizontal sweep, we only take care of drop-outs */
+
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 > e2 )
+ {
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
+
+ case 4:
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+ break;
+
+ case 2:
+ case 5:
+
+ /* Drop-out Control Rule #4 */
+
+ /* The spec is not very clear regarding rule #4. It */
+ /* presents a method that is way too costly to implement */
+ /* while the general idea seems to get rid of `stubs'. */
+ /* */
+
+ /* rightmost stub test */
+ if ( left->next == right && left->height <= 0 )
+ return;
+
+ /* leftmost stub test */
+ if ( right->next == left && left->start == y )
+ return;
+
+ /* check that the rightmost pixel isn't set */
+
+ e1 = TRUNC( e1 );
+
+ bits = ras.bTarget + ( y >> 3 );
+ f1 = (Byte)( 0x80 >> ( y & 7 ) );
+
+ bits -= e1 * ras.target.pitch;
+ if ( ras.target.pitch > 0 )
+ bits += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ if ( e1 >= 0 &&
+ e1 < ras.target.rows &&
+ *bits & f1 )
+ return;
+
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+ break;
+
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
+
+ bits = ras.bTarget + ( y >> 3 );
+ f1 = (Byte)( 0x80 >> ( y & 7 ) );
+
+ e1 = TRUNC( e1 );
+
+ if ( e1 >= 0 && e1 < ras.target.rows )
+ {
+ bits -= e1 * ras.target.pitch;
+ if ( ras.target.pitch > 0 )
+ bits += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ bits[0] |= f1;
+ }
+ }
+
+
+ static
+ void Horizontal_Sweep_Step( RAS_ARG )
+ {
+ /* Nothing, really */
+ FT_UNUSED( raster );
+ }
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+
+ /*************************************************************************/
+ /* */
+ /* Vertical Gray Sweep Procedure Set */
+ /* */
+ /* These two routines are used during the vertical gray-levels sweep */
+ /* phase by the generic Draw_Sweep() function. */
+ /* */
+ /* NOTES */
+ /* */
+ /* - The target pixmap's width *must* be a multiple of 4. */
+ /* */
+ /* - You have to use the function Vertical_Sweep_Span() for the gray */
+ /* span call. */
+ /* */
+ /*************************************************************************/
+
+ static
+ void Vertical_Gray_Sweep_Init( RAS_ARGS Short* min,
+ Short* max )
+ {
+ Long pitch, byte_len;
+
+
+ *min = *min & -2;
+ *max = ( *max + 3 ) & -2;
+
+ ras.traceOfs = 0;
+ pitch = ras.target.pitch;
+ byte_len = -pitch;
+ ras.traceIncr = (Short)byte_len;
+ ras.traceG = ( *min / 2 ) * byte_len;
+
+ if ( pitch > 0 )
+ {
+ ras.traceG += ( ras.target.rows - 1 ) * pitch;
+ byte_len = -byte_len;
+ }
+
+ ras.gray_min_x = (Short)byte_len;
+ ras.gray_max_x = -(Short)byte_len;
+ }
+
+
+ static
+ void Vertical_Gray_Sweep_Step( RAS_ARG )
+ {
+ Int c1, c2;
+ PByte pix, bit, bit2;
+ Int* count = ras.count_table;
+ Byte* grays;
+
+
+ ras.traceOfs += ras.gray_width;
+
+ if ( ras.traceOfs > ras.gray_width )
+ {
+ pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
+ grays = ras.grays;
+
+ if ( ras.gray_max_x >= 0 )
+ {
+ Long last_pixel = ras.target.width - 1;
+ Int last_cell = last_pixel >> 2;
+ Int last_bit = last_pixel & 3;
+ Bool over = 0;
+
+
+ if ( ras.gray_max_x >= last_cell && last_bit != 3 )
+ {
+ ras.gray_max_x = last_cell - 1;
+ over = 1;
+ }
+
+ if ( ras.gray_min_x < 0 )
+ ras.gray_min_x = 0;
+
+ bit = ras.bTarget + ras.gray_min_x;
+ bit2 = bit + ras.gray_width;
+
+ c1 = ras.gray_max_x - ras.gray_min_x;
+
+ while ( c1 >= 0 )
+ {
+ c2 = count[*bit] + count[*bit2];
+
+ if ( c2 )
+ {
+ pix[0] = grays[(c2 >> 12) & 0x000F];
+ pix[1] = grays[(c2 >> 8 ) & 0x000F];
+ pix[2] = grays[(c2 >> 4 ) & 0x000F];
+ pix[3] = grays[ c2 & 0x000F];
+
+ *bit = 0;
+ *bit2 = 0;
+ }
+
+ bit++;
+ bit2++;
+ pix += 4;
+ c1--;
+ }
+
+ if ( over )
+ {
+ c2 = count[*bit] + count[*bit2];
+ if ( c2 )
+ {
+ switch ( last_bit )
+ {
+ case 2:
+ pix[2] = grays[(c2 >> 4 ) & 0x000F];
+ case 1:
+ pix[1] = grays[(c2 >> 8 ) & 0x000F];
+ default:
+ pix[0] = grays[(c2 >> 12) & 0x000F];
+ }
+
+ *bit = 0;
+ *bit2 = 0;
+ }
+ }
+ }
+
+ ras.traceOfs = 0;
+ ras.traceG += ras.traceIncr;
+
+ ras.gray_min_x = 32000;
+ ras.gray_max_x = -32000;
+ }
+ }
+
+
+ static
+ void Horizontal_Gray_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ /* nothing, really */
+ FT_UNUSED( raster );
+ FT_UNUSED( y );
+ FT_UNUSED( x1 );
+ FT_UNUSED( x2 );
+ FT_UNUSED( left );
+ FT_UNUSED( right );
+ }
+
+
+ static
+ void Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ PByte pixel;
+ Byte color;
+
+
+ /* During the horizontal sweep, we only take care of drop-outs */
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 > e2 )
+ {
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
+
+ case 4:
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+ break;
+
+ case 2:
+ case 5:
+
+ /* Drop-out Control Rule #4 */
+
+ /* The spec is not very clear regarding rule #4. It */
+ /* presents a method that is way too costly to implement */
+ /* while the general idea seems to get rid of `stubs'. */
+ /* */
+
+ /* rightmost stub test */
+ if ( left->next == right && left->height <= 0 )
+ return;
+
+ /* leftmost stub test */
+ if ( right->next == left && left->start == y )
+ return;
+
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+ break;
+
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
+
+ if ( e1 >= 0 )
+ {
+ if ( x2 - x1 >= ras.precision_half )
+ color = ras.grays[2];
+ else
+ color = ras.grays[1];
+
+ e1 = TRUNC( e1 ) / 2;
+ if ( e1 < ras.target.rows )
+ {
+ pixel = ras.gTarget - e1 * ras.target.pitch + y / 2;
+ if ( ras.target.pitch > 0 )
+ pixel += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ if ( pixel[0] == ras.grays[0] )
+ pixel[0] = color;
+ }
+ }
+ }
+
+
+#endif /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+
+ /*************************************************************************/
+ /* */
+ /* Generic Sweep Drawing routine */
+ /* */
+ /*************************************************************************/
+
+ static
+ Bool Draw_Sweep( RAS_ARG )
+ {
+ Short y, y_change, y_height;
+
+ PProfile P, Q, P_Left, P_Right;
+
+ Short min_Y, max_Y, top, bottom, dropouts;
+
+ Long x1, x2, xs, e1, e2;
+
+ TProfileList wait;
+ TProfileList draw_left, draw_right;
+
+
+ /* Init empty linked lists */
+
+ Init_Linked( &wait );
+
+ Init_Linked( &draw_left );
+ Init_Linked( &draw_right );
+
+ /* first, compute min and max Y */
+
+ P = ras.fProfile;
+ max_Y = (Short)TRUNC( ras.minY );
+ min_Y = (Short)TRUNC( ras.maxY );
+
+ while ( P )
+ {
+ Q = P->link;
+
+ bottom = (Short)P->start;
+ top = (Short)P->start + P->height - 1;
+
+ if ( min_Y > bottom ) min_Y = bottom;
+ if ( max_Y < top ) max_Y = top;
+
+ P->X = 0;
+ InsNew( &wait, P );
+
+ P = Q;
+ }
+
+ /* Check the Y-turns */
+ if ( ras.numTurns == 0 )
+ {
+ ras.error = Raster_Err_Invalid;
+ return FAILURE;
+ }
+
+ /* Now inits the sweep */
+
+ ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
+
+ /* Then compute the distance of each profile from min_Y */
+
+ P = wait;
+
+ while ( P )
+ {
+ P->countL = P->start - min_Y;
+ P = P->link;
+ }
+
+ /* Let's go */
+
+ y = min_Y;
+ y_height = 0;
+
+ if ( ras.numTurns > 0 &&
+ ras.sizeBuff[-ras.numTurns] == min_Y )
+ ras.numTurns--;
+
+ while ( ras.numTurns > 0 )
+ {
+ /* look in the wait list for new activations */
+
+ P = wait;
+
+ while ( P )
+ {
+ Q = P->link;
+ P->countL -= y_height;
+ if ( P->countL == 0 )
+ {
+ DelOld( &wait, P );
+
+ switch ( P->flow )
+ {
+ case Flow_Up:
+ InsNew( &draw_left, P );
+ break;
+
+ case Flow_Down:
+ InsNew( &draw_right, P );
+ break;
+ }
+ }
+
+ P = Q;
+ }
+
+ /* Sort the drawing lists */
+
+ Sort( &draw_left );
+ Sort( &draw_right );
+
+ y_change = (Short)ras.sizeBuff[-ras.numTurns--];
+ y_height = y_change - y;
+
+ while ( y < y_change )
+ {
+ /* Let's trace */
+
+ dropouts = 0;
+
+ P_Left = draw_left;
+ P_Right = draw_right;
+
+ while ( P_Left )
+ {
+ x1 = P_Left ->X;
+ x2 = P_Right->X;
+
+ if ( x1 > x2 )
+ {
+ xs = x1;
+ x1 = x2;
+ x2 = xs;
+ }
+
+ if ( x2 - x1 <= ras.precision )
+ {
+ e1 = FLOOR( x1 );
+ e2 = CEILING( x2 );
+
+ if ( ras.dropOutControl != 0 &&
+ ( e1 > e2 || e2 == e1 + ras.precision ) )
+ {
+ /* a drop out was detected */
+
+ P_Left ->X = x1;
+ P_Right->X = x2;
+
+ /* mark profile for drop-out processing */
+ P_Left->countL = 1;
+ dropouts++;
+
+ goto Skip_To_Next;
+ }
+ }
+
+ ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
+
+ Skip_To_Next:
+
+ P_Left = P_Left->link;
+ P_Right = P_Right->link;
+ }
+
+ /* now perform the dropouts _after_ the span drawing -- */
+ /* drop-outs processing has been moved out of the loop */
+ /* for performance tuning */
+ if ( dropouts > 0 )
+ goto Scan_DropOuts;
+
+ Next_Line:
+
+ ras.Proc_Sweep_Step( RAS_VAR );
+
+ y++;
+
+ if ( y < y_change )
+ {
+ Sort( &draw_left );
+ Sort( &draw_right );
+ }
+ }
+
+ /* Now finalize the profiles that needs it */
+
+ P = draw_left;
+ while ( P )
+ {
+ Q = P->link;
+ if ( P->height == 0 )
+ DelOld( &draw_left, P );
+ P = Q;
+ }
+
+ P = draw_right;
+ while ( P )
+ {
+ Q = P->link;
+ if ( P->height == 0 )
+ DelOld( &draw_right, P );
+ P = Q;
+ }
+ }
+
+ /* for gray-scaling, flushes the bitmap scanline cache */
+ while ( y <= max_Y )
+ {
+ ras.Proc_Sweep_Step( RAS_VAR );
+ y++;
+ }
+
+ return SUCCESS;
+
+ Scan_DropOuts:
+
+ P_Left = draw_left;
+ P_Right = draw_right;
+
+ while ( P_Left )
+ {
+ if ( P_Left->countL )
+ {
+ P_Left->countL = 0;
+#if 0
+ dropouts--; /* -- this is useful when debugging only */
+#endif
+ ras.Proc_Sweep_Drop( RAS_VARS y,
+ P_Left->X,
+ P_Right->X,
+ P_Left,
+ P_Right );
+ }
+
+ P_Left = P_Left->link;
+ P_Right = P_Right->link;
+ }
+
+ goto Next_Line;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Render_Single_Pass */
+ /* */
+ /* <Description> */
+ /* Performs one sweep with sub-banding. */
+ /* */
+ /* <Input> */
+ /* flipped :: If set, flip the direction of the outline. */
+ /* */
+ /* <Return> */
+ /* Renderer error code. */
+ /* */
+ static
+ int Render_Single_Pass( RAS_ARGS Bool flipped )
+ {
+ Short i, j, k;
+
+
+ while ( ras.band_top >= 0 )
+ {
+ ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
+ ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
+
+ ras.top = ras.buff;
+
+ ras.error = Raster_Err_None;
+
+ if ( Convert_Glyph( RAS_VARS flipped ) )
+ {
+ if ( ras.error != Raster_Err_Overflow )
+ return FAILURE;
+
+ ras.error = Raster_Err_None;
+
+ /* sub-banding */
+
+#ifdef DEBUG_RASTER
+ ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
+#endif
+
+ i = ras.band_stack[ras.band_top].y_min;
+ j = ras.band_stack[ras.band_top].y_max;
+
+ k = ( i + j ) / 2;
+
+ if ( ras.band_top >= 7 || k < i )
+ {
+ ras.band_top = 0;
+ ras.error = Raster_Err_Invalid;
+
+ return ras.error;
+ }
+
+ ras.band_stack[ras.band_top + 1].y_min = k;
+ ras.band_stack[ras.band_top + 1].y_max = j;
+
+ ras.band_stack[ras.band_top].y_max = k - 1;
+
+ ras.band_top++;
+ }
+ else
+ {
+ if ( ras.fProfile )
+ if ( Draw_Sweep( RAS_VAR ) )
+ return ras.error;
+ ras.band_top--;
+ }
+ }
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Render_Glyph */
+ /* */
+ /* <Description> */
+ /* Renders a glyph in a bitmap. Sub-banding if needed. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ LOCAL_FUNC
+ FT_Error Render_Glyph( RAS_ARG )
+ {
+ FT_Error error;
+
+
+ Set_High_Precision( RAS_VARS ras.outline.flags &
+ ft_outline_high_precision );
+ ras.scale_shift = ras.precision_shift;
+ ras.dropOutControl = 2;
+ ras.second_pass = !( ras.outline.flags & ft_outline_single_pass );
+
+ /* Vertical Sweep */
+ ras.Proc_Sweep_Init = Vertical_Sweep_Init;
+ ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+ ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
+ ras.Proc_Sweep_Step = Vertical_Sweep_Step;
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = ras.target.rows - 1;
+
+ ras.bWidth = ras.target.width;
+ ras.bTarget = (Byte*)ras.target.buffer;
+
+ if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
+ return error;
+
+ /* Horizontal Sweep */
+ if ( ras.second_pass && ras.dropOutControl != 0 )
+ {
+ ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+ ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
+ ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
+ ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = ras.target.width - 1;
+
+ if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 )
+ return error;
+ }
+
+ return FT_Err_Ok;
+ }
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Render_Gray_Glyph */
+ /* */
+ /* <Description> */
+ /* Renders a glyph with grayscaling. Sub-banding if needed. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ LOCAL_FUNC
+ FT_Error Render_Gray_Glyph( RAS_ARG )
+ {
+ Long pixel_width;
+ FT_Error error;
+
+
+ Set_High_Precision( RAS_VARS ras.outline.flags &
+ ft_outline_high_precision );
+ ras.scale_shift = ras.precision_shift + 1;
+ ras.dropOutControl = 2;
+ ras.second_pass = !( ras.outline.flags & ft_outline_single_pass );
+
+ /* Vertical Sweep */
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
+
+ ras.bWidth = ras.gray_width;
+ pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 );
+
+ if ( ras.bWidth > pixel_width )
+ ras.bWidth = pixel_width;
+
+ ras.bWidth = ras.bWidth * 8;
+ ras.bTarget = (Byte*)ras.gray_lines;
+ ras.gTarget = (Byte*)ras.target.buffer;
+
+ ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
+ ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+ ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
+ ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
+
+ error = Render_Single_Pass( RAS_VARS 0 );
+ if ( error )
+ return error;
+
+ /* Horizontal Sweep */
+ if ( ras.second_pass && ras.dropOutControl != 0 )
+ {
+ ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+ ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
+ ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
+ ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = ras.target.width * 2 - 1;
+
+ error = Render_Single_Pass( RAS_VARS 1 );
+ if ( error )
+ return error;
+ }
+
+ return FT_Err_Ok;
+ }
+
+#else /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+ LOCAL_FUNC
+ FT_Error Render_Gray_Glyph( RAS_ARG )
+ {
+ FT_UNUSED_RASTER;
+
+ return FT_Err_Cannot_Render_Glyph;
+ }
+
+#endif /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+
+ static
+ void ft_black_init( TRaster_Instance* raster )
+ {
+ FT_UInt n;
+ FT_ULong c;
+
+
+ /* setup count table */
+ for ( n = 0; n < 256; n++ )
+ {
+ c = ( n & 0x55 ) + ( ( n & 0xAA ) >> 1 );
+
+ c = ( ( c << 6 ) & 0x3000 ) |
+ ( ( c << 4 ) & 0x0300 ) |
+ ( ( c << 2 ) & 0x0030 ) |
+ (c & 0x0003 );
+
+ raster->count_table[n] = c;
+ }
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+ /* set default 5-levels gray palette */
+ for ( n = 0; n < 5; n++ )
+ raster->grays[n] = n * 255 / 4;
+
+ raster->gray_width = RASTER_GRAY_LINES / 2;
+
+#endif
+ }
+
+
+ /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
+ /**** a static object. *****/
+
+
+#ifdef _STANDALONE_
+
+
+ static
+ int ft_black_new( void* memory,
+ FT_Raster *araster )
+ {
+ static FT_RasterRec_ the_raster;
+
+
+ *araster = &the_raster;
+ memset( &the_raster, sizeof ( the_raster ), 0 );
+ ft_black_init( &the_raster );
+
+ return 0;
+ }
+
+
+ static
+ void ft_black_done( FT_Raster raster )
+ {
+ /* nothing */
+ raster->init = 0;
+ }
+
+
+#else /* _STANDALONE_ */
+
+
+ static
+ int ft_black_new( FT_Memory memory,
+ TRaster_Instance** araster )
+ {
+ FT_Error error;
+ TRaster_Instance* raster;
+
+
+ *araster = 0;
+ if ( !ALLOC( raster, sizeof ( *raster ) ) )
+ {
+ raster->memory = memory;
+ ft_black_init( raster );
+
+ *araster = raster;
+ }
+
+ return error;
+ }
+
+
+ static
+ void ft_black_done( TRaster_Instance* raster )
+ {
+ FT_Memory memory = (FT_Memory)raster->memory;
+ FREE( raster );
+ }
+
+
+#endif /* _STANDALONE_ */
+
+
+ static
+ void ft_black_reset( TRaster_Instance* raster,
+ const char* pool_base,
+ long pool_size )
+ {
+ if ( raster && pool_base && pool_size >= 4096 )
+ {
+ /* save the pool */
+ raster->buff = (PLong)pool_base;
+ raster->sizeBuff = raster->buff + pool_size / sizeof ( Long );
+ }
+ }
+
+
+ static
+ void ft_black_set_mode( TRaster_Instance* raster,
+ unsigned long mode,
+ const char* palette )
+ {
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+ if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
+ {
+ /* set 5-levels gray palette */
+ raster->grays[0] = palette[0];
+ raster->grays[1] = palette[1];
+ raster->grays[2] = palette[2];
+ raster->grays[3] = palette[3];
+ raster->grays[4] = palette[4];
+ }
+
+#else
+
+ FT_UNUSED( raster );
+ FT_UNUSED( mode );
+ FT_UNUSED( palette );
+
+#endif
+ }
+
+
+ static
+ int ft_black_render( TRaster_Instance* raster,
+ FT_Raster_Params* params )
+ {
+ FT_Outline* outline = (FT_Outline*)params->source;
+ FT_Bitmap* target_map = params->target;
+
+
+ if ( !raster || !raster->buff || !raster->sizeBuff )
+ return Raster_Err_Not_Ini;
+
+ /* return immediately if the outline is empty */
+ if ( outline->n_points == 0 || outline->n_contours <= 0 )
+ return Raster_Err_None;
+
+ if ( !outline || !outline->contours || !outline->points )
+ return Raster_Err_Invalid;
+
+ if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 )
+ return Raster_Err_Invalid;
+
+ if ( !target_map || !target_map->buffer )
+ return Raster_Err_Invalid;
+
+ /* this version of the raster does not support direct rendering, sorry */
+ if ( params->flags & ft_raster_flag_direct )
+ return Raster_Err_Unsupported;
+
+ ras.outline = *outline;
+ ras.target = *target_map;
+
+ return ( ( params->flags & ft_raster_flag_aa )
+ ? Render_Gray_Glyph( raster )
+ : Render_Glyph( raster ) );
+ }
+
+
+ const FT_Raster_Funcs ft_standard_raster =
+ {
+ ft_glyph_format_outline,
+ (FT_Raster_New_Func) ft_black_new,
+ (FT_Raster_Reset_Func) ft_black_reset,
+ (FT_Raster_Set_Mode_Func)ft_black_set_mode,
+ (FT_Raster_Render_Func) ft_black_render,
+ (FT_Raster_Done_Func) ft_black_done
+ };
+
+
+/* END */
--- /dev/null
+++ b/src/raster/ftraster.h
@@ -1,0 +1,50 @@
+/***************************************************************************/
+/* */
+/* ftraster.h */
+/* */
+/* The FreeType glyph rasterizer (specification). */
+/* */
+/* 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 FTRASTER_H
+#define FTRASTER_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include <freetype/ftimage.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* Uncomment the following line if you are using ftraster.c as a */
+ /* standalone module, fully independent of FreeType. */
+ /* */
+/* #define _STANDALONE_ */
+
+#ifndef FT_EXPORT_VAR
+#define FT_EXPORT_VAR( x ) extern x
+#endif
+
+ FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_standard_raster;
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif /* FTRASTER_H */
+
+
+/* END */
--- /dev/null
+++ b/src/raster/ftrend1.c
@@ -1,0 +1,276 @@
+/***************************************************************************/
+/* */
+/* ftrend1.c */
+/* */
+/* The FreeType glyph rasterizer interface (body). */
+/* */
+/* 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. */
+/* */
+/***************************************************************************/
+
+
+#include <freetype/internal/ftobjs.h>
+#include <freetype/ftoutln.h>
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "ftrend1.h"
+#include "ftraster.h"
+
+#else
+
+#include <raster/ftrend1.h>
+#include <raster/ftraster.h>
+
+#endif
+
+
+ /* initialize renderer -- init its raster */
+ static
+ FT_Error ft_raster1_init( FT_Renderer render )
+ {
+ FT_Library library = FT_MODULE_LIBRARY( render );
+
+
+ render->clazz->raster_class->raster_reset( render->raster,
+ library->raster_pool,
+ library->raster_pool_size );
+
+ return FT_Err_Ok;
+ }
+
+
+ /* set render-specific mode */
+ static
+ FT_Error ft_raster1_set_mode( FT_Renderer render,
+ FT_ULong mode_tag,
+ FT_Pointer data )
+ {
+ /* we simply pass it to the raster */
+ return render->clazz->raster_class->raster_set_mode( render->raster,
+ mode_tag,
+ data );
+ }
+
+
+ /* transform a given glyph image */
+ static
+ FT_Error ft_raster1_transform( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( slot->format != render->glyph_format )
+ {
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( matrix )
+ FT_Outline_Transform( &slot->outline, matrix );
+
+ if ( delta )
+ FT_Outline_Translate( &slot->outline, delta->x, delta->y );
+
+ Exit:
+ return error;
+ }
+
+
+ /* return the glyph's control box */
+ static
+ void ft_raster1_get_cbox( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_BBox* cbox )
+ {
+ MEM_Set( cbox, 0, sizeof ( *cbox ) );
+
+ if ( slot->format == render->glyph_format )
+ FT_Outline_Get_CBox( &slot->outline, cbox );
+ }
+
+
+ /* convert a slot's glyph image into a bitmap */
+ static
+ FT_Error ft_raster1_render( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_UInt mode,
+ FT_Vector* origin )
+ {
+ FT_Error error;
+ FT_Outline* outline;
+ FT_BBox cbox;
+ FT_UInt width, height, pitch;
+ FT_Bitmap* bitmap;
+ FT_Memory memory;
+
+ FT_Raster_Params params;
+
+
+ /* check glyph image format */
+ if ( slot->format != render->glyph_format )
+ {
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* check rendering mode */
+ if ( mode != ft_render_mode_mono )
+ {
+ /* raster1 is only capable of producing monochrome bitmaps */
+ if ( render->clazz == &ft_raster1_renderer_class )
+ return FT_Err_Cannot_Render_Glyph;
+ }
+ else
+ {
+ /* raster5 is only capable of producing 5-gray-levels bitmaps */
+ if ( render->clazz == &ft_raster5_renderer_class )
+ return FT_Err_Cannot_Render_Glyph;
+ }
+
+ outline = &slot->outline;
+
+ /* translate the outline to the new origin if needed */
+ if ( origin )
+ FT_Outline_Translate( outline, origin->x, origin->y );
+
+ /* compute the control box, and grid fit it */
+ FT_Outline_Get_CBox( outline, &cbox );
+
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax + 63 ) & -64;
+ cbox.yMax = ( cbox.yMax + 63 ) & -64;
+
+ width = ( cbox.xMax - cbox.xMin ) >> 6;
+ height = ( cbox.yMax - cbox.yMin ) >> 6;
+ bitmap = &slot->bitmap;
+ memory = render->root.memory;
+
+ /* release old bitmap buffer */
+ if ( slot->flags & ft_glyph_own_bitmap )
+ {
+ FREE( bitmap->buffer );
+ slot->flags &= ~ft_glyph_own_bitmap;
+ }
+
+ /* allocate new one, depends on pixel format */
+ if ( !( mode & ft_render_mode_mono ) )
+ {
+ /* we pad to 32 bits, only for backwards compatibility with FT 1.x */
+ pitch = ( width + 3 ) & -4;
+ bitmap->pixel_mode = ft_pixel_mode_grays;
+ bitmap->num_grays = 256;
+ }
+ else
+ {
+ pitch = ( width + 7 ) >> 3;
+ bitmap->pixel_mode = ft_pixel_mode_mono;
+ }
+
+ bitmap->width = width;
+ bitmap->rows = height;
+ bitmap->pitch = pitch;
+
+ if ( ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
+ goto Exit;
+
+ slot->flags |= ft_glyph_own_bitmap;
+
+ /* translate outline to render it into the bitmap */
+ FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );
+
+ /* set up parameters */
+ params.target = bitmap;
+ params.source = outline;
+ params.flags = 0;
+
+ if ( bitmap->pixel_mode == ft_pixel_mode_grays )
+ params.flags |= ft_raster_flag_aa;
+
+ /* render outline into the bitmap */
+ error = render->raster_render( render->raster, ¶ms );
+ if ( error )
+ goto Exit;
+
+ slot->format = ft_glyph_format_bitmap;
+ slot->bitmap_left = cbox.xMin >> 6;
+ slot->bitmap_top = cbox.yMax >> 6;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CPLUSPLUS( const FT_Renderer_Class ) ft_raster1_renderer_class =
+ {
+ {
+ ft_module_renderer,
+ sizeof( FT_RendererRec ),
+
+ "raster1",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module specific interface */
+
+ (FT_Module_Constructor)ft_raster1_init,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ ft_glyph_format_outline,
+
+ (FTRenderer_render) ft_raster1_render,
+ (FTRenderer_transform)ft_raster1_transform,
+ (FTRenderer_getCBox) ft_raster1_get_cbox,
+ (FTRenderer_setMode) ft_raster1_set_mode,
+
+ (FT_Raster_Funcs*) &ft_standard_raster
+ };
+
+
+ /* This renderer is _NOT_ part of the default modules; you will need */
+ /* to register it by hand in your application. It should only be */
+ /* used for backwards-compatibility with FT 1.x anyway. */
+ /* */
+ FT_CPLUSPLUS( const FT_Renderer_Class ) ft_raster5_renderer_class =
+ {
+ {
+ ft_module_renderer,
+ sizeof( FT_RendererRec ),
+
+ "raster5",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module specific interface */
+
+ (FT_Module_Constructor)ft_raster1_init,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ ft_glyph_format_outline,
+
+ (FTRenderer_render) ft_raster1_render,
+ (FTRenderer_transform)ft_raster1_transform,
+ (FTRenderer_getCBox) ft_raster1_get_cbox,
+ (FTRenderer_setMode) ft_raster1_set_mode,
+
+ (FT_Raster_Funcs*) &ft_standard_raster
+ };
+
+
+/* END */
--- /dev/null
+++ b/src/raster/ftrend1.h
@@ -1,0 +1,48 @@
+/***************************************************************************/
+/* */
+/* ftrend1.h */
+/* */
+/* The FreeType glyph rasterizer interface (specification). */
+/* */
+/* 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 FTREND1_H
+#define FTREND1_H
+
+
+#include <freetype/ftrender.h>
+
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_raster1_renderer_class;
+
+ /* this renderer is _NOT_ part of the default modules, you'll need */
+ /* to register it by hand in your application. It should only be */
+ /* used for backwards-compatibility with FT 1.x anyway. */
+ /* */
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_raster5_renderer_class;
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif /* FTREND1_H */
+
+
+/* END */
--- /dev/null
+++ b/src/raster/module.mk
@@ -1,0 +1,22 @@
+#
+# FreeType 2 renderer module definition
+#
+
+
+# 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.
+
+
+make_module_list: add_raster_module
+
+add_raster_module:
+ $(OPEN_DRIVER)ft_raster1_renderer_class$(CLOSE_DRIVER)
+ $(ECHO_DRIVER)raster $(ECHO_DRIVER_DESC)monochrome bitmap renderer$(ECHO_DRIVER_DONE)
+
+# EOF
--- /dev/null
+++ b/src/raster/raster.c
@@ -1,0 +1,35 @@
+/***************************************************************************/
+/* */
+/* raster1.c */
+/* */
+/* FreeType monochrome rasterer module component (body only). */
+/* */
+/* 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. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "ftraster.c"
+#include "ftrend1.c"
+
+#else
+
+#include <raster/ftraster.c>
+#include <raster/ftrend1.c>
+
+#endif
+
+
+/* END */
--- /dev/null
+++ b/src/raster/rules.mk
@@ -1,0 +1,69 @@
+#
+# FreeType 2 renderer module build 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.
+
+
+# raster1 driver directory
+#
+RAS1_DIR := $(SRC_)raster
+RAS1_DIR_ := $(RAS1_DIR)$(SEP)
+
+# compilation flags for the driver
+#
+RAS1_COMPILE := $(FT_COMPILE)
+
+
+# raster1 driver sources (i.e., C files)
+#
+RAS1_DRV_SRC := $(RAS1_DIR_)ftraster.c \
+ $(RAS1_DIR_)ftrend1.c
+
+
+# raster1 driver headers
+#
+RAS1_DRV_H := $(RAS1_DRV_SRC:%.c=%.h)
+
+
+# raster1 driver object(s)
+#
+# RAS1_DRV_OBJ_M is used during `multi' builds.
+# RAS1_DRV_OBJ_S is used during `single' builds.
+#
+RAS1_DRV_OBJ_M := $(RAS1_DRV_SRC:$(RAS1_DIR_)%.c=$(OBJ_)%.$O)
+RAS1_DRV_OBJ_S := $(OBJ_)raster.$O
+
+# raster1 driver source file for single build
+#
+RAS1_DRV_SRC_S := $(RAS1_DIR_)raster.c
+
+
+# raster1 driver - single object
+#
+$(RAS1_DRV_OBJ_S): $(RAS1_DRV_SRC_S) $(RAS1_DRV_SRC) \
+ $(FREETYPE_H) $(RAS1_DRV_H)
+ $(RAS1_COMPILE) $T$@ $(RAS1_DRV_SRC_S)
+
+
+# raster1 driver - multiple objects
+#
+$(OBJ_)%.$O: $(RAS1_DIR_)%.c $(FREETYPE_H) $(RAS1_DRV_H)
+ $(RAS1_COMPILE) $T$@ $<
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(RAS1_DRV_OBJ_S)
+DRV_OBJS_M += $(RAS1_DRV_OBJ_M)
+
+
+# EOF
--- a/src/raster1/module.mk
+++ /dev/null
@@ -1,22 +1,0 @@
-#
-# FreeType 2 renderer module definition
-#
-
-
-# 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.
-
-
-make_module_list: add_raster1_module
-
-add_raster1_module:
- $(OPEN_DRIVER)ft_raster1_renderer_class$(CLOSE_DRIVER)
- $(ECHO_DRIVER)raster1 $(ECHO_DRIVER_DESC)monochrome bitmap renderer$(ECHO_DRIVER_DONE)
-
-# EOF
--- a/src/raster1/rules.mk
+++ /dev/null
@@ -1,69 +1,0 @@
-#
-# FreeType 2 renderer module build 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.
-
-
-# raster1 driver directory
-#
-RAS1_DIR := $(SRC_)raster1
-RAS1_DIR_ := $(RAS1_DIR)$(SEP)
-
-# compilation flags for the driver
-#
-RAS1_COMPILE := $(FT_COMPILE)
-
-
-# raster1 driver sources (i.e., C files)
-#
-RAS1_DRV_SRC := $(RAS1_DIR_)ftraster.c \
- $(RAS1_DIR_)ftrend1.c
-
-
-# raster1 driver headers
-#
-RAS1_DRV_H := $(RAS1_DRV_SRC:%.c=%.h)
-
-
-# raster1 driver object(s)
-#
-# RAS1_DRV_OBJ_M is used during `multi' builds.
-# RAS1_DRV_OBJ_S is used during `single' builds.
-#
-RAS1_DRV_OBJ_M := $(RAS1_DRV_SRC:$(RAS1_DIR_)%.c=$(OBJ_)%.$O)
-RAS1_DRV_OBJ_S := $(OBJ_)raster1.$O
-
-# raster1 driver source file for single build
-#
-RAS1_DRV_SRC_S := $(RAS1_DIR_)raster1.c
-
-
-# raster1 driver - single object
-#
-$(RAS1_DRV_OBJ_S): $(RAS1_DRV_SRC_S) $(RAS1_DRV_SRC) \
- $(FREETYPE_H) $(RAS1_DRV_H)
- $(RAS1_COMPILE) $T$@ $(RAS1_DRV_SRC_S)
-
-
-# raster1 driver - multiple objects
-#
-$(OBJ_)%.$O: $(RAS1_DIR_)%.c $(FREETYPE_H) $(RAS1_DRV_H)
- $(RAS1_COMPILE) $T$@ $<
-
-
-# update main driver object lists
-#
-DRV_OBJS_S += $(RAS1_DRV_OBJ_S)
-DRV_OBJS_M += $(RAS1_DRV_OBJ_M)
-
-
-# EOF
--- /dev/null
+++ b/src/type1/module.mk
@@ -1,0 +1,22 @@
+#
+# FreeType 2 Type1z module definition
+#
+
+
+# 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.
+
+
+make_module_list: add_type1_driver
+
+add_type1_driver:
+ $(OPEN_DRIVER)t1_driver_class$(CLOSE_DRIVER)
+ $(ECHO_DRIVER)type1 $(ECHO_DRIVER_DESC)Postscript font files with extension *.pfa or *.pfb$(ECHO_DRIVER_DONE)
+
+# EOF
--- /dev/null
+++ b/src/type1/rules.mk
@@ -1,0 +1,72 @@
+#
+# FreeType 2 Type1z 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.
+
+
+# Type1 driver directory
+#
+T1_DIR := $(SRC_)type1
+T1_DIR_ := $(T1_DIR)$(SEP)
+
+
+# compilation flags for the driver
+#
+T1_COMPILE := $(FT_COMPILE)
+
+
+# Type1 driver sources (i.e., C files)
+#
+T1_DRV_SRC := $(T1_DIR_)z1parse.c \
+ $(T1_DIR_)z1load.c \
+ $(T1_DIR_)z1driver.c \
+ $(T1_DIR_)z1afm.c \
+ $(T1_DIR_)z1gload.c \
+ $(T1_DIR_)z1objs.c
+
+# Type1 driver headers
+#
+T1_DRV_H := $(T1_DRV_SRC:%.c=%.h) \
+ $(T1_DIR_)z1tokens.h
+
+
+# Type1z driver object(s)
+#
+# T1_DRV_OBJ_M is used during `multi' builds
+# T1_DRV_OBJ_S is used during `single' builds
+#
+T1_DRV_OBJ_M := $(T1_DRV_SRC:$(T1_DIR_)%.c=$(OBJ_)%.$O)
+T1_DRV_OBJ_S := $(OBJ_)type1.$O
+
+# Type1z driver source file for single build
+#
+T1_DRV_SRC_S := $(T1_DIR_)type1.c
+
+
+# Type1z driver - single object
+#
+$(T1_DRV_OBJ_S): $(T1_DRV_SRC_S) $(T1_DRV_SRC) $(FREETYPE_H) $(T1_DRV_H)
+ $(T1_COMPILE) $T$@ $(T1_DRV_SRC_S)
+
+
+# Type1z driver - multiple objects
+#
+$(OBJ_)%.$O: $(T1_DIR_)%.c $(FREETYPE_H) $(T1_DRV_H)
+ $(T1_COMPILE) $T$@ $<
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(T1_DRV_OBJ_S)
+DRV_OBJS_M += $(T1_DRV_OBJ_M)
+
+# EOF
--- /dev/null
+++ b/src/type1/type1.c
@@ -1,0 +1,49 @@
+/***************************************************************************/
+/* */
+/* type1z.c */
+/* */
+/* FreeType experimental Type 1 driver component (body only). */
+/* */
+/* 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. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1parse.c"
+#include "z1load.c"
+#include "z1objs.c"
+#include "z1driver.c"
+#include "z1gload.c"
+
+#ifndef Z1_CONFIG_OPTION_NO_AFM
+#include "z1afm.c"
+#endif
+
+#else /* FT_FLAT_COMPILE */
+
+#include <type1z/z1parse.c>
+#include <type1z/z1load.c>
+#include <type1z/z1objs.c>
+#include <type1z/z1driver.c>
+#include <type1z/z1gload.c>
+
+#ifndef Z1_CONFIG_OPTION_NO_AFM
+#include <type1z/z1afm.c>
+#endif
+
+#endif /* FT_FLAT_COMPILE */
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1afm.c
@@ -1,0 +1,293 @@
+/***************************************************************************/
+/* */
+/* z1afm.c */
+/* */
+/* AFM support for Type 1 fonts (body). */
+/* */
+/* 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. */
+/* */
+/***************************************************************************/
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1afm.h"
+
+#else
+
+#include <type1z/z1afm.h>
+
+#endif
+
+
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/t1types.h>
+
+#include <stdlib.h> /* for qsort() */
+#include <string.h> /* for strcmp() */
+#include <ctype.h> /* for isalnum() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_z1afm
+
+
+ LOCAL_FUNC
+ void Z1_Done_AFM( FT_Memory memory,
+ Z1_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 ) ( isalnum( c ) || \
+ 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 && !isdigit( *p ) )
+ {
+ sign = 1;
+ if ( *p == '-' )
+ sign = -1;
+
+ p++;
+ }
+
+ while ( p < limit && isdigit( *p ) )
+ {
+ 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 */
+ LOCAL_FUNC_X
+ int compare_kern_pairs( const void* a,
+ const void* b )
+ {
+ Z1_Kern_Pair* pair1 = (Z1_Kern_Pair*)a;
+ Z1_Kern_Pair* pair2 = (Z1_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 Z1_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;
+ Z1_Kern_Pair* pair;
+ T1_Font* type1 = &((T1_Face)t1_face)->type1;
+ Z1_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, Z1_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 ( Z1_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 Z1_Get_Kerning( Z1_AFM* afm,
+ FT_UInt glyph1,
+ FT_UInt glyph2,
+ FT_Vector* kerning )
+ {
+ Z1_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;
+ }
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1afm.h
@@ -1,0 +1,79 @@
+/***************************************************************************/
+/* */
+/* z1afm.h */
+/* */
+/* AFM support for Type 1 fonts (specification). */
+/* */
+/* 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 Z1AFM_H
+#define Z1AFM_H
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1objs.h"
+
+#else
+
+#include <type1z/z1objs.h>
+
+#endif
+
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+ typedef struct Z1_Kern_Pair_
+ {
+ FT_UInt glyph1;
+ FT_UInt glyph2;
+ FT_Vector kerning;
+
+ } Z1_Kern_Pair;
+
+
+ typedef struct Z1_AFM_
+ {
+ FT_Int num_pairs;
+ Z1_Kern_Pair* kern_pairs;
+
+ } Z1_AFM;
+
+
+ LOCAL_DEF
+ FT_Error Z1_Read_AFM( FT_Face face,
+ FT_Stream stream );
+
+ LOCAL_DEF
+ void Z1_Done_AFM( FT_Memory memory,
+ Z1_AFM* afm );
+
+ LOCAL_DEF
+ void Z1_Get_Kerning( Z1_AFM* afm,
+ FT_UInt glyph1,
+ FT_UInt glyph2,
+ FT_Vector* kerning );
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif /* Z1AFM_H */
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1driver.c
@@ -1,0 +1,340 @@
+/***************************************************************************/
+/* */
+/* z1driver.c */
+/* */
+/* Experimental Type 1 driver interface (body). */
+/* */
+/* 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. */
+/* */
+/***************************************************************************/
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1driver.h"
+#include "z1gload.h"
+#include "z1load.h"
+#include "z1afm.h"
+
+#else
+
+#include <type1z/z1driver.h>
+#include <type1z/z1gload.h>
+#include <type1z/z1load.h>
+#include <type1z/z1afm.h>
+
+#endif
+
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/psnames.h>
+
+#include <string.h> /* for strcmp() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_z1driver
+
+
+ static
+ FT_Error get_z1_glyph_name( T1_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ FT_String* gname;
+
+
+ gname = face->type1.glyph_names[glyph_index];
+
+ if ( buffer_max > 0 )
+ {
+ FT_UInt len = strlen( gname );
+
+
+ if (len >= buffer_max)
+ len = buffer_max - 1;
+
+ MEM_Copy( buffer, gname, len );
+ ((FT_Byte*)buffer)[len] = 0;
+ }
+
+ return T1_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <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
+ FT_Module_Interface Get_Interface( FT_Driver driver,
+ const FT_String* interface )
+ {
+ FT_UNUSED( driver );
+ FT_UNUSED( interface );
+
+ if ( strcmp( (const char*)interface, "glyph_name" ) == 0 )
+ return (FT_Module_Interface)get_z1_glyph_name;
+
+#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT
+ if ( strcmp( (const char*)interface, "get_mm" ) == 0 )
+ return (FT_Module_Interface)Z1_Get_Multi_Master;
+
+ if ( strcmp( (const char*)interface, "set_mm_design") == 0 )
+ return (FT_Module_Interface)Z1_Set_MM_Design;
+
+ if ( strcmp( (const char*)interface, "set_mm_blend") == 0 )
+ return (FT_Module_Interface)Z1_Set_MM_Blend;
+#endif
+ return 0;
+ }
+
+
+#ifndef Z1_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,
+ FT_Vector* kerning )
+ {
+ Z1_AFM* afm;
+
+
+ kerning->x = 0;
+ kerning->y = 0;
+
+ afm = (Z1_AFM*)face->afm_data;
+ if ( afm )
+ Z1_Get_Kerning( afm, left_glyph, right_glyph, kerning );
+
+ return T1_Err_Ok;
+ }
+
+
+#endif /* T1_CONFIG_OPTION_NO_AFM */
+
+
+ /*************************************************************************/
+ /* */
+ /* <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 if the Unicode charcode has */
+ /* no corresponding glyph */
+ if ( result == 0xFFFF )
+ result = 0;
+ goto Exit;
+
+ /*******************************************************************/
+ /* */
+ /* Custom Type 1 encoding */
+ /* */
+ case ft_encoding_adobe_custom:
+ {
+ T1_Encoding* encoding = &face->type1.encoding;
+
+
+ if ( charcode >= encoding->code_first &&
+ charcode <= encoding->code_last )
+ result = encoding->char_index[charcode];
+ goto Exit;
+ }
+
+ /*******************************************************************/
+ /* */
+ /* Adobe Standard & Expert encoding support */
+ /* */
+ default:
+ if ( charcode < 256 )
+ {
+ FT_UInt code;
+ FT_Int n;
+ const char* glyph_name;
+
+
+ code = psnames->adobe_std_encoding[charcode];
+ if ( charmap->encoding == ft_encoding_adobe_expert )
+ code = psnames->adobe_expert_encoding[charcode];
+
+ glyph_name = psnames->adobe_std_strings( code );
+ if ( !glyph_name )
+ break;
+
+ for ( n = 0; n < face->type1.num_glyphs; n++ )
+ {
+ const char* gname = face->type1.glyph_names[n];
+
+
+ if ( gname && gname[0] == glyph_name[0] &&
+ strcmp( gname, glyph_name ) == 0 )
+ {
+ result = n;
+ break;
+ }
+ }
+ }
+ }
+ Exit:
+ return result;
+ }
+
+
+ FT_CPLUSPLUS( const FT_Driver_Class ) t1_driver_class =
+ {
+ {
+ ft_module_font_driver | ft_module_driver_scalable,
+ sizeof( FT_DriverRec ),
+
+ "type1",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* format interface */
+
+ (FT_Module_Constructor)Z1_Init_Driver,
+ (FT_Module_Destructor) Z1_Done_Driver,
+ (FT_Module_Requester) Get_Interface,
+ },
+
+ sizeof( T1_FaceRec ),
+ sizeof( Z1_SizeRec ),
+ sizeof( Z1_GlyphSlotRec ),
+
+ (FTDriver_initFace) Z1_Init_Face,
+ (FTDriver_doneFace) Z1_Done_Face,
+ (FTDriver_initSize) 0,
+ (FTDriver_doneSize) 0,
+ (FTDriver_initGlyphSlot)0,
+ (FTDriver_doneGlyphSlot)0,
+
+ (FTDriver_setCharSizes) 0,
+ (FTDriver_setPixelSizes)0,
+ (FTDriver_loadGlyph) Z1_Load_Glyph,
+ (FTDriver_getCharIndex) Get_Char_Index,
+
+#ifdef Z1_CONFIG_OPTION_NO_AFM
+ (FTDriver_getKerning) 0,
+ (FTDriver_attachFile) 0,
+#else
+ (FTDriver_getKerning) Get_Kerning,
+ (FTDriver_attachFile) Z1_Read_AFM,
+#endif
+ (FTDriver_getAdvances) 0
+ };
+
+
+#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
+
+ EXPORT_FUNC( const FT_Driver_Class* ) getDriverClass( void )
+ {
+ return &t1z_driver_class;
+ }
+
+#endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1driver.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/* */
+/* z1driver.h */
+/* */
+/* High-level experimental Type 1 driver interface (specification). */
+/* */
+/* 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 Z1DRIVER_H
+#define Z1DRIVER_H
+
+#include <freetype/internal/ftdriver.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+ FT_EXPORT_VAR( const FT_Driver_Class ) t1_driver_class;
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif /* Z1DRIVER_H */
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1gload.c
@@ -1,0 +1,309 @@
+/***************************************************************************/
+/* */
+/* z1gload.c */
+/* */
+/* Experimental Type 1 Glyph Loader (body). */
+/* */
+/* 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. */
+/* */
+/***************************************************************************/
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1gload.h"
+
+#else
+
+#include <type1z/z1gload.h>
+
+#endif
+
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/ftoutln.h>
+#include <freetype/internal/psaux.h>
+
+
+#include <string.h> /* for strcmp() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_z1gload
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
+ /********** *********/
+ /********** The following code is in charge of computing *********/
+ /********** the maximum advance width of the font. It *********/
+ /********** quickly processes each glyph charstring to *********/
+ /********** extract the value from either a `sbw' or `seac' *********/
+ /********** operator. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ LOCAL_FUNC_X
+ FT_Error Z1_Parse_Glyph( T1_Decoder* decoder,
+ FT_UInt glyph_index )
+ {
+ T1_Face face = (T1_Face)decoder->builder.face;
+ T1_Font* type1 = &face->type1;
+
+
+ decoder->font_matrix = type1->font_matrix;
+ decoder->font_offset = type1->font_offset;
+
+ return decoder->funcs.parse_charstrings(
+ decoder,
+ type1->charstrings [glyph_index],
+ type1->charstrings_len[glyph_index] );
+ }
+
+
+ LOCAL_FUNC
+ FT_Error Z1_Compute_Max_Advance( T1_Face face,
+ FT_Int* max_advance )
+ {
+ FT_Error error;
+ T1_Decoder decoder;
+ FT_Int glyph_index;
+ T1_Font* type1 = &face->type1;
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+
+ *max_advance = 0;
+
+ /* initialize load decoder */
+ error = psaux->t1_decoder_funcs->init( &decoder,
+ (FT_Face)face,
+ 0, /* size */
+ 0, /* glyph slot */
+ (FT_Byte**)type1->glyph_names,
+ face->blend,
+ Z1_Parse_Glyph );
+ if ( error )
+ return error;
+
+ decoder.builder.metrics_only = 1;
+ decoder.builder.load_points = 0;
+
+ decoder.num_subrs = type1->num_subrs;
+ decoder.subrs = type1->subrs;
+ decoder.subrs_len = type1->subrs_len;
+
+ /* for each glyph, parse the glyph charstring and extract */
+ /* the advance width */
+ for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ )
+ {
+ /* now get load the unscaled outline */
+ error = Z1_Parse_Glyph( &decoder, glyph_index );
+ /* ignore the error if one occured - skip to next glyph */
+ }
+
+ *max_advance = decoder.builder.advance.x;
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** 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. *********/
+ /********** *********/
+ /********** The Type 1 hinter is located in `t1hint.c' *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ LOCAL_FUNC
+ FT_Error Z1_Load_Glyph( Z1_GlyphSlot glyph,
+ Z1_Size size,
+ FT_Int glyph_index,
+ FT_Int load_flags )
+ {
+ FT_Error error;
+ T1_Decoder decoder;
+ T1_Face face = (T1_Face)glyph->root.face;
+ FT_Bool hinting;
+ T1_Font* type1 = &face->type1;
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+ const T1_Decoder_Funcs* decoder_funcs = psaux->t1_decoder_funcs;
+
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+
+ 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_outline;
+
+ error = decoder_funcs->init( &decoder,
+ (FT_Face)face,
+ (FT_Size)size,
+ (FT_GlyphSlot)glyph,
+ (FT_Byte**)type1->glyph_names,
+ face->blend,
+ Z1_Parse_Glyph );
+ if ( error )
+ goto Exit;
+
+ decoder.builder.no_recurse = ( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
+
+ decoder.num_subrs = type1->num_subrs;
+ decoder.subrs = type1->subrs;
+ decoder.subrs_len = type1->subrs_len;
+
+
+ /* now load the unscaled outline */
+ error = Z1_Parse_Glyph( &decoder, glyph_index );
+ if ( error )
+ goto Exit;
+
+ font_matrix = decoder.font_matrix;
+ font_offset = decoder.font_offset;
+
+ /* save new glyph tables */
+ decoder_funcs->done( &decoder );
+
+ /* 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 )
+ {
+ glyph->root.outline.flags &= ft_outline_owner;
+ glyph->root.outline.flags |= ft_outline_reverse_fill;
+
+ /* for composite glyphs, return only left side bearing and */
+ /* 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;
+ glyph->root.linearHoriAdvance = decoder.builder.advance.x;
+
+ /* make up vertical metrics */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+
+ glyph->root.linearVertAdvance = 0;
+
+ glyph->root.format = ft_glyph_format_outline;
+
+ if ( size && size->root.metrics.y_ppem < 24 )
+ glyph->root.outline.flags |= ft_outline_high_precision;
+
+ /* apply the font matrix */
+ FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+ FT_Outline_Translate( &glyph->root.outline,
+ font_offset.x,
+ font_offset.y );
+
+#if 0
+
+ glyph->root.outline.second_pass = TRUE;
+ glyph->root.outline.high_precision = size->root.metrics.y_ppem < 24;
+ glyph->root.outline.dropout_mode = 2;
+
+#endif /* 0 */
+
+ if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ /* scale the outline and the metrics */
+ FT_Int n;
+ FT_Outline* cur = decoder.builder.base;
+ FT_Vector* vec = cur->points;
+ FT_Fixed x_scale = glyph->x_scale;
+ FT_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->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+
+ metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+ metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+ }
+
+ /* 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;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1gload.h
@@ -1,0 +1,58 @@
+/***************************************************************************/
+/* */
+/* z1gload.h */
+/* */
+/* Experimental Type 1 Glyph Loader (specification). */
+/* */
+/* 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 Z1GLOAD_H
+#define Z1GLOAD_H
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1objs.h"
+
+#else
+
+#include <type1z/z1objs.h>
+
+#endif
+
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+ LOCAL_DEF
+ FT_Error Z1_Compute_Max_Advance( T1_Face face,
+ FT_Int* max_advance );
+
+ LOCAL_DEF
+ FT_Error Z1_Load_Glyph( Z1_GlyphSlot glyph,
+ Z1_Size size,
+ FT_Int glyph_index,
+ FT_Int load_flags );
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif /* Z1GLOAD_H */
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1load.c
@@ -1,0 +1,1702 @@
+/***************************************************************************/
+/* */
+/* z1load.c */
+/* */
+/* Experimental Type 1 font loader (body). */
+/* */
+/* Copyright 1996-2000 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This is the new and improved Type 1 data loader for FreeType 2. The */
+ /* old loader has several problems: it is slow, complex, difficult to */
+ /* maintain, and contains incredible hacks to make it accept some */
+ /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */
+ /* the Type 1 fonts on my machine still aren't loaded correctly by it. */
+ /* */
+ /* This version is much simpler, much faster and also easier to read and */
+ /* maintain by a great order of magnitude. The idea behind it is to */
+ /* _not_ try to read the Type 1 token stream with a state machine (i.e. */
+ /* a Postscript-like interpreter) but rather to perform simple pattern */
+ /* matching. */
+ /* */
+ /* Indeed, nearly all data definitions follow a simple pattern like */
+ /* */
+ /* ... /Field <data> ... */
+ /* */
+ /* where <data> can be a number, a boolean, a string, or an array of */
+ /* numbers. There are a few exceptions, namely the encoding, font name, */
+ /* charstrings, and subrs; they are handled with a special pattern */
+ /* matching routine. */
+ /* */
+ /* All other common cases are handled very simply. The matching rules */
+ /* are defined in the file `t1tokens.h' through the use of several */
+ /* macros calls PARSE_XXX. */
+ /* */
+ /* This file is included twice here; the first time to generate parsing */
+ /* callback functions, the second to generate a table of keywords (with */
+ /* pointers to the associated callback). */
+ /* */
+ /* The function `parse_dict' simply scans *linearly* a given dictionary */
+ /* (either the top-level or private one) and calls the appropriate */
+ /* callback when it encounters an immediate keyword. */
+ /* */
+ /* This is by far the fastest way one can find to parse and read all */
+ /* data. */
+ /* */
+ /* This led to tremendous code size reduction. Note that later, the */
+ /* glyph loader will also be _greatly_ simplified, and the automatic */
+ /* hinter will replace the clumsy `t1hinter'. */
+ /* */
+ /*************************************************************************/
+
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/config/ftconfig.h>
+#include <freetype/ftmm.h>
+
+#include <freetype/internal/t1types.h>
+#include <freetype/internal/t1errors.h>
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1load.h"
+
+#else
+
+#include <type1z/z1load.h>
+
+#endif
+
+
+#include <string.h> /* for strncmp(), strcmp() */
+#include <ctype.h> /* for isalnum() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_z1load
+
+
+#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** MULTIPLE MASTERS SUPPORT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static
+ FT_Error t1_allocate_blend( T1_Face face,
+ FT_UInt num_designs,
+ FT_UInt num_axis )
+ {
+ T1_Blend* blend;
+ FT_Memory memory = face->root.memory;
+ FT_Error error = 0;
+
+
+ blend = face->blend;
+ if ( !blend )
+ {
+ if ( ALLOC( blend, sizeof ( *blend ) ) )
+ goto Exit;
+
+ face->blend = blend;
+ }
+
+ /* allocate design data if needed */
+ if ( num_designs > 0 )
+ {
+ if ( blend->num_designs == 0 )
+ {
+ FT_UInt nn;
+
+
+ /* allocate the blend `private' and `font_info' dictionaries */
+ if ( ALLOC_ARRAY( blend->font_infos[1], num_designs, T1_FontInfo ) ||
+ ALLOC_ARRAY( blend->privates[1], num_designs, T1_Private ) ||
+ ALLOC_ARRAY( blend->weight_vector, num_designs * 2, FT_Fixed ) )
+ goto Exit;
+
+ blend->default_weight_vector = blend->weight_vector + num_designs;
+
+ blend->font_infos[0] = &face->type1.font_info;
+ blend->privates [0] = &face->type1.private_dict;
+
+ for ( nn = 2; nn <= num_designs; nn++ )
+ {
+ blend->privates[nn] = blend->privates [nn - 1] + 1;
+ blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
+ }
+
+ blend->num_designs = num_designs;
+ }
+ else if ( blend->num_designs != num_designs )
+ goto Fail;
+ }
+
+ /* allocate axis data if needed */
+ if ( num_axis > 0 )
+ {
+ if ( blend->num_axis != 0 && blend->num_axis != num_axis )
+ goto Fail;
+
+ blend->num_axis = num_axis;
+ }
+
+ /* allocate the blend design pos table if needed */
+ num_designs = blend->num_designs;
+ num_axis = blend->num_axis;
+ if ( num_designs && num_axis && blend->design_pos[0] == 0 )
+ {
+ FT_UInt n;
+
+
+ if ( ALLOC_ARRAY( blend->design_pos[0],
+ num_designs * num_axis, FT_Fixed ) )
+ goto Exit;
+
+ for ( n = 1; n < num_designs; n++ )
+ blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
+ }
+
+ Exit:
+ return error;
+
+ Fail:
+ error = -1;
+ goto Exit;
+ }
+
+
+ LOCAL_FUNC
+ FT_Error Z1_Get_Multi_Master( T1_Face face,
+ FT_Multi_Master* master )
+ {
+ T1_Blend* blend = face->blend;
+ FT_UInt n;
+ FT_Error error;
+
+
+ error = T1_Err_Invalid_Argument;
+
+ if ( blend )
+ {
+ master->num_axis = blend->num_axis;
+ master->num_designs = blend->num_designs;
+
+ for ( n = 0; n < blend->num_axis; n++ )
+ {
+ FT_MM_Axis* axis = master->axis + n;
+ T1_DesignMap* map = blend->design_map + n;
+
+
+ axis->name = blend->axis_names[n];
+ axis->minimum = map->design_points[0];
+ axis->maximum = map->design_points[map->num_points - 1];
+ }
+ error = 0;
+ }
+ return error;
+ }
+
+
+ LOCAL_FUNC
+ FT_Error Z1_Set_MM_Blend( T1_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ T1_Blend* blend = face->blend;
+ FT_Error error;
+ FT_UInt n, m;
+
+
+ error = T1_Err_Invalid_Argument;
+
+ if ( blend && blend->num_axis == num_coords )
+ {
+ /* recompute the weight vector from the blend coordinates */
+ error = FT_Err_Ok;
+
+ for ( n = 0; n < blend->num_designs; n++ )
+ {
+ FT_Fixed result = 0x10000L; /* 1.0 fixed */
+
+
+ for ( m = 0; m < blend->num_axis; m++ )
+ {
+ FT_Fixed factor;
+
+
+ /* get current blend axis position */
+ factor = coords[m];
+ if ( factor < 0 ) factor = 0;
+ if ( factor > 0x10000L ) factor = 0x10000L;
+
+ if ( ( n & ( 1 << m ) ) == 0 )
+ factor = 0x10000L - factor;
+
+ result = FT_MulFix( result, factor );
+ }
+ blend->weight_vector[n] = result;
+ }
+
+ error = FT_Err_Ok;
+ }
+ return error;
+ }
+
+
+ LOCAL_FUNC
+ FT_Error Z1_Set_MM_Design( T1_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords )
+ {
+ T1_Blend* blend = face->blend;
+ FT_Error error;
+ FT_UInt n, p;
+
+
+ error = T1_Err_Invalid_Argument;
+ if ( blend && blend->num_axis == num_coords )
+ {
+ /* compute the blend coordinates through the blend design map */
+ FT_Fixed final_blends[T1_MAX_MM_DESIGNS];
+
+
+ for ( n = 0; n < blend->num_axis; n++ )
+ {
+ FT_Long design = coords[n];
+ FT_Fixed the_blend;
+ T1_DesignMap* map = blend->design_map + n;
+ FT_Fixed* designs = map->design_points;
+ FT_Fixed* blends = map->blend_points;
+ FT_Int before = -1, after = -1;
+
+ for ( p = 0; p < map->num_points; p++ )
+ {
+ FT_Fixed p_design = designs[p];
+
+
+ /* exact match ? */
+ if ( design == p_design )
+ {
+ the_blend = blends[p];
+ goto Found;
+ }
+
+ if ( design < p_design )
+ {
+ after = p;
+ break;
+ }
+
+ before = p;
+ }
+
+ /* now, interpolate if needed */
+ if ( before < 0 )
+ the_blend = blends[0];
+
+ else if ( after < 0 )
+ the_blend = blends[map->num_points - 1];
+
+ else
+ the_blend = FT_MulDiv( design - designs[before],
+ blends [after] - blends [before],
+ designs[after] - designs[before] );
+
+ Found:
+ final_blends[n] = the_blend;
+ }
+
+ error = Z1_Set_MM_Blend( face, num_coords, final_blends );
+ }
+
+ return error;
+ }
+
+
+ LOCAL_FUNC
+ void Z1_Done_Blend( T1_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ T1_Blend* blend = face->blend;
+
+
+ if ( blend )
+ {
+ FT_UInt num_designs = blend->num_designs;
+ FT_UInt num_axis = blend->num_axis;
+ FT_UInt n;
+
+
+ /* release design pos table */
+ FREE( blend->design_pos[0] );
+ for ( n = 1; n < num_designs; n++ )
+ blend->design_pos[n] = 0;
+
+ /* release blend `private' and `font info' dictionaries */
+ FREE( blend->privates[1] );
+ FREE( blend->font_infos[1] );
+
+ for ( n = 0; n < num_designs; n++ )
+ {
+ blend->privates [n] = 0;
+ blend->font_infos[n] = 0;
+ }
+
+ /* release weight vectors */
+ FREE( blend->weight_vector );
+ blend->default_weight_vector = 0;
+
+ /* release axis names */
+ for ( n = 0; n < num_axis; n++ )
+ FREE( blend->axis_names[n] );
+
+ /* release design map */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ T1_DesignMap* dmap = blend->design_map + n;
+
+
+ FREE( dmap->design_points );
+ dmap->num_points = 0;
+ }
+
+ FREE( face->blend );
+ }
+ }
+
+
+ static
+ void parse_blend_axis_types( T1_Face face,
+ Z1_Loader* loader )
+ {
+ T1_Token axis_tokens[ T1_MAX_MM_AXIS ];
+ FT_Int n, num_axis;
+ FT_Error error = 0;
+ T1_Blend* blend;
+ FT_Memory memory;
+
+
+ /* take an array of objects */
+ Z1_ToTokenArray( &loader->parser, axis_tokens,
+ T1_MAX_MM_AXIS, &num_axis );
+ if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
+ {
+ FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
+ num_axis ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* allocate blend if necessary */
+ error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
+ if ( error )
+ goto Exit;
+
+ blend = face->blend;
+ memory = face->root.memory;
+
+ /* each token is an immediate containing the name of the axis */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ T1_Token* token = axis_tokens + n;
+ FT_Byte* name;
+ FT_Int len;
+
+ /* skip first slash, if any */
+ if (token->start[0] == '/')
+ token->start++;
+
+ len = token->limit - token->start;
+ if ( len <= 0 )
+ {
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ if ( ALLOC( blend->axis_names[n], len + 1 ) )
+ goto Exit;
+
+ name = (FT_Byte*)blend->axis_names[n];
+ MEM_Copy( name, token->start, len );
+ name[len] = 0;
+ }
+
+ Exit:
+ loader->parser.root.error = error;
+ }
+
+
+ static
+ void parse_blend_design_positions( T1_Face face,
+ Z1_Loader* loader )
+ {
+ T1_Token design_tokens[ T1_MAX_MM_DESIGNS ];
+ FT_Int num_designs;
+ FT_Int num_axis;
+ Z1_Parser* parser = &loader->parser;
+
+ FT_Error error = 0;
+ T1_Blend* blend;
+
+
+ /* get the array of design tokens - compute number of designs */
+ Z1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs );
+ if ( num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS )
+ {
+ FT_ERROR(( "parse_blend_design_positions:" ));
+ FT_ERROR(( " incorrect number of designs: %d\n",
+ num_designs ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ {
+ FT_Byte* old_cursor = parser->root.cursor;
+ FT_Byte* old_limit = parser->root.limit;
+ FT_UInt n;
+
+
+ blend = face->blend;
+ num_axis = 0; /* make compiler happy */
+
+ for ( n = 0; n < (FT_UInt)num_designs; n++ )
+ {
+ T1_Token axis_tokens[ T1_MAX_MM_DESIGNS ];
+ T1_Token* token;
+ FT_Int axis, n_axis;
+
+
+ /* read axis/coordinates tokens */
+ token = design_tokens + n;
+ parser->root.cursor = token->start - 1;
+ parser->root.limit = token->limit + 1;
+ Z1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
+
+ if ( n == 0 )
+ {
+ num_axis = n_axis;
+ error = t1_allocate_blend( face, num_designs, num_axis );
+ if ( error )
+ goto Exit;
+ blend = face->blend;
+ }
+ else if ( n_axis != num_axis )
+ {
+ FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* now, read each axis token into the design position */
+ for ( axis = 0; axis < n_axis; axis++ )
+ {
+ T1_Token* token2 = axis_tokens + axis;
+
+
+ parser->root.cursor = token2->start;
+ parser->root.limit = token2->limit;
+ blend->design_pos[n][axis] = Z1_ToFixed( parser, 0 );
+ }
+ }
+
+ loader->parser.root.cursor = old_cursor;
+ loader->parser.root.limit = old_limit;
+ }
+
+ Exit:
+ loader->parser.root.error = error;
+ }
+
+
+ static
+ void parse_blend_design_map( T1_Face face,
+ Z1_Loader* loader )
+ {
+ FT_Error error = 0;
+ Z1_Parser* parser = &loader->parser;
+ T1_Blend* blend;
+ T1_Token axis_tokens[ T1_MAX_MM_AXIS ];
+ FT_Int n, num_axis;
+ FT_Byte* old_cursor;
+ FT_Byte* old_limit;
+ FT_Memory memory = face->root.memory;
+
+
+ Z1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
+ if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
+ {
+ FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
+ num_axis ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ old_cursor = parser->root.cursor;
+ old_limit = parser->root.limit;
+
+ error = t1_allocate_blend( face, 0, num_axis );
+ if ( error )
+ goto Exit;
+ blend = face->blend;
+
+ /* now, read each axis design map */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ T1_DesignMap* map = blend->design_map + n;
+ T1_Token* token;
+ FT_Int p, num_points;
+
+
+ token = axis_tokens + n;
+ parser->root.cursor = token->start;
+ parser->root.limit = token->limit;
+
+ /* count the number of map points */
+ {
+ FT_Byte* ptr = token->start;
+ FT_Byte* limit = token->limit;
+
+
+ num_points = 0;
+ for ( ; ptr < limit; ptr++ )
+ if ( ptr[0] == '[' )
+ num_points++;
+ }
+ if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
+ {
+ FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* allocate design map data */
+ if ( ALLOC_ARRAY( map->design_points, num_points * 2, FT_Fixed ) )
+ goto Exit;
+ map->blend_points = map->design_points + num_points;
+ map->num_points = (FT_Byte)num_points;
+
+ for ( p = 0; p < num_points; p++ )
+ {
+ map->design_points[p] = Z1_ToInt( parser );
+ map->blend_points [p] = Z1_ToFixed( parser, 0 );
+ }
+ }
+
+ parser->root.cursor = old_cursor;
+ parser->root.limit = old_limit;
+
+ Exit:
+ parser->root.error = error;
+ }
+
+
+ static
+ void parse_weight_vector( T1_Face face,
+ Z1_Loader* loader )
+ {
+ FT_Error error = 0;
+ Z1_Parser* parser = &loader->parser;
+ T1_Blend* blend = face->blend;
+ T1_Token master;
+ FT_UInt n;
+ FT_Byte* old_cursor;
+ FT_Byte* old_limit;
+
+
+ if ( !blend || blend->num_designs == 0 )
+ {
+ FT_ERROR(( "parse_weight_vector: too early!\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ Z1_ToToken( parser, &master );
+ if ( master.type != t1_token_array )
+ {
+ FT_ERROR(( "parse_weight_vector: incorrect format!\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ old_cursor = parser->root.cursor;
+ old_limit = parser->root.limit;
+
+ parser->root.cursor = master.start;
+ parser->root.limit = master.limit;
+
+ for ( n = 0; n < blend->num_designs; n++ )
+ {
+ blend->default_weight_vector[n] =
+ blend->weight_vector[n] = Z1_ToFixed( parser, 0 );
+ }
+
+ parser->root.cursor = old_cursor;
+ parser->root.limit = old_limit;
+
+ Exit:
+ parser->root.error = error;
+ }
+
+
+ /* the keyword `/shareddict' appears in some multiple master fonts */
+ /* with a lot of Postscript garbage behind it (that's completely out */
+ /* of spec!); we detect it and terminate the parsing */
+ /* */
+ static
+ void parse_shared_dict( T1_Face face,
+ Z1_Loader* loader )
+ {
+ Z1_Parser* parser = &loader->parser;
+
+ FT_UNUSED( face );
+
+
+ parser->root.cursor = parser->root.limit;
+ parser->root.error = 0;
+ }
+
+#endif /* Z1_CONFIG_OPTION_NO_MM_SUPPORT */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE 1 SYMBOL PARSING *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* First of all, define the token field static variables. This is a set */
+ /* of T1_Field variables used later. */
+ /* */
+ /*************************************************************************/
+
+
+ static
+ FT_Error t1_load_keyword( T1_Face face,
+ Z1_Loader* loader,
+ T1_Field* field )
+ {
+ FT_Error error;
+ void* dummy_object;
+ void** objects;
+ FT_UInt max_objects;
+ T1_Blend* blend = face->blend;
+
+
+ /* if the keyword has a dedicated callback, call it */
+ if ( field->type == t1_field_callback )
+ {
+ field->reader( (FT_Face)face, loader );
+ error = loader->parser.root.error;
+ goto Exit;
+ }
+
+ /* now, the keyword is either a simple field, or a table of fields; */
+ /* we are now going to take care of it */
+ switch ( field->location )
+ {
+ case t1_field_font_info:
+ dummy_object = &face->type1.font_info;
+ objects = &dummy_object;
+ max_objects = 0;
+
+ if ( blend )
+ {
+ objects = (void**)blend->font_infos;
+ max_objects = blend->num_designs;
+ }
+ break;
+
+ case t1_field_private:
+ dummy_object = &face->type1.private_dict;
+ objects = &dummy_object;
+ max_objects = 0;
+
+ if ( blend )
+ {
+ objects = (void**)blend->privates;
+ max_objects = blend->num_designs;
+ }
+ break;
+
+ default:
+ dummy_object = &face->type1;
+ objects = &dummy_object;
+ max_objects = 0;
+ }
+
+ if ( field->type == t1_field_integer_array ||
+ field->type == t1_field_fixed_array )
+ error = Z1_Load_Field_Table( &loader->parser, field,
+ objects, max_objects, 0 );
+ else
+ error = Z1_Load_Field( &loader->parser, field,
+ objects, max_objects, 0 );
+
+ Exit:
+ return error;
+ }
+
+
+ static
+ int is_space( FT_Byte c )
+ {
+ return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' );
+ }
+
+
+ static
+ int is_alpha( FT_Byte c )
+ {
+ return ( isalnum( c ) || c == '.' || c == '_' );
+ }
+
+
+
+ static
+ int read_binary_data( Z1_Parser* parser,
+ FT_Int* size,
+ FT_Byte** base )
+ {
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+
+
+ /* the binary data has the following format */
+ /* */
+ /* `size' [white*] RD white ....... ND */
+ /* */
+
+ Z1_Skip_Spaces( parser );
+ cur = parser->root.cursor;
+
+ if ( cur < limit && (FT_Byte)( *cur - '0' ) < 10 )
+ {
+ *size = Z1_ToInt( parser );
+
+ Z1_Skip_Spaces( parser );
+ Z1_Skip_Alpha ( parser ); /* `RD' or `-|' or something else */
+
+ /* there is only one whitespace char after the */
+ /* `RD' or `-|' token */
+ *base = parser->root.cursor + 1;
+
+ parser->root.cursor += *size + 1;
+ return 1;
+ }
+
+ FT_ERROR(( "read_binary_data: invalid size field\n" ));
+ parser->root.error = T1_Err_Invalid_File_Format;
+ return 0;
+ }
+
+
+ /* we will now define the routines used to handle */
+ /* the `/Encoding', `/Subrs', and `/CharStrings' */
+ /* dictionaries */
+
+ static
+ void parse_font_name( T1_Face face,
+ Z1_Loader* loader )
+ {
+ Z1_Parser* parser = &loader->parser;
+ FT_Error error;
+ FT_Memory memory = parser->root.memory;
+ FT_Int len;
+ FT_Byte* cur;
+ FT_Byte* cur2;
+ FT_Byte* limit;
+
+
+ Z1_Skip_Spaces( parser );
+
+ cur = parser->root.cursor;
+ limit = parser->root.limit;
+
+ if ( cur >= limit - 1 || *cur != '/' )
+ return;
+
+ cur++;
+ cur2 = cur;
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+
+ len = cur2 - cur;
+ if ( len > 0 )
+ {
+ if ( ALLOC( face->type1.font_name, len + 1 ) )
+ {
+ parser->root.error = error;
+ return;
+ }
+
+ MEM_Copy( face->type1.font_name, cur, len );
+ face->type1.font_name[len] = '\0';
+ }
+ parser->root.cursor = cur2;
+ }
+
+
+ static
+ void parse_font_bbox( T1_Face face,
+ Z1_Loader* loader )
+ {
+ Z1_Parser* parser = &loader->parser;
+ FT_Short temp[4];
+ FT_BBox* bbox = &face->type1.font_bbox;
+
+
+ (void)Z1_ToCoordArray( parser, 4, temp );
+ bbox->xMin = temp[0];
+ bbox->yMin = temp[1];
+ bbox->xMax = temp[2];
+ bbox->yMax = temp[3];
+ }
+
+
+ static
+ void parse_font_matrix( T1_Face face,
+ Z1_Loader* loader )
+ {
+ Z1_Parser* parser = &loader->parser;
+ FT_Matrix* matrix = &face->type1.font_matrix;
+ FT_Vector* offset = &face->type1.font_offset;
+ FT_Fixed temp[6];
+
+
+ if ( matrix->xx || matrix->yx )
+ /* with synthetic fonts, it's possible we get here twice */
+ return;
+
+ (void)Z1_ToFixedArray( parser, 6, temp, 3 );
+
+ /* we need to scale the values by 1.0/temp[3] */
+ if ( temp[3] != 0x10000L )
+ {
+ temp[0] = FT_DivFix( temp[0], temp[3] );
+ temp[1] = FT_DivFix( temp[1], temp[3] );
+ temp[2] = FT_DivFix( temp[2], temp[3] );
+ temp[4] = FT_DivFix( temp[4], temp[3] );
+ temp[5] = FT_DivFix( temp[5], temp[3] );
+ temp[3] = 0x10000L;
+ }
+
+ matrix->xx = temp[0];
+ matrix->yx = temp[1];
+ matrix->xy = temp[2];
+ matrix->yy = temp[3];
+
+ /* note that the offsets must be expressed in integer font units */
+ offset->x = temp[4] >> 16;
+ offset->y = temp[5] >> 16;
+ }
+
+
+ static
+ void parse_encoding( T1_Face face,
+ Z1_Loader* loader )
+ {
+ Z1_Parser* parser = &loader->parser;
+ FT_Byte* cur = parser->root.cursor;
+ FT_Byte* limit = parser->root.limit;
+
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+
+ /* skip whitespace */
+ while ( is_space( *cur ) )
+ {
+ cur++;
+ if ( cur >= limit )
+ {
+ FT_ERROR(( "parse_encoding: out of bounds!\n" ));
+ parser->root.error = T1_Err_Invalid_File_Format;
+ return;
+ }
+ }
+
+ /* if we have a number, then the encoding is an array, */
+ /* and we must load it now */
+ if ( (FT_Byte)( *cur - '0' ) < 10 )
+ {
+ T1_Encoding* encode = &face->type1.encoding;
+ FT_Int count, n;
+ PS_Table* char_table = &loader->encoding_table;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+
+
+ /* read the number of entries in the encoding, should be 256 */
+ count = Z1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* we use a Z1_Table to store our charnames */
+ encode->num_chars = count;
+ if ( ALLOC_ARRAY( encode->char_index, count, FT_Short ) ||
+ ALLOC_ARRAY( encode->char_name, count, FT_String* ) ||
+ ( error = psaux->ps_table_funcs->init(
+ char_table, count, memory ) ) != 0 )
+ {
+ parser->root.error = error;
+ return;
+ }
+
+ /* We need to `zero' out encoding_table.elements */
+ for ( n = 0; n < count; n++ )
+ {
+ char* notdef = ".notdef";
+
+
+ Z1_Add_Table( char_table, n, notdef, 8 );
+ }
+
+ /* Now, we will need to read a record of the form */
+ /* ... charcode /charname ... for each entry in our table */
+ /* */
+ /* We simply look for a number followed by an immediate */
+ /* name. Note that this ignores correctly the sequence */
+ /* that is often seen in type1 fonts: */
+ /* */
+ /* 0 1 255 { 1 index exch /.notdef put } for dup */
+ /* */
+ /* used to clean the encoding array before anything else. */
+ /* */
+ /* We stop when we encounter a `def'. */
+
+ cur = parser->root.cursor;
+ limit = parser->root.limit;
+ n = 0;
+
+ for ( ; cur < limit; )
+ {
+ FT_Byte c;
+
+
+ c = *cur;
+
+ /* we stop when we encounter a `def' */
+ if ( c == 'd' && cur + 3 < limit )
+ {
+ if ( cur[1] == 'e' &&
+ cur[2] == 'f' &&
+ is_space(cur[-1]) &&
+ is_space(cur[3]) )
+ {
+ FT_TRACE6(( "encoding end\n" ));
+ break;
+ }
+ }
+
+ /* otherwise, we must find a number before anything else */
+ if ( (FT_Byte)( c - '0' ) < 10 )
+ {
+ FT_Int charcode;
+
+
+ parser->root.cursor = cur;
+ charcode = Z1_ToInt( parser );
+ cur = parser->root.cursor;
+
+ /* skip whitespace */
+ while ( cur < limit && is_space( *cur ) )
+ cur++;
+
+ if ( cur < limit && *cur == '/' )
+ {
+ /* bingo, we have an immediate name -- it must be a */
+ /* character name */
+ FT_Byte* cur2 = cur + 1;
+ FT_Int len;
+
+
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+
+ len = cur2 - cur - 1;
+
+ parser->root.error = Z1_Add_Table( char_table, charcode,
+ cur + 1, len + 1 );
+ char_table->elements[charcode][len] = '\0';
+ if ( parser->root.error )
+ return;
+
+ cur = cur2;
+ }
+ }
+ else
+ cur++;
+ }
+
+ face->type1.encoding_type = t1_encoding_array;
+ parser->root.cursor = cur;
+ }
+ /* Otherwise, we should have either `StandardEncoding' or */
+ /* `ExpertEncoding' */
+ else
+ {
+ if ( cur + 17 < limit &&
+ strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
+ face->type1.encoding_type = t1_encoding_standard;
+
+ else if ( cur + 15 < limit &&
+ strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
+ face->type1.encoding_type = t1_encoding_expert;
+
+ else
+ {
+ FT_ERROR(( "parse_encoding: invalid token!\n" ));
+ parser->root.error = T1_Err_Invalid_File_Format;
+ }
+ }
+ }
+
+
+ static
+ void parse_subrs( T1_Face face,
+ Z1_Loader* loader )
+ {
+ Z1_Parser* parser = &loader->parser;
+ PS_Table* table = &loader->subrs;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+ FT_Int n;
+
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+
+ loader->num_subrs = Z1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* position the parser right before the `dup' of the first subr */
+ Z1_Skip_Spaces( parser );
+ Z1_Skip_Alpha( parser ); /* `array' */
+ Z1_Skip_Spaces( parser );
+
+ /* initialize subrs array */
+ error = psaux->ps_table_funcs->init( table, loader->num_subrs, memory );
+ if ( error )
+ goto Fail;
+
+ /* the format is simple: */
+ /* */
+ /* `index' + binary data */
+ /* */
+
+ for ( n = 0; n < loader->num_subrs; n++ )
+ {
+ FT_Int index, size;
+ FT_Byte* base;
+
+
+ /* If the next token isn't `dup', we are also done. This */
+ /* happens when there are `holes' in the Subrs array. */
+ if ( strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
+ break;
+
+ index = Z1_ToInt( parser );
+
+ if ( !read_binary_data( parser, &size, &base ) )
+ return;
+
+ /* The binary string is followed by one token, e.g. `NP' */
+ /* (bound to `noaccess put') or by two separate tokens: */
+ /* `noaccess' & `put'. We position the parser right */
+ /* before the next `dup', if any. */
+ Z1_Skip_Spaces( parser );
+ Z1_Skip_Alpha( parser ); /* `NP' or `I' or `noaccess' */
+ Z1_Skip_Spaces( parser );
+
+ if ( strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
+ {
+ Z1_Skip_Alpha( parser ); /* skip `put' */
+ Z1_Skip_Spaces( parser );
+ }
+
+ /* some fonts use a value of -1 for lenIV to indicate that */
+ /* the charstrings are unencoded */
+ /* */
+ /* thanks to Tom Kacvinsky for pointing this out */
+ /* */
+ if ( face->type1.private_dict.lenIV >= 0 )
+ {
+ Z1_Decrypt( base, size, 4330 );
+ size -= face->type1.private_dict.lenIV;
+ base += face->type1.private_dict.lenIV;
+ }
+
+ error = Z1_Add_Table( table, index, base, size );
+ if ( error )
+ goto Fail;
+ }
+ return;
+
+ Fail:
+ parser->root.error = error;
+ }
+
+
+ static
+ void parse_charstrings( T1_Face face,
+ Z1_Loader* loader )
+ {
+ Z1_Parser* parser = &loader->parser;
+ PS_Table* code_table = &loader->charstrings;
+ PS_Table* name_table = &loader->glyph_names;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+ FT_Int n;
+ FT_UInt notdef_index = 0;
+ FT_Byte notdef_found = 0;
+
+
+ if ( loader->num_glyphs )
+ /* with synthetic fonts, it's possible we get here twice */
+ return;
+
+ loader->num_glyphs = Z1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* initialize tables, adding space for `swap' at table end */
+ error = psaux->ps_table_funcs->init( code_table,
+ loader->num_glyphs + 1,
+ memory );
+ if ( error )
+ goto Fail;
+
+ error = psaux->ps_table_funcs->init( name_table,
+ loader->num_glyphs + 1,
+ memory );
+ if ( error )
+ goto Fail;
+
+ n = 0;
+ for (;;)
+ {
+ FT_Int size;
+ FT_Byte* base;
+
+
+ /* the format is simple: */
+ /* `/glyphname' + binary data */
+ /* */
+ /* note that we stop when we find a `def' */
+ /* */
+ Z1_Skip_Spaces( parser );
+
+ cur = parser->root.cursor;
+ if ( cur >= limit )
+ break;
+
+ /* we stop when we find a `def' or `end' keyword */
+ if ( *cur == 'd' &&
+ cur + 3 < limit &&
+ cur[1] == 'e' &&
+ cur[2] == 'f' )
+ break;
+
+ if ( *cur == 'e' &&
+ cur + 3 < limit &&
+ cur[1] == 'n' &&
+ cur[2] == 'd' )
+ break;
+
+ if ( *cur != '/' )
+ Z1_Skip_Alpha( parser );
+ else
+ {
+ FT_Byte* cur2 = cur + 1;
+ FT_Int len;
+
+
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+ len = cur2 - cur - 1;
+
+ error = Z1_Add_Table( name_table, n, cur + 1, len + 1 );
+ if ( error )
+ goto Fail;
+
+ /* add a trailing zero to the name table */
+ name_table->elements[n][len] = '\0';
+
+ /* record index of /.notdef */
+ if ( strcmp( (const char*)".notdef",
+ (const char*)(name_table->elements[n]) ) == 0 )
+ {
+ notdef_index = n;
+ notdef_found = 1;
+ }
+
+ parser->root.cursor = cur2;
+ if ( !read_binary_data( parser, &size, &base ) )
+ return;
+
+ if ( face->type1.private_dict.lenIV >= 0 )
+ {
+ Z1_Decrypt( base, size, 4330 );
+ size -= face->type1.private_dict.lenIV;
+ base += face->type1.private_dict.lenIV;
+ }
+
+ error = Z1_Add_Table( code_table, n, base, size );
+ if ( error )
+ goto Fail;
+
+ n++;
+ if ( n >= loader->num_glyphs )
+ break;
+ }
+ }
+
+ loader->num_glyphs = n;
+
+ /* if /.notdef is found but does not occupy index 0, do our magic. */
+ if ( strcmp( (const char*)".notdef",
+ (const char*)name_table->elements[0] ) &&
+ notdef_found )
+ {
+
+ /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
+ /* name/code to end of table. Then place notdef_index name/code into */
+ /* index 0. Then take end of table name/code and place it into index */
+ /* notdef_index. */
+
+ error = Z1_Add_Table( name_table, n,
+ name_table->elements[0],
+ name_table->lengths [0] );
+ if ( error )
+ goto Fail;
+ error = Z1_Add_Table( code_table, n,
+ code_table->elements[0],
+ code_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = Z1_Add_Table( name_table, 0,
+ name_table->elements[notdef_index],
+ name_table->lengths [notdef_index] );
+ if ( error )
+ goto Fail;
+
+ error = Z1_Add_Table( code_table, 0,
+ code_table->elements[notdef_index],
+ code_table->lengths [notdef_index] );
+ if ( error )
+ goto Fail;
+
+ error = Z1_Add_Table( name_table, notdef_index,
+ name_table->elements[n],
+ name_table->lengths [n] );
+ if ( error )
+ goto Fail;
+
+ error = Z1_Add_Table( code_table, notdef_index,
+ code_table->elements[n],
+ code_table->lengths [n] );
+ if ( error )
+ goto Fail;
+
+ }
+ else if ( !notdef_found )
+ {
+
+ /* notdef_index is already 0, or /.notdef is undefined in */
+ /* charstrings dictionary. Worry about /.notdef undefined. */
+ /* we take index 0 and add it to the end of the table(s) */
+ /* and add our own /.notdef glyph to index 0. */
+
+ /* 0 333 hsbw endchar */
+ FT_Byte notdef_glyph[] = {0x8B, 0xF7, 0xE1, 0x0D, 0x0E};
+ char* notdef_name = ".notdef";
+
+
+ error = Z1_Add_Table( name_table, n,
+ name_table->elements[0],
+ name_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = Z1_Add_Table( code_table, n,
+ code_table->elements[0],
+ code_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = Z1_Add_Table( name_table, 0, notdef_name, 8 );
+ if ( error )
+ goto Fail;
+
+ error = Z1_Add_Table( code_table, 0, notdef_glyph, 5 );
+
+ if ( error )
+ goto Fail;
+
+ /* we added a glyph. */
+ loader->num_glyphs = n + 1;
+
+ }
+
+ return;
+
+ Fail:
+ parser->root.error = error;
+ }
+
+
+ static
+ const T1_Field t1_keywords[] =
+ {
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1tokens.h"
+
+#else
+
+#include <type1z/z1tokens.h>
+
+#endif
+
+ /* now add the special functions... */
+ T1_FIELD_CALLBACK( "FontName", parse_font_name )
+ T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
+ T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
+ T1_FIELD_CALLBACK( "Encoding", parse_encoding )
+ T1_FIELD_CALLBACK( "Subrs", parse_subrs )
+ T1_FIELD_CALLBACK( "CharStrings", parse_charstrings )
+
+#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT
+ T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions )
+ T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map )
+ T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types )
+ T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector )
+ T1_FIELD_CALLBACK( "shareddict", parse_shared_dict )
+#endif
+
+ { 0, t1_field_cid_info, t1_field_none, 0, 0, 0, 0, 0 }
+ };
+
+
+ static
+ FT_Error parse_dict( T1_Face face,
+ Z1_Loader* loader,
+ FT_Byte* base,
+ FT_Long size )
+ {
+ Z1_Parser* parser = &loader->parser;
+
+
+ parser->root.cursor = base;
+ parser->root.limit = base + size;
+ parser->root.error = 0;
+
+ {
+ FT_Byte* cur = base;
+ FT_Byte* limit = cur + size;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ /* look for `FontDirectory', which causes problems on some fonts */
+ if ( *cur == 'F' && cur + 25 < limit &&
+ strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
+ {
+ FT_Byte* cur2;
+
+
+ /* skip the `FontDirectory' keyword */
+ cur += 13;
+ cur2 = cur;
+
+ /* lookup the `known' keyword */
+ while ( cur < limit && *cur != 'k' &&
+ strncmp( (char*)cur, "known", 5 ) )
+ cur++;
+
+ if ( cur < limit )
+ {
+ T1_Token token;
+
+
+ /* skip the `known' keyword and the token following it */
+ cur += 5;
+ loader->parser.root.cursor = cur;
+ Z1_ToToken( &loader->parser, &token );
+
+ /* if the last token was an array, skip it! */
+ if ( token.type == t1_token_array )
+ cur2 = parser->root.cursor;
+ }
+ cur = cur2;
+ }
+ /* 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 )
+ {
+ if ( !loader->fontdata )
+ {
+ if ( strncmp( (char*)cur, "FontInfo", 8 ) == 0 )
+ loader->fontdata = 1;
+ }
+ else
+ {
+ /* now, compare the immediate name to the keyword table */
+ T1_Field* keyword = (T1_Field*)t1_keywords;
+
+
+ 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->root.cursor = cur2;
+ Z1_Skip_Spaces( parser );
+ parser->root.error = t1_load_keyword( face,
+ loader,
+ keyword );
+ if ( parser->root.error )
+ return parser->root.error;
+
+ cur = parser->root.cursor;
+ break;
+ }
+ }
+ keyword++;
+ }
+ }
+ }
+ }
+ }
+ }
+ return parser->root.error;
+ }
+
+
+ static
+ void t1_init_loader( Z1_Loader* loader,
+ T1_Face face )
+ {
+ FT_UNUSED( face );
+
+ MEM_Set( loader, 0, sizeof ( *loader ) );
+ loader->num_glyphs = 0;
+ loader->num_chars = 0;
+
+ /* initialize the tables -- simply set their `init' field to 0 */
+ loader->encoding_table.init = 0;
+ loader->charstrings.init = 0;
+ loader->glyph_names.init = 0;
+ loader->subrs.init = 0;
+ loader->fontdata = 0;
+ }
+
+
+ static
+ void t1_done_loader( Z1_Loader* loader )
+ {
+ Z1_Parser* parser = &loader->parser;
+
+
+ /* finalize tables */
+ Z1_Release_Table( &loader->encoding_table );
+ Z1_Release_Table( &loader->charstrings );
+ Z1_Release_Table( &loader->glyph_names );
+ Z1_Release_Table( &loader->subrs );
+
+ /* finalize parser */
+ Z1_Done_Parser( parser );
+ }
+
+
+ LOCAL_FUNC
+ FT_Error Z1_Open_Face( T1_Face face )
+ {
+ Z1_Loader loader;
+ Z1_Parser* parser;
+ T1_Font* type1 = &face->type1;
+ FT_Error error;
+
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+
+ t1_init_loader( &loader, face );
+
+ /* default lenIV */
+ type1->private_dict.lenIV = 4;
+
+ parser = &loader.parser;
+ error = Z1_New_Parser( parser,
+ face->root.stream,
+ face->root.memory,
+ psaux );
+ if ( error )
+ goto Exit;
+
+ error = parse_dict( face, &loader, parser->base_dict, parser->base_len );
+ if ( error )
+ goto Exit;
+
+ error = Z1_Get_Private_Dict( parser );
+ if ( error )
+ goto Exit;
+
+ error = parse_dict( face, &loader, parser->private_dict,
+ parser->private_len );
+ if ( error )
+ goto Exit;
+
+ /* now, propagate the subrs, charstrings, and glyphnames tables */
+ /* to the Type1 data */
+ type1->num_glyphs = loader.num_glyphs;
+
+ if ( !loader.subrs.init )
+ {
+ FT_ERROR(( "Z1_Open_Face: no subrs array in face!\n" ));
+ error = T1_Err_Invalid_File_Format;
+ }
+
+ if ( !loader.charstrings.init )
+ {
+ FT_ERROR(( "Z1_Open_Face: no charstrings array in face!\n" ));
+ error = T1_Err_Invalid_File_Format;
+ }
+
+ loader.subrs.init = 0;
+ type1->num_subrs = loader.num_subrs;
+ type1->subrs_block = loader.subrs.block;
+ type1->subrs = loader.subrs.elements;
+ type1->subrs_len = loader.subrs.lengths;
+
+ loader.charstrings.init = 0;
+ type1->charstrings_block = loader.charstrings.block;
+ type1->charstrings = loader.charstrings.elements;
+ type1->charstrings_len = loader.charstrings.lengths;
+
+ /* we copy the glyph names `block' and `elements' fields; */
+ /* the `lengths' field must be released later */
+ type1->glyph_names_block = loader.glyph_names.block;
+ type1->glyph_names = (FT_String**)loader.glyph_names.elements;
+ loader.glyph_names.block = 0;
+ loader.glyph_names.elements = 0;
+
+ /* we must now build type1.encoding when we have a custom */
+ /* array.. */
+ if ( type1->encoding_type == t1_encoding_array )
+ {
+ FT_Int charcode, index, min_char, max_char;
+ FT_Byte* char_name;
+ FT_Byte* glyph_name;
+
+
+ /* OK, we do the following: for each element in the encoding */
+ /* table, look up the index of the glyph having the same name */
+ /* the index is then stored in type1.encoding.char_index, and */
+ /* a the name to type1.encoding.char_name */
+
+ min_char = +32000;
+ max_char = -32000;
+
+ charcode = 0;
+ for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
+ {
+ type1->encoding.char_index[charcode] = 0;
+ type1->encoding.char_name [charcode] = (char *)".notdef";
+
+ char_name = loader.encoding_table.elements[charcode];
+ if ( char_name )
+ for ( index = 0; index < type1->num_glyphs; index++ )
+ {
+ glyph_name = (FT_Byte*)type1->glyph_names[index];
+ if ( strcmp( (const char*)char_name,
+ (const char*)glyph_name ) == 0 )
+ {
+ type1->encoding.char_index[charcode] = index;
+ type1->encoding.char_name [charcode] = (char*)glyph_name;
+
+ /* Change min/max encoded char only if glyph name is */
+ /* not /.notdef */
+ if ( strcmp( (const char*)".notdef",
+ (const char*)glyph_name ) != 0 )
+ {
+ if (charcode < min_char) min_char = charcode;
+ if (charcode > max_char) max_char = charcode;
+ }
+ break;
+ }
+ }
+ }
+ type1->encoding.code_first = min_char;
+ type1->encoding.code_last = max_char;
+ type1->encoding.num_chars = loader.num_chars;
+ }
+
+ Exit:
+ t1_done_loader( &loader );
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1load.h
@@ -1,0 +1,93 @@
+/***************************************************************************/
+/* */
+/* z1load.h */
+/* */
+/* Experimental Type 1 font loader (specification). */
+/* */
+/* 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 Z1LOAD_H
+#define Z1LOAD_H
+
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/psaux.h>
+#include <freetype/ftmm.h>
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1parse.h"
+
+#else
+
+#include <type1z/z1parse.h>
+
+#endif
+
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ typedef struct Z1_Loader_
+ {
+ Z1_Parser parser; /* parser used to read the stream */
+
+ FT_Int num_chars; /* number of characters in encoding */
+ PS_Table encoding_table; /* PS_Table used to store the */
+ /* encoding character names */
+
+ FT_Int num_glyphs;
+ PS_Table glyph_names;
+ PS_Table charstrings;
+
+ FT_Int num_subrs;
+ PS_Table subrs;
+ FT_Bool fontdata;
+
+ } Z1_Loader;
+
+
+ LOCAL_DEF
+ FT_Error Z1_Open_Face( T1_Face face );
+
+#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT
+
+ LOCAL_DEF
+ FT_Error Z1_Get_Multi_Master( T1_Face face,
+ FT_Multi_Master* master );
+
+ LOCAL_DEF
+ FT_Error Z1_Set_MM_Blend( T1_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
+
+ LOCAL_DEF
+ FT_Error Z1_Set_MM_Design( T1_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords );
+
+ LOCAL_DEF
+ void Z1_Done_Blend( T1_Face face );
+
+#endif /* !Z1_CONFIG_OPTION_NO_MM_SUPPORT */
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* Z1LOAD_H */
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1objs.c
@@ -1,0 +1,406 @@
+/***************************************************************************/
+/* */
+/* z1objs.c */
+/* */
+/* Experimental Type 1 objects manager (body). */
+/* */
+/* 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. */
+/* */
+/***************************************************************************/
+
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1gload.h"
+#include "z1load.h"
+#include "z1afm.h"
+
+#else
+
+#include <type1z/z1gload.h>
+#include <type1z/z1load.h>
+#include <type1z/z1afm.h>
+
+#endif
+
+
+#include <freetype/internal/psnames.h>
+#include <freetype/internal/psaux.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_z1objs
+
+
+ /*************************************************************************/
+ /* */
+ /* FACE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Z1_Done_Face */
+ /* */
+ /* <Description> */
+ /* The face object destructor. */
+ /* */
+ /* <Input> */
+ /* face :: A typeless pointer to the face object to destroy. */
+ /* */
+ LOCAL_FUNC
+ void Z1_Done_Face( T1_Face face )
+ {
+ FT_Memory memory;
+ T1_Font* type1 = &face->type1;
+
+
+ if ( face )
+ {
+ memory = face->root.memory;
+
+#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT
+ /* release multiple masters information */
+ Z1_Done_Blend( face );
+ face->blend = 0;
+#endif
+
+ /* release font info strings */
+ {
+ T1_FontInfo* info = &type1->font_info;
+
+
+ FREE( info->version );
+ FREE( info->notice );
+ FREE( info->full_name );
+ FREE( info->family_name );
+ FREE( info->weight );
+ }
+
+ /* release top dictionary */
+ FREE( type1->charstrings_len );
+ FREE( type1->charstrings );
+ FREE( type1->glyph_names );
+
+ FREE( type1->subrs );
+ FREE( type1->subrs_len );
+
+ FREE( type1->subrs_block );
+ FREE( type1->charstrings_block );
+ FREE( type1->glyph_names_block );
+
+ FREE( type1->encoding.char_index );
+ FREE( type1->font_name );
+
+#ifndef Z1_CONFIG_OPTION_NO_AFM
+ /* release afm data if present */
+ if ( face->afm_data )
+ Z1_Done_AFM( memory, (Z1_AFM*)face->afm_data );
+#endif
+
+ /* release unicode map, if any */
+ FREE( face->unicode_map.maps );
+ face->unicode_map.num_maps = 0;
+
+ face->root.family_name = 0;
+ face->root.style_name = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Z1_Init_Face */
+ /* */
+ /* <Description> */
+ /* The face object constructor. */
+ /* */
+ /* <Input> */
+ /* stream :: input stream where to load font data. */
+ /* */
+ /* face_index :: The index of the font face in the resource. */
+ /* */
+ /* num_params :: Number of additional generic parameters. Ignored. */
+ /* */
+ /* params :: Additional generic parameters. Ignored. */
+ /* */
+ /* <InOut> */
+ /* face :: The face record to build. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ LOCAL_FUNC
+ FT_Error Z1_Init_Face( FT_Stream stream,
+ T1_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ PSNames_Interface* psnames;
+ PSAux_Interface* psaux;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+ FT_UNUSED( stream );
+
+
+ face->root.num_faces = 1;
+
+ psnames = (PSNames_Interface*)face->psnames;
+ if ( !psnames )
+ {
+ psnames = (PSNames_Interface*)
+ FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), "psnames" );
+
+ face->psnames = psnames;
+ }
+
+ psaux = (PSAux_Interface*)face->psaux;
+ if ( !psaux )
+ {
+ psaux = (PSAux_Interface*)
+ FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), "psaux" );
+
+ face->psaux = psaux;
+ }
+
+ /* open the tokenizer, this will also check the font format */
+ error = Z1_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(( "Z1_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->type1.num_glyphs;
+ root->num_charmaps = 1;
+
+ root->face_index = face_index;
+ root->face_flags = FT_FACE_FLAG_SCALABLE;
+
+ root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+
+ root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
+
+ if ( face->type1.font_info.is_fixed_pitch )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ if ( face->blend )
+ root->face_flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
+
+ /* XXX: TODO -- add kerning with .afm support */
+
+ /* get style name -- be careful, some broken fonts only */
+ /* have a `/FontName' dictionary entry! */
+ root->family_name = face->type1.font_info.family_name;
+ if ( root->family_name )
+ {
+ char* full = face->type1.font_info.full_name;
+ char* family = root->family_name;
+
+
+ while ( *family && *full == *family )
+ {
+ family++;
+ full++;
+ }
+
+ root->style_name = ( *full == ' ' ? full + 1
+ : (char *)"Regular" );
+ }
+ else
+ {
+ /* do we have a `/FontName'? */
+ if ( face->type1.font_name )
+ {
+ root->family_name = face->type1.font_name;
+ root->style_name = (char *)"Regular";
+ }
+ }
+
+ /* no embedded bitmap support */
+ root->num_fixed_sizes = 0;
+ root->available_sizes = 0;
+
+ root->bbox = face->type1.font_bbox;
+ root->units_per_EM = 1000;
+ root->ascender = (FT_Short)face->type1.font_bbox.yMax;
+ root->descender = (FT_Short)face->type1.font_bbox.yMin;
+ root->height = ( ( root->ascender + root->descender ) * 12 ) / 10;
+
+ /* 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 = Z1_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;
+
+ root->underline_position = face->type1.font_info.underline_position;
+ root->underline_thickness = face->type1.font_info.underline_thickness;
+
+ root->max_points = 0;
+ root->max_contours = 0;
+ }
+
+ /* charmap support -- synthetize unicode charmap if possible */
+ {
+ FT_Face root = &face->root;
+ FT_CharMap charmap = face->charmaprecs;
+
+
+ /* synthesize a Unicode charmap if there is support in the `PSNames' */
+ /* module */
+ if ( 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 = FT_Err_Ok;
+ }
+ }
+
+ /* now, support either the standard, expert, or custom encoding */
+ charmap->face = (FT_Face)face;
+ charmap->platform_id = 7; /* a new platform id for Adobe fonts? */
+
+ switch ( face->type1.encoding_type )
+ {
+ case t1_encoding_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];
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Z1_Init_Driver */
+ /* */
+ /* <Description> */
+ /* Initializes a given Type 1 driver object. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ LOCAL_FUNC
+ FT_Error Z1_Init_Driver( Z1_Driver driver )
+ {
+ FT_UNUSED( driver );
+
+ return T1_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Z1_Done_Driver */
+ /* */
+ /* <Description> */
+ /* Finalizes a given Type 1 driver. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target Type 1 driver. */
+ /* */
+ LOCAL_DEF
+ void Z1_Done_Driver( Z1_Driver driver )
+ {
+ FT_UNUSED( driver );
+ }
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1objs.h
@@ -1,0 +1,161 @@
+/***************************************************************************/
+/* */
+/* z1objs.h */
+/* */
+/* Experimental Type 1 objects manager (specification). */
+/* */
+/* 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 Z1OBJS_H
+#define Z1OBJS_H
+
+#include <freetype/internal/ftobjs.h>
+#include <freetype/config/ftconfig.h>
+#include <freetype/internal/t1errors.h>
+#include <freetype/internal/t1types.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ /* The following structures must be defined by the hinter */
+ typedef struct Z1_Size_Hints_ Z1_Size_Hints;
+ typedef struct Z1_Glyph_Hints_ Z1_Glyph_Hints;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* Z1_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 driver object. */
+ /* */
+ typedef struct Z1_DriverRec_ *Z1_Driver;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* Z1_Size */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 size object. */
+ /* */
+ typedef struct Z1_SizeRec_* Z1_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* Z1_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 glyph slot object. */
+ /* */
+ typedef struct Z1_GlyphSlotRec_* Z1_GlyphSlot;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* Z1_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 Z1_CharMapRec_* Z1_CharMap;
+
+
+ /*************************************************************************/
+ /* */
+ /* HERE BEGINS THE TYPE1 SPECIFIC STUFF */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* Z1_SizeRec */
+ /* */
+ /* <Description> */
+ /* Type 1 size record. */
+ /* */
+ typedef struct Z1_SizeRec_
+ {
+ FT_SizeRec root;
+ FT_Bool valid;
+ Z1_Size_Hints* hints; /* defined in the hinter. This allows */
+ /* us to experiment with different */
+ /* hinting schemes without having to */
+ /* change `z1objs' each time. */
+ } Z1_SizeRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* Z1_GlyphSlotRec */
+ /* */
+ /* <Description> */
+ /* Type 1 glyph slot record. */
+ /* */
+ typedef struct Z1_GlyphSlotRec_
+ {
+ FT_GlyphSlotRec root;
+
+ FT_Bool hint;
+ FT_Bool scaled;
+
+ FT_Int max_points;
+ FT_Int max_contours;
+
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+
+ Z1_Glyph_Hints* hints; /* defined in the hinter */
+
+ } Z1_GlyphSlotRec;
+
+
+ LOCAL_DEF
+ FT_Error Z1_Init_Face( FT_Stream stream,
+ T1_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ LOCAL_DEF
+ void Z1_Done_Face( T1_Face face );
+
+ LOCAL_DEF
+ FT_Error Z1_Init_Driver( Z1_Driver driver );
+
+ LOCAL_DEF
+ void Z1_Done_Driver( Z1_Driver driver );
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* Z1OBJS_H */
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1parse.c
@@ -1,0 +1,487 @@
+/***************************************************************************/
+/* */
+/* z1parse.c */
+/* */
+/* Experimental Type 1 parser (body). */
+/* */
+/* 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 Type 1 parser is in charge of the following: */
+ /* */
+ /* - provide an implementation of a growing sequence of objects called */
+ /* a `Z1_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 `z1load.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 <freetype/internal/t1errors.h>
+#include <freetype/internal/psaux.h>
+
+#ifdef FT_FLAT_COMPILE
+
+#include "z1parse.h"
+
+#else
+
+#include <type1z/z1parse.h>
+
+#endif
+
+
+#include <string.h> /* for strncmp() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_z1parse
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** INPUT STREAM PARSER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define IS_Z1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
+#define IS_Z1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' )
+
+#define IS_Z1_SPACE( c ) ( IS_Z1_WHITESPACE( c ) || IS_Z1_LINESPACE( c ) )
+
+
+ typedef struct PFB_Tag_
+ {
+ FT_UShort tag;
+ FT_Long size;
+
+ } PFB_Tag;
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PFB_Tag
+
+
+ static
+ const FT_Frame_Field pfb_tag_fields[] =
+ {
+ FT_FRAME_START( 6 ),
+ FT_FRAME_USHORT ( tag ),
+ FT_FRAME_LONG_LE( size ),
+ FT_FRAME_END
+ };
+
+
+ static
+ FT_Error read_pfb_tag( FT_Stream stream,
+ FT_UShort* tag,
+ FT_Long* size )
+ {
+ FT_Error error;
+ PFB_Tag head;
+
+
+ *tag = 0;
+ *size = 0;
+ if ( !READ_Fields( pfb_tag_fields, &head ) )
+ {
+ if ( head.tag == 0x8001 || head.tag == 0x8002 )
+ {
+ *tag = head.tag;
+ *size = head.size;
+ }
+ }
+ return error;
+ }
+
+
+ LOCAL_FUNC
+ FT_Error Z1_New_Parser( Z1_Parser* parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Interface* psaux )
+ {
+ FT_Error error;
+ FT_UShort tag;
+ FT_Long size;
+
+
+ psaux->t1_parser_funcs->init( &parser->root,0, 0, memory );
+
+ parser->stream = stream;
+ parser->base_len = 0;
+ parser->base_dict = 0;
+ parser->private_len = 0;
+ parser->private_dict = 0;
+ parser->in_pfb = 0;
+ parser->in_memory = 0;
+ parser->single_block = 0;
+
+ /******************************************************************/
+ /* */
+ /* Here a short summary of what is going on: */
+ /* */
+ /* When creating a new Type 1 parser, we try to locate and load */
+ /* the base dictionary if this is possible (i.e. for PFB */
+ /* files). Otherwise, we load the whole font into memory. */
+ /* */
+ /* When `loading' the base dictionary, we only setup pointers */
+ /* in the case of a memory-based stream. Otherwise, we */
+ /* allocate and load the base dictionary in it. */
+ /* */
+ /* parser->in_pfb is set if we are in a binary (".pfb") font. */
+ /* parser->in_memory is set if we have a memory stream. */
+ /* */
+
+ /* try to compute the size of the base dictionary; */
+ /* look for a Postscript binary file tag, i.e 0x8001 */
+ if ( FILE_Seek( 0L ) )
+ goto Exit;
+
+ error = read_pfb_tag( stream, &tag, &size );
+ if ( error )
+ goto Exit;
+
+ if ( tag != 0x8001 )
+ {
+ /* assume that this is a PFA file for now; an error will */
+ /* be produced later when more things are checked */
+ if ( FILE_Seek( 0L ) )
+ goto Exit;
+ size = stream->size;
+ }
+ else
+ parser->in_pfb = 1;
+
+ /* now, try to load `size' bytes of the `base' dictionary we */
+ /* found previously */
+
+ /* if it is a memory-based resource, set up pointers */
+ if ( !stream->read )
+ {
+ parser->base_dict = (FT_Byte*)stream->base + stream->pos;
+ parser->base_len = size;
+ parser->in_memory = 1;
+
+ /* check that the `size' field is valid */
+ if ( FILE_Skip( size ) )
+ goto Exit;
+ }
+ else
+ {
+ /* read segment in memory */
+ if ( ALLOC( parser->base_dict, size ) ||
+ FILE_Read( parser->base_dict, size ) )
+ goto Exit;
+ parser->base_len = size;
+ }
+
+ /* Now check font format; we must see `%!PS-AdobeFont-1' */
+ /* or `%!FontType' */
+ {
+ if ( size <= 16 ||
+ ( strncmp( (const char*)parser->base_dict,
+ "%!PS-AdobeFont-1", 16 ) &&
+ strncmp( (const char*)parser->base_dict,
+ "%!FontType", 10 ) ) )
+ {
+ FT_TRACE2(( "[not a Type1 font]\n" ));
+ error = FT_Err_Unknown_File_Format;
+ }
+ else
+ {
+ parser->root.base = parser->base_dict;
+ parser->root.cursor = parser->base_dict;
+ parser->root.limit = parser->root.cursor + parser->base_len;
+ }
+ }
+
+ Exit:
+ if ( error && !parser->in_memory )
+ FREE( parser->base_dict );
+
+ return error;
+ }
+
+
+ LOCAL_FUNC
+ void Z1_Done_Parser( Z1_Parser* parser )
+ {
+ FT_Memory memory = parser->root.memory;
+
+
+ /* always free the private dictionary */
+ FREE( parser->private_dict );
+
+ /* free the base dictionary only when we have a disk stream */
+ if ( !parser->in_memory )
+ FREE( parser->base_dict );
+
+ parser->root.funcs.done( &parser->root );
+ }
+
+
+ /* 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;
+ }
+
+
+ LOCAL_FUNC
+ void Z1_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--;
+ }
+ }
+
+
+ LOCAL_FUNC
+ FT_Error Z1_Get_Private_Dict( Z1_Parser* parser )
+ {
+ FT_Stream stream = parser->stream;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error = 0;
+ FT_Long size;
+
+
+ if ( parser->in_pfb )
+ {
+ /* in the case of the PFB format, the private dictionary can be */
+ /* made of several segments. We thus first read the number of */
+ /* segments to compute the total size of the private dictionary */
+ /* then re-read them into memory. */
+ FT_Long start_pos = FILE_Pos();
+ FT_UShort tag;
+
+
+ parser->private_len = 0;
+ for (;;)
+ {
+ error = read_pfb_tag( stream, &tag, &size );
+ if ( error )
+ goto Fail;
+
+ if ( tag != 0x8002 )
+ break;
+
+ parser->private_len += size;
+
+ if ( FILE_Skip( size ) )
+ goto Fail;
+ }
+
+ /* Check that we have a private dictionary there */
+ /* and allocate private dictionary buffer */
+ if ( parser->private_len == 0 )
+ {
+ FT_ERROR(( "Z1_Get_Private_Dict:" ));
+ FT_ERROR(( " invalid private dictionary section\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ if ( FILE_Seek( start_pos ) ||
+ ALLOC( parser->private_dict, parser->private_len ) )
+ goto Fail;
+
+ parser->private_len = 0;
+ for (;;)
+ {
+ error = read_pfb_tag( stream, &tag, &size );
+ if ( error || tag != 0x8002 )
+ {
+ error = FT_Err_Ok;
+ break;
+ }
+
+ if ( FILE_Read( parser->private_dict + parser->private_len, size ) )
+ goto Fail;
+
+ parser->private_len += size;
+ }
+ }
+ else
+ {
+ /* we have already `loaded' the whole PFA font file into memory; */
+ /* if this is a memory resource, allocate a new block to hold */
+ /* the private dict. Otherwise, simply overwrite into the base */
+ /* dictionary block in the heap. */
+
+ /* first of all, look at the `eexec' keyword */
+ FT_Byte* cur = parser->base_dict;
+ FT_Byte* limit = cur + parser->base_len;
+ FT_Byte c;
+
+
+ for (;;)
+ {
+ c = cur[0];
+ if ( c == 'e' && cur + 9 < limit ) /* 9 = 5 letters for `eexec' + */
+ /* newline + 4 chars */
+ {
+ if ( cur[1] == 'e' && cur[2] == 'x' &&
+ cur[3] == 'e' && cur[4] == 'c' )
+ {
+ cur += 6; /* we skip the newling after the `eexec' */
+
+ /* XXX: Some fonts use DOS-linefeeds, i.e. \r\n; we need to */
+ /* skip the extra \n if we find it */
+ if ( cur[0] == '\n' )
+ cur++;
+
+ break;
+ }
+ }
+ cur++;
+ if ( cur >= limit )
+ {
+ FT_ERROR(( "Z1_Get_Private_Dict:" ));
+ FT_ERROR(( " could not find `eexec' keyword\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ }
+
+ /* now determine where to write the _encrypted_ binary private */
+ /* dictionary. We overwrite the base dictionary for disk-based */
+ /* resources and allocate a new block otherwise */
+
+ size = parser->base_len - ( cur - parser->base_dict);
+
+ if ( parser->in_memory )
+ {
+ /* note that we allocate one more byte to put a terminating `0' */
+ if ( ALLOC( parser->private_dict, size + 1 ) )
+ goto Fail;
+ parser->private_len = size;
+ }
+ else
+ {
+ parser->single_block = 1;
+ parser->private_dict = parser->base_dict;
+ parser->private_len = size;
+ parser->base_dict = 0;
+ parser->base_len = 0;
+ }
+
+ /* now determine whether the private dictionary is encoded in binary */
+ /* or hexadecimal ASCII format -- decode it accordingly */
+
+ /* we need to access the next 4 bytes (after the final \r following */
+ /* the `eexec' keyword); if they all are hexadecimal digits, then */
+ /* we have a case of ASCII storage */
+
+ if ( ( hexa_value( cur[0] ) | hexa_value( cur[1] ) |
+ hexa_value( cur[2] ) | hexa_value( cur[3] ) ) < 0 )
+
+ /* binary encoding -- `simply' copy the private dict */
+ MEM_Copy( parser->private_dict, cur, size );
+
+ else
+ {
+ /* ASCII hexadecimal encoding */
+
+ FT_Byte* write;
+ FT_Int count;
+
+
+ write = parser->private_dict;
+ count = 0;
+
+ for ( ;cur < limit; cur++ )
+ {
+ int hex1;
+
+
+ /* check for newline */
+ if ( cur[0] == '\r' || cur[0] == '\n' )
+ continue;
+
+ /* exit if we have a non-hexadecimal digit that isn't a newline */
+ hex1 = hexa_value( cur[0] );
+ if ( hex1 < 0 || cur + 1 >= limit )
+ break;
+
+ /* otherwise, store byte */
+ *write++ = ( hex1 << 4 ) | hexa_value( cur[1] );
+ count++;
+ cur++;
+ }
+
+ /* put a safeguard */
+ parser->private_len = write - parser->private_dict;
+ *write++ = 0;
+ }
+ }
+
+ /* we now decrypt the encoded binary private dictionary */
+ Z1_Decrypt( parser->private_dict, parser->private_len, 55665 );
+ parser->root.base = parser->private_dict;
+ parser->root.cursor = parser->private_dict;
+ parser->root.limit = parser->root.cursor + parser->private_len;
+
+ Fail:
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1parse.h
@@ -1,0 +1,140 @@
+/***************************************************************************/
+/* */
+/* z1parse.h */
+/* */
+/* Experimental Type 1 parser (specification). */
+/* */
+/* 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 Z1PARSE_H
+#define Z1PARSE_H
+
+#include <freetype/internal/t1types.h>
+#include <freetype/internal/ftstream.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* Z1_Parser */
+ /* */
+ /* <Description> */
+ /* A Z1_Parser is an object used to parse a Type 1 fonts very */
+ /* quickly. */
+ /* */
+ /* <Fields> */
+ /* root :: The root parser. */
+ /* */
+ /* stream :: The current input stream. */
+ /* */
+ /* base_dict :: A pointer to the top-level dictionary. */
+ /* */
+ /* base_len :: The length in bytes of the top dictionary. */
+ /* */
+ /* private_dict :: A pointer to the private dictionary. */
+ /* */
+ /* private_len :: The length in bytes of the private dictionary. */
+ /* */
+ /* in_pfb :: A boolean. Indicates that we are handling a PFB */
+ /* file. */
+ /* */
+ /* in_memory :: A boolean. Indicates a memory-based stream. */
+ /* */
+ /* single_block :: A boolean. Indicates that the private dictionary */
+ /* is stored in lieu of the base dictionary. */
+ /* */
+ typedef struct Z1_Parser_
+ {
+ T1_Parser root;
+ FT_Stream stream;
+
+ FT_Byte* base_dict;
+ FT_Int base_len;
+
+ FT_Byte* private_dict;
+ FT_Int private_len;
+
+ FT_Byte in_pfb;
+ FT_Byte in_memory;
+ FT_Byte single_block;
+
+ } Z1_Parser;
+
+
+#define Z1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
+#define Z1_Done_Table( p ) \
+ do \
+ { \
+ if ( (p)->funcs.done ) \
+ (p)->funcs.done( p ); \
+ } while ( 0 )
+#define Z1_Release_Table( p ) \
+ do \
+ { \
+ if ( (p)->funcs.release ) \
+ (p)->funcs.release( p ); \
+ } while ( 0 )
+
+
+#define Z1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
+#define Z1_Skip_Alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root )
+
+#define Z1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root )
+#define Z1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t )
+
+#define Z1_ToCoordArray( p, m, c ) \
+ (p)->root.funcs.to_coord_array( &(p)->root, m, c )
+#define Z1_ToFixedArray( p, m, f, t ) \
+ (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
+#define Z1_ToToken( p, t ) \
+ (p)->root.funcs.to_token( &(p)->root, t )
+#define Z1_ToTokenArray( p, t, m, c ) \
+ (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
+
+#define Z1_Load_Field( p, f, o, m, pf ) \
+ (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
+#define Z1_Load_Field_Table( p, f, o, m, pf ) \
+ (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
+
+
+ LOCAL_DEF
+ FT_Error Z1_New_Parser( Z1_Parser* parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Interface* psaux );
+
+ LOCAL_DEF
+ FT_Error Z1_Get_Private_Dict( Z1_Parser* parser );
+
+ LOCAL_DEF
+ void Z1_Decrypt( FT_Byte* buffer,
+ FT_Int length,
+ FT_UShort seed );
+
+ LOCAL_DEF
+ void Z1_Done_Parser( Z1_Parser* parser );
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif /* Z1PARSE_H */
+
+
+/* END */
--- /dev/null
+++ b/src/type1/z1tokens.h
@@ -1,0 +1,73 @@
+/***************************************************************************/
+/* */
+/* z1tokens.h */
+/* */
+/* Experimental Type 1 tokenizer (specification). */
+/* */
+/* 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. */
+/* */
+/***************************************************************************/
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_FontInfo
+#undef T1CODE
+#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_NUM ( "ItalicAngle", italic_angle )
+ T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch )
+ T1_FIELD_NUM ( "UnderlinePosition", underline_position )
+ T1_FIELD_NUM ( "UnderlineThickness", underline_thickness )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_Private
+#undef T1CODE
+#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 )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_Font
+#undef T1CODE
+#define T1CODE t1_field_font_dict
+
+ T1_FIELD_NUM( "PaintType", paint_type )
+ T1_FIELD_NUM( "FontType", font_type )
+ T1_FIELD_NUM( "StrokeWidth", stroke_width )
+
+
+/* END */
--- a/src/type1z/Readme.txt
+++ /dev/null
@@ -1,10 +1,0 @@
-This directory contains an experimental Type 1 driver that will ultimately
-replace the "official" one in "src/type1".
-
-This driver doesn't provide a mini Postscript interpreter, but uses
-pattern matching in order to load data from fonts. It works better and
-faster than the official driver, but will replace it only when we finish
-the auto-hinting module..
-
-You don't need to compile it to support Type 1 fonts, the driver should
-co-exist peacefully with the rest of the engine however..
--- a/src/type1z/module.mk
+++ /dev/null
@@ -1,22 +1,0 @@
-#
-# FreeType 2 Type1z module definition
-#
-
-
-# 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.
-
-
-make_module_list: add_type1_driver
-
-add_type1_driver:
- $(OPEN_DRIVER)t1_driver_class$(CLOSE_DRIVER)
- $(ECHO_DRIVER)type1 $(ECHO_DRIVER_DESC)Postscript font files with extension *.pfa or *.pfb$(ECHO_DRIVER_DONE)
-
-# EOF
--- a/src/type1z/rules.mk
+++ /dev/null
@@ -1,72 +1,0 @@
-#
-# FreeType 2 Type1z 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.
-
-
-# Type1z driver directory
-#
-T1Z_DIR := $(SRC_)type1z
-T1Z_DIR_ := $(T1Z_DIR)$(SEP)
-
-
-# compilation flags for the driver
-#
-T1Z_COMPILE := $(FT_COMPILE)
-
-
-# Type1 driver sources (i.e., C files)
-#
-T1Z_DRV_SRC := $(T1Z_DIR_)z1parse.c \
- $(T1Z_DIR_)z1load.c \
- $(T1Z_DIR_)z1driver.c \
- $(T1Z_DIR_)z1afm.c \
- $(T1Z_DIR_)z1gload.c \
- $(T1Z_DIR_)z1objs.c
-
-# Type1 driver headers
-#
-T1Z_DRV_H := $(T1Z_DRV_SRC:%.c=%.h) \
- $(T1Z_DIR_)z1tokens.h
-
-
-# Type1z driver object(s)
-#
-# T1Z_DRV_OBJ_M is used during `multi' builds
-# T1Z_DRV_OBJ_S is used during `single' builds
-#
-T1Z_DRV_OBJ_M := $(T1Z_DRV_SRC:$(T1Z_DIR_)%.c=$(OBJ_)%.$O)
-T1Z_DRV_OBJ_S := $(OBJ_)type1z.$O
-
-# Type1z driver source file for single build
-#
-T1Z_DRV_SRC_S := $(T1Z_DIR_)type1z.c
-
-
-# Type1z driver - single object
-#
-$(T1Z_DRV_OBJ_S): $(T1Z_DRV_SRC_S) $(T1Z_DRV_SRC) $(FREETYPE_H) $(T1Z_DRV_H)
- $(T1Z_COMPILE) $T$@ $(T1Z_DRV_SRC_S)
-
-
-# Type1z driver - multiple objects
-#
-$(OBJ_)%.$O: $(T1Z_DIR_)%.c $(FREETYPE_H) $(T1Z_DRV_H)
- $(T1Z_COMPILE) $T$@ $<
-
-
-# update main driver object lists
-#
-DRV_OBJS_S += $(T1Z_DRV_OBJ_S)
-DRV_OBJS_M += $(T1Z_DRV_OBJ_M)
-
-# EOF
--- a/src/type1z/type1z.c
+++ /dev/null
@@ -1,49 +1,0 @@
-/***************************************************************************/
-/* */
-/* type1z.c */
-/* */
-/* FreeType experimental Type 1 driver component (body only). */
-/* */
-/* 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. */
-/* */
-/***************************************************************************/
-
-
-#define FT_MAKE_OPTION_SINGLE_OBJECT
-
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1parse.c"
-#include "z1load.c"
-#include "z1objs.c"
-#include "z1driver.c"
-#include "z1gload.c"
-
-#ifndef Z1_CONFIG_OPTION_NO_AFM
-#include "z1afm.c"
-#endif
-
-#else /* FT_FLAT_COMPILE */
-
-#include <type1z/z1parse.c>
-#include <type1z/z1load.c>
-#include <type1z/z1objs.c>
-#include <type1z/z1driver.c>
-#include <type1z/z1gload.c>
-
-#ifndef Z1_CONFIG_OPTION_NO_AFM
-#include <type1z/z1afm.c>
-#endif
-
-#endif /* FT_FLAT_COMPILE */
-
-
-/* END */
--- a/src/type1z/z1afm.c
+++ /dev/null
@@ -1,293 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1afm.c */
-/* */
-/* AFM support for Type 1 fonts (body). */
-/* */
-/* 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. */
-/* */
-/***************************************************************************/
-
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1afm.h"
-
-#else
-
-#include <type1z/z1afm.h>
-
-#endif
-
-
-#include <freetype/internal/ftstream.h>
-#include <freetype/internal/t1types.h>
-
-#include <stdlib.h> /* for qsort() */
-#include <string.h> /* for strcmp() */
-#include <ctype.h> /* for isalnum() */
-
-
- /*************************************************************************/
- /* */
- /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
- /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
- /* messages during execution. */
- /* */
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_z1afm
-
-
- LOCAL_FUNC
- void Z1_Done_AFM( FT_Memory memory,
- Z1_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 ) ( isalnum( c ) || \
- 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 && !isdigit( *p ) )
- {
- sign = 1;
- if ( *p == '-' )
- sign = -1;
-
- p++;
- }
-
- while ( p < limit && isdigit( *p ) )
- {
- 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 */
- LOCAL_FUNC_X
- int compare_kern_pairs( const void* a,
- const void* b )
- {
- Z1_Kern_Pair* pair1 = (Z1_Kern_Pair*)a;
- Z1_Kern_Pair* pair2 = (Z1_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 Z1_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;
- Z1_Kern_Pair* pair;
- T1_Font* type1 = &((T1_Face)t1_face)->type1;
- Z1_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, Z1_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 ( Z1_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 Z1_Get_Kerning( Z1_AFM* afm,
- FT_UInt glyph1,
- FT_UInt glyph2,
- FT_Vector* kerning )
- {
- Z1_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;
- }
-
-
-/* END */
--- a/src/type1z/z1afm.h
+++ /dev/null
@@ -1,79 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1afm.h */
-/* */
-/* AFM support for Type 1 fonts (specification). */
-/* */
-/* 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 Z1AFM_H
-#define Z1AFM_H
-
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1objs.h"
-
-#else
-
-#include <type1z/z1objs.h>
-
-#endif
-
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-
- typedef struct Z1_Kern_Pair_
- {
- FT_UInt glyph1;
- FT_UInt glyph2;
- FT_Vector kerning;
-
- } Z1_Kern_Pair;
-
-
- typedef struct Z1_AFM_
- {
- FT_Int num_pairs;
- Z1_Kern_Pair* kern_pairs;
-
- } Z1_AFM;
-
-
- LOCAL_DEF
- FT_Error Z1_Read_AFM( FT_Face face,
- FT_Stream stream );
-
- LOCAL_DEF
- void Z1_Done_AFM( FT_Memory memory,
- Z1_AFM* afm );
-
- LOCAL_DEF
- void Z1_Get_Kerning( Z1_AFM* afm,
- FT_UInt glyph1,
- FT_UInt glyph2,
- FT_Vector* kerning );
-
-
-#ifdef __cplusplus
- }
-#endif
-
-
-#endif /* Z1AFM_H */
-
-
-/* END */
--- a/src/type1z/z1driver.c
+++ /dev/null
@@ -1,340 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1driver.c */
-/* */
-/* Experimental Type 1 driver interface (body). */
-/* */
-/* 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. */
-/* */
-/***************************************************************************/
-
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1driver.h"
-#include "z1gload.h"
-#include "z1load.h"
-#include "z1afm.h"
-
-#else
-
-#include <type1z/z1driver.h>
-#include <type1z/z1gload.h>
-#include <type1z/z1load.h>
-#include <type1z/z1afm.h>
-
-#endif
-
-
-#include <freetype/internal/ftdebug.h>
-#include <freetype/internal/ftstream.h>
-#include <freetype/internal/psnames.h>
-
-#include <string.h> /* for strcmp() */
-
-
- /*************************************************************************/
- /* */
- /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
- /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
- /* messages during execution. */
- /* */
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_z1driver
-
-
- static
- FT_Error get_z1_glyph_name( T1_Face face,
- FT_UInt glyph_index,
- FT_Pointer buffer,
- FT_UInt buffer_max )
- {
- FT_String* gname;
-
-
- gname = face->type1.glyph_names[glyph_index];
-
- if ( buffer_max > 0 )
- {
- FT_UInt len = strlen( gname );
-
-
- if (len >= buffer_max)
- len = buffer_max - 1;
-
- MEM_Copy( buffer, gname, len );
- ((FT_Byte*)buffer)[len] = 0;
- }
-
- return T1_Err_Ok;
- }
-
-
- /*************************************************************************/
- /* */
- /* <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
- FT_Module_Interface Get_Interface( FT_Driver driver,
- const FT_String* interface )
- {
- FT_UNUSED( driver );
- FT_UNUSED( interface );
-
- if ( strcmp( (const char*)interface, "glyph_name" ) == 0 )
- return (FT_Module_Interface)get_z1_glyph_name;
-
-#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT
- if ( strcmp( (const char*)interface, "get_mm" ) == 0 )
- return (FT_Module_Interface)Z1_Get_Multi_Master;
-
- if ( strcmp( (const char*)interface, "set_mm_design") == 0 )
- return (FT_Module_Interface)Z1_Set_MM_Design;
-
- if ( strcmp( (const char*)interface, "set_mm_blend") == 0 )
- return (FT_Module_Interface)Z1_Set_MM_Blend;
-#endif
- return 0;
- }
-
-
-#ifndef Z1_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,
- FT_Vector* kerning )
- {
- Z1_AFM* afm;
-
-
- kerning->x = 0;
- kerning->y = 0;
-
- afm = (Z1_AFM*)face->afm_data;
- if ( afm )
- Z1_Get_Kerning( afm, left_glyph, right_glyph, kerning );
-
- return T1_Err_Ok;
- }
-
-
-#endif /* T1_CONFIG_OPTION_NO_AFM */
-
-
- /*************************************************************************/
- /* */
- /* <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 if the Unicode charcode has */
- /* no corresponding glyph */
- if ( result == 0xFFFF )
- result = 0;
- goto Exit;
-
- /*******************************************************************/
- /* */
- /* Custom Type 1 encoding */
- /* */
- case ft_encoding_adobe_custom:
- {
- T1_Encoding* encoding = &face->type1.encoding;
-
-
- if ( charcode >= encoding->code_first &&
- charcode <= encoding->code_last )
- result = encoding->char_index[charcode];
- goto Exit;
- }
-
- /*******************************************************************/
- /* */
- /* Adobe Standard & Expert encoding support */
- /* */
- default:
- if ( charcode < 256 )
- {
- FT_UInt code;
- FT_Int n;
- const char* glyph_name;
-
-
- code = psnames->adobe_std_encoding[charcode];
- if ( charmap->encoding == ft_encoding_adobe_expert )
- code = psnames->adobe_expert_encoding[charcode];
-
- glyph_name = psnames->adobe_std_strings( code );
- if ( !glyph_name )
- break;
-
- for ( n = 0; n < face->type1.num_glyphs; n++ )
- {
- const char* gname = face->type1.glyph_names[n];
-
-
- if ( gname && gname[0] == glyph_name[0] &&
- strcmp( gname, glyph_name ) == 0 )
- {
- result = n;
- break;
- }
- }
- }
- }
- Exit:
- return result;
- }
-
-
- FT_CPLUSPLUS( const FT_Driver_Class ) t1_driver_class =
- {
- {
- ft_module_font_driver | ft_module_driver_scalable,
- sizeof( FT_DriverRec ),
-
- "type1",
- 0x10000L,
- 0x20000L,
-
- 0, /* format interface */
-
- (FT_Module_Constructor)Z1_Init_Driver,
- (FT_Module_Destructor) Z1_Done_Driver,
- (FT_Module_Requester) Get_Interface,
- },
-
- sizeof( T1_FaceRec ),
- sizeof( Z1_SizeRec ),
- sizeof( Z1_GlyphSlotRec ),
-
- (FTDriver_initFace) Z1_Init_Face,
- (FTDriver_doneFace) Z1_Done_Face,
- (FTDriver_initSize) 0,
- (FTDriver_doneSize) 0,
- (FTDriver_initGlyphSlot)0,
- (FTDriver_doneGlyphSlot)0,
-
- (FTDriver_setCharSizes) 0,
- (FTDriver_setPixelSizes)0,
- (FTDriver_loadGlyph) Z1_Load_Glyph,
- (FTDriver_getCharIndex) Get_Char_Index,
-
-#ifdef Z1_CONFIG_OPTION_NO_AFM
- (FTDriver_getKerning) 0,
- (FTDriver_attachFile) 0,
-#else
- (FTDriver_getKerning) Get_Kerning,
- (FTDriver_attachFile) Z1_Read_AFM,
-#endif
- (FTDriver_getAdvances) 0
- };
-
-
-#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
-
- EXPORT_FUNC( const FT_Driver_Class* ) getDriverClass( void )
- {
- return &t1z_driver_class;
- }
-
-#endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */
-
-
-/* END */
--- a/src/type1z/z1driver.h
+++ /dev/null
@@ -1,39 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1driver.h */
-/* */
-/* High-level experimental Type 1 driver interface (specification). */
-/* */
-/* 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 Z1DRIVER_H
-#define Z1DRIVER_H
-
-#include <freetype/internal/ftdriver.h>
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-
- FT_EXPORT_VAR( const FT_Driver_Class ) t1_driver_class;
-
-#ifdef __cplusplus
- }
-#endif
-
-
-#endif /* Z1DRIVER_H */
-
-
-/* END */
--- a/src/type1z/z1gload.c
+++ /dev/null
@@ -1,309 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1gload.c */
-/* */
-/* Experimental Type 1 Glyph Loader (body). */
-/* */
-/* 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. */
-/* */
-/***************************************************************************/
-
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1gload.h"
-
-#else
-
-#include <type1z/z1gload.h>
-
-#endif
-
-
-#include <freetype/internal/ftdebug.h>
-#include <freetype/internal/ftstream.h>
-#include <freetype/ftoutln.h>
-#include <freetype/internal/psaux.h>
-
-
-#include <string.h> /* for strcmp() */
-
-
- /*************************************************************************/
- /* */
- /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
- /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
- /* messages during execution. */
- /* */
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_z1gload
-
-
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /********** *********/
- /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
- /********** *********/
- /********** The following code is in charge of computing *********/
- /********** the maximum advance width of the font. It *********/
- /********** quickly processes each glyph charstring to *********/
- /********** extract the value from either a `sbw' or `seac' *********/
- /********** operator. *********/
- /********** *********/
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
-
-
- LOCAL_FUNC_X
- FT_Error Z1_Parse_Glyph( T1_Decoder* decoder,
- FT_UInt glyph_index )
- {
- T1_Face face = (T1_Face)decoder->builder.face;
- T1_Font* type1 = &face->type1;
-
-
- decoder->font_matrix = type1->font_matrix;
- decoder->font_offset = type1->font_offset;
-
- return decoder->funcs.parse_charstrings(
- decoder,
- type1->charstrings [glyph_index],
- type1->charstrings_len[glyph_index] );
- }
-
-
- LOCAL_FUNC
- FT_Error Z1_Compute_Max_Advance( T1_Face face,
- FT_Int* max_advance )
- {
- FT_Error error;
- T1_Decoder decoder;
- FT_Int glyph_index;
- T1_Font* type1 = &face->type1;
- PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
-
-
- *max_advance = 0;
-
- /* initialize load decoder */
- error = psaux->t1_decoder_funcs->init( &decoder,
- (FT_Face)face,
- 0, /* size */
- 0, /* glyph slot */
- (FT_Byte**)type1->glyph_names,
- face->blend,
- Z1_Parse_Glyph );
- if ( error )
- return error;
-
- decoder.builder.metrics_only = 1;
- decoder.builder.load_points = 0;
-
- decoder.num_subrs = type1->num_subrs;
- decoder.subrs = type1->subrs;
- decoder.subrs_len = type1->subrs_len;
-
- /* for each glyph, parse the glyph charstring and extract */
- /* the advance width */
- for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ )
- {
- /* now get load the unscaled outline */
- error = Z1_Parse_Glyph( &decoder, glyph_index );
- /* ignore the error if one occured - skip to next glyph */
- }
-
- *max_advance = decoder.builder.advance.x;
- return FT_Err_Ok;
- }
-
-
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /********** *********/
- /********** 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. *********/
- /********** *********/
- /********** The Type 1 hinter is located in `t1hint.c' *********/
- /********** *********/
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
-
-
- LOCAL_FUNC
- FT_Error Z1_Load_Glyph( Z1_GlyphSlot glyph,
- Z1_Size size,
- FT_Int glyph_index,
- FT_Int load_flags )
- {
- FT_Error error;
- T1_Decoder decoder;
- T1_Face face = (T1_Face)glyph->root.face;
- FT_Bool hinting;
- T1_Font* type1 = &face->type1;
- PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
- const T1_Decoder_Funcs* decoder_funcs = psaux->t1_decoder_funcs;
-
- FT_Matrix font_matrix;
- FT_Vector font_offset;
-
- 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_outline;
-
- error = decoder_funcs->init( &decoder,
- (FT_Face)face,
- (FT_Size)size,
- (FT_GlyphSlot)glyph,
- (FT_Byte**)type1->glyph_names,
- face->blend,
- Z1_Parse_Glyph );
- if ( error )
- goto Exit;
-
- decoder.builder.no_recurse = ( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
-
- decoder.num_subrs = type1->num_subrs;
- decoder.subrs = type1->subrs;
- decoder.subrs_len = type1->subrs_len;
-
-
- /* now load the unscaled outline */
- error = Z1_Parse_Glyph( &decoder, glyph_index );
- if ( error )
- goto Exit;
-
- font_matrix = decoder.font_matrix;
- font_offset = decoder.font_offset;
-
- /* save new glyph tables */
- decoder_funcs->done( &decoder );
-
- /* 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 )
- {
- glyph->root.outline.flags &= ft_outline_owner;
- glyph->root.outline.flags |= ft_outline_reverse_fill;
-
- /* for composite glyphs, return only left side bearing and */
- /* 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;
- glyph->root.linearHoriAdvance = decoder.builder.advance.x;
-
- /* make up vertical metrics */
- metrics->vertBearingX = 0;
- metrics->vertBearingY = 0;
- metrics->vertAdvance = 0;
-
- glyph->root.linearVertAdvance = 0;
-
- glyph->root.format = ft_glyph_format_outline;
-
- if ( size && size->root.metrics.y_ppem < 24 )
- glyph->root.outline.flags |= ft_outline_high_precision;
-
- /* apply the font matrix */
- FT_Outline_Transform( &glyph->root.outline, &font_matrix );
-
- FT_Outline_Translate( &glyph->root.outline,
- font_offset.x,
- font_offset.y );
-
-#if 0
-
- glyph->root.outline.second_pass = TRUE;
- glyph->root.outline.high_precision = size->root.metrics.y_ppem < 24;
- glyph->root.outline.dropout_mode = 2;
-
-#endif /* 0 */
-
- if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
- {
- /* scale the outline and the metrics */
- FT_Int n;
- FT_Outline* cur = decoder.builder.base;
- FT_Vector* vec = cur->points;
- FT_Fixed x_scale = glyph->x_scale;
- FT_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->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
-
- metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
- metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
- }
-
- /* 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;
- }
- }
-
- Exit:
- return error;
- }
-
-
-/* END */
--- a/src/type1z/z1gload.h
+++ /dev/null
@@ -1,58 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1gload.h */
-/* */
-/* Experimental Type 1 Glyph Loader (specification). */
-/* */
-/* 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 Z1GLOAD_H
-#define Z1GLOAD_H
-
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1objs.h"
-
-#else
-
-#include <type1z/z1objs.h>
-
-#endif
-
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-
- LOCAL_DEF
- FT_Error Z1_Compute_Max_Advance( T1_Face face,
- FT_Int* max_advance );
-
- LOCAL_DEF
- FT_Error Z1_Load_Glyph( Z1_GlyphSlot glyph,
- Z1_Size size,
- FT_Int glyph_index,
- FT_Int load_flags );
-
-
-#ifdef __cplusplus
- }
-#endif
-
-
-#endif /* Z1GLOAD_H */
-
-
-/* END */
--- a/src/type1z/z1load.c
+++ /dev/null
@@ -1,1702 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1load.c */
-/* */
-/* Experimental Type 1 font loader (body). */
-/* */
-/* Copyright 1996-2000 by */
-/* David Turner, Robert Wilhelm, and Werner Lemberg. */
-/* */
-/* This file is part of the FreeType project, and may only be used, */
-/* modified, and distributed under the terms of the FreeType project */
-/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
-/* this file you indicate that you have read the license and */
-/* understand and accept it fully. */
-/* */
-/***************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* This is the new and improved Type 1 data loader for FreeType 2. The */
- /* old loader has several problems: it is slow, complex, difficult to */
- /* maintain, and contains incredible hacks to make it accept some */
- /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */
- /* the Type 1 fonts on my machine still aren't loaded correctly by it. */
- /* */
- /* This version is much simpler, much faster and also easier to read and */
- /* maintain by a great order of magnitude. The idea behind it is to */
- /* _not_ try to read the Type 1 token stream with a state machine (i.e. */
- /* a Postscript-like interpreter) but rather to perform simple pattern */
- /* matching. */
- /* */
- /* Indeed, nearly all data definitions follow a simple pattern like */
- /* */
- /* ... /Field <data> ... */
- /* */
- /* where <data> can be a number, a boolean, a string, or an array of */
- /* numbers. There are a few exceptions, namely the encoding, font name, */
- /* charstrings, and subrs; they are handled with a special pattern */
- /* matching routine. */
- /* */
- /* All other common cases are handled very simply. The matching rules */
- /* are defined in the file `t1tokens.h' through the use of several */
- /* macros calls PARSE_XXX. */
- /* */
- /* This file is included twice here; the first time to generate parsing */
- /* callback functions, the second to generate a table of keywords (with */
- /* pointers to the associated callback). */
- /* */
- /* The function `parse_dict' simply scans *linearly* a given dictionary */
- /* (either the top-level or private one) and calls the appropriate */
- /* callback when it encounters an immediate keyword. */
- /* */
- /* This is by far the fastest way one can find to parse and read all */
- /* data. */
- /* */
- /* This led to tremendous code size reduction. Note that later, the */
- /* glyph loader will also be _greatly_ simplified, and the automatic */
- /* hinter will replace the clumsy `t1hinter'. */
- /* */
- /*************************************************************************/
-
-
-#include <freetype/internal/ftdebug.h>
-#include <freetype/config/ftconfig.h>
-#include <freetype/ftmm.h>
-
-#include <freetype/internal/t1types.h>
-#include <freetype/internal/t1errors.h>
-
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1load.h"
-
-#else
-
-#include <type1z/z1load.h>
-
-#endif
-
-
-#include <string.h> /* for strncmp(), strcmp() */
-#include <ctype.h> /* for isalnum() */
-
-
- /*************************************************************************/
- /* */
- /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
- /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
- /* messages during execution. */
- /* */
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_z1load
-
-
-#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** MULTIPLE MASTERS SUPPORT *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
- static
- FT_Error t1_allocate_blend( T1_Face face,
- FT_UInt num_designs,
- FT_UInt num_axis )
- {
- T1_Blend* blend;
- FT_Memory memory = face->root.memory;
- FT_Error error = 0;
-
-
- blend = face->blend;
- if ( !blend )
- {
- if ( ALLOC( blend, sizeof ( *blend ) ) )
- goto Exit;
-
- face->blend = blend;
- }
-
- /* allocate design data if needed */
- if ( num_designs > 0 )
- {
- if ( blend->num_designs == 0 )
- {
- FT_UInt nn;
-
-
- /* allocate the blend `private' and `font_info' dictionaries */
- if ( ALLOC_ARRAY( blend->font_infos[1], num_designs, T1_FontInfo ) ||
- ALLOC_ARRAY( blend->privates[1], num_designs, T1_Private ) ||
- ALLOC_ARRAY( blend->weight_vector, num_designs * 2, FT_Fixed ) )
- goto Exit;
-
- blend->default_weight_vector = blend->weight_vector + num_designs;
-
- blend->font_infos[0] = &face->type1.font_info;
- blend->privates [0] = &face->type1.private_dict;
-
- for ( nn = 2; nn <= num_designs; nn++ )
- {
- blend->privates[nn] = blend->privates [nn - 1] + 1;
- blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
- }
-
- blend->num_designs = num_designs;
- }
- else if ( blend->num_designs != num_designs )
- goto Fail;
- }
-
- /* allocate axis data if needed */
- if ( num_axis > 0 )
- {
- if ( blend->num_axis != 0 && blend->num_axis != num_axis )
- goto Fail;
-
- blend->num_axis = num_axis;
- }
-
- /* allocate the blend design pos table if needed */
- num_designs = blend->num_designs;
- num_axis = blend->num_axis;
- if ( num_designs && num_axis && blend->design_pos[0] == 0 )
- {
- FT_UInt n;
-
-
- if ( ALLOC_ARRAY( blend->design_pos[0],
- num_designs * num_axis, FT_Fixed ) )
- goto Exit;
-
- for ( n = 1; n < num_designs; n++ )
- blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
- }
-
- Exit:
- return error;
-
- Fail:
- error = -1;
- goto Exit;
- }
-
-
- LOCAL_FUNC
- FT_Error Z1_Get_Multi_Master( T1_Face face,
- FT_Multi_Master* master )
- {
- T1_Blend* blend = face->blend;
- FT_UInt n;
- FT_Error error;
-
-
- error = T1_Err_Invalid_Argument;
-
- if ( blend )
- {
- master->num_axis = blend->num_axis;
- master->num_designs = blend->num_designs;
-
- for ( n = 0; n < blend->num_axis; n++ )
- {
- FT_MM_Axis* axis = master->axis + n;
- T1_DesignMap* map = blend->design_map + n;
-
-
- axis->name = blend->axis_names[n];
- axis->minimum = map->design_points[0];
- axis->maximum = map->design_points[map->num_points - 1];
- }
- error = 0;
- }
- return error;
- }
-
-
- LOCAL_FUNC
- FT_Error Z1_Set_MM_Blend( T1_Face face,
- FT_UInt num_coords,
- FT_Fixed* coords )
- {
- T1_Blend* blend = face->blend;
- FT_Error error;
- FT_UInt n, m;
-
-
- error = T1_Err_Invalid_Argument;
-
- if ( blend && blend->num_axis == num_coords )
- {
- /* recompute the weight vector from the blend coordinates */
- error = FT_Err_Ok;
-
- for ( n = 0; n < blend->num_designs; n++ )
- {
- FT_Fixed result = 0x10000L; /* 1.0 fixed */
-
-
- for ( m = 0; m < blend->num_axis; m++ )
- {
- FT_Fixed factor;
-
-
- /* get current blend axis position */
- factor = coords[m];
- if ( factor < 0 ) factor = 0;
- if ( factor > 0x10000L ) factor = 0x10000L;
-
- if ( ( n & ( 1 << m ) ) == 0 )
- factor = 0x10000L - factor;
-
- result = FT_MulFix( result, factor );
- }
- blend->weight_vector[n] = result;
- }
-
- error = FT_Err_Ok;
- }
- return error;
- }
-
-
- LOCAL_FUNC
- FT_Error Z1_Set_MM_Design( T1_Face face,
- FT_UInt num_coords,
- FT_Long* coords )
- {
- T1_Blend* blend = face->blend;
- FT_Error error;
- FT_UInt n, p;
-
-
- error = T1_Err_Invalid_Argument;
- if ( blend && blend->num_axis == num_coords )
- {
- /* compute the blend coordinates through the blend design map */
- FT_Fixed final_blends[T1_MAX_MM_DESIGNS];
-
-
- for ( n = 0; n < blend->num_axis; n++ )
- {
- FT_Long design = coords[n];
- FT_Fixed the_blend;
- T1_DesignMap* map = blend->design_map + n;
- FT_Fixed* designs = map->design_points;
- FT_Fixed* blends = map->blend_points;
- FT_Int before = -1, after = -1;
-
- for ( p = 0; p < map->num_points; p++ )
- {
- FT_Fixed p_design = designs[p];
-
-
- /* exact match ? */
- if ( design == p_design )
- {
- the_blend = blends[p];
- goto Found;
- }
-
- if ( design < p_design )
- {
- after = p;
- break;
- }
-
- before = p;
- }
-
- /* now, interpolate if needed */
- if ( before < 0 )
- the_blend = blends[0];
-
- else if ( after < 0 )
- the_blend = blends[map->num_points - 1];
-
- else
- the_blend = FT_MulDiv( design - designs[before],
- blends [after] - blends [before],
- designs[after] - designs[before] );
-
- Found:
- final_blends[n] = the_blend;
- }
-
- error = Z1_Set_MM_Blend( face, num_coords, final_blends );
- }
-
- return error;
- }
-
-
- LOCAL_FUNC
- void Z1_Done_Blend( T1_Face face )
- {
- FT_Memory memory = face->root.memory;
- T1_Blend* blend = face->blend;
-
-
- if ( blend )
- {
- FT_UInt num_designs = blend->num_designs;
- FT_UInt num_axis = blend->num_axis;
- FT_UInt n;
-
-
- /* release design pos table */
- FREE( blend->design_pos[0] );
- for ( n = 1; n < num_designs; n++ )
- blend->design_pos[n] = 0;
-
- /* release blend `private' and `font info' dictionaries */
- FREE( blend->privates[1] );
- FREE( blend->font_infos[1] );
-
- for ( n = 0; n < num_designs; n++ )
- {
- blend->privates [n] = 0;
- blend->font_infos[n] = 0;
- }
-
- /* release weight vectors */
- FREE( blend->weight_vector );
- blend->default_weight_vector = 0;
-
- /* release axis names */
- for ( n = 0; n < num_axis; n++ )
- FREE( blend->axis_names[n] );
-
- /* release design map */
- for ( n = 0; n < num_axis; n++ )
- {
- T1_DesignMap* dmap = blend->design_map + n;
-
-
- FREE( dmap->design_points );
- dmap->num_points = 0;
- }
-
- FREE( face->blend );
- }
- }
-
-
- static
- void parse_blend_axis_types( T1_Face face,
- Z1_Loader* loader )
- {
- T1_Token axis_tokens[ T1_MAX_MM_AXIS ];
- FT_Int n, num_axis;
- FT_Error error = 0;
- T1_Blend* blend;
- FT_Memory memory;
-
-
- /* take an array of objects */
- Z1_ToTokenArray( &loader->parser, axis_tokens,
- T1_MAX_MM_AXIS, &num_axis );
- if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
- {
- FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
- num_axis ));
- error = T1_Err_Invalid_File_Format;
- goto Exit;
- }
-
- /* allocate blend if necessary */
- error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
- if ( error )
- goto Exit;
-
- blend = face->blend;
- memory = face->root.memory;
-
- /* each token is an immediate containing the name of the axis */
- for ( n = 0; n < num_axis; n++ )
- {
- T1_Token* token = axis_tokens + n;
- FT_Byte* name;
- FT_Int len;
-
- /* skip first slash, if any */
- if (token->start[0] == '/')
- token->start++;
-
- len = token->limit - token->start;
- if ( len <= 0 )
- {
- error = T1_Err_Invalid_File_Format;
- goto Exit;
- }
-
- if ( ALLOC( blend->axis_names[n], len + 1 ) )
- goto Exit;
-
- name = (FT_Byte*)blend->axis_names[n];
- MEM_Copy( name, token->start, len );
- name[len] = 0;
- }
-
- Exit:
- loader->parser.root.error = error;
- }
-
-
- static
- void parse_blend_design_positions( T1_Face face,
- Z1_Loader* loader )
- {
- T1_Token design_tokens[ T1_MAX_MM_DESIGNS ];
- FT_Int num_designs;
- FT_Int num_axis;
- Z1_Parser* parser = &loader->parser;
-
- FT_Error error = 0;
- T1_Blend* blend;
-
-
- /* get the array of design tokens - compute number of designs */
- Z1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs );
- if ( num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS )
- {
- FT_ERROR(( "parse_blend_design_positions:" ));
- FT_ERROR(( " incorrect number of designs: %d\n",
- num_designs ));
- error = T1_Err_Invalid_File_Format;
- goto Exit;
- }
-
- {
- FT_Byte* old_cursor = parser->root.cursor;
- FT_Byte* old_limit = parser->root.limit;
- FT_UInt n;
-
-
- blend = face->blend;
- num_axis = 0; /* make compiler happy */
-
- for ( n = 0; n < (FT_UInt)num_designs; n++ )
- {
- T1_Token axis_tokens[ T1_MAX_MM_DESIGNS ];
- T1_Token* token;
- FT_Int axis, n_axis;
-
-
- /* read axis/coordinates tokens */
- token = design_tokens + n;
- parser->root.cursor = token->start - 1;
- parser->root.limit = token->limit + 1;
- Z1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
-
- if ( n == 0 )
- {
- num_axis = n_axis;
- error = t1_allocate_blend( face, num_designs, num_axis );
- if ( error )
- goto Exit;
- blend = face->blend;
- }
- else if ( n_axis != num_axis )
- {
- FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
- error = T1_Err_Invalid_File_Format;
- goto Exit;
- }
-
- /* now, read each axis token into the design position */
- for ( axis = 0; axis < n_axis; axis++ )
- {
- T1_Token* token2 = axis_tokens + axis;
-
-
- parser->root.cursor = token2->start;
- parser->root.limit = token2->limit;
- blend->design_pos[n][axis] = Z1_ToFixed( parser, 0 );
- }
- }
-
- loader->parser.root.cursor = old_cursor;
- loader->parser.root.limit = old_limit;
- }
-
- Exit:
- loader->parser.root.error = error;
- }
-
-
- static
- void parse_blend_design_map( T1_Face face,
- Z1_Loader* loader )
- {
- FT_Error error = 0;
- Z1_Parser* parser = &loader->parser;
- T1_Blend* blend;
- T1_Token axis_tokens[ T1_MAX_MM_AXIS ];
- FT_Int n, num_axis;
- FT_Byte* old_cursor;
- FT_Byte* old_limit;
- FT_Memory memory = face->root.memory;
-
-
- Z1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
- if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
- {
- FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
- num_axis ));
- error = T1_Err_Invalid_File_Format;
- goto Exit;
- }
- old_cursor = parser->root.cursor;
- old_limit = parser->root.limit;
-
- error = t1_allocate_blend( face, 0, num_axis );
- if ( error )
- goto Exit;
- blend = face->blend;
-
- /* now, read each axis design map */
- for ( n = 0; n < num_axis; n++ )
- {
- T1_DesignMap* map = blend->design_map + n;
- T1_Token* token;
- FT_Int p, num_points;
-
-
- token = axis_tokens + n;
- parser->root.cursor = token->start;
- parser->root.limit = token->limit;
-
- /* count the number of map points */
- {
- FT_Byte* ptr = token->start;
- FT_Byte* limit = token->limit;
-
-
- num_points = 0;
- for ( ; ptr < limit; ptr++ )
- if ( ptr[0] == '[' )
- num_points++;
- }
- if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
- {
- FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
- error = T1_Err_Invalid_File_Format;
- goto Exit;
- }
-
- /* allocate design map data */
- if ( ALLOC_ARRAY( map->design_points, num_points * 2, FT_Fixed ) )
- goto Exit;
- map->blend_points = map->design_points + num_points;
- map->num_points = (FT_Byte)num_points;
-
- for ( p = 0; p < num_points; p++ )
- {
- map->design_points[p] = Z1_ToInt( parser );
- map->blend_points [p] = Z1_ToFixed( parser, 0 );
- }
- }
-
- parser->root.cursor = old_cursor;
- parser->root.limit = old_limit;
-
- Exit:
- parser->root.error = error;
- }
-
-
- static
- void parse_weight_vector( T1_Face face,
- Z1_Loader* loader )
- {
- FT_Error error = 0;
- Z1_Parser* parser = &loader->parser;
- T1_Blend* blend = face->blend;
- T1_Token master;
- FT_UInt n;
- FT_Byte* old_cursor;
- FT_Byte* old_limit;
-
-
- if ( !blend || blend->num_designs == 0 )
- {
- FT_ERROR(( "parse_weight_vector: too early!\n" ));
- error = T1_Err_Invalid_File_Format;
- goto Exit;
- }
-
- Z1_ToToken( parser, &master );
- if ( master.type != t1_token_array )
- {
- FT_ERROR(( "parse_weight_vector: incorrect format!\n" ));
- error = T1_Err_Invalid_File_Format;
- goto Exit;
- }
-
- old_cursor = parser->root.cursor;
- old_limit = parser->root.limit;
-
- parser->root.cursor = master.start;
- parser->root.limit = master.limit;
-
- for ( n = 0; n < blend->num_designs; n++ )
- {
- blend->default_weight_vector[n] =
- blend->weight_vector[n] = Z1_ToFixed( parser, 0 );
- }
-
- parser->root.cursor = old_cursor;
- parser->root.limit = old_limit;
-
- Exit:
- parser->root.error = error;
- }
-
-
- /* the keyword `/shareddict' appears in some multiple master fonts */
- /* with a lot of Postscript garbage behind it (that's completely out */
- /* of spec!); we detect it and terminate the parsing */
- /* */
- static
- void parse_shared_dict( T1_Face face,
- Z1_Loader* loader )
- {
- Z1_Parser* parser = &loader->parser;
-
- FT_UNUSED( face );
-
-
- parser->root.cursor = parser->root.limit;
- parser->root.error = 0;
- }
-
-#endif /* Z1_CONFIG_OPTION_NO_MM_SUPPORT */
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** TYPE 1 SYMBOL PARSING *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* First of all, define the token field static variables. This is a set */
- /* of T1_Field variables used later. */
- /* */
- /*************************************************************************/
-
-
- static
- FT_Error t1_load_keyword( T1_Face face,
- Z1_Loader* loader,
- T1_Field* field )
- {
- FT_Error error;
- void* dummy_object;
- void** objects;
- FT_UInt max_objects;
- T1_Blend* blend = face->blend;
-
-
- /* if the keyword has a dedicated callback, call it */
- if ( field->type == t1_field_callback )
- {
- field->reader( (FT_Face)face, loader );
- error = loader->parser.root.error;
- goto Exit;
- }
-
- /* now, the keyword is either a simple field, or a table of fields; */
- /* we are now going to take care of it */
- switch ( field->location )
- {
- case t1_field_font_info:
- dummy_object = &face->type1.font_info;
- objects = &dummy_object;
- max_objects = 0;
-
- if ( blend )
- {
- objects = (void**)blend->font_infos;
- max_objects = blend->num_designs;
- }
- break;
-
- case t1_field_private:
- dummy_object = &face->type1.private_dict;
- objects = &dummy_object;
- max_objects = 0;
-
- if ( blend )
- {
- objects = (void**)blend->privates;
- max_objects = blend->num_designs;
- }
- break;
-
- default:
- dummy_object = &face->type1;
- objects = &dummy_object;
- max_objects = 0;
- }
-
- if ( field->type == t1_field_integer_array ||
- field->type == t1_field_fixed_array )
- error = Z1_Load_Field_Table( &loader->parser, field,
- objects, max_objects, 0 );
- else
- error = Z1_Load_Field( &loader->parser, field,
- objects, max_objects, 0 );
-
- Exit:
- return error;
- }
-
-
- static
- int is_space( FT_Byte c )
- {
- return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' );
- }
-
-
- static
- int is_alpha( FT_Byte c )
- {
- return ( isalnum( c ) || c == '.' || c == '_' );
- }
-
-
-
- static
- int read_binary_data( Z1_Parser* parser,
- FT_Int* size,
- FT_Byte** base )
- {
- FT_Byte* cur;
- FT_Byte* limit = parser->root.limit;
-
-
- /* the binary data has the following format */
- /* */
- /* `size' [white*] RD white ....... ND */
- /* */
-
- Z1_Skip_Spaces( parser );
- cur = parser->root.cursor;
-
- if ( cur < limit && (FT_Byte)( *cur - '0' ) < 10 )
- {
- *size = Z1_ToInt( parser );
-
- Z1_Skip_Spaces( parser );
- Z1_Skip_Alpha ( parser ); /* `RD' or `-|' or something else */
-
- /* there is only one whitespace char after the */
- /* `RD' or `-|' token */
- *base = parser->root.cursor + 1;
-
- parser->root.cursor += *size + 1;
- return 1;
- }
-
- FT_ERROR(( "read_binary_data: invalid size field\n" ));
- parser->root.error = T1_Err_Invalid_File_Format;
- return 0;
- }
-
-
- /* we will now define the routines used to handle */
- /* the `/Encoding', `/Subrs', and `/CharStrings' */
- /* dictionaries */
-
- static
- void parse_font_name( T1_Face face,
- Z1_Loader* loader )
- {
- Z1_Parser* parser = &loader->parser;
- FT_Error error;
- FT_Memory memory = parser->root.memory;
- FT_Int len;
- FT_Byte* cur;
- FT_Byte* cur2;
- FT_Byte* limit;
-
-
- Z1_Skip_Spaces( parser );
-
- cur = parser->root.cursor;
- limit = parser->root.limit;
-
- if ( cur >= limit - 1 || *cur != '/' )
- return;
-
- cur++;
- cur2 = cur;
- while ( cur2 < limit && is_alpha( *cur2 ) )
- cur2++;
-
- len = cur2 - cur;
- if ( len > 0 )
- {
- if ( ALLOC( face->type1.font_name, len + 1 ) )
- {
- parser->root.error = error;
- return;
- }
-
- MEM_Copy( face->type1.font_name, cur, len );
- face->type1.font_name[len] = '\0';
- }
- parser->root.cursor = cur2;
- }
-
-
- static
- void parse_font_bbox( T1_Face face,
- Z1_Loader* loader )
- {
- Z1_Parser* parser = &loader->parser;
- FT_Short temp[4];
- FT_BBox* bbox = &face->type1.font_bbox;
-
-
- (void)Z1_ToCoordArray( parser, 4, temp );
- bbox->xMin = temp[0];
- bbox->yMin = temp[1];
- bbox->xMax = temp[2];
- bbox->yMax = temp[3];
- }
-
-
- static
- void parse_font_matrix( T1_Face face,
- Z1_Loader* loader )
- {
- Z1_Parser* parser = &loader->parser;
- FT_Matrix* matrix = &face->type1.font_matrix;
- FT_Vector* offset = &face->type1.font_offset;
- FT_Fixed temp[6];
-
-
- if ( matrix->xx || matrix->yx )
- /* with synthetic fonts, it's possible we get here twice */
- return;
-
- (void)Z1_ToFixedArray( parser, 6, temp, 3 );
-
- /* we need to scale the values by 1.0/temp[3] */
- if ( temp[3] != 0x10000L )
- {
- temp[0] = FT_DivFix( temp[0], temp[3] );
- temp[1] = FT_DivFix( temp[1], temp[3] );
- temp[2] = FT_DivFix( temp[2], temp[3] );
- temp[4] = FT_DivFix( temp[4], temp[3] );
- temp[5] = FT_DivFix( temp[5], temp[3] );
- temp[3] = 0x10000L;
- }
-
- matrix->xx = temp[0];
- matrix->yx = temp[1];
- matrix->xy = temp[2];
- matrix->yy = temp[3];
-
- /* note that the offsets must be expressed in integer font units */
- offset->x = temp[4] >> 16;
- offset->y = temp[5] >> 16;
- }
-
-
- static
- void parse_encoding( T1_Face face,
- Z1_Loader* loader )
- {
- Z1_Parser* parser = &loader->parser;
- FT_Byte* cur = parser->root.cursor;
- FT_Byte* limit = parser->root.limit;
-
- PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
-
-
- /* skip whitespace */
- while ( is_space( *cur ) )
- {
- cur++;
- if ( cur >= limit )
- {
- FT_ERROR(( "parse_encoding: out of bounds!\n" ));
- parser->root.error = T1_Err_Invalid_File_Format;
- return;
- }
- }
-
- /* if we have a number, then the encoding is an array, */
- /* and we must load it now */
- if ( (FT_Byte)( *cur - '0' ) < 10 )
- {
- T1_Encoding* encode = &face->type1.encoding;
- FT_Int count, n;
- PS_Table* char_table = &loader->encoding_table;
- FT_Memory memory = parser->root.memory;
- FT_Error error;
-
-
- /* read the number of entries in the encoding, should be 256 */
- count = Z1_ToInt( parser );
- if ( parser->root.error )
- return;
-
- /* we use a Z1_Table to store our charnames */
- encode->num_chars = count;
- if ( ALLOC_ARRAY( encode->char_index, count, FT_Short ) ||
- ALLOC_ARRAY( encode->char_name, count, FT_String* ) ||
- ( error = psaux->ps_table_funcs->init(
- char_table, count, memory ) ) != 0 )
- {
- parser->root.error = error;
- return;
- }
-
- /* We need to `zero' out encoding_table.elements */
- for ( n = 0; n < count; n++ )
- {
- char* notdef = ".notdef";
-
-
- Z1_Add_Table( char_table, n, notdef, 8 );
- }
-
- /* Now, we will need to read a record of the form */
- /* ... charcode /charname ... for each entry in our table */
- /* */
- /* We simply look for a number followed by an immediate */
- /* name. Note that this ignores correctly the sequence */
- /* that is often seen in type1 fonts: */
- /* */
- /* 0 1 255 { 1 index exch /.notdef put } for dup */
- /* */
- /* used to clean the encoding array before anything else. */
- /* */
- /* We stop when we encounter a `def'. */
-
- cur = parser->root.cursor;
- limit = parser->root.limit;
- n = 0;
-
- for ( ; cur < limit; )
- {
- FT_Byte c;
-
-
- c = *cur;
-
- /* we stop when we encounter a `def' */
- if ( c == 'd' && cur + 3 < limit )
- {
- if ( cur[1] == 'e' &&
- cur[2] == 'f' &&
- is_space(cur[-1]) &&
- is_space(cur[3]) )
- {
- FT_TRACE6(( "encoding end\n" ));
- break;
- }
- }
-
- /* otherwise, we must find a number before anything else */
- if ( (FT_Byte)( c - '0' ) < 10 )
- {
- FT_Int charcode;
-
-
- parser->root.cursor = cur;
- charcode = Z1_ToInt( parser );
- cur = parser->root.cursor;
-
- /* skip whitespace */
- while ( cur < limit && is_space( *cur ) )
- cur++;
-
- if ( cur < limit && *cur == '/' )
- {
- /* bingo, we have an immediate name -- it must be a */
- /* character name */
- FT_Byte* cur2 = cur + 1;
- FT_Int len;
-
-
- while ( cur2 < limit && is_alpha( *cur2 ) )
- cur2++;
-
- len = cur2 - cur - 1;
-
- parser->root.error = Z1_Add_Table( char_table, charcode,
- cur + 1, len + 1 );
- char_table->elements[charcode][len] = '\0';
- if ( parser->root.error )
- return;
-
- cur = cur2;
- }
- }
- else
- cur++;
- }
-
- face->type1.encoding_type = t1_encoding_array;
- parser->root.cursor = cur;
- }
- /* Otherwise, we should have either `StandardEncoding' or */
- /* `ExpertEncoding' */
- else
- {
- if ( cur + 17 < limit &&
- strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
- face->type1.encoding_type = t1_encoding_standard;
-
- else if ( cur + 15 < limit &&
- strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
- face->type1.encoding_type = t1_encoding_expert;
-
- else
- {
- FT_ERROR(( "parse_encoding: invalid token!\n" ));
- parser->root.error = T1_Err_Invalid_File_Format;
- }
- }
- }
-
-
- static
- void parse_subrs( T1_Face face,
- Z1_Loader* loader )
- {
- Z1_Parser* parser = &loader->parser;
- PS_Table* table = &loader->subrs;
- FT_Memory memory = parser->root.memory;
- FT_Error error;
- FT_Int n;
-
- PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
-
-
- loader->num_subrs = Z1_ToInt( parser );
- if ( parser->root.error )
- return;
-
- /* position the parser right before the `dup' of the first subr */
- Z1_Skip_Spaces( parser );
- Z1_Skip_Alpha( parser ); /* `array' */
- Z1_Skip_Spaces( parser );
-
- /* initialize subrs array */
- error = psaux->ps_table_funcs->init( table, loader->num_subrs, memory );
- if ( error )
- goto Fail;
-
- /* the format is simple: */
- /* */
- /* `index' + binary data */
- /* */
-
- for ( n = 0; n < loader->num_subrs; n++ )
- {
- FT_Int index, size;
- FT_Byte* base;
-
-
- /* If the next token isn't `dup', we are also done. This */
- /* happens when there are `holes' in the Subrs array. */
- if ( strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
- break;
-
- index = Z1_ToInt( parser );
-
- if ( !read_binary_data( parser, &size, &base ) )
- return;
-
- /* The binary string is followed by one token, e.g. `NP' */
- /* (bound to `noaccess put') or by two separate tokens: */
- /* `noaccess' & `put'. We position the parser right */
- /* before the next `dup', if any. */
- Z1_Skip_Spaces( parser );
- Z1_Skip_Alpha( parser ); /* `NP' or `I' or `noaccess' */
- Z1_Skip_Spaces( parser );
-
- if ( strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
- {
- Z1_Skip_Alpha( parser ); /* skip `put' */
- Z1_Skip_Spaces( parser );
- }
-
- /* some fonts use a value of -1 for lenIV to indicate that */
- /* the charstrings are unencoded */
- /* */
- /* thanks to Tom Kacvinsky for pointing this out */
- /* */
- if ( face->type1.private_dict.lenIV >= 0 )
- {
- Z1_Decrypt( base, size, 4330 );
- size -= face->type1.private_dict.lenIV;
- base += face->type1.private_dict.lenIV;
- }
-
- error = Z1_Add_Table( table, index, base, size );
- if ( error )
- goto Fail;
- }
- return;
-
- Fail:
- parser->root.error = error;
- }
-
-
- static
- void parse_charstrings( T1_Face face,
- Z1_Loader* loader )
- {
- Z1_Parser* parser = &loader->parser;
- PS_Table* code_table = &loader->charstrings;
- PS_Table* name_table = &loader->glyph_names;
- FT_Memory memory = parser->root.memory;
- FT_Error error;
-
- PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
-
- FT_Byte* cur;
- FT_Byte* limit = parser->root.limit;
- FT_Int n;
- FT_UInt notdef_index = 0;
- FT_Byte notdef_found = 0;
-
-
- if ( loader->num_glyphs )
- /* with synthetic fonts, it's possible we get here twice */
- return;
-
- loader->num_glyphs = Z1_ToInt( parser );
- if ( parser->root.error )
- return;
-
- /* initialize tables, adding space for `swap' at table end */
- error = psaux->ps_table_funcs->init( code_table,
- loader->num_glyphs + 1,
- memory );
- if ( error )
- goto Fail;
-
- error = psaux->ps_table_funcs->init( name_table,
- loader->num_glyphs + 1,
- memory );
- if ( error )
- goto Fail;
-
- n = 0;
- for (;;)
- {
- FT_Int size;
- FT_Byte* base;
-
-
- /* the format is simple: */
- /* `/glyphname' + binary data */
- /* */
- /* note that we stop when we find a `def' */
- /* */
- Z1_Skip_Spaces( parser );
-
- cur = parser->root.cursor;
- if ( cur >= limit )
- break;
-
- /* we stop when we find a `def' or `end' keyword */
- if ( *cur == 'd' &&
- cur + 3 < limit &&
- cur[1] == 'e' &&
- cur[2] == 'f' )
- break;
-
- if ( *cur == 'e' &&
- cur + 3 < limit &&
- cur[1] == 'n' &&
- cur[2] == 'd' )
- break;
-
- if ( *cur != '/' )
- Z1_Skip_Alpha( parser );
- else
- {
- FT_Byte* cur2 = cur + 1;
- FT_Int len;
-
-
- while ( cur2 < limit && is_alpha( *cur2 ) )
- cur2++;
- len = cur2 - cur - 1;
-
- error = Z1_Add_Table( name_table, n, cur + 1, len + 1 );
- if ( error )
- goto Fail;
-
- /* add a trailing zero to the name table */
- name_table->elements[n][len] = '\0';
-
- /* record index of /.notdef */
- if ( strcmp( (const char*)".notdef",
- (const char*)(name_table->elements[n]) ) == 0 )
- {
- notdef_index = n;
- notdef_found = 1;
- }
-
- parser->root.cursor = cur2;
- if ( !read_binary_data( parser, &size, &base ) )
- return;
-
- if ( face->type1.private_dict.lenIV >= 0 )
- {
- Z1_Decrypt( base, size, 4330 );
- size -= face->type1.private_dict.lenIV;
- base += face->type1.private_dict.lenIV;
- }
-
- error = Z1_Add_Table( code_table, n, base, size );
- if ( error )
- goto Fail;
-
- n++;
- if ( n >= loader->num_glyphs )
- break;
- }
- }
-
- loader->num_glyphs = n;
-
- /* if /.notdef is found but does not occupy index 0, do our magic. */
- if ( strcmp( (const char*)".notdef",
- (const char*)name_table->elements[0] ) &&
- notdef_found )
- {
-
- /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
- /* name/code to end of table. Then place notdef_index name/code into */
- /* index 0. Then take end of table name/code and place it into index */
- /* notdef_index. */
-
- error = Z1_Add_Table( name_table, n,
- name_table->elements[0],
- name_table->lengths [0] );
- if ( error )
- goto Fail;
- error = Z1_Add_Table( code_table, n,
- code_table->elements[0],
- code_table->lengths [0] );
- if ( error )
- goto Fail;
-
- error = Z1_Add_Table( name_table, 0,
- name_table->elements[notdef_index],
- name_table->lengths [notdef_index] );
- if ( error )
- goto Fail;
-
- error = Z1_Add_Table( code_table, 0,
- code_table->elements[notdef_index],
- code_table->lengths [notdef_index] );
- if ( error )
- goto Fail;
-
- error = Z1_Add_Table( name_table, notdef_index,
- name_table->elements[n],
- name_table->lengths [n] );
- if ( error )
- goto Fail;
-
- error = Z1_Add_Table( code_table, notdef_index,
- code_table->elements[n],
- code_table->lengths [n] );
- if ( error )
- goto Fail;
-
- }
- else if ( !notdef_found )
- {
-
- /* notdef_index is already 0, or /.notdef is undefined in */
- /* charstrings dictionary. Worry about /.notdef undefined. */
- /* we take index 0 and add it to the end of the table(s) */
- /* and add our own /.notdef glyph to index 0. */
-
- /* 0 333 hsbw endchar */
- FT_Byte notdef_glyph[] = {0x8B, 0xF7, 0xE1, 0x0D, 0x0E};
- char* notdef_name = ".notdef";
-
-
- error = Z1_Add_Table( name_table, n,
- name_table->elements[0],
- name_table->lengths [0] );
- if ( error )
- goto Fail;
-
- error = Z1_Add_Table( code_table, n,
- code_table->elements[0],
- code_table->lengths [0] );
- if ( error )
- goto Fail;
-
- error = Z1_Add_Table( name_table, 0, notdef_name, 8 );
- if ( error )
- goto Fail;
-
- error = Z1_Add_Table( code_table, 0, notdef_glyph, 5 );
-
- if ( error )
- goto Fail;
-
- /* we added a glyph. */
- loader->num_glyphs = n + 1;
-
- }
-
- return;
-
- Fail:
- parser->root.error = error;
- }
-
-
- static
- const T1_Field t1_keywords[] =
- {
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1tokens.h"
-
-#else
-
-#include <type1z/z1tokens.h>
-
-#endif
-
- /* now add the special functions... */
- T1_FIELD_CALLBACK( "FontName", parse_font_name )
- T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
- T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
- T1_FIELD_CALLBACK( "Encoding", parse_encoding )
- T1_FIELD_CALLBACK( "Subrs", parse_subrs )
- T1_FIELD_CALLBACK( "CharStrings", parse_charstrings )
-
-#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT
- T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions )
- T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map )
- T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types )
- T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector )
- T1_FIELD_CALLBACK( "shareddict", parse_shared_dict )
-#endif
-
- { 0, t1_field_cid_info, t1_field_none, 0, 0, 0, 0, 0 }
- };
-
-
- static
- FT_Error parse_dict( T1_Face face,
- Z1_Loader* loader,
- FT_Byte* base,
- FT_Long size )
- {
- Z1_Parser* parser = &loader->parser;
-
-
- parser->root.cursor = base;
- parser->root.limit = base + size;
- parser->root.error = 0;
-
- {
- FT_Byte* cur = base;
- FT_Byte* limit = cur + size;
-
-
- for ( ; cur < limit; cur++ )
- {
- /* look for `FontDirectory', which causes problems on some fonts */
- if ( *cur == 'F' && cur + 25 < limit &&
- strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
- {
- FT_Byte* cur2;
-
-
- /* skip the `FontDirectory' keyword */
- cur += 13;
- cur2 = cur;
-
- /* lookup the `known' keyword */
- while ( cur < limit && *cur != 'k' &&
- strncmp( (char*)cur, "known", 5 ) )
- cur++;
-
- if ( cur < limit )
- {
- T1_Token token;
-
-
- /* skip the `known' keyword and the token following it */
- cur += 5;
- loader->parser.root.cursor = cur;
- Z1_ToToken( &loader->parser, &token );
-
- /* if the last token was an array, skip it! */
- if ( token.type == t1_token_array )
- cur2 = parser->root.cursor;
- }
- cur = cur2;
- }
- /* 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 )
- {
- if ( !loader->fontdata )
- {
- if ( strncmp( (char*)cur, "FontInfo", 8 ) == 0 )
- loader->fontdata = 1;
- }
- else
- {
- /* now, compare the immediate name to the keyword table */
- T1_Field* keyword = (T1_Field*)t1_keywords;
-
-
- 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->root.cursor = cur2;
- Z1_Skip_Spaces( parser );
- parser->root.error = t1_load_keyword( face,
- loader,
- keyword );
- if ( parser->root.error )
- return parser->root.error;
-
- cur = parser->root.cursor;
- break;
- }
- }
- keyword++;
- }
- }
- }
- }
- }
- }
- return parser->root.error;
- }
-
-
- static
- void t1_init_loader( Z1_Loader* loader,
- T1_Face face )
- {
- FT_UNUSED( face );
-
- MEM_Set( loader, 0, sizeof ( *loader ) );
- loader->num_glyphs = 0;
- loader->num_chars = 0;
-
- /* initialize the tables -- simply set their `init' field to 0 */
- loader->encoding_table.init = 0;
- loader->charstrings.init = 0;
- loader->glyph_names.init = 0;
- loader->subrs.init = 0;
- loader->fontdata = 0;
- }
-
-
- static
- void t1_done_loader( Z1_Loader* loader )
- {
- Z1_Parser* parser = &loader->parser;
-
-
- /* finalize tables */
- Z1_Release_Table( &loader->encoding_table );
- Z1_Release_Table( &loader->charstrings );
- Z1_Release_Table( &loader->glyph_names );
- Z1_Release_Table( &loader->subrs );
-
- /* finalize parser */
- Z1_Done_Parser( parser );
- }
-
-
- LOCAL_FUNC
- FT_Error Z1_Open_Face( T1_Face face )
- {
- Z1_Loader loader;
- Z1_Parser* parser;
- T1_Font* type1 = &face->type1;
- FT_Error error;
-
- PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
-
-
- t1_init_loader( &loader, face );
-
- /* default lenIV */
- type1->private_dict.lenIV = 4;
-
- parser = &loader.parser;
- error = Z1_New_Parser( parser,
- face->root.stream,
- face->root.memory,
- psaux );
- if ( error )
- goto Exit;
-
- error = parse_dict( face, &loader, parser->base_dict, parser->base_len );
- if ( error )
- goto Exit;
-
- error = Z1_Get_Private_Dict( parser );
- if ( error )
- goto Exit;
-
- error = parse_dict( face, &loader, parser->private_dict,
- parser->private_len );
- if ( error )
- goto Exit;
-
- /* now, propagate the subrs, charstrings, and glyphnames tables */
- /* to the Type1 data */
- type1->num_glyphs = loader.num_glyphs;
-
- if ( !loader.subrs.init )
- {
- FT_ERROR(( "Z1_Open_Face: no subrs array in face!\n" ));
- error = T1_Err_Invalid_File_Format;
- }
-
- if ( !loader.charstrings.init )
- {
- FT_ERROR(( "Z1_Open_Face: no charstrings array in face!\n" ));
- error = T1_Err_Invalid_File_Format;
- }
-
- loader.subrs.init = 0;
- type1->num_subrs = loader.num_subrs;
- type1->subrs_block = loader.subrs.block;
- type1->subrs = loader.subrs.elements;
- type1->subrs_len = loader.subrs.lengths;
-
- loader.charstrings.init = 0;
- type1->charstrings_block = loader.charstrings.block;
- type1->charstrings = loader.charstrings.elements;
- type1->charstrings_len = loader.charstrings.lengths;
-
- /* we copy the glyph names `block' and `elements' fields; */
- /* the `lengths' field must be released later */
- type1->glyph_names_block = loader.glyph_names.block;
- type1->glyph_names = (FT_String**)loader.glyph_names.elements;
- loader.glyph_names.block = 0;
- loader.glyph_names.elements = 0;
-
- /* we must now build type1.encoding when we have a custom */
- /* array.. */
- if ( type1->encoding_type == t1_encoding_array )
- {
- FT_Int charcode, index, min_char, max_char;
- FT_Byte* char_name;
- FT_Byte* glyph_name;
-
-
- /* OK, we do the following: for each element in the encoding */
- /* table, look up the index of the glyph having the same name */
- /* the index is then stored in type1.encoding.char_index, and */
- /* a the name to type1.encoding.char_name */
-
- min_char = +32000;
- max_char = -32000;
-
- charcode = 0;
- for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
- {
- type1->encoding.char_index[charcode] = 0;
- type1->encoding.char_name [charcode] = (char *)".notdef";
-
- char_name = loader.encoding_table.elements[charcode];
- if ( char_name )
- for ( index = 0; index < type1->num_glyphs; index++ )
- {
- glyph_name = (FT_Byte*)type1->glyph_names[index];
- if ( strcmp( (const char*)char_name,
- (const char*)glyph_name ) == 0 )
- {
- type1->encoding.char_index[charcode] = index;
- type1->encoding.char_name [charcode] = (char*)glyph_name;
-
- /* Change min/max encoded char only if glyph name is */
- /* not /.notdef */
- if ( strcmp( (const char*)".notdef",
- (const char*)glyph_name ) != 0 )
- {
- if (charcode < min_char) min_char = charcode;
- if (charcode > max_char) max_char = charcode;
- }
- break;
- }
- }
- }
- type1->encoding.code_first = min_char;
- type1->encoding.code_last = max_char;
- type1->encoding.num_chars = loader.num_chars;
- }
-
- Exit:
- t1_done_loader( &loader );
- return error;
- }
-
-
-/* END */
--- a/src/type1z/z1load.h
+++ /dev/null
@@ -1,93 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1load.h */
-/* */
-/* Experimental Type 1 font loader (specification). */
-/* */
-/* 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 Z1LOAD_H
-#define Z1LOAD_H
-
-#include <freetype/internal/ftstream.h>
-#include <freetype/internal/psaux.h>
-#include <freetype/ftmm.h>
-
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1parse.h"
-
-#else
-
-#include <type1z/z1parse.h>
-
-#endif
-
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
- typedef struct Z1_Loader_
- {
- Z1_Parser parser; /* parser used to read the stream */
-
- FT_Int num_chars; /* number of characters in encoding */
- PS_Table encoding_table; /* PS_Table used to store the */
- /* encoding character names */
-
- FT_Int num_glyphs;
- PS_Table glyph_names;
- PS_Table charstrings;
-
- FT_Int num_subrs;
- PS_Table subrs;
- FT_Bool fontdata;
-
- } Z1_Loader;
-
-
- LOCAL_DEF
- FT_Error Z1_Open_Face( T1_Face face );
-
-#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT
-
- LOCAL_DEF
- FT_Error Z1_Get_Multi_Master( T1_Face face,
- FT_Multi_Master* master );
-
- LOCAL_DEF
- FT_Error Z1_Set_MM_Blend( T1_Face face,
- FT_UInt num_coords,
- FT_Fixed* coords );
-
- LOCAL_DEF
- FT_Error Z1_Set_MM_Design( T1_Face face,
- FT_UInt num_coords,
- FT_Long* coords );
-
- LOCAL_DEF
- void Z1_Done_Blend( T1_Face face );
-
-#endif /* !Z1_CONFIG_OPTION_NO_MM_SUPPORT */
-
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif /* Z1LOAD_H */
-
-
-/* END */
--- a/src/type1z/z1objs.c
+++ /dev/null
@@ -1,406 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1objs.c */
-/* */
-/* Experimental Type 1 objects manager (body). */
-/* */
-/* 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. */
-/* */
-/***************************************************************************/
-
-
-#include <freetype/internal/ftdebug.h>
-#include <freetype/internal/ftstream.h>
-
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1gload.h"
-#include "z1load.h"
-#include "z1afm.h"
-
-#else
-
-#include <type1z/z1gload.h>
-#include <type1z/z1load.h>
-#include <type1z/z1afm.h>
-
-#endif
-
-
-#include <freetype/internal/psnames.h>
-#include <freetype/internal/psaux.h>
-
-
- /*************************************************************************/
- /* */
- /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
- /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
- /* messages during execution. */
- /* */
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_z1objs
-
-
- /*************************************************************************/
- /* */
- /* FACE FUNCTIONS */
- /* */
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Z1_Done_Face */
- /* */
- /* <Description> */
- /* The face object destructor. */
- /* */
- /* <Input> */
- /* face :: A typeless pointer to the face object to destroy. */
- /* */
- LOCAL_FUNC
- void Z1_Done_Face( T1_Face face )
- {
- FT_Memory memory;
- T1_Font* type1 = &face->type1;
-
-
- if ( face )
- {
- memory = face->root.memory;
-
-#ifndef Z1_CONFIG_OPTION_NO_MM_SUPPORT
- /* release multiple masters information */
- Z1_Done_Blend( face );
- face->blend = 0;
-#endif
-
- /* release font info strings */
- {
- T1_FontInfo* info = &type1->font_info;
-
-
- FREE( info->version );
- FREE( info->notice );
- FREE( info->full_name );
- FREE( info->family_name );
- FREE( info->weight );
- }
-
- /* release top dictionary */
- FREE( type1->charstrings_len );
- FREE( type1->charstrings );
- FREE( type1->glyph_names );
-
- FREE( type1->subrs );
- FREE( type1->subrs_len );
-
- FREE( type1->subrs_block );
- FREE( type1->charstrings_block );
- FREE( type1->glyph_names_block );
-
- FREE( type1->encoding.char_index );
- FREE( type1->font_name );
-
-#ifndef Z1_CONFIG_OPTION_NO_AFM
- /* release afm data if present */
- if ( face->afm_data )
- Z1_Done_AFM( memory, (Z1_AFM*)face->afm_data );
-#endif
-
- /* release unicode map, if any */
- FREE( face->unicode_map.maps );
- face->unicode_map.num_maps = 0;
-
- face->root.family_name = 0;
- face->root.style_name = 0;
- }
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Z1_Init_Face */
- /* */
- /* <Description> */
- /* The face object constructor. */
- /* */
- /* <Input> */
- /* stream :: input stream where to load font data. */
- /* */
- /* face_index :: The index of the font face in the resource. */
- /* */
- /* num_params :: Number of additional generic parameters. Ignored. */
- /* */
- /* params :: Additional generic parameters. Ignored. */
- /* */
- /* <InOut> */
- /* face :: The face record to build. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- LOCAL_FUNC
- FT_Error Z1_Init_Face( FT_Stream stream,
- T1_Face face,
- FT_Int face_index,
- FT_Int num_params,
- FT_Parameter* params )
- {
- FT_Error error;
- PSNames_Interface* psnames;
- PSAux_Interface* psaux;
-
- FT_UNUSED( num_params );
- FT_UNUSED( params );
- FT_UNUSED( face_index );
- FT_UNUSED( stream );
-
-
- face->root.num_faces = 1;
-
- psnames = (PSNames_Interface*)face->psnames;
- if ( !psnames )
- {
- psnames = (PSNames_Interface*)
- FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), "psnames" );
-
- face->psnames = psnames;
- }
-
- psaux = (PSAux_Interface*)face->psaux;
- if ( !psaux )
- {
- psaux = (PSAux_Interface*)
- FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), "psaux" );
-
- face->psaux = psaux;
- }
-
- /* open the tokenizer, this will also check the font format */
- error = Z1_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(( "Z1_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->type1.num_glyphs;
- root->num_charmaps = 1;
-
- root->face_index = face_index;
- root->face_flags = FT_FACE_FLAG_SCALABLE;
-
- root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
-
- root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
-
- if ( face->type1.font_info.is_fixed_pitch )
- root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
-
- if ( face->blend )
- root->face_flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
-
- /* XXX: TODO -- add kerning with .afm support */
-
- /* get style name -- be careful, some broken fonts only */
- /* have a `/FontName' dictionary entry! */
- root->family_name = face->type1.font_info.family_name;
- if ( root->family_name )
- {
- char* full = face->type1.font_info.full_name;
- char* family = root->family_name;
-
-
- while ( *family && *full == *family )
- {
- family++;
- full++;
- }
-
- root->style_name = ( *full == ' ' ? full + 1
- : (char *)"Regular" );
- }
- else
- {
- /* do we have a `/FontName'? */
- if ( face->type1.font_name )
- {
- root->family_name = face->type1.font_name;
- root->style_name = (char *)"Regular";
- }
- }
-
- /* no embedded bitmap support */
- root->num_fixed_sizes = 0;
- root->available_sizes = 0;
-
- root->bbox = face->type1.font_bbox;
- root->units_per_EM = 1000;
- root->ascender = (FT_Short)face->type1.font_bbox.yMax;
- root->descender = (FT_Short)face->type1.font_bbox.yMin;
- root->height = ( ( root->ascender + root->descender ) * 12 ) / 10;
-
- /* 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 = Z1_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;
-
- root->underline_position = face->type1.font_info.underline_position;
- root->underline_thickness = face->type1.font_info.underline_thickness;
-
- root->max_points = 0;
- root->max_contours = 0;
- }
-
- /* charmap support -- synthetize unicode charmap if possible */
- {
- FT_Face root = &face->root;
- FT_CharMap charmap = face->charmaprecs;
-
-
- /* synthesize a Unicode charmap if there is support in the `PSNames' */
- /* module */
- if ( 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 = FT_Err_Ok;
- }
- }
-
- /* now, support either the standard, expert, or custom encoding */
- charmap->face = (FT_Face)face;
- charmap->platform_id = 7; /* a new platform id for Adobe fonts? */
-
- switch ( face->type1.encoding_type )
- {
- case t1_encoding_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];
- }
-
- Exit:
- return error;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Z1_Init_Driver */
- /* */
- /* <Description> */
- /* Initializes a given Type 1 driver object. */
- /* */
- /* <Input> */
- /* driver :: A handle to the target driver object. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- LOCAL_FUNC
- FT_Error Z1_Init_Driver( Z1_Driver driver )
- {
- FT_UNUSED( driver );
-
- return T1_Err_Ok;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Z1_Done_Driver */
- /* */
- /* <Description> */
- /* Finalizes a given Type 1 driver. */
- /* */
- /* <Input> */
- /* driver :: A handle to the target Type 1 driver. */
- /* */
- LOCAL_DEF
- void Z1_Done_Driver( Z1_Driver driver )
- {
- FT_UNUSED( driver );
- }
-
-
-/* END */
--- a/src/type1z/z1objs.h
+++ /dev/null
@@ -1,161 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1objs.h */
-/* */
-/* Experimental Type 1 objects manager (specification). */
-/* */
-/* 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 Z1OBJS_H
-#define Z1OBJS_H
-
-#include <freetype/internal/ftobjs.h>
-#include <freetype/config/ftconfig.h>
-#include <freetype/internal/t1errors.h>
-#include <freetype/internal/t1types.h>
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
- /* The following structures must be defined by the hinter */
- typedef struct Z1_Size_Hints_ Z1_Size_Hints;
- typedef struct Z1_Glyph_Hints_ Z1_Glyph_Hints;
-
-
- /*************************************************************************/
- /* */
- /* <Type> */
- /* Z1_Driver */
- /* */
- /* <Description> */
- /* A handle to a Type 1 driver object. */
- /* */
- typedef struct Z1_DriverRec_ *Z1_Driver;
-
-
- /*************************************************************************/
- /* */
- /* <Type> */
- /* Z1_Size */
- /* */
- /* <Description> */
- /* A handle to a Type 1 size object. */
- /* */
- typedef struct Z1_SizeRec_* Z1_Size;
-
-
- /*************************************************************************/
- /* */
- /* <Type> */
- /* Z1_GlyphSlot */
- /* */
- /* <Description> */
- /* A handle to a Type 1 glyph slot object. */
- /* */
- typedef struct Z1_GlyphSlotRec_* Z1_GlyphSlot;
-
-
- /*************************************************************************/
- /* */
- /* <Type> */
- /* Z1_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 Z1_CharMapRec_* Z1_CharMap;
-
-
- /*************************************************************************/
- /* */
- /* HERE BEGINS THE TYPE1 SPECIFIC STUFF */
- /* */
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* <Type> */
- /* Z1_SizeRec */
- /* */
- /* <Description> */
- /* Type 1 size record. */
- /* */
- typedef struct Z1_SizeRec_
- {
- FT_SizeRec root;
- FT_Bool valid;
- Z1_Size_Hints* hints; /* defined in the hinter. This allows */
- /* us to experiment with different */
- /* hinting schemes without having to */
- /* change `z1objs' each time. */
- } Z1_SizeRec;
-
-
- /*************************************************************************/
- /* */
- /* <Type> */
- /* Z1_GlyphSlotRec */
- /* */
- /* <Description> */
- /* Type 1 glyph slot record. */
- /* */
- typedef struct Z1_GlyphSlotRec_
- {
- FT_GlyphSlotRec root;
-
- FT_Bool hint;
- FT_Bool scaled;
-
- FT_Int max_points;
- FT_Int max_contours;
-
- FT_Fixed x_scale;
- FT_Fixed y_scale;
-
- Z1_Glyph_Hints* hints; /* defined in the hinter */
-
- } Z1_GlyphSlotRec;
-
-
- LOCAL_DEF
- FT_Error Z1_Init_Face( FT_Stream stream,
- T1_Face face,
- FT_Int face_index,
- FT_Int num_params,
- FT_Parameter* params );
-
- LOCAL_DEF
- void Z1_Done_Face( T1_Face face );
-
- LOCAL_DEF
- FT_Error Z1_Init_Driver( Z1_Driver driver );
-
- LOCAL_DEF
- void Z1_Done_Driver( Z1_Driver driver );
-
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif /* Z1OBJS_H */
-
-
-/* END */
--- a/src/type1z/z1parse.c
+++ /dev/null
@@ -1,487 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1parse.c */
-/* */
-/* Experimental Type 1 parser (body). */
-/* */
-/* 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 Type 1 parser is in charge of the following: */
- /* */
- /* - provide an implementation of a growing sequence of objects called */
- /* a `Z1_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 `z1load.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 <freetype/internal/t1errors.h>
-#include <freetype/internal/psaux.h>
-
-#ifdef FT_FLAT_COMPILE
-
-#include "z1parse.h"
-
-#else
-
-#include <type1z/z1parse.h>
-
-#endif
-
-
-#include <string.h> /* for strncmp() */
-
-
- /*************************************************************************/
- /* */
- /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
- /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
- /* messages during execution. */
- /* */
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_z1parse
-
-
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** INPUT STREAM PARSER *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
- /*************************************************************************/
-
-
-#define IS_Z1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
-#define IS_Z1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' )
-
-#define IS_Z1_SPACE( c ) ( IS_Z1_WHITESPACE( c ) || IS_Z1_LINESPACE( c ) )
-
-
- typedef struct PFB_Tag_
- {
- FT_UShort tag;
- FT_Long size;
-
- } PFB_Tag;
-
-
-#undef FT_STRUCTURE
-#define FT_STRUCTURE PFB_Tag
-
-
- static
- const FT_Frame_Field pfb_tag_fields[] =
- {
- FT_FRAME_START( 6 ),
- FT_FRAME_USHORT ( tag ),
- FT_FRAME_LONG_LE( size ),
- FT_FRAME_END
- };
-
-
- static
- FT_Error read_pfb_tag( FT_Stream stream,
- FT_UShort* tag,
- FT_Long* size )
- {
- FT_Error error;
- PFB_Tag head;
-
-
- *tag = 0;
- *size = 0;
- if ( !READ_Fields( pfb_tag_fields, &head ) )
- {
- if ( head.tag == 0x8001 || head.tag == 0x8002 )
- {
- *tag = head.tag;
- *size = head.size;
- }
- }
- return error;
- }
-
-
- LOCAL_FUNC
- FT_Error Z1_New_Parser( Z1_Parser* parser,
- FT_Stream stream,
- FT_Memory memory,
- PSAux_Interface* psaux )
- {
- FT_Error error;
- FT_UShort tag;
- FT_Long size;
-
-
- psaux->t1_parser_funcs->init( &parser->root,0, 0, memory );
-
- parser->stream = stream;
- parser->base_len = 0;
- parser->base_dict = 0;
- parser->private_len = 0;
- parser->private_dict = 0;
- parser->in_pfb = 0;
- parser->in_memory = 0;
- parser->single_block = 0;
-
- /******************************************************************/
- /* */
- /* Here a short summary of what is going on: */
- /* */
- /* When creating a new Type 1 parser, we try to locate and load */
- /* the base dictionary if this is possible (i.e. for PFB */
- /* files). Otherwise, we load the whole font into memory. */
- /* */
- /* When `loading' the base dictionary, we only setup pointers */
- /* in the case of a memory-based stream. Otherwise, we */
- /* allocate and load the base dictionary in it. */
- /* */
- /* parser->in_pfb is set if we are in a binary (".pfb") font. */
- /* parser->in_memory is set if we have a memory stream. */
- /* */
-
- /* try to compute the size of the base dictionary; */
- /* look for a Postscript binary file tag, i.e 0x8001 */
- if ( FILE_Seek( 0L ) )
- goto Exit;
-
- error = read_pfb_tag( stream, &tag, &size );
- if ( error )
- goto Exit;
-
- if ( tag != 0x8001 )
- {
- /* assume that this is a PFA file for now; an error will */
- /* be produced later when more things are checked */
- if ( FILE_Seek( 0L ) )
- goto Exit;
- size = stream->size;
- }
- else
- parser->in_pfb = 1;
-
- /* now, try to load `size' bytes of the `base' dictionary we */
- /* found previously */
-
- /* if it is a memory-based resource, set up pointers */
- if ( !stream->read )
- {
- parser->base_dict = (FT_Byte*)stream->base + stream->pos;
- parser->base_len = size;
- parser->in_memory = 1;
-
- /* check that the `size' field is valid */
- if ( FILE_Skip( size ) )
- goto Exit;
- }
- else
- {
- /* read segment in memory */
- if ( ALLOC( parser->base_dict, size ) ||
- FILE_Read( parser->base_dict, size ) )
- goto Exit;
- parser->base_len = size;
- }
-
- /* Now check font format; we must see `%!PS-AdobeFont-1' */
- /* or `%!FontType' */
- {
- if ( size <= 16 ||
- ( strncmp( (const char*)parser->base_dict,
- "%!PS-AdobeFont-1", 16 ) &&
- strncmp( (const char*)parser->base_dict,
- "%!FontType", 10 ) ) )
- {
- FT_TRACE2(( "[not a Type1 font]\n" ));
- error = FT_Err_Unknown_File_Format;
- }
- else
- {
- parser->root.base = parser->base_dict;
- parser->root.cursor = parser->base_dict;
- parser->root.limit = parser->root.cursor + parser->base_len;
- }
- }
-
- Exit:
- if ( error && !parser->in_memory )
- FREE( parser->base_dict );
-
- return error;
- }
-
-
- LOCAL_FUNC
- void Z1_Done_Parser( Z1_Parser* parser )
- {
- FT_Memory memory = parser->root.memory;
-
-
- /* always free the private dictionary */
- FREE( parser->private_dict );
-
- /* free the base dictionary only when we have a disk stream */
- if ( !parser->in_memory )
- FREE( parser->base_dict );
-
- parser->root.funcs.done( &parser->root );
- }
-
-
- /* 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;
- }
-
-
- LOCAL_FUNC
- void Z1_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--;
- }
- }
-
-
- LOCAL_FUNC
- FT_Error Z1_Get_Private_Dict( Z1_Parser* parser )
- {
- FT_Stream stream = parser->stream;
- FT_Memory memory = parser->root.memory;
- FT_Error error = 0;
- FT_Long size;
-
-
- if ( parser->in_pfb )
- {
- /* in the case of the PFB format, the private dictionary can be */
- /* made of several segments. We thus first read the number of */
- /* segments to compute the total size of the private dictionary */
- /* then re-read them into memory. */
- FT_Long start_pos = FILE_Pos();
- FT_UShort tag;
-
-
- parser->private_len = 0;
- for (;;)
- {
- error = read_pfb_tag( stream, &tag, &size );
- if ( error )
- goto Fail;
-
- if ( tag != 0x8002 )
- break;
-
- parser->private_len += size;
-
- if ( FILE_Skip( size ) )
- goto Fail;
- }
-
- /* Check that we have a private dictionary there */
- /* and allocate private dictionary buffer */
- if ( parser->private_len == 0 )
- {
- FT_ERROR(( "Z1_Get_Private_Dict:" ));
- FT_ERROR(( " invalid private dictionary section\n" ));
- error = T1_Err_Invalid_File_Format;
- goto Fail;
- }
-
- if ( FILE_Seek( start_pos ) ||
- ALLOC( parser->private_dict, parser->private_len ) )
- goto Fail;
-
- parser->private_len = 0;
- for (;;)
- {
- error = read_pfb_tag( stream, &tag, &size );
- if ( error || tag != 0x8002 )
- {
- error = FT_Err_Ok;
- break;
- }
-
- if ( FILE_Read( parser->private_dict + parser->private_len, size ) )
- goto Fail;
-
- parser->private_len += size;
- }
- }
- else
- {
- /* we have already `loaded' the whole PFA font file into memory; */
- /* if this is a memory resource, allocate a new block to hold */
- /* the private dict. Otherwise, simply overwrite into the base */
- /* dictionary block in the heap. */
-
- /* first of all, look at the `eexec' keyword */
- FT_Byte* cur = parser->base_dict;
- FT_Byte* limit = cur + parser->base_len;
- FT_Byte c;
-
-
- for (;;)
- {
- c = cur[0];
- if ( c == 'e' && cur + 9 < limit ) /* 9 = 5 letters for `eexec' + */
- /* newline + 4 chars */
- {
- if ( cur[1] == 'e' && cur[2] == 'x' &&
- cur[3] == 'e' && cur[4] == 'c' )
- {
- cur += 6; /* we skip the newling after the `eexec' */
-
- /* XXX: Some fonts use DOS-linefeeds, i.e. \r\n; we need to */
- /* skip the extra \n if we find it */
- if ( cur[0] == '\n' )
- cur++;
-
- break;
- }
- }
- cur++;
- if ( cur >= limit )
- {
- FT_ERROR(( "Z1_Get_Private_Dict:" ));
- FT_ERROR(( " could not find `eexec' keyword\n" ));
- error = T1_Err_Invalid_File_Format;
- goto Exit;
- }
- }
-
- /* now determine where to write the _encrypted_ binary private */
- /* dictionary. We overwrite the base dictionary for disk-based */
- /* resources and allocate a new block otherwise */
-
- size = parser->base_len - ( cur - parser->base_dict);
-
- if ( parser->in_memory )
- {
- /* note that we allocate one more byte to put a terminating `0' */
- if ( ALLOC( parser->private_dict, size + 1 ) )
- goto Fail;
- parser->private_len = size;
- }
- else
- {
- parser->single_block = 1;
- parser->private_dict = parser->base_dict;
- parser->private_len = size;
- parser->base_dict = 0;
- parser->base_len = 0;
- }
-
- /* now determine whether the private dictionary is encoded in binary */
- /* or hexadecimal ASCII format -- decode it accordingly */
-
- /* we need to access the next 4 bytes (after the final \r following */
- /* the `eexec' keyword); if they all are hexadecimal digits, then */
- /* we have a case of ASCII storage */
-
- if ( ( hexa_value( cur[0] ) | hexa_value( cur[1] ) |
- hexa_value( cur[2] ) | hexa_value( cur[3] ) ) < 0 )
-
- /* binary encoding -- `simply' copy the private dict */
- MEM_Copy( parser->private_dict, cur, size );
-
- else
- {
- /* ASCII hexadecimal encoding */
-
- FT_Byte* write;
- FT_Int count;
-
-
- write = parser->private_dict;
- count = 0;
-
- for ( ;cur < limit; cur++ )
- {
- int hex1;
-
-
- /* check for newline */
- if ( cur[0] == '\r' || cur[0] == '\n' )
- continue;
-
- /* exit if we have a non-hexadecimal digit that isn't a newline */
- hex1 = hexa_value( cur[0] );
- if ( hex1 < 0 || cur + 1 >= limit )
- break;
-
- /* otherwise, store byte */
- *write++ = ( hex1 << 4 ) | hexa_value( cur[1] );
- count++;
- cur++;
- }
-
- /* put a safeguard */
- parser->private_len = write - parser->private_dict;
- *write++ = 0;
- }
- }
-
- /* we now decrypt the encoded binary private dictionary */
- Z1_Decrypt( parser->private_dict, parser->private_len, 55665 );
- parser->root.base = parser->private_dict;
- parser->root.cursor = parser->private_dict;
- parser->root.limit = parser->root.cursor + parser->private_len;
-
- Fail:
- Exit:
- return error;
- }
-
-
-/* END */
--- a/src/type1z/z1parse.h
+++ /dev/null
@@ -1,140 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1parse.h */
-/* */
-/* Experimental Type 1 parser (specification). */
-/* */
-/* 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 Z1PARSE_H
-#define Z1PARSE_H
-
-#include <freetype/internal/t1types.h>
-#include <freetype/internal/ftstream.h>
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-
- /*************************************************************************/
- /* */
- /* <Struct> */
- /* Z1_Parser */
- /* */
- /* <Description> */
- /* A Z1_Parser is an object used to parse a Type 1 fonts very */
- /* quickly. */
- /* */
- /* <Fields> */
- /* root :: The root parser. */
- /* */
- /* stream :: The current input stream. */
- /* */
- /* base_dict :: A pointer to the top-level dictionary. */
- /* */
- /* base_len :: The length in bytes of the top dictionary. */
- /* */
- /* private_dict :: A pointer to the private dictionary. */
- /* */
- /* private_len :: The length in bytes of the private dictionary. */
- /* */
- /* in_pfb :: A boolean. Indicates that we are handling a PFB */
- /* file. */
- /* */
- /* in_memory :: A boolean. Indicates a memory-based stream. */
- /* */
- /* single_block :: A boolean. Indicates that the private dictionary */
- /* is stored in lieu of the base dictionary. */
- /* */
- typedef struct Z1_Parser_
- {
- T1_Parser root;
- FT_Stream stream;
-
- FT_Byte* base_dict;
- FT_Int base_len;
-
- FT_Byte* private_dict;
- FT_Int private_len;
-
- FT_Byte in_pfb;
- FT_Byte in_memory;
- FT_Byte single_block;
-
- } Z1_Parser;
-
-
-#define Z1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
-#define Z1_Done_Table( p ) \
- do \
- { \
- if ( (p)->funcs.done ) \
- (p)->funcs.done( p ); \
- } while ( 0 )
-#define Z1_Release_Table( p ) \
- do \
- { \
- if ( (p)->funcs.release ) \
- (p)->funcs.release( p ); \
- } while ( 0 )
-
-
-#define Z1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
-#define Z1_Skip_Alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root )
-
-#define Z1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root )
-#define Z1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t )
-
-#define Z1_ToCoordArray( p, m, c ) \
- (p)->root.funcs.to_coord_array( &(p)->root, m, c )
-#define Z1_ToFixedArray( p, m, f, t ) \
- (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
-#define Z1_ToToken( p, t ) \
- (p)->root.funcs.to_token( &(p)->root, t )
-#define Z1_ToTokenArray( p, t, m, c ) \
- (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
-
-#define Z1_Load_Field( p, f, o, m, pf ) \
- (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
-#define Z1_Load_Field_Table( p, f, o, m, pf ) \
- (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
-
-
- LOCAL_DEF
- FT_Error Z1_New_Parser( Z1_Parser* parser,
- FT_Stream stream,
- FT_Memory memory,
- PSAux_Interface* psaux );
-
- LOCAL_DEF
- FT_Error Z1_Get_Private_Dict( Z1_Parser* parser );
-
- LOCAL_DEF
- void Z1_Decrypt( FT_Byte* buffer,
- FT_Int length,
- FT_UShort seed );
-
- LOCAL_DEF
- void Z1_Done_Parser( Z1_Parser* parser );
-
-
-#ifdef __cplusplus
- }
-#endif
-
-
-#endif /* Z1PARSE_H */
-
-
-/* END */
--- a/src/type1z/z1tokens.h
+++ /dev/null
@@ -1,73 +1,0 @@
-/***************************************************************************/
-/* */
-/* z1tokens.h */
-/* */
-/* Experimental Type 1 tokenizer (specification). */
-/* */
-/* 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. */
-/* */
-/***************************************************************************/
-
-
-#undef FT_STRUCTURE
-#define FT_STRUCTURE T1_FontInfo
-#undef T1CODE
-#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_NUM ( "ItalicAngle", italic_angle )
- T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch )
- T1_FIELD_NUM ( "UnderlinePosition", underline_position )
- T1_FIELD_NUM ( "UnderlineThickness", underline_thickness )
-
-
-#undef FT_STRUCTURE
-#define FT_STRUCTURE T1_Private
-#undef T1CODE
-#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 )
-
-
-#undef FT_STRUCTURE
-#define FT_STRUCTURE T1_Font
-#undef T1CODE
-#define T1CODE t1_field_font_dict
-
- T1_FIELD_NUM( "PaintType", paint_type )
- T1_FIELD_NUM( "FontType", font_type )
- T1_FIELD_NUM( "StrokeWidth", stroke_width )
-
-
-/* END */