1 /* $XConsortium: type1.c,v 1.5 91/10/10 11:20:06 rws Exp $ */
2 /* Copyright International Business Machines, Corp. 1991
3  * All Rights Reserved
4  * Copyright Lexmark International, Inc. 1991
5  * All Rights Reserved
6  * Portions Copyright (c) 1990 Adobe Systems Incorporated.
7  * All Rights Reserved
8  *
9  * License to use, copy, modify, and distribute this software and its
10  * documentation for any purpose and without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and that
12  * both that copyright notice and this permission notice appear in
13  * supporting documentation, and that the name of IBM or Lexmark or Adobe
14  * not be used in advertising or publicity pertaining to distribution of
15  * the software without specific, written prior permission.
16  *
17  * IBM, LEXMARK, AND ADOBE PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY
18  * WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
19  * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20  * PARTICULAR PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  THE
21  * ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING
22  * ANY DUTY TO SUPPORT OR MAINTAIN, BELONGS TO THE LICENSEE.  SHOULD ANY
23  * PORTION OF THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM,
24  * LEXMARK, OR ADOBE) ASSUMES THE ENTIRE COST OF ALL SERVICING, REPAIR AND
25  * CORRECTION.  IN NO EVENT SHALL IBM, LEXMARK, OR ADOBE BE LIABLE FOR ANY
26  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
27  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
28  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
29  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30  */
31 
32 /*********************************************************************/
33 /*                                                                   */
34 /* Type 1 module - Converting fonts in Adobe Type 1 Font Format      */
35 /*                 to scaled and hinted paths for rasterization.     */
36 /*                 Files: type1.c, type1.h, and blues.h.             */
37 /*                                                                   */
38 /* Authors:   Sten F. Andler, IBM Almaden Research Center            */
39 /*                 (Type 1 interpreter, stem & flex hints)           */
40 /*                                                                   */
41 /*            Patrick A. Casey, Lexmark International, Inc.          */
42 /*                 (Font level hints & stem hints)                   */
43 /*                                                                   */
44 /*********************************************************************/
45 
46 /******************/
47 /* Include Files: */
48 /******************/
49 #include  "types.h"
50 #include  <stdio.h>          /* a system-dependent include, usually */
51 
52 #include  "objects.h"
53 #include  "spaces.h"
54 #include  "paths.h"
55 #include  "fonts.h"        /* understands about TEXTTYPEs */
56 #include  "pictures.h"     /* understands about handles */
57 #include  "util.h"       /* PostScript objects */
58 #include  "blues.h"          /* Blues structure for font-level hints */
59 #include  "fontmisc.h"
60 #include  "ffilest.h"
61 #include  "fontfcn.h"
62 
63 /**********************************/
64 /* Type1 Constants and Structures */
65 /**********************************/
66 #define MAXSTACK 24        /* Adobe Type1 limit */
67 #define MAXCALLSTACK 10    /* Adobe Type1 limit */
68 #define MAXPSFAKESTACK 32  /* Max depth of fake PostScript stack (local) */
69 #define MAXSTRLEN 512      /* Max length of a Type 1 string (local) */
70 #define MAXLABEL 256       /* Maximum number of new hints */
71 #define MAXSTEMS 128       /* Maximum number of VSTEM and HSTEM hints */
72 #define EPS 0.001          /* Small number for comparisons */
73 
74 /************************************/
75 /* Adobe Type 1 CharString commands */
76 /************************************/
77 #define HSTEM        1
78 #define VSTEM        3
79 #define VMOVETO      4
80 #define RLINETO      5
81 #define HLINETO      6
82 #define VLINETO      7
83 #define RRCURVETO    8
84 #define CLOSEPATH    9
85 #define CALLSUBR    10
86 #define RETURN      11
87 #define ESCAPE      12
88 #define HSBW        13
89 #define ENDCHAR     14
90 #define RMOVETO     21
91 #define HMOVETO     22
92 #define VHCURVETO   30
93 #define HVCURVETO   31
94 
95 /*******************************************/
96 /* Adobe Type 1 CharString Escape commands */
97 /*******************************************/
98 #define DOTSECTION       0
99 #define VSTEM3           1
100 #define HSTEM3           2
101 #define SEAC             6
102 #define SBW              7
103 #define DIV             12
104 #define CALLOTHERSUBR   16
105 #define POP             17
106 #define SETCURRENTPOINT 33
107 
108 /*****************/
109 /* Useful macros */
110 /*****************/
111 
112 #define FABS(x) fabs(x)
113 
114 #define CEIL(x) ceil(x)
115 
116 #define FLOOR(x) floor(x)
117 
118 #define ROUND(x) FLOOR((x) + 0.5)
119 
120 #define ODD(x) (((int)(x)) & 01)
121 
122 int currentchar = -1; /* for error reporting */
123 
124 #define CC IfTrace1(TRUE, "'%03o ", currentchar)
125 
126 #define Error {errflag = TRUE; return;}
127 
128 #define Error0(errmsg) { CC; IfTrace0(TRUE, errmsg); Error;}
129 
130 #define Error01(errmsg) { CC; IfTrace0(TRUE, errmsg); errflag = TRUE; return -1.0;}
131 
132 #define Error1(errmsg,arg) { CC; IfTrace1(TRUE, errmsg, arg); Error;}
133 
134 /********************/
135 /* global variables */
136 /********************/
137 struct stem {                     /* representation of a STEM hint */
138     int vertical;                 /* TRUE if vertical, FALSE otherwise */
139     DOUBLE x, dx;                 /* interval of vertical stem */
140     DOUBLE y, dy;                 /* interval of horizontal stem */
141     struct segment *lbhint, *lbrevhint;   /* left  or bottom hint adjustment */
142     struct segment *rthint, *rtrevhint;   /* right or top    hint adjustment */
143 };
144 
145 static DOUBLE escapementX, escapementY;
146 static DOUBLE sidebearingX, sidebearingY;
147 static DOUBLE accentoffsetX, accentoffsetY;
148 
149 static struct segment *path;
150 static int errflag;
151 
152 /*************************************************/
153 /* Global variables to hold Type1Char parameters */
154 /*************************************************/
155 static psfont *Environment;
156 static struct XYspace *CharSpace;
157 static psobj *CharStringP, *SubrsP, *OtherSubrsP;
158 static int *ModeP;
159 
160 /************************/
161 /* Forward declarations */
162 /************************/
163 #ifdef WIN32
164 /* Unfortunately, there is such a function in the Win32 API */
165 #define Escape Type1Escape
166 #endif
167 static void ComputeAlignmentZones(void);
168 static void InitStems(void);
169 static void FinitStems(void);
170 static void ComputeStem(int stemno);
171 static struct segment *Applyhint(struct segment *p,int stemnumber,int half);
172 static struct segment *Applyrevhint(struct segment *p,int stemnumber,int half);
173 static struct segment *FindStems(DOUBLE x,DOUBLE y,DOUBLE dx,DOUBLE dy);
174 static void ClearStack(void);
175 static void Push(DOUBLE Num);
176 static void ClearCallStack(void);
177 static void PushCall(psobj *CurrStrP,int CurrIndex,unsigned short CurrKey);
178 static void PopCall(psobj **CurrStrPP ,int *CurrIndexP,unsigned short *CurrKeyP);
179 static void ClearPSFakeStack(void);
180 static void PSFakePush(DOUBLE Num);
181 static DOUBLE PSFakePop(void);
182 static struct segment *CenterStem(DOUBLE edge1,DOUBLE edge2);
183 static unsigned char Decrypt(unsigned char cipher);
184 static int DoRead(int *CodeP);
185 static void StartDecrypt(void);
186 static void Decode(int Code);
187 static void DoCommand(int Code);
188 static void Escape(int Code);
189 static void HStem(DOUBLE y,DOUBLE dy);
190 static void VStem(DOUBLE x,DOUBLE dx);
191 static void RLineTo(DOUBLE dx,DOUBLE dy);
192 static void RRCurveTo(DOUBLE dx1,DOUBLE dy1,DOUBLE dx2,DOUBLE dy2,DOUBLE dx3,DOUBLE dy3);
193 static void DoClosePath(void);
194 static void CallSubr(int subrno);
195 static void Return(void);
196 static void EndChar(void);
197 static void RMoveTo(DOUBLE dx,DOUBLE dy);
198 static void DotSection(void);
199 static void Seac(DOUBLE asb,DOUBLE adx,DOUBLE ady,unsigned char bchar,unsigned char achar);
200 static void Sbw(DOUBLE sbx,DOUBLE sby,DOUBLE wx,DOUBLE wy);
201 static DOUBLE Div(DOUBLE num1,DOUBLE num2);
202 static void FlxProc(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);
203 static void FlxProc1(void);
204 static void FlxProc2(void);
205 static void HintReplace(void);
206 static void CallOtherSubr(int othersubrno);
207 static void SetCurrentPoint(DOUBLE x,DOUBLE y);
208 
209 /*****************************************/
210 /* statics for Flex procedures (FlxProc) */
211 /*****************************************/
212 static struct segment *FlxOldPath; /* save path before Flex feature */
213 
214 /******************************************************/
215 /* statics for Font level hints (Blues) (see blues.h) */
216 /******************************************************/
217 static struct blues_struct *blues; /* the blues structure */
218 static struct alignmentzone alignmentzones[MAXALIGNMENTZONES];
219 int numalignmentzones;          /* total number of alignment zones */
220 
221 /****************************************************************/
222 /* Subroutines for the Font level hints (Alignment zones, etc.) */
223 /****************************************************************/
224 
225 /******************************************/
226 /* Fill in the alignment zone structures. */
227 /******************************************/
ComputeAlignmentZones(void)228 static void ComputeAlignmentZones(void)
229 {
230   int i;
231   DOUBLE dummy, bluezonepixels, familyzonepixels;
232   struct segment *p;
233 
234   numalignmentzones = 0;     /* initialize total # of zones */
235 
236   /* do the BlueValues zones */
237   for (i = 0; i < blues->numBlueValues; i +=2, ++numalignmentzones) {
238     /* the 0th & 1st numbers in BlueValues are for a bottom zone */
239     /* the rest are topzones */
240     if (i == 0)           /* bottom zone */
241       alignmentzones[numalignmentzones].topzone = FALSE;
242     else                  /* top zone */
243       alignmentzones[numalignmentzones].topzone = TRUE;
244     if (i < blues->numFamilyBlues) {    /* we must consider FamilyBlues */
245       p = ILoc(CharSpace,0,blues->BlueValues[i] - blues->BlueValues[i+1]);
246       QueryLoc(p, IDENTITY, &dummy, &bluezonepixels);
247       Destroy(p);
248       p = ILoc(CharSpace,0,blues->FamilyBlues[i]-blues->FamilyBlues[i+1]);
249       QueryLoc(p, IDENTITY, &dummy, &familyzonepixels);
250       Destroy(p);
251       /* is the difference in size of the zones less than 1 pixel? */
252       if (FABS(bluezonepixels - familyzonepixels) < 1.0) {
253         /* use the Family zones */
254         alignmentzones[numalignmentzones].bottomy =
255           blues->FamilyBlues[i];
256         alignmentzones[numalignmentzones].topy =
257           blues->FamilyBlues[i+1];
258         continue;
259       }
260     }
261     /* use this font's Blue zones */
262     alignmentzones[numalignmentzones].bottomy = blues->BlueValues[i];
263     alignmentzones[numalignmentzones].topy = blues->BlueValues[i+1];
264   }
265 
266   /* do the OtherBlues zones */
267   for (i = 0; i < blues->numOtherBlues; i +=2, ++numalignmentzones) {
268     /* all of the OtherBlues zones are bottom zones */
269     alignmentzones[numalignmentzones].topzone = FALSE;
270     if (i < blues->numFamilyOtherBlues) {/* consider FamilyOtherBlues  */
271       p = ILoc(CharSpace,0,blues->OtherBlues[i] - blues->OtherBlues[i+1]);
272       QueryLoc(p, IDENTITY, &dummy, &bluezonepixels);
273       Destroy(p);
274       p = ILoc(CharSpace,0,blues->FamilyOtherBlues[i] -
275         blues->FamilyOtherBlues[i+1]);
276       QueryLoc(p, IDENTITY, &dummy, &familyzonepixels);
277       Destroy(p);
278       /* is the difference in size of the zones less than 1 pixel? */
279       if (FABS(bluezonepixels - familyzonepixels) < 1.0) {
280         /* use the Family zones */
281         alignmentzones[numalignmentzones].bottomy =
282           blues->FamilyOtherBlues[i];
283         alignmentzones[numalignmentzones].topy =
284           blues->FamilyOtherBlues[i+1];
285         continue;
286       }
287     }
288     /* use this font's Blue zones (as opposed to the Family Blues */
289     alignmentzones[numalignmentzones].bottomy = blues->OtherBlues[i];
290     alignmentzones[numalignmentzones].topy = blues->OtherBlues[i+1];
291   }
292 }
293 
294 /**********************************************************************/
295 /* Subroutines and statics for handling of the VSTEM and HSTEM hints. */
296 /**********************************************************************/
297 int InDotSection;             /* DotSection flag */
298 struct stem stems[MAXSTEMS];  /* All STEM hints */
299 int numstems;                 /* Number of STEM hints */
300 int currstartstem;            /* The current starting stem. */
301 int oldvert, oldhor;          /* Remember hint in effect */
302 int oldhorhalf, oldverthalf;  /* Remember which half of the stem */
303 DOUBLE wsoffsetX, wsoffsetY;  /* White space offset - for VSTEM3,HSTEM3 */
304 int wsset;                    /* Flag for whether we've set wsoffsetX,Y */
305 
InitStems(void)306 static void InitStems(void) /* Initialize the STEM hint data structures */
307 {
308   InDotSection = FALSE;
309   currstartstem = numstems = 0;
310   oldvert = oldhor = -1;
311 }
312 
FinitStems(void)313 static void FinitStems(void) /* Terminate the STEM hint data structures */
314 {
315   int i;
316 
317   for (i = 0; i < numstems; i++) {
318     Destroy(stems[i].lbhint);
319     Destroy(stems[i].lbrevhint);
320     Destroy(stems[i].rthint);
321     Destroy(stems[i].rtrevhint);
322   }
323 }
324 
325 /*******************************************************************/
326 /* Compute the dislocation that a stemhint should cause for points */
327 /* inside the stem.                                                */
328 /*******************************************************************/
ComputeStem(int stemno)329 static void ComputeStem(int stemno)
330 {
331   int verticalondevice, idealwidth;
332   DOUBLE stemstart, stemwidth;
333   struct segment *p;
334   int i;
335   DOUBLE stembottom, stemtop, flatposition;
336   DOUBLE Xpixels, Ypixels;
337   DOUBLE unitpixels, onepixel;
338   int suppressovershoot, enforceovershoot;
339   DOUBLE stemshift, flatpospixels, overshoot;
340   DOUBLE widthdiff; /* Number of character space units to adjust width */
341   DOUBLE lbhintvalue, rthintvalue;
342   DOUBLE cxx, cyx, cxy, cyy; /* Transformation matrix */
343   int rotated; /* TRUE if character is on the side, FALSE if upright */
344 
345   /************************************************/
346   /* DETERMINE ORIENTATION OF CHARACTER ON DEVICE */
347   /************************************************/
348 
349   QuerySpace(CharSpace, &cxx, &cyx, &cxy, &cyy); /* Transformation matrix */
350 
351   if (FABS(cxx) < 0.00001 || FABS(cyy) < 0.00001)
352     rotated = TRUE; /* Char is on side (90 or 270 degrees), possibly oblique. */
353   else if (FABS(cyx) < 0.00001 || FABS(cxy) < 0.00001)
354     rotated = FALSE; /* Char is upright (0 or 180 degrees), possibly oblique. */
355   else {
356     stems[stemno].lbhint = NULL; /* Char is at non-axial angle, ignore hints. */
357     stems[stemno].lbrevhint = NULL;
358     stems[stemno].rthint = NULL;
359     stems[stemno].rtrevhint = NULL;
360     return;
361   }
362 
363   /* Determine orientation of stem */
364 
365   if (stems[stemno].vertical) {
366     verticalondevice = !rotated;
367     stemstart = stems[stemno].x;
368     stemwidth = stems[stemno].dx;
369   } else {
370     verticalondevice = rotated;
371     stemstart = stems[stemno].y;
372     stemwidth = stems[stemno].dy;
373   }
374 
375   /* Determine how many pixels (non-negative) correspond to 1 character space
376      unit (unitpixels), and how many character space units (non-negative)
377      correspond to one pixel (onepixel). */
378 
379   if (stems[stemno].vertical)
380     p = ILoc(CharSpace, 1, 0);
381   else
382     p = ILoc(CharSpace, 0, 1);
383   QueryLoc(p, IDENTITY, &Xpixels, &Ypixels);
384   Destroy(p);
385   if (verticalondevice)
386     unitpixels = FABS(Xpixels);
387   else
388     unitpixels = FABS(Ypixels);
389 
390   onepixel = 1.0 / unitpixels;
391 
392   /**********************/
393   /* ADJUST STEM WIDTHS */
394   /**********************/
395 
396   widthdiff = 0.0;
397 
398   /* Find standard stem with smallest width difference from this stem */
399   if (stems[stemno].vertical) { /* vertical stem */
400     if (blues->StdVW != 0)      /* there is an entry for StdVW */
401       widthdiff = blues->StdVW - stemwidth;
402     for (i = 0; i < blues->numStemSnapV; ++i) { /* now look at StemSnapV */
403       if (blues->StemSnapV[i] - stemwidth < widthdiff)
404         /* this standard width is the best match so far for this stem */
405         widthdiff = blues->StemSnapV[i] - stemwidth;
406     }
407   } else {                      /* horizontal stem */
408     if (blues->StdHW != 0)      /* there is an entry for StdHW */
409       widthdiff = blues->StdHW - stemwidth;
410     for (i = 0; i < blues->numStemSnapH; ++i) { /* now look at StemSnapH */
411       if (blues->StemSnapH[i] - stemwidth < widthdiff)
412         /* this standard width is the best match so far for this stem */
413         widthdiff = blues->StemSnapH[i] - stemwidth;
414     }
415   }
416 
417   /* Only expand or contract stems if they differ by less than 1 pixel from
418      the closest standard width, otherwise make the width difference = 0. */
419   if (FABS(widthdiff) > onepixel)
420     widthdiff = 0.0;
421 
422   /* Expand or contract stem to the nearest integral number of pixels. */
423   idealwidth = ROUND((stemwidth + widthdiff) * unitpixels);
424   /* Ensure that all stems are at least one pixel wide. */
425   if (idealwidth == 0)
426     idealwidth = 1;
427   /* Apply ForceBold to vertical stems. */
428   if (blues->ForceBold && stems[stemno].vertical)
429     /* Force this vertical stem to be at least DEFAULTBOLDSTEMWIDTH wide. */
430     if (idealwidth < DEFAULTBOLDSTEMWIDTH)
431       idealwidth = DEFAULTBOLDSTEMWIDTH;
432   /* Now compute the number of character space units necessary */
433   widthdiff = idealwidth * onepixel - stemwidth;
434 
435   /*********************************************************************/
436   /* ALIGNMENT ZONES AND OVERSHOOT SUPPRESSION - HORIZONTAL STEMS ONLY */
437   /*********************************************************************/
438 
439   stemshift = 0.0;
440 
441   if (!stems[stemno].vertical) {
442 
443     /* Get bottom and top boundaries of the stem. */
444     stembottom = stemstart;
445     stemtop = stemstart + stemwidth;
446 
447     /* Find out if this stem intersects an alignment zone (the BlueFuzz  */
448     /* entry in the Private dictionary specifies the number of character */
449     /* units to extend (in both directions) the effect of an alignment   */
450     /* zone on a horizontal stem.  The default value of BlueFuzz is 1.   */
451     for (i = 0; i < numalignmentzones; ++i) {
452       if (alignmentzones[i].topzone) {
453         if (stemtop >= alignmentzones[i].bottomy &&
454             stemtop <= alignmentzones[i].topy + blues->BlueFuzz) {
455           break; /* We found a top-zone */
456         }
457       } else {
458         if (stembottom <= alignmentzones[i].topy &&
459             stembottom >= alignmentzones[i].bottomy - blues->BlueFuzz) {
460           break; /* We found a bottom-zone */
461         }
462       }
463     }
464 
465     if (i < numalignmentzones) { /* We found an intersecting zone (number i). */
466       suppressovershoot = FALSE;
467       enforceovershoot = FALSE;
468 
469       /* When 1 character space unit is rendered smaller than BlueScale
470          device units (pixels), we must SUPPRESS overshoots.  Otherwise,
471          if the top (or bottom) of this stem is more than BlueShift character
472          space units away from the flat position, we must ENFORCE overshoot. */
473 
474       if (unitpixels < blues->BlueScale)
475         suppressovershoot = TRUE;
476       else
477         if (alignmentzones[i].topzone) {
478           if (stemtop >= alignmentzones[i].bottomy + blues->BlueShift)
479             enforceovershoot = TRUE;
480         } else
481           if (stembottom <= alignmentzones[i].topy - blues->BlueShift)
482             enforceovershoot = TRUE;
483 
484       /*************************************************/
485       /* ALIGN THE FLAT POSITION OF THE ALIGNMENT ZONE */
486       /*************************************************/
487 
488       /* Compute the position of the alignment zone's flat position in
489          device space and the amount of shift needed to align it on a
490          pixel boundary. Move all stems this amount. */
491 
492       if (alignmentzones[i].topzone)
493         flatposition = alignmentzones[i].bottomy;
494       else
495         flatposition = alignmentzones[i].topy;
496 
497       /* Find the flat position in pixels */
498       flatpospixels = flatposition * unitpixels;
499 
500       /* Find the stem shift necessary to align the flat
501          position on a pixel boundary, and use this shift for all stems */
502       stemshift = (ROUND(flatpospixels) - flatpospixels) * onepixel;
503 
504       /************************************************/
505       /* HANDLE OVERSHOOT ENFORCEMENT AND SUPPRESSION */
506       /************************************************/
507 
508       /* Compute overshoot amount (non-negative) */
509       if (alignmentzones[i].topzone)
510         overshoot = stemtop - flatposition;
511       else
512         overshoot = flatposition - stembottom;
513 
514       if (overshoot > 0.0) {
515         /* ENFORCE overshoot by shifting the entire stem (if necessary) so that
516            it falls at least one pixel beyond the flat position. */
517 
518         if (enforceovershoot)
519           if (overshoot < onepixel) {
520             if (alignmentzones[i].topzone)
521               stemshift += onepixel - overshoot;
522             else
523               stemshift -= onepixel - overshoot;
524           }
525 
526         /* SUPPRESS overshoot by aligning the stem to the alignment zone's
527            flat position. */
528 
529         if (suppressovershoot) {
530           if (alignmentzones[i].topzone)
531             stemshift -= overshoot;
532           else
533             stemshift += overshoot;
534         }
535       }
536 
537       /************************************************************/
538       /* COMPUTE HINT VALUES FOR EACH SIDE OF THE HORIZONTAL STEM */
539       /************************************************************/
540 
541       /* If the stem was aligned by a topzone, we expand or contract the stem
542          only at the bottom - since the stem top was aligned by the zone.
543          If the stem was aligned by a bottomzone, we expand or contract the stem
544          only at the top - since the stem bottom was aligned by the zone. */
545       if (alignmentzones[i].topzone) {
546         lbhintvalue = stemshift - widthdiff; /* bottom */
547         rthintvalue = stemshift;             /* top    */
548       } else {
549         lbhintvalue = stemshift;             /* bottom */
550         rthintvalue = stemshift + widthdiff; /* top    */
551       }
552 
553       stems[stemno].lbhint    = (struct segment *)Permanent(Loc(CharSpace, 0.0,  lbhintvalue));
554       stems[stemno].lbrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -lbhintvalue));
555       stems[stemno].rthint    = (struct segment *)Permanent(Loc(CharSpace, 0.0,  rthintvalue));
556       stems[stemno].rtrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -rthintvalue));
557 
558       return;
559 
560     } /* endif (i < numalignmentzones) */
561 
562     /* We didn't find any alignment zones intersecting this stem, so
563        proceed with normal stem alignment below. */
564 
565   } /* endif (!stems[stemno].vertical) */
566 
567   /* Align stem with pixel boundaries on device */
568   stemstart = stemstart - widthdiff / 2;
569   stemshift = ROUND(stemstart * unitpixels) * onepixel - stemstart;
570 
571   /* Adjust the boundaries of the stem */
572   lbhintvalue = stemshift - widthdiff / 2; /* left  or bottom */
573   rthintvalue = stemshift + widthdiff / 2; /* right or top    */
574 
575   if (stems[stemno].vertical) {
576     stems[stemno].lbhint    = (struct segment *)Permanent(Loc(CharSpace,  lbhintvalue, 0.0));
577     stems[stemno].lbrevhint = (struct segment *)Permanent(Loc(CharSpace, -lbhintvalue, 0.0));
578     stems[stemno].rthint    = (struct segment *)Permanent(Loc(CharSpace,  rthintvalue, 0.0));
579     stems[stemno].rtrevhint = (struct segment *)Permanent(Loc(CharSpace, -rthintvalue, 0.0));
580   } else {
581     stems[stemno].lbhint    = (struct segment *)Permanent(Loc(CharSpace, 0.0,  lbhintvalue));
582     stems[stemno].lbrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -lbhintvalue));
583     stems[stemno].rthint    = (struct segment *)Permanent(Loc(CharSpace, 0.0,  rthintvalue));
584     stems[stemno].rtrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -rthintvalue));
585   }
586 }
587 
588 #define LEFT   1
589 #define RIGHT  2
590 #define BOTTOM 3
591 #define TOP    4
592 
593 /*********************************************************************/
594 /* Adjust a point using the given stem hint.  Use the left/bottom    */
595 /* hint value or the right/top hint value depending on where the     */
596 /* point lies in the stem.                                           */
597 /*********************************************************************/
Applyhint(struct segment * p,int stemnumber,int half)598 static struct segment *Applyhint(struct segment *p, int stemnumber, int half)
599 {
600   if (half == LEFT || half == BOTTOM)
601     return Join(p, stems[stemnumber].lbhint); /* left  or bottom hint */
602   else
603     return Join(p, stems[stemnumber].rthint); /* right or top    hint */
604 }
605 
606 /*********************************************************************/
607 /* Adjust a point using the given reverse hint.  Use the left/bottom */
608 /* hint value or the right/top hint value depending on where the     */
609 /* point lies in the stem.                                           */
610 /*********************************************************************/
Applyrevhint(struct segment * p,int stemnumber,int half)611 static struct segment *Applyrevhint(struct segment *p, int stemnumber, int half)
612 {
613   if (half == LEFT || half == BOTTOM)
614     return Join(p, stems[stemnumber].lbrevhint); /* left  or bottom hint */
615   else
616     return Join(p, stems[stemnumber].rtrevhint); /* right or top    hint */
617 }
618 
619 /***********************************************************************/
620 /* Find the vertical and horizontal stems that the current point       */
621 /* (x, y) may be involved in.  At most one horizontal and one vertical */
622 /* stem can apply to a single point, since there are no overlaps       */
623 /* allowed.                                                            */
624 /*   The actual hintvalue is returned as a location.                   */
625 /* Hints are ignored inside a DotSection.                              */
626 /***********************************************************************/
FindStems(DOUBLE x,DOUBLE y,DOUBLE dx,DOUBLE dy)627 static struct segment *FindStems(DOUBLE x, DOUBLE y, DOUBLE dx, DOUBLE dy)
628 {
629   int i;
630   int newvert, newhor;
631   struct segment *p;
632   int newhorhalf, newverthalf;
633 
634   if (InDotSection) return(NULL);
635 
636   newvert = newhor = -1;
637   newhorhalf = newverthalf = -1;
638 
639   for (i = currstartstem; i < numstems; i++) {
640     if (stems[i].vertical) { /* VSTEM hint */
641       if ((x >= stems[i].x - EPS) &&
642           (x <= stems[i].x+stems[i].dx + EPS)) {
643         newvert = i;
644         if (dy != 0.0) {
645           if (dy < 0) newverthalf = LEFT;
646           else        newverthalf = RIGHT;
647         } else {
648           if (x < stems[i].x+stems[i].dx / 2) newverthalf = LEFT;
649           else                                newverthalf = RIGHT;
650         }
651       }
652     } else {                 /* HSTEM hint */
653       if ((y >= stems[i].y - EPS) &&
654           (y <= stems[i].y+stems[i].dy + EPS)) {
655         newhor = i;
656         if (dx != 0.0) {
657           if (dx < 0) newhorhalf = TOP;
658           else        newhorhalf = BOTTOM;
659         } else {
660           if (y < stems[i].y+stems[i].dy / 2) newhorhalf = BOTTOM;
661           else                                newhorhalf = TOP;
662         }
663       }
664     }
665   }
666 
667   p = NULL;
668 
669   if (newvert == -1 && oldvert == -1) ; /* Outside of any hints */
670   else if (newvert == oldvert &&
671     newverthalf == oldverthalf); /* No hint change */
672   else if (oldvert == -1) { /* New vertical hint in effect */
673     p = Applyhint(p, newvert, newverthalf);
674   } else if (newvert == -1) { /* Old vertical hint no longer in effect */
675     p = Applyrevhint(p, oldvert, oldverthalf);
676   } else { /* New vertical hint in effect, old hint no longer in effect */
677     p = Applyrevhint(p, oldvert, oldverthalf);
678     p = Applyhint(p, newvert, newverthalf);
679   }
680 
681   if (newhor == -1 && oldhor == -1) ; /* Outside of any hints */
682   else if (newhor == oldhor &&
683     newhorhalf == oldhorhalf) ; /* No hint change */
684   else if (oldhor == -1) { /* New horizontal hint in effect */
685     p = Applyhint(p, newhor, newhorhalf);
686   } else if (newhor == -1) { /* Old horizontal hint no longer in effect */
687     p = Applyrevhint(p, oldhor, oldhorhalf);
688   }
689   else { /* New horizontal hint in effect, old hint no longer in effect */
690     p = Applyrevhint(p, oldhor, oldhorhalf);
691     p = Applyhint(p, newhor, newhorhalf);
692   }
693 
694   oldvert = newvert; oldverthalf = newverthalf;
695   oldhor  = newhor;  oldhorhalf  = newhorhalf;
696 
697   return p;
698 }
699 
700 /******************************************************/
701 /* Subroutines and statics for the Type1Char routines */
702 /******************************************************/
703 
704 static int strindex; /* index into PostScript string being interpreted */
705 static DOUBLE currx, curry; /* accumulated x and y values for hints */
706 
707 struct callstackentry {
708   psobj *currstrP;        /* current CharStringP */
709   int currindex;          /* current strindex */
710   unsigned short currkey; /* current decryption key */
711   };
712 
713 static DOUBLE Stack[MAXSTACK];
714 static int Top;
715 static struct callstackentry CallStack[MAXCALLSTACK];
716 static int CallTop;
717 static DOUBLE PSFakeStack[MAXPSFAKESTACK];
718 static int PSFakeTop;
719 
ClearStack(void)720 static void ClearStack(void)
721 {
722   Top = -1;
723 }
724 
Push(DOUBLE Num)725 static void Push(DOUBLE Num)
726 {
727   if (++Top < MAXSTACK) Stack[Top] = Num;
728   else Error0("Push: Stack full\n");
729 }
730 
ClearCallStack(void)731 static void ClearCallStack(void)
732 {
733   CallTop = -1;
734 }
735 
PushCall(psobj * CurrStrP,int CurrIndex,unsigned short CurrKey)736 static void PushCall(psobj *CurrStrP, int CurrIndex, unsigned short CurrKey)
737 {
738   if (++CallTop < MAXCALLSTACK) {
739     CallStack[CallTop].currstrP = CurrStrP;   /* save CharString pointer */
740     CallStack[CallTop].currindex = CurrIndex; /* save CharString index */
741     CallStack[CallTop].currkey = CurrKey;     /* save decryption key */
742   }
743   else Error0("PushCall: Stack full\n");
744 }
745 
PopCall(psobj ** CurrStrPP,int * CurrIndexP,unsigned short * CurrKeyP)746 static void PopCall(psobj **CurrStrPP, int *CurrIndexP, unsigned short *CurrKeyP)
747 {
748   if (CallTop >= 0) {
749     *CurrStrPP = CallStack[CallTop].currstrP; /* restore CharString pointer */
750     *CurrIndexP = CallStack[CallTop].currindex; /* restore CharString index */
751     *CurrKeyP = CallStack[CallTop--].currkey;   /* restore decryption key */
752   }
753   else Error0("PopCall: Stack empty\n");
754 }
755 
ClearPSFakeStack(void)756 static void ClearPSFakeStack(void)
757 {
758   PSFakeTop = -1;
759 }
760 
761 /* PSFakePush: Pushes a number onto the fake PostScript stack */
PSFakePush(DOUBLE Num)762 static void PSFakePush(DOUBLE Num)
763 {
764   if (++PSFakeTop < MAXPSFAKESTACK) PSFakeStack[PSFakeTop] = Num;
765   else Error0("PSFakePush: Stack full\n");
766 }
767 
768 /* PSFakePop: Removes a number from the top of the fake PostScript stack */
PSFakePop(void)769 static DOUBLE PSFakePop (void)
770 {
771   if (PSFakeTop >= 0) return(PSFakeStack[PSFakeTop--]);
772   else Error01("PSFakePop : Stack empty\n");
773   /*NOTREACHED*/
774 }
775 
776 /***********************************************************************/
777 /* Center a stem on the pixel grid -- used by HStem3 and VStem3        */
778 /***********************************************************************/
CenterStem(DOUBLE edge1,DOUBLE edge2)779 static struct segment *CenterStem(DOUBLE edge1, DOUBLE edge2)
780 {
781   int idealwidth, verticalondevice;
782   DOUBLE leftx, lefty, rightx, righty, center, width;
783   DOUBLE widthx, widthy;
784   DOUBLE shift, shiftx, shifty;
785   DOUBLE Xpixels, Ypixels;
786   struct segment *p;
787 
788   p = Loc(CharSpace, edge1, 0.0);
789   QueryLoc(p, IDENTITY, &leftx, &lefty);
790 
791   p = Join(p, Loc(CharSpace, edge2, 0.0));
792   QueryLoc(p, IDENTITY, &rightx, &righty);
793   Destroy(p);
794 
795   widthx = FABS(rightx - leftx);
796   widthy = FABS(righty - lefty);
797 
798   if (widthy <= EPS) { /* verticalondevice hint */
799     verticalondevice = TRUE;
800     center = (rightx + leftx) / 2.0;
801     width = widthx;
802   }
803   else if (widthx <= EPS) { /* horizontal hint */
804     verticalondevice = FALSE;
805     center = (righty + lefty) / 2.0;
806     width = widthy;
807   }
808   else { /* neither horizontal nor verticalondevice and not oblique */
809     return (NULL);
810   }
811 
812   idealwidth = ROUND(width);
813   if (idealwidth == 0) idealwidth = 1;
814   if (ODD(idealwidth)) {       /* is ideal width odd? */
815     /* center stem over pixel */
816     shift = FLOOR(center) + 0.5 - center;
817   }
818   else {
819     /* align stem on pixel boundary */
820     shift = ROUND(center) - center;
821   }
822 
823   if (verticalondevice) {
824     shiftx = shift;
825     shifty = 0.0;
826   } else {
827     shifty = shift;
828     shiftx = 0.0;
829   }
830 
831   p = Loc(IDENTITY, shiftx, shifty);
832   QueryLoc(p, CharSpace, &Xpixels, &Ypixels);
833   wsoffsetX = Xpixels; wsoffsetY = Ypixels;
834   currx += wsoffsetX; curry += wsoffsetY;
835 
836   return (p);
837 }
838 
839 /*-----------------------------------------------------------------------
840   Decrypt - From Adobe Type 1 book page 63, with some modifications
841 -----------------------------------------------------------------------*/
842 #define KEY 4330 /* Initial key (seed) for CharStrings decryption */
843 #define C1 52845 /* Multiplier for pseudo-random number generator */
844 #define C2 22719 /* Constant for pseudo-random number generator */
845 
846 static unsigned short r; /* Pseudo-random sequence of keys */
847 
Decrypt(unsigned char cipher)848 static unsigned char Decrypt(unsigned char cipher)
849 {
850   unsigned char plain;
851 
852   plain = cipher ^ (r >> 8);
853   r = (cipher + r) * C1 + C2;
854   return plain;
855 }
856 
857 /* Get the next byte from the codestring being interpreted */
DoRead(int * CodeP)858 static int DoRead(int *CodeP)
859 {
860   if (strindex >= CharStringP->len) return(FALSE); /* end of string */
861   *CodeP = Decrypt((unsigned char) CharStringP->data.stringP[strindex++]);
862   return(TRUE);
863 }
864 
865 /* Strip blues->lenIV bytes from CharString and update encryption key */
866 /* (the lenIV entry in the Private dictionary specifies the number of */
867 /* random bytes at the beginning of each CharString; default is 4)    */
StartDecrypt(void)868 static void StartDecrypt(void)
869 {
870   int Code;
871 
872   r = KEY; /* Initial key (seed) for CharStrings decryption */
873   for (strindex = 0; strindex < blues->lenIV;)
874     if (!DoRead(&Code)) /* Read a byte and update decryption key */
875       Error0("StartDecrypt: Premature end of CharString\n");
876 }
877 
Decode(int Code)878 static void Decode(int Code)
879 {
880   int Code1, Code2, Code3, Code4;
881 
882   if (Code <= 31)                           /* Code is [0,31]    */
883     DoCommand(Code);
884   else if (Code <= 246)                     /* Code is [32,246]  */
885     Push((DOUBLE)(Code - 139));
886   else if (Code <= 250) {                   /* Code is [247,250] */
887     if (!DoRead(&Code2)) goto ended;
888     Push((DOUBLE)(((Code - 247) << 8) + Code2 + 108));
889   }
890   else if (Code <= 254) {                   /* Code is [251,254] */
891     if (!DoRead(&Code2)) goto ended;
892     Push((DOUBLE)( -((Code - 251) << 8) - Code2 - 108));
893   }
894   else {                                    /* Code is 255 */
895     if (!DoRead(&Code1)) goto ended;
896     if (!DoRead(&Code2)) goto ended;
897     if (!DoRead(&Code3)) goto ended;
898     if (!DoRead(&Code4)) goto ended;
899     Push((DOUBLE)((((((Code1<<8) + Code2)<<8) + Code3)<<8) + Code4));
900   }
901   return;
902 
903 ended: Error0("Decode: Premature end of Type 1 CharString");
904 }
905 
906 /* Interpret a command code */
DoCommand(int Code)907 static void DoCommand(int Code)
908 {
909   switch(Code) {
910     case HSTEM: /* |- y dy HSTEM |- */
911       /* Vertical range of a horizontal stem zone */
912       if (Top < 1) Error0("DoCommand: Stack low\n");
913       HStem(Stack[0], Stack[1]);
914       ClearStack();
915       break;
916     case VSTEM: /* |- x dx VSTEM |- */
917       /* Horizontal range of a vertical stem zone */
918       if (Top < 1) Error0("DoCommand: Stack low\n");
919       VStem(Stack[0], Stack[1]);
920       ClearStack();
921       break;
922     case VMOVETO: /* |- dy VMOVETO |- */
923       /* Vertical MOVETO, equivalent to 0 dy RMOVETO */
924       if (Top < 0) Error0("DoCommand: Stack low\n");
925       RMoveTo(0.0, Stack[0]);
926       ClearStack();
927       break;
928     case RLINETO: /* |- dx dy RLINETO |- */
929       /* Like RLINETO in PostScript */
930       if (Top < 1) Error0("DoCommand: Stack low\n");
931       RLineTo(Stack[0], Stack[1]);
932       ClearStack();
933       break;
934     case HLINETO: /* |- dx HLINETO |- */
935       /* Horizontal LINETO, equivalent to dx 0 RLINETO */
936       if (Top < 0) Error0("DoCommand: Stack low\n");
937       RLineTo(Stack[0], 0.0);
938       ClearStack();
939       break;
940     case VLINETO: /* |- dy VLINETO |- */
941       /* Vertical LINETO, equivalent to 0 dy RLINETO */
942       if (Top < 0) Error0("DoCommand: Stack low\n");
943       RLineTo(0.0, Stack[0]);
944       ClearStack();
945       break;
946     case RRCURVETO:
947       /* |- dx1 dy1 dx2 dy2 dx3 dy3 RRCURVETO |- */
948       /* Relative RCURVETO, equivalent to dx1 dy1 */
949       /* (dx1+dx2) (dy1+dy2) (dx1+dx2+dx3) */
950       /* (dy1+dy2+dy3) RCURVETO in PostScript */
951       if (Top < 5) Error0("DoCommand: Stack low\n");
952       RRCurveTo(Stack[0], Stack[1], Stack[2], Stack[3],
953         Stack[4], Stack[5]);
954       ClearStack();
955       break;
956     case CLOSEPATH: /* - CLOSEPATH |- */
957       /* Closes a subpath without repositioning the */
958       /* current point */
959       DoClosePath();
960       ClearStack();
961       break;
962     case CALLSUBR: /* subr# CALLSUBR - */
963       /* Calls a CharString subroutine with index */
964       /* subr# from the Subrs array */
965       if (Top < 0) Error0("DoCommand: Stack low\n");
966       CallSubr((int)Stack[Top--]);
967       break;
968     case RETURN: /* - RETURN - */
969       /* Returns from a Subrs array CharString */
970       /* subroutine called with CALLSUBR */
971       Return();
972       break;
973     case ESCAPE: /* ESCAPE to two-byte command code */
974       if (!DoRead(&Code)) Error0("DoCommand: ESCAPE is last byte\n");
975       Escape(Code);
976       break;
977     case HSBW: /* |- sbx wx HSBW |- */
978       /* Set the left sidebearing point to (sbx,0), */
979       /* set the character width vector to (wx,0). */
980       /* Equivalent to sbx 0 wx 0 SBW.  Space */
981       /* character should have sbx = 0 */
982       if (Top < 1) Error0("DoCommand: Stack low\n");
983       Sbw(Stack[0], 0.0, Stack[1], 0.0);
984       ClearStack();
985       break;
986     case ENDCHAR: /* - ENDCHAR |- */
987       /* Finishes a CharString outline */
988       EndChar();
989       ClearStack();
990       break;
991     case RMOVETO: /* |- dx dy RMOVETO |- */
992       /* Behaves like RMOVETO in PostScript */
993       if (Top < 1) Error0("DoCommand: Stack low\n");
994       RMoveTo(Stack[0], Stack[1]);
995       ClearStack();
996       break;
997     case HMOVETO: /* |- dx HMOVETO |- */
998       /* Horizontal MOVETO. Equivalent to dx 0 RMOVETO */
999       if (Top < 0) Error0("DoCommand: Stack low\n");
1000       RMoveTo(Stack[0], 0.0);
1001       ClearStack();
1002       break;
1003     case VHCURVETO: /* |- dy1 dx2 dy2 dx3 VHCURVETO |- */
1004       /* Vertical-Horizontal CURVETO, equivalent to */
1005       /* 0 dy1 dx2 dy2 dx3 0 RRCURVETO */
1006       if (Top < 3) Error0("DoCommand: Stack low\n");
1007       RRCurveTo(0.0, Stack[0], Stack[1], Stack[2],
1008               Stack[3], 0.0);
1009       ClearStack();
1010       break;
1011     case HVCURVETO: /* |- dx1 dx2 dy2 dy3 HVCURVETO |- */
1012       /* Horizontal-Vertical CURVETO, equivalent to */
1013       /* dx1 0 dx2 dy2 0 dy3 RRCURVETO */
1014       if (Top < 3) Error0("DoCommand: Stack low\n");
1015       RRCurveTo(Stack[0], 0.0, Stack[1], Stack[2], 0.0, Stack[3]);
1016       ClearStack();
1017       break;
1018     default: /* Unassigned command code */
1019       ClearStack();
1020       Error1("DoCommand: Unassigned code %d\n", Code);
1021   }
1022 }
1023 
Escape(int Code)1024 static void Escape(int Code)
1025 {
1026   int i, Num;
1027   struct segment *p;
1028 
1029   switch(Code) {
1030     case DOTSECTION: /* - DOTSECTION |- */
1031       /* Brackets an outline section for the dots in */
1032       /* letters such as "i", "j", and "!". */
1033       DotSection();
1034       ClearStack();
1035       break;
1036     case VSTEM3: /* |- x0 dx0 x1 dx1 x2 dx2 VSTEM3 |- */
1037       /* Declares the horizontal ranges of three */
1038       /* vertical stem zones between x0 and x0+dx0, */
1039       /* x1 and x1+dx1, and x2 and x2+dx2. */
1040       if (Top < 5) Error0("DoCommand: Stack low\n");
1041       if (!wsset && ProcessHints) {
1042         /* Shift the whole character so that the middle stem is centered. */
1043         p = CenterStem(Stack[2] + sidebearingX, Stack[3]);
1044         path = Join(path, p);
1045         wsset = 1;
1046       }
1047 
1048       VStem(Stack[0], Stack[1]);
1049       VStem(Stack[2], Stack[3]);
1050       VStem(Stack[4], Stack[5]);
1051       ClearStack();
1052       break;
1053     case HSTEM3: /* |- y0 dy0 y1 dy1 y2 dy2 HSTEM3 |- */
1054       /* Declares the vertical ranges of three hori- */
1055       /* zontal stem zones between y0 and y0+dy0, */
1056       /* y1 and y1+dy1, and y2 and y2+dy2. */
1057       if (Top < 5) Error0("DoCommand: Stack low\n");
1058       HStem(Stack[0], Stack[1]);
1059       HStem(Stack[2], Stack[3]);
1060       HStem(Stack[4], Stack[5]);
1061       ClearStack();
1062       break;
1063     case SEAC: /* |- asb adx ady bchar achar SEAC |- */
1064       /* Standard Encoding Accented Character. */
1065       if (Top < 4) Error0("DoCommand: Stack low\n");
1066       Seac(Stack[0], Stack[1], Stack[2],
1067         (unsigned char) Stack[3],
1068         (unsigned char) Stack[4]);
1069       ClearStack();
1070       break;
1071     case SBW: /* |- sbx sby wx wy SBW |- */
1072       /* Set the left sidebearing point to (sbx,sby), */
1073       /* set the character width vector to (wx,wy). */
1074       if (Top < 3) Error0("DoCommand: Stack low\n");
1075       Sbw(Stack[0], Stack[1], Stack[2], Stack[3]);
1076       ClearStack();
1077       break;
1078     case DIV: /* num1 num2 DIV quotient */
1079       /* Behaves like DIV in the PostScript language */
1080       if (Top < 1) Error0("DoCommand: Stack low\n");
1081       Stack[Top-1] = Div(Stack[Top-1], Stack[Top]);
1082       Top--;
1083       break;
1084     case CALLOTHERSUBR:
1085       /* arg1 ... argn n othersubr# CALLOTHERSUBR - */
1086       /* Make calls on the PostScript interpreter */
1087       if (Top < 1) Error0("DoCommand: Stack low\n");
1088       Num = Stack[Top-1];
1089       if (Top < Num+1) Error0("DoCommand: Stack low\n");
1090       for (i = 0; i < Num; i++) PSFakePush(Stack[Top - i - 2]);
1091       Top -= Num + 2;
1092       CallOtherSubr((int)Stack[Top + Num + 2]);
1093       break;
1094     case POP: /* - POP number */
1095       /* Removes a number from the top of the */
1096       /* PostScript interpreter stack and pushes it */
1097       /* onto the Type 1 BuildChar operand stack */
1098       Push(PSFakePop());
1099       break;
1100     case SETCURRENTPOINT: /* |- x y SETCURRENTPOINT |- */
1101       /* Sets the current point to (x,y) in absolute */
1102       /* character space coordinates without per- */
1103       /* forming a CharString MOVETO command */
1104       if (Top < 1) Error0("DoCommand: Stack low\n");
1105       SetCurrentPoint(Stack[0], Stack[1]);
1106       ClearStack();
1107       break;
1108     default: /* Unassigned escape code command */
1109       ClearStack();
1110       Error1("Escape: Unassigned code %d\n", Code);
1111   }
1112 }
1113 
1114 /* |- y dy HSTEM |- */
1115 /* Declares the vertical range of a horizontal stem zone */
1116 /* between coordinates y and y + dy */
1117 /* y is relative to the left sidebearing point */
HStem(DOUBLE y,DOUBLE dy)1118 static void HStem(DOUBLE y, DOUBLE dy)
1119 {
1120   IfTrace2((FontDebug), "Hstem %f %f\n", y, dy);
1121   if (ProcessHints) {
1122     if (numstems >= MAXSTEMS) Error0("HStem: Too many hints\n");
1123     if (dy < 0.0) {y += dy; dy = -dy;}
1124     stems[numstems].vertical = FALSE;
1125     stems[numstems].x = 0.0;
1126     stems[numstems].y = sidebearingY + y + wsoffsetY;
1127     stems[numstems].dx = 0.0;
1128     stems[numstems].dy = dy;
1129     ComputeStem(numstems);
1130     numstems++;
1131   }
1132 }
1133 
1134 /* |- x dx VSTEM |- */
1135 /* Declares the horizontal range of a vertical stem zone */
1136 /* between coordinates x and x + dx */
1137 /* x is relative to the left sidebearing point */
VStem(DOUBLE x,DOUBLE dx)1138 static void VStem(DOUBLE x, DOUBLE dx)
1139 {
1140   IfTrace2((FontDebug), "Vstem %f %f\n", x, dx);
1141   if (ProcessHints) {
1142     if (numstems >= MAXSTEMS) Error0("VStem: Too many hints\n");
1143     if (dx < 0.0) {x += dx; dx = -dx;}
1144     stems[numstems].vertical = TRUE;
1145     stems[numstems].x = sidebearingX + x + wsoffsetX;
1146     stems[numstems].y = 0.0;
1147     stems[numstems].dx = dx;
1148     stems[numstems].dy = 0.0;
1149     ComputeStem(numstems);
1150     numstems++;
1151   }
1152 }
1153 
1154 /* |- dx dy RLINETO |- */
1155 /* Behaves like RLINETO in PostScript */
RLineTo(DOUBLE dx,DOUBLE dy)1156 static void RLineTo(DOUBLE dx, DOUBLE dy)
1157 {
1158   struct segment *B;
1159 
1160   IfTrace2((FontDebug), "RLineTo %f %f\n", dx, dy);
1161 
1162   B = Loc(CharSpace, dx, dy);
1163 
1164   if (ProcessHints) {
1165     currx += dx;
1166     curry += dy;
1167     /* B = Join(B, FindStems(currx, curry)); */
1168     B = Join(B, FindStems(currx, curry, dx, dy));
1169   }
1170 
1171   path = Join(path, Line(B));
1172 }
1173 
1174 /* |- dx1 dy1 dx2 dy2 dx3 dy3 RRCURVETO |- */
1175 /* Relative RCURVETO, equivalent to dx1 dy1 */
1176 /* (dx1+dx2) (dy1+dy2) (dx1+dx2+dx3) */
1177 /* (dy1+dy2+dy3) RCURVETO in PostScript */
RRCurveTo(DOUBLE dx1,DOUBLE dy1,DOUBLE dx2,DOUBLE dy2,DOUBLE dx3,DOUBLE dy3)1178 static void RRCurveTo(DOUBLE dx1, DOUBLE dy1, DOUBLE dx2, DOUBLE dy2, DOUBLE dx3, DOUBLE dy3)
1179 {
1180   struct segment *B, *C, *D;
1181 
1182   IfTrace4((FontDebug), "RRCurveTo %f %f %f %f ", dx1, dy1, dx2, dy2);
1183   IfTrace2((FontDebug), "%f %f\n", dx3, dy3);
1184 
1185   B = Loc(CharSpace, dx1, dy1);
1186   C = Loc(CharSpace, dx2, dy2);
1187   D = Loc(CharSpace, dx3, dy3);
1188 
1189   if (ProcessHints) {
1190     /* For a Bezier curve, we apply the full hint value to
1191        the Bezier C point (and thereby D point). */
1192     currx += dx1 + dx2 + dx3;
1193     curry += dy1 + dy2 + dy3;
1194     /* C = Join(C, FindStems(currx, curry)); */
1195     C = Join(C, FindStems(currx, curry, dx3, dy3));
1196   }
1197 
1198   /* Since XIMAGER is not completely relative, */
1199   /* we need to add up the delta values */
1200 
1201   C = Join(C, (struct segment *)Dup((struct xobject *)B));
1202   D = Join(D, (struct segment *)Dup((struct xobject *)C));
1203 
1204   path = Join(path, (struct segment *)Bezier(B, C, D));
1205 }
1206 
1207 /* - CLOSEPATH |- */
1208 /* Closes a subpath WITHOUT repositioning the */
1209 /* current point */
DoClosePath(void)1210 static void DoClosePath(void)
1211 {
1212   struct segment *CurrentPoint;
1213 
1214   IfTrace0((FontDebug), "DoClosePath\n");
1215   CurrentPoint = Phantom(path);
1216   path = ClosePath(path);
1217   path = Join(Snap(path), CurrentPoint);
1218 }
1219 
1220 /* subr# CALLSUBR - */
1221 /* Calls a CharString subroutine with index */
1222 /* subr# from the Subrs array */
CallSubr(int subrno)1223 static void CallSubr(int subrno)
1224 {
1225   IfTrace1((FontDebug), "CallSubr %d\n", subrno);
1226   if ((subrno < 0) || (subrno >= SubrsP->len))
1227     Error0("CallSubr: subrno out of range\n");
1228   PushCall(CharStringP, strindex, r);
1229   CharStringP = &SubrsP->data.arrayP[subrno];
1230   StartDecrypt();
1231 }
1232 
1233 /* - RETURN - */
1234 /* Returns from a Subrs array CharString */
1235 /* subroutine called with CALLSUBR */
Return(void)1236 static void Return(void)
1237 {
1238   IfTrace0((FontDebug), "Return\n");
1239   PopCall(&CharStringP, &strindex, &r);
1240 }
1241 
1242 /* - ENDCHAR |- */
1243 /* Finishes a CharString outline */
1244 /* Executes SETCHACHEDEVICE using a bounding box */
1245 /* it computes directly from the character outline */
1246 /* and using the width information acquired from a previous */
1247 /* HSBW or SBW.  It then calls a special version of FILL */
1248 /* or STROKE depending on the value of PaintType in the */
1249 /* font dictionary */
EndChar(void)1250 static void EndChar(void)
1251 {
1252   IfTrace0((FontDebug), "EndChar\n");
1253 
1254   /* There is no need to compute and set bounding box for
1255      the cache, since XIMAGER does that on the fly. */
1256 
1257   /* Perform a Closepath just in case the command was left out */
1258   path = ClosePath(path);
1259 
1260   /* Set character width */
1261   path = Join(Snap(path), Loc(CharSpace, escapementX, escapementY));
1262 
1263 }
1264 
1265 /* |- dx dy RMOVETO |- */
1266 /* Behaves like RMOVETO in PostScript */
RMoveTo(DOUBLE dx,DOUBLE dy)1267 static void RMoveTo(DOUBLE dx, DOUBLE dy)
1268 {
1269   struct segment *B;
1270 
1271   IfTrace2((FontDebug), "RMoveTo %f %f\n", dx, dy);
1272 
1273   B = Loc(CharSpace, dx, dy);
1274 
1275   if (ProcessHints) {
1276     currx += dx;
1277     curry += dy;
1278     /* B = Join(B, FindStems(currx, curry)); */
1279     B = Join(B, FindStems(currx, curry, 0.0, 0.0));
1280   }
1281 
1282   path = Join(path, B);
1283 }
1284 
1285 /* - DOTSECTION |- */
1286 /* Brackets an outline section for the dots in */
1287 /* letters such as "i", "j", and "!". */
DotSection(void)1288 static void DotSection(void)
1289 {
1290   IfTrace0((FontDebug), "DotSection\n");
1291   InDotSection = !InDotSection;
1292 }
1293 
1294 /* |- asb adx ady bchar achar SEAC |- */
1295 /* Standard Encoding Accented Character. */
Seac(DOUBLE asb,DOUBLE adx,DOUBLE ady,unsigned char bchar,unsigned char achar)1296 static void Seac(DOUBLE asb, DOUBLE adx, DOUBLE ady,
1297                  unsigned char bchar, unsigned char achar)
1298 {
1299   int Code;
1300   struct segment *mypath;
1301 
1302   IfTrace4((FontDebug), "SEAC %f %f %f %d ", asb, adx, ady, bchar);
1303   IfTrace1((FontDebug), "%d\n", achar);
1304 
1305   /* Move adx - asb, ady over and up from base char's sbpoint. */
1306   /* (We use adx - asb to counteract the accents sb shift.) */
1307   /* The variables accentoffsetX/Y modify sidebearingX/Y in Sbw(). */
1308   /* Note that these incorporate the base character's sidebearing shift by */
1309   /* using the current sidebearingX, Y values. */
1310   accentoffsetX = sidebearingX + adx - asb;
1311   accentoffsetY = sidebearingY + ady;
1312 
1313   /* Set path = NULL to avoid complaints from Sbw(). */
1314   path = NULL;
1315 
1316   /* Go find the CharString for the accent's code via an upcall */
1317   CharStringP = GetType1CharString(Environment, achar);
1318   if (CharStringP == NULL) {
1319      Error1("Invalid accent ('%03o) in SEAC\n", achar);
1320      return;
1321   }
1322   StartDecrypt();
1323 
1324   ClearStack();
1325   ClearPSFakeStack();
1326   ClearCallStack();
1327 
1328   for (;;) {
1329     if (!DoRead(&Code)) break;
1330     Decode(Code);
1331     if (errflag) return;
1332   }
1333   /* Copy snapped path to mypath and set path to NULL as above. */
1334   mypath = Snap(path);
1335   path = NULL;
1336 
1337   /* We must reset these to null now. */
1338   accentoffsetX = accentoffsetY = 0;
1339 
1340   /* go find the CharString for the base char's code via an upcall */
1341   CharStringP = GetType1CharString(Environment, bchar);
1342   StartDecrypt();
1343 
1344   ClearStack();
1345   ClearPSFakeStack();
1346   ClearCallStack();
1347 
1348   FinitStems();
1349   InitStems();
1350 
1351   for (;;) {
1352     if (!DoRead(&Code)) break;
1353     Decode(Code);
1354     if (errflag) return;
1355   }
1356   path = Join(mypath, path);
1357 }
1358 
1359 
1360 /* |- sbx sby wx wy SBW |- */
1361 /* Set the left sidebearing point to (sbx,sby), */
1362 /* set the character width vector to (wx,wy). */
Sbw(DOUBLE sbx,DOUBLE sby,DOUBLE wx,DOUBLE wy)1363 static void Sbw(DOUBLE sbx, DOUBLE sby, DOUBLE wx, DOUBLE wy)
1364 {
1365   IfTrace4((FontDebug), "SBW %f %f %f %f\n", sbx, sby, wx, wy);
1366 
1367   escapementX = wx; /* Character width vector */
1368   escapementY = wy;
1369 
1370   /* Sidebearing values are sbx, sby args, plus accent offset from Seac(). */
1371   sidebearingX = sbx + accentoffsetX;
1372   sidebearingY = sby + accentoffsetY;
1373 
1374   path = Join(path, Loc(CharSpace, sidebearingX, sidebearingY));
1375   if (ProcessHints) {currx = sidebearingX; curry = sidebearingY;}
1376 }
1377 
1378  /* num1 num2 DIV quotient */
1379 /* Behaves like DIV in the PostScript language */
Div(DOUBLE num1,DOUBLE num2)1380 static DOUBLE Div(DOUBLE num1, DOUBLE num2)
1381 {
1382   IfTrace2((FontDebug), "Div %f %f\n", num1, num2);
1383   return(num1 / num2);
1384 }
1385 
1386 /*
1387   The following four subroutines (FlxProc, FlxProc1, FlxProc2, and
1388   HintReplace) are C versions of the OtherSubrs Programs, which were
1389   were published in the Adobe Type 1 Font Format book.
1390 
1391   The Flex outline fragment is described by
1392     c1: (x0, y0) = c3: (x0, yshrink(y0)) or (xshrink(x0), y0)
1393      "  (x1, y1) =  "  (x1, yshrink(y1)) or (xshrink(x1), y1)
1394      "  (x2, y2) - reference point
1395     c2: (x0, y0) = c4: (x0, yshrink(y0)) or (xshrink(x0), y0)
1396      "  (x1, y1) =  "  (x1, yshrink(y1)) or (xshrink(x1), y1)
1397      "  (x2, y2) =  "  (x2, y2), rightmost endpoint
1398     c3: (x0, y0) - control point, 1st Bezier curve
1399      "  (x1, y1) - control point,      -"-
1400      "  (x2, y2) - end point,          -"-
1401     c4: (x0, y0) - control point, 2nd Bezier curve
1402      "  (x1, y1) - control point,      -"-
1403      "  (x2, y2) - end point,          -"-
1404     ep: (epY, epX) - final endpoint (should be same as c4: (x2, y2))
1405     idmin - minimum Flex height (1/100 pixel) at which to render curves
1406 */
1407 
1408 #define dtransform(dxusr,dyusr,dxdev,dydev) { \
1409   register struct segment *point = Loc(CharSpace, dxusr, dyusr); \
1410   QueryLoc(point, IDENTITY, dxdev, dydev); \
1411   Destroy(point); \
1412 }
1413 
1414 #define itransform(xdev,ydev,xusr,yusr) { \
1415   register struct segment *point = Loc(IDENTITY, xdev, ydev); \
1416   QueryLoc(point, CharSpace, xusr, yusr); \
1417   Destroy(point); \
1418 }
1419 
1420 #define transform(xusr,yusr,xdev,ydev) dtransform(xusr,yusr,xdev,ydev)
1421 
1422 #define PaintType (0)
1423 
1424 #define lineto(x,y) { \
1425   struct segment *CurrentPoint; \
1426   DOUBLE CurrentX, CurrentY; \
1427   CurrentPoint = Phantom(path); \
1428   QueryLoc(CurrentPoint, CharSpace, &CurrentX, &CurrentY); \
1429   Destroy(CurrentPoint); \
1430   RLineTo(x - CurrentX, y - CurrentY); \
1431 }
1432 
1433 #define curveto(x0,y0,x1,y1,x2,y2) { \
1434   struct segment *CurrentPoint; \
1435   DOUBLE CurrentX, CurrentY; \
1436   CurrentPoint = Phantom(path); \
1437   QueryLoc(CurrentPoint, CharSpace, &CurrentX, &CurrentY); \
1438   Destroy(CurrentPoint); \
1439   RRCurveTo(x0 - CurrentX, y0 - CurrentY, x1 - x0, y1 - y0, x2 - x1, y2 - y1); \
1440 }
1441 
1442 #define xshrink(x) ((x - c4x2) * shrink +c4x2)
1443 #define yshrink(y) ((y - c4y2) * shrink +c4y2)
1444 
1445 #define PickCoords(flag) \
1446   if (flag) { /* Pick "shrunk" coordinates */ \
1447     x0 = c1x0; y0 = c1y0; \
1448     x1 = c1x1; y1 = c1y1; \
1449     x2 = c1x2; y2 = c1y2; \
1450     x3 = c2x0; y3 = c2y0; \
1451     x4 = c2x1; y4 = c2y1; \
1452     x5 = c2x2; y5 = c2y2; \
1453   } else { /* Pick original coordinates */ \
1454     x0 = c3x0; y0 = c3y0; \
1455     x1 = c3x1; y1 = c3y1; \
1456     x2 = c3x2; y2 = c3y2; \
1457     x3 = c4x0; y3 = c4y0; \
1458     x4 = c4x1; y4 = c4y1; \
1459     x5 = c4x2; y5 = c4y2; \
1460   }
1461 
1462 /* FlxProc() = OtherSubrs[0]; Main part of Flex          */
1463 /*   Calling sequence: 'idmin epX epY 3 0 callothersubr' */
1464 /*   Computes Flex values, and renders the Flex path,    */
1465 /*   and returns (leaves) ending coordinates on stack    */
FlxProc(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)1466 static void FlxProc(DOUBLE c1x2, DOUBLE c1y2,
1467              DOUBLE c3x0, DOUBLE c3y0, DOUBLE c3x1, DOUBLE c3y1, DOUBLE c3x2, DOUBLE c3y2,
1468              DOUBLE c4x0, DOUBLE c4y0, DOUBLE c4x1, DOUBLE c4y1, DOUBLE c4x2, DOUBLE c4y2,
1469              DOUBLE epY, DOUBLE epX, int idmin)
1470 {
1471   DOUBLE dmin;
1472   DOUBLE c1x0, c1y0, c1x1, c1y1;
1473   DOUBLE c2x0, c2y0, c2x1, c2y1, c2x2, c2y2;
1474   char yflag;
1475   DOUBLE x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5;
1476   DOUBLE cxx, cyx, cxy, cyy; /* Transformation matrix */
1477   int flipXY;
1478   DOUBLE x, y;
1479   DOUBLE erosion = 1; /* Device parameter */
1480     /* Erosion may have different value specified in 'internaldict' */
1481   DOUBLE shrink;
1482   DOUBLE dX, dY;
1483   char erode;
1484   DOUBLE eShift;
1485   DOUBLE cx, cy;
1486   DOUBLE ex, ey;
1487 
1488   Destroy(path);
1489   path = FlxOldPath; /* Restore previous path (stored in FlxProc1) */
1490 
1491   if (ProcessHints) {
1492     dmin = ABS(idmin) / 100.0; /* Minimum Flex height in pixels */
1493 
1494     c2x2 = c4x2; c2y2 = c4y2; /* Point c2 = c4 */
1495 
1496     yflag = FABS(c1y2 - c3y2) > FABS(c1x2 - c3x2); /* Flex horizontal? */
1497 
1498     QuerySpace(CharSpace, &cxx, &cyx, &cxy, &cyy); /* Transformation matrix */
1499 
1500     if (FABS(cxx) < 0.00001 || FABS(cyy) < 0.00001)
1501       flipXY = -1; /* Char on side */
1502     else if (FABS(cyx) < 0.00001 || FABS(cxy) < 0.00001)
1503       flipXY = 1; /* Char upright */
1504     else
1505       flipXY = 0; /* Char at angle */
1506 
1507     if (yflag) { /* Flex horizontal */
1508       if (flipXY == 0 || c3y2 == c4y2) { /* Char at angle or Flex height = 0 */
1509         PickCoords(FALSE); /* Pick original control points */
1510       } else {
1511         shrink = FABS((c1y2 - c4y2) / (c3y2 - c4y2)); /* Slope */
1512 
1513         c1x0 = c3x0; c1y0 = yshrink(c3y0);
1514         c1x1 = c3x1; c1y1 = yshrink(c3y1);
1515         c2x0 = c4x0; c2y0 = yshrink(c4y0);
1516         c2x1 = c4x1; c2y1 = yshrink(c4y1);
1517 
1518         dtransform(0.0, ROUND(c3y2-c1y2), &x, &y); /* Flex height in pixels */
1519         dY = FABS((flipXY == 1) ? y : x);
1520         PickCoords(dY < dmin); /* If Flex small, pick 'shrunk' control points */
1521 
1522         if (FABS(y2 - c1y2) > 0.001) { /* Flex 'non-zero'? */
1523           transform(c1x2, c1y2, &x, &y);
1524 
1525           if (flipXY == 1) {
1526             cx = x; cy = y;
1527           } else {
1528             cx = y; cy = x;
1529           }
1530 
1531           dtransform(0.0, ROUND(y2-c1y2), &x, &y);
1532           dY = (flipXY == 1) ? y : x;
1533           if (ROUND(dY) != 0)
1534             dY = ROUND(dY);
1535           else
1536             dY = (dY < 0) ? -1 : 1;
1537 
1538           erode = PaintType != 2 && erosion >= 0.5;
1539           if (erode)
1540             cy -= 0.5;
1541           ey = cy + dY;
1542           ey = CEIL(ey) - ey + FLOOR(ey);
1543           if (erode)
1544             ey += 0.5;
1545 
1546           if (flipXY == 1) {
1547             itransform(cx, ey, &x, &y);
1548           } else {
1549             itransform(ey, cx, &x, &y);
1550           }
1551 
1552           eShift = y - y2;
1553           y1 += eShift;
1554           y2 += eShift;
1555           y3 += eShift;
1556         }
1557       }
1558     } else { /* Flex vertical */
1559       if (flipXY == 0 || c3x2 == c4x2) { /* Char at angle or Flex height = 0 */
1560         PickCoords(FALSE); /* Pick original control points */
1561       } else {
1562         shrink = FABS((c1x2 - c4x2) / (c3x2 - c4x2)); /* Slope */
1563 
1564         c1x0 = xshrink(c3x0); c1y0 = c3y0;
1565         c1x1 = xshrink(c3x1); c1y1 = c3y1;
1566         c2x0 = xshrink(c4x0); c2y0 = c4y0;
1567         c2x1 = xshrink(c4x1); c2y1 = c4y1;
1568 
1569         dtransform(ROUND(c3x2 - c1x2), 0.0, &x, &y); /* Flex height in pixels */
1570         dX = FABS((flipXY == -1) ? y : x);
1571         PickCoords(dX < dmin); /* If Flex small, pick 'shrunk' control points */
1572 
1573         if (FABS(x2 - c1x2) > 0.001) {
1574           transform(c1x2, c1y2, &x, &y);
1575           if (flipXY == -1) {
1576             cx = y; cy = x;
1577           } else {
1578             cx = x; cy = y;
1579           }
1580 
1581           dtransform(ROUND(x2-c1x2), 0.0, &x, &y);
1582           dX = (flipXY == -1) ? y : x;
1583           if (ROUND(dX) != 0)
1584             dX = ROUND(dX);
1585           else
1586             dX = (dX < 0) ? -1 : 1;
1587 
1588           erode = PaintType != 2 && erosion >= 0.5;
1589           if (erode)
1590             cx -= 0.5;
1591           ex = cx + dX;
1592           ex = CEIL(ex) - ex + FLOOR(ex);
1593           if (erode)
1594             ex += 0.5;
1595 
1596           if (flipXY == -1) {
1597             itransform(cy, ex, &x, &y);
1598           } else {
1599             itransform(ex, cy, &x, &y);
1600           }
1601 
1602           eShift = x - x2;
1603           x1 += eShift;
1604           x2 += eShift;
1605           x3 += eShift;
1606         }
1607       }
1608     }
1609 
1610     if (x2 == x5 || y2 == y5) {
1611       lineto(x5, y5);
1612     } else {
1613       curveto(x0, y0, x1, y1, x2, y2);
1614       curveto(x3, y3, x4, y4, x5, y5);
1615     }
1616   } else { /* ProcessHints is off */
1617     PickCoords(FALSE); /* Pick original control points */
1618     curveto(x0, y0, x1, y1, x2, y2);
1619     curveto(x3, y3, x4, y4, x5, y5);
1620   }
1621 
1622   PSFakePush(epY);
1623   PSFakePush(epX);
1624 }
1625 
1626 /* FlxProc1() = OtherSubrs[1]; Part of Flex            */
1627 /*   Calling sequence: '0 1 callothersubr'             */
1628 /*   Saves and clears path, then restores currentpoint */
FlxProc1(void)1629 static void FlxProc1(void)
1630 {
1631   struct segment *CurrentPoint;
1632 
1633   CurrentPoint = Phantom(path);
1634 
1635   FlxOldPath = path;
1636   path = CurrentPoint;
1637 }
1638 
1639 /* FlxProc2() = OtherSubrs[2]; Part of Flex */
1640 /*   Calling sequence: '0 2 callothersubr'  */
1641 /*   Returns currentpoint on stack          */
FlxProc2(void)1642 static void FlxProc2(void)
1643 {
1644   struct segment *CurrentPoint;
1645   DOUBLE CurrentX, CurrentY;
1646 
1647   CurrentPoint = Phantom(path);
1648   QueryLoc(CurrentPoint, CharSpace, &CurrentX, &CurrentY);
1649   Destroy(CurrentPoint);
1650 
1651   /* Push CurrentPoint on fake PostScript stack */
1652   PSFakePush(CurrentX);
1653   PSFakePush(CurrentY);
1654 }
1655 
1656 /* HintReplace() = OtherSubrs[3]; Hint Replacement            */
1657 /*   Calling sequence: 'subr# 1 3 callothersubr pop callsubr' */
1658 /*   Reinitializes stem hint structure                        */
HintReplace(void)1659 static void HintReplace(void)
1660 {
1661   /* Effectively retire the current stems, but keep them around for */
1662   /* revhint use in case we are in a stem when we replace hints. */
1663   currstartstem = numstems;
1664 
1665   /* 'subr#' is left on PostScript stack (for 'pop callsubr') */
1666 }
1667 
1668 /* arg1 ... argn n othersubr# CALLOTHERSUBR - */
1669 /* Make calls on the PostScript interpreter (or call equivalent C code) */
1670 /* NOTE: The n arguments have been pushed on the fake PostScript stack */
CallOtherSubr(int othersubrno)1671 static void CallOtherSubr(int othersubrno)
1672 {
1673   IfTrace1((FontDebug), "CallOtherSubr %d\n", othersubrno);
1674 
1675   switch(othersubrno) {
1676     case 0: /* OtherSubrs[0]; Main part of Flex */
1677       if (PSFakeTop < 16) Error0("CallOtherSubr: PSFakeStack low");
1678       ClearPSFakeStack();
1679       FlxProc(
1680         PSFakeStack[0],  PSFakeStack[1],  PSFakeStack[2],  PSFakeStack[3],
1681         PSFakeStack[4],  PSFakeStack[5],  PSFakeStack[6],  PSFakeStack[7],
1682         PSFakeStack[8],  PSFakeStack[9],  PSFakeStack[10], PSFakeStack[11],
1683         PSFakeStack[12], PSFakeStack[13], PSFakeStack[14], PSFakeStack[15],
1684         (int) PSFakeStack[16]
1685       );
1686       break;
1687     case 1: /* OtherSubrs[1]; Part of Flex */
1688       FlxProc1();
1689       break;
1690     case 2: /* OtherSubrs[2]; Part of Flex */
1691       FlxProc2();
1692       break;
1693     case 3: /* OtherSubrs[3]; Hint Replacement */
1694       HintReplace();
1695       break;
1696     default: { /* call OtherSubrs[4] or higher if PostScript is present */
1697     }
1698   }
1699 }
1700 
1701 /* |- x y SETCURRENTPOINT |- */
1702 /* Sets the current point to (x,y) in absolute */
1703 /* character space coordinates without per- */
1704 /* forming a CharString MOVETO command */
SetCurrentPoint(DOUBLE x,DOUBLE y)1705 static void SetCurrentPoint(DOUBLE x, DOUBLE y)
1706 {
1707   IfTrace2((FontDebug), "SetCurrentPoint %f %f\n", x, y);
1708 
1709   currx = x;
1710   curry = y;
1711 }
1712 
1713 /* The Type1Char routine for use by PostScript. */
1714 /************************************************/
Type1Char(psfont * FontP,struct XYspace * S,psobj * charstrP,psobj * subrsP,psobj * osubrsP,struct blues_struct * bluesP,int * modeP)1715 struct xobject *Type1Char(
1716   psfont *FontP,
1717   struct XYspace *S,
1718   psobj *charstrP,
1719   psobj *subrsP,
1720   psobj *osubrsP,
1721   struct blues_struct *bluesP,  /* FontID's ptr to the blues struct */
1722   int *modeP)
1723 {
1724   int Code;
1725 
1726   path = NULL;
1727   errflag = FALSE;
1728 
1729   /* Make parameters available to all Type1 routines */
1730   Environment = FontP;
1731   CharSpace = S; /* used when creating path elements */
1732   CharStringP = charstrP;
1733   SubrsP = subrsP;
1734   OtherSubrsP = osubrsP;
1735   ModeP = modeP;
1736 
1737     blues = bluesP;
1738 
1739   /* compute the alignment zones */
1740   ComputeAlignmentZones();
1741 
1742   StartDecrypt();
1743 
1744   ClearStack();
1745   ClearPSFakeStack();
1746   ClearCallStack();
1747 
1748   InitStems();
1749 
1750   currx = curry = 0;
1751   escapementX = escapementY = 0;
1752   sidebearingX = sidebearingY = 0;
1753   accentoffsetX = accentoffsetY = 0;
1754   wsoffsetX = wsoffsetY = 0;           /* No shift to preserve whitspace. */
1755   wsset = 0;                           /* wsoffsetX,Y haven't been set yet. */
1756 
1757   for (;;) {
1758     if (!DoRead(&Code)) break;
1759     Decode(Code);
1760     if (errflag) break;
1761   }
1762 
1763   FinitStems();
1764 
1765 
1766   /* Clean up if an error has occurred */
1767   if (errflag) {
1768     if (path != NULL) {
1769       Destroy(path); /* Reclaim storage */
1770       path = NULL;   /* Indicate that character could not be built */
1771     }
1772   }
1773 
1774   return((struct xobject *) path);
1775 }
1776 
1777