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