Back to index

tetex-bin  3.0
type1.c
Go to the documentation of this file.
00001 /* $XConsortium: type1.c,v 1.5 91/10/10 11:20:06 rws Exp $ */
00002 /* Copyright International Business Machines, Corp. 1991
00003  * All Rights Reserved
00004  * Copyright Lexmark International, Inc. 1991
00005  * All Rights Reserved
00006  * Portions Copyright (c) 1990 Adobe Systems Incorporated.
00007  * All Rights Reserved
00008  *
00009  * License to use, copy, modify, and distribute this software and its
00010  * documentation for any purpose and without fee is hereby granted,
00011  * provided that the above copyright notice appear in all copies and that
00012  * both that copyright notice and this permission notice appear in
00013  * supporting documentation, and that the name of IBM or Lexmark or Adobe
00014  * not be used in advertising or publicity pertaining to distribution of
00015  * the software without specific, written prior permission.
00016  *
00017  * IBM, LEXMARK, AND ADOBE PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY
00018  * WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
00019  * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
00020  * PARTICULAR PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  THE
00021  * ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING
00022  * ANY DUTY TO SUPPORT OR MAINTAIN, BELONGS TO THE LICENSEE.  SHOULD ANY
00023  * PORTION OF THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM,
00024  * LEXMARK, OR ADOBE) ASSUMES THE ENTIRE COST OF ALL SERVICING, REPAIR AND
00025  * CORRECTION.  IN NO EVENT SHALL IBM, LEXMARK, OR ADOBE BE LIABLE FOR ANY
00026  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
00027  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
00028  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
00029  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00030  */
00031  
00032 /*********************************************************************/
00033 /*                                                                   */
00034 /* Type 1 module - Converting fonts in Adobe Type 1 Font Format      */
00035 /*                 to scaled and hinted paths for rasterization.     */
00036 /*                 Files: type1.c, type1.h, and blues.h.             */
00037 /*                                                                   */
00038 /* Authors:   Sten F. Andler, IBM Almaden Research Center            */
00039 /*                 (Type 1 interpreter, stem & flex hints)           */
00040 /*                                                                   */
00041 /*            Patrick A. Casey, Lexmark International, Inc.          */
00042 /*                 (Font level hints & stem hints)                   */
00043 /*                                                                   */
00044 /*********************************************************************/
00045  
00046 /******************/
00047 /* Include Files: */
00048 /******************/
00049 #include  "types.h"
00050 #include  <stdio.h>          /* a system-dependent include, usually */
00051  
00052 #include  "objects.h"
00053 #include  "spaces.h"
00054 #include  "paths.h"
00055 #include  "fonts.h"        /* understands about TEXTTYPEs */
00056 #include  "pictures.h"     /* understands about handles */
00057  
00058 typedef struct xobject xobject;
00059 #include  "util.h"       /* PostScript objects */
00060 #include  "blues.h"          /* Blues structure for font-level hints */
00061  
00062 /**********************************/
00063 /* Type1 Constants and Structures */
00064 /**********************************/
00065 #define MAXSTACK 24        /* Adobe Type1 limit */
00066 #define MAXCALLSTACK 10    /* Adobe Type1 limit */
00067 #define MAXPSFAKESTACK 32  /* Max depth of fake PostScript stack (local) */
00068 #define MAXSTRLEN 512      /* Max length of a Type 1 string (local) */
00069 #define MAXLABEL 256       /* Maximum number of new hints */
00070 #define MAXSTEMS 128       /* Maximum number of VSTEM and HSTEM hints */
00071 #define EPS 0.001          /* Small number for comparisons */
00072  
00073 /************************************/
00074 /* Adobe Type 1 CharString commands */
00075 /************************************/
00076 #define HSTEM        1
00077 #define VSTEM        3
00078 #define VMOVETO      4
00079 #define RLINETO      5
00080 #define HLINETO      6
00081 #define VLINETO      7
00082 #define RRCURVETO    8
00083 #define CLOSEPATH    9
00084 #define CALLSUBR    10
00085 #define RETURN      11
00086 #define ESCAPE      12
00087 #define HSBW        13
00088 #define ENDCHAR     14
00089 #define RMOVETO     21
00090 #define HMOVETO     22
00091 #define VHCURVETO   30
00092 #define HVCURVETO   31
00093  
00094 /*******************************************/
00095 /* Adobe Type 1 CharString Escape commands */
00096 /*******************************************/
00097 #define DOTSECTION       0
00098 #define VSTEM3           1
00099 #define HSTEM3           2
00100 #define SEAC             6
00101 #define SBW              7
00102 #define DIV             12
00103 #define CALLOTHERSUBR   16
00104 #define POP             17
00105 #define SETCURRENTPOINT 33
00106  
00107 /*****************/
00108 /* Useful macros */
00109 /*****************/
00110 static DOUBLE tmpx;  /* Store macro argument in tmpx to avoid re-evaluation */
00111 static LONG tmpi;    /* Store converted value in tmpi to avoid re-evaluation */
00112  
00113 #define FABS(x) (((tmpx = (x)) < 0.0) ? -tmpx : tmpx)
00114  
00115 #define CEIL(x) (((tmpi = (LONG) (tmpx = (x))) < tmpx) ? ++tmpi : tmpi)
00116  
00117 #define FLOOR(x) (((tmpi = (LONG) (tmpx = (x))) > tmpx) ? --tmpi : tmpi)
00118  
00119 #define ROUND(x) FLOOR((x) + 0.5)
00120  
00121 #define ODD(x) (((int)(x)) & 01)
00122 
00123 int currentchar = -1; /* for error reporting */
00124 
00125 #define CC IfTrace1(TRUE, "'%03o ", currentchar)
00126 
00127 #define Error {errflag = TRUE; return;}
00128  
00129 #define Error0(errmsg) { CC; IfTrace0(TRUE, errmsg); Error;}
00130  
00131 #define Error1(errmsg,arg) { CC; IfTrace1(TRUE, errmsg, arg); Error;}
00132  
00133 /********************/
00134 /* global variables */
00135 /********************/
00136 struct stem {                     /* representation of a STEM hint */
00137     int vertical;                 /* TRUE if vertical, FALSE otherwise */
00138     DOUBLE x, dx;                 /* interval of vertical stem */
00139     DOUBLE y, dy;                 /* interval of horizontal stem */
00140     struct segment *lbhint, *lbrevhint;   /* left  or bottom hint adjustment */
00141     struct segment *rthint, *rtrevhint;   /* right or top    hint adjustment */
00142 };
00143  
00144 extern struct XYspace *IDENTITY;
00145  
00146 static DOUBLE escapementX, escapementY;
00147 static DOUBLE sidebearingX, sidebearingY;
00148 static DOUBLE accentoffsetX, accentoffsetY;
00149  
00150 static struct segment *path;
00151 static int errflag;
00152  
00153 /*************************************************/
00154 /* Global variables to hold Type1Char parameters */
00155 /*************************************************/
00156 static char *Environment;
00157 static struct XYspace *CharSpace;
00158 static psobj *CharStringP, *SubrsP, *OtherSubrsP;
00159 static int *ModeP;
00160  
00161 /************************/
00162 /* Forward declarations */
00163 /************************/
00164 #ifdef WIN32
00165 /* Unfortunately, there is such a function in the Win32 API */
00166 #define Escape Type1Escape
00167 #endif
00168 #ifdef KPATHSEA
00169 static void ComputeAlignmentZones P1H(void);
00170 static void InitStems P1H(void);
00171 static void FinitStems P1H(void);
00172 static void ComputeStem P1H(int stemno);
00173 static struct segment *Applyhint P3H(struct segment *p,int stemnumber,int half);
00174 static struct segment *Applyrevhint P3H(struct segment *p,int stemnumber,int half);
00175 static struct segment *FindStems P4H(DOUBLE x,DOUBLE y,DOUBLE dx,DOUBLE dy);
00176 static void ClearStack P1H(void);
00177 static void Push P1H(DOUBLE Num);
00178 static void ClearCallStack P1H(void);
00179 static void PushCall P3H(psobj *CurrStrP,int CurrIndex,unsigned short CurrKey);
00180 static void PopCall P3H(psobj **CurrStrPP ,int *CurrIndexP,unsigned short *CurrKeyP);
00181 static void ClearPSFakeStack P1H(void);
00182 static void PSFakePush P1H(DOUBLE Num);
00183 static DOUBLE PSFakePop P1H(void);
00184 static struct segment *CenterStem P2H(DOUBLE edge1,DOUBLE edge2);
00185 static unsigned char Decrypt P1H(unsigned char cipher);
00186 static int DoRead P1H(int *CodeP);
00187 static void StartDecrypt P1H(void);
00188 static void Decode P1H(int Code);
00189 static void DoCommand P1H(int Code);
00190 static void Escape P1H(int Code);
00191 static void HStem P2H(DOUBLE y,DOUBLE dy);
00192 static void VStem P2H(DOUBLE x,DOUBLE dx);
00193 static void RLineTo P2H(DOUBLE dx,DOUBLE dy);
00194 static void RRCurveTo P6H(DOUBLE dx1,DOUBLE dy1,DOUBLE dx2,DOUBLE dy2,DOUBLE dx3,DOUBLE dy3);
00195 static void DoClosePath P1H(void);
00196 static void CallSubr P1H(int subrno);
00197 static void Return P1H(void);
00198 static void EndChar P1H(void);
00199 static void RMoveTo P2H(DOUBLE dx,DOUBLE dy);
00200 static void DotSection P1H(void);
00201 static void Seac P5H(DOUBLE asb,DOUBLE adx,DOUBLE ady,unsigned char bchar,unsigned char achar);
00202 static void Sbw P4H(DOUBLE sbx,DOUBLE sby,DOUBLE wx,DOUBLE wy);
00203 static DOUBLE Div P2H(DOUBLE num1,DOUBLE num2);
00204 static void FlxProc AA((DOUBLE c1x2,DOUBLE c1y2,DOUBLE c3x0,DOUBLE c3y0,DOUBLE c3x1,DOUBLE c3y1,DOUBLE c3x2,DOUBLE c3y2,DOUBLE c4x0,DOUBLE c4y0,DOUBLE c4x1,DOUBLE c4y1,DOUBLE c4x2,DOUBLE c4y2,DOUBLE epY,DOUBLE epX,int idmin));
00205 static void FlxProc1 P1H(void);
00206 static void FlxProc2 P1H(void);
00207 static void HintReplace P1H(void);
00208 static void CallOtherSubr P1H(int othersubrno);
00209 static void SetCurrentPoint P2H(DOUBLE x,DOUBLE y);
00210 extern struct xobject *Type1Char AA((char *env,struct XYspace *S,psobj *charstrP,psobj *subrsP,psobj *osubrsP,struct blues_struct *bluesP,int *modeP));
00211 #else
00212 static DOUBLE Div();
00213 static DOUBLE PSFakePop();
00214 static DoCommand();
00215 static Escape();
00216 static HStem();
00217 static VStem();
00218 static RLineTo();
00219 static RRCurveTo();
00220 static DoClosePath();
00221 static CallSubr();
00222 static Return();
00223 static EndChar();
00224 static RMoveTo();
00225 static DotSection();
00226 static Seac();
00227 static Sbw();
00228 static CallOtherSubr();
00229 static SetCurrentPoint();
00230 #endif
00231 /*****************************************/
00232 /* statics for Flex procedures (FlxProc) */
00233 /*****************************************/
00234 static struct segment *FlxOldPath; /* save path before Flex feature */
00235  
00236 /******************************************************/
00237 /* statics for Font level hints (Blues) (see blues.h) */
00238 /******************************************************/
00239 static struct blues_struct *blues; /* the blues structure */
00240 static struct alignmentzone alignmentzones[MAXALIGNMENTZONES];
00241 int numalignmentzones;          /* total number of alignment zones */
00242  
00243 /****************************************************************/
00244 /* Subroutines for the Font level hints (Alignment zones, etc.) */
00245 /****************************************************************/
00246  
00247 /******************************************/
00248 /* Fill in the alignment zone structures. */
00249 /******************************************/
00250 static void ComputeAlignmentZones()
00251 {
00252   int i;
00253   DOUBLE dummy, bluezonepixels, familyzonepixels;
00254   struct segment *p;
00255  
00256   numalignmentzones = 0;     /* initialize total # of zones */
00257  
00258   /* do the BlueValues zones */
00259   for (i = 0; i < blues->numBlueValues; i +=2, ++numalignmentzones) {
00260     /* the 0th & 1st numbers in BlueValues are for a bottom zone */
00261     /* the rest are topzones */
00262     if (i == 0)           /* bottom zone */
00263       alignmentzones[numalignmentzones].topzone = FALSE;
00264     else                  /* top zone */
00265       alignmentzones[numalignmentzones].topzone = TRUE;
00266     if (i < blues->numFamilyBlues) {    /* we must consider FamilyBlues */
00267       p = ILoc(CharSpace,0,blues->BlueValues[i] - blues->BlueValues[i+1]);
00268       QueryLoc(p, IDENTITY, &dummy, &bluezonepixels);
00269       Destroy(p);
00270       p = ILoc(CharSpace,0,blues->FamilyBlues[i]-blues->FamilyBlues[i+1]);
00271       QueryLoc(p, IDENTITY, &dummy, &familyzonepixels);
00272       Destroy(p);
00273       /* is the difference in size of the zones less than 1 pixel? */
00274       if (FABS(bluezonepixels - familyzonepixels) < 1.0) {
00275         /* use the Family zones */
00276         alignmentzones[numalignmentzones].bottomy =
00277           blues->FamilyBlues[i];
00278         alignmentzones[numalignmentzones].topy =
00279           blues->FamilyBlues[i+1];
00280         continue;
00281       }
00282     }
00283     /* use this font's Blue zones */
00284     alignmentzones[numalignmentzones].bottomy = blues->BlueValues[i];
00285     alignmentzones[numalignmentzones].topy = blues->BlueValues[i+1];
00286   }
00287  
00288   /* do the OtherBlues zones */
00289   for (i = 0; i < blues->numOtherBlues; i +=2, ++numalignmentzones) {
00290     /* all of the OtherBlues zones are bottom zones */
00291     alignmentzones[numalignmentzones].topzone = FALSE;
00292     if (i < blues->numFamilyOtherBlues) {/* consider FamilyOtherBlues  */
00293       p = ILoc(CharSpace,0,blues->OtherBlues[i] - blues->OtherBlues[i+1]);
00294       QueryLoc(p, IDENTITY, &dummy, &bluezonepixels);
00295       Destroy(p);
00296       p = ILoc(CharSpace,0,blues->FamilyOtherBlues[i] -
00297         blues->FamilyOtherBlues[i+1]);
00298       QueryLoc(p, IDENTITY, &dummy, &familyzonepixels);
00299       Destroy(p);
00300       /* is the difference in size of the zones less than 1 pixel? */
00301       if (FABS(bluezonepixels - familyzonepixels) < 1.0) {
00302         /* use the Family zones */
00303         alignmentzones[numalignmentzones].bottomy =
00304           blues->FamilyOtherBlues[i];
00305         alignmentzones[numalignmentzones].topy =
00306           blues->FamilyOtherBlues[i+1];
00307         continue;
00308       }
00309     }
00310     /* use this font's Blue zones (as opposed to the Family Blues */
00311     alignmentzones[numalignmentzones].bottomy = blues->OtherBlues[i];
00312     alignmentzones[numalignmentzones].topy = blues->OtherBlues[i+1];
00313   }
00314 }
00315  
00316 /**********************************************************************/
00317 /* Subroutines and statics for handling of the VSTEM and HSTEM hints. */
00318 /**********************************************************************/
00319 int InDotSection;             /* DotSection flag */
00320 struct stem stems[MAXSTEMS];  /* All STEM hints */
00321 int numstems;                 /* Number of STEM hints */
00322 int currstartstem;            /* The current starting stem. */
00323 int oldvert, oldhor;          /* Remember hint in effect */
00324 int oldhorhalf, oldverthalf;  /* Remember which half of the stem */
00325 DOUBLE wsoffsetX, wsoffsetY;  /* White space offset - for VSTEM3,HSTEM3 */
00326 int wsset;                    /* Flag for whether we've set wsoffsetX,Y */
00327  
00328 static void InitStems()  /* Initialize the STEM hint data structures */
00329 {
00330   InDotSection = FALSE;
00331   currstartstem = numstems = 0;
00332   oldvert = oldhor = -1;
00333 }
00334  
00335 static void FinitStems()  /* Terminate the STEM hint data structures */
00336 {
00337   int i;
00338  
00339   for (i = 0; i < numstems; i++) {
00340     Destroy(stems[i].lbhint);
00341     Destroy(stems[i].lbrevhint);
00342     Destroy(stems[i].rthint);
00343     Destroy(stems[i].rtrevhint);
00344   }
00345 }
00346  
00347 /*******************************************************************/
00348 /* Compute the dislocation that a stemhint should cause for points */
00349 /* inside the stem.                                                */
00350 /*******************************************************************/
00351 static void ComputeStem(stemno)
00352 int stemno;
00353 {
00354   int verticalondevice, idealwidth;
00355   DOUBLE stemstart, stemwidth;
00356   struct segment *p;
00357   int i;
00358   DOUBLE stembottom, stemtop, flatposition;
00359   DOUBLE Xpixels, Ypixels;
00360   DOUBLE unitpixels, onepixel;
00361   int suppressovershoot, enforceovershoot;
00362   DOUBLE stemshift, flatpospixels, overshoot;
00363   DOUBLE widthdiff; /* Number of character space units to adjust width */
00364   DOUBLE lbhintvalue, rthintvalue;
00365   DOUBLE cxx, cyx, cxy, cyy; /* Transformation matrix */
00366   int rotated; /* TRUE if character is on the side, FALSE if upright */
00367  
00368   /************************************************/
00369   /* DETERMINE ORIENTATION OF CHARACTER ON DEVICE */
00370   /************************************************/
00371  
00372   QuerySpace(CharSpace, &cxx, &cyx, &cxy, &cyy); /* Transformation matrix */
00373  
00374   if (FABS(cxx) < 0.00001 || FABS(cyy) < 0.00001)
00375     rotated = TRUE; /* Char is on side (90 or 270 degrees), possibly oblique. */
00376   else if (FABS(cyx) < 0.00001 || FABS(cxy) < 0.00001)
00377     rotated = FALSE; /* Char is upright (0 or 180 degrees), possibly oblique. */
00378   else {
00379     stems[stemno].lbhint = NULL; /* Char is at non-axial angle, ignore hints. */
00380     stems[stemno].lbrevhint = NULL;
00381     stems[stemno].rthint = NULL;
00382     stems[stemno].rtrevhint = NULL;
00383     return;
00384   }
00385  
00386   /* Determine orientation of stem */
00387  
00388   if (stems[stemno].vertical) {
00389     verticalondevice = !rotated;
00390     stemstart = stems[stemno].x;
00391     stemwidth = stems[stemno].dx;
00392   } else {
00393     verticalondevice = rotated;
00394     stemstart = stems[stemno].y;
00395     stemwidth = stems[stemno].dy;
00396   }
00397  
00398   /* Determine how many pixels (non-negative) correspond to 1 character space
00399      unit (unitpixels), and how many character space units (non-negative)
00400      correspond to one pixel (onepixel). */
00401  
00402   if (stems[stemno].vertical)
00403     p = ILoc(CharSpace, 1, 0);
00404   else
00405     p = ILoc(CharSpace, 0, 1);
00406   QueryLoc(p, IDENTITY, &Xpixels, &Ypixels);
00407   Destroy(p);
00408   if (verticalondevice)
00409     unitpixels = FABS(Xpixels);
00410   else
00411     unitpixels = FABS(Ypixels);
00412  
00413   onepixel = 1.0 / unitpixels;
00414  
00415   /**********************/
00416   /* ADJUST STEM WIDTHS */
00417   /**********************/
00418  
00419   widthdiff = 0.0;
00420  
00421   /* Find standard stem with smallest width difference from this stem */
00422   if (stems[stemno].vertical) { /* vertical stem */
00423     if (blues->StdVW != 0)      /* there is an entry for StdVW */
00424       widthdiff = blues->StdVW - stemwidth;
00425     for (i = 0; i < blues->numStemSnapV; ++i) { /* now look at StemSnapV */
00426       if (blues->StemSnapV[i] - stemwidth < widthdiff)
00427         /* this standard width is the best match so far for this stem */
00428         widthdiff = blues->StemSnapV[i] - stemwidth;
00429     }
00430   } else {                      /* horizontal stem */
00431     if (blues->StdHW != 0)      /* there is an entry for StdHW */
00432       widthdiff = blues->StdHW - stemwidth;
00433     for (i = 0; i < blues->numStemSnapH; ++i) { /* now look at StemSnapH */
00434       if (blues->StemSnapH[i] - stemwidth < widthdiff)
00435         /* this standard width is the best match so far for this stem */
00436         widthdiff = blues->StemSnapH[i] - stemwidth;
00437     }
00438   }
00439  
00440   /* Only expand or contract stems if they differ by less than 1 pixel from
00441      the closest standard width, otherwise make the width difference = 0. */
00442   if (FABS(widthdiff) > onepixel)
00443     widthdiff = 0.0;
00444  
00445   /* Expand or contract stem to the nearest integral number of pixels. */
00446   idealwidth = ROUND((stemwidth + widthdiff) * unitpixels);
00447   /* Ensure that all stems are at least one pixel wide. */
00448   if (idealwidth == 0)
00449     idealwidth = 1;
00450   /* Apply ForceBold to vertical stems. */
00451   if (blues->ForceBold && stems[stemno].vertical)
00452     /* Force this vertical stem to be at least DEFAULTBOLDSTEMWIDTH wide. */
00453     if (idealwidth < DEFAULTBOLDSTEMWIDTH)
00454       idealwidth = DEFAULTBOLDSTEMWIDTH;
00455   /* Now compute the number of character space units necessary */
00456   widthdiff = idealwidth * onepixel - stemwidth;
00457  
00458   /*********************************************************************/
00459   /* ALIGNMENT ZONES AND OVERSHOOT SUPPRESSION - HORIZONTAL STEMS ONLY */
00460   /*********************************************************************/
00461  
00462   stemshift = 0.0;
00463  
00464   if (!stems[stemno].vertical) {
00465  
00466     /* Get bottom and top boundaries of the stem. */
00467     stembottom = stemstart;
00468     stemtop = stemstart + stemwidth;
00469  
00470     /* Find out if this stem intersects an alignment zone (the BlueFuzz  */
00471     /* entry in the Private dictionary specifies the number of character */
00472     /* units to extend (in both directions) the effect of an alignment   */
00473     /* zone on a horizontal stem.  The default value of BlueFuzz is 1.   */
00474     for (i = 0; i < numalignmentzones; ++i) {
00475       if (alignmentzones[i].topzone) {
00476         if (stemtop >= alignmentzones[i].bottomy &&
00477             stemtop <= alignmentzones[i].topy + blues->BlueFuzz) {
00478           break; /* We found a top-zone */
00479         }
00480       } else {
00481         if (stembottom <= alignmentzones[i].topy &&
00482             stembottom >= alignmentzones[i].bottomy - blues->BlueFuzz) {
00483           break; /* We found a bottom-zone */
00484         }
00485       }
00486     }
00487  
00488     if (i < numalignmentzones) { /* We found an intersecting zone (number i). */
00489       suppressovershoot = FALSE;
00490       enforceovershoot = FALSE;
00491  
00492       /* When 1 character space unit is rendered smaller than BlueScale
00493          device units (pixels), we must SUPPRESS overshoots.  Otherwise,
00494          if the top (or bottom) of this stem is more than BlueShift character
00495          space units away from the flat position, we must ENFORCE overshoot. */
00496  
00497       if (unitpixels < blues->BlueScale)
00498         suppressovershoot = TRUE;
00499       else
00500         if (alignmentzones[i].topzone)
00501           if (stemtop >= alignmentzones[i].bottomy + blues->BlueShift)
00502             enforceovershoot = TRUE;
00503         else
00504           if (stembottom <= alignmentzones[i].topy - blues->BlueShift)
00505             enforceovershoot = TRUE;
00506  
00507       /*************************************************/
00508       /* ALIGN THE FLAT POSITION OF THE ALIGNMENT ZONE */
00509       /*************************************************/
00510  
00511       /* Compute the position of the alignment zone's flat position in
00512          device space and the amount of shift needed to align it on a
00513          pixel boundary. Move all stems this amount. */
00514  
00515       if (alignmentzones[i].topzone)
00516         flatposition = alignmentzones[i].bottomy;
00517       else
00518         flatposition = alignmentzones[i].topy;
00519  
00520       /* Find the flat position in pixels */
00521       flatpospixels = flatposition * unitpixels;
00522  
00523       /* Find the stem shift necessary to align the flat
00524          position on a pixel boundary, and use this shift for all stems */
00525       stemshift = (ROUND(flatpospixels) - flatpospixels) * onepixel;
00526  
00527       /************************************************/
00528       /* HANDLE OVERSHOOT ENFORCEMENT AND SUPPRESSION */
00529       /************************************************/
00530  
00531       /* Compute overshoot amount (non-negative) */
00532       if (alignmentzones[i].topzone)
00533         overshoot = stemtop - flatposition;
00534       else
00535         overshoot = flatposition - stembottom;
00536  
00537       if (overshoot > 0.0) {
00538         /* ENFORCE overshoot by shifting the entire stem (if necessary) so that
00539            it falls at least one pixel beyond the flat position. */
00540  
00541         if (enforceovershoot)
00542           if (overshoot < onepixel)
00543             if (alignmentzones[i].topzone)
00544               stemshift += onepixel - overshoot;
00545             else
00546               stemshift -= onepixel - overshoot;
00547  
00548         /* SUPPRESS overshoot by aligning the stem to the alignment zone's
00549            flat position. */
00550  
00551         if (suppressovershoot)
00552           if (alignmentzones[i].topzone)
00553             stemshift -= overshoot;
00554           else
00555             stemshift += overshoot;
00556       }
00557  
00558       /************************************************************/
00559       /* COMPUTE HINT VALUES FOR EACH SIDE OF THE HORIZONTAL STEM */
00560       /************************************************************/
00561  
00562       /* If the stem was aligned by a topzone, we expand or contract the stem
00563          only at the bottom - since the stem top was aligned by the zone.
00564          If the stem was aligned by a bottomzone, we expand or contract the stem
00565          only at the top - since the stem bottom was aligned by the zone. */
00566       if (alignmentzones[i].topzone) {
00567         lbhintvalue = stemshift - widthdiff; /* bottom */
00568         rthintvalue = stemshift;             /* top    */
00569       } else {
00570         lbhintvalue = stemshift;             /* bottom */
00571         rthintvalue = stemshift + widthdiff; /* top    */
00572       }
00573  
00574       stems[stemno].lbhint    = (struct segment *)Permanent(Loc(CharSpace, 0.0,  lbhintvalue));
00575       stems[stemno].lbrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -lbhintvalue));
00576       stems[stemno].rthint    = (struct segment *)Permanent(Loc(CharSpace, 0.0,  rthintvalue));
00577       stems[stemno].rtrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -rthintvalue));
00578  
00579       return;
00580  
00581     } /* endif (i < numalignmentzones) */
00582  
00583     /* We didn't find any alignment zones intersecting this stem, so
00584        proceed with normal stem alignment below. */
00585  
00586   } /* endif (!stems[stemno].vertical) */
00587  
00588   /* Align stem with pixel boundaries on device */
00589   stemstart = stemstart - widthdiff / 2;
00590   stemshift = ROUND(stemstart * unitpixels) * onepixel - stemstart;
00591  
00592   /* Adjust the boundaries of the stem */
00593   lbhintvalue = stemshift - widthdiff / 2; /* left  or bottom */
00594   rthintvalue = stemshift + widthdiff / 2; /* right or top    */
00595  
00596   if (stems[stemno].vertical) {
00597     stems[stemno].lbhint    = (struct segment *)Permanent(Loc(CharSpace,  lbhintvalue, 0.0));
00598     stems[stemno].lbrevhint = (struct segment *)Permanent(Loc(CharSpace, -lbhintvalue, 0.0));
00599     stems[stemno].rthint    = (struct segment *)Permanent(Loc(CharSpace,  rthintvalue, 0.0));
00600     stems[stemno].rtrevhint = (struct segment *)Permanent(Loc(CharSpace, -rthintvalue, 0.0));
00601   } else {
00602     stems[stemno].lbhint    = (struct segment *)Permanent(Loc(CharSpace, 0.0,  lbhintvalue));
00603     stems[stemno].lbrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -lbhintvalue));
00604     stems[stemno].rthint    = (struct segment *)Permanent(Loc(CharSpace, 0.0,  rthintvalue));
00605     stems[stemno].rtrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -rthintvalue));
00606   }
00607 }
00608  
00609 #define LEFT   1
00610 #define RIGHT  2
00611 #define BOTTOM 3
00612 #define TOP    4
00613  
00614 /*********************************************************************/
00615 /* Adjust a point using the given stem hint.  Use the left/bottom    */
00616 /* hint value or the right/top hint value depending on where the     */
00617 /* point lies in the stem.                                           */
00618 /*********************************************************************/
00619 static struct segment *Applyhint(p, stemnumber, half)
00620 struct segment *p;
00621 int stemnumber, half;
00622 {
00623   if (half == LEFT || half == BOTTOM)
00624     return Join(p, stems[stemnumber].lbhint); /* left  or bottom hint */
00625   else
00626     return Join(p, stems[stemnumber].rthint); /* right or top    hint */
00627 }
00628  
00629 /*********************************************************************/
00630 /* Adjust a point using the given reverse hint.  Use the left/bottom */
00631 /* hint value or the right/top hint value depending on where the     */
00632 /* point lies in the stem.                                           */
00633 /*********************************************************************/
00634 static struct segment *Applyrevhint(p, stemnumber, half)
00635 struct segment *p;
00636 int stemnumber, half;
00637 {
00638   if (half == LEFT || half == BOTTOM)
00639     return Join(p, stems[stemnumber].lbrevhint); /* left  or bottom hint */
00640   else
00641     return Join(p, stems[stemnumber].rtrevhint); /* right or top    hint */
00642 }
00643  
00644 /***********************************************************************/
00645 /* Find the vertical and horizontal stems that the current point       */
00646 /* (x, y) may be involved in.  At most one horizontal and one vertical */
00647 /* stem can apply to a single point, since there are no overlaps       */
00648 /* allowed.                                                            */
00649 /*   The actual hintvalue is returned as a location.                   */
00650 /* Hints are ignored inside a DotSection.                              */
00651 /***********************************************************************/
00652 static struct segment *FindStems(x, y, dx, dy)
00653 DOUBLE x, y, dx, dy;
00654 {
00655   int i;
00656   int newvert, newhor;
00657   struct segment *p;
00658   int newhorhalf, newverthalf;
00659  
00660   if (InDotSection) return(NULL);
00661  
00662   newvert = newhor = -1;
00663   newhorhalf = newverthalf = -1;
00664  
00665   for (i = currstartstem; i < numstems; i++) {
00666     if (stems[i].vertical) { /* VSTEM hint */
00667       if ((x >= stems[i].x - EPS) &&
00668           (x <= stems[i].x+stems[i].dx + EPS)) {
00669         newvert = i;
00670         if (dy != 0.0) {
00671           if (dy < 0) newverthalf = LEFT;
00672           else        newverthalf = RIGHT;
00673         } else {
00674           if (x < stems[i].x+stems[i].dx / 2) newverthalf = LEFT;
00675           else                                newverthalf = RIGHT;
00676         }
00677       }
00678     } else {                 /* HSTEM hint */
00679       if ((y >= stems[i].y - EPS) &&
00680           (y <= stems[i].y+stems[i].dy + EPS)) {
00681         newhor = i;
00682         if (dx != 0.0) {
00683           if (dx < 0) newhorhalf = TOP;
00684           else        newhorhalf = BOTTOM;
00685         } else {
00686           if (y < stems[i].y+stems[i].dy / 2) newhorhalf = BOTTOM;
00687           else                                newhorhalf = TOP;
00688         }
00689       }
00690     }
00691   }
00692  
00693   p = NULL;
00694  
00695   if (newvert == -1 && oldvert == -1) ; /* Outside of any hints */
00696   else if (newvert == oldvert &&
00697     newverthalf == oldverthalf); /* No hint change */
00698   else if (oldvert == -1) { /* New vertical hint in effect */
00699     p = Applyhint(p, newvert, newverthalf);
00700   } else if (newvert == -1) { /* Old vertical hint no longer in effect */
00701     p = Applyrevhint(p, oldvert, oldverthalf);
00702   } else { /* New vertical hint in effect, old hint no longer in effect */
00703     p = Applyrevhint(p, oldvert, oldverthalf);
00704     p = Applyhint(p, newvert, newverthalf);
00705   }
00706  
00707   if (newhor == -1 && oldhor == -1) ; /* Outside of any hints */
00708   else if (newhor == oldhor &&
00709     newhorhalf == oldhorhalf) ; /* No hint change */
00710   else if (oldhor == -1) { /* New horizontal hint in effect */
00711     p = Applyhint(p, newhor, newhorhalf);
00712   } else if (newhor == -1) { /* Old horizontal hint no longer in effect */
00713     p = Applyrevhint(p, oldhor, oldhorhalf);
00714   }
00715   else { /* New horizontal hint in effect, old hint no longer in effect */
00716     p = Applyrevhint(p, oldhor, oldhorhalf);
00717     p = Applyhint(p, newhor, newhorhalf);
00718   }
00719  
00720   oldvert = newvert; oldverthalf = newverthalf;
00721   oldhor  = newhor;  oldhorhalf  = newhorhalf;
00722  
00723   return p;
00724 }
00725  
00726 /******************************************************/
00727 /* Subroutines and statics for the Type1Char routines */
00728 /******************************************************/
00729  
00730 static int strindex; /* index into PostScript string being interpreted */
00731 static DOUBLE currx, curry; /* accumulated x and y values for hints */
00732  
00733 struct callstackentry {
00734   psobj *currstrP;        /* current CharStringP */
00735   int currindex;          /* current strindex */
00736   unsigned short currkey; /* current decryption key */
00737   };
00738  
00739 static DOUBLE Stack[MAXSTACK];
00740 static int Top;
00741 static struct callstackentry CallStack[MAXCALLSTACK];
00742 static int CallTop;
00743 static DOUBLE PSFakeStack[MAXPSFAKESTACK];
00744 static int PSFakeTop;
00745  
00746 static void ClearStack()
00747 {
00748   Top = -1;
00749 }
00750  
00751 static void Push(Num)
00752         DOUBLE Num;
00753 {
00754   if (++Top < MAXSTACK) Stack[Top] = Num;
00755   else Error0("Push: Stack full\n");
00756 }
00757  
00758 static void ClearCallStack()
00759 {
00760   CallTop = -1;
00761 }
00762  
00763 static void PushCall(psobj *CurrStrP, int CurrIndex, unsigned short CurrKey)
00764 {
00765   if (++CallTop < MAXCALLSTACK) {
00766     CallStack[CallTop].currstrP = CurrStrP;   /* save CharString pointer */
00767     CallStack[CallTop].currindex = CurrIndex; /* save CharString index */
00768     CallStack[CallTop].currkey = CurrKey;     /* save decryption key */
00769   }
00770   else Error0("PushCall: Stack full\n");
00771 }
00772  
00773 static void PopCall(CurrStrPP, CurrIndexP, CurrKeyP)
00774   psobj **CurrStrPP;
00775   int *CurrIndexP;
00776   unsigned short *CurrKeyP;
00777 {
00778   if (CallTop >= 0) {
00779     *CurrStrPP = CallStack[CallTop].currstrP; /* restore CharString pointer */
00780     *CurrIndexP = CallStack[CallTop].currindex; /* restore CharString index */
00781     *CurrKeyP = CallStack[CallTop--].currkey;   /* restore decryption key */
00782   }
00783   else Error0("PopCall: Stack empty\n");
00784 }
00785  
00786 static void ClearPSFakeStack()
00787 {
00788   PSFakeTop = -1;
00789 }
00790  
00791 /* PSFakePush: Pushes a number onto the fake PostScript stack */
00792 static void PSFakePush(Num)
00793   DOUBLE Num;
00794 {
00795   if (++PSFakeTop < MAXPSFAKESTACK) PSFakeStack[PSFakeTop] = Num;
00796   else Error0("PSFakePush: Stack full\n");
00797 }
00798  
00799 /* PSFakePop: Removes a number from the top of the fake PostScript stack */
00800 static DOUBLE PSFakePop ()
00801 {
00802   if (PSFakeTop >= 0) return(PSFakeStack[PSFakeTop--]);
00803   else Error0("PSFakePop : Stack empty\n");
00804   /*NOTREACHED*/
00805 }
00806  
00807 /***********************************************************************/
00808 /* Center a stem on the pixel grid -- used by HStem3 and VStem3        */
00809 /***********************************************************************/
00810 static struct segment *CenterStem(edge1, edge2)
00811     DOUBLE edge1;
00812     DOUBLE edge2;
00813 {
00814   int idealwidth, verticalondevice;
00815   DOUBLE leftx, lefty, rightx, righty, center, width;
00816   DOUBLE widthx, widthy;
00817   DOUBLE shift, shiftx, shifty;
00818   DOUBLE Xpixels, Ypixels;
00819   struct segment *p;
00820  
00821   p = Loc(CharSpace, edge1, 0.0);
00822   QueryLoc(p, IDENTITY, &leftx, &lefty);
00823  
00824   p = Join(p, Loc(CharSpace, edge2, 0.0));
00825   QueryLoc(p, IDENTITY, &rightx, &righty);
00826   Destroy(p);
00827  
00828   widthx = FABS(rightx - leftx);
00829   widthy = FABS(righty - lefty);
00830  
00831   if (widthy <= EPS) { /* verticalondevice hint */
00832     verticalondevice = TRUE;
00833     center = (rightx + leftx) / 2.0;
00834     width = widthx;
00835   }
00836   else if (widthx <= EPS) { /* horizontal hint */
00837     verticalondevice = FALSE;
00838     center = (righty + lefty) / 2.0;
00839     width = widthy;
00840   }
00841   else { /* neither horizontal nor verticalondevice and not oblique */
00842     return (NULL);
00843   }
00844  
00845   idealwidth = ROUND(width);
00846   if (idealwidth == 0) idealwidth = 1;
00847   if (ODD(idealwidth)) {       /* is ideal width odd? */
00848     /* center stem over pixel */
00849     shift = FLOOR(center) + 0.5 - center;
00850   }
00851   else {
00852     /* align stem on pixel boundary */
00853     shift = ROUND(center) - center;
00854   }
00855  
00856   if (verticalondevice) {
00857     shiftx = shift;
00858     shifty = 0.0;
00859   } else {
00860     shifty = shift;
00861     shiftx = 0.0;
00862   }
00863  
00864   p = Loc(IDENTITY, shiftx, shifty);
00865   QueryLoc(p, CharSpace, &Xpixels, &Ypixels);
00866   wsoffsetX = Xpixels; wsoffsetY = Ypixels;
00867   currx += wsoffsetX; curry += wsoffsetY;
00868  
00869   return (p);
00870 }
00871  
00872 /*-----------------------------------------------------------------------
00873   Decrypt - From Adobe Type 1 book page 63, with some modifications
00874 -----------------------------------------------------------------------*/
00875 #define KEY 4330 /* Initial key (seed) for CharStrings decryption */
00876 #define C1 52845 /* Multiplier for pseudo-random number generator */
00877 #define C2 22719 /* Constant for pseudo-random number generator */
00878  
00879 static unsigned short r; /* Pseudo-random sequence of keys */
00880  
00881 static unsigned char Decrypt(unsigned char cipher)
00882 {
00883   unsigned char plain;
00884  
00885   plain = cipher ^ (r >> 8);
00886   r = (cipher + r) * C1 + C2;
00887   return plain;
00888 }
00889  
00890 /* Get the next byte from the codestring being interpreted */
00891 static int DoRead(CodeP)
00892   int *CodeP;
00893 {
00894   if (strindex >= CharStringP->len) return(FALSE); /* end of string */
00895   *CodeP = Decrypt((unsigned char) CharStringP->data.stringP[strindex++]);
00896   return(TRUE);
00897 }
00898  
00899 /* Strip blues->lenIV bytes from CharString and update encryption key */
00900 /* (the lenIV entry in the Private dictionary specifies the number of */
00901 /* random bytes at the beginning of each CharString; default is 4)    */
00902 static void StartDecrypt()
00903 {
00904   int Code;
00905  
00906   r = KEY; /* Initial key (seed) for CharStrings decryption */
00907   for (strindex = 0; strindex < blues->lenIV;)
00908     if (!DoRead(&Code)) /* Read a byte and update decryption key */
00909       Error0("StartDecrypt: Premature end of CharString\n");
00910 }
00911  
00912 static void Decode(Code)
00913   int Code;
00914 {
00915   int Code1, Code2, Code3, Code4;
00916  
00917   if (Code <= 31)                           /* Code is [0,31]    */
00918     DoCommand(Code);
00919   else if (Code <= 246)                     /* Code is [32,246]  */
00920     Push((DOUBLE)(Code - 139));
00921   else if (Code <= 250) {                   /* Code is [247,250] */
00922     if (!DoRead(&Code2)) goto ended;
00923     Push((DOUBLE)(((Code - 247) << 8) + Code2 + 108));
00924   }
00925   else if (Code <= 254) {                   /* Code is [251,254] */
00926     if (!DoRead(&Code2)) goto ended;
00927     Push((DOUBLE)( -((Code - 251) << 8) - Code2 - 108));
00928   }
00929   else {                                    /* Code is 255 */
00930     if (!DoRead(&Code1)) goto ended;
00931     if (!DoRead(&Code2)) goto ended;
00932     if (!DoRead(&Code3)) goto ended;
00933     if (!DoRead(&Code4)) goto ended;
00934     Push((DOUBLE)((((((Code1<<8) + Code2)<<8) + Code3)<<8) + Code4));
00935   }
00936   return;
00937  
00938 ended: Error0("Decode: Premature end of Type 1 CharString");
00939 }
00940  
00941 /* Interpret a command code */
00942 static void DoCommand(Code)
00943   int Code;
00944 {
00945   switch(Code) {
00946     case HSTEM: /* |- y dy HSTEM |- */
00947       /* Vertical range of a horizontal stem zone */
00948       if (Top < 1) Error0("DoCommand: Stack low\n");
00949       HStem(Stack[0], Stack[1]);
00950       ClearStack();
00951       break;
00952     case VSTEM: /* |- x dx VSTEM |- */
00953       /* Horizontal range of a vertical stem zone */
00954       if (Top < 1) Error0("DoCommand: Stack low\n");
00955       VStem(Stack[0], Stack[1]);
00956       ClearStack();
00957       break;
00958     case VMOVETO: /* |- dy VMOVETO |- */
00959       /* Vertical MOVETO, equivalent to 0 dy RMOVETO */
00960       if (Top < 0) Error0("DoCommand: Stack low\n");
00961       RMoveTo(0.0, Stack[0]);
00962       ClearStack();
00963       break;
00964     case RLINETO: /* |- dx dy RLINETO |- */
00965       /* Like RLINETO in PostScript */
00966       if (Top < 1) Error0("DoCommand: Stack low\n");
00967       RLineTo(Stack[0], Stack[1]);
00968       ClearStack();
00969       break;
00970     case HLINETO: /* |- dx HLINETO |- */
00971       /* Horizontal LINETO, equivalent to dx 0 RLINETO */
00972       if (Top < 0) Error0("DoCommand: Stack low\n");
00973       RLineTo(Stack[0], 0.0);
00974       ClearStack();
00975       break;
00976     case VLINETO: /* |- dy VLINETO |- */
00977       /* Vertical LINETO, equivalent to 0 dy RLINETO */
00978       if (Top < 0) Error0("DoCommand: Stack low\n");
00979       RLineTo(0.0, Stack[0]);
00980       ClearStack();
00981       break;
00982     case RRCURVETO:
00983       /* |- dx1 dy1 dx2 dy2 dx3 dy3 RRCURVETO |- */
00984       /* Relative RCURVETO, equivalent to dx1 dy1 */
00985       /* (dx1+dx2) (dy1+dy2) (dx1+dx2+dx3) */
00986       /* (dy1+dy2+dy3) RCURVETO in PostScript */
00987       if (Top < 5) Error0("DoCommand: Stack low\n");
00988       RRCurveTo(Stack[0], Stack[1], Stack[2], Stack[3],
00989         Stack[4], Stack[5]);
00990       ClearStack();
00991       break;
00992     case CLOSEPATH: /* - CLOSEPATH |- */
00993       /* Closes a subpath without repositioning the */
00994       /* current point */
00995       DoClosePath();
00996       ClearStack();
00997       break;
00998     case CALLSUBR: /* subr# CALLSUBR - */
00999       /* Calls a CharString subroutine with index */
01000       /* subr# from the Subrs array */
01001       if (Top < 0) Error0("DoCommand: Stack low\n");
01002       CallSubr((int)Stack[Top--]);
01003       break;
01004     case RETURN: /* - RETURN - */
01005       /* Returns from a Subrs array CharString */
01006       /* subroutine called with CALLSUBR */
01007       Return();
01008       break;
01009     case ESCAPE: /* ESCAPE to two-byte command code */
01010       if (!DoRead(&Code)) Error0("DoCommand: ESCAPE is last byte\n");
01011       Escape(Code);
01012       break;
01013     case HSBW: /* |- sbx wx HSBW |- */
01014       /* Set the left sidebearing point to (sbx,0), */
01015       /* set the character width vector to (wx,0). */
01016       /* Equivalent to sbx 0 wx 0 SBW.  Space */
01017       /* character should have sbx = 0 */
01018       if (Top < 1) Error0("DoCommand: Stack low\n");
01019       Sbw(Stack[0], 0.0, Stack[1], 0.0);
01020       ClearStack();
01021       break;
01022     case ENDCHAR: /* - ENDCHAR |- */
01023       /* Finishes a CharString outline */
01024       EndChar();
01025       ClearStack();
01026       break;
01027     case RMOVETO: /* |- dx dy RMOVETO |- */
01028       /* Behaves like RMOVETO in PostScript */
01029       if (Top < 1) Error0("DoCommand: Stack low\n");
01030       RMoveTo(Stack[0], Stack[1]);
01031       ClearStack();
01032       break;
01033     case HMOVETO: /* |- dx HMOVETO |- */
01034       /* Horizontal MOVETO. Equivalent to dx 0 RMOVETO */
01035       if (Top < 0) Error0("DoCommand: Stack low\n");
01036       RMoveTo(Stack[0], 0.0);
01037       ClearStack();
01038       break;
01039     case VHCURVETO: /* |- dy1 dx2 dy2 dx3 VHCURVETO |- */
01040       /* Vertical-Horizontal CURVETO, equivalent to */
01041       /* 0 dy1 dx2 dy2 dx3 0 RRCURVETO */
01042       if (Top < 3) Error0("DoCommand: Stack low\n");
01043       RRCurveTo(0.0, Stack[0], Stack[1], Stack[2],
01044               Stack[3], 0.0);
01045       ClearStack();
01046       break;
01047     case HVCURVETO: /* |- dx1 dx2 dy2 dy3 HVCURVETO |- */
01048       /* Horizontal-Vertical CURVETO, equivalent to */
01049       /* dx1 0 dx2 dy2 0 dy3 RRCURVETO */
01050       if (Top < 3) Error0("DoCommand: Stack low\n");
01051       RRCurveTo(Stack[0], 0.0, Stack[1], Stack[2], 0.0, Stack[3]);
01052       ClearStack();
01053       break;
01054     default: /* Unassigned command code */
01055       ClearStack();
01056       Error1("DoCommand: Unassigned code %d\n", Code);
01057   }
01058 }
01059  
01060 static void Escape(Code)
01061   int Code;
01062 {
01063   int i, Num;
01064   struct segment *p;
01065  
01066   switch(Code) {
01067     case DOTSECTION: /* - DOTSECTION |- */
01068       /* Brackets an outline section for the dots in */
01069       /* letters such as "i", "j", and "!". */
01070       DotSection();
01071       ClearStack();
01072       break;
01073     case VSTEM3: /* |- x0 dx0 x1 dx1 x2 dx2 VSTEM3 |- */
01074       /* Declares the horizontal ranges of three */
01075       /* vertical stem zones between x0 and x0+dx0, */
01076       /* x1 and x1+dx1, and x2 and x2+dx2. */
01077       if (Top < 5) Error0("DoCommand: Stack low\n");
01078       if (!wsset && ProcessHints) {
01079         /* Shift the whole character so that the middle stem is centered. */
01080         p = CenterStem(Stack[2] + sidebearingX, Stack[3]);
01081         path = Join(path, p);
01082         wsset = 1;
01083       }
01084  
01085       VStem(Stack[0], Stack[1]);
01086       VStem(Stack[2], Stack[3]);
01087       VStem(Stack[4], Stack[5]);
01088       ClearStack();
01089       break;
01090     case HSTEM3: /* |- y0 dy0 y1 dy1 y2 dy2 HSTEM3 |- */
01091       /* Declares the vertical ranges of three hori- */
01092       /* zontal stem zones between y0 and y0+dy0, */
01093       /* y1 and y1+dy1, and y2 and y2+dy2. */
01094       if (Top < 5) Error0("DoCommand: Stack low\n");
01095       HStem(Stack[0], Stack[1]);
01096       HStem(Stack[2], Stack[3]);
01097       HStem(Stack[4], Stack[5]);
01098       ClearStack();
01099       break;
01100     case SEAC: /* |- asb adx ady bchar achar SEAC |- */
01101       /* Standard Encoding Accented Character. */
01102       if (Top < 4) Error0("DoCommand: Stack low\n");
01103       Seac(Stack[0], Stack[1], Stack[2],
01104         (unsigned char) Stack[3],
01105         (unsigned char) Stack[4]);
01106       ClearStack();
01107       break;
01108     case SBW: /* |- sbx sby wx wy SBW |- */
01109       /* Set the left sidebearing point to (sbx,sby), */
01110       /* set the character width vector to (wx,wy). */
01111       if (Top < 3) Error0("DoCommand: Stack low\n");
01112       Sbw(Stack[0], Stack[1], Stack[2], Stack[3]);
01113       ClearStack();
01114       break;
01115     case DIV: /* num1 num2 DIV quotient */
01116       /* Behaves like DIV in the PostScript language */
01117       if (Top < 1) Error0("DoCommand: Stack low\n");
01118       Stack[Top-1] = Div(Stack[Top-1], Stack[Top]);
01119       Top--;
01120       break;
01121     case CALLOTHERSUBR:
01122       /* arg1 ... argn n othersubr# CALLOTHERSUBR - */
01123       /* Make calls on the PostScript interpreter */
01124       if (Top < 1) Error0("DoCommand: Stack low\n");
01125       Num = Stack[Top-1];
01126       if (Top < Num+1) Error0("DoCommand: Stack low\n");
01127       for (i = 0; i < Num; i++) PSFakePush(Stack[Top - i - 2]);
01128       Top -= Num + 2;
01129       CallOtherSubr((int)Stack[Top + Num + 2]);
01130       break;
01131     case POP: /* - POP number */
01132       /* Removes a number from the top of the */
01133       /* PostScript interpreter stack and pushes it */
01134       /* onto the Type 1 BuildChar operand stack */
01135       Push(PSFakePop());
01136       break;
01137     case SETCURRENTPOINT: /* |- x y SETCURRENTPOINT |- */
01138       /* Sets the current point to (x,y) in absolute */
01139       /* character space coordinates without per- */
01140       /* forming a CharString MOVETO command */
01141       if (Top < 1) Error0("DoCommand: Stack low\n");
01142       SetCurrentPoint(Stack[0], Stack[1]);
01143       ClearStack();
01144       break;
01145     default: /* Unassigned escape code command */
01146       ClearStack();
01147       Error1("Escape: Unassigned code %d\n", Code);
01148   }
01149 }
01150  
01151 /* |- y dy HSTEM |- */
01152 /* Declares the vertical range of a horizontal stem zone */
01153 /* between coordinates y and y + dy */
01154 /* y is relative to the left sidebearing point */
01155 static void HStem(y, dy)
01156   DOUBLE y, dy;
01157 {
01158   IfTrace2((FontDebug), "Hstem %f %f\n", &y, &dy);
01159   if (ProcessHints) {
01160     if (numstems >= MAXSTEMS) Error0("HStem: Too many hints\n");
01161     if (dy < 0.0) {y += dy; dy = -dy;}
01162     stems[numstems].vertical = FALSE;
01163     stems[numstems].x = 0.0;
01164     stems[numstems].y = sidebearingY + y + wsoffsetY;
01165     stems[numstems].dx = 0.0;
01166     stems[numstems].dy = dy;
01167     ComputeStem(numstems);
01168     numstems++;
01169   }
01170 }
01171  
01172 /* |- x dx VSTEM |- */
01173 /* Declares the horizontal range of a vertical stem zone */
01174 /* between coordinates x and x + dx */
01175 /* x is relative to the left sidebearing point */
01176 static void VStem(x, dx)
01177   DOUBLE x, dx;
01178 {
01179   IfTrace2((FontDebug), "Vstem %f %f\n", &x, &dx);
01180   if (ProcessHints) {
01181     if (numstems >= MAXSTEMS) Error0("VStem: Too many hints\n");
01182     if (dx < 0.0) {x += dx; dx = -dx;}
01183     stems[numstems].vertical = TRUE;
01184     stems[numstems].x = sidebearingX + x + wsoffsetX;
01185     stems[numstems].y = 0.0;
01186     stems[numstems].dx = dx;
01187     stems[numstems].dy = 0.0;
01188     ComputeStem(numstems);
01189     numstems++;
01190   }
01191 }
01192  
01193 /* |- dx dy RLINETO |- */
01194 /* Behaves like RLINETO in PostScript */
01195 static void RLineTo(dx, dy)
01196   DOUBLE dx, dy;
01197 {
01198   struct segment *B;
01199  
01200   IfTrace2((FontDebug), "RLineTo %f %f\n", &dx, &dy);
01201  
01202   B = Loc(CharSpace, dx, dy);
01203  
01204   if (ProcessHints) {
01205     currx += dx;
01206     curry += dy;
01207     /* B = Join(B, FindStems(currx, curry)); */
01208     B = Join(B, FindStems(currx, curry, dx, dy));
01209   }
01210  
01211   path = Join(path, Line(B));
01212 }
01213  
01214 /* |- dx1 dy1 dx2 dy2 dx3 dy3 RRCURVETO |- */
01215 /* Relative RCURVETO, equivalent to dx1 dy1 */
01216 /* (dx1+dx2) (dy1+dy2) (dx1+dx2+dx3) */
01217 /* (dy1+dy2+dy3) RCURVETO in PostScript */
01218 static void RRCurveTo(dx1, dy1, dx2, dy2, dx3, dy3)
01219   DOUBLE dx1, dy1, dx2, dy2, dx3, dy3;
01220 {
01221   struct segment *B, *C, *D;
01222  
01223   IfTrace4((FontDebug), "RRCurveTo %f %f %f %f ", &dx1, &dy1, &dx2, &dy2);
01224   IfTrace2((FontDebug), "%f %f\n", &dx3, &dy3);
01225  
01226   B = Loc(CharSpace, dx1, dy1);
01227   C = Loc(CharSpace, dx2, dy2);
01228   D = Loc(CharSpace, dx3, dy3);
01229  
01230   if (ProcessHints) {
01231     /* For a Bezier curve, we apply the full hint value to
01232        the Bezier C point (and thereby D point). */
01233     currx += dx1 + dx2 + dx3;
01234     curry += dy1 + dy2 + dy3;
01235     /* C = Join(C, FindStems(currx, curry)); */
01236     C = Join(C, FindStems(currx, curry, dx3, dy3));
01237   }
01238  
01239   /* Since XIMAGER is not completely relative, */
01240   /* we need to add up the delta values */
01241  
01242   C = Join(C, Dup(B));
01243   D = Join(D, Dup(C));
01244  
01245   path = Join(path, Bezier(B, C, D));
01246 }
01247  
01248 /* - CLOSEPATH |- */
01249 /* Closes a subpath WITHOUT repositioning the */
01250 /* current point */
01251 static void DoClosePath()
01252 {
01253   struct segment *CurrentPoint;
01254  
01255   IfTrace0((FontDebug), "DoClosePath\n");
01256   CurrentPoint = Phantom(path);
01257   path = ClosePath(path);
01258   path = Join(Snap(path), CurrentPoint);
01259 }
01260  
01261 /* subr# CALLSUBR - */
01262 /* Calls a CharString subroutine with index */
01263 /* subr# from the Subrs array */
01264 static void CallSubr(subrno)
01265   int subrno;
01266 {
01267   IfTrace1((FontDebug), "CallSubr %d\n", subrno);
01268   if ((subrno < 0) || (subrno >= SubrsP->len))
01269     Error0("CallSubr: subrno out of range\n");
01270   PushCall(CharStringP, strindex, r);
01271   CharStringP = &SubrsP->data.arrayP[subrno];
01272   StartDecrypt();
01273 }
01274  
01275 /* - RETURN - */
01276 /* Returns from a Subrs array CharString */
01277 /* subroutine called with CALLSUBR */
01278 static void Return()
01279 {
01280   IfTrace0((FontDebug), "Return\n");
01281   PopCall(&CharStringP, &strindex, &r);
01282 }
01283  
01284 /* - ENDCHAR |- */
01285 /* Finishes a CharString outline */
01286 /* Executes SETCHACHEDEVICE using a bounding box */
01287 /* it computes directly from the character outline */
01288 /* and using the width information acquired from a previous */
01289 /* HSBW or SBW.  It then calls a special version of FILL */
01290 /* or STROKE depending on the value of PaintType in the */
01291 /* font dictionary */
01292 static void EndChar()
01293 {
01294   IfTrace0((FontDebug), "EndChar\n");
01295  
01296   /* There is no need to compute and set bounding box for
01297      the cache, since XIMAGER does that on the fly. */
01298  
01299   /* Perform a Closepath just in case the command was left out */
01300   path = ClosePath(path);
01301  
01302   /* Set character width */
01303   path = Join(Snap(path), Loc(CharSpace, escapementX, escapementY));
01304  
01305 }
01306  
01307 /* |- dx dy RMOVETO |- */
01308 /* Behaves like RMOVETO in PostScript */
01309 static void RMoveTo(dx,dy)
01310   DOUBLE dx,dy;
01311 {
01312   struct segment *B;
01313  
01314   IfTrace2((FontDebug), "RMoveTo %f %f\n", &dx, &dy);
01315  
01316   B = Loc(CharSpace, dx, dy);
01317  
01318   if (ProcessHints) {
01319     currx += dx;
01320     curry += dy;
01321     /* B = Join(B, FindStems(currx, curry)); */
01322     B = Join(B, FindStems(currx, curry, 0.0, 0.0));
01323   }
01324  
01325   path = Join(path, B);
01326 }
01327  
01328 /* - DOTSECTION |- */
01329 /* Brackets an outline section for the dots in */
01330 /* letters such as "i", "j", and "!". */
01331 static void DotSection()
01332 {
01333   IfTrace0((FontDebug), "DotSection\n");
01334   InDotSection = !InDotSection;
01335 }
01336  
01337 /* |- asb adx ady bchar achar SEAC |- */
01338 /* Standard Encoding Accented Character. */
01339 static void Seac(DOUBLE asb, DOUBLE adx, DOUBLE ady,
01340                  unsigned char bchar, unsigned char achar)
01341 {
01342   int Code;
01343   struct segment *mypath;
01344  
01345   IfTrace4((FontDebug), "SEAC %f %f %f %d ", &asb, &adx, &ady, bchar);
01346   IfTrace1((FontDebug), "%d\n", achar);
01347  
01348   /* Move adx - asb, ady over and up from base char's sbpoint. */
01349   /* (We use adx - asb to counteract the accents sb shift.) */
01350   /* The variables accentoffsetX/Y modify sidebearingX/Y in Sbw(). */
01351   /* Note that these incorporate the base character's sidebearing shift by */
01352   /* using the current sidebearingX, Y values. */
01353   accentoffsetX = sidebearingX + adx - asb;
01354   accentoffsetY = sidebearingY + ady;
01355  
01356   /* Set path = NULL to avoid complaints from Sbw(). */
01357   path = NULL;
01358  
01359   /* Go find the CharString for the accent's code via an upcall */
01360   CharStringP = GetType1CharString(Environment, achar);
01361   if (CharStringP == NULL) {
01362      Error1("Invalid accent ('%03o) in SEAC\n", achar);
01363      return;
01364   }
01365   StartDecrypt();
01366  
01367   ClearStack();
01368   ClearPSFakeStack();
01369   ClearCallStack();
01370  
01371   for (;;) {
01372     if (!DoRead(&Code)) break;
01373     Decode(Code);
01374     if (errflag) return;
01375   }
01376   /* Copy snapped path to mypath and set path to NULL as above. */
01377   mypath = Snap(path);
01378   path = NULL;
01379  
01380   /* We must reset these to null now. */
01381   accentoffsetX = accentoffsetY = 0;
01382  
01383   /* go find the CharString for the base char's code via an upcall */
01384   CharStringP = GetType1CharString(Environment, bchar);
01385   StartDecrypt();
01386  
01387   ClearStack();
01388   ClearPSFakeStack();
01389   ClearCallStack();
01390  
01391   FinitStems();
01392   InitStems();
01393  
01394   for (;;) {
01395     if (!DoRead(&Code)) break;
01396     Decode(Code);
01397     if (errflag) return;
01398   }
01399   path = Join(mypath, path);
01400 }
01401  
01402  
01403 /* |- sbx sby wx wy SBW |- */
01404 /* Set the left sidebearing point to (sbx,sby), */
01405 /* set the character width vector to (wx,wy). */
01406 static void Sbw(sbx, sby, wx, wy)
01407   DOUBLE sbx, sby, wx, wy;
01408 {
01409   IfTrace4((FontDebug), "SBW %f %f %f %f\n", &sbx, &sby, &wx, &wy);
01410  
01411   escapementX = wx; /* Character width vector */
01412   escapementY = wy;
01413  
01414   /* Sidebearing values are sbx, sby args, plus accent offset from Seac(). */
01415   sidebearingX = sbx + accentoffsetX;
01416   sidebearingY = sby + accentoffsetY;
01417  
01418   path = Join(path, Loc(CharSpace, sidebearingX, sidebearingY));
01419   if (ProcessHints) {currx = sidebearingX; curry = sidebearingY;}
01420 }
01421  
01422  /* num1 num2 DIV quotient */
01423 /* Behaves like DIV in the PostScript language */
01424 static DOUBLE Div(num1, num2)
01425   DOUBLE num1, num2;
01426 {
01427   IfTrace2((FontDebug), "Div %f %f\n", &num1, &num2);
01428   return(num1 / num2);
01429 }
01430  
01431 /*
01432   The following four subroutines (FlxProc, FlxProc1, FlxProc2, and
01433   HintReplace) are C versions of the OtherSubrs Programs, which were
01434   were published in the Adobe Type 1 Font Format book.
01435  
01436   The Flex outline fragment is described by
01437     c1: (x0, y0) = c3: (x0, yshrink(y0)) or (xshrink(x0), y0)
01438      "  (x1, y1) =  "  (x1, yshrink(y1)) or (xshrink(x1), y1)
01439      "  (x2, y2) - reference point
01440     c2: (x0, y0) = c4: (x0, yshrink(y0)) or (xshrink(x0), y0)
01441      "  (x1, y1) =  "  (x1, yshrink(y1)) or (xshrink(x1), y1)
01442      "  (x2, y2) =  "  (x2, y2), rightmost endpoint
01443     c3: (x0, y0) - control point, 1st Bezier curve
01444      "  (x1, y1) - control point,      -"-
01445      "  (x2, y2) - end point,          -"-
01446     c4: (x0, y0) - control point, 2nd Bezier curve
01447      "  (x1, y1) - control point,      -"-
01448      "  (x2, y2) - end point,          -"-
01449     ep: (epY, epX) - final endpoint (should be same as c4: (x2, y2))
01450     idmin - minimum Flex height (1/100 pixel) at which to render curves
01451 */
01452  
01453 #define dtransform(dxusr,dyusr,dxdev,dydev) { \
01454   register struct segment *point = Loc(CharSpace, dxusr, dyusr); \
01455   QueryLoc(point, IDENTITY, dxdev, dydev); \
01456   Destroy(point); \
01457 }
01458  
01459 #define itransform(xdev,ydev,xusr,yusr) { \
01460   register struct segment *point = Loc(IDENTITY, xdev, ydev); \
01461   QueryLoc(point, CharSpace, xusr, yusr); \
01462   Destroy(point); \
01463 }
01464  
01465 #define transform(xusr,yusr,xdev,ydev) dtransform(xusr,yusr,xdev,ydev)
01466  
01467 #define PaintType (0)
01468  
01469 #define lineto(x,y) { \
01470   struct segment *CurrentPoint; \
01471   DOUBLE CurrentX, CurrentY; \
01472   CurrentPoint = Phantom(path); \
01473   QueryLoc(CurrentPoint, CharSpace, &CurrentX, &CurrentY); \
01474   Destroy(CurrentPoint); \
01475   RLineTo(x - CurrentX, y - CurrentY); \
01476 }
01477  
01478 #define curveto(x0,y0,x1,y1,x2,y2) { \
01479   struct segment *CurrentPoint; \
01480   DOUBLE CurrentX, CurrentY; \
01481   CurrentPoint = Phantom(path); \
01482   QueryLoc(CurrentPoint, CharSpace, &CurrentX, &CurrentY); \
01483   Destroy(CurrentPoint); \
01484   RRCurveTo(x0 - CurrentX, y0 - CurrentY, x1 - x0, y1 - y0, x2 - x1, y2 - y1); \
01485 }
01486  
01487 #define xshrink(x) ((x - c4x2) * shrink +c4x2)
01488 #define yshrink(y) ((y - c4y2) * shrink +c4y2)
01489  
01490 #define PickCoords(flag) \
01491   if (flag) { /* Pick "shrunk" coordinates */ \
01492     x0 = c1x0; y0 = c1y0; \
01493     x1 = c1x1; y1 = c1y1; \
01494     x2 = c1x2; y2 = c1y2; \
01495     x3 = c2x0; y3 = c2y0; \
01496     x4 = c2x1; y4 = c2y1; \
01497     x5 = c2x2; y5 = c2y2; \
01498   } else { /* Pick original coordinates */ \
01499     x0 = c3x0; y0 = c3y0; \
01500     x1 = c3x1; y1 = c3y1; \
01501     x2 = c3x2; y2 = c3y2; \
01502     x3 = c4x0; y3 = c4y0; \
01503     x4 = c4x1; y4 = c4y1; \
01504     x5 = c4x2; y5 = c4y2; \
01505   }
01506  
01507 /* FlxProc() = OtherSubrs[0]; Main part of Flex          */
01508 /*   Calling sequence: 'idmin epX epY 3 0 callothersubr' */
01509 /*   Computes Flex values, and renders the Flex path,    */
01510 /*   and returns (leaves) ending coordinates on stack    */
01511 static void FlxProc(c1x2, c1y2, c3x0, c3y0, c3x1, c3y1, c3x2, c3y2,
01512              c4x0, c4y0, c4x1, c4y1, c4x2, c4y2, epY, epX, idmin)
01513   DOUBLE c1x2, c1y2;
01514   DOUBLE c3x0, c3y0, c3x1, c3y1, c3x2, c3y2;
01515   DOUBLE c4x0, c4y0, c4x1, c4y1, c4x2, c4y2;
01516   DOUBLE epX, epY;
01517   int idmin;
01518 {
01519   DOUBLE dmin;
01520   DOUBLE c1x0, c1y0, c1x1, c1y1;
01521   DOUBLE c2x0, c2y0, c2x1, c2y1, c2x2, c2y2;
01522   char yflag;
01523   DOUBLE x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5;
01524   DOUBLE cxx, cyx, cxy, cyy; /* Transformation matrix */
01525   int flipXY;
01526   DOUBLE x, y;
01527   DOUBLE erosion = 1; /* Device parameter */
01528     /* Erosion may have different value specified in 'internaldict' */
01529   DOUBLE shrink;
01530   DOUBLE dX, dY;
01531   char erode;
01532   DOUBLE eShift;
01533   DOUBLE cx, cy;
01534   DOUBLE ex, ey;
01535  
01536   Destroy(path);
01537   path = FlxOldPath; /* Restore previous path (stored in FlxProc1) */
01538  
01539   if (ProcessHints) {
01540     dmin = ABS(idmin) / 100.0; /* Minimum Flex height in pixels */
01541  
01542     c2x2 = c4x2; c2y2 = c4y2; /* Point c2 = c4 */
01543  
01544     yflag = FABS(c1y2 - c3y2) > FABS(c1x2 - c3x2); /* Flex horizontal? */
01545  
01546     QuerySpace(CharSpace, &cxx, &cyx, &cxy, &cyy); /* Transformation matrix */
01547  
01548     if (FABS(cxx) < 0.00001 || FABS(cyy) < 0.00001)
01549       flipXY = -1; /* Char on side */
01550     else if (FABS(cyx) < 0.00001 || FABS(cxy) < 0.00001)
01551       flipXY = 1; /* Char upright */
01552     else
01553       flipXY = 0; /* Char at angle */
01554  
01555     if (yflag) { /* Flex horizontal */
01556       if (flipXY == 0 || c3y2 == c4y2) { /* Char at angle or Flex height = 0 */
01557         PickCoords(FALSE); /* Pick original control points */
01558       } else {
01559         shrink = FABS((c1y2 - c4y2) / (c3y2 - c4y2)); /* Slope */
01560  
01561         c1x0 = c3x0; c1y0 = yshrink(c3y0);
01562         c1x1 = c3x1; c1y1 = yshrink(c3y1);
01563         c2x0 = c4x0; c2y0 = yshrink(c4y0);
01564         c2x1 = c4x1; c2y1 = yshrink(c4y1);
01565  
01566         dtransform(0.0, ROUND(c3y2-c1y2), &x, &y); /* Flex height in pixels */
01567         dY = FABS((flipXY == 1) ? y : x);
01568         PickCoords(dY < dmin); /* If Flex small, pick 'shrunk' control points */
01569  
01570         if (FABS(y2 - c1y2) > 0.001) { /* Flex 'non-zero'? */
01571           transform(c1x2, c1y2, &x, &y);
01572  
01573           if (flipXY == 1) {
01574             cx = x; cy = y;
01575           } else {
01576             cx = y; cy = x;
01577           }
01578  
01579           dtransform(0.0, ROUND(y2-c1y2), &x, &y);
01580           dY = (flipXY == 1) ? y : x;
01581           if (ROUND(dY) != 0)
01582             dY = ROUND(dY);
01583           else
01584             dY = (dY < 0) ? -1 : 1;
01585  
01586           erode = PaintType != 2 && erosion >= 0.5;
01587           if (erode)
01588             cy -= 0.5;
01589           ey = cy + dY;
01590           ey = CEIL(ey) - ey + FLOOR(ey);
01591           if (erode)
01592             ey += 0.5;
01593  
01594           if (flipXY == 1) {
01595             itransform(cx, ey, &x, &y);
01596           } else {
01597             itransform(ey, cx, &x, &y);
01598           }
01599  
01600           eShift = y - y2;
01601           y1 += eShift;
01602           y2 += eShift;
01603           y3 += eShift;
01604         }
01605       }
01606     } else { /* Flex vertical */
01607       if (flipXY == 0 || c3x2 == c4x2) { /* Char at angle or Flex height = 0 */
01608         PickCoords(FALSE); /* Pick original control points */
01609       } else {
01610         shrink = FABS((c1x2 - c4x2) / (c3x2 - c4x2)); /* Slope */
01611  
01612         c1x0 = xshrink(c3x0); c1y0 = c3y0;
01613         c1x1 = xshrink(c3x1); c1y1 = c3y1;
01614         c2x0 = xshrink(c4x0); c2y0 = c4y0;
01615         c2x1 = xshrink(c4x1); c2y1 = c4y1;
01616  
01617         dtransform(ROUND(c3x2 - c1x2), 0.0, &x, &y); /* Flex height in pixels */
01618         dX = FABS((flipXY == -1) ? y : x);
01619         PickCoords(dX < dmin); /* If Flex small, pick 'shrunk' control points */
01620  
01621         if (FABS(x2 - c1x2) > 0.001) {
01622           transform(c1x2, c1y2, &x, &y);
01623           if (flipXY == -1) {
01624             cx = y; cy = x;
01625           } else {
01626             cx = x; cy = y;
01627           }
01628  
01629           dtransform(ROUND(x2-c1x2), 0.0, &x, &y);
01630           dX = (flipXY == -1) ? y : x;
01631           if (ROUND(dX) != 0)
01632             dX = ROUND(dX);
01633           else
01634             dX = (dX < 0) ? -1 : 1;
01635  
01636           erode = PaintType != 2 && erosion >= 0.5;
01637           if (erode)
01638             cx -= 0.5;
01639           ex = cx + dX;
01640           ex = CEIL(ex) - ex + FLOOR(ex);
01641           if (erode)
01642             ex += 0.5;
01643  
01644           if (flipXY == -1) {
01645             itransform(cy, ex, &x, &y);
01646           } else {
01647             itransform(ex, cy, &x, &y);
01648           }
01649  
01650           eShift = x - x2;
01651           x1 += eShift;
01652           x2 += eShift;
01653           x3 += eShift;
01654         }
01655       }
01656     }
01657  
01658     if (x2 == x5 || y2 == y5) {
01659       lineto(x5, y5);
01660     } else {
01661       curveto(x0, y0, x1, y1, x2, y2);
01662       curveto(x3, y3, x4, y4, x5, y5);
01663     }
01664   } else { /* ProcessHints is off */
01665     PickCoords(FALSE); /* Pick original control points */
01666     curveto(x0, y0, x1, y1, x2, y2);
01667     curveto(x3, y3, x4, y4, x5, y5);
01668   }
01669  
01670   PSFakePush(epY);
01671   PSFakePush(epX);
01672 }
01673  
01674 /* FlxProc1() = OtherSubrs[1]; Part of Flex            */
01675 /*   Calling sequence: '0 1 callothersubr'             */
01676 /*   Saves and clears path, then restores currentpoint */
01677 static void FlxProc1()
01678 {
01679   struct segment *CurrentPoint;
01680  
01681   CurrentPoint = Phantom(path);
01682  
01683   FlxOldPath = path;
01684   path = CurrentPoint;
01685 }
01686  
01687 /* FlxProc2() = OtherSubrs[2]; Part of Flex */
01688 /*   Calling sequence: '0 2 callothersubr'  */
01689 /*   Returns currentpoint on stack          */
01690 static void FlxProc2()
01691 {
01692   struct segment *CurrentPoint;
01693   DOUBLE CurrentX, CurrentY;
01694  
01695   CurrentPoint = Phantom(path);
01696   QueryLoc(CurrentPoint, CharSpace, &CurrentX, &CurrentY);
01697   Destroy(CurrentPoint);
01698  
01699   /* Push CurrentPoint on fake PostScript stack */
01700   PSFakePush(CurrentX);
01701   PSFakePush(CurrentY);
01702 }
01703  
01704 /* HintReplace() = OtherSubrs[3]; Hint Replacement            */
01705 /*   Calling sequence: 'subr# 1 3 callothersubr pop callsubr' */
01706 /*   Reinitializes stem hint structure                        */
01707 static void HintReplace()
01708 {
01709   /* Effectively retire the current stems, but keep them around for */
01710   /* revhint use in case we are in a stem when we replace hints. */
01711   currstartstem = numstems;
01712  
01713   /* 'subr#' is left on PostScript stack (for 'pop callsubr') */
01714 }
01715  
01716 /* arg1 ... argn n othersubr# CALLOTHERSUBR - */
01717 /* Make calls on the PostScript interpreter (or call equivalent C code) */
01718 /* NOTE: The n arguments have been pushed on the fake PostScript stack */
01719 static void CallOtherSubr(othersubrno)
01720   int othersubrno;
01721 {
01722   IfTrace1((FontDebug), "CallOtherSubr %d\n", othersubrno);
01723  
01724   switch(othersubrno) {
01725     case 0: /* OtherSubrs[0]; Main part of Flex */
01726       if (PSFakeTop < 16) Error0("CallOtherSubr: PSFakeStack low");
01727       ClearPSFakeStack();
01728       FlxProc(
01729         PSFakeStack[0],  PSFakeStack[1],  PSFakeStack[2],  PSFakeStack[3],
01730         PSFakeStack[4],  PSFakeStack[5],  PSFakeStack[6],  PSFakeStack[7],
01731         PSFakeStack[8],  PSFakeStack[9],  PSFakeStack[10], PSFakeStack[11],
01732         PSFakeStack[12], PSFakeStack[13], PSFakeStack[14], PSFakeStack[15],
01733         (int) PSFakeStack[16]
01734       );
01735       break;
01736     case 1: /* OtherSubrs[1]; Part of Flex */
01737       FlxProc1();
01738       break;
01739     case 2: /* OtherSubrs[2]; Part of Flex */
01740       FlxProc2();
01741       break;
01742     case 3: /* OtherSubrs[3]; Hint Replacement */
01743       HintReplace();
01744       break;
01745     default: { /* call OtherSubrs[4] or higher if PostScript is present */
01746     }
01747   }
01748 }
01749  
01750 /* |- x y SETCURRENTPOINT |- */
01751 /* Sets the current point to (x,y) in absolute */
01752 /* character space coordinates without per- */
01753 /* forming a CharString MOVETO command */
01754 static void SetCurrentPoint(x, y)
01755   DOUBLE x, y;
01756 {
01757   IfTrace2((FontDebug), "SetCurrentPoint %f %f\n", &x, &y);
01758  
01759   currx = x;
01760   curry = y;
01761 }
01762  
01763 /* The Type1Char routine for use by PostScript. */
01764 /************************************************/
01765 struct xobject *Type1Char(env, S, charstrP, subrsP, osubrsP, bluesP, modeP)
01766   char *env;
01767   struct XYspace *S;
01768   psobj *charstrP;
01769   psobj *subrsP;
01770   psobj *osubrsP;
01771   struct blues_struct *bluesP;  /* FontID's ptr to the blues struct */
01772   int *modeP;
01773 {
01774   int Code;
01775  
01776   path = NULL;
01777   errflag = FALSE;
01778  
01779   /* Make parameters available to all Type1 routines */
01780   Environment = env;
01781   CharSpace = S; /* used when creating path elements */
01782   CharStringP = charstrP;
01783   SubrsP = subrsP;
01784   OtherSubrsP = osubrsP;
01785   ModeP = modeP;
01786  
01787     blues = bluesP;
01788  
01789   /* compute the alignment zones */
01790   ComputeAlignmentZones();
01791  
01792   StartDecrypt();
01793  
01794   ClearStack();
01795   ClearPSFakeStack();
01796   ClearCallStack();
01797  
01798   InitStems();
01799  
01800   currx = curry = 0;
01801   escapementX = escapementY = 0;
01802   sidebearingX = sidebearingY = 0;
01803   accentoffsetX = accentoffsetY = 0;
01804   wsoffsetX = wsoffsetY = 0;           /* No shift to preserve whitspace. */
01805   wsset = 0;                           /* wsoffsetX,Y haven't been set yet. */
01806  
01807   for (;;) {
01808     if (!DoRead(&Code)) break;
01809     Decode(Code);
01810     if (errflag) break;
01811   }
01812  
01813   FinitStems();
01814  
01815  
01816   /* Clean up if an error has occurred */
01817   if (errflag) {
01818     if (path != NULL) {
01819       Destroy(path); /* Reclaim storage */
01820       path = NULL;   /* Indicate that character could not be built */
01821     }
01822   }
01823  
01824   return((struct xobject *) path);
01825 }
01826