summaryrefslogtreecommitdiff
path: root/src/Type1
diff options
context:
space:
mode:
Diffstat (limited to 'src/Type1')
-rw-r--r--src/Type1/arith.c484
-rw-r--r--src/Type1/arith.h70
-rw-r--r--src/Type1/blues.h93
-rw-r--r--src/Type1/cluts.h35
-rw-r--r--src/Type1/curves.c217
-rw-r--r--src/Type1/curves.h40
-rw-r--r--src/Type1/digit.h64
-rw-r--r--src/Type1/fontfcn.c308
-rw-r--r--src/Type1/fontfcn.h98
-rw-r--r--src/Type1/fonts.h49
-rw-r--r--src/Type1/hdigit.h94
-rw-r--r--src/Type1/hints.c919
-rw-r--r--src/Type1/hints.h42
-rw-r--r--src/Type1/lines.c186
-rw-r--r--src/Type1/lines.h37
-rw-r--r--src/Type1/objects.c1125
-rw-r--r--src/Type1/objects.h291
-rw-r--r--src/Type1/paths.c1506
-rw-r--r--src/Type1/paths.h197
-rw-r--r--src/Type1/pictures.h48
-rw-r--r--src/Type1/regions.c1749
-rw-r--r--src/Type1/regions.h213
-rw-r--r--src/Type1/scanfont.c1519
-rw-r--r--src/Type1/spaces.c998
-rw-r--r--src/Type1/spaces.h140
-rw-r--r--src/Type1/strokes.h38
-rw-r--r--src/Type1/t1funcs.c694
-rw-r--r--src/Type1/t1hdigit.h40
-rw-r--r--src/Type1/t1imager.h148
-rw-r--r--src/Type1/t1info.c488
-rw-r--r--src/Type1/t1intf.h36
-rw-r--r--src/Type1/t1io.c294
-rw-r--r--src/Type1/t1malloc.c735
-rw-r--r--src/Type1/t1snap.c79
-rw-r--r--src/Type1/t1stdio.h68
-rw-r--r--src/Type1/t1stub.c42
-rw-r--r--src/Type1/token.c1212
-rw-r--r--src/Type1/token.h77
-rw-r--r--src/Type1/tokst.h508
-rw-r--r--src/Type1/trig.h35
-rw-r--r--src/Type1/type1.c1810
-rw-r--r--src/Type1/util.c195
-rw-r--r--src/Type1/util.h182
43 files changed, 17203 insertions, 0 deletions
diff --git a/src/Type1/arith.c b/src/Type1/arith.c
new file mode 100644
index 0000000..65162ea
--- /dev/null
+++ b/src/Type1/arith.c
@@ -0,0 +1,484 @@
+/* $Xorg: arith.c,v 1.3 2000/08/17 19:46:29 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+ /* ARITH CWEB V0006 ******** */
+/*
+:h1.ARITH Module - Portable Module for Multiple Precision Fixed Point Arithmetic
+
+This module provides division and multiplication of 64-bit fixed point
+numbers. (To be more precise, the module works on numbers that take
+two 'longs' to store. That is almost always equivalent to saying 64-bit
+numbers.)
+
+Note: it is frequently easy and desirable to recode these functions in
+assembly language for the particular processor being used, because
+assembly language, unlike C, will have 64-bit multiply products and
+64-bit dividends. This module is offered as a portable version.
+
+&author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com) and Sten F. Andler
+
+
+:h3.Include Files
+
+The included files are:
+*/
+
+#include "objects.h"
+#include "spaces.h"
+#include "arith.h"
+
+/*
+:h3.
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+Reference for all algorithms: Donald E. Knuth, "The Art of Computer
+Programming, Volume 2, Semi-Numerical Algorithms," Addison-Wesley Co.,
+Massachusetts, 1969, pp. 229-279.
+
+Knuth talks about a 'digit' being an arbitrary sized unit and a number
+being a sequence of digits. We'll take a digit to be a 'short'.
+The following assumption must be valid for these algorithms to work:
+:ol.
+:li.A 'long' is two 'short's.
+:eol.
+The following code is INDEPENDENT of:
+:ol.
+:li.The actual size of a short.
+:li.Whether shorts and longs are stored most significant byte
+first or least significant byte first.
+:eol.
+
+SHORTSIZE is the number of bits in a short; LONGSIZE is the number of
+bits in a long; MAXSHORT is the maximum unsigned short:
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+ASSEMBLE concatenates two shorts to form a long:
+*/
+#define ASSEMBLE(hi,lo) ((((unsigned long)hi)<<SHORTSIZE)+(lo))
+/*
+HIGHDIGIT extracts the most significant short from a long; LOWDIGIT
+extracts the least significant short from a long:
+*/
+#define HIGHDIGIT(u) ((u)>>SHORTSIZE)
+#define LOWDIGIT(u) ((u)&MAXSHORT)
+
+/*
+SIGNBITON tests the high order bit of a long 'w':
+*/
+#define SIGNBITON(w) (((long)w)<0)
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h2.Double Long Arithmetic
+
+:h3.DLmult() - Multiply Two Longs to Yield a Double Long
+
+The two multiplicands must be positive.
+*/
+
+void DLmult(product, u, v)
+ register doublelong *product;
+ register unsigned long u;
+ register unsigned long v;
+{
+#ifdef LONG64
+/* printf("DLmult(? ?, %lx, %lx)\n", u, v); */
+ *product = u*v;
+/* printf("DLmult returns %lx\n", *product); */
+#else
+ register unsigned long u1, u2; /* the digits of u */
+ register unsigned long v1, v2; /* the digits of v */
+ register unsigned int w1, w2, w3, w4; /* the digits of w */
+ register unsigned long t; /* temporary variable */
+/* printf("DLmult(? ?, %x, %x)\n", u, v); */
+ u1 = HIGHDIGIT(u);
+ u2 = LOWDIGIT(u);
+ v1 = HIGHDIGIT(v);
+ v2 = LOWDIGIT(v);
+
+ if (v2 == 0) w4 = w3 = w2 = 0;
+ else
+ {
+ t = u2 * v2;
+ w4 = LOWDIGIT(t);
+ t = u1 * v2 + HIGHDIGIT(t);
+ w3 = LOWDIGIT(t);
+ w2 = HIGHDIGIT(t);
+ }
+
+ if (v1 == 0) w1 = 0;
+ else
+ {
+ t = u2 * v1 + w3;
+ w3 = LOWDIGIT(t);
+ t = u1 * v1 + w2 + HIGHDIGIT(t);
+ w2 = LOWDIGIT(t);
+ w1 = HIGHDIGIT(t);
+ }
+
+ product->high = ASSEMBLE(w1, w2);
+ product->low = ASSEMBLE(w3, w4);
+#endif /* LONG64 else */
+}
+
+/*
+:h2.DLdiv() - Divide Two Longs by One Long, Yielding Two Longs
+
+Both the dividend and the divisor must be positive.
+*/
+
+void DLdiv(quotient, divisor)
+ doublelong *quotient; /* also where dividend is, originally */
+ unsigned long divisor;
+{
+#ifdef LONG64
+/* printf("DLdiv(%lx %lx)\n", quotient, divisor); */
+ *quotient /= divisor;
+/* printf("DLdiv returns %lx\n", *quotient); */
+#else
+ register unsigned long u1u2 = quotient->high;
+ register unsigned long u3u4 = quotient->low;
+ register long u3; /* single digit of dividend */
+ register int v1,v2; /* divisor in registers */
+ register long t; /* signed copy of u1u2 */
+ register int qhat; /* guess at the quotient digit */
+ register unsigned long q3q4; /* low two digits of quotient */
+ register int shift; /* holds the shift value for normalizing */
+ register int j; /* loop variable */
+
+/* printf("DLdiv(%x %x, %x)\n", quotient->high, quotient->low, divisor); */
+ /*
+ * Knuth's algorithm works if the dividend is smaller than the
+ * divisor. We can get to that state quickly:
+ */
+ if (u1u2 >= divisor) {
+ quotient->high = u1u2 / divisor;
+ u1u2 %= divisor;
+ }
+ else
+ quotient->high = 0;
+
+ if (divisor <= MAXSHORT) {
+
+ /*
+ * This is the case where the divisor is contained in one
+ * 'short'. It is worthwhile making this fast:
+ */
+ u1u2 = ASSEMBLE(u1u2, HIGHDIGIT(u3u4));
+ q3q4 = u1u2 / divisor;
+ u1u2 %= divisor;
+ u1u2 = ASSEMBLE(u1u2, LOWDIGIT(u3u4));
+ quotient->low = ASSEMBLE(q3q4, u1u2 / divisor);
+ return;
+ }
+
+
+ /*
+ * At this point the divisor is a true 'long' so we must use
+ * Knuth's algorithm.
+ *
+ * Step D1: Normalize divisor and dividend (this makes our 'qhat'
+ * guesses more accurate):
+ */
+ for (shift=0; !SIGNBITON(divisor); shift++, divisor <<= 1) { ; }
+ shift--;
+ divisor >>= 1;
+
+ if ((u1u2 >> (LONGSIZE - shift)) != 0 && shift != 0)
+ abort("DLdiv: dividend too large");
+ u1u2 = (u1u2 << shift) + ((shift == 0) ? 0 : u3u4 >> (LONGSIZE - shift));
+ u3u4 <<= shift;
+
+ /*
+ * Step D2: Begin Loop through digits, dividing u1,u2,u3 by v1,v2,
+ * then shifting U left by 1 digit:
+ */
+ v1 = HIGHDIGIT(divisor);
+ v2 = LOWDIGIT(divisor);
+ q3q4 = 0;
+ u3 = HIGHDIGIT(u3u4);
+
+ for (j=0; j < 2; j++) {
+
+ /*
+ * Step D3: make a guess (qhat) at the next quotient denominator:
+ */
+ qhat = (HIGHDIGIT(u1u2) == v1) ? MAXSHORT : u1u2 / v1;
+ /*
+ * At this point Knuth would have us further refine our
+ * guess, since we know qhat is too big if
+ *
+ * v2 * qhat > ASSEMBLE(u1u2 % v, u3)
+ *
+ * That would make sense if u1u2 % v was easy to find, as it
+ * would be in assembly language. I ignore this step, and
+ * repeat step D6 if qhat is too big.
+ */
+
+ /*
+ * Step D4: Multiply v1,v2 times qhat and subtract it from
+ * u1,u2,u3:
+ */
+ u3 -= qhat * v2;
+ /*
+ * The high digit of u3 now contains the "borrow" for the
+ * rest of the substraction from u1,u2.
+ * Sometimes we can lose the sign bit with the above.
+ * If so, we have to force the high digit negative:
+ */
+ t = HIGHDIGIT(u3);
+ if (t > 0)
+ t |= -1 << SHORTSIZE;
+ t += u1u2 - qhat * v1;
+/* printf("..>divide step qhat=%x t=%x u3=%x u1u2=%x v1=%x v2=%x\n",
+ qhat, t, u3, u1u2, v1, v2); */
+ while (t < 0) { /* Test is Step D5. */
+
+ /*
+ * D6: Oops, qhat was too big. Add back in v1,v2 and
+ * decrease qhat by 1:
+ */
+ u3 = LOWDIGIT(u3) + v2;
+ t += HIGHDIGIT(u3) + v1;
+ qhat--;
+/* printf("..>>qhat correction t=%x u3=%x qhat=%x\n", t, u3, qhat); */
+ }
+ /*
+ * Step D7: shift U left one digit and loop:
+ */
+ u1u2 = t;
+ if (HIGHDIGIT(u1u2) != 0)
+ abort("divide algorithm error");
+ u1u2 = ASSEMBLE(u1u2, LOWDIGIT(u3));
+ u3 = LOWDIGIT(u3u4);
+ q3q4 = ASSEMBLE(q3q4, qhat);
+ }
+ quotient->low = q3q4;
+/* printf("DLdiv returns %x %x\n", quotient->high, quotient->low); */
+#endif /* !LONG64 */
+ return;
+}
+
+/*
+:h3.DLadd() - Add Two Double Longs
+
+In this case, the doublelongs may be signed. The algorithm takes the
+piecewise sum of the high and low longs, with the possibility that the
+high should be incremented if there is a carry out of the low. How to
+tell if there is a carry? Alex Harbury suggested that if the sum of
+the lows is less than the max of the lows, there must have been a
+carry. Conversely, if there was a carry, the sum of the lows must be
+less than the max of the lows. So, the test is "if and only if".
+*/
+
+void DLadd(u, v)
+ doublelong *u; /* u = u + v */
+ doublelong *v;
+{
+#ifdef LONG64
+/* printf("DLadd(%lx %lx)\n", *u, *v); */
+ *u = *u + *v;
+/* printf("DLadd returns %lx\n", *u); */
+#else
+ register unsigned long lowmax = MAX(u->low, v->low);
+
+/* printf("DLadd(%x %x, %x %x)\n", u->high, u->low, v->high, v->low); */
+ u->high += v->high;
+ u->low += v->low;
+ if (lowmax > u->low)
+ u->high++;
+#endif
+}
+/*
+:h3.DLsub() - Subtract Two Double Longs
+
+Testing for a borrow is even easier. If the v.low is greater than
+u.low, there must be a borrow.
+*/
+
+void DLsub(u, v)
+ doublelong *u; /* u = u - v */
+ doublelong *v;
+{
+#ifdef LONG64
+/* printf("DLsub(%lx %lx)\n", *u, *v); */
+ *u = *u - *v;
+/* printf("DLsub returns %lx\n", *u); */
+#else
+/* printf("DLsub(%x %x, %x %x)\n", u->high, u->low, v->high, v->low);*/
+ u->high -= v->high;
+ if (v->low > u->low)
+ u->high--;
+ u->low -= v->low;
+#endif
+}
+/*
+:h3.DLrightshift() - Macro to Shift Double Long Right by N
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h2.Fractional Pel Arithmetic
+*/
+/*
+:h3.FPmult() - Multiply Two Fractional Pel Values
+
+This funtion first calculates w = u * v to "doublelong" precision.
+It then shifts w right by FRACTBITS bits, and checks that no
+overflow will occur when the resulting value is passed back as
+a fractpel.
+*/
+
+fractpel FPmult(u, v)
+ register fractpel u,v;
+{
+ doublelong w;
+ register int negative = FALSE; /* sign flag */
+#ifdef LONG64
+ register fractpel ret;
+#endif
+
+ if ((u == 0) || (v == 0)) return (0);
+
+
+ if (u < 0) {u = -u; negative = TRUE;}
+ if (v < 0) {v = -v; negative = !negative;}
+
+ if (u == TOFRACTPEL(1)) return ((negative) ? -v : v);
+ if (v == TOFRACTPEL(1)) return ((negative) ? -u : u);
+
+ DLmult(&w, u, v);
+ DLrightshift(w, FRACTBITS);
+#ifndef LONG64
+ if (w.high != 0 || SIGNBITON(w.low)) {
+ IfTrace2(TRUE,"FPmult: overflow, %px%p\n", u, v);
+ w.low = TOFRACTPEL(MAXSHORT);
+ }
+
+ return ((negative) ? -w.low : w.low);
+#else
+ if (w & 0xffffffff80000000L ) {
+ IfTrace2(TRUE,"FPmult: overflow, %px%p\n", u, v);
+ ret = TOFRACTPEL(MAXSHORT);
+ }
+ else
+ ret = (fractpel)w;
+
+ return ((negative) ? -ret : ret);
+#endif
+}
+
+/*
+:h3.FPdiv() - Divide Two Fractional Pel Values
+
+These values may be signed. The function returns the quotient.
+*/
+
+fractpel FPdiv(dividend, divisor)
+ register fractpel dividend;
+ register fractpel divisor;
+{
+ doublelong w; /* result will be built here */
+ int negative = FALSE; /* flag for sign bit */
+#ifdef LONG64
+ register fractpel ret;
+#endif
+
+ if (dividend < 0) {
+ dividend = -dividend;
+ negative = TRUE;
+ }
+ if (divisor < 0) {
+ divisor = -divisor;
+ negative = !negative;
+ }
+#ifndef LONG64
+ w.low = dividend << FRACTBITS;
+ w.high = dividend >> (LONGSIZE - FRACTBITS);
+ DLdiv(&w, divisor);
+ if (w.high != 0 || SIGNBITON(w.low)) {
+ IfTrace2(TRUE,"FPdiv: overflow, %p/%p\n", dividend, divisor);
+ w.low = TOFRACTPEL(MAXSHORT);
+ }
+ return( (negative) ? -w.low : w.low);
+#else
+ w = ((long)dividend) << FRACTBITS;
+ DLdiv(&w, divisor);
+ if (w & 0xffffffff80000000L ) {
+ IfTrace2(TRUE,"FPdiv: overflow, %p/%p\n", dividend, divisor);
+ ret = TOFRACTPEL(MAXSHORT);
+ }
+ else
+ ret = (fractpel)w;
+ return( (negative) ? -ret : ret);
+#endif
+}
+
+/*
+:h3.FPstarslash() - Multiply then Divide
+
+Borrowing a chapter from the language Forth, it is useful to define
+an operator that first multiplies by one constant then divides by
+another, keeping the intermediate result in extended precision.
+*/
+
+fractpel FPstarslash(a, b, c)
+ register fractpel a,b,c; /* result = a * b / c */
+{
+ doublelong w; /* result will be built here */
+ int negative = FALSE;
+#ifdef LONG64
+ register fractpel ret;
+#endif
+
+ if (a < 0) { a = -a; negative = TRUE; }
+ if (b < 0) { b = -b; negative = !negative; }
+ if (c < 0) { c = -c; negative = !negative; }
+
+ DLmult(&w, a, b);
+ DLdiv(&w, c);
+#ifndef LONG64
+ if (w.high != 0 || SIGNBITON(w.low)) {
+ IfTrace3(TRUE,"FPstarslash: overflow, %p*%p/%p\n", a, b, c);
+ w.low = TOFRACTPEL(MAXSHORT);
+ }
+ return((negative) ? -w.low : w.low);
+#else
+ if (w & 0xffffffff80000000L ) {
+ IfTrace3(TRUE,"FPstarslash: overflow, %p*%p/%p\n", a, b, c);
+ ret = TOFRACTPEL(MAXSHORT);
+ }
+ else
+ ret = (fractpel)w;
+ return( (negative) ? -ret : ret);
+#endif
+}
diff --git a/src/Type1/arith.h b/src/Type1/arith.h
new file mode 100644
index 0000000..ab9412b
--- /dev/null
+++ b/src/Type1/arith.h
@@ -0,0 +1,70 @@
+/* $Xorg: arith.h,v 1.3 2000/08/17 19:46:29 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+/*SHARED*/
+
+#include <X11/Xmd.h> /* LONG64 */
+
+void DLmult(),DLdiv(),DLadd(),DLsub();
+
+fractpel FPmult();
+fractpel FPdiv();
+fractpel FPstarslash();
+
+/*END SHARED*/
+/*SHARED*/
+
+#define SHORTSIZE (sizeof(short)*8)
+#define LONGSIZE (SHORTSIZE*2)
+#define MAXSHORT ((1<<SHORTSIZE)-1)
+
+/*END SHARED*/
+/*SHARED*/
+
+#ifdef LONG64
+typedef long doublelong;
+#else
+typedef struct {
+ long high;
+ unsigned long low;
+} doublelong;
+#endif /* LONG64 else */
+
+/*END SHARED*/
+/*SHARED*/
+
+#ifdef LONG64
+#define DLrightshift(dl,N) ((dl) >>= (N))
+#else
+#define DLrightshift(dl,N) { \
+ dl.low = (dl.low >> N) + (((unsigned long) dl.high) << (LONGSIZE - N)); \
+ dl.high >>= N; \
+}
+#endif
+
+/*END SHARED*/
diff --git a/src/Type1/blues.h b/src/Type1/blues.h
new file mode 100644
index 0000000..2480b14
--- /dev/null
+++ b/src/Type1/blues.h
@@ -0,0 +1,93 @@
+/* $Xorg: blues.h,v 1.3 2000/08/17 19:46:29 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ * Portions Copyright (c) 1990 Adobe Systems Incorporated.
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark or Adobe
+ * not be used in advertising or publicity pertaining to distribution of
+ * the software without specific, written prior permission.
+ *
+ * IBM, LEXMARK, AND ADOBE PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY
+ * WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE
+ * ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING
+ * ANY DUTY TO SUPPORT OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY
+ * PORTION OF THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM,
+ * LEXMARK, OR ADOBE) ASSUMES THE ENTIRE COST OF ALL SERVICING, REPAIR AND
+ * CORRECTION. IN NO EVENT SHALL IBM, LEXMARK, OR ADOBE BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+extern psobj *GetType1CharString();
+
+#define TOPLEFT 1
+#define BOTTOMRIGHT 2
+
+#define NUMBLUEVALUES 14
+#define NUMOTHERBLUES 10
+#define NUMFAMILYBLUES 14
+#define NUMFAMILYOTHERBLUES 10
+#define NUMSTEMSNAPH 12
+#define NUMSTEMSNAPV 12
+#define NUMSTDHW 1
+#define NUMSTDVW 1
+
+#define DEFAULTBOLDSTEMWIDTH 2.0
+
+#define MAXALIGNMENTZONES ((NUMBLUEVALUES+NUMOTHERBLUES)/2)
+#define DEFAULTBLUESCALE 0.039625
+#define DEFAULTBLUESHIFT 7
+#define DEFAULTBLUEFUZZ 1
+#define DEFAULTSTDHW 0
+#define DEFAULTSTDVW 0
+#define DEFAULTFORCEBOLD FALSE
+#define DEFAULTLANGUAGEGROUP 0
+#define DEFAULTRNDSTEMUP FALSE
+#define DEFAULTLENIV 4
+#define DEFAULTEXPANSIONFACTOR 0.06
+
+/* see Type 1 Font Format book for explanations of these values */
+/* Note that we're currently doing nothing for minfeature and password. */
+struct blues_struct {
+ struct blues_struct *next; /* ptr to next Blues structure in list */
+ int numBlueValues; /* # of BlueValues in following array */
+ int BlueValues[NUMBLUEVALUES];
+ int numOtherBlues; /* # of OtherBlues values in following array */
+ int OtherBlues[NUMOTHERBLUES];
+ int numFamilyBlues; /* # of FamilyBlues values in following array */
+ int FamilyBlues[NUMFAMILYBLUES];
+ int numFamilyOtherBlues; /* # of FamilyOtherBlues values in */
+ int FamilyOtherBlues[NUMFAMILYOTHERBLUES]; /* this array */
+ double BlueScale;
+ int BlueShift;
+ int BlueFuzz;
+ double StdHW;
+ double StdVW;
+ int numStemSnapH; /* # of StemSnapH values in following array */
+ double StemSnapH[NUMSTEMSNAPH];
+ int numStemSnapV; /* # of StemSnapV values in following array */
+ double StemSnapV[NUMSTEMSNAPV];
+ int ForceBold;
+ int LanguageGroup;
+ int RndStemUp;
+ int lenIV;
+ double ExpansionFactor;
+};
+
+/* the alignment zone structure -- somewhat similar to the stem structure */
+/* see Adobe Type1 Font Format book about the terms used in this structure */
+struct alignmentzone {
+ int topzone; /* TRUE if a topzone, FALSE if a bottom zone */
+ double bottomy, topy; /* interval of this alignment zone */
+};
diff --git a/src/Type1/cluts.h b/src/Type1/cluts.h
new file mode 100644
index 0000000..67d9303
--- /dev/null
+++ b/src/Type1/cluts.h
@@ -0,0 +1,35 @@
+/* $Xorg: cluts.h,v 1.3 2000/08/17 19:46:29 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* STUB */
+
+#define KillCLUT(T)
+#define CopyCLUT(T) T
+#define UniqueCLUT(T)
+
diff --git a/src/Type1/curves.c b/src/Type1/curves.c
new file mode 100644
index 0000000..d1033fe
--- /dev/null
+++ b/src/Type1/curves.c
@@ -0,0 +1,217 @@
+/* $Xorg: curves.c,v 1.3 2000/08/17 19:46:29 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991 */
+/* All Rights Reserved */
+
+/* License to use, copy, modify, and distribute this software */
+/* and its documentation for any purpose and without fee is */
+/* hereby granted, provided that licensee provides a license to */
+/* IBM, Corp. to use, copy, modify, and distribute derivative */
+/* works and their documentation for any purpose and without */
+/* fee, that the above copyright notice appear in all copies */
+/* and that both that copyright notice and this permission */
+/* notice appear in supporting documentation, and that the name */
+/* of IBM not be used in advertising or publicity pertaining to */
+/* distribution of the software without specific, written prior */
+/* permission. */
+
+/* IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES */
+/* OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT */
+/* LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, */
+/* FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF */
+/* THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND */
+/* PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT */
+/* OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF */
+/* THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES */
+/* THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN */
+/* NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR */
+/* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING */
+/* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF */
+/* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT */
+/* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS */
+/* SOFTWARE. */
+/*
+:h1.CURVES Module - Stepping Beziers
+
+This module is responsible for "rasterizing"
+third order curves. That is, it changes the high level curve
+specification into a list of pels that that curve travels
+through.
+
+:h3.Include Files
+
+Include files needed:
+*/
+
+#include "objects.h"
+#include "spaces.h"
+#include "paths.h"
+#include "regions.h"
+#include "curves.h"
+#include "lines.h"
+#include "arith.h"
+
+
+/*
+:h3.Functions Provided to Other Modules
+
+External entry points:
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+Note that "stepping" and "flattening" are so similiar that they use the
+same routine. When the "region" parameter is NULL, that is a flag that
+we are flattening instead of stepping.
+*/
+/*
+:h2.Bezier Third Order Curves
+*/
+/*
+:h3.The "bezierinfo" Structure
+
+This structure is used to store information used when we subdivide
+Bezier curves.
+*/
+
+struct bezierinfo {
+ struct region *region; /* the region being built or NULL */
+ struct fractpoint last; /* not used yet; maybe could save some work */
+ struct fractpoint origin; /* the origin of the bezier */
+} ;
+
+/*
+ Checking for termination of the subdivision process:
+ This is the stupidest test in the world, just check if the coordinatewise
+ distance from an end control point to the next control point is less than
+ one half pel. If so, we must be done.
+ This returns 1 if the subdivision is terminated and 0 if you still need
+ to subdivide.
+*/
+
+static int BezierTerminationTest(xa,ya,xb,yb,xc,yc,xd,yd)
+fractpel xa,ya,xb,yb,xc,yc,xd,yd;
+{
+ fractpel dmax;
+ dmax = ABS(xa - xb);
+ dmax = MAX(dmax,ABS(ya - yb));
+ dmax = MAX(dmax,ABS(xd - xc));
+ dmax = MAX(dmax,ABS(yd - yc));
+ if(dmax > FPHALF)
+ return(0); /* not done yet */
+ else
+ return(1); /* done */
+}
+
+/*
+:h3.StepBezierRecurse() - The Recursive Logic in StepBezier()
+
+The recursion involves dividing the control polygon into two smaller
+control polygons by finding the midpoints of the lines. This idea is
+described in any graphics text book and its simplicity is what caused
+Bezier to define his curves as he did. If the input region 'R' is NULL,
+the result is a path that is the 'flattened' curve; otherwise StepBezier
+returns nothing special.
+*/
+static struct segment *StepBezierRecurse(I,xA,yA,xB,yB,xC,yC,xD,yD)
+ struct bezierinfo *I; /* Region under construction or NULL */
+ fractpel xA,yA; /* A control point */
+ fractpel xB,yB; /* B control point */
+ fractpel xC,yC; /* C control point */
+ fractpel xD,yD; /* D control point */
+
+{
+ if (BezierTerminationTest(xA,yA,xB,yB,xC,yC,xD,yD))
+ {
+ if (I->region == NULL)
+ return(PathSegment(LINETYPE, xD - xA, yD - yA));
+ else
+ StepLine(I->region, I->origin.x + xA, I->origin.y + yA,
+ I->origin.x + xD, I->origin.y + yD);
+ }
+ else
+ {
+ fractpel xAB,yAB;
+ fractpel xBC,yBC;
+ fractpel xCD,yCD;
+ fractpel xABC,yABC;
+ fractpel xBCD,yBCD;
+ fractpel xABCD,yABCD;
+
+ xAB = xA + xB; yAB = yA + yB;
+ xBC = xB + xC; yBC = yB + yC;
+ xCD = xC + xD; yCD = yC + yD;
+
+ xABC = xAB + xBC; yABC = yAB + yBC;
+ xBCD = xBC + xCD; yBCD = yBC + yCD;
+
+ xABCD = xABC + xBCD; yABCD = yABC + yBCD;
+
+ xAB >>= 1; yAB >>= 1;
+ xBC >>= 1; yBC >>= 1;
+ xCD >>= 1; yCD >>= 1;
+ xABC >>= 2; yABC >>= 2;
+ xBCD >>= 2; yBCD >>= 2;
+ xABCD >>= 3; yABCD >>= 3;
+
+ if (I->region == NULL)
+ {
+ return( Join(
+ StepBezierRecurse(I, xA, yA, xAB, yAB, xABC, yABC, xABCD, yABCD),
+ StepBezierRecurse(I, xABCD, yABCD, xBCD, yBCD, xCD, yCD, xD, yD)
+ )
+ );
+ }
+ else
+ {
+ StepBezierRecurse(I, xA, yA, xAB, yAB, xABC, yABC, xABCD, yABCD);
+ StepBezierRecurse(I, xABCD, yABCD, xBCD, yBCD, xCD, yCD, xD, yD);
+ }
+ }
+ /*NOTREACHED*/
+}
+
+/*
+:h3.TOOBIG() - Macro to Test if a Coordinate is Too Big to Bezier SubDivide Normally
+
+Intermediate values in the Bezier subdivision are 8 times bigger than
+the starting values. If this overflows, a 'long', we are in trouble:
+*/
+
+#define BITS (sizeof(long)*8)
+#define HIGHTEST(p) (((p)>>(BITS-4)) != 0) /* includes sign bit */
+#define TOOBIG(xy) ((xy < 0) ? HIGHTEST(-xy) : HIGHTEST(xy))
+
+/*
+:h3.StepBezier() - Produce Run Ends for a Bezier Curve
+
+This is the entry point called from outside the module.
+*/
+
+struct segment *StepBezier(R, xA, yA, xB, yB, xC, yC, xD, yD)
+ struct region *R; /* Region under construction or NULL */
+ fractpel xA,yA; /* A control point */
+ fractpel xB,yB; /* B control point */
+ fractpel xC,yC; /* C control point */
+ fractpel xD,yD; /* D control point */
+{
+ struct bezierinfo Info;
+
+ Info.region = R;
+ Info.origin.x = xA;
+ Info.origin.y = yA;
+
+ xB -= xA;
+ xC -= xA;
+ xD -= xA;
+ yB -= yA;
+ yC -= yA;
+ yD -= yA;
+
+ if ( TOOBIG(xB) || TOOBIG(yB) || TOOBIG(xC) || TOOBIG(yC)
+ || TOOBIG(xD) || TOOBIG(yD) )
+ abort("Beziers this big not yet supported");
+
+ return(StepBezierRecurse(&Info,
+ (fractpel) 0, (fractpel) 0, xB, yB, xC, yC, xD, yD));
+}
+
diff --git a/src/Type1/curves.h b/src/Type1/curves.h
new file mode 100644
index 0000000..4138a6f
--- /dev/null
+++ b/src/Type1/curves.h
@@ -0,0 +1,40 @@
+/* $Xorg: curves.h,v 1.3 2000/08/17 19:46:29 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+/*SHARED*/
+
+#define StepConic(R,xA,yA,xB,yB,xC,yC,r) t1_StepConic(R,xA,yA,xB,yB,xC,yC,r)
+#define StepBezier(R,xA,yA,xB,yB,xC,yC,xD,yD) t1_StepBezier(R,xA,yA,xB,yB,xC,yC,xD,yD)
+
+#define FlattenConic(xM,yM,xC,yC,r) t1_StepConic(NULL,(fractpel)0,(fractpel)0,xM,yM,xC,yC,r)
+#define FlattenBezier(xB,yB,xC,yC,xD,yD) t1_StepBezier(NULL,(fractpel)0,(fractpel)0,xB,yB,xC,yC,xD,yD)
+
+struct segment *t1_StepConic();
+struct segment *t1_StepBezier();
+
+/*END SHARED*/
diff --git a/src/Type1/digit.h b/src/Type1/digit.h
new file mode 100644
index 0000000..c693809
--- /dev/null
+++ b/src/Type1/digit.h
@@ -0,0 +1,64 @@
+/* $Xorg: digit.h,v 1.3 2000/08/17 19:46:29 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* -------------------------------------- */
+/* --- MACHINE GENERATED, DO NOT EDIT --- */
+/* -------------------------------------- */
+
+#ifndef DIGIT
+#define DIGIT 1
+
+/*
+ * Digit Value Table --
+ *
+ * The entries in the Digit Value Table map character
+ * codes in the set {0-9,a-z,A-Z} to their numeric
+ * values as part of numbers of radix 2-36.
+ *
+ */
+unsigned char digit_value[256] = {
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
+ 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
+ 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+};
+
+#endif
diff --git a/src/Type1/fontfcn.c b/src/Type1/fontfcn.c
new file mode 100644
index 0000000..5516468
--- /dev/null
+++ b/src/Type1/fontfcn.c
@@ -0,0 +1,308 @@
+/* $Xorg: fontfcn.c,v 1.5 2000/12/01 16:26:25 steve Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* Author: Katherine A. Hitchcock IBM Almaden Research Laboratory */
+
+#include <stdio.h>
+#include <string.h>
+#include "t1imager.h"
+#include "util.h"
+#include "fontfcn.h"
+#include "fontmisc.h"
+
+extern xobject Type1Char();
+/***================================================================***/
+/* GLOBALS */
+/***================================================================***/
+char CurFontName[120];
+char *CurFontEnv;
+char *vm_base = NULL;
+psfont *FontP = NULL;
+psfont TheCurrentFont;
+
+
+/***================================================================***/
+/* SearchDict - look for name */
+/* - compare for match on len and string */
+/* return 0 - not found. */
+/* return n - nth element in dictionary. */
+/***================================================================***/
+int SearchDictName(dictP,keyP)
+ psdict *dictP;
+ psobj *keyP;
+{
+ int i,n;
+
+
+ n = dictP[0].key.len;
+ for (i=1;i<=n;i++) { /* scan the intire dictionary */
+ if (
+ (dictP[i].key.len == keyP->len )
+ &&
+ (strncmp(dictP[i].key.data.valueP,
+ keyP->data.valueP,
+ keyP->len) == 0
+ )
+ ) return(i);
+ }
+ return(0);
+}
+/***================================================================***/
+boolean initFont(cnt)
+int cnt;
+{
+
+ if (!(vm_init(cnt))) return(FALSE);
+ vm_base = vm_next_byte();
+ if (!(Init_BuiltInEncoding())) return(FALSE);
+ strcpy(CurFontName, ""); /* iniitialize to none */
+ FontP = &TheCurrentFont;
+ FontP->vm_start = vm_next_byte();
+ FontP->FontFileName.len = 0;
+ FontP->FontFileName.data.valueP = CurFontName;
+ return(TRUE);
+}
+/***================================================================***/
+static void resetFont(env)
+ char *env;
+{
+
+ vm_next = FontP->vm_start;
+ vm_free = vm_size - ( vm_next - vm_base);
+ FontP->Subrs.len = 0;
+ FontP->Subrs.data.stringP = NULL;
+ FontP->CharStringsP = NULL;
+ FontP->Private = NULL;
+ FontP->fontInfoP = NULL;
+ FontP->BluesP = NULL;
+ /* This will load the font into the FontP */
+ strcpy(CurFontName,env);
+ FontP->FontFileName.len = strlen(CurFontName);
+ FontP->FontFileName.data.valueP = CurFontName;
+
+}
+/***================================================================***/
+int readFont(env)
+char *env;
+{
+ int rcode;
+
+ /* restore the virtual memory and eliminate old font */
+ resetFont(env);
+ /* This will load the font into the FontP */
+ rcode = scan_font(FontP);
+ if (rcode == SCAN_OUT_OF_MEMORY) {
+ /* free the memory and start again */
+ xfree(vm_base);
+ if (!(initFont(vm_size * 2))) {
+ /* we are really out of memory */
+ return(SCAN_OUT_OF_MEMORY);
+ }
+ resetFont(env);
+ rcode = scan_font(FontP);
+ /* only double the memory once, then report error */
+ }
+ return(rcode);
+}
+/***================================================================***/
+xobject fontfcnB(S,code,lenP,mode)
+XYspace S;
+unsigned char *code;
+int *lenP;
+int *mode;
+{
+ path updateWidth();
+
+ psobj *charnameP; /* points to psobj that is name of character*/
+ int N;
+ psdict *CharStringsDictP; /* dictionary with char strings */
+ psobj CodeName; /* used to store the translation of the name*/
+ psobj *SubrsArrayP;
+ psobj *theStringP;
+
+ path charpath; /* the path for this character */
+
+ charnameP = &CodeName;
+ charnameP->len = *lenP;
+ charnameP->data.stringP = code;
+
+ CharStringsDictP = FontP->CharStringsP;
+
+ /* search the chars string for this charname as key */
+ N = SearchDictName(CharStringsDictP,charnameP);
+ if (N<=0) {
+ *mode = FF_PARSE_ERROR;
+ return(NULL);
+ }
+ /* ok, the nth item is the psobj that is the string for this char */
+ theStringP = &(CharStringsDictP[N].value);
+
+ /* get the dictionary pointers to the Subrs */
+
+ SubrsArrayP = &(FontP->Subrs);
+ /* scale the Adobe fonts to 1 unit high */
+ /* call the type 1 routine to rasterize the character */
+ charpath = Type1Char(FontP,S,theStringP,SubrsArrayP,NULL,
+ FontP->BluesP , mode);
+ /* if Type1Char reported an error, then return */
+ if ( *mode == FF_PARSE_ERROR) return(NULL);
+ /* fill with winding rule unless path was requested */
+ if (*mode != FF_PATH) {
+ charpath = Interior(charpath,WINDINGRULE+CONTINUITY);
+ }
+ return(charpath);
+}
+/***================================================================***/
+/* fontfcnA(env, mode) */
+/* */
+/* env is a pointer to a string that contains the fontname. */
+/* */
+/* 1) initialize the font - global indicates it has been done */
+/* 2) load the font */
+/***================================================================***/
+Bool fontfcnA(env,mode)
+char *env;
+int *mode;
+{
+ int rc;
+
+ /* Has the FontP initialized? If not, then */
+ /* Initialize */
+ if (FontP == NULL) {
+ InitImager();
+ if (!(initFont(VM_SIZE))) {
+ /* we are really out of memory */
+ *mode = SCAN_OUT_OF_MEMORY;
+ return(FALSE);
+ }
+ }
+
+ /* if the env is null, then use font already loaded */
+
+ /* if the not same font name */
+ if ( (env) && (strcmp(env,CurFontName) != 0 ) ) {
+ /* restore the virtual memory and eliminate old font, read new one */
+ rc = readFont(env);
+ if (rc != 0 ) {
+ strcpy(CurFontName, ""); /* no font loaded */
+ *mode = rc;
+ return(FALSE);
+ }
+ }
+ return(TRUE);
+
+}
+/***================================================================***/
+/* QueryFontLib(env, infoName,infoValue,rcodeP) */
+/* */
+/* env is a pointer to a string that contains the fontname. */
+/* */
+/* 1) initialize the font - global indicates it has been done */
+/* 2) load the font */
+/* 3) use the font to call getInfo for that value. */
+/***================================================================***/
+
+void QueryFontLib(env,infoName,infoValue,rcodeP)
+char *env;
+char *infoName;
+pointer infoValue; /* parameter returned here */
+int *rcodeP;
+{
+ int rc,N,i;
+ psdict *dictP;
+ psobj nameObj;
+ psobj *valueP;
+
+ /* Has the FontP initialized? If not, then */
+ /* Initialize */
+ if (FontP == NULL) {
+ InitImager();
+ if (!(initFont(VM_SIZE))) {
+ *rcodeP = 1;
+ return;
+ }
+ }
+ /* if the env is null, then use font already loaded */
+ /* if the not same font name, reset and load next font */
+ if ( (env) && (strcmp(env,CurFontName) != 0 ) ) {
+ /* restore the virtual memory and eliminate old font */
+ rc = readFont(env);
+ if (rc != 0 ) {
+ strcpy(CurFontName, ""); /* no font loaded */
+ *rcodeP = 1;
+ return;
+ }
+ }
+ dictP = FontP->fontInfoP;
+ objFormatName(&nameObj,strlen(infoName),infoName);
+ N = SearchDictName(dictP,&nameObj);
+ /* if found */
+ if ( N > 0 ) {
+ *rcodeP = 0;
+ switch (dictP[N].value.type) {
+ case OBJ_ARRAY:
+ valueP = dictP[N].value.data.arrayP;
+ /* don't dereference a NULL pointer, in the case of a bad font file */
+ if (valueP == NULL) break;
+ if (strcmp(infoName,"FontMatrix") == 0) {
+ /* 6 elments, return them as floats */
+ for (i=0;i<6;i++) {
+ if (valueP->type == OBJ_INTEGER )
+ ((float *)infoValue)[i] = valueP->data.integer;
+ else
+ ((float *)infoValue)[i] = valueP->data.real;
+ valueP++;
+ }
+ }
+ if (strcmp(infoName,"FontBBox") == 0) {
+ /* 4 elments for Bounding Box. all integers */
+ for (i=0;i<4;i++) {
+ ((int *)infoValue)[i] = valueP->data.integer;
+ valueP++;
+ }
+ break;
+ case OBJ_INTEGER:
+ case OBJ_BOOLEAN:
+ *((int *)infoValue) = dictP[N].value.data.integer;
+ break;
+ case OBJ_REAL:
+ *((float *)infoValue) = dictP[N].value.data.real;
+ break;
+ case OBJ_NAME:
+ case OBJ_STRING:
+ *((char **)infoValue) = dictP[N].value.data.valueP;
+ break;
+ default:
+ *rcodeP = 1;
+ break;
+ }
+ }
+ }
+ else *rcodeP = 1;
+}
diff --git a/src/Type1/fontfcn.h b/src/Type1/fontfcn.h
new file mode 100644
index 0000000..cbf23a1
--- /dev/null
+++ b/src/Type1/fontfcn.h
@@ -0,0 +1,98 @@
+/* $Xorg: fontfcn.h,v 1.3 2000/08/17 19:46:30 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* Definition of a PostScript FONT */
+typedef struct ps_font {
+ char *vm_start;
+ psobj FontFileName;
+ psobj Subrs;
+ psdict *CharStringsP;
+ psdict *Private;
+ psdict *fontInfoP;
+struct blues_struct *BluesP;
+} psfont;
+/***================================================================***/
+/* Routines in scan_font */
+/***================================================================***/
+
+extern boolean Init_StdEnc();
+extern int scan_font();
+extern int GetFontInfo();
+/***================================================================***/
+/* Return codes from scan_font */
+/***================================================================***/
+#define SCAN_OK 0
+#define SCAN_FILE_EOF -1
+#define SCAN_ERROR -2
+#define SCAN_OUT_OF_MEMORY -3
+#define SCAN_FILE_OPEN_ERROR -4
+#define SCAN_TRUE -5
+#define SCAN_FALSE -6
+#define SCAN_END -7
+
+/***================================================================***/
+/* Name of FontInfo fields */
+/***================================================================***/
+
+#define FONTNAME 1
+#define PAINTTYPE 2
+#define FONTTYPENUM 3
+#define FONTMATRIX 4
+#define FONTBBOX 5
+#define UNIQUEID 6
+#define STROKEWIDTH 7
+#define VERSION 8
+#define NOTICE 9
+#define FULLNAME 10
+#define FAMILYNAME 11
+#define WEIGHT 12
+#define ITALICANGLE 13
+#define ISFIXEDPITCH 14
+#define UNDERLINEPOSITION 15
+#define UNDERLINETHICKNESS 16
+#define ENCODING 17
+/***================================================================***/
+/* Name of Private values */
+/***================================================================***/
+#define BLUEVALUES 1
+#define OTHERBLUES 2
+#define FAMILYBLUES 3
+#define FAMILYOTHERBLUES 4
+#define BLUESCALE 5
+#define BLUESHIFT 6
+#define BLUEFUZZ 7
+#define STDHW 8
+#define STDVW 9
+#define STEMSNAPH 10
+#define STEMSNAPV 11
+#define FORCEBOLD 12
+#define LANGUAGEGROUP 13
+#define LENIV 14
+#define RNDSTEMUP 15
+#define EXPANSIONFACTOR 16
diff --git a/src/Type1/fonts.h b/src/Type1/fonts.h
new file mode 100644
index 0000000..7215e0f
--- /dev/null
+++ b/src/Type1/fonts.h
@@ -0,0 +1,49 @@
+/* $Xorg: fonts.h,v 1.3 2000/08/17 19:46:30 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/* STUB */
+
+#define CopyFont(f) f
+#define UniqueFont(f) f
+#define KillFont(f)
+#define KillText(t)
+#define CopyText(t) t
+#define I_DumpText(t)
+#define CoerceText(t) t
+#define TextDelta(t,pt)
+#define XformText(p,s)
+#define GimeSpace() FALSE
+
+#define LibInit()
+#define InitFonts()
+#define InitFiles()
+#define TraceClose()
+
+#define FF_PARSE_ERROR -1
diff --git a/src/Type1/hdigit.h b/src/Type1/hdigit.h
new file mode 100644
index 0000000..fbaa9c1
--- /dev/null
+++ b/src/Type1/hdigit.h
@@ -0,0 +1,94 @@
+/* $Xorg: hdigit.h,v 1.3 2000/08/17 19:46:30 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* -------------------------------------- */
+/* --- MACHINE GENERATED, DO NOT EDIT --- */
+/* -------------------------------------- */
+
+#ifndef HDIGIT
+#define HDIGIT 1
+
+/*
+ * Hex Digit Value Table --
+ *
+ * The entries in the Digit Value Table map character codes in the set
+ * {0-9,a-f,A-F} to their numeric values for readhexstring
+ * (00 10...F0 for the high hex digit and 00 01...0F for the low).
+ * The white-space and hex string termination characters are.
+ * mapped to codes > 0xf0 to enable usage by several modules.
+ * 2 tables are build HighHex and LowHex.
+ *
+ */
+
+/* Indicators for special characters in these tables */
+#define HERROR (0xfe)
+#define HWHITE_SPACE (0xfd)
+#define HRIGHT_ANGLE (0xfc)
+#define LAST_HDIGIT (0xf0)
+
+#define HighHexP (HighHex+1)
+unsigned char HighHex[257] = { 0xFF,
+ 0xFD,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFD,0xFD,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFD,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xFE,0xFE,0xFE,0xFE,0xFC,0xFE,
+ 0xFE,0xA0,0xB0,0xC0,0xD0,0xE0,0xF0,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xA0,0xB0,0xC0,0xD0,0xE0,0xF0,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE
+};
+#define LowHexP (LowHex+1)
+unsigned char LowHex[257] = { 0xFF,
+ 0xFD,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFD,0xFD,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFD,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFE,0xFE,0xFE,0xFE,0xFC,0xFE,
+ 0xFE,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
+ 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE
+};
+
+#endif
diff --git a/src/Type1/hints.c b/src/Type1/hints.c
new file mode 100644
index 0000000..c3db5a4
--- /dev/null
+++ b/src/Type1/hints.c
@@ -0,0 +1,919 @@
+/* $Xorg: hints.c,v 1.3 2000/08/17 19:46:30 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+ /* HINTS CWEB V0006 ******** */
+/*
+:h1.HINTS Module - Processing Rasterization Hints
+
+&author. Sten F. Andler; continuity by Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com) and Duaine
+W. Pryor, Jr.
+
+
+:h3.Include Files
+
+The included files are:
+*/
+
+#include "objects.h"
+#include "spaces.h"
+#include "paths.h"
+#include "regions.h"
+#include "hints.h"
+
+/*
+:h3.Functions Provided to the TYPE1IMAGER User
+
+None.
+*/
+
+/*
+:h3.Functions Provided to Other Modules
+
+This module provides the following entry point to other modules:
+*/
+
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h3.Macros Provided to Other Modules
+
+None.
+*/
+
+/*
+:h2.InitHints() - Initialize hint data structure
+*/
+
+#define MAXLABEL 20
+static struct {
+ int inuse;
+ int computed;
+ struct fractpoint hint;
+} oldHint[MAXLABEL];
+
+#define ODD(x) (((int)(x)) & 01)
+#define FPFLOOR(fp) TOFRACTPEL((fp) >> FRACTBITS)
+#define FPROUND(fp) FPFLOOR((fp) + FPHALF)
+
+void InitHints()
+{
+ int i;
+
+ for (i = 0; i < MAXLABEL; i++)
+ {
+ oldHint[i].inuse = FALSE;
+ oldHint[i].computed = FALSE;
+ }
+}
+
+/*
+:h3.CloseHints(hintP) - Reverse hints that are still open
+*/
+
+void CloseHints(hintP)
+ struct fractpoint *hintP;
+{
+ int i;
+
+ for (i = 0; i < MAXLABEL; i++)
+ {
+ if (oldHint[i].inuse)
+ {
+ hintP->x -= oldHint[i].hint.x;
+ hintP->y -= oldHint[i].hint.y;
+
+ oldHint[i].inuse = FALSE;
+
+ IfTrace3((HintDebug > 1)," Hint %d was open, hint=(%p,%p)\n",
+ i, hintP->x, hintP->y);
+ }
+ }
+}
+
+/*
+:h3.ComputeHint(hP, currX, currY, hintP) - Compute the value of a hint
+*/
+
+static void ComputeHint(hP, currX, currY, hintP)
+ struct hintsegment *hP;
+ fractpel currX, currY;
+ struct fractpoint *hintP;
+{
+ fractpel currRef, currWidth;
+ int idealWidth;
+ fractpel hintValue;
+ char orientation;
+
+/*
+By construction, width is never zero. Therefore we can use the
+width value to determine if the hint has been rotated by a
+multiple of 90 degrees.
+*/
+
+ if (hP->width.y == 0)
+ {
+ orientation = 'v'; /* vertical */
+ IfTrace0((HintDebug > 0)," vertical hint\n");
+ }
+ else if (hP->width.x == 0)
+ {
+ orientation = 'h'; /* horizontal */
+ IfTrace0((HintDebug > 0)," horizontal hint\n");
+ }
+ else
+ {
+ IfTrace0((HintDebug > 0)," hint not vertical or horizontal\n");
+ hintP->x = hintP->y = 0;
+ return;
+ }
+
+ /* Compute currRef and currWidth with a unit of 1 pel */
+ if (orientation == 'v') /* vertical */
+ {
+ currRef = hP->ref.x + currX;
+ currWidth = ABS(hP->width.x);
+ }
+ else if (orientation == 'h') /* horizontal */
+ {
+ currRef = hP->ref.y + currY;
+ currWidth = ABS(hP->width.y);
+ }
+ else /* error */
+ {
+ abort("ComputeHint: invalid orientation");
+ }
+
+ IfTrace4((HintDebug > 1),
+ " currX=%p, currY=%p, currRef=%p, currWidth=%p\n",
+ currX, currY,
+ currRef, currWidth);
+
+ if ((hP->hinttype == 'b') /* Bar or stem */
+ || (hP->hinttype == 's')) /* Serif */
+ {
+ idealWidth = NEARESTPEL(currWidth);
+ if (idealWidth == 0) idealWidth = 1;
+ if (ODD(idealWidth)) /* Is ideal width odd? */
+ {
+ /* center "ref" over pel */
+ hintValue = FPFLOOR(currRef) + FPHALF - currRef;
+ }
+ else
+ {
+ /* align "ref" on pel boundary */
+ hintValue = FPROUND(currRef) - currRef;
+ }
+ if (HintDebug > 2) {
+ IfTrace1(TRUE," idealWidth=%d, ", idealWidth);
+ }
+ }
+ else if (hP->hinttype == 'c') /* Curve extrema */
+ {
+ /* align "ref" on pel boundary */
+ hintValue = FPROUND(currRef) - currRef;
+ }
+ else /* error */
+ {
+ abort("ComputeHint: invalid hinttype");
+ }
+
+ IfTrace1((HintDebug > 1)," hintValue=%p", hintValue);
+
+ if (orientation == 'v') /* vertical */
+ {
+ hintP->x = hintValue;
+ hintP->y = 0;
+ }
+ else if (orientation == 'h') /* horizontal */
+ {
+ hintP->x = 0;
+ hintP->y = hintValue;
+ }
+ else /* error */
+ {
+ abort("ComputeHint: invalid orientation");
+ }
+}
+
+/*
+:h3.ProcessHint(hP, currX, currY, hintP) - Process a rasterization hint
+*/
+
+void ProcessHint(hP, currX, currY, hintP)
+ struct hintsegment *hP;
+ fractpel currX, currY;
+ struct fractpoint *hintP;
+{
+ struct fractpoint thisHint;
+
+ IfTrace4((HintDebug > 1)," ref=(%p,%p), width=(%p,%p)",
+ hP->ref.x, hP->ref.y,
+ hP->width.x, hP->width.y);
+ IfTrace4((HintDebug > 1),", %c %c %c %c",
+ hP->orientation, hP->hinttype,
+ hP->adjusttype, hP->direction);
+ IfTrace1((HintDebug > 1),", label=%d\n", hP->label);
+
+ if ((hP->adjusttype == 'm') /* Move */
+ || (hP->adjusttype == 'a')) /* Adjust */
+ {
+ /* Look up hint in oldHint table */
+ if ((hP->label >= 0) && (hP->label < MAXLABEL))
+ {
+ if (oldHint[hP->label].computed)
+ /* Use old hint value if already computed */
+ {
+ thisHint.x = oldHint[hP->label].hint.x;
+ thisHint.y = oldHint[hP->label].hint.y;
+ oldHint[hP->label].inuse = TRUE;
+ }
+ else
+ /* Compute new value for hint and store it for future use */
+ {
+ ComputeHint(hP, currX, currY, &thisHint);
+
+ oldHint[hP->label].hint.x = thisHint.x;
+ oldHint[hP->label].hint.y = thisHint.y;
+ oldHint[hP->label].inuse = TRUE;
+ oldHint[hP->label].computed = TRUE;
+ }
+ }
+ else /* error */
+ {
+ abort("ProcessHint: invalid label");
+ }
+ }
+ else if (hP->adjusttype == 'r') /* Reverse */
+ {
+ /* Use the inverse of the existing hint value to reverse hint */
+ if ((hP->label >= 0) && (hP->label < MAXLABEL))
+ {
+ if (oldHint[hP->label].inuse)
+ {
+ thisHint.x = -oldHint[hP->label].hint.x;
+ thisHint.y = -oldHint[hP->label].hint.y;
+ oldHint[hP->label].inuse = FALSE;
+ }
+ else /* error */
+ {
+ abort("ProcessHint: label is not in use");
+ }
+ }
+ else /* error */
+ {
+ abort("ProcessHint: invalid label");
+ }
+
+ }
+ else /* error */
+ {
+ abort("ProcessHint: invalid adjusttype");
+ }
+ IfTrace3((HintDebug > 1)," label=%d, thisHint=(%p,%p)\n",
+ hP->label, thisHint.x, thisHint.y);
+
+ hintP->x += thisHint.x;
+ hintP->y += thisHint.y;
+
+ IfTrace2((HintDebug > 1)," hint=(%p,%p)\n",
+ hintP->x, hintP->y);
+}
+
+/*
+:h2 id=subpath.Navigation Through Edge Lists
+
+For continuity checking purposes, we need to navigate through edge
+lists by the "subpath" chains and answer questions about edges. The
+subpath chain links together edges that were part of the same subpath
+(no intervening move segments) when the interior of the path was
+calculated. Here we use the term "edge" to mean every edge list
+that was created in between changes of direction.
+
+The subpath chains are singly-linked circular chains. For the convenience
+of building them, they direction of the list (from edge to edge) is the
+reverse of the order in which they were built. Within any single edge,
+the subpath chain goes from top-to-bottom. (There might be a violation
+of this because of the way the user started the first chain; see
+:hdref refid=fixsubp..).
+
+:h3.ISTOP() and ISBOTTOM() - Flag Bits for Edge Lists at the Top and
+Bottom of Their SubPaths
+*/
+
+#define ISTOP(flag) ((flag)&0x20)
+#define ISBOTTOM(flag) ((flag)&0x10)
+/*
+:h3.ISLEFT() - Flag Bit for Left Edges
+*/
+
+#define ISLEFT(flag) ((flag)&0x08)
+
+/*
+:h3.XofY() - Macro to Find X Value at Given Y
+
+This macro can only be used if it is known that the Y is within the
+given edgelist's ymin and ymax.
+*/
+
+#define XofY(edge, y) edge->xvalues[y - edge->ymin]
+
+/*
+:h3.findXofY() - Like XofY(), Except not Restricted
+
+If the Y is out of bounds of the given edgelist, this macro will
+call SearchXofY to search the edge's subpath chain for the correct
+Y range. If the Y value is off the edge, MINPEL is returned.
+*/
+#define findXofY(edge, y) ((y < edge->ymin || y >= edge->ymax) ? SearchXofY(edge, y) : XofY(edge, y))
+
+/*
+:h4.SearchXofY() - Routine Called by FindXofY() for Difficult Cases
+
+The concept of this routine is to follow the subpath chain to find the
+edge just below (i.e., next in chain) or just above (i.e., immediately
+before in chain. It is assumed that the Y value is no more than one
+off of the edge's range; XofY() could be replace by FindXofY() to
+call ourselves recursively if this were not true.
+*/
+
+static pel SearchXofY(edge, y)
+ register struct edgelist *edge; /* represents edge */
+ register pel y; /* 'y' value to find edge for */
+{
+ register struct edgelist *e; /* loop variable */
+
+ if (y < edge->ymin) {
+ if (ISTOP(edge->flag))
+ return(MINPEL);
+ for (e = edge->subpath; e->subpath != edge; e = e->subpath) { ; }
+ if (e->ymax == edge->ymin)
+ return(XofY(e, y));
+ }
+ else if (y >= edge->ymax) {
+ if (ISBOTTOM(edge->flag))
+ return(MINPEL);
+ e = edge->subpath;
+ if (e->ymin == edge->ymax)
+ return(XofY(e, y));
+ }
+ else
+ return(XofY(edge, y));
+
+ abort("bad subpath chain");
+ /*NOTREACHED*/
+}
+/*
+:h3.ISBREAK() Macro - Tests if an Edge List is at a "Break"
+
+The subpath chains are organized top to bottom. When the bottom of
+a given edge is reached, the subpath chain points to the top of the
+next edge. We call this a "break" in the chain. The following macro
+is the simple test for the break condition:
+*/
+
+#define ISBREAK(top,bot) (top->ymax != bot->ymin)
+
+
+/*
+:h3.ImpliedHorizontalLine() - Tests for Horizontal Connectivity
+
+This function returns true if two edges are connected horizontally.
+They are connected horizontally if they are consecutive in the subpath,
+and either we are at the bottom and the first edge is going down or we
+are at the top and the first edge is going up.
+*/
+
+#define BLACKABOVE -1
+#define BLACKBELOW +1
+#define NONE 0
+
+static int ImpliedHorizontalLine(e1, e2, y)
+ register struct edgelist *e1,*e2; /* two edges to check */
+ register int y; /* y where they might be connected */
+{
+ register struct edgelist *e3,*e4;
+
+ if (ISDOWN(e1->flag) == ISDOWN(e2->flag))
+ return(NONE); /* can't be consecutive unless different directions */
+/*
+Now we check for consecutiveness: Can we get from 'e1' to 'e2' with
+only one intervening break? Can we get from 'e2' to 'e1' with only one
+intervening break? 'e3' will be as far as we can get after 'e1'; 'e4'
+will be has far as we can get after 'e2':
+*/
+ for (e3 = e1; !ISBREAK(e3, e3->subpath); e3 = e3->subpath) { ; }
+ for (e3 = e3->subpath; e3 != e2; e3 = e3->subpath)
+ if (ISBREAK(e3, e3->subpath))
+ break;
+
+ for (e4 = e2; !ISBREAK(e4, e4->subpath); e4 = e4->subpath) { ; }
+ for (e4 = e4->subpath; e4 != e1; e4 = e4->subpath)
+ if (ISBREAK(e4, e4->subpath))
+ break;
+/*
+If the edges are mutually consecutive, we must have horizontal lines
+both top and bottom:
+*/
+ if (e3 == e2 && e4 == e1)
+ return(TRUE);
+/*
+If the edges are not consecutive either way, no horizontal lines are
+possible:
+*/
+ if (e3 != e2 && e4 != e1)
+ return(NONE);
+/*
+Now let's swap 'e1' and 'e2' if necessary to enforce the rule that 'e2'
+follows 'e1'. Remember that subpath chains go in the opposite direction
+from the way the subpaths were built; this led to the simplest way
+do build them.
+*/
+ if (e4 != e1) {
+ e2 = e1;
+ e1 = e3; /* remember e3 == e2, this just swaps 'e1' and 'e2' */
+ }
+/*
+Now we have everything to return the answer:
+*/
+ if (ISTOP(e1->flag) && y == e1->ymin)
+ return(ISDOWN(e2->flag));
+ else if (ISBOTTOM(e1->flag) && y == e1->ymax)
+ return(!ISDOWN(e2->flag));
+ else
+ abort("ImpliedHorizontalLine: why ask?");
+ /*NOTREACHED*/
+}
+
+/*
+:h3 id=fixsubp.FixSubPaths() - Must be Called to Organize Subpath Chains
+
+The region-building code in Interior(), in particular splitedge(),
+maintains the rule that sub-paths are linked top-to-bottom except
+at breaks. However, it is possible that there may be a "false break"
+because the user started the subpath in the middle of an edge (and
+went in the "wrong" direction from there, up instead of down). This
+routine finds and fixes false breaks.
+
+Also, this routine sets the ISTOP and ISBOTTOM flags in the edge lists.
+*/
+
+static void FixSubPaths(R)
+ register struct region *R; /* anchor of region */
+{
+ register struct edgelist *e; /* fast loop variable */
+ register struct edgelist *edge; /* current edge in region */
+ register struct edgelist *next; /* next in subpath after 'edge' */
+ register struct edgelist *break1; /* first break after 'next' */
+ register struct edgelist *break2; /* last break before 'edge' */
+ register struct edgelist *prev; /* previous edge for fixing links */
+ int left = TRUE;
+
+ for (edge = R->anchor; edge != NULL; edge = edge->link) {
+
+ if (left)
+ edge->flag |= ISLEFT(ON);
+ left = !left;
+
+ next = edge->subpath;
+
+ if (!ISBREAK(edge, next))
+ continue;
+ if (edge->ymax < next->ymin)
+ abort("disjoint subpath?");
+/*
+'edge' now contains an edgelist at the bottom of an edge, and 'next'
+contains the next subsequent edgelist in the subpath, which must be at
+the top. We refer to this a "break" in the subpath.
+*/
+ next->flag |= ISTOP(ON);
+ edge->flag |= ISBOTTOM(ON);
+
+ if (ISDOWN(edge->flag) != ISDOWN(next->flag))
+ continue;
+/*
+We are now in the unusual case; both edges are going in the same
+direction so this must be a "false break" due to the way that the user
+created the path. We'll have to fix it.
+*/
+ for (break1 = next; !ISBREAK(break1, break1->subpath); break1 = break1->subpath) { ; }
+
+ for (e = break1->subpath; e != edge; e = e->subpath)
+ if (ISBREAK(e, e->subpath))
+ break2 = e;
+/*
+Now we've set up 'break1' and 'break2'. I've found the following
+diagram invaluable. 'break1' is the first break after 'next'. 'break2'
+is the LAST break before 'edge'.
+&drawing.
+ next
+ +------+ +---->+------+
+ +--->| >-----+ | | >-----+
+ | | | | | | | |
+ | +-------------+ | +-------------+
+ | | |break1| | | | |
+ | +->| >-------+ +->| >-----+
+ | | | | | |
+ | | | +-------------+
+ | +------+ | | |
+ | +----------------+ | | |
+ | | +------+ | +->| >-----+
+ | +->| >-----+ | | | |
+ | | | | | +-------------+
+ | +-------------+ | | | |
+ | | |edge | | | |break2|
+ | +->| >-----+ | +->| >-----+
+ | | | | | | | |
+ | | | | | | | |
+ | | | | | | | |
+ | +------+ | | +------+ |
+ | | | |
+ +---------------+ +---------------+
+
+&edrawing.
+We want to fix this situation by having 'edge' point to where 'break1'
+now points, and having 'break1' point to where 'break2' now points.
+Finally, 'break2' should point to 'next'. Also, we observe that
+'break1' can't be a bottom, and is also not a top unless it is the same
+as 'next':
+*/
+ edge->subpath = break1->subpath;
+
+ break1->subpath = break2->subpath;
+ if (ISBREAK(break1, break1->subpath))
+ abort("unable to fix subpath break?");
+
+ break2->subpath = next;
+
+ break1->flag &= ~ISBOTTOM(ON);
+ if (break1 != next)
+ break1->flag &= ~ISTOP(ON);
+ }
+/*
+This region might contain "ambiguous" edges; edges exactly equal to
+edge->link. Due to the random dynamics of where they get sorted into
+the list, they can yield false crossings, where the edges appear
+to cross. This confuses our continuity logic no end. Since we can
+swap them without changing the region, we do.
+*/
+ for (edge = R->anchor, prev = NULL; VALIDEDGE(edge); prev = edge, edge = prev->link) {
+
+ if (! ISAMBIGUOUS(edge->flag))
+ continue;
+
+ next = edge->subpath;
+
+ while (ISAMBIGUOUS(next->flag) && next != edge)
+ next = next->subpath;
+/*
+We've finally found a non-ambiguous edge; we make sure it is left/right
+compatible with 'edge':
+*/
+ if ( (ISLEFT(edge->flag) == ISLEFT(next->flag) && ISDOWN(edge->flag) == ISDOWN(next->flag) )
+ || (ISLEFT(edge->flag) != ISLEFT(next->flag) && ISDOWN(edge->flag) != ISDOWN(next->flag) ) )
+ continue;
+
+/*
+Incompatible, we will swap 'edge' and the following edge in the list.
+You may think that there must be a next edge in this swath. So did I.
+No! If there is a totally ambiguous inner loop, for example, we could
+get all the way to the outside without resolving ambiguity.
+*/
+ next = edge->link; /* note new meaning of 'next' */
+ if (next == NULL || edge->ymin != next->ymin)
+ continue;
+ if (prev == NULL)
+ R->anchor = next;
+ else
+ prev->link = next;
+ edge->link = next->link;
+ next->link = edge;
+ edge->flag ^= ISLEFT(ON);
+ edge->flag &= ~ISAMBIGUOUS(ON);
+ next->flag ^= ISLEFT(ON);
+ next->flag &= ~ISAMBIGUOUS(ON);
+ edge = next;
+ }
+}
+/*
+:h3.DumpSubPaths()
+
+A debug tool.
+*/
+
+static struct edgelist *before(); /* subroutine of DumpSubPaths */
+
+static void DumpSubPaths(anchor)
+ struct edgelist *anchor;
+{
+
+ register struct edgelist *edge,*e,*e2;
+ pel y;
+
+ for (edge = anchor; VALIDEDGE(edge); edge = edge->link) {
+ if (ISPERMANENT(edge->flag))
+ continue;
+ IfTrace0(TRUE, "BEGIN Subpath\n");
+ for (e2 = edge; !ISPERMANENT(e2->flag);) {
+ if (ISDOWN(e2->flag)) {
+ IfTrace1(TRUE, ". Downgoing edge's top at %x\n", e2);
+ for (e = e2;; e = e->subpath) {
+ IfTrace4(TRUE, ". . [%5d] %5d @ %x[%x]\n",
+ e->ymin, *e->xvalues, e, e->flag);
+ for (y=e->ymin+1; y < e->ymax; y++)
+ IfTrace2(TRUE, ". . [%5d] %5d \"\n", y, e->xvalues[y-e->ymin]);
+ e->flag |= ISPERMANENT(ON);
+ if (ISBREAK(e, e->subpath))
+ break;
+ }
+ }
+ else {
+ IfTrace1(TRUE, ". Upgoing edge's top at %x\n", e2);
+ for (e = e2; !ISBREAK(e, e->subpath); e = e->subpath) { ; }
+ for (;; e=before(e)) {
+ IfTrace4(TRUE, ". . [%5d] %5d @ %x[%x]\n",
+ e->ymax-1, e->xvalues[e->ymax-1-e->ymin], e, e->flag);
+ for (y=e->ymax-2; y >= e->ymin; y--)
+ IfTrace2(TRUE, ". . [%5d] %5d \"\n", y, e->xvalues[y-e->ymin]);
+ e->flag |= ISPERMANENT(ON);
+ if (e == e2)
+ break;
+ }
+ }
+ do {
+ e2 = before(e2);
+ } while (!ISBREAK(before(e2), e2));
+ }
+ }
+}
+
+static struct edgelist *before(e)
+ struct edgelist *e;
+{
+ struct edgelist *r;
+ for (r = e->subpath; r->subpath != e; r = r->subpath) { ; }
+ return(r);
+}
+
+/*
+:h2.Fixing Region Continuity Problems
+
+Small regions may become disconnected when their connecting segments are
+less than a pel wide. This may be correct in some applications, but in
+many (especially small font characters), it is more pleasing to keep
+connectivity. ApplyContinuity() (invoked by +CONTINUITY on the
+Interior() fill rule) fixes connection breaks. The resulting region
+is geometrically less accurate, but may be more pleasing to the eye.
+*/
+/*
+Here are some macros which we will need:
+*/
+
+#define IsValidPel(j) (j!=MINPEL)
+
+/*
+:h3.writeXofY() - Stuffs an X Value Into an "edgelist"
+
+writeXofY writes an x value into an edge at position 'y'. It must
+update the edge's xmin and xmax. If there is a possibility that this
+new x might exceed the region's bounds, updating those are the
+responsibility of the caller.
+*/
+
+static void writeXofY(e, y, x)
+ struct edgelist *e; /* relevant edgelist */
+ int y; /* y value */
+ int x; /* new x value */
+{
+ if (e->xmin > x) e->xmin = x;
+ if (e->xmax < x) e->xmax = x;
+ e->xvalues[y - e->ymin] = x;
+}
+
+/*-------------------------------------------------------------------------*/
+/* the following three macros tell us whether we are at a birth point, a */
+/* death point, or simply in the middle of the character */
+/*-------------------------------------------------------------------------*/
+#define WeAreAtTop(e,i) (ISTOP(e->flag) && e->ymin == i)
+#define WeAreAtBottom(e,i) (ISBOTTOM(e->flag) && e->ymax-1 == i)
+#define WeAreInMiddle(e,i) \
+ ((!ISTOP(e->flag) && !ISBOTTOM(e->flag))||(i < e->ymax-1 && i > e->ymin))
+/*
+The following macro tests if two "edgelist" structures are in the same
+swath:
+*/
+#define SAMESWATH(e1,e2) (e1->ymin == e2->ymin)
+
+/*
+:h3.CollapseWhiteRun() - Subroutine of ApplyContinuity()
+
+When we have a white run with an implied horizontal line above or
+below it, we better have black on the other side of this line. This
+function both tests to see if black is there, and adjusts the end
+points (collapses) the white run as necessary if it is not. The
+goal is to collapse the white run as little as possible.
+*/
+
+static void CollapseWhiteRun(anchor, yblack, left, right, ywhite)
+ struct edgelist *anchor; /* anchor of edge list */
+ pel yblack; /* y of (hopefully) black run above or below */
+ struct edgelist *left; /* edgelist at left of WHITE run */
+ struct edgelist *right; /* edgelist at right of WHITE run */
+ pel ywhite; /* y location of white run */
+{
+ struct edgelist *edge;
+ struct edgelist *swathstart = anchor;
+ register pel x;
+
+ if (XofY(left, ywhite) >= XofY(right, ywhite))
+ return;
+/*
+Find the swath with 'yblack'. If we don't find it, completely collapse
+the white run and return:
+*/
+ while (VALIDEDGE(swathstart)) {
+ if (yblack < swathstart->ymin) {
+ writeXofY(left, ywhite, XofY(right, ywhite));
+ return;
+ }
+ if (yblack < swathstart->ymax) break;
+ swathstart = swathstart->link->link;
+ }
+ if(!VALIDEDGE(swathstart)) {
+ writeXofY(left, ywhite, XofY(right, ywhite));
+ return;
+ }
+/*
+Now we are in the swath that contains 'y', the reference line above
+or below that we are trying to maintain continuity with. If black
+in this line begins in the middle of our white run, we must collapse
+the white run from the left to that point. If black ends in the
+middle of our white run, we must collapse the white run from the right
+to that point.
+*/
+ for (edge = swathstart; VALIDEDGE(edge); edge = edge->link) {
+
+ if (!SAMESWATH(swathstart,edge))
+ break;
+ if( XofY(edge, yblack) > XofY(left, ywhite)) {
+ if (ISLEFT(edge->flag)) {
+ x = XofY(edge, yblack);
+ if (XofY(right, ywhite) < x)
+ x = XofY(right, ywhite);
+ writeXofY(left, ywhite, x);
+ }
+ else {
+ x = XofY(edge, yblack);
+ while (edge->link != NULL && SAMESWATH(edge, edge->link)
+ && x >= XofY(edge->link, yblack) ) {
+ edge = edge->link->link;
+ x = XofY(edge, yblack);
+ }
+ if (x < XofY(right, ywhite))
+ writeXofY(right, ywhite, x);
+ return;
+ }
+ }
+ }
+ writeXofY(left, ywhite, XofY(right, ywhite));
+}
+
+/*
+:h3.ApplyContinuity() - Fix False Breaks in a Region
+
+This is the externally visible routine called from the REGIONS module
+when the +CONTINUITY flag is on the Interior() fill rule.
+*/
+
+void ApplyContinuity(R)
+struct region *R;
+{
+ struct edgelist *left;
+ struct edgelist *right;
+ struct edgelist *edge,*e2;
+ pel rightXabove,rightXbelow,leftXabove,leftXbelow;
+ pel leftX,rightX;
+ int i;
+ long newcenter,abovecenter,belowcenter;
+
+ FixSubPaths(R);
+ if (RegionDebug >= 3)
+ DumpSubPaths(R->anchor);
+ left = R->anchor;
+/* loop through and do all of the easy checking. ( no tops or bottoms) */
+ while(VALIDEDGE(left))
+ {
+ right = left->link;
+ for(i=left->ymin;i<left->ymax;++i)
+ {
+ leftX = findXofY(left,i);
+ rightX = findXofY(right,i);
+ leftXbelow = findXofY(left,i+1);
+ rightXbelow = findXofY(right,i+1);
+ if(rightX <= leftX)
+ {
+/* then, we have a break in a near vertical line */
+ leftXabove = findXofY(left,i-1);
+ rightXabove = findXofY(right,i-1);
+ if( IsValidPel(leftXabove) && IsValidPel(rightXabove) )
+ {
+ abovecenter = leftXabove + rightXabove;
+ }
+ else
+ {
+ abovecenter = leftX + rightX;
+ }
+ if( IsValidPel(leftXbelow) && IsValidPel(rightXbelow) )
+ {
+ belowcenter = leftXbelow + rightXbelow;
+ }
+ else
+ {
+ belowcenter = leftX + rightX;
+ }
+ newcenter = abovecenter + belowcenter;
+ if( newcenter > 4*leftX )
+ {
+ rightX = rightX + 1;
+ }
+ else if( newcenter < 4*leftX)
+ {
+ leftX = leftX - 1;
+ }
+ else
+ {
+ rightX = rightX + 1;
+ }
+ writeXofY(right,i,rightX);
+ writeXofY(left,i,leftX);
+ if(rightX > R->xmax) {R->xmax = rightX;}
+ if(leftX < R->xmin) {R->xmin = leftX;}
+ }
+ if( !WeAreAtBottom(left,i) && (leftXbelow>=rightX))
+ {
+/* then we have a break in a near horizontal line in the middle */
+ writeXofY(right,i,leftXbelow);
+ }
+ if( !WeAreAtBottom(right,i) && (leftX >=rightXbelow))
+ {
+/* then we have a break in a near horizontal line in the middle */
+ writeXofY(left,i,rightXbelow);
+ }
+ }
+ left = right->link;
+ }
+/*
+There may be "implied horizontal lines" between edges that have
+implications for continuity. This loop looks for white runs that
+have implied horizontal lines on the top or bottom, and calls
+CollapseWhiteRuns to check and fix any continuity problems from
+them.
+*/
+ for (edge = R->anchor; VALIDEDGE(edge); edge = edge->link) {
+ if ((!ISTOP(edge->flag) && !ISBOTTOM(edge->flag)) || ISLEFT(edge->flag))
+ continue; /* at some future date we may want left edge logic here too */
+ for (e2 = edge->link; VALIDEDGE(e2) && SAMESWATH(edge,e2); e2 = e2->link) {
+ if (ISTOP(e2->flag) && ISTOP(edge->flag)
+ && NONE != ImpliedHorizontalLine(edge,e2,edge->ymin)) {
+ if (ISLEFT(e2->flag))
+ CollapseWhiteRun(R->anchor, edge->ymin-1,
+ edge, e2, edge->ymin);
+ }
+ if (ISBOTTOM(e2->flag) && ISBOTTOM(edge->flag)
+ && NONE != ImpliedHorizontalLine(edge,e2, edge->ymax)) {
+ if (ISLEFT(e2->flag))
+ CollapseWhiteRun(R->anchor, edge->ymax,
+ edge, e2, edge->ymax-1);
+ }
+ }
+ }
+}
+
+
+
+
diff --git a/src/Type1/hints.h b/src/Type1/hints.h
new file mode 100644
index 0000000..79ef326
--- /dev/null
+++ b/src/Type1/hints.h
@@ -0,0 +1,42 @@
+/* $Xorg: hints.h,v 1.3 2000/08/17 19:46:30 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+/*SHARED*/
+
+#define InitHints() t1_InitHints()
+void t1_InitHints(); /* Initialize hint data structure */
+
+#define CloseHints(hintP) t1_CloseHints(hintP)
+void t1_CloseHints(); /* Reverse hints that are still open */
+
+#define ProcessHint(hP, currX, currY, hintP) t1_ProcessHint(hP, currX, currY, hintP)
+void t1_ProcessHint(); /* Process a rasterization hint */
+
+#define ApplyContinuity(R) t1_ApplyContinuity(R)
+void t1_ApplyContinuity(); /* fix false connection breaks in a region */
+/*END SHARED*/
diff --git a/src/Type1/lines.c b/src/Type1/lines.c
new file mode 100644
index 0000000..3afcfc1
--- /dev/null
+++ b/src/Type1/lines.c
@@ -0,0 +1,186 @@
+/* $Xorg: lines.c,v 1.3 2000/08/17 19:46:30 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+ /* LINES CWEB V0003 ******** */
+/*
+:h1.LINES Module - Rasterizing Lines
+
+&author. Duaine W. Pryor, Jr. and Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
+
+
+:h3.Include Files
+
+The included files are:
+*/
+
+#include "objects.h"
+#include "spaces.h"
+#include "regions.h"
+#include "lines.h"
+
+/*
+:h3.Functions Provided to the TYPE1IMAGER User
+
+None.
+*/
+
+/*
+:h3.Functions Provided to Other Modules
+
+This module provides the following entry point to other modules:
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h3.Macros Provided to Other Modules
+
+None.
+*/
+
+/*
+:h2.StepLine() - Produces Run Ends for a Line After Checks
+
+The main work is done by Bresenham(); here we just perform checks and
+get the line so that its Y direction is always increasing:
+*/
+
+void StepLine(R, x1, y1, x2, y2)
+ register struct region *R; /* region being built */
+ register fractpel x1,y1; /* starting point */
+ register fractpel x2,y2; /* ending point */
+{
+ register fractpel dy;
+
+ IfTrace4((LineDebug > 0), ".....StepLine: (%p,%p) to (%p,%p)\n",
+ x1, y1, x2, y2);
+
+ dy = y2 - y1;
+
+/*
+We execute the "GOING_TO" macro to call back the REGIONS module, if
+necessary (like if the Y direction of the edge has changed):
+*/
+ GOING_TO(R, x1, y1, x2, y2, dy);
+
+ if (dy == 0)
+ return;
+
+ if (dy < 0)
+ Bresenham(R->edge, x2, y2, x1, y1);
+ else
+ Bresenham(R->edge, x1, y1, x2, y2);
+ return;
+}
+/*
+:h3.Bresenham() - Actually Produces Run Ends
+
+This routine runs a Bresenham line-stepping
+algorithm. See, for example, Newman and Sproul, :hp1/Principles
+of Interactive Computer Graphics/, pp. 25-27.
+When we enter this, we
+are guaranteed that dy is positive.
+We'd like to work in 8 bit precision, so we'll define some macros and
+constants to let us do that:
+*/
+
+#define PREC 8 /* we'll keep fraction pels in 8 bit precision */
+/*
+RoundFP() rounds down by 'b' bits:
+*/
+#define RoundFP(xy,b) (((xy)+(1<<((b)-1)))>>(b))
+
+/*
+TruncFP() truncates down by 'b' bits:
+*/
+#define TruncFP(xy,b) ((xy)>>(b))
+
+
+void Bresenham(edgeP,x1,y1,x2,y2)
+ register pel *edgeP; /* pointer to top of list (y == 0) */
+ register fractpel x1,y1; /* starting point on line */
+ register fractpel x2,y2; /* ending point on the line (down) */
+{
+ register long dx,dy; /* change in x and y, in my own precision */
+ register long x,y; /* integer pel starting point */
+ register int count; /* integer pel delta y */
+ register long d; /* the Bresenham algorithm error term */
+
+ x1 = TruncFP(x1, FRACTBITS-PREC);
+ y1 = TruncFP(y1, FRACTBITS-PREC);
+ x2 = TruncFP(x2, FRACTBITS-PREC);
+ y2 = TruncFP(y2, FRACTBITS-PREC);
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+/*
+Find the starting x and y integer pel coordinates:
+*/
+
+ x = RoundFP(x1,PREC);
+ y = RoundFP(y1,PREC);
+ edgeP += y;
+ count = RoundFP(y2,PREC) - y;
+/*------------------------------------------------------------------*/
+/* Force dx to be positive so that dfy will be negative */
+/* this means that vertical moves will decrease d */
+/*------------------------------------------------------------------*/
+ if (dx<0)
+ {
+ dx = -dx;
+#define P PREC
+ d=(dy*(x1-(x<<P)+(1<<(P-1)))-dx*((y<<P)-y1+(1<<(P-1))))>>P;
+#undef P
+ while(--count >= 0 )
+ {
+ while(d<0)
+ {
+ --x;
+ d += dy;
+ }
+ *(edgeP++) = x;
+ d -= dx;
+ }
+ }
+ else /* positive dx */
+ {
+#define P PREC
+ d = (dy*((x<<P)-x1+(1<<(P-1)))-dx*((y<<P)-y1+(1<<(P-1))))>>P;
+#undef P
+ while(--count >= 0 )
+ {
+ while(d<0)
+ {
+ ++x;
+ d += dy;
+ }
+ *(edgeP++) = x;
+ d -= dx;
+ }
+ }
+}
diff --git a/src/Type1/lines.h b/src/Type1/lines.h
new file mode 100644
index 0000000..8e2cc74
--- /dev/null
+++ b/src/Type1/lines.h
@@ -0,0 +1,37 @@
+/* $Xorg: lines.h,v 1.3 2000/08/17 19:46:30 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+/*SHARED*/
+
+#define StepLine(R,x1,y1,x2,y2) t1_StepLine(R,x1,y1,x2,y2)
+#define Bresenham(e,x1,y1,x2,y2) t1_Bresenham(e,x1,y1,x2,y2)
+
+void t1_StepLine(); /* check for special conditions, call Bresenham */
+void t1_Bresenham(); /* produce run ends for lines */
+
+/*END SHARED*/
diff --git a/src/Type1/objects.c b/src/Type1/objects.c
new file mode 100644
index 0000000..438e859
--- /dev/null
+++ b/src/Type1/objects.c
@@ -0,0 +1,1125 @@
+/* $Xorg: objects.c,v 1.3 2000/08/17 19:46:30 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+ /* OBJECTS CWEB V0025 ******** */
+/*
+:h1.OBJECTS Module - TYPE1IMAGER Objects Common Routines
+
+This module defines and implements the C structures that represent
+objects in the TYPE1IMAGER. All common routines for manipulating these
+objects are defined in this module. Specific routines for
+specific objects are defined in the modules that deal with that
+object type.
+
+
+&author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
+
+
+:h3.Include Files
+
+The included files are:
+*/
+#define GLOBALS 1 /* see :hdref refid=debugvar. */
+/*
+The following two includes are C standards; we include them because we
+use 'toupper' and the 'str'-type functions in this module. Potentially
+these may be defined as macros; if these ".h" files do not exist on your
+system it is a pretty safe bet that these are external entry points and
+you do do not need to include these header files.
+*/
+
+#include <string.h>
+#include <ctype.h>
+
+/*
+override incorrect system functions; for example you might define
+a macro for "strcpy" that diverts it to "my_strcpy".
+*/
+
+ /* moved these includes from above the */
+ /* was included first (it contains com- */
+ /* piler defines). dsr 081291 */
+#include "objects.h"
+#include "spaces.h"
+#include "paths.h"
+#include "regions.h"
+#include "fonts.h"
+#include "pictures.h"
+#include "strokes.h"
+#include "cluts.h"
+static char *TypeFmt();
+
+/*
+:h3.The "pointer" Macro - Define a Generic Pointer
+
+Sadly, many compilers will give a warning message when a pointer to
+one structure is assigned to a pointer to another. We've even seen
+some that give severe errors (when the wrong pointer type is used as
+an initializer or returned from a function). TYPE1IMAGER has routines
+like Dup and Allocate that are perfectly willing to duplicate or
+allocate any of a number of different types of structures. How to
+declare them in a truely portable way?
+
+Well, there is no single good answer that I've found. You can always
+beg the question and "cast" everything. I find this distracting and the
+resulting code ugly. On the other hand, we have found at least one
+compiler that will accept "void *" as a generic pointer that can
+assigned to any other pointer type without error or warning (apparently
+this is also the ANSI standard). So, we define "void *" to be a generic
+pointer. (You might have to change this for your compiler; the "ifndef"
+allows the change to be made on the command line if you want.)
+:i1/portability assumptions/
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.Functions Provided to the TYPE1IMAGER User
+
+This module provides the following TYPE1IMAGER entry points:
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+Note that entry points that are intended for use external to TYPE1IMAGER
+begin with the characters :q/xi/. Macros are used to make the names
+more mnemonic.
+*/
+
+/*
+:h3.Functions Provided to Other Modules
+
+This module provides the following functions for other modules:
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+Note that entry points that intended for use within TYPE1IMAGER, but
+which must be global because they are used across module boundaries,
+begin with the characters :q/I_/. Macros are used to make the names
+more mnemonic.
+
+Entry points totally within a module use mnemonic names and are
+declared :hp2/static/. One of the compilers I used had a bug when
+static functions were passed as addresses. Thus, some functions
+which are logically "static" are not so declared.
+
+Note also the trick of declaring routines, like Consume(), with a
+variable number of arguments. To avoid the restrictions on variable
+numbers of arguments in the macro processor, we just replace the
+text 'Consume' with 'I_Consume'.
+*/
+/*
+:h3.Macros Provided to Other Modules
+
+This is the module where we define all the useful constants like
+TRUE, FALSE, and NULL, and simple expressions like MIN(), MAX(), and ABS().
+We might as well get to it right here:
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+Notice that upper case is used for constant values and macro
+definitions. I generally follow that convention.
+
+Many more global macros are defined later in this module.
+*/
+/*
+:h2.Basic TYPE1IMAGER Object Structure
+
+All TYPE1IMAGER objects which are available to the user have a common
+header. This header is defined below:
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+The following define is an attempt to centralize the definition of the
+common xobject data shared by structures that are derived from the
+generic xobject structure. For example, the structure font, defined in
+fonts.shr :
+&code.
+ struct font {
+ char type;
+ char flag;
+ int references;
+ ... other data types & structs ...
+ }
+&ecode.
+would now be defined as:
+&code.
+ struct font {
+ XOBJ_COMMON
+ ... other data types & structs ...
+ }
+&ecode.
+Thus we have a better-structured inheritance mechanism. 3-26-91 PNM
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.Object Type Definitions
+
+These constants define the values which go in the 'type' field of
+an TYPE1IMAGER object structure:
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.Flag Byte Definitions
+
+Many programmers define flag bits as a mask (for example, 0x04), and
+test, set, and reset them as follows:
+
+&code.
+ if ((flag & PERMANENT) != 0)
+
+ flag |= PERMANENT;
+ flag &= &inv.PERMANENT;
+:exmp.
+
+I favor a style where the 'if' statement can ask a question:
+
+&code.
+ if (ISPERMANENT(flag))
+
+ flag |= ISPERMANENT(ON);
+ flag &= &inv.ISPERMANENT(ON);
+
+:exmp.
+This said, we now define two bit settings of the flag byte of the
+object. "ISPERMANENT" will be set by the user, when he calls
+Permanent(). "ISIMMORTAL" will be used for compiled-in objects
+that we don't want the user to ever destroy.
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+Flag bit definitions that apply to all objects are assigned
+starting with the least significant (0x01) bit. Flag bit definitions
+specific to a certain object type are assigned starting with the
+most significant (0x80) bit. We hope they never meet.
+*/
+/*
+:h3 id=preserve.PRESERVE() Macro
+
+Occasionally an TYPE1IMAGER operator is implemented by calling other
+TYPE1IMAGER operators. For example, Arc2() calls Conic(). When we
+call more than one operator as a subroutine, we have to be careful
+of temporary objects. A temporary object will be consumed by the
+subroutine operator and then is no longer available for the caller.
+This can be prevented simply by bumping a temporary object's reference
+count.
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h3.RefRoll() Macro to Detect References Count Rollover
+
+The following macro is designed to check for reference count rollover.
+A return value of TRUE means rollover has not occurred; a return value
+of FALSE means we cannot increment the reference count. Note also that
+those functions that use this macro must decrement the reference count
+afterwards. 3-26-91 PNM
+*/
+
+#define RefRoll(obj) (++(obj)->references > 0)
+
+/*
+:h2.TYPE1IMAGER Object Functions
+
+:h3.LONGCOPY() - Macro to Copy "long" Aligned Data
+
+Copying arbitrary bytes in C is a bit of a problem. "strcpy" can't be
+used, because 0 bytes are special-cased. Most environments have a
+routine "memcopy" or "bcopy" or "bytecopy" that copies memory containing
+zero bytes. Sadly, there is no standard on the name of such a routine,
+which makes it impossible to write truely portable code to use it.
+
+It turns out that TYPE1IMAGER, when it wants to copy data, frequently
+knows that both the source and destination are aligned on "long"
+boundaries. This allows us to copy by using "long *" pointers. This
+is usually very efficient on almost all processors. Frequently, it
+is more efficient than using general-purpose assembly language routines.
+So, we define a macro to do this in a portable way. "dest" and "source"
+must be long-aligned, and "bytes" must be a multiple of "sizeof(long)":
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.Allocate() - Allocating a Memory Block
+
+Allocate returns a pointer to memory object that is a copy of
+the template passed (if any). In addition, extra bytes may be
+allocated contiguously with the object. (This may be useful for
+variable size objects such as edge lists. See :hdref refid=regions..)
+
+Allocate() always returns a non-immortal object, even if the template is
+immortal. Therefore a non-NULL template must have a "flag" byte.
+
+If the template is NULL, then 'size' bytes are cleared to all NULLs.
+
+If the template is non-NULL, a new object is allocated in memory.
+It therefore seems logical that its reference count field should be
+set to 1. So, a nun-NULL template must also have a "references" field.
+PNM 3-26-91
+*/
+
+struct xobject *t1_Allocate(size, template, extra) /* non-ANSI; type checking was too strict */
+ register int size; /* number of bytes to allocate & initialize */
+ register struct xobject *template; /* example structure to allocate */
+ register int extra; /* any extra uninitialized bytes needed contiguously */
+{
+ extern char *xiMalloc(); /* standard C routine */
+
+ register struct xobject *r;
+
+ /*
+ * round up 'size' and 'extra' to be an integer number of 'long's:
+ */
+ size = (size + sizeof(long) - 1) & -(int)sizeof(long);
+ extra = (extra + sizeof(long) - 1) & -(int)sizeof(long);
+ if (size + extra <= 0)
+ abort("Non-positive allocate?");
+ r = (struct xobject *) xiMalloc(size + extra);
+
+ while (r == NULL) {
+ if (!GimeSpace()) {
+ IfTrace1(TRUE, "malloc attempted %d bytes.\n",
+ size + extra);
+ abort("We have REALLY run out of memory");
+ }
+ r = (struct xobject *) xiMalloc(size + extra);
+ }
+
+ /*
+ * copy the template into the new memory:
+ */
+ if (template != NULL) {
+ /* Added references count decrement if template is not permanent.
+ This is for the case where Allocate is called by a Dupxxxx
+ function, which was in turn called by Unique(). (PNM) */
+ if (!ISPERMANENT(template->flag))
+ --template->references;
+ LONGCOPY(r, template, size);
+ r->flag &= ~(ISPERMANENT(ON) | ISIMMORTAL(ON));
+ /* added reference field 3-2-6-91 PNM */
+ r->references = 1;
+ }
+ else {
+ register char **p1;
+
+ for (p1=(char **)r; size > 0; size -= sizeof(char *))
+ *p1++ = NULL;
+ }
+
+ if (MemoryDebug > 1) {
+ register long *L;
+ L = (long *) r;
+ IfTrace4(TRUE, "Allocating at %x: %x %x %x\n",
+ L, L[-1], L[0], L[1]);
+ }
+ return(r);
+}
+
+/*
+:h3.Free() - Frees an Allocated Object
+
+This routine makes a sanity check to make sure the "type" field of the
+standard object structure has not been cleared. If the object is
+not a standard structure, then the macro "NonObjectFree" is available
+that does not perform this check.
+
+In either case, the object must not be the NULL pointer. This preserves
+portability, as the C system xiFree() will not always accept NULL.
+*/
+
+void Free(obj) /* non-ANSI to avoid overly strict type checking */
+ register struct xobject *obj; /* structure to free */
+{
+ if (obj->type == INVALIDTYPE)
+ abort("Free of already freed object?");
+ obj->type = INVALIDTYPE;
+
+ if (MemoryDebug > 1) {
+ register long *L;
+ L = (long *) obj;
+ IfTrace4(TRUE,"Freeing at %x: %x %x %x\n", L, L[-1], L[0], L[1]);
+ }
+
+ xiFree(obj);
+}
+
+/*
+:h3.Permanent() - Makes an Object Permanent
+
+Real simple--just set a flag. Every routine that consumes its objects
+(which is almost every user entry) must check this flag, and not consume
+the object if it is set.
+
+If a temporary object is made permanent, and there is more than one
+reference to it, we must first Copy() it, then set the ISPERMANENT
+flag. Note also that the reference count must be incremented when an
+object is changed from temporary to permanent (see the ISUNIQUE macro).
+
+Note that the purpose of this function is to convert an object into a
+permanent object:
+ If it was permanent to begin with, we do nothing;
+ If it was temporary and unique, we set the PERMANENT flag and increment
+the reference count;
+ If it was temporary and nonunique, we must make a unique Copy(), set
+the PERMANENT flag, and set the reference count to 2. We must also
+decrement the original object's reference count, because what we have
+done is to change one of the old temporary handles to a permanent one.
+3-26-91 PNM
+*/
+
+struct xobject *t1_Permanent(obj) /* non-ANSI to avoid overly strict type checking */
+ register struct xobject *obj; /* object to be made permanent */
+{
+ IfTrace1((MustTraceCalls),"Permanent(%z)\n", obj);
+
+ if ( (obj != NULL) && ( !(ISPERMANENT(obj->flag)) ) )
+ {
+ /* there is a non-NULL, temporary object to be made permanent.
+ If there are multiple references to this object, first get
+ a new COPY().
+ Note also that we have to decrement the reference count if
+ we do a Copy() here, because we are consuming the temporary
+ argument passed, and returning a unique, permanent one.
+ */
+ if ( obj->references > 1)
+ {
+ obj = Copy(obj);
+ }
+ /* now set the permanent flag, and increment the reference
+ count, since a temporary object has now become permanent. */
+ obj->references++;
+ obj->flag |= ISPERMANENT(ON);
+ }
+ return(obj);
+}
+
+/*
+:h3.Temporary() - Undoes the Effect of "Permanent()"
+
+This simply resets the "ISPERMANENT" flag.
+
+If a permanent object is made temporary, and there is more than one reference
+to it, we must first Copy() it, then reset the ISPERMANENT flag. However,
+if the permanent object has obly one reference, we need only decrement the
+reference count ( and reset the flag).
+
+Note that this function, in the case of a PERMANENT argument, basically
+converts the PERMANENT handle to a TEMPORARY one. Thus, in the case of
+a nonunique, permanent argument passed, we not only make a Copy(),
+we also decrement the reference count, to reflect the fact that we have
+lost a permanent handle and gained a temporary one.
+PNM 3-2-6-91
+*/
+
+struct xobject *xiTemporary(obj) /* non-ANSI to avoid overly strict type checking */
+ register struct xobject *obj; /* object to be made permanent */
+{
+ IfTrace1((MustTraceCalls),"Temporary(%z)\n", obj);
+
+ if (obj != NULL) {
+ /* if it's already temporary, there's nothing to do. */
+ if ISPERMANENT(obj->flag)
+ {
+ /* if there are multiple references to this object, get a
+ Copy we can safely alter. Recall that the reference count
+ is incremented for permanent objects.
+ Recall further that Copy returns an object with the
+ same flag state and a reference count of 2 (for PERMANENT
+ objects).
+ Thus, regardless of whether or not we need to copy a
+ permanent object, we still decrement its reference
+ count and reset the flag.
+ */
+ if (obj->references != 2 || ISIMMORTAL(obj->flag))
+ {
+ /* not unique; consume handle, get a temporary Copy! */
+ obj = Copy(obj);
+ }
+ /* else decrement the reference count (since it's going from
+ permanent to temporary) and clear the flag. */
+ else {
+ obj->references--;
+ obj->flag &= ~ISPERMANENT(ON);
+ }
+ }
+ }
+ return(obj);
+}
+
+/*
+:h3.Dup() - Duplicate an Object
+
+Dup will increment the reference count of an object, only making a
+Copy() if needed.
+Note that Dup() retains the state of the permanent flag.
+3-26-91 PNM
+*/
+
+
+struct xobject *t1_Dup(obj) /* non-ANSI avoids overly strict type checking */
+ register struct xobject *obj; /* object to be duplicated */
+{
+ register char oldflag; /* copy of original object's flag byte */
+
+ IfTrace1((MustTraceCalls),"Dup(%z)\n", obj);
+
+ if (obj == NULL)
+ return(NULL);
+ /* An immortal object must be Copy'ed, so that we get a mortal
+ copy of it, since we try not to destroy immortal objects. */
+ if (ISIMMORTAL(obj->flag))
+ return(Copy(obj));
+
+ /* if incrementing the reference count doesn't cause the count
+ to wrap, simply return the object with the count bumped. Note
+ that the RefRoll macro increments the count to perform the
+ rollover check, so we must decrement the count. */
+ if (RefRoll(obj))
+ return(obj);
+
+ /* that didn't work out, so put the count back and call Copy(). */
+ --obj->references;
+ oldflag = obj->flag;
+ obj = Copy(obj);
+ if (ISPERMANENT(oldflag))
+ obj = Permanent(obj);
+ return(obj);
+}
+
+/*
+:h3.Copy() - Make a New Copy of an Object
+
+This is the generic Copy() where the object type is unknown. There
+are specific Copyxxx functions for known object types.
+
+Copy will create a NEW temporary object, and WILL NOT simply bump the
+reference count.
+
+Sometimes duplicating an object is just as simple as Allocating with it
+as a template. But other objects are complicated linked lists. So, we
+let each module provide us a routine (or macro) that duplicates the
+objects it knows about.
+*/
+
+struct xobject *t1_Copy(obj)
+ register struct xobject *obj; /* object to be Copy'ed */
+{
+ if (obj == NULL)
+ return(NULL);
+
+ if (ISPATHTYPE(obj->type))
+ obj = (struct xobject *) CopyPath(obj);
+ else
+ switch (obj->type) {
+ case SPACETYPE:
+ obj = (struct xobject *) CopySpace(obj); break;
+ case FONTTYPE:
+ obj = (struct xobject *) CopyFont(obj); break;
+ case REGIONTYPE:
+ obj = (struct xobject *) CopyRegion(obj); break;
+ case PICTURETYPE:
+ obj = (struct xobject *) CopyPicture(obj); break;
+ case LINESTYLETYPE:
+ obj = (struct xobject *) CopyLineStyle(obj); break;
+ case STROKEPATHTYPE:
+ obj = (struct xobject *) CopyStrokePath(obj); break;
+ case CLUTTYPE:
+ obj = (struct xobject *) CopyCLUT(obj); break;
+ default:
+ return(ArgErr("Copy: invalid object", obj, NULL));
+ }
+
+ return(obj);
+}
+
+/*
+:h3.Destroy() - Destroys an Object
+
+This can get complicated. Just like with Copy(), we let the experts
+handle it.
+*/
+struct xobject *Destroy(obj) /* non-ANSI avoids overly strict type checking */
+ register struct xobject *obj; /* object to be destroyed */
+{
+ IfTrace1((MustTraceCalls),"Destroy(%z)\n", obj);
+
+ if (obj == NULL)
+ return(NULL);
+ if (ISIMMORTAL(obj->flag)) {
+ IfTrace1(TRUE,"Destroy of immortal object %z ignored\n", obj);
+ return(NULL);
+ }
+ if (ISPATHTYPE(obj->type))
+ KillPath(obj);
+ else {
+ switch (obj->type) {
+ case REGIONTYPE:
+ KillRegion(obj);
+ break;
+ case SPACETYPE:
+ KillSpace(obj);
+ break;
+ case LINESTYLETYPE:
+ KillLineStyle(obj);
+ break;
+ case FONTTYPE:
+ KillFont(obj);
+ break;
+ case PICTURETYPE:
+ KillPicture(obj);
+ break;
+ case STROKEPATHTYPE:
+ KillStrokePath(obj);
+ break;
+ case CLUTTYPE:
+ KillCLUT(obj);
+ break;
+ default:
+ return(ArgErr("Destroy: invalid object", obj, NULL));
+ }
+ }
+ return(NULL);
+}
+/*
+:h2.Generally Useful Macros
+
+:h3.FOLLOWING() - Macro to Point to the Data Following a Structure
+
+There are several places in TYPE1IMAGER where we will allocate variable
+data that belongs to a structure immediately after that structure.
+This is a performance technique, because it reduces the number of
+trips we have to take through xiMalloc() and xiFree(). It turns out C has
+a very convenient way to point past a structure--if 'p' is a pointer
+to a structure, 'p+1' is a pointer to the data after it. This
+behavior of C is somewhat startling and somewhat hard to follow, if
+you are not used to it, so we define a macro to point to the data
+following a structure:
+*/
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.TYPECHECK() - Verify the Type of an Argument
+
+This macro tests the type of an argument. If the test fails, it consumes
+any other arguments as necessary and causes the imbedding routine to
+return the value 'whenBAD'.
+
+Note that the consumeables list should be an argument list itself, for
+example (0) or (2,A,B). See :hdref refid=consume. below.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.ARGCHECK() - Perform an Arbitrary Check on an Argument
+
+This macro is a generalization of TYPECHECK to take an arbitrary
+predicate. If the error occurs (i.e., the predicate is true), the
+arbitrary message 'msg' is returned.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.TYPENULLCHECK() - Extension of TYPECHECK() for NULL arguments
+
+Many routines allow NULLs to be passed as arguments. 'whenBAD' will
+be returned in this case, too.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.MAKECONSUME() - Create a "Consume"-type Macro
+
+Consuming an object means destroying it if it is not permanent. This
+logic is so common to all the routines, that it is immortalized in this
+macro. For example, ConsumePath(p) can be simply defined as
+MAKECONSUME(p,KillPath(p)). In effect, this macro operates on a
+meta-level.
+:i1/consuming objects/
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h3.MAKEUNIQUE() - Create a "Unique"-type Macro
+
+Many routines are written to modify their arguments in place. Thus,
+they want to insure that they duplicate an object if it is permanent.
+This is called making an object "unique". For example, UniquePath(p)
+can be simply defined as MAKEUNIQUE(p,DupPath(p)).
+:i1/unique objects/
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+An object is unique (and directly alterable) if there is only one
+reference to it, and it is not permanent (in which case we increment
+the reference count, so we don't have to check the permanent bit).
+3-26-91 PNM
+
+Note the rules for making a unique object:
+&drawing.
+ IF (obj->references = 1) return(obj);
+ ELSE (references > 1)
+ IF (ISPERMANENT(obj->flag)) return(Dupxxx(obj));
+ ELSE (nonunique, temporary object!)
+ obj->references--; return(Dupxxx(obj));
+&edrawing.
+If we must make a Copy of a nonunique, temporary object, we decrement
+reference count of the original object!
+*/
+
+/*
+:h3.Unique() - Make a Unique Object
+
+Here is a generic 'Unique' function if the object type is not known.
+Why didn't we build it with the MAKEUNIQUE macro, you ask? Well, we
+used to, but there is at least one damn compiler in the world that
+raises errors if the types of an "(a) ? b : c" expression do not match.
+Also, when we changed Dup() to retain the permanent/temporary flag, we
+wanted to make sure "Unique" always returned a temporary object.
+
+Note that we cannot use Dup() to create a copy of the object in question,
+because Dup() may simply bump the reference count, and not return a
+unique copy to us. That is why we use t1_Copy().
+
+The purpose of this function is to make sure we have a copy of an object
+that we can safely alter:
+:ol.
+:li.If we have a unique, temporary object, we simply return the argument.
+:li.If we have a nonunique, temporary object, we have to make a new copy
+of it, and decrement the reference count of the original object, to reflect
+the fact that we traded temporary handles.
+:li.If we have a permanent object, we make a temporary copy of it, but
+we do not decrement the reference count of the original permanent object,
+because permanent objects, by definition, are persistent. 3-2-6-91 PNM
+:eol.
+*/
+
+struct xobject *t1_Unique(obj)
+ struct xobject *obj;
+{
+ /* if the original object is not already unique, make a unique
+ copy...Note also that if the object was not permanent, we must
+ consume the old handle! 3-26-91 PNM
+ NOTE : consumption of the old handle moved to Allocate. 4-18-91 */
+ if (!obj || obj->references == 1)
+ return(obj);
+
+ obj = Copy(obj);
+ /* and make sure we return a temporary object ! */
+ if (ISPERMANENT(obj->flag))
+ {
+ obj->flag &= ~ISPERMANENT(ON);
+ obj->references--;
+ }
+ return(obj);
+}
+
+
+/*
+:h2.Initialization, Error, and Debug Routines
+
+:h3 id=debugvar.Declarations for Debug Purposes
+
+We declare all the debug flags here. Some link editors make the not
+unreasonable restriction that only one module may declare and
+initialize global variables; all the rest must declare the variable
+'extern'. This is logical, but is somewhat awkward to implement with
+C include files. We solve the problem by temporarily making the name
+'extern' a null name if GLOBALS is defined. (GLOBALS is only defined
+in this OBJECTS module.) Since 'externs' can't be initialized, we
+have to handle that with #defines too.
+:i1/GLOBALS (&#define.)/
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+static char *ErrorMessage = NULL;
+
+/*
+:h3.Pragmatics() - Set/Reset Debug Flags
+
+We provide a controlled way for the TYPE1IMAGER user to set and reset
+our debugging and tracing:
+*/
+void Pragmatics(username, value)
+ char *username; /* name of the flag */
+ int value; /* value to set it to */
+{
+ register char *p; /* temporary loop variable */
+#define NAMESIZE 40
+ char name[NAMESIZE]; /* buffer to store my copy of 'username' */
+
+ if (strlen(username) >= (unsigned)NAMESIZE)
+ abort("Pragmatics name too large");
+ strcpy(name, username);
+ for (p = name; *p != '\0'; p++)
+ *p = toupper(*p);
+
+ if (!strcmp(name, "ALL"))
+ MustTraceCalls = InternalTrace = /* MustCrash = */
+ LineIOTrace = value;
+
+ else if (!strcmp(name, "LINEIOTRACE"))
+ LineIOTrace = value;
+
+ else if (!strcmp(name, "TRACECALLS"))
+ MustTraceCalls = value;
+
+ else if (!strcmp(name, "CHECKARGS"))
+ MustCheckArgs = value;
+
+ else if (!strcmp(name, "PROCESSHINTS"))
+ ProcessHints = value;
+
+ else if (!strcmp(name, "SAVEFONTPATHS"))
+ SaveFontPaths = value;
+
+ else if (!strcmp(name, "CRASTERCOMPRESSIONTYPE"))
+ CRASTERCompressionType = value;
+
+ else if (!strcmp(name, "CRASHONUSERERROR"))
+ MustCrash = value;
+
+ else if (!strcmp(name, "DEBUG"))
+ StrokeDebug = SpaceDebug = PathDebug = ConicDebug = LineDebug =
+ RegionDebug = MemoryDebug = FontDebug =
+ HintDebug = ImageDebug = OffPageDebug = value;
+
+ else if (!strcmp(name, "CONICDEBUG"))
+ ConicDebug = value;
+
+ else if (!strcmp(name, "LINEDEBUG"))
+ LineDebug = value;
+
+ else if (!strcmp(name, "REGIONDEBUG"))
+ RegionDebug = value;
+
+ else if (!strcmp(name, "PATHDEBUG"))
+ PathDebug = value;
+
+ else if (!strcmp(name, "SPACEDEBUG"))
+ SpaceDebug = value;
+
+ else if (!strcmp(name, "STROKEDEBUG"))
+ StrokeDebug = value;
+
+ else if (!strcmp(name, "MEMORYDEBUG"))
+ MemoryDebug = value;
+
+ else if (!strcmp(name, "FONTDEBUG"))
+ FontDebug = value;
+
+ else if (!strcmp(name, "HINTDEBUG"))
+ HintDebug = value;
+
+ else if (!strcmp(name, "IMAGEDEBUG"))
+ ImageDebug = value;
+
+ else if (!strcmp(name, "OFFPAGEDEBUG"))
+ OffPageDebug = value;
+
+#ifdef MC68000
+/*
+The following pragmatics flag turns on or off instruction histograming
+for performance analysis. It is only defined in the Delta card
+environment.
+*/
+ else if (!strcmp(name, "PROFILE")) {
+ if (value)
+ StartProfile();
+ else
+ StopProfile();
+ }
+#endif
+ else if (!strcmp(name, "FLUSHCACHE")) {
+#ifdef notdef
+ while (GimeSpace()) { ; }
+#endif
+ }
+
+ else if (!strcmp(name, "CACHEDCHARS"))
+ CachedChars = (value <= 0) ? 1 : value;
+
+ else if (!strcmp(name, "CACHEDFONTS"))
+ CachedFonts = (value <= 0) ? 1 : value;
+
+ else if (!strcmp(name, "CACHEBLIMIT"))
+ CacheBLimit = value;
+
+ else if (!strcmp(name, "CONTINUITY"))
+ Continuity = value;
+
+
+ else {
+ printf("Pragmatics flag = '%s'\n", name);
+ ArgErr("Pragmatics: flag not known", NULL, NULL);
+ }
+ return;
+}
+
+/*
+:h3.Consume() - Consume a List of Arguments
+
+This general purpose routine is provided in the case where the object
+type(s) to be consumed are unknown or not yet verified, and/or it is
+not known whether the object is permanent.
+
+If the type of the argument is known, it is faster to directly consume
+that type, for example, ConsumeRegion() or ConsumePath(). Furthermore,
+if it is already known that the object is temporary, it is faster to
+just kill it rather than consume it, for example, KillSpace().
+*/
+
+void Consume(n, obj1, obj2, obj3) /* non-ANSI avoids overly strict type checking */
+ int n;
+ struct xobject *obj1,*obj2,*obj3;
+{
+ switch(n) {
+
+ case 0:
+ return;
+
+ case 1:
+ if (obj1 != NULL && !ISPERMANENT(obj1->flag))
+ Destroy(obj1);
+ return;
+
+ case 2:
+ if (obj1 != NULL && !ISPERMANENT(obj1->flag))
+ Destroy(obj1);
+ if (obj2 != NULL && !ISPERMANENT(obj2->flag))
+ Destroy(obj2);
+ return;
+
+ case 3:
+ if (obj1 != NULL && !ISPERMANENT(obj1->flag))
+ Destroy(obj1);
+ if (obj2 != NULL && !ISPERMANENT(obj2->flag))
+ Destroy(obj2);
+ if (obj3 != NULL && !ISPERMANENT(obj3->flag))
+ Destroy(obj3);
+ return;
+
+ default:
+ abort("Consume: too many objects");
+ }
+}
+/*
+:h4.ObjectPostMortem() - Prints as Much as We Can About a Bad Object
+
+This is a subroutine of TypeErr() and ArgErr().
+*/
+
+/*ARGSUSED*/
+static void
+ObjectPostMortem(obj) /* non-ANSI avoids overly strict type checking */
+ register struct xobject *obj;
+{
+ extern struct XYspace *USER;
+
+ Pragmatics("Debug", 10);
+ IfTrace2(TRUE,"Bad object is of %s type %z\n", TypeFmt(obj->type), obj);
+
+ IfTrace0((obj == (struct xobject *) USER),
+ "Suspect that InitImager() was omitted.\n");
+ Pragmatics("Debug", 0);
+}
+
+/*
+:h3.TypeErr() - Handles "Invalid Object Type" Errors
+*/
+
+struct xobject *TypeErr(name, obj, expect, ret) /* non-ANSI avoids overly strict type checking */
+ char *name; /* Name of routine (for error message) */
+ struct xobject *obj; /* Object in error */
+ int expect; /* type expected */
+ struct xobject *ret; /* object to return to caller */
+{
+ /*
+ * This buffer must be large enough to hold 'name' plus
+ * two of the largest strings that can be returned by TypeFmt.
+ * The largest value of 'name' is currently 9 ("ClosePath")
+ * and the longest strings in TypeFmt are 30 characters.
+ */
+ static char typemsg[115];
+
+ if (MustCrash)
+ LineIOTrace = TRUE;
+
+ sprintf(typemsg, "Wrong object type in %s. Expected %s; was %s.\n",
+ name, TypeFmt(expect), TypeFmt(obj->type));
+ IfTrace0(TRUE,typemsg);
+
+ ObjectPostMortem(obj);
+
+ if (MustCrash)
+ abort("Terminating because of CrashOnUserError...");
+ else
+ ErrorMessage = typemsg;
+
+/* changed ISPERMANENT to ret->references > 1 3-26-91 PNM */
+ if (ret != NULL && (ret->references > 1))
+ ret = Dup(ret);
+ return(ret);
+}
+
+/*
+:h4.TypeFmt() - Returns Pointer to English Name of Object Type
+
+This is a subroutine of TypeErr().
+*/
+
+static char *TypeFmt(type)
+ int type; /* type field */
+{
+ char *r;
+
+ if (ISPATHTYPE(type))
+ if (type == TEXTTYPE)
+ r = "path or region (from TextPath)";
+ else
+ r = "path";
+ else {
+ switch (type) {
+ case INVALIDTYPE:
+ r = "INVALID (previously consumed?)";
+ break;
+ case REGIONTYPE:
+ r = "region";
+ break;
+ case SPACETYPE:
+ r = "XYspace";
+ break;
+ case LINESTYLETYPE:
+ r = "linestyle";
+ break;
+ case FONTTYPE:
+ r = "font";
+ break;
+ case PICTURETYPE:
+ r = "picture";
+ break;
+ case STROKEPATHTYPE:
+ r = "path (from StrokePath)";
+ break;
+ default:
+ r = "UNKNOWN";
+ break;
+ }
+ }
+ return(r);
+}
+/*
+:h3.ArgErr() - Invalid Argument Passed to a Routine
+
+A common routine to report argument errors. It is usually called
+is returned to the caller in case MustCrash is FALSE and ArgErr
+returns to its caller.
+*/
+
+struct xobject *ArgErr(string, obj, ret) /* non-ANSI avoids overly strict type checking */
+ char *string; /* description of error */
+ struct xobject *obj; /* object, if any, that was in error */
+ struct xobject *ret; /* object returned to caller or NULL */
+{
+ if (MustCrash)
+ LineIOTrace = TRUE;
+ IfTrace1(TRUE,"ARGUMENT ERROR-- %s.\n", string);
+ if (obj != NULL)
+ ObjectPostMortem(obj);
+ if (MustCrash)
+ abort("Terminating because of CrashOnUserError...");
+ else
+ ErrorMessage = string;
+ return(ret);
+}
+
+/*
+:h3.abort() - Crash Due to Error
+
+Defined in objects.h to be FatalError(), the server's abort routine.
+*/
+
+/*
+:h3.REAL Miscellaneous Stuff
+
+:h4.ErrorMsg() - Return the User an Error Message
+*/
+
+char *ErrorMsg()
+{
+ register char *r;
+
+ r = ErrorMessage;
+ ErrorMessage = NULL;
+ return(r);
+}
+
+/*
+:h4.InitImager() - Initialize TYPE1IMAGER
+
+We check that a short is 16 bits and a long 32 bits; we have made
+those assumptions elsewhere in the code. (This is almost a C standard,
+anyway.) Note that TYPE1IMAGER makes no assumptions about the size of an
+'int'!
+:i1/portability assumptions/
+*/
+
+void InitImager()
+{
+
+/* Check to see if we have been using our own malloc. If so,*/
+/* Undef malloc so that we can get to the system call. */
+/* All other calls to malloc are defined to xiMalloc. */
+
+
+/* if (sizeof(short) != 2 || sizeof(INT32) != 4)
+ abort("Fundamental TYPE1IMAGER assumptions invalid in this port");
+*/
+ InitSpaces();
+ InitFonts();
+ InitFiles();
+/*
+In some environments, constants and/or exception handling need to be
+*/
+ LibInit();
+}
+/*
+:h4.TermImager() - Terminate TYPE1IMAGER
+
+This only makes sense in a server environment; true TYPE1IMAGER needs do
+nothing.
+*/
+void TermImager()
+{
+ return;
+}
+/*
+:h4.reportusage() - A Stub to Get a Clean Link with Portable PMP
+*/
+void reportusage()
+{
+ return;
+}
diff --git a/src/Type1/objects.h b/src/Type1/objects.h
new file mode 100644
index 0000000..30a9773
--- /dev/null
+++ b/src/Type1/objects.h
@@ -0,0 +1,291 @@
+/* $Xorg: objects.h,v 1.3 2000/08/17 19:46:31 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+/*SHARED*/
+
+/*END SHARED*/
+/*SHARED*/
+
+#define Permanent(obj) t1_Permanent(obj)
+#define Temporary(obj) t1_Temporary(obj)
+#define Destroy(obj) t1_Destroy(obj)
+#define Dup(obj) t1_Dup(obj)
+#define InitImager() t1_InitImager()
+#define TermImager() t1_TermImager()
+#define Pragmatics(f,v) t1_Pragmatics(f,v)
+#define ErrorMsg() t1_ErrorMsg()
+
+struct xobject *t1_Permanent(); /* make an object permanent */
+struct xobject *t1_Temporary(); /* make an object temporary */
+struct xobject *t1_Destroy(); /* destroy an object */
+struct xobject *t1_Dup(); /* duplicate an object */
+void t1_InitImager(); /* initialize TYPE1IMAGER */
+void t1_TermImager(); /* terminate TYPE1IMAGER */
+void t1_Pragmatics(); /* set debug flags, etc. */
+char *t1_ErrorMsg(); /* return last TYPE1IMAGER error message */
+
+/*END SHARED*/
+/*SHARED*/
+
+#define abort(line) FatalError(line)
+#define Allocate(n,t,s) t1_Allocate(n,t,s)
+#define Free(obj) t1_Free(obj)
+#define NonObjectFree(a) xiFree(a)
+#define Consume t1_Consume
+#define ArgErr(s,o,r) t1_ArgErr(s,o,r)
+#define TypeErr(n,o,e,r) t1_TypeErr(n,o,e,r)
+#define Copy(obj) t1_Copy(obj)
+#define Unique(obj) t1_Unique(obj)
+
+struct xobject *t1_Allocate(); /* allocate memory */
+void t1_Free(); /* free memory */
+struct xobject *t1_Unique(); /* make a unique temporary copy of an object */
+struct xobject *t1_ArgErr(); /* handle argument errors */
+struct xobject *t1_TypeErr(); /* handle 'bad type' argument errors */
+void t1_Consume(); /* consume a variable number of arguments */
+struct xobject *t1_Copy(); /* make a new copy, not reference bump PNM */
+
+/*END SHARED*/
+/*SHARED*/
+
+#define ON (~0) /* all bits on */
+#ifndef FALSE
+#define FALSE 0 /* handy zero value */
+#endif
+#ifndef TRUE
+#define TRUE 1 /* handy non-zero value */
+#endif
+
+#ifndef NULL
+#define NULL 0
+/*
+The NULL pointer is system specific. (Most systems, however, use 0.)
+TYPE1IMAGER could have its own NULL, independent of the rest of the system,
+were it not for malloc(). The system call malloc() returns NULL when
+out of memory.
+:i1/portibility assumptions/
+*/
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b)) ? a : b)
+#endif
+#ifndef MAX
+#define MAX(a,b) (((a)>(b)) ? a : b)
+#endif
+#ifndef ABS
+#define ABS(a) (((a)>=0)?(a):-(a))
+#endif
+
+/*END SHARED*/
+/*SHARED*/
+
+struct xobject {
+ char type; /* encoded type of object */
+ unsigned char flag; /* flag byte for temporary object characteristics*/
+ short references; /* count of pointers to this object
+ (plus 1 for permanent objects) PNM */
+} ;
+
+/*END SHARED*/
+/*SHARED*/
+
+#define XOBJ_COMMON char type; unsigned char flag; short references;
+
+/*END SHARED*/
+/*SHARED*/
+
+
+#define INVALIDTYPE 0
+#define FONTTYPE 1
+#define REGIONTYPE 3
+#define PICTURETYPE 4
+#define SPACETYPE 5
+#define LINESTYLETYPE 6
+#define EDGETYPE 7
+#define STROKEPATHTYPE 8
+#define CLUTTYPE 9
+
+#define ISPATHTYPE(type) ((type)&0x10) /* all path segments have this bit on */
+#define LINETYPE (0+ISPATHTYPE(ON))
+#define CONICTYPE (1+ISPATHTYPE(ON))
+#define BEZIERTYPE (2+ISPATHTYPE(ON))
+#define HINTTYPE (3+ISPATHTYPE(ON))
+
+#define MOVETYPE (5+ISPATHTYPE(ON))
+#define TEXTTYPE (6+ISPATHTYPE(ON))
+
+/*END SHARED*/
+/*SHARED*/
+
+#define ISPERMANENT(flag) ((flag)&0x01)
+#define ISIMMORTAL(flag) ((flag)&0x02)
+
+/*END SHARED*/
+/*SHARED*/
+
+#define PRESERVE(obj) if (!ISPERMANENT((obj)->flag)) \
+ (obj)->references++;
+
+/*END SHARED*/
+/*SHARED*/
+
+#define LONGCOPY(dest,source,bytes) { \
+ register long *p1 = (long *)dest; register long *p2 = (long *)source; \
+ register int count = (bytes) / sizeof(long); \
+ while (--count >= 0) *p1++ = *p2++; }
+
+
+/*END SHARED*/
+/*SHARED*/
+
+#define FOLLOWING(p) ((p)+1)
+
+/*END SHARED*/
+/*SHARED*/
+
+#define TYPECHECK(name, obj, expect, whenBAD, consumables, rettype) { \
+ if (obj->type != expect) { \
+ (Consume)consumables; \
+ return((rettype)TypeErr(name, obj, expect, whenBAD)); \
+ } \
+}
+
+/*END SHARED*/
+/*SHARED*/
+
+#define ARGCHECK(test,msg,obj,whenBAD,consumables,rettype) { \
+ if (test) { \
+ (Consume)consumables; \
+ return((rettype)ArgErr(msg, obj, whenBAD)); \
+ } \
+}
+
+/*END SHARED*/
+/*SHARED*/
+
+/* Changed use of Dup() below to Temporary(Copy()) because Dup() does not
+ necessarily return a Unique Copy anymore! 3-26-91 */
+#define TYPENULLCHECK(name, obj, expect, whenBAD, consumables,rettype) \
+ if (obj == NULL) { \
+ (Consume)consumables; \
+ if (whenBAD != NULL && ISPERMANENT(whenBAD->flag)) \
+ return((rettype)Temporary(Copy(whenBAD))); \
+ else return((rettype)whenBAD); \
+ } else { \
+ if (obj->type != expect) { \
+ (Consume)consumables; \
+ return((rettype)TypeErr(name, obj, expect, whenBAD)); \
+ } \
+ }
+/*END SHARED*/
+/*SHARED*/
+
+#define MAKECONSUME(obj,stmt) { if (!ISPERMANENT(obj->flag)) stmt; }
+
+/*END SHARED*/
+/*SHARED*/
+
+#define MAKEUNIQUE(obj,stmt) ( ( (obj)->references > 1 ) ? stmt : obj )
+
+/*END SHARED*/
+/*SHARED*/
+#define IfTrace0(condition,model)
+#define IfTrace1(condition,model,arg0)
+#define IfTrace2(condition,model,arg0,arg1)
+#define IfTrace3(condition,model,arg0,arg1,arg2)
+#define IfTrace4(condition,model,arg0,arg1,arg2,arg3)
+#define IfTrace5(condition,model,arg0,arg1,arg2,arg3,arg4)
+#define IfTrace6(condition,model,arg0,arg1,arg2,arg3,arg4,arg5)
+
+
+void Trace0();
+char *Trace1(),*Trace2(),*Trace3(),*Trace4(),*Trace5(),*Trace6();
+
+#ifdef GLOBALS
+
+#define extern
+#define INITIALIZED(value) = value
+
+#else
+
+#define INITIALIZED(value)
+
+#endif
+
+extern char MustCheckArgs INITIALIZED(TRUE);
+extern char MustTraceCalls INITIALIZED(FALSE);
+extern char MustCrash INITIALIZED(TRUE);
+extern char InternalTrace INITIALIZED(TRUE);
+extern char LineIOTrace INITIALIZED(TRUE);
+
+extern char ProcessHints INITIALIZED(TRUE);
+
+extern char SaveFontPaths INITIALIZED(TRUE);
+
+extern short CRASTERCompressionType INITIALIZED(1);
+
+extern char ConicDebug INITIALIZED(0);
+extern char LineDebug INITIALIZED(0);
+extern char RegionDebug INITIALIZED(0);
+extern char PathDebug INITIALIZED(0);
+extern char FontDebug INITIALIZED(0);
+extern char SpaceDebug INITIALIZED(0);
+extern char StrokeDebug INITIALIZED(0);
+extern char MemoryDebug INITIALIZED(0);
+extern char HintDebug INITIALIZED(0);
+extern char ImageDebug INITIALIZED(0);
+extern char OffPageDebug INITIALIZED(0);
+
+extern short CachedChars INITIALIZED(0x7FFF);
+extern short CachedFonts INITIALIZED(0x7FFF);
+extern int CacheBLimit INITIALIZED(12500);
+extern char Continuity INITIALIZED(2);
+
+#ifdef extern
+#undef extern
+#endif
+
+/*
+We define other routines formatting parameters
+*/
+#define DumpArea(area) t1_DumpArea(area)
+#define DumpText(text) t1_DumpText(text)
+#define DumpPath(path) t1_DumpPath(path)
+#define DumpSpace(space) t1_DumpSpace(space)
+#define DumpEdges(e) t1_DumpEdges(e)
+#define FormatFP(s,p) t1_FormatFP(s,p)
+
+void t1_DumpArea(); /* dump a region structure */
+void t1_DumpText(); /* dump a textpath structure */
+void t1_DumpPath(); /* dump a path list */
+void t1_DumpSpace(); /* dump a coordinate space structure */
+void t1_DumpEdges(); /* dump a region's edge list */
+void t1_FormatFP(); /* dump a format a "fractpel" coordinate */
+
+/*END SHARED*/
diff --git a/src/Type1/paths.c b/src/Type1/paths.c
new file mode 100644
index 0000000..35c3e41
--- /dev/null
+++ b/src/Type1/paths.c
@@ -0,0 +1,1506 @@
+/* $Xorg: paths.c,v 1.3 2000/08/17 19:46:31 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+ /* PATHS CWEB V0021 ******** */
+/*
+:h1 id=paths.PATHS Module - Path Operator Handler
+
+This is the module that is responsible for building and transforming
+path lists.
+
+&author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
+
+
+:h3.Include Files
+
+The included files are:
+*/
+
+ /* after the system includes (dsr) */
+#include "objects.h"
+#include "spaces.h"
+#include "paths.h"
+#include "regions.h" /* understands about Union */
+#include "fonts.h" /* understands about TEXTTYPEs */
+#include "pictures.h" /* understands about handles */
+#include "strokes.h" /* understands how to coerce stroke paths */
+#include "trig.h"
+
+/*
+:h3.Routines Available to the TYPE1IMAGER User
+
+The PATHS routines that are made available to the outside user are:
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.Functions Provided to Other Modules
+
+The path routines that are made available to other TYPE1IMAGER modules
+are defined here:
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+NOTE: because of the casts put in the macros for Loc, ArcCA, Conic,
+RoundConic, PathSegment, and JoinSegment, we cannot use the macro names
+when the functions are actually defined. We have to use the unique
+names with their unique first two characters. Thus, if anyone in the
+future ever decided to change the first two characters, it would not be
+enough just to change the macro (as it would for most other functions).
+He would have to also change the function definition.
+*/
+/*
+:h3.Macros Provided to Other Modules
+
+The CONCAT macro is defined here and used in the STROKES module. See
+:hdref refid=pathmac..
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h2.Path Segment Structures
+
+A path is represented as a linked list of the following structure:
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+When 'link' is NULL, we are at the last segment in the path (surprise!).
+
+'last' is only non-NULL on the first segment of a path,
+for all the other segments 'last' == NULL. We test for a non-NULL
+'last' (ISPATHANCHOR predicate) when we are given an alleged path
+to make sure the user is not trying to pull a fast one on us.
+
+A path may be a collection of disjoint paths. Every break in the
+disjoint path is represented by a MOVETYPE segment.
+
+Closed paths are discussed in :hdref refid=close..
+
+:h3.CopyPath() - Physically Duplicating a Path
+
+This simple function illustrates moving through the path linked list.
+Duplicating a segment just involves making a copy of it, except for
+text, which has some auxilliary things involved. We don't feel
+competent to duplicate text in this module, so we call someone who
+knows how (in the FONTS module).
+*/
+struct segment *CopyPath(p0)
+ register struct segment *p0; /* path to duplicate */
+{
+ register struct segment *p,*n,*last,*anchor;
+
+ for (p = p0, anchor = NULL; p != NULL; p = p->link) {
+
+ ARGCHECK((!ISPATHTYPE(p->type) || (p != p0 && p->last != NULL)),
+ "CopyPath: invalid segment", p, NULL, (0), struct segment *);
+
+ if (p->type == TEXTTYPE)
+ n = (struct segment *) CopyText(p);
+ else
+ n = (struct segment *)Allocate(p->size, p, 0);
+ n->last = NULL;
+ if (anchor == NULL)
+ anchor = n;
+ else
+ last->link = n;
+ last = n;
+ }
+/*
+At this point we have a chain of newly allocated segments hanging off
+'anchor'. We need to make sure the first segment points to the last:
+*/
+ if (anchor != NULL) {
+ n->link = NULL;
+ anchor->last = n;
+ }
+
+ return(anchor);
+}
+/*
+:h3.KillPath() - Destroying a Path
+
+Destroying a path is simply a matter of freeing each segment in the
+linked list. Again, we let the experts handle text.
+*/
+void KillPath(p)
+ register struct segment *p; /* path to destroy */
+{
+ register struct segment *linkp; /* temp register holding next segment*/
+
+ /* return conditional based on reference count 3-26-91 PNM */
+ if ( (--(p->references) > 1) ||
+ ( (p->references == 1) && !ISPERMANENT(p->flag) ) )
+ return;
+
+ while (p != NULL) {
+ if (!ISPATHTYPE(p->type)) {
+ ArgErr("KillPath: bad segment", p, NULL);
+ return;
+ }
+ linkp = p->link;
+ if (p->type == TEXTTYPE)
+ KillText(p);
+ else
+ Free(p);
+ p = linkp;
+ }
+}
+
+/*
+:h2 id=location."location" Objects
+
+The TYPE1IMAGER user creates and destroys objects of type "location". These
+objects locate points for the primitive path operators. We play a trick
+here and store these objects in the same "segment" structure used for
+paths, with a type field == MOVETYPE.
+
+This allows the Line() operator, for example, to be very trivial:
+It merely stamps its input structure as a LINETYPE and returns it to the
+caller--assuming, of course, the input structure was not permanent (as
+it usually isn't).
+
+:h3.The "movesegment" Template Structure
+
+This template is used as a generic segment structure for Allocate:
+*/
+
+/* added reference field 1 to temporary template below 3-26-91 PNM */
+static struct segment movetemplate = { MOVETYPE, 0, 1, sizeof(struct segment), 0,
+ NULL, NULL, 0, 0 };
+/*
+:h3.Loc() - Create an "Invisible Line" Between (0,0) and a Point
+
+*/
+
+struct segment *t1_Loc(S, x, y)
+ register struct XYspace *S; /* coordinate space to interpret X,Y */
+ double x,y; /* destination point */
+{
+ register struct segment *r;
+
+
+ IfTrace3((MustTraceCalls),"..Loc(S=%z, x=%f, y=%f)\n", S, &x, &y);
+
+ r = (struct segment *)Allocate(sizeof(struct segment), &movetemplate, 0);
+ TYPECHECK("Loc", S, SPACETYPE, r, (0), struct segment *);
+
+ r->last = r;
+ r->context = S->context;
+ (*S->convert)(&r->dest, S, x, y);
+ ConsumeSpace(S);
+ return(r);
+}
+/*
+:h3.ILoc() - Loc() With Integer Arguments
+
+*/
+struct segment *ILoc(S, x, y)
+ register struct XYspace *S; /* coordinate space to interpret X,Y */
+ register int x,y; /* destination point */
+{
+ register struct segment *r;
+
+ IfTrace3((MustTraceCalls),"..ILoc(S=%z, x=%d, y=%d)\n",
+ S, (long) x, (long) y);
+ r = (struct segment *)Allocate(sizeof(struct segment), &movetemplate, 0);
+ TYPECHECK("Loc", S, SPACETYPE, r, (0), struct segment *);
+
+ r->last = r;
+ r->context = S->context;
+ (*S->iconvert)(&r->dest, S, (long) x, (long) y);
+ ConsumeSpace(S);
+ return(r);
+}
+
+/*
+:h3.SubLoc() - Vector Subtraction of Two Locition Objects
+
+This user operator subtracts two location objects, yielding a new
+location object that is the result.
+
+The symmetrical function AddLoc() is totally redundent with Join(),
+so it is not provided.
+*/
+
+struct segment *SubLoc(p1, p2)
+ register struct segment *p1;
+ register struct segment *p2;
+{
+ IfTrace2((MustTraceCalls),"SubLoc(%z, %z)\n", p1, p2);
+
+ ARGCHECK(!ISLOCATION(p1), "SubLoc: bad first arg", p1, NULL, (0), struct segment *);
+ ARGCHECK(!ISLOCATION(p2), "SubLoc: bad second arg", p2, NULL, (0), struct segment *);
+ p1 = UniquePath(p1);
+ p1->dest.x -= p2->dest.x;
+ p1->dest.y -= p2->dest.y;
+ ConsumePath(p2);
+ return(p1);
+}
+
+/*
+:h2.Straight Line Segments
+
+:h3.PathSegment() - Create a Generic Path Segment
+
+Many routines need a LINETYPE or MOVETYPE path segment, but do not
+want to go through the external user's interface, because, for example,
+they already know the "fractpel" destination of the segment and the
+conversion is unnecessary. PathSegment() is an internal routine
+provided to the rest of TYPE1IMAGER for handling these cases.
+*/
+
+struct segment *t1_PathSegment(type, x, y)
+ int type; /* LINETYPE or MOVETYPE */
+ fractpel x,y; /* where to go to, if known */
+{
+ register struct segment *r; /* newly created segment */
+
+ r = (struct segment *)Allocate(sizeof(struct segment), &movetemplate, 0);
+ r->type = type;
+ r->last = r; /* last points to itself for singleton */
+ r->dest.x = x;
+ r->dest.y = y;
+ return(r);
+}
+/*
+:h3.Line() - Create a Line Segment Between (0,0) and a Point P
+
+This involves just creating and filling out a segment structure:
+*/
+struct segment *Line(P)
+ register struct segment *P; /* relevant coordinate space */
+{
+
+ IfTrace1((MustTraceCalls),"..Line(%z)\n", P);
+ ARGCHECK(!ISLOCATION(P), "Line: arg not a location", P, NULL, (0), struct segment *);
+
+ P = UniquePath(P);
+ P->type = LINETYPE;
+ return(P);
+}
+/*
+:h2.Curved Path Segments
+
+We need more points to describe curves. So, the structures for curved
+path segments are slightly different. The first part is identical;
+the curved structures are larger with the extra points on the end.
+
+:h3.Bezier Segment Structure
+
+We support third order Bezier curves. They are specified with four
+control points A, B, C, and D. The curve starts at A with slope AB
+and ends at D with slope CD. The curvature at the point A is inversely
+related to the length |AB|, and the curvature at the point D is
+inversely related to the length |CD|. Point A is always point (0,0).
+
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.Bezier() - Generate a Bezier Segment
+
+This is just a simple matter of filling out a 'beziersegment' structure:
+*/
+
+struct beziersegment *Bezier(B, C, D)
+ register struct segment *B; /* second control point */
+ register struct segment *C; /* third control point */
+ register struct segment *D; /* fourth control point (ending point) */
+{
+/* added reference field of 1 to temporary template below 3-26-91 PNM */
+ static struct beziersegment template =
+ { BEZIERTYPE, 0, 1, sizeof(struct beziersegment), 0,
+ NULL, NULL, { 0, 0 }, { 0, 0 }, { 0, 0 } };
+
+ register struct beziersegment *r; /* output segment */
+
+ IfTrace3((MustTraceCalls),"..Bezier(%z, %z, %z)\n", B, C, D);
+ ARGCHECK(!ISLOCATION(B), "Bezier: bad B", B, NULL, (2,C,D), struct beziersegment *);
+ ARGCHECK(!ISLOCATION(C), "Bezier: bad C", C, NULL, (2,B,D), struct beziersegment *);
+ ARGCHECK(!ISLOCATION(D), "Bezier: bad D", D, NULL, (2,B,C), struct beziersegment *);
+
+ r = (struct beziersegment *)Allocate(sizeof(struct beziersegment), &template, 0);
+ r->last = (struct segment *) r;
+ r->dest.x = D->dest.x;
+ r->dest.y = D->dest.y;
+ r->B.x = B->dest.x;
+ r->B.y = B->dest.y;
+ r->C.x = C->dest.x;
+ r->C.y = C->dest.y;
+
+ ConsumePath(B);
+ ConsumePath(C);
+ ConsumePath(D);
+ return(r);
+}
+
+/*
+:h2.Font "Hint" Segments
+
+:h3.Hint() - A Font 'Hint' Segment
+
+This is temporary code while we experiment with hints.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+struct hintsegment *Hint(S, ref, width, orientation, hinttype, adjusttype, direction, label)
+ struct XYspace *S;
+ float ref;
+ float width;
+ char orientation;
+ char hinttype;
+ char adjusttype;
+ char direction;
+ int label;
+{
+/* added reference field of 1 to hintsegment template below 3-26-91 PNM */
+ static struct hintsegment template = { HINTTYPE, 0, 1, sizeof(struct hintsegment), 0,
+ NULL, NULL, { 0, 0 }, { 0, 0 }, { 0, 0 },
+ ' ', ' ', ' ', ' ', 0};
+
+ register struct hintsegment *r;
+
+ r = (struct hintsegment *)Allocate(sizeof(struct hintsegment), &template, 0);
+
+ r->orientation = orientation;
+ if (width == 0.0) width = 1.0;
+
+ if (orientation == 'h') {
+ (*S->convert)(&r->ref, S, 0.0, ref);
+ (*S->convert)(&r->width, S, 0.0, width);
+ }
+ else if (orientation == 'v') {
+ (*S->convert)(&r->ref, S, ref, 0.0);
+ (*S->convert)(&r->width, S, width, 0.0);
+ }
+ else
+ return((struct hintsegment *)ArgErr("Hint: orient not 'h' or 'v'", NULL, NULL));
+ if (r->width.x < 0) r->width.x = - r->width.x;
+ if (r->width.y < 0) r->width.y = - r->width.y;
+ r->hinttype = hinttype;
+ r->adjusttype = adjusttype;
+ r->direction = direction;
+ r->label = label;
+ r->last = (struct segment *) r;
+ ConsumeSpace(S);
+ return(r);
+}
+
+/*
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+POP removes the first segment in a path 'p' and Frees it. 'p' is left
+pointing to the end of the path:
+*/
+#define POP(p) \
+ { register struct segment *linkp; \
+ linkp = p->link; \
+ if (linkp != NULL) \
+ linkp->last = p->last; \
+ Free(p); \
+ p = linkp; }
+/*
+INSERT inserts a single segment in the middle of a chain. 'b' is
+the segment before, 'p' the segment to be inserted, and 'a' the
+segment after.
+*/
+#define INSERT(b,p,a) b->link=p; p->link=a; p->last=NULL
+
+/*
+:h3.Join() - Join Two Objects Together
+
+If these are paths, this operator simply invokes the CONCAT macro.
+Why so much code then, you ask? Well we have to check for object
+types other than paths, and also check for certain path consistency
+rules.
+*/
+
+struct segment *Join(p1, p2)
+ register struct segment *p1,*p2;
+{
+ IfTrace2((MustTraceCalls && PathDebug > 1),"..Join(%z, %z)\n", p1, p2);
+ IfTrace2((MustTraceCalls && PathDebug <=1),"..Join(%x, %x)\n", p1, p2);
+/*
+We start with a whole bunch of very straightforward argument tests:
+*/
+ if (p2 != NULL) {
+ if (!ISPATHTYPE(p2->type)) {
+
+ if (p1 == NULL)
+ return((struct segment *)Unique(p2));
+
+ switch (p1->type) {
+
+ case REGIONTYPE:
+
+ case STROKEPATHTYPE:
+ p1 = CoercePath(p1);
+ break;
+
+ default:
+ return((struct segment *)BegHandle(p1, p2));
+ }
+ }
+
+ ARGCHECK((p2->last == NULL), "Join: right arg not anchor", p2, NULL, (1,p1), struct segment *);
+ p2 = UniquePath(p2);
+
+/*
+In certain circumstances, we don't have to duplicate a permanent
+location. (We would just end up destroying it anyway). These cases
+are when 'p2' begins with a move-type segment:
+*/
+ if (p2->type == TEXTTYPE || p2->type == MOVETYPE) {
+ if (p1 == NULL)
+ return(p2);
+ if (ISLOCATION(p1)) {
+ p2->dest.x += p1->dest.x;
+ p2->dest.y += p1->dest.y;
+ ConsumePath(p1);
+ return(p2);
+ }
+ }
+ }
+ else
+ return((struct segment *)Unique(p1));
+
+ if (p1 != NULL) {
+ if (!ISPATHTYPE(p1->type))
+
+ switch (p2->type) {
+
+ case REGIONTYPE:
+
+ case STROKEPATHTYPE:
+ p2 = CoercePath(p2);
+ break;
+
+ default:
+ return((struct segment *)EndHandle(p1, p2));
+ }
+
+ ARGCHECK((p1->last == NULL), "Join: left arg not anchor", p1, NULL, (1,p2), struct segment *);
+ p1 = UniquePath(p1);
+ }
+ else
+ return(p2);
+
+/*
+At this point all the checking is done. We have two temporary non-null
+path types in 'p1' and 'p2'. If p1 ends with a MOVE, and p2 begins with
+a MOVE, we collapse the two MOVEs into one. We enforce the rule that
+there may not be two MOVEs in a row:
+*/
+
+ if (p1->last->type == MOVETYPE && p2->type == MOVETYPE) {
+ p1->last->flag |= p2->flag;
+ p1->last->dest.x += p2->dest.x;
+ p1->last->dest.y += p2->dest.y;
+ POP(p2);
+ if (p2 == NULL)
+ return(p1);
+ }
+/*
+Now we check for another silly rule. If a path has any TEXTTYPEs,
+then it must have only TEXTTYPEs and MOVETYPEs, and furthermore,
+it must begin with a TEXTTYPE. This rule makes it easy to check
+for the special case of text. If necessary, we will coerce
+TEXTTYPEs into paths so we don't mix TEXTTYPEs with normal paths.
+*/
+ if (p1->type == TEXTTYPE) {
+ if (p2->type != TEXTTYPE && !ISLOCATION(p2))
+ p1 = CoerceText(p1);
+ }
+ else {
+ if (p2->type == TEXTTYPE) {
+ if (ISLOCATION(p1)) {
+ p2->dest.x += p1->dest.x;
+ p2->dest.y += p1->dest.y;
+ Free(p1);
+ return(p2);
+ }
+ else
+ p2 = CoerceText(p2);
+ }
+ }
+/*
+Thank God! Finally! It's hard to believe, but we are now able to
+actually do the join. This is just invoking the CONCAT macro:
+*/
+ CONCAT(p1, p2);
+
+ return(p1);
+}
+
+/*
+:h3.JoinSegment() - Create a Path Segment and Join It to a Known Path
+
+This internal function is quicker than a full-fledged join because
+it can do much less checking.
+*/
+
+struct segment *t1_JoinSegment(before, type, x, y, after)
+ register struct segment *before; /* path to join before new segment */
+ int type; /* type of new segment (MOVETYPE or LINETYPE) */
+ fractpel x,y; /* x,y of new segment */
+ register struct segment *after; /* path to join after new segment */
+{
+ register struct segment *r; /* returned path built here */
+
+ r = PathSegment(type, x, y);
+ if (before != NULL) {
+ CONCAT(before, r);
+ r = before;
+ }
+ else
+ r->context = after->context;
+ if (after != NULL)
+ CONCAT(r, after);
+ return(r);
+}
+
+/*
+:h2.Other Path Functions
+
+*/
+
+
+struct segment *t1_ClosePath(p0,lastonly)
+ register struct segment *p0; /* path to close */
+ register int lastonly; /* flag deciding to close all subpaths or... */
+{
+ register struct segment *p,*last,*start; /* used in looping through path */
+ register fractpel x,y; /* current position in path */
+ register fractpel firstx,firsty; /* start position of sub path */
+ register struct segment *lastnonhint; /* last non-hint segment in path */
+
+ IfTrace1((MustTraceCalls),"ClosePath(%z)\n", p0);
+ if (p0 != NULL && p0->type == TEXTTYPE)
+ return(UniquePath(p0));
+ if (p0->type == STROKEPATHTYPE)
+ return((struct segment *)Unique(p0));
+ /*
+ * NOTE: a null closed path is different from a null open path
+ * and is denoted by a closed (0,0) move segment. We make
+ * sure this path begins and ends with a MOVETYPE:
+ */
+ if (p0 == NULL || p0->type != MOVETYPE)
+ p0 = JoinSegment(NULL, MOVETYPE, 0, 0, p0);
+ TYPECHECK("ClosePath", p0, MOVETYPE, NULL, (0), struct segment *);
+ if (p0->last->type != MOVETYPE)
+ p0 = JoinSegment(p0, MOVETYPE, 0, 0, NULL);
+
+ p0 = UniquePath(p0);
+
+/*
+We now begin a loop through the path,
+incrementing current 'x' and 'y'. We are searching
+for MOVETYPE segments (breaks in the path) that are not already closed.
+At each break, we insert a close segment.
+*/
+ for (p = p0, x = y = 0, start = NULL;
+ p != NULL;
+ x += p->dest.x, y += p->dest.y, last = p, p = p->link)
+ {
+
+ if (p->type == MOVETYPE) {
+ if (start != NULL && (lastonly?p->link==NULL:TRUE) &&
+ !(ISCLOSED(start->flag) && LASTCLOSED(last->flag))) {
+ register struct segment *r; /* newly created */
+
+ start->flag |= ISCLOSED(ON);
+ r = PathSegment(LINETYPE, firstx - x,
+ firsty - y);
+ INSERT(last, r, p);
+ r->flag |= LASTCLOSED(ON);
+ /*< adjust 'last' if possible for a 0,0 close >*/
+{
+
+#define CLOSEFUDGE 3 /* if we are this close, let's change last segment */
+
+ if (r->dest.x != 0 || r->dest.y != 0) {
+ if (r->dest.x <= CLOSEFUDGE && r->dest.x >= -CLOSEFUDGE
+ && r->dest.y <= CLOSEFUDGE && r->dest.y >= -CLOSEFUDGE) {
+ IfTrace2((PathDebug),
+ "ClosePath forced closed by (%p,%p)\n",
+ r->dest.x, r->dest.y);
+ lastnonhint->dest.x += r->dest.x;
+ lastnonhint->dest.y += r->dest.y;
+ r->dest.x = r->dest.y = 0;
+ }
+ }
+}
+ if (p->link != NULL) {
+ p->dest.x += x - firstx;
+ p->dest.y += y - firsty;
+ x = firstx;
+ y = firsty;
+ }
+ }
+ start = p;
+ firstx = x + p->dest.x;
+ firsty = y + p->dest.y;
+ }
+ else if (p->type != HINTTYPE)
+ lastnonhint = p;
+ }
+ return(p0);
+}
+/*
+*/
+/*
+:h2.Reversing the Direction of a Path
+
+This turned out to be more difficult than I thought at first. The
+trickiness was due to the fact that closed paths must remain closed,
+etc.
+
+We need three subroutines:
+*/
+
+static struct segment *SplitPath(); /* break a path at any point */
+static struct segment *DropSubPath(); /* breaks a path after first sub-path */
+static struct segment *ReverseSubPath(); /* reverses a single sub-path */
+
+/*
+:h3.Reverse() - User Operator to Reverse a Path
+
+This operator reverses the entire path.
+*/
+
+struct segment *Reverse(p)
+ register struct segment *p; /* full path to reverse */
+{
+ register struct segment *r; /* output path built here */
+ register struct segment *nextp; /* contains next sub-path */
+
+ IfTrace1((MustTraceCalls),"Reverse(%z)\n", p);
+
+ if (p == NULL)
+ return(NULL);
+
+ ARGCHECK(!ISPATHANCHOR(p), "Reverse: invalid path", p, NULL, (0), struct segment *);
+
+ if (p->type == TEXTTYPE)
+ p = CoerceText(p);
+ p = UniquePath(p);
+
+ r = NULL;
+
+ do {
+ nextp = DropSubPath(p);
+ p = ReverseSubPath(p);
+ r = Join(p, r);
+ p = nextp;
+
+ } while (p != NULL);
+
+ return(r);
+}
+
+/*
+:h4.ReverseSubPath() - Subroutine to Reverse a Single Sub-Path
+*/
+
+static struct segment *ReverseSubPath(p)
+ register struct segment *p; /* input path */
+{
+ register struct segment *r; /* reversed path will be created here */
+ register struct segment *nextp; /* temporary variable used in loop */
+ register int wasclosed; /* flag, path was closed */
+
+ if (p == NULL)
+ return(NULL);
+
+ wasclosed = ISCLOSED(p->flag);
+ r = NULL;
+
+ do {
+/*
+First we reverse the direction of this segment and clean up its flags:
+*/
+ p->dest.x = - p->dest.x; p->dest.y = - p->dest.y;
+ p->flag &= ~(ISCLOSED(ON) | LASTCLOSED(ON));
+
+ switch (p->type) {
+
+ case LINETYPE:
+ case MOVETYPE:
+ break;
+
+ case CONICTYPE:
+ {
+/*
+The logic of this is that the new M point (stored relative to the new
+beginning) is (M - C). However, C ("dest") has already been reversed
+So, we add "dest" instead of subtracting it:
+*/
+ register struct conicsegment *cp = (struct conicsegment *) p;
+
+ cp->M.x += cp->dest.x; cp->M.y += cp->dest.y;
+ }
+ break;
+
+ case BEZIERTYPE:
+ {
+ register struct beziersegment *bp = (struct beziersegment *) p;
+
+ bp->B.x += bp->dest.x; bp->B.y += bp->dest.y;
+ bp->C.x += bp->dest.x; bp->C.y += bp->dest.y;
+ }
+ break;
+
+ case HINTTYPE:
+ {
+ register struct hintsegment *hp = (struct hintsegment *) p;
+
+ hp->ref.x = -hp->ref.x; hp->ref.y = -hp->ref.y;
+ }
+ break;
+
+ default:
+ abort("Reverse: bad path segment");
+ }
+/*
+We need to reverse the order of segments too, so we break this segment
+off of the input path, and tack it on the front of the growing path
+in 'r':
+*/
+ nextp = p->link;
+ p->link = NULL;
+ p->last = p;
+ if (r != NULL)
+ CONCAT(p,r); /* leaves result in 'p'... not what we want */
+ r = p;
+ p = nextp; /* advance to next segment in input path */
+
+ } while (p != NULL);
+
+ if (wasclosed)
+ r = ClosePath(r);
+
+ return(r);
+}
+
+/*
+:h4.DropSubPath() - Drops the First Sub-Path Off a Path
+
+This subroutine returns the remaining sub-path(s). While doing so, it
+breaks the input path after the first sub-path so that a pointer to
+the original path now contains the first sub-path only.
+*/
+
+static struct segment *DropSubPath(p0)
+ register struct segment *p0; /* original path */
+{
+ register struct segment *p; /* returned remainder here */
+
+ for (p = p0; p->link != NULL; p = p->link) {
+ if (p->link->type == MOVETYPE)
+ break;
+ }
+
+ return(SplitPath(p0, p));
+}
+
+static struct segment *SplitPath(anchor, before)
+ register struct segment *anchor;
+ register struct segment *before;
+{
+ register struct segment *r;
+
+ if (before == anchor->last)
+ return(NULL);
+
+ r = before->link;
+ r->last = anchor->last;
+ anchor->last = before;
+ before->link = NULL;
+
+ return(r);
+}
+
+static void
+UnClose(p0)
+ register struct segment *p0;
+{
+ register struct segment *p;
+
+ for (p=p0; p->link->link != NULL; p=p->link) { ; }
+
+ if (!LASTCLOSED(p->link->flag))
+ abort("UnClose: no LASTCLOSED");
+
+ Free(SplitPath(p0, p));
+ p0->flag &= ~ISCLOSED(ON);
+}
+
+/*
+:h3.ReverseSubPaths() - Reverse the Direction of Sub-paths Within a Path
+
+This user operator reverses the sub-paths in a path, but leaves the
+'move' segments unchanged. It builds on top of the subroutines
+already established.
+*/
+
+struct segment *ReverseSubPaths(p)
+ register struct segment *p; /* input path */
+{
+ register struct segment *r; /* reversed path will be created here */
+ register struct segment *nextp; /* temporary variable used in loop */
+ int wasclosed; /* flag; subpath was closed */
+ register struct segment *nomove; /* the part of sub-path without move segment */
+ struct fractpoint delta;
+
+ IfTrace1((MustTraceCalls),"ReverseSubPaths(%z)\n", p);
+
+ if (p == NULL)
+ return(NULL);
+
+ ARGCHECK(!ISPATHANCHOR(p), "ReverseSubPaths: invalid path", p, NULL, (0), struct segment *);
+
+ if (p->type == TEXTTYPE)
+ p = CoerceText(p);
+ if (p->type != MOVETYPE)
+ p = JoinSegment(NULL, MOVETYPE, 0, 0, p);
+
+ p = UniquePath(p);
+
+ r = NULL;
+
+ for (; p != NULL;) {
+ nextp = DropSubPath(p);
+ wasclosed = ISCLOSED(p->flag);
+ if (wasclosed)
+ UnClose(p);
+
+ nomove = SplitPath(p, p);
+ r = Join(r, p);
+
+ PathDelta(nomove, &delta);
+
+ nomove = ReverseSubPath(nomove);
+ p->dest.x += delta.x;
+ p->dest.y += delta.y;
+ if (nextp != NULL) {
+ nextp->dest.x += delta.x;
+ nextp->dest.y += delta.y;
+ }
+ if (wasclosed) {
+ nomove = ClosePath(nomove);
+ nextp->dest.x -= delta.x;
+ nextp->dest.y -= delta.y;
+ }
+ r = Join(r, nomove);
+ p = nextp;
+
+ }
+
+ return(r);
+}
+
+/*
+:h2.Transforming and Putting Handles on Paths
+
+:h3.PathTransform() - Transform a Path
+
+Transforming a path involves transforming all the points. In order
+that closed paths do not become "unclosed" when their relative
+positions are slightly changed due to loss of arithmetic precision,
+all point transformations are in absolute coordinates.
+
+(It might be better to reset the "absolute" coordinates every time a
+move segment is encountered. This would mean that we could accumulate
+error from subpath to subpath, but we would be less likely to make
+the "big error" where our fixed point arithmetic "wraps". However, I
+think I'll keep it this way until something happens to convince me
+otherwise.)
+
+The transform is described as a "space", that way we can use our
+old friend the "iconvert" function, which should be very efficient.
+*/
+
+struct segment *PathTransform(p0, S)
+ register struct segment *p0; /* path to transform */
+ register struct XYspace *S; /* pseudo space to transform in */
+{
+ register struct segment *p; /* to loop through path with */
+ register fractpel newx,newy; /* current transformed position in path */
+ register fractpel oldx,oldy; /* current untransformed position in path */
+ register fractpel savex,savey; /* save path delta x,y */
+
+ p0 = UniquePath(p0);
+
+ newx = newy = oldx = oldy = 0;
+
+ for (p=p0; p != NULL; p=p->link) {
+
+ savex = p->dest.x; savey = p->dest.y;
+
+ (*S->iconvert)(&p->dest, S, p->dest.x + oldx, p->dest.y + oldy);
+ p->dest.x -= newx;
+ p->dest.y -= newy;
+
+ switch (p->type) {
+
+ case LINETYPE:
+ case MOVETYPE:
+ break;
+
+ case CONICTYPE:
+ {
+ register struct conicsegment *cp = (struct conicsegment *) p;
+
+ (*S->iconvert)(&cp->M, S, cp->M.x + oldx, cp->M.y + oldy);
+ cp->M.x -= newx;
+ cp->M.y -= newy;
+ /*
+ * Note roundness doesn't change... linear transform
+ */
+ break;
+ }
+
+
+ case BEZIERTYPE:
+ {
+ register struct beziersegment *bp = (struct beziersegment *) p;
+
+ (*S->iconvert)(&bp->B, S, bp->B.x + oldx, bp->B.y + oldy);
+ bp->B.x -= newx;
+ bp->B.y -= newy;
+ (*S->iconvert)(&bp->C, S, bp->C.x + oldx, bp->C.y + oldy);
+ bp->C.x -= newx;
+ bp->C.y -= newy;
+ break;
+ }
+
+ case HINTTYPE:
+ {
+ register struct hintsegment *hp = (struct hintsegment *) p;
+
+ (*S->iconvert)(&hp->ref, S, hp->ref.x + oldx, hp->ref.y + oldy);
+ hp->ref.x -= newx;
+ hp->ref.y -= newy;
+ (*S->iconvert)(&hp->width, S, hp->width.x, hp->width.y);
+ /* Note: width is not relative to origin */
+ break;
+ }
+
+ case TEXTTYPE:
+ {
+ XformText(p,S);
+ break;
+ }
+
+ default:
+ IfTrace1(TRUE,"path = %z\n", p);
+ abort("PathTransform: invalid segment");
+ }
+ oldx += savex;
+ oldy += savey;
+ newx += p->dest.x;
+ newy += p->dest.y;
+ }
+ return(p0);
+}
+
+/*
+:h3.PathDelta() - Return a Path's Ending Point
+*/
+
+void PathDelta(p, pt)
+ register struct segment *p; /* input path */
+ register struct fractpoint *pt; /* pointer to x,y to set */
+{
+ struct fractpoint mypoint; /* I pass this to TextDelta */
+ register fractpel x,y; /* working variables for path current point */
+
+ for (x=y=0; p != NULL; p=p->link) {
+ x += p->dest.x;
+ y += p->dest.y;
+ if (p->type == TEXTTYPE) {
+ TextDelta(p, &mypoint);
+ x += mypoint.x;
+ y += mypoint.y;
+ }
+ }
+
+ pt->x = x;
+ pt->y = y;
+}
+
+/*
+:h3.BoundingBox() - Produce a Bounding Box Path
+
+This function is called by image code, when we know the size of the
+image in pels, and need to get a bounding box path that surrounds it.
+The starting/ending handle is in the lower right hand corner.
+*/
+struct segment *BoundingBox(h, w)
+ register pel h,w; /* size of box */
+{
+ register struct segment *path;
+
+ path = PathSegment(LINETYPE, -TOFRACTPEL(w), 0);
+ path = JoinSegment(NULL, LINETYPE, 0, -TOFRACTPEL(h), path);
+ path = JoinSegment(NULL, LINETYPE, TOFRACTPEL(w), 0, path);
+ path = ClosePath(path);
+
+ return(path);
+}
+
+/*
+:h2.Querying Locations and Paths
+
+:h3.QueryLoc() - Return the X,Y of a Locition
+*/
+
+void QueryLoc(P, S, xP, yP)
+ register struct segment *P; /* location to query, not consumed */
+ register struct XYspace *S; /* XY space to return coordinates in */
+ register double *xP,*yP; /* coordinates returned here */
+{
+ IfTrace4((MustTraceCalls),"QueryLoc(P=%z, S=%z, (%x, %x))\n",
+ P, S, xP, yP);
+ if (!ISLOCATION(P)) {
+ ArgErr("QueryLoc: first arg not a location", P, NULL);
+ return;
+ }
+ if (S->type != SPACETYPE) {
+ ArgErr("QueryLoc: second arg not a space", S, NULL);
+ return;
+ }
+ UnConvert(S, &P->dest, xP, yP);
+}
+/*
+:h3.QueryPath() - Find Out the Type of Segment at the Head of a Path
+
+This is a very simple routine that looks at the first segment of a
+path and tells the caller what it is, as well as returning the control
+point(s) of the path segment. Different path segments have different
+number of control points. If the caller knows that the segment is
+a move segment, for example, he only needs to pass pointers to return
+one control point.
+*/
+
+void QueryPath(path, typeP, Bp, Cp, Dp, fP)
+ register struct segment *path; /* path to check */
+ register int *typeP; /* return the type of path here */
+ register struct segment **Bp; /* return location of first point */
+ register struct segment **Cp; /* return location of second point */
+ register struct segment **Dp; /* return location of third point */
+ register double *fP; /* return Conic sharpness */
+{
+ register int coerced = FALSE; /* did I coerce a text path? */
+
+ IfTrace3((MustTraceCalls), "QueryPath(%z, %x, %x, ...)\n",
+ path, typeP, Bp);
+ if (path == NULL) {
+ *typeP = -1;
+ return;
+ }
+ if (!ISPATHANCHOR(path)) {
+ ArgErr("QueryPath: arg not a valid path", path, NULL);
+ }
+ if (path->type == TEXTTYPE) {
+ path = CoerceText(path);
+ coerced = TRUE;
+ }
+
+ switch (path->type) {
+
+ case MOVETYPE:
+ *typeP = 0;
+ *Bp = PathSegment(MOVETYPE, path->dest.x, path->dest.y);
+ break;
+
+ case LINETYPE:
+ *typeP = (LASTCLOSED(path->flag)) ? 4 : 1;
+ *Bp = PathSegment(MOVETYPE, path->dest.x, path->dest.y);
+ break;
+
+ case CONICTYPE:
+ {
+ register struct conicsegment *cp = (struct conicsegment *) path;
+
+ *typeP = 2;
+ *Bp = PathSegment(MOVETYPE, cp->M.x, cp->M.y);
+ *Cp = PathSegment(MOVETYPE, cp->dest.x, cp->dest.y);
+ *fP = cp->roundness;
+ }
+ break;
+
+ case BEZIERTYPE:
+ {
+ register struct beziersegment *bp = (struct beziersegment *) path;
+
+ *typeP = 3;
+ *Bp = PathSegment(MOVETYPE, bp->B.x, bp->B.y);
+ *Cp = PathSegment(MOVETYPE, bp->C.x, bp->C.y);
+ *Dp = PathSegment(MOVETYPE, bp->dest.x, bp->dest.y);
+ }
+ break;
+
+ case HINTTYPE:
+ *typeP = 5;
+ break;
+
+ default:
+ abort("QueryPath: unknown segment");
+ }
+ if (coerced)
+ KillPath(path);
+}
+/*
+:h3.QueryBounds() - Return the Bounding Box of a Path
+
+Returns the bounding box by setting the user's variables.
+*/
+
+void QueryBounds(p0, S, xminP, yminP, xmaxP, ymaxP)
+ register struct segment *p0; /* object to check for bound */
+ struct XYspace *S; /* coordinate space of returned values */
+ double *xminP,*yminP; /* lower left hand corner (set by routine) */
+ double *xmaxP,*ymaxP; /* upper right hand corner (set by routine) */
+{
+ register struct segment *path; /* loop variable for path segments */
+ register fractpel lastx,lasty; /* loop variables: previous endingpoint */
+ register fractpel x,y; /* loop variables: current ending point */
+ struct fractpoint min; /* registers to keep lower left hand corner */
+ struct fractpoint max; /* registers to keep upper right hand corner */
+ int coerced = FALSE; /* we have coerced the path from another object */
+ double x1,y1,x2,y2,x3,y3,x4,y4; /* corners of rectangle in space X */
+
+ IfTrace2((MustTraceCalls), "QueryBounds(%z, %z,", p0, S);
+ IfTrace4((MustTraceCalls), " %x, %x, %x, %x)\n",
+ xminP, yminP, xmaxP, ymaxP);
+ if (S->type != SPACETYPE) {
+ ArgErr("QueryBounds: bad XYspace", S, NULL);
+ return;
+ }
+
+ min.x = min.y = max.x = max.y = 0;
+ if (p0 != NULL) {
+ if (!ISPATHANCHOR(p0)) {
+ switch(p0->type) {
+ case STROKEPATHTYPE:
+ /* replaced DupStrokePath() with Dup() 3-26-91 PNM */
+ p0 = (struct segment *) DoStroke(Dup(p0));
+ /* no break here, we have a region in p0 */
+ case REGIONTYPE:
+ p0 = RegionBounds(p0);
+ break;
+
+ case PICTURETYPE:
+ p0 = PictureBounds(p0);
+ break;
+
+ default:
+ ArgErr("QueryBounds: bad object", p0, NULL);
+ return;
+ }
+ coerced = TRUE;
+ }
+ if (p0->type == TEXTTYPE) {
+ /* replaced CopyPath() with Dup() 3-26-91 PNM */
+ p0 = (struct segment *)CoerceText(Dup(p0)); /* there are faster ways */
+ coerced = TRUE;
+ }
+ if (p0->type == MOVETYPE) {
+ min.x = max.x = p0->dest.x;
+ min.y = max.y = p0->dest.y;
+ }
+ }
+ lastx = lasty = 0;
+
+ for (path = p0; path != NULL; path = path->link) {
+
+ x = lastx + path->dest.x;
+ y = lasty + path->dest.y;
+
+ switch (path->type) {
+
+ case LINETYPE:
+ break;
+
+ case CONICTYPE:
+ {
+ register struct conicsegment *cp = (struct conicsegment *) path;
+ register fractpel Mx = lastx + cp->M.x;
+ register fractpel My = lasty + cp->M.y;
+ register fractpel deltax = 0.5 * cp->roundness * cp->dest.x;
+ register fractpel deltay = 0.5 * cp->roundness * cp->dest.y;
+ register fractpel Px = Mx - deltax;
+ register fractpel Py = My - deltay;
+ register fractpel Qx = Mx + deltax;
+ register fractpel Qy = My + deltay;
+
+
+ if (Mx < min.x) min.x = Mx;
+ else if (Mx > max.x) max.x = Mx;
+ if (My < min.y) min.y = My;
+ else if (My > max.y) max.y = My;
+
+ if (Px < min.x) min.x = Px;
+ else if (Px > max.x) max.x = Px;
+ if (Py < min.y) min.y = Py;
+ else if (Py > max.y) max.y = Py;
+
+ if (Qx < min.x) min.x = Qx;
+ else if (Qx > max.x) max.x = Qx;
+ if (Qy < min.y) min.y = Qy;
+ else if (Qy > max.y) max.y = Qy;
+ }
+ break;
+
+
+ case MOVETYPE:
+ /*
+ * We can't risk adding trailing Moves to the
+ * bounding box:
+ */
+ if (path->link == NULL)
+ goto done; /* God forgive me */
+ break;
+
+ case BEZIERTYPE:
+ {
+ register struct beziersegment *bp = (struct beziersegment *) path;
+ register fractpel Bx = lastx + bp->B.x;
+ register fractpel By = lasty + bp->B.y;
+ register fractpel Cx = lastx + bp->C.x;
+ register fractpel Cy = lasty + bp->C.y;
+
+ if (Bx < min.x) min.x = Bx;
+ else if (Bx > max.x) max.x = Bx;
+ if (By < min.y) min.y = By;
+ else if (By > max.y) max.y = By;
+
+ if (Cx < min.x) min.x = Cx;
+ else if (Cx > max.x) max.x = Cx;
+ if (Cy < min.y) min.y = Cy;
+ else if (Cy > max.y) max.y = Cy;
+ }
+ break;
+
+ case HINTTYPE:
+ break;
+ default:
+ abort("QueryBounds: unknown type");
+ }
+
+ if (x < min.x) min.x = x;
+ else if (x > max.x) max.x = x;
+ if (y < min.y) min.y = y;
+ else if (y > max.y) max.y = y;
+
+ lastx = x; lasty = y;
+ }
+done:
+ UnConvert(S, &min, &x1, &y1);
+ UnConvert(S, &max, &x4, &y4);
+ x = min.x; min.x = max.x; max.x = x;
+ UnConvert(S, &min, &x2, &y2);
+ UnConvert(S, &max, &x3, &y3);
+
+ *xminP = *xmaxP = x1;
+ if (x2 < *xminP) *xminP = x2;
+ else if (x2 > *xmaxP) *xmaxP = x2;
+ if (x3 < *xminP) *xminP = x3;
+ else if (x3 > *xmaxP) *xmaxP = x3;
+ if (x4 < *xminP) *xminP = x4;
+ else if (x4 > *xmaxP) *xmaxP = x4;
+
+ *yminP = *ymaxP = y1;
+ if (y2 < *yminP) *yminP = y2;
+ else if (y2 > *ymaxP) *ymaxP = y2;
+ if (y3 < *yminP) *yminP = y3;
+ else if (y3 > *ymaxP) *ymaxP = y3;
+ if (y4 < *yminP) *yminP = y4;
+ else if (y4 > *ymaxP) *ymaxP = y4;
+
+ if (coerced)
+ Destroy(p0);
+}
+/*
+:h3.BoxPath()
+*/
+struct segment *BoxPath(S, h, w)
+ struct XYspace *S;
+ int h,w;
+{
+ struct segment *path;
+
+ path = Join( Line(ILoc(S, w, 0)), Line(ILoc(S, 0, h)) );
+ path = JoinSegment(path, LINETYPE, -path->dest.x, -path->dest.y, NULL);
+ return(ClosePath(path));
+}
+
+/*
+:h3.DropSegment() - Drop the First Segment in a Path
+
+This routine takes the path and returns a new path that is one segment
+shorter. It can be used in conjunction with QueryPath(), for example,
+to ask about an entire path.
+*/
+
+struct segment *DropSegment(path)
+ register struct segment *path;
+{
+ IfTrace1((MustTraceCalls),"DropSegment(%z)\n", path);
+ if (path != NULL && path->type == STROKEPATHTYPE)
+ path = CoercePath(path);
+ ARGCHECK((path == NULL || !ISPATHANCHOR(path)),
+ "DropSegment: arg not a non-null path", path, path, (0), struct segment *);
+ if (path->type == TEXTTYPE)
+ path = CoerceText(path);
+ path = UniquePath(path);
+
+ POP(path);
+ return(path);
+}
+/*
+:h3.HeadSegment() - Return the First Segment in a Path
+
+This routine takes the path and returns a new path consists of the
+first segment only.
+*/
+
+struct segment *HeadSegment(path)
+ register struct segment *path; /* input path */
+{
+ IfTrace1((MustTraceCalls),"HeadSegment(%z)\n", path);
+ if (path == NULL)
+ return(NULL);
+ if (path->type == STROKEPATHTYPE)
+ path = CoercePath(path);
+ ARGCHECK(!ISPATHANCHOR(path), "HeadSegment: arg not a path", path, path, (0), struct segment *);
+ if (path->type == TEXTTYPE)
+ path = CoerceText(path);
+ path = UniquePath(path);
+
+ if (path->link != NULL)
+ KillPath(path->link);
+ path->link = NULL;
+ path->last = path;
+ return(path);
+}
+
+/*
+:h2.Path Debug Routines
+
+:h3.DumpPath() - Display a Path on the Trace File
+*/
+
+void DumpPath(p)
+ register struct segment *p;
+{
+ register fractpel x,y;
+ register fractpel lastx,lasty;
+ double roundness;
+
+ IfTrace1(TRUE,"Dumping path, anchor=%x:\n", p);
+ lastx = lasty = 0;
+
+ for (;p != NULL; p=p->link) {
+
+ IfTrace0(TRUE,". ");
+ x = p->dest.x;
+ y = p->dest.y;
+ switch (p->type) {
+
+ case LINETYPE:
+ IfTrace1(TRUE,". line<%x> to", (long) p->flag);
+ IfTrace4(TRUE," (%p,%p), delta=(%p,%p)",
+ x + lastx, y + lasty, x, y);
+ break;
+
+ case MOVETYPE:
+ IfTrace1(TRUE,"MOVE<%x> to", (long) p->flag);
+ IfTrace4(TRUE,"(%p,%p), delta=(%p,%p)",
+ x + lastx, y + lasty, x, y);
+ break;
+
+ case CONICTYPE:
+ {
+ register struct conicsegment *cp = (struct conicsegment *) p;
+
+ roundness = cp->roundness;
+ IfTrace2(TRUE, ". conic to (%p,%p),",
+ x + lastx, y + lasty);
+ IfTrace3(TRUE," M=(%p,%p), r=%f", cp->M.x + lastx,
+ cp->M.y + lasty, &roundness);
+ }
+ break;
+
+ case BEZIERTYPE:
+ {
+ register struct beziersegment *bp = (struct beziersegment *) p;
+
+ IfTrace4(TRUE,". bezier to (%p,%p), B=(%p,%p)",
+ x + lastx, y + lasty,
+ bp->B.x + lastx, bp->B.y + lasty);
+ IfTrace2(TRUE, ", C=(%p,%p)",
+ bp->C.x + lastx, bp->C.y + lasty);
+ }
+ break;
+
+ case HINTTYPE:
+ {
+ register struct hintsegment *hp = (struct hintsegment *) p;
+
+ IfTrace4(TRUE,". hint ref=(%p,%p), width=(%p,%p)",
+ hp->ref.x + lastx, hp->ref.y + lasty,
+ hp->width.x, hp->width.y);
+ IfTrace4(TRUE, ", %c %c %c %c",
+ hp->orientation, hp->hinttype,
+ hp->adjusttype, hp->direction);
+ IfTrace1(TRUE, ", %ld", (long) hp->label);
+ }
+ break;
+
+ case TEXTTYPE:
+ DumpText(p);
+ break;
+
+ default:
+ IfTrace0(TRUE, "bad path segment?");
+ }
+ IfTrace1(TRUE," at %x\n", p);
+ lastx += x;
+ lasty += y;
+ }
+}
+
+
diff --git a/src/Type1/paths.h b/src/Type1/paths.h
new file mode 100644
index 0000000..e52a760
--- /dev/null
+++ b/src/Type1/paths.h
@@ -0,0 +1,197 @@
+/* $Xorg: paths.h,v 1.3 2000/08/17 19:46:31 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+/*SHARED*/
+
+#define Loc(S,x,y) t1_Loc(S,(double)x,(double)y)
+#define ILoc(S,x,y) t1_ILoc(S,x,y)
+#define Line(P) t1_Line(P)
+#define Join(p1,p2) t1_Join(p1,p2)
+#define ClosePath(p) t1_ClosePath(p,0)
+#define CloseLastSubPath(p) t1_ClosePath(p,1)
+#define Conic(B,C,s) t1_Conic(B,C,(double)s)
+#define RoundConic(M,C,r) t1_RoundConic(M,C,(double)r)
+#define ArcP3(S,P2,P3) t1_ArcP3(S,P2,P3)
+#define ArcCA(S,C,d) t1_ArcCA(S,C,(double)d)
+#define Bezier(B,C,D) t1_Bezier(B,C,D)
+#define Hint(S,r,w,o,h,a,d,l) t1_Hint(S,r,w,o,h,a,d,l)
+#define Reverse(p) t1_Reverse(p)
+#define ReverseSubPaths(p) t1_ReverseSubPaths(p)
+#define AddLoc(p1,p2) t1_Join(p1,p2)
+#define SubLoc(p1,p2) t1_SubLoc(p1,p2)
+#define DropSegment(p) t1_DropSegment(p)
+#define HeadSegment(p) t1_HeadSegment(p)
+#define QueryLoc(P,S,x,y) t1_QueryLoc(P,S,x,y)
+#define QueryPath(p,t,B,C,D,r) t1_QueryPath(p,t,B,C,D,r)
+#define QueryBounds(p,S,x1,y1,x2,y2) t1_QueryBounds(p,S,x1,y1,x2,y2)
+
+
+struct segment *t1_Loc(); /* create a location object (or "move" segment) */
+struct segment *t1_ILoc(); /* integer argument version of same */
+struct segment *t1_Line(); /* straight line path segment */
+struct segment *t1_Join(); /* join two paths or regions together */
+struct segment *t1_ClosePath(); /* close a path or path set */
+struct conicsegment *t1_Conic(); /* conic curve path segment */
+struct conicsegment *t1_RoundConic(); /* ditto, specified another way */
+struct conicsegment *t1_ArcP3(); /* circular path segment with three points */
+struct conicsegment *t1_ArcCA(); /* ditto, with center point and angle */
+struct beziersegment *t1_Bezier(); /* Bezier third order curve path segment */
+struct hintsegment *t1_Hint(); /* produce a font 'hint' path segment */
+struct segment *t1_Reverse(); /* reverse the complete order of paths */
+struct segment *t1_ReverseSubPaths(); /* reverse only sub-paths; moves unchanged */
+struct segment *t1_SubLoc(); /* subtract two location objects */
+struct segment *t1_DropSegment(); /* Drop the first segment in a path */
+struct segment *t1_HeadSegment(); /* return the first segment in a path */
+void t1_QueryLoc(); /* Query location; return its (x,y) */
+void t1_QueryPath(); /* Query segment at head of a path */
+void t1_QueryBounds(); /* Query the bounding box of a path */
+
+/*END SHARED*/
+/*SHARED*/
+
+#define CopyPath(p) t1_CopyPath(p)
+#define KillPath(p) t1_KillPath(p)
+#define PathTransform(p,m) t1_PathXform(p,m)
+#define PathDelta(p,pt) t1_PathDelta(p,pt)
+#define BoundingBox(h,w) t1_BoundingBox(h,w)
+#define PathSegment(t,x,y) t1_PathSegment(t,(fractpel)x,(fractpel)y)
+#define JoinSegment(b,t,x,y,a) t1_JoinSegment(b,t,(fractpel)x,(fractpel)y,a)
+#define Hypoteneuse(dx,dy) t1_Hypoteneuse(dx,dy)
+#define BoxPath(S,h,w) t1_BoxPath(S,h,w)
+
+struct segment *t1_CopyPath(); /* duplicate a path */
+void t1_KillPath(); /* destroy a path */
+struct segment *t1_PathXform(); /* transform a path arbitrarily */
+void t1_PathDelta(); /* calculate the ending point of a path */
+struct segment *t1_PathSegment(); /* produce a MOVE or LINE segment */
+struct segment *t1_JoinSegment(); /* join a MOVE or LINE segment to a path */
+double t1_Hypoteneuse(); /* returns the length of a line */
+struct segment *t1_BoxPath(); /* returns a rectangular path */
+
+/*END SHARED*/
+/*SHARED*/
+
+#define ConsumePath(p) MAKECONSUME(p,KillPath(p))
+#define UniquePath(p) MAKEUNIQUE(p,CopyPath(p))
+
+/*END SHARED*/
+/*SHARED*/
+
+struct segment {
+ XOBJ_COMMON /* xobject common data define 3-26-91 PNM */
+ unsigned char size; /* size of the structure */
+ unsigned char context; /* index to device context */
+ struct segment *link; /* pointer to next structure in linked list */
+ struct segment *last; /* pointer to last structure in list */
+ struct fractpoint dest; /* relative ending location of path segment */
+} ;
+
+#define ISCLOSED(flag) ((flag)&0x80) /* subpath is closed */
+#define LASTCLOSED(flag) ((flag)&0x40) /* last segment in closed subpath */
+
+/*
+NOTE: The ISCLOSED flag is set on the MOVETYPE segment before the
+subpath proper; the LASTCLOSED flag is set on the last segment (LINETYPE)
+in the subpath
+
+We define the ISPATHANCHOR predicate to test that a path handle
+passed by the user is valid:
+*/
+
+#define ISPATHANCHOR(p) (ISPATHTYPE(p->type)&&p->last!=NULL)
+
+/*
+For performance reasons, a user's "location" object is identical to
+a path whose only segment is a move segment. We define a predicate
+to test for this case. See also :hdref refid=location..
+*/
+
+#define ISLOCATION(p) ((p)->type == MOVETYPE && (p)->link == NULL)
+
+/*END SHARED*/
+/*SHARED*/
+
+struct conicsegment {
+ XOBJ_COMMON /* xobject common data define 3-26-91 PNM */
+ /* type = CONICTYPE */
+ unsigned char size; /* as with any 'segment' type */
+ unsigned char context; /* as with any 'segment' type */
+ struct segment *link; /* as with any 'segment' type */
+ struct segment *last; /* as with any 'segment' type */
+ struct fractpoint dest; /* Ending point (C point) */
+ struct fractpoint M; /* "midpoint" of conic explained above */
+ float roundness; /* explained above */
+} ;
+/*END SHARED*/
+/*SHARED*/
+
+struct beziersegment {
+ XOBJ_COMMON /* xobject common data define 3-26-91 PNM */
+ /* type = BEZIERTYPE */
+ unsigned char size; /* as with any 'segment' type */
+ unsigned char context; /* as with any 'segment' type */
+ struct segment *link; /* as with any 'segment' type */
+ struct segment *last; /* as with any 'segment' type */
+ struct fractpoint dest; /* ending point (D) */
+ struct fractpoint B; /* control point B */
+ struct fractpoint C; /* control point C */
+} ;
+
+/*END SHARED*/
+/*SHARED*/
+
+struct hintsegment {
+ XOBJ_COMMON /* xobject common data define 3-26-91 PNM */
+ /* type = HINTTYPE */
+ unsigned char size; /* size of the structure */
+ unsigned char context; /* device context */
+ struct segment *link; /* pointer to next structure in linked list */
+ struct segment *last; /* pointer to last structure in list */
+ struct fractpoint dest; /* ALWAYS 0,0 */
+ struct fractpoint ref;
+ struct fractpoint width;
+ char orientation;
+ char hinttype;
+ char adjusttype;
+ char direction;
+ int label;
+} ;
+
+/*END SHARED*/
+/*SHARED*/
+
+/*
+CONCAT links the 'p2' path chain on the end of the 'p1' chain. (This macro
+is also used by the STROKES module.)
+*/
+#define CONCAT(p1, p2) { \
+ p1->last->link = p2; /* link p2 on end of p1 */ \
+ p1->last = p2->last; /* last of new is last of p2 */ \
+ p2->last = NULL; } /* only first segment has non-NULL "last" */
+
+/*END SHARED*/
diff --git a/src/Type1/pictures.h b/src/Type1/pictures.h
new file mode 100644
index 0000000..6a14292
--- /dev/null
+++ b/src/Type1/pictures.h
@@ -0,0 +1,48 @@
+/* $Xorg: pictures.h,v 1.3 2000/08/17 19:46:31 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* STUB */
+
+#define CopyPicture(p) p
+#define UniquePicture(p) p
+#define KillPicture(p)
+#define BegHandle(o,m) o
+#define EndHandle(o,m) o
+#define PictureBounds(P) P
+
+struct picture {
+ struct fractpoint origin;
+ struct fractpoint ending;
+};
+
+#define Phantom(o) t1_Phantom(o)
+#define Snap(o) t1_Snap(o)
+
+struct segment *t1_Phantom();
+struct segment *t1_Snap();
diff --git a/src/Type1/regions.c b/src/Type1/regions.c
new file mode 100644
index 0000000..2824887
--- /dev/null
+++ b/src/Type1/regions.c
@@ -0,0 +1,1749 @@
+/* $Xorg: regions.c,v 1.3 2000/08/17 19:46:31 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+ /* REGIONS CWEB V0023 LOTS */
+/*
+:h1 id=regions.REGIONS Module - Regions Operator Handler
+
+This module is responsible for creating and manipulating regions.
+
+&author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
+
+
+:h3.Include Files
+
+The included files are:
+*/
+
+#include "objects.h"
+#include "spaces.h"
+#include "regions.h"
+#include "paths.h"
+#include "curves.h"
+#include "lines.h"
+#include "pictures.h"
+#include "fonts.h"
+#include "hints.h"
+#include "strokes.h" /* to pick up 'DoStroke' */
+static void newfilledge();
+static struct edgelist *splitedge();
+static void vertjoin();
+static int touches();
+static int crosses();
+static void edgemin();
+static void edgemax();
+static struct edgelist *NewEdge();
+static struct edgelist *swathxsort(); /* 'SortSwath' function */
+
+/*
+:h3.Functions Provided to the TYPE1IMAGER User
+
+This module provides the following TYPE1IMAGER entry points:
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.Functions Provided to Other Modules
+
+This module provides the following entry points to other modules:
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.Macros Provided to Other Modules
+
+:h4.GOING_TO() - Macro Predicate Needed for Changing Direction, Etc.
+
+The actual generation of run end lists (edge boundaries) is left
+to the low level rasterizing modules, LINES and CURVES. There
+are some global region-type
+questions that occur when doing a low-level
+rasterization:
+:ol.
+:li.Did we just change direction in Y and therefore need to start
+a new edge?
+:li.Did we run out of allocated edge space?
+:li.Do the minimum or maximum X values for the current edge need
+updating?
+:eol.
+In general the REGIONS is not smart enough to answer those questions
+itself. (For example, determining if and when a curve changes direction
+may need detailed curve knowledge.) Yet, this must be done efficiently.
+We provide a macro "GOING_TO" where the invoker tells us where it is
+heading for (x2,y2), plus where it is now (x1,y1), plus the current
+region under construction, and the macro answers the questions above.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h2.Data Structures Used to Represent Regions
+
+:h3.The "region" Structure
+
+The region structure is an anchor for a linked list of "edgelist"
+structures (see :hdref refid=edgelist..). It also summarizes the
+information in the edgelist structures (for example, the bounding
+box of the region). And, it contains scratch areas used during
+the creation of a region.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+The ISOPTIMIZED flag tells us if we've put a permanent region in
+'optimal' form.
+*/
+#define ISOPTIMIZED(flag) ((flag)&0x10)
+
+/*
+The ISRECTANGULAR flag tells us if a region is a rectangle. We don't
+always notice rectangles--if this flag is set, the region definitely
+is a rectangle, but some rectangular regions will not have the flag
+set. The flag is used to optimize some paths.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h4."INFINITY" - A Constant Region Structure of Infinite Extent
+
+Infinity is the complement of a null area:
+Note - removed the refcount = 1 init, replaced with references = 2 3-26-91 PNM
+*/
+static struct region infinity = { REGIONTYPE,
+ ISCOMPLEMENT(ON)+ISINFINITE(ON)+ISPERMANENT(ON)+ISIMMORTAL(ON), 2,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ NULL, NULL,
+ 0, 0, 0, 0, 0, NULL, NULL,
+ NULL, 0, NULL, NULL };
+struct region *INFINITY = &infinity;
+
+/*
+:h4."EmptyRegion" - A Region Structure with Zero Area
+
+This structure is used to initialize the region to be built in
+Interior():
+Note - replaced refcount = 1 init with references = 2 3-26-91 PNM
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+struct region EmptyRegion = { REGIONTYPE,
+ ISPERMANENT(ON)+ISIMMORTAL(ON), 2,
+ 0, 0, 0, 0,
+ MAXPEL, MAXPEL, MINPEL, MINPEL,
+ NULL, NULL,
+ 0, 0, 0, 0, 0, NULL, NULL,
+ NULL, 0, NULL, NULL };
+
+/*
+:h3 id=edgelist.The "edgelist" Structure
+
+Regions are represented by a linked list of 'edgelist' structures.
+When a region is complete, the structures are paired, one for the
+left and one for the right edge. While a region is being built,
+this rule may be violated temporarily.
+
+An 'edgelist' structure contains the X values for a given span
+of Y values. The (X,Y) pairs define an edge. We use the crack
+and edge coordinate system, so that integer values of X and Y
+go between pels. The edge is defined between the minimum Y and
+maximum Y.
+
+The linked list is kept sorted from top to bottom, that is, in
+increasing y. Also, if 'e1' is an edgelist structure and 'e2' is the
+next one in the list, they must have exactly the same ymin,ymax values
+or be totally disjoint. These two requirements mean that if e2's ymin
+is less than e1's ymax, it must be exactly equal to e1's ymin. A
+sublist of structures with identical ymin and ymax values is called a
+'swath'.
+
+In addition, edgelist structures are separately linked together based
+on what subpath originally created them; each subpath is kept as a
+separate circular linked list. This information is ignored unless
+continuity checking is invoked. See :hdref refid=subpath. for a
+complete description of this.
+*/
+
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+The "edgelist" structure follows the convention of TYPE1IMAGER user
+objects, having a type field and a flag field as the first two
+elements. However, the user never sees "edgelist" structures
+directly; he is given handles to "region" structures only.
+
+By having a type field, we can use the "copy" feature of Allocate()
+to duplicate edge lists quickly.
+
+We also define two flag bits for this structure. The ISDOWN bit is set
+if the edge is going in the direction of increasing Y. The ISAMBIGUOUS
+bit is set if the edge is identical to its neighbor (edge->link); such
+edges may be "left" when they should be "right", or vice versa,
+unnecessarily confusing the continuity checking logic. The FixSubPaths()
+routine in HINTS will swap ambiguous edges if that avoids crossing edges;
+see :hdref refid=fixsubp..
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h3.KillRegion() - Destroys a Region
+
+KillRegion nominally just decrements the reference count to that region.
+If the reference count becomes 0, all memory associated with it is
+freed. We just follow the linked list, freeing as we go, then kill any
+associated (thresholded) picture.
+Note - added conditional return based on references 3-26-91 PNM
+*/
+
+void KillRegion(area)
+ register struct region *area; /* area to free */
+{
+ register struct edgelist *p; /* loop variable */
+ register struct edgelist *next; /* loop variable */
+
+ if (area->references < 0)
+ abort("KillRegion: negative reference count");
+ if ( (--(area->references) > 1) ||
+ ( (area->references == 1) && !ISPERMANENT(area->flag) ) )
+ return;
+
+ for (p=area->anchor; p != NULL; p=next) {
+ next = p->link;
+ Free(p);
+ }
+ if (area->thresholded != NULL)
+ KillPicture(area->thresholded);
+ Free(area);
+}
+/*
+:h3.CopyRegion() - Makes a Copy of a Region
+*/
+struct region *CopyRegion(area)
+ register struct region *area; /* region to duplicate */
+{
+ register struct region *r; /* output region built here */
+ register struct edgelist *last; /* loop variable */
+ register struct edgelist *p,*newp; /* loop variables */
+
+ r = (struct region *)Allocate(sizeof(struct region), area, 0);
+ r->anchor = NULL;
+
+ for (p=area->anchor; VALIDEDGE(p); p=p->link) {
+
+ newp = NewEdge(p->xmin, p->xmax, p->ymin, p->ymax, p->xvalues, ISDOWN(p->flag));
+ if (r->anchor == NULL)
+ r->anchor = last = newp;
+ else
+ last->link = newp;
+
+ last = newp;
+ }
+ if (area->thresholded != NULL)
+ /* replaced DupPicture with Dup() 3-26-91 PNM */
+ r->thresholded = (struct picture *)Dup(area->thresholded);
+ return(r);
+}
+/*
+:h4.NewEdge() - Allocates and Returns a New "edgelist" Structure
+
+We allocate space for the X values contiguously with the 'edgelist'
+structure that locates them. That way, we only have to free the
+edgelist structure to free all memory associated with it. Damn
+clever, huh?
+*/
+
+static struct edgelist *NewEdge(xmin, xmax, ymin, ymax, xvalues, isdown)
+ pel xmin,xmax; /* X extent of edge */
+ pel ymin,ymax; /* Y extent of edge */
+ pel *xvalues; /* list of X values for entire edge */
+ int isdown; /* flag: TRUE means edge progresses downward */
+{
+ static struct edgelist template = {
+ EDGETYPE, 0, 1, NULL, NULL,
+ 0, 0, 0, 0, NULL };
+
+ register struct edgelist *r; /* returned structure */
+ register int iy; /* ymin adjusted for 'long' alignment purposes */
+
+ IfTrace2((RegionDebug),"....new edge: ymin=%d, ymax=%d ",
+ (long)ymin, (long) ymax);
+ if (ymin >= ymax)
+ abort("newedge: height not positive");
+/*
+We are going to copy the xvalues into a newly allocated area. It
+helps performance if the values are all "long" aligned. We can test
+if the xvalues are long aligned by ANDing the address with the
+(sizeof(long) - 1)--if non zero, the xvalues are not aligned well. We
+set 'iy' to the ymin value that would give us good alignment:
+*/
+ iy = ymin - (((int) xvalues) & (sizeof(long) - 1)) / sizeof(pel);
+
+ r = (struct edgelist *)Allocate(sizeof(struct edgelist), &template,
+ (ymax - iy) * sizeof(pel));
+
+ if (isdown) r->flag = ISDOWN(ON);
+ r->xmin = xmin;
+ r->xmax = xmax;
+ r->ymin = ymin;
+ r->ymax = ymax;
+
+ r->xvalues = (pel *) FOLLOWING(r);
+ if (ymin != iy) {
+ r->xvalues += ymin - iy;
+ xvalues -= ymin - iy;
+ }
+
+/*
+We must round up (ymax - iy) so we get the ceiling of the number of
+longs. The destination must be able to hold these extra bytes because
+Allocate() makes everything it allocates be in multiples of longs.
+*/
+ LONGCOPY(&r[1], xvalues, (ymax - iy) * sizeof(pel) + sizeof(long) - 1);
+
+ IfTrace1((RegionDebug),"result=%x\n", r);
+ return(r);
+}
+
+/*
+:h3 id=discard.discard() - Discard All Edges Between Two Edges
+
+At first glance it would seem that we could discard an edgelist
+structure merely by unlinking it from the list and freeing it. You are
+wrong, region-breath! For performance, the X values associated with an
+edge are allocated contiguously with it. So, we free the X values when
+we free a structure. However, once an edge has been split, we are no
+longer sure which control block actually is part of the memory block
+that contains the edges. Rather than trying to decide, we play it safe
+and never free part of a region.
+
+So, to mark a 'edgelist' structure as discarded, we move it to the end
+of the list and set ymin=ymax.
+*/
+
+static void
+discard(left, right)
+ register struct edgelist *left,*right; /* all edges between here exclusive */
+ /* should be discarded */
+{
+ register struct edgelist *beg,*end,*p;
+
+ IfTrace2((RegionDebug > 0),"discard: l=%x, r=%x\n", left, right);
+
+ beg = left->link;
+ if (beg == right)
+ return;
+
+ for (p = beg; p != right; p = p->link) {
+ if (p->link == NULL && right != NULL)
+ abort("discard(): ran off end");
+ IfTrace1((RegionDebug > 0),"discarding %x\n", p);
+ p->ymin = p->ymax = 32767;
+ end = p;
+ }
+ /*
+ * now put the chain beg/end at the end of right, if it is not
+ * already there:
+ */
+ if (right != NULL) {
+ left->link = right;
+ while (right->link != NULL)
+ right = right->link;
+ right->link = beg;
+ }
+ end->link = NULL;
+}
+
+/*
+:h4.Unwind() - Discards Edges That Fail the Winding Rule Test
+
+The winding rule says that upward going edges should be paired with
+downward going edges only, and vice versa. So, if two upward edges
+or two downward edges are nominally left/right pairs, Unwind() should
+discard the second one. Everything should balance; we should discard
+an even number of edges; of course, we abort if we don't.
+*/
+static void
+Unwind(area)
+ register struct edgelist *area; /* input area modified in place */
+{
+ register struct edgelist *last,*next; /* struct before and after current one */
+ register int y; /* ymin of current swath */
+ register int count,newcount; /* winding count registers */
+
+ IfTrace1((RegionDebug>0),"...Unwind(%z)\n", area);
+
+ while (VALIDEDGE(area)) {
+
+ count = 0;
+ y = area->ymin;
+
+ do {
+ next = area->link;
+
+ if (ISDOWN(area->flag))
+ newcount = count + 1;
+ else
+ newcount = count - 1;
+
+ if (count == 0 || newcount == 0)
+ last = area;
+ else
+ discard(last, next);
+
+ count = newcount;
+ area = next;
+
+ } while (area != NULL && area->ymin == y);
+
+ if (count != 0)
+ abort("Unwind: uneven edges");
+ }
+}
+/*
+:h2.Building Regions
+
+:h3.Interior() - Iterate Through a Path, Building a Region
+
+This routine is the workhorse driver routine that iterates through a
+path, calling the appropriate stepping routines to actually produce the
+run end "edgelist" structures.
+
+:ol.
+:li."Interior" calls StepLine or StepConic or StepBezier as appropriate
+to produce run ends.
+:li.Occasionally these routines will notice a change in Y direction
+and will call ChangeDirection (through the GOING_TO macro); this is
+a call back to the REGIONS module.
+:li.ChangeDirection will call whatever function is in the region
+structure; for Interior, this function is 'newfilledge'.
+:li.Newfilledge will call NewEdge to create a new edgelist structure,
+then, call SortSwath to sort it onto the linked list being built at
+the region "anchor".
+:eol.
+
+By making the function called by ChangeDirection be a parameter of the
+region, we allow the same ChangeDirection logic to be used by stroking.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+struct region *Interior(p, fillrule)
+ register struct segment *p; /* take interior of this path */
+ register int fillrule; /* rule to follow if path crosses itself */
+{
+ register fractpel x,y; /* keeps ending point of path segment */
+ fractpel lastx,lasty; /* previous x,y from path segment before */
+ register struct region *R; /* region I will build */
+ register struct segment *nextP; /* next segment of path */
+ struct fractpoint hint; /* accumulated hint value */
+ char tempflag; /* flag; is path temporary? */
+ char Cflag; /* flag; should we apply continuity? */
+
+ IfTrace2((MustTraceCalls),". INTERIOR(%z, %d)\n", p, (long) fillrule);
+
+ if (p == NULL)
+ return(NULL);
+/*
+Establish the 'Cflag' continuity flag based on user's fill rule and
+our own 'Continuity' pragmatic (0: never do continuity, 1: do what
+user asked, >1: do it regardless).
+*/
+ if (fillrule > 0) {
+ Cflag = Continuity > 0;
+ fillrule -= CONTINUITY;
+ }
+ else
+ Cflag = Continuity > 1;
+
+ ARGCHECK((fillrule != WINDINGRULE && fillrule != EVENODDRULE),
+ "Interior: bad fill rule", NULL, NULL, (1,p), struct region *);
+
+ if (p->type == TEXTTYPE)
+/* if (fillrule != EVENODDRULE)
+ else */
+ return((struct region *)UniquePath(p));
+ if (p->type == STROKEPATHTYPE)
+ if (fillrule == WINDINGRULE)
+ return((struct region *)DoStroke(p));
+ else
+ p = CoercePath(p);
+
+ R = (struct region *)Allocate(sizeof(struct region), &EmptyRegion, 0);
+
+ ARGCHECK(!ISPATHANCHOR(p), "Interior: bad path", p, R, (0), struct region *);
+ ARGCHECK((p->type != MOVETYPE), "Interior: path not closed", p, R, (0), struct region *);
+
+
+/* changed definition from !ISPERMANENT to references <= 1 3-26-91 PNM */
+ tempflag = (p->references <= 1); /* only first segment in path is so marked */
+ if (!ISPERMANENT(p->flag)) p->references -= 1;
+
+ R->newedgefcn = newfilledge;
+/*
+Believe it or not, "R" is now completely initialized. We are counting
+on the copy of template to get other fields the way we want them,
+namely
+:ol.
+:li.anchor = NULL
+:li.xmin, ymin, xmax, ymax, to minimum and maximum values respectively.
+:eol.
+Anchor = NULL is very
+important to ChangeDirection.
+See :hdref refid=CD..
+
+To minimize problems of "wrapping" in our pel arithmetic, we keep an
+origin of the region which is the first move. Hopefully, that keeps
+numbers within plus or minus 32K pels.
+*/
+ R->origin.x = 0/*TOFRACTPEL(NEARESTPEL(p->dest.x))*/;
+ R->origin.y = 0/*TOFRACTPEL(NEARESTPEL(p->dest.y))*/;
+ lastx = - R->origin.x;
+ lasty = - R->origin.y;
+/*
+ChangeDirection initializes other important fields in R, such as
+lastdy, edge, edgeYstop, edgexmin, and edgexmax. The first segment
+is a MOVETYPE, so it will be called first.
+*/
+/*
+The hints data structure must be initialized once for each path.
+*/
+
+ if (ProcessHints)
+ InitHints(); /* initialize hint data structure */
+
+ while (p != NULL) {
+
+ x = lastx + p->dest.x;
+ y = lasty + p->dest.y;
+
+ IfTrace2((HintDebug > 0),"Ending point = (%p,%p)\n", x, y);
+
+ nextP = p->link;
+
+/*
+Here we start the hints processing by initializing the hint value to
+zero. If ProcessHints is FALSE, the value will remain zero.
+Otherwise, hint accumulates the computed hint values.
+*/
+
+ hint.x = hint.y = 0;
+
+/*
+If we are processing hints, and this is a MOVE segment (other than
+the first on the path), we need to close (reverse) any open hints.
+*/
+
+ if (ProcessHints)
+ if ((p->type == MOVETYPE) && (p->last == NULL)) {
+ CloseHints(&hint);
+ IfTrace2((HintDebug>0),"Closed point= (%p,%p)\n",
+ x+hint.x, y+hint.y);
+ }
+
+/*
+Next we run through all the hint segments (if any) attached to this
+segment. If ProcessHints is TRUE, we will accumulate computed hint
+values. In either case, nextP will be advanced to the first non-HINT
+segment (or NULL), and each hint segment will be freed if necessary.
+*/
+
+ while ((nextP != NULL) && (nextP->type == HINTTYPE)) {
+ if (ProcessHints)
+ ProcessHint(nextP, x + hint.x, y + hint.y, &hint);
+
+ {
+ register struct segment *saveP = nextP;
+
+ nextP = nextP->link;
+ if (tempflag)
+ Free(saveP);
+ }
+ }
+
+/*
+We now apply the full hint value to the ending point of the path segment.
+*/
+
+ x += hint.x;
+ y += hint.y;
+
+ IfTrace2((HintDebug>0),"Hinted ending point = (%p,%p)\n", x, y);
+
+ switch(p->type) {
+
+ case LINETYPE:
+ StepLine(R, lastx, lasty, x, y);
+ break;
+
+ case CONICTYPE:
+ {
+
+/*
+For a conic curve, we apply half the hint value to the conic midpoint.
+*/
+
+ }
+ break;
+
+ case BEZIERTYPE:
+ {
+ register struct beziersegment *bp = (struct beziersegment *) p;
+
+/*
+For a Bezier curve, we apply the full hint value to the Bezier C point.
+*/
+
+ StepBezier(R, lastx, lasty,
+ lastx + bp->B.x, lasty + bp->B.y,
+ lastx + bp->C.x + hint.x,
+ lasty + bp->C.y + hint.y,
+ x, y);
+ }
+ break;
+
+ case MOVETYPE:
+/*
+At this point we have encountered a MOVE segment. This breaks the
+path, making it disjoint.
+*/
+ if (p->last == NULL) /* i.e., not first in path */
+ ChangeDirection(CD_LAST, R, lastx, lasty, (fractpel) 0);
+
+ ChangeDirection(CD_FIRST, R, x, y, (fractpel) 0);
+/*
+We'll just double check for closure here. We forgive an appended
+MOVETYPE at the end of the path, if it isn't closed:
+*/
+ if (!ISCLOSED(p->flag) && p->link != NULL)
+ return((struct region *)ArgErr("Fill: sub-path not closed", p, NULL));
+ break;
+
+ default:
+ abort("Interior: path type error");
+ }
+/*
+We're done with this segment. Advance to the next path segment in
+the list, freeing this one if necessary:
+*/
+ lastx = x; lasty = y;
+
+ if (tempflag)
+ Free(p);
+ p = nextP;
+ }
+ ChangeDirection(CD_LAST, R, lastx, lasty, (fractpel) 0);
+ R->ending.x = lastx;
+ R->ending.y = lasty;
+/*
+Finally, clean up the region's based on the user's 'fillrule' request:
+*/
+ if (Cflag)
+ ApplyContinuity(R);
+ if (fillrule == WINDINGRULE)
+ Unwind(R->anchor);
+ return(R);
+}
+/*
+:h3."workedge" Array
+
+This is a statically allocated array where edges are built
+before being copied into more permanent storage by NewEdge().
+*/
+
+#ifndef MAXEDGE
+#define MAXEDGE 1000
+#endif
+
+static pel workedge[MAXEDGE];
+static pel *currentworkarea = workedge;
+static pel currentsize = MAXEDGE;
+
+/*
+:h3 id=cd.ChangeDirection() - Called When Y Direction Changes
+
+The rasterizing routines call this entry point when they detect
+a change in Y. We then build the current edge and sort it into
+emerging edgelist at 'anchor' by calling whatever "newedgefcn"
+is appropriate.
+*/
+
+void ChangeDirection(type, R, x, y, dy)
+ int type; /* CD_FIRST, CD_CONTINUE, or CD_LAST */
+ register struct region *R; /* region in which we are changing direction */
+ fractpel x,y; /* current beginning x,y */
+ fractpel dy; /* direction and magnitude of change in y */
+{
+ register fractpel ymin,ymax; /* minimum and maximum Y since last call */
+ register fractpel x_at_ymin,x_at_ymax; /* their respective X's */
+ register pel iy; /* nearest integer pel to 'y' */
+ register pel idy; /* nearest integer pel to 'dy' */
+ register int ydiff; /* allowed Y difference in 'currentworkarea' */
+
+ IfTrace4((RegionDebug>0),"Change Y direction (%d) from (%p,%p), dy=%p\n",
+ (long) type, x, y, dy);
+
+ if (type != CD_FIRST) {
+
+ if (R->lastdy > 0) {
+ ymin = R->firsty;
+ x_at_ymin = R->firstx;
+ ymax = y;
+ x_at_ymax = x;
+ }
+ else {
+ ymin = y;
+ x_at_ymin = x;
+ ymax = R->firsty;
+ x_at_ymax = R->firstx;
+ }
+
+ if (ymax < ymin)
+ abort("negative sized edge?");
+
+
+ (*R->newedgefcn)(R, R->edgexmin, R->edgexmax, ymin, ymax,
+ R->lastdy > 0, x_at_ymin, x_at_ymax);
+
+ }
+
+ R->firsty = y;
+ R->firstx = x;
+ R->lastdy = dy;
+
+ iy = NEARESTPEL(y);
+ idy = NEARESTPEL(dy);
+ if (currentworkarea != workedge && idy < MAXEDGE && idy > -MAXEDGE) {
+ NonObjectFree(currentworkarea);
+ currentworkarea = workedge;
+ currentsize = MAXEDGE;
+ }
+ ydiff = currentsize - 1;
+ if (dy > 0) {
+ R->edge = &currentworkarea[-iy];
+ R->edgeYstop = TOFRACTPEL(ydiff + iy) + FPHALF;
+ }
+ else {
+ R->edge = &currentworkarea[ydiff - iy];
+ R->edgeYstop = TOFRACTPEL(iy - ydiff) - FPHALF;
+ }
+ R->edgexmax = R->edgexmin = x;
+/*
+If this is the end of a subpath, we complete the subpath circular
+chain:
+*/
+ if (type == CD_LAST && R->lastedge != NULL) {
+ register struct edgelist *e = R->firstedge;
+
+ while (e->subpath != NULL)
+ e = e->subpath;
+ e->subpath = R->lastedge;
+ R->lastedge = R->firstedge = NULL;
+ }
+}
+/*
+:h3 id=newfill.newfilledge() - Called When We Have a New Edge While Filling
+
+This is the prototypical "newedge" function passed to "Rasterize" and
+stored in "newedgefcn" in the region being built.
+
+If the edge is non-null, we sort it onto the list of edges we are
+building at "anchor".
+
+This function also has to keep the bounding box of the region
+up to date.
+*/
+
+static void newfilledge(R, xmin, xmax, ymin, ymax, isdown)
+ register struct region *R; /* region being built */
+ fractpel xmin,xmax; /* X range of this edge */
+ fractpel ymin,ymax; /* Y range of this edge */
+ int isdown; /* flag: TRUE means edge goes down, else up */
+{
+
+ register pel pelxmin,pelymin,pelxmax,pelymax; /* pel versions of bounds */
+ register struct edgelist *edge; /* newly created edge */
+
+ pelymin = NEARESTPEL(ymin);
+ pelymax = NEARESTPEL(ymax);
+ if (pelymin == pelymax)
+ return;
+
+ pelxmin = NEARESTPEL(xmin);
+ pelxmax = NEARESTPEL(xmax);
+
+ if (pelxmin < R->xmin) R->xmin = pelxmin;
+ if (pelxmax > R->xmax) R->xmax = pelxmax;
+ if (pelymin < R->ymin) R->ymin = pelymin;
+ if (pelymax > R->ymax) R->ymax = pelymax;
+
+ edge = NewEdge(pelxmin, pelxmax, pelymin, pelymax, &R->edge[pelymin], isdown);
+ edge->subpath = R->lastedge;
+ R->lastedge = edge;
+ if (R->firstedge == NULL)
+ R->firstedge = edge;
+
+ R->anchor = SortSwath(R->anchor, edge, swathxsort);
+
+}
+
+/*
+:h2.Sorting Edges
+
+:h3.SortSwath() - Vertically Sort an Edge into a Region
+
+This routine sorts an edge or a pair of edges into a growing region,
+so that the region maintains its top-to-bottom, left-to-right form.
+The rules for sorting horizontally may vary depending on what you
+are doing, but the rules for vertical sorting are always the same.
+This routine is passed an argument that is a function that will
+perform the horizontal sort on demand (for example, swathxsort() or
+SwathUnion()).
+
+This is a recursive routine. A new edge (or edge pair) may overlap
+the list I am building in strange and wonderful ways. Edges may
+cross. When this happens, my strategy is to split the incoming edge
+(or the growing list) in two at that point, execute the actual sort on
+the top part of the split, and recursively call myself to figure out
+exactly where the bottom part belongs.
+*/
+
+#define TOP(e) ((e)->ymin) /* the top of an edge (for readability */
+#define BOTTOM(e) ((e)->ymax) /* the bottom of an edge (for readability */
+
+struct edgelist *SortSwath(anchor, edge, swathfcn)
+ struct edgelist *anchor; /* list being built */
+ register struct edgelist *edge; /* incoming edge or pair of edges */
+ struct edgelist *(*swathfcn)(); /* horizontal sorter */
+{
+ register struct edgelist *before,*after;
+ struct edgelist base;
+
+ if (RegionDebug > 0) {
+ if (RegionDebug > 2) {
+ IfTrace3(TRUE,"SortSwath(anchor=%z, edge=%z, fcn=%x)\n",
+ anchor, edge, swathfcn);
+ }
+ else {
+ IfTrace3(TRUE,"SortSwath(anchor=%x, edge=%x, fcn=%x)\n",
+ anchor, edge, swathfcn);
+ }
+ }
+ if (anchor == NULL)
+ return(edge);
+
+ before = &base;
+ before->ymin = before->ymax = MINPEL;
+ before->link = after = anchor;
+
+/*
+If the incoming edge is above the current list, we connect the current
+list to the bottom of the incoming edge. One slight complication is
+if the incoming edge overlaps into the current list. Then, we
+first split the incoming edge in two at the point of overlap and recursively
+call ourselves to sort the bottom of the split into the current list:
+*/
+ if (TOP(edge) < TOP(after)) {
+ if (BOTTOM(edge) > TOP(after)) {
+
+ after = SortSwath(after, splitedge(edge, TOP(after)), swathfcn);
+ }
+ vertjoin(edge, after);
+ return(edge);
+ }
+/*
+At this point the top of edge is not higher than the top of the list,
+which we keep in 'after'. We move the 'after' point down the list,
+until the top of the edge occurs in the swath beginning with 'after'.
+
+If the bottom of 'after' is below the bottom of the edge, we have to
+split the 'after' swath into two parts, at the bottom of the edge.
+If the bottom of 'after' is above the bottom of the swath,
+*/
+
+ while (VALIDEDGE(after)) {
+
+ if (TOP(after) == TOP(edge)) {
+ if (BOTTOM(after) > BOTTOM(edge))
+ vertjoin(after, splitedge(after, BOTTOM(edge)));
+ else if (BOTTOM(after) < BOTTOM(edge)) {
+ after = SortSwath(after,
+ splitedge(edge, BOTTOM(after)), swathfcn);
+ }
+ break;
+ }
+ else if (TOP(after) > TOP(edge)) {
+ IfTrace0((BOTTOM(edge) < TOP(after) && RegionDebug > 0),
+ "SortSwath: disjoint edges\n");
+ if (BOTTOM(edge) > TOP(after)) {
+ after = SortSwath(after,
+ splitedge(edge, TOP(after)), swathfcn);
+ }
+ break;
+ }
+ else if (BOTTOM(after) > TOP(edge))
+ vertjoin(after, splitedge(after, TOP(edge)));
+
+ before = after;
+ after = after->link;
+ }
+
+/*
+At this point 'edge' exactly corresponds in height to the current
+swath pointed to by 'after'.
+*/
+ if (after != NULL && TOP(after) == TOP(edge)) {
+ before = (*swathfcn)(before, edge);
+ after = before->link;
+ }
+/*
+At this point 'after' contains all the edges after 'edge', and 'before'
+contains all the edges before. Whew! A simple matter now of adding
+'edge' to the linked list in its rightful place:
+*/
+ before->link = edge;
+ if (RegionDebug > 1) {
+ IfTrace3(TRUE,"SortSwath: in between %x and %x are %x",
+ before, after, edge);
+ while (edge->link != NULL) {
+ edge = edge->link;
+ IfTrace1(TRUE," and %x", edge);
+ }
+ IfTrace0(TRUE,"\n");
+ }
+ else
+ for (; edge->link != NULL; edge = edge->link) { ; }
+
+ edge->link = after;
+ return(base.link);
+}
+
+/*
+:h3.splitedge() - Split an Edge or Swath in Two at a Given Y Value
+
+This function returns the edge or swath beginning at the Y value, and
+is guaranteed not to change the address of the old swath while splitting
+it.
+*/
+
+static struct edgelist *splitedge(list, y)
+ struct edgelist *list; /* area to split */
+ register pel y; /* Y value to split list at */
+{
+ register struct edgelist *new; /* anchor for newly built list */
+ register struct edgelist *last; /* end of newly built list */
+ register struct edgelist *r; /* temp pointer to new structure */
+ register struct edgelist *lastlist; /* temp pointer to last 'list' value */
+
+ IfTrace2((RegionDebug > 1),"splitedge of %x at %d ", list, (long) y);
+
+ lastlist = new = NULL;
+
+ while (list != NULL) {
+ if (y < list->ymin)
+ break;
+ if (y >= list->ymax)
+ abort("splitedge: above top of list");
+ if (y == list->ymin)
+ abort("splitedge: would be null");
+
+ r = (struct edgelist *)Allocate(sizeof(struct edgelist), list, 0);
+/*
+At this point 'r' points to a copy of the single structure at 'list'.
+We will make 'r' be the new split 'edgelist'--the lower half.
+We don't bother to correct 'xmin' and 'xmax', we'll take the
+the pessimistic answer that results from using the old values.
+*/
+ r->ymin = y;
+ r->xvalues = list->xvalues + (y - list->ymin);
+/*
+Note that we do not need to allocate new memory for the X values,
+they can remain with the old "edgelist" structure. We do have to
+update that old structure so it is not as high:
+*/
+ list->ymax = y;
+/*
+Insert 'r' in the subpath chain:
+*/
+ r->subpath = list->subpath;
+ list->subpath = r;
+/*
+Now attach 'r' to the list we are building at 'new', and advance
+'list' to point to the next element in the old list:
+*/
+ if (new == NULL)
+ new = r;
+ else
+ last->link = r;
+ last = r;
+ lastlist = list;
+ list = list->link;
+ }
+/*
+At this point we have a new list built at 'new'. We break the old
+list at 'lastlist', and add the broken off part to the end of 'new'.
+Then, we return the caller a pointer to 'new':
+*/
+ if (new == NULL)
+ abort("null splitedge");
+ lastlist->link = NULL;
+ last->link = list;
+ IfTrace1((RegionDebug > 1),"yields %x\n", new);
+ return(new);
+}
+
+/*
+:h3.vertjoin() - Join Two Disjoint Edge Lists Vertically
+
+The two edges must be disjoint vertically.
+*/
+static void vertjoin(top, bottom)
+ register struct edgelist *top; /* uppermost region */
+ register struct edgelist *bottom; /* bottommost region */
+{
+ if (BOTTOM(top) > TOP(bottom))
+ abort("vertjoin not disjoint");
+
+ for (; top->link != NULL; top=top->link) { ; }
+
+ top->link = bottom;
+ return;
+}
+
+/*
+:h3.swathxsort() - Sorting by X Values
+
+We need to sort 'edge' into its rightful
+place in the swath by X value, taking care that we do not accidentally
+advance to the next swath while searching for the correct X value. Like
+all swath functions, this function returns a pointer to the edge
+BEFORE the given edge in the sort.
+*/
+
+static struct edgelist *swathxsort(before0, edge)
+ register struct edgelist *before0; /* edge before this swath */
+ register struct edgelist *edge; /* input edge */
+{
+ register struct edgelist *before;
+ register struct edgelist *after;
+ register pel y;
+
+ before = before0;
+ after = before->link;
+
+ while (after != NULL && TOP(after) == TOP(edge)) {
+
+ register pel *x1,*x2;
+
+ y = TOP(edge);
+ x1 = after->xvalues;
+ x2 = edge->xvalues;
+
+ while (y < BOTTOM(edge) && *x1 == *x2) {
+ x1++; x2++; y++;
+ }
+ if (y >= BOTTOM(edge)) {
+ edge->flag |= ISAMBIGUOUS(ON);
+ after->flag |= ISAMBIGUOUS(ON);
+ break;
+ }
+
+ if (*x1 >= *x2)
+ break;
+
+ before = after;
+ after = after->link;
+ }
+
+/*
+At this point, 'edge' is between 'before' and 'after'. If 'edge' didn't
+cross either of those other edges, we would be done. We check for
+crossing. If it does cross, we split the problem up by calling SortSwath
+recursively with the part of the edge that is below the crossing point:
+*/
+{
+ register int h0,h; /* height of edge--number of scans */
+
+ h0 = h = BOTTOM(edge) - y;
+ y -= TOP(edge);
+
+ if (h0 <= 0) {
+ IfTrace0((RegionDebug>0),"swathxsort: exactly equal edges\n");
+ return(before);
+ }
+
+ if (TOP(before) == TOP(edge))
+ h -= crosses(h, &before->xvalues[y], &edge->xvalues[y]);
+ if (after != NULL && TOP(after) == TOP(edge))
+ h -= crosses(h, &edge->xvalues[y], &after->xvalues[y]);
+
+ if (h < h0) {
+ SortSwath(before0->link,
+ splitedge(edge, TOP(edge) + y + h),
+ swathxsort);
+
+ }
+}
+
+ return(before);
+}
+/*
+:h3.SwathUnion() - Union Two Edges by X Value
+
+We have a left and right edge that must be unioned into a growing
+swath. If they are totally disjoint, they are just added in. The
+fun comes in they overlap the existing edges. Then some edges
+will disappear.
+*/
+
+struct edgelist *SwathUnion(before0, edge)
+ register struct edgelist *before0; /* edge before the swath */
+ register struct edgelist *edge; /* list of two edges to be unioned */
+{
+ register int h; /* saves height of edge */
+ register struct edgelist *rightedge; /* saves right edge of 'edge' */
+ register struct edgelist *before,*after; /* edge before and after */
+ int h0; /* saves initial height */
+
+ IfTrace2((RegionDebug > 1),"SwathUnion entered, before=%x, edge=%x\n",
+ before0, edge);
+
+ h0 = h = edge->ymax - edge->ymin;
+ if (h <= 0)
+ abort("SwathUnion: 0 height swath?");
+
+ before = before0;
+ after = before->link;
+
+ while (after != NULL && TOP(after) == TOP(edge)) {
+ register struct edgelist *right;
+
+ right = after->link;
+ if (right->xvalues[0] >= edge->xvalues[0])
+ break;
+ before = right;
+ after = before->link;
+ }
+/*
+This is the picture at this point. 'L' indicates a left hand edge,
+'R' indicates the right hand edge.
+'<--->' indicates the degree of uncertainty as to its placement
+relative to other edges:
+:xmp atomic.
+ before after
+ R <---L----> R L R L R
+ <---L---> <------R-------------------------->
+ edge
+:exmp.
+In case the left of 'edge' touches 'before', we need to reduce
+the height by that amount.
+*/
+ if (TOP(before) == TOP(edge))
+ h -= touches(h, before->xvalues, edge->xvalues);
+
+ rightedge = edge->link;
+
+ if (after == NULL || TOP(after) != TOP(edge) ||
+ after->xvalues[0] > rightedge->xvalues[0]) {
+ IfTrace2((RegionDebug > 1),
+ "SwathUnion starts disjoint: before=%x after=%x\n",
+ before, after);
+/*
+On this side of the the above 'if', the new edge is disjoint from the
+existing edges in the swath. This is the picture:
+:xmp atomic.
+ before after
+ R L R L R L R
+ L R
+ edge
+:exmp.
+We will verify it remains disjoint for the entire height. If the
+situation changes somewhere down the edge, we split the edge at that
+point and recursively call ourselves (through 'SortSwath') to figure
+out the new situation:
+*/
+ if (after != NULL && TOP(after) == TOP(edge))
+ h -= touches(h, rightedge->xvalues, after->xvalues);
+ if (h < h0)
+ SortSwath(before0->link, splitedge(edge, edge->ymin + h), t1_SwathUnion);
+ /* go to "return" this edge pair; it is totally disjoint */
+ }
+ else {
+/*
+At this point, at the 'else', we know that the
+new edge overlaps one or more pairs in the existing swath. Here is
+a picture of our knowledge and uncertainties:
+:xmp atomic.
+ before after
+ R L R L R L R
+ <---L---> <---R------------------->
+ edge
+:exmp.
+We need to move 'after' along until it is to the right of the
+right of 'edge'. ('After' should always point to a left edge of a pair:)
+*/
+ register struct edgelist *left; /* variable to keep left edge in */
+
+ do {
+ left = after;
+ after = (after->link)->link;
+
+ } while (after != NULL && TOP(after) == TOP(edge)
+ && after->xvalues[0] <= rightedge->xvalues[0]);
+/*
+At this point this is the picture:
+:xmp atomic.
+ before left after
+ R L R L R L R
+ <---L---> <---R--->
+ edge
+:exmp.
+We need to verify that the situation stays like this all the way
+down the edge. Again, if the
+situation changes somewhere down the edge, we split the edge at that
+point and recursively call ourselves (through 'SortSwath') to figure
+out the new situation:
+*/
+
+ h -= crosses(h, left->xvalues, rightedge->xvalues);
+ h -= crosses(h, edge->xvalues, ((before->link)->link)->xvalues);
+
+ if (after != NULL && TOP(after) == TOP(edge))
+
+ h -= touches(h, rightedge->xvalues, after->xvalues);
+
+ IfTrace3((RegionDebug > 1),
+ "SwathUnion is overlapped until %d: before=%x after=%x\n",
+ (long) TOP(edge) + h, before, after);
+/*
+OK, if we touched either of our neighbors we need to split at that point
+and recursively sort the split edge onto the list. One tricky part
+is that when we recursively sort, 'after' will change if it was not
+in our current swath:
+*/
+ if (h < h0) {
+ SortSwath(before0->link,
+ splitedge(edge, edge->ymin + h),
+ t1_SwathUnion);
+
+ if (after == NULL || TOP(after) != TOP(edge))
+ for (after = before0->link;
+ TOP(after) == TOP(edge);
+ after = after->link) { ; }
+ }
+/*
+Now we need to augment 'edge' by the left and right of the overlapped
+swath, and to discard all edges between before and after, because they
+were overlapped and have been combined with the new incoming 'edge':
+*/
+ edge->xmin = MIN(edge->xmin, (before->link)->xmin);
+ edge->xmax = MIN(edge->xmax, (before->link)->xmax);
+ edgemin(h, edge->xvalues, (before->link)->xvalues);
+ rightedge->xmin = MAX(rightedge->xmin, (left->link)->xmin);
+ rightedge->xmax = MAX(rightedge->xmax, (left->link)->xmax);
+ edgemax(h, rightedge->xvalues, (left->link)->xvalues);
+ discard(before, after);
+ }
+ return(before);
+}
+/*
+:h3.swathrightmost() - Simply Sorts New Edge to Rightmost of Swath
+
+Like all swath functions, this function returns a pointer to the edge
+BEFORE the given edge in the sort.
+*/
+
+static struct edgelist *swathrightmost(before, edge)
+ register struct edgelist *before; /* edge before this swath */
+ register struct edgelist *edge; /* input edge */
+{
+ register struct edgelist *after;
+
+ after = before->link;
+
+ while (after != NULL && TOP(after) == TOP(edge)) {
+ before = after;
+ after = after->link;
+ }
+
+ return(before);
+
+}
+/*
+:h3.touches() - Returns the Remaining Height When Two Edges Touch
+
+So, it will return 0 if they never touch. Allows incredibly(?) mnemonic
+if (touches(...)) construct.
+*/
+
+static int touches(h, left, right)
+ register int h;
+ register pel *left,*right;
+{
+ for (; h > 0; h--)
+ if (*left++ >= *right++)
+ break;
+ return(h);
+}
+/*
+:h3.crosses() - Returns the Remaining Height When Two Edges Cross
+
+So, it will return 0 if they never cross.
+*/
+
+static int crosses(h, left, right)
+ register int h;
+ register pel *left,*right;
+{
+ for (; h > 0; h--)
+ if (*left++ > *right++)
+ break;
+ return(h);
+}
+/*
+:h3.cedgemin() - Stores the Mininum of an Edge and an X Value
+*/
+
+static void cedgemin(h, e1, x)
+ register int h;
+ register pel *e1;
+ register pel x;
+{
+ for (; --h >= 0; e1++)
+ if (*e1 > x)
+ *e1 = x;
+}
+/*
+:h3.cedgemax() - Stores the Maximum of an Edge and an X Value
+*/
+
+static void cedgemax(h, e1, x)
+ register int h;
+ register pel *e1;
+ register pel x;
+{
+ for (; --h >= 0; e1++)
+ if (*e1 < x)
+ *e1 = x;
+}
+/*
+:h3.edgemin() - Stores the Mininum of Two Edges in First Edge
+*/
+
+static void edgemin(h, e1, e2)
+ register int h;
+ register pel *e1,*e2;
+{
+ for (; --h >= 0; e1++,e2++)
+ if (*e1 > *e2)
+ *e1 = *e2;
+}
+/*
+:h3.edgemax() - Stores the Maximum of Two Edges in First Edge
+*/
+
+static void edgemax(h, e1, e2)
+ register int h;
+ register pel *e1,*e2;
+{
+ for (; --h >= 0; e1++,e2++)
+ if (*e1 < *e2)
+ *e1 = *e2;
+}
+
+/*
+:h2.Changing the Representation of Regions
+
+For convenience and/or performance, we sometimes like to change the way
+regions are represented. This does not change the object itself, just
+the representation, so these transformations can be made on a permanent
+region.
+
+*/
+
+void
+MoveEdges(R, dx, dy)
+ register struct region *R; /* region to modify */
+ register fractpel dx,dy; /* delta X and Y to move edge list by */
+{
+ register struct edgelist *edge; /* for looping through edges */
+
+ R->origin.x += dx;
+ R->origin.y += dy;
+ R->ending.x += dx;
+ R->ending.y += dy;
+ if (R->thresholded != NULL) {
+ R->thresholded->origin.x -= dx;
+ R->thresholded->origin.y -= dy;
+ }
+/*
+From now on we will deal with dx and dy as integer pel values:
+*/
+ dx = NEARESTPEL(dx);
+ dy = NEARESTPEL(dy);
+ if (dx == 0 && dy == 0)
+ return;
+
+ R->xmin += dx;
+ R->xmax += dx;
+ R->ymin += dy;
+ R->ymax += dy;
+
+ for (edge = R->anchor; VALIDEDGE(edge); edge = edge->link) {
+ edge->ymin += dy;
+ edge->ymax += dy;
+ if (dx != 0) {
+ register int h; /* loop index; height of edge */
+ register pel *Xp; /* loop pointer to X values */
+
+ edge->xmin += dx;
+ edge->xmax += dx;
+ for (Xp = edge->xvalues, h = edge->ymax - edge->ymin;
+ --h >= 0; )
+ *Xp++ += dx;
+ }
+ }
+}
+
+/*
+:h3.UnJumble() - Sort a Region Top to Bottom
+
+It is an open question whether it pays in general to do this.
+*/
+
+void UnJumble(region)
+ struct region *region; /* region to sort */
+{
+ register struct edgelist *anchor; /* new lists built here */
+ register struct edgelist *edge; /* edge pointer for loop */
+ register struct edgelist *next; /* ditto */
+
+ anchor = NULL;
+
+ for (edge=region->anchor; VALIDEDGE(edge); edge=next) {
+ if (edge->link == NULL)
+ abort("UnJumble: unpaired edge?");
+ next = edge->link->link;
+ edge->link->link = NULL;
+ anchor = SortSwath(anchor, edge, t1_SwathUnion);
+ }
+
+ if (edge != NULL)
+ vertjoin(anchor, edge);
+
+ region->anchor = anchor;
+ region->flag &= ~ISJUMBLED(ON);
+}
+
+/*
+*/
+
+static void
+OptimizeRegion(R)
+ struct region *R; /* region to optimize */
+{
+ register pel *xP; /* pel pointer for inner loop */
+ register int x; /* holds X value */
+ register int xmin,xmax; /* holds X range */
+ register int h; /* loop counter */
+ register struct edgelist *e; /* edgelist pointer for loop */
+
+ R->flag |= ISRECTANGULAR(ON);
+
+ for (e = R->anchor; VALIDEDGE(e); e=e->link) {
+ xmin = MAXPEL;
+ xmax = MINPEL;
+ for (h = e->ymax - e->ymin, xP = e->xvalues; --h >= 0;) {
+ x = *xP++;
+ if (x < xmin) xmin = x;
+ if (x > xmax) xmax = x;
+ }
+ if (xmin != xmax || (xmin != R->xmin && xmax != R->xmax))
+ R->flag &= ~ISRECTANGULAR(ON);
+ if (xmin < e->xmin || xmax > e->xmax)
+ abort("Tighten: existing edge bound was bad");
+ if (xmin < R->xmin || xmax > R->xmax)
+ abort("Tighten: existing region bound was bad");
+ e->xmin = xmin;
+ e->xmax = xmax;
+ }
+ R->flag |= ISOPTIMIZED(ON);
+}
+
+/*
+:h2.Miscelaneous Routines
+
+:h3.MoreWorkArea() - Allocate New Space for "edge"
+
+Our strategy is to temporarily allocate an array to hold this
+unexpectedly large edge. ChangeDirection frees this array any time
+it gets a shorter 'dy'.
+*/
+
+/*ARGSUSED*/
+void MoreWorkArea(R, x1, y1, x2, y2)
+ struct region *R; /* region we are generating */
+ fractpel x1,y1; /* starting point of line */
+ fractpel x2,y2; /* ending point of line */
+{
+ register int idy; /* integer dy of line */
+
+ idy = NEARESTPEL(y1) - NEARESTPEL(y2);
+ if (idy < 0) idy = - idy;
+
+ /*
+ * we must add one to the delta for the number of run ends we
+ * need to store:
+ */
+ if (++idy > currentsize) {
+ IfTrace1((RegionDebug > 0),"Allocating edge of %d pels\n", idy);
+ if (currentworkarea != workedge)
+ NonObjectFree(currentworkarea);
+ currentworkarea = (pel *)Allocate(0, NULL, idy * sizeof(pel));
+ currentsize = idy;
+ }
+ ChangeDirection(CD_CONTINUE, R, x1, y1, y2 - y1);
+}
+
+/*
+:h3.BoxClip() - Clip a Region to a Rectangle
+
+BoxClip also duplicates the region if it is permanent. Note the
+clipping box is specified in REGION coordinates, that is, in
+coordinates relative to the region (0,0) point
+*/
+
+struct region *BoxClip(R, xmin, ymin, xmax, ymax)
+ register struct region *R; /* region to clip */
+ register pel xmin,ymin; /* upper left hand corner of rectangle */
+ register pel xmax,ymax; /* lower right hand corner */
+{
+ struct edgelist anchor; /* pretend edgelist to facilitate discards */
+ register struct edgelist *e,*laste;
+
+ IfTrace1((OffPageDebug),"BoxClip of %z:\n", R);
+
+ R = UniqueRegion(R);
+
+ if (xmin > R->xmin) {
+ IfTrace2((OffPageDebug),"BoxClip: left clip old %d new %d\n",
+ (long) R->xmin, (long) xmin);
+ R->xmin = xmin;
+ }
+ if (xmax < R->xmax) {
+ IfTrace2((OffPageDebug),"BoxClip: right clip old %d new %d\n",
+ (long) R->xmax, (long) xmax);
+ R->xmax = xmax;
+ }
+
+ if (ymin > R->ymin) {
+ IfTrace2((OffPageDebug),"BoxClip: top clip old %d new %d\n",
+ (long) R->ymin, (long) ymin);
+ R->ymin = ymin;
+ }
+ if (ymax < R->ymax) {
+ IfTrace2((OffPageDebug),"BoxClip: bottom clip old %d new %d\n",
+ (long) R->ymax, (long) ymax);
+ R->ymax = ymax;
+ }
+
+
+ laste = &anchor;
+ anchor.link = R->anchor;
+
+ for (e = R->anchor; VALIDEDGE(e); e = e->link) {
+ if (TOP(e) < ymin) {
+ e->xvalues += ymin - e->ymin;
+ e->ymin = ymin;
+ }
+ if (BOTTOM(e) > ymax)
+ e->ymax = ymax;
+ if (TOP(e) >= BOTTOM(e)) {
+ discard(laste, e->link->link);
+ e = laste;
+ continue;
+ }
+ if (e->xmin < xmin) {
+ cedgemax(BOTTOM(e) - TOP(e), e->xvalues, xmin);
+ e->xmin = xmin;
+ e->xmax = MAX(e->xmax, xmin);
+ }
+ if (e->xmax > xmax) {
+ cedgemin(BOTTOM(e) - TOP(e), e->xvalues, xmax);
+ e->xmin = MIN(e->xmin, xmax);
+ e->xmax = xmax;
+ }
+ laste = e;
+ }
+
+ R->anchor = anchor.link;
+
+ return(R);
+}
+
+#ifdef notdef
+/*
+:h3.CoerceRegion() - Force a TextPath Structure to Become a Region
+
+We also save the newly created region in the textpath structure, if the
+structure was permanent. Then we don't have to do this again. Why not
+save it all the time? Well, we certainly could, but I suspect it
+wouldn't pay. We would have to make this region permanent (because we
+couldn't have it be consumed) and this would probably require
+unnecessary CopyRegions in most cases.
+*/
+
+struct region *CoerceRegion(tp)
+ register struct textpath *tp; /* input TEXTTYPE */
+{
+ struct segment *path; /* temporary character path */
+ struct region *R; /* returned region */
+
+
+ R = Interior(path, EVENODDRULE);
+ return(R);
+}
+#endif
+
+/*
+:h3.RegionBounds() - Returns Bounding Box of a Region
+*/
+
+struct segment *RegionBounds(R)
+ register struct region *R;
+{
+ extern struct XYspace *IDENTITY;
+
+ register struct segment *path; /* returned path */
+
+ path = BoxPath(IDENTITY, R->ymax - R->ymin, R->xmax - R->xmin);
+ path = Join(PathSegment(MOVETYPE, R->origin.x + TOFRACTPEL(R->xmin),
+ R->origin.y + TOFRACTPEL(R->ymin) ),
+ path);
+ return(path);
+}
+
+/*
+:h2.Formatting/Dump Routines for Debug
+
+:h3.DumpArea() - Display a Region
+*/
+void DumpArea(area)
+ register struct region *area;
+{
+ IfTrace1(TRUE,"Dumping area %x,", area);
+ IfTrace4(TRUE," X %d:%d Y %d:%d;", (long) area->xmin,
+ (long) area->xmax, (long) area->ymin,(long) area->ymax);
+ IfTrace4(TRUE," origin=(%p,%p), ending=(%p,%p)\n",
+ area->origin.x, area->origin.y, area->ending.x, area->ending.y);
+ DumpEdges(area->anchor);
+}
+
+#define INSWATH(p, y0, y1) (p != NULL && p->ymin == y0 && p->ymax == y1)
+/*
+:h3.DumpEdges() - Display Run End Lists (Edge Lists)
+*/
+
+/*
+:h3.edgecheck() - For Debug, Verify that an Edge Obeys the Rules
+*/
+
+/*ARGSUSED*/
+static void
+edgecheck(edge, oldmin, oldmax)
+ struct edgelist *edge;
+ int oldmin,oldmax;
+{
+ if (edge->type != EDGETYPE)
+ abort("EDGE ERROR: non EDGETYPE in list");
+/*
+The following check is not valid if the region is jumbled so I took it
+out:
+*/
+/* if (edge->ymin < oldmax && edge->ymin != oldmin)
+ abort("EDGE ERROR: overlapping swaths"); */
+}
+
+static pel RegionDebugYMin = MINPEL;
+static pel RegionDebugYMax = MAXPEL;
+
+void DumpEdges(edges)
+ register struct edgelist *edges;
+{
+ register struct edgelist *p,*p2;
+ register pel ymin = MINPEL;
+ register pel ymax = MINPEL;
+ register int y;
+
+ if (edges == NULL) {
+ IfTrace0(TRUE," NULL area.\n");
+ return;
+ }
+ if (RegionDebug <= 1) {
+ for (p=edges; p != NULL; p = p->link) {
+ edgecheck(p, ymin, ymax);
+ ymin = p->ymin; ymax = p->ymax;
+ IfTrace3(TRUE,". at %x type=%d flag=%x",
+ p, (long) p->type,(long) p->flag);
+ IfTrace4(TRUE," bounding box HxW is %dx%d at (%d,%d)\n",
+ (long) ymax - ymin, (long) p->xmax - p->xmin,
+ (long) p->xmin, (long) ymin);
+ }
+ }
+ else {
+
+ for (p2=edges; p2 != NULL; ) {
+
+ edgecheck(p2, ymin, ymax);
+ ymin = p2->ymin;
+ ymax = p2->ymax;
+
+ if (RegionDebug > 3 || (ymax > RegionDebugYMin
+ && ymin < RegionDebugYMax)) {
+ IfTrace2 (TRUE,". Swath from %d to %d:\n",
+ ymin, ymax);
+ for (p=p2; INSWATH(p,ymin,ymax); p = p->link) {
+ IfTrace4(TRUE,". . at %x[%x] range %d:%d, ",
+ p, (long) p->flag,
+ (long) p->xmin, (long)p->xmax);
+ IfTrace1(TRUE, "subpath=%x,\n", p->subpath);
+ }
+ }
+ for (y=MAX(ymin,RegionDebugYMin); y < MIN(ymax, RegionDebugYMax); y++) {
+ IfTrace1(TRUE,". . . Y[%5d] ", (long) y);
+ for (p=p2; INSWATH(p,ymin,ymax); p = p->link)
+ IfTrace1(TRUE,"%5d ",
+ (long) p->xvalues[y - ymin]);
+ IfTrace0(TRUE,"\n");
+ }
+ while (INSWATH(p2, ymin, ymax))
+ p2 = p2->link;
+ }
+ }
+}
+
diff --git a/src/Type1/regions.h b/src/Type1/regions.h
new file mode 100644
index 0000000..3870cf4
--- /dev/null
+++ b/src/Type1/regions.h
@@ -0,0 +1,213 @@
+/* $Xorg: regions.h,v 1.3 2000/08/17 19:46:32 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+/*SHARED*/
+
+#define Interior(p,rule) t1_Interior(p,rule)
+#define Union(a1,a2) t1_Union(a1,a2)
+#define Intersect(a1,a2) t1_Intersect(a1,a2)
+#define Complement(area) t1_Complement(area)
+#define Overlap(a1,a2) t1_OverLap(a1,a2)
+
+struct region *t1_Interior(); /* returns the interior of a closed path */
+struct region *t1_Union(); /* set union of paths or regions */
+struct region *t1_Intersect(); /* set intersection of regions */
+struct region *t1_Complement(); /* complement of a region */
+int t1_Overlap(); /* returns a Boolean; TRUE if regions overlap */
+
+#define INFINITY t1_Infinity
+
+/*END SHARED*/
+/*SHARED*/
+
+#define ChangeDirection(type,R,x,y,dy) t1_ChangeDirection(type,R,x,y,dy)
+
+void t1_ChangeDirection(); /* called when we change direction in Y */
+#define CD_FIRST -1 /* enumeration of ChangeDirection type */
+#define CD_CONTINUE 0 /* enumeration of ChangeDirection type */
+#define CD_LAST 1 /* enumeration of ChangeDirection type */
+
+#define MoreWorkArea(R,x1,y1,x2,y2) t1_MoreWorkArea(R,x1,y1,x2,y2)
+#define KillRegion(area) t1_KillRegion(area)
+#define CopyRegion(area) t1_CopyRegion(area)
+#define BoxClip(R,xmin,ymin,xmax,ymax) t1_BoxClip(R,xmin,ymin,xmax,ymax)
+#define SortSwath(a,p,f) t1_SortSwath(a,p,f)
+#define SwathUnion(b,e) t1_SwathUnion(b,e)
+#define RegionBounds(r) t1_RegionBounds(r)
+#define CoerceRegion(p) t1_CoerceRegion(p)
+#define MoveEdges(R,dx,dy) t1_MoveEdges(R,dx,dy)
+#define UnJumble(R) t1_UnJumble(R)
+
+void t1_MoreWorkArea(); /* get longer edge list for stepping */
+struct region *t1_CopyRegion(); /* duplicate a region */
+void t1_KillRegion(); /* destroy a region */
+struct region *t1_BoxClip(); /* clip a region to a rectangle */
+struct edgelist *t1_SortSwath(); /* sort edges onto growing edge list */
+struct edgelist *t1_SwathUnion(); /* 'union' two edges into a swath */
+struct segment *t1_RegionBounds(); /* returns bounding box of a region */
+struct region *t1_CoerceRegion(); /* force text to become a true region */
+void t1_MoveEdges(); /* moves the edge values in a region */
+void t1_UnJumble(); /* sort the edges and reset the jumbled flag */
+
+/*END SHARED*/
+/*SHARED*/
+
+#define GOING_TO(R, x1, y1, x2, y2, dy) { \
+ if (dy < 0) { \
+ if (R->lastdy >= 0) \
+ ChangeDirection(CD_CONTINUE, R, x1, y1, dy); \
+ if (y2 < R->edgeYstop) \
+ MoreWorkArea(R, x1, y1, x2, y2); \
+ } \
+ else if (dy > 0) { \
+ if (R->lastdy <= 0) \
+ ChangeDirection(CD_CONTINUE, R, x1, y1, dy); \
+ if (y2 > R->edgeYstop) \
+ MoreWorkArea(R, x1, y1, x2, y2); \
+ } \
+ else /* dy == 0 */ ChangeDirection(CD_CONTINUE, R, x1, y1, dy); \
+ if (x2 < R->edgexmin) R->edgexmin = x2; \
+ else if (x2 > R->edgexmax) R->edgexmax = x2; \
+}
+
+#ifndef __sxg__
+#include <limits.h>
+#endif
+#ifdef SHRT_MIN
+#define MINPEL SHRT_MIN
+#else
+#define MINPEL ((pel)(-1<<(8*sizeof(pel)-1))) /* smallest value fitting in a pel */
+#endif
+#ifdef SHRT_MAX
+#define MAXPEL SHRT_MAX
+#else
+#define MAXPEL ((pel)((1<<(8*sizeof(pel)-1))-1))/* largest value fitting in a pel */
+#endif
+
+/*
+The "Unique"-type macro is different (unique?) for regions, because some
+regions structures are shared among several objects, and might have
+to be made unique for that reason (i.e., references > 1).
+*/
+
+#define ConsumeRegion(R) MAKECONSUME(R,KillRegion(R))
+#define UniqueRegion(R) MAKEUNIQUE(R,CopyRegion(R))
+
+
+/*END SHARED*/
+/*SHARED*/
+
+struct region {
+ XOBJ_COMMON /* xobject common data define 3-26-91 PNM */
+ /* type = REGIONTYPE */
+ struct fractpoint origin; /* beginning handle: X,Y origin of region */
+ struct fractpoint ending; /* ending handle: X,Y change after painting region */
+ pel xmin,ymin; /* minimum X,Y of region */
+ pel xmax,ymax; /* mat1_mum X,Y of region */
+ struct edgelist *anchor; /* list of edges that bound the region */
+ struct picture *thresholded; /* region defined by thresholded picture*/
+/*
+Note that the ending handle and the bounding box values are stored
+relative to 'origin'.
+
+The above elements describe a region. The following elements are
+scratchpad areas used while the region is being built:
+*/
+ fractpel lastdy; /* direction of last segment */
+ fractpel firstx,firsty; /* starting point of current edge */
+ fractpel edgexmin,edgexmax; /* x extent of current edge */
+ struct edgelist *lastedge,*firstedge; /* last and first edges in subpath */
+ pel *edge; /* pointer to array of X values for edge */
+ fractpel edgeYstop; /* Y value where 'edges' array ends */
+ void (*newedgefcn)(); /* function to use when building a new edge */
+ struct strokeinfo *strokeinfo; /* scratchpad info during stroking only */
+} ;
+/*
+The ISCOMPLEMENT flag indicates the region is reversed--it is the
+"outside" of the nominal region.
+*/
+#define ISCOMPLEMENT(flag) ((flag)&0x80)
+/*
+The ISJUMBLED flag indicates the region is not sorted top-to-bottom.
+*/
+#define ISJUMBLED(flag) ((flag)&0x40)
+/*
+The ISINFINITE flag allows a quick check for an INFINITE region, which
+is frequently intersected.
+*/
+#define ISINFINITE(flag) ((flag)&0x20)
+
+/*END SHARED*/
+/*SHARED*/
+
+#define ISRECTANGULAR(flag) ((flag)&0x08)
+
+/*END SHARED*/
+/*SHARED*/
+
+#define EmptyRegion t1_EmptyRegion
+
+/*END SHARED*/
+/*SHARED*/
+
+struct edgelist {
+ XOBJ_COMMON /* xobject common data define 3-26-91 PNM */
+ /* type = EDGETYPE */
+ struct edgelist *link; /* pointer to next in linked list */
+ struct edgelist *subpath; /* informational link for "same subpath" */
+ pel xmin,xmax; /* range of edge in X */
+ pel ymin,ymax; /* range of edge in Y */
+ pel *xvalues; /* pointer to ymax-ymin X values */
+} ;
+/*
+The end of the list is marked by either "link" being NULL, or by
+ymin == ymax. See :hdref refid=discard.. We define the VALIDEDGE
+predicate to test for the opposite of these conditions:
+*/
+
+#define VALIDEDGE(p) ((p)!=NULL&&(p)->ymin<(p)->ymax)
+
+/*END SHARED*/
+/*SHARED*/
+
+#define ISDOWN(f) ((f)&0x80)
+
+#define ISAMBIGUOUS(f) ((f)&0x40)
+
+/*END SHARED*/
+/*SHARED*/
+
+/*
+Interior() rule enumerations:
+*/
+#define WINDINGRULE -2
+#define EVENODDRULE -3
+
+#define CONTINUITY 0x80 /* can be added to above rules; e.g. WINDINGRULE+CONTINUITY */
+
+/*END SHARED*/
diff --git a/src/Type1/scanfont.c b/src/Type1/scanfont.c
new file mode 100644
index 0000000..71dd687
--- /dev/null
+++ b/src/Type1/scanfont.c
@@ -0,0 +1,1519 @@
+/* $Xorg: scanfont.c,v 1.4 2000/12/01 16:26:25 steve Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* Author: Katherine A. Hitchcock IBM Almaden Research Laboratory */
+
+#include <string.h>
+#include "t1stdio.h"
+#include "util.h"
+#include "token.h"
+#include "fontfcn.h"
+#include "blues.h"
+
+
+
+static int rc;
+static boolean InPrivateDict;
+static boolean WantFontInfo;
+static boolean TwoSubrs;
+static psobj inputFile;
+static psobj filterFile;
+static psobj *inputP;
+
+
+/**********************************************************************/
+/* Init_BuiltInEncoding() */
+/* */
+/* Initializes the StandardEncoding and ISOLatin1Encoding vector. */
+/* */
+/**********************************************************************/
+typedef struct /* Builtin Standard Encoding */
+{
+ int index;
+ char *name;
+} EncodingTable;
+
+static EncodingTable StdEnc[] = {
+ 040 , "space",
+ 041 , "exclam",
+ 042 , "quotedbl",
+ 043 , "numbersign",
+ 044 , "dollar",
+ 045 , "percent",
+ 046 , "ampersand",
+ 047 , "quoteright",
+ 050 , "parenleft",
+ 051 , "parenright",
+ 052 , "asterisk",
+ 053 , "plus",
+ 054 , "comma",
+ 055 , "hyphen",
+ 056 , "period",
+ 057 , "slash",
+ 060 , "zero",
+ 061 , "one",
+ 062 , "two",
+ 063 , "three",
+ 064 , "four",
+ 065 , "five",
+ 066 , "six",
+ 067 , "seven",
+ 070 , "eight",
+ 071 , "nine",
+ 072 , "colon",
+ 073 , "semicolon",
+ 074 , "less",
+ 075 , "equal",
+ 076 , "greater",
+ 077 , "question",
+ 0100 , "at",
+ 0101 , "A",
+ 0102 , "B",
+ 0103 , "C",
+ 0104 , "D",
+ 0105 , "E",
+ 0106 , "F",
+ 0107 , "G",
+ 0110 , "H",
+ 0111 , "I",
+ 0112 , "J",
+ 0113 , "K",
+ 0114 , "L",
+ 0115 , "M",
+ 0116 , "N",
+ 0117 , "O",
+ 0120 , "P",
+ 0121 , "Q",
+ 0122 , "R",
+ 0123 , "S",
+ 0124 , "T",
+ 0125 , "U",
+ 0126 , "V",
+ 0127 , "W",
+ 0130 , "X",
+ 0131 , "Y",
+ 0132 , "Z",
+ 0133 , "bracketleft",
+ 0134 , "backslash",
+ 0135 , "bracketright",
+ 0136 , "asciicircum",
+ 0137 , "underscore",
+ 0140 , "quoteleft",
+ 0141 , "a",
+ 0142 , "b",
+ 0143 , "c",
+ 0144 , "d",
+ 0145 , "e",
+ 0146 , "f",
+ 0147 , "g",
+ 0150 , "h",
+ 0151 , "i",
+ 0152 , "j",
+ 0153 , "k",
+ 0154 , "l",
+ 0155 , "m",
+ 0156 , "n",
+ 0157 , "o",
+ 0160 , "p",
+ 0161 , "q",
+ 0162 , "r",
+ 0163 , "s",
+ 0164 , "t",
+ 0165 , "u",
+ 0166 , "v",
+ 0167 , "w",
+ 0170 , "x",
+ 0171 , "y",
+ 0172 , "z",
+ 0173 , "braceleft",
+ 0174 , "bar",
+ 0175 , "braceright",
+ 0176 , "asciitilde",
+ 0241 , "exclamdown",
+ 0242 , "cent",
+ 0243 , "sterling",
+ 0244 , "fraction",
+ 0245 , "yen",
+ 0246 , "florin",
+ 0247 , "section",
+ 0250 , "currency",
+ 0251 , "quotesingle",
+ 0252 , "quotedblleft",
+ 0253 , "guillemotleft",
+ 0254 , "guilsinglleft",
+ 0255 , "guilsinglright",
+ 0256 , "fi",
+ 0257 , "fl",
+ 0261 , "endash",
+ 0262 , "dagger",
+ 0263 , "daggerdbl",
+ 0264 , "periodcentered",
+ 0266 , "paragraph",
+ 0267 , "bullet",
+ 0270 , "quotesinglbase",
+ 0271 , "quotedblbase",
+ 0272 , "quotedblright",
+ 0273 , "guillemotright",
+ 0274 , "ellipsis",
+ 0275 , "perthousand",
+ 0277 , "questiondown",
+ 0301 , "grave",
+ 0302 , "acute",
+ 0303 , "circumflex",
+ 0304 , "tilde",
+ 0305 , "macron",
+ 0306 , "breve",
+ 0307 , "dotaccent",
+ 0310 , "dieresis",
+ 0312 , "ring",
+ 0313 , "cedilla",
+ 0315 , "hungarumlaut",
+ 0316 , "ogonek",
+ 0317 , "caron",
+ 0320 , "emdash",
+ 0341 , "AE",
+ 0343 , "ordfeminine",
+ 0350 , "Lslash",
+ 0351 , "Oslash",
+ 0352 , "OE",
+ 0353 , "ordmasculine",
+ 0361 , "ae",
+ 0365 , "dotlessi",
+ 0370 , "lslash",
+ 0371 , "oslash",
+ 0372 , "oe",
+ 0373 , "germandbls",
+ 0, 0
+};
+
+static EncodingTable ISO8859Enc[] = {
+ 32, "space",
+ 33, "exclam",
+ 34, "quotedbl",
+ 35, "numbersign",
+ 36, "dollar",
+ 37, "percent",
+ 38, "ampersand",
+ 39, "quoteright",
+ 40, "parenleft",
+ 41, "parenright",
+ 42, "asterisk",
+ 43, "plus",
+ 44, "comma",
+ 45, "minus",
+ 46, "period",
+ 47, "slash",
+ 48, "zero",
+ 49, "one",
+ 50, "two",
+ 51, "three",
+ 52, "four",
+ 53, "five",
+ 54, "six",
+ 55, "seven",
+ 56, "eight",
+ 57, "nine",
+ 58, "colon",
+ 59, "semicolon",
+ 60, "less",
+ 61, "equal",
+ 62, "greater",
+ 63, "question",
+ 64, "at",
+ 65, "A",
+ 66, "B",
+ 67, "C",
+ 68, "D",
+ 69, "E",
+ 70, "F",
+ 71, "G",
+ 72, "H",
+ 73, "I",
+ 74, "J",
+ 75, "K",
+ 76, "L",
+ 77, "M",
+ 78, "N",
+ 79, "O",
+ 80, "P",
+ 81, "Q",
+ 82, "R",
+ 83, "S",
+ 84, "T",
+ 85, "U",
+ 86, "V",
+ 87, "W",
+ 88, "X",
+ 89, "Y",
+ 90, "Z",
+ 91, "bracketleft",
+ 92, "backslash",
+ 93, "bracketright",
+ 94, "asciicircum",
+ 95, "underscore",
+ 96, "quoteleft",
+ 97, "a",
+ 98, "b",
+ 99, "c",
+ 100, "d",
+ 101, "e",
+ 102, "f",
+ 103, "g",
+ 104, "h",
+ 105, "i",
+ 106, "j",
+ 107, "k",
+ 108, "l",
+ 109, "m",
+ 110, "n",
+ 111, "o",
+ 112, "p",
+ 113, "q",
+ 114, "r",
+ 115, "s",
+ 116, "t",
+ 117, "u",
+ 118, "v",
+ 119, "w",
+ 120, "x",
+ 121, "y",
+ 122, "z",
+ 123, "braceleft",
+ 124, "bar",
+ 125, "braceright",
+ 126, "asciitilde",
+ 161, "exclamdown",
+ 162, "cent",
+ 163, "sterling",
+ 164, "currency",
+ 165, "yen",
+ 166, "brokenbar",
+ 167, "section",
+ 168, "dieresis",
+ 169, "copyright",
+ 170, "ordfeminine",
+ 171, "guillemotleft",
+ 172, "logicalnot",
+ 173, "hyphen",
+ 174, "registered",
+ 175, "macron",
+ 176, "degree",
+ 177, "plusminus",
+ 178, "twosuperior",
+ 179, "threesuperior",
+ 180, "acute",
+ 181, "mu",
+ 182, "paragraph",
+ 183, "periodcentered",
+ 184, "cedilla",
+ 185, "onesuperior",
+ 186, "ordmasculine",
+ 187, "guillemotright",
+ 188, "onequarter",
+ 189, "onehalf",
+ 190, "threequarters",
+ 191, "questiondown",
+ 192, "Agrave",
+ 193, "Aacute",
+ 194, "Acircumflex",
+ 195, "Atilde",
+ 196, "Adieresis",
+ 197, "Aring",
+ 198, "AE",
+ 199, "Ccedilla",
+ 200, "Egrave",
+ 201, "Eacute",
+ 202, "Ecircumflex",
+ 203, "Edieresis",
+ 204, "Igrave",
+ 205, "Iacute",
+ 206, "Icircumflex",
+ 207, "Idieresis",
+ 208, "Eth",
+ 209, "Ntilde",
+ 210, "Ograve",
+ 211, "Oacute",
+ 212, "Ocircumflex",
+ 213, "Otilde",
+ 214, "Odieresis",
+ 215, "multiply",
+ 216, "Oslash",
+ 217, "Ugrave",
+ 218, "Uacute",
+ 219, "Ucircumflex",
+ 220, "Udieresis",
+ 221, "Yacute",
+ 222, "Thorn",
+ 223, "germandbls",
+ 224, "agrave",
+ 225, "aacute",
+ 226, "acircumflex",
+ 227, "atilde",
+ 228, "adieresis",
+ 229, "aring",
+ 230, "ae",
+ 231, "ccedilla",
+ 232, "egrave",
+ 233, "eacute",
+ 234, "ecircumflex",
+ 235, "edieresis",
+ 236, "igrave",
+ 237, "iacute",
+ 238, "icircumflex",
+ 239, "idieresis",
+ 240, "eth",
+ 241, "ntilde",
+ 242, "ograve",
+ 243, "oacute",
+ 244, "ocircumflex",
+ 245, "otilde",
+ 246, "odieresis",
+ 247, "divide",
+ 248, "oslash",
+ 249, "ugrave",
+ 250, "uacute",
+ 251, "ucircumflex",
+ 252, "udieresis",
+ 253, "yacute",
+ 254, "thorn",
+ 255, "ydieresis",
+ 0, 0
+};
+
+static psobj *StdEncArrayP = NULL;
+psobj *ISOLatin1EncArrayP = NULL;
+
+static psobj *MakeEncodingArrayP(encodingTable)
+ EncodingTable *encodingTable;
+{
+ int i;
+ psobj *encodingArrayP;
+
+ encodingArrayP = (psobj *)vm_alloc(256*(sizeof(psobj)));
+ if (!encodingArrayP)
+ return NULL;
+
+ /* initialize everything to .notdef */
+ for (i=0; i<256;i++)
+ objFormatName(&(encodingArrayP[i]),7, ".notdef");
+
+ for (i=0; encodingTable[i].name; i++)
+ {
+ objFormatName(&(encodingArrayP[encodingTable[i].index]),
+ strlen(encodingTable[i].name),
+ encodingTable[i].name);
+ }
+
+ return(encodingArrayP);
+}
+
+boolean Init_BuiltInEncoding()
+{
+ StdEncArrayP = MakeEncodingArrayP(StdEnc);
+ ISOLatin1EncArrayP = MakeEncodingArrayP(ISO8859Enc);
+ return (StdEncArrayP && ISOLatin1EncArrayP);
+}
+
+/********************************************************************/
+/***================================================================***/
+static int getNextValue(valueType)
+ int valueType;
+{
+ scan_token(inputP);
+ if (tokenType != valueType) {
+ return(SCAN_ERROR);
+ }
+ return(SCAN_OK);
+
+}
+/***================================================================***/
+/* This routine will set the global rc if there is an error */
+/***================================================================***/
+static int getInt()
+{
+ scan_token(inputP);
+ if (tokenType != TOKEN_INTEGER) {
+ rc = SCAN_ERROR;
+ return(0);
+ }
+ else {
+ return( tokenValue.integer);
+ }
+
+}
+/***================================================================***/
+/*
+ * See Sec 10.3 of ``Adobe Type 1 Font Format'' v1.1,
+ * for parsing Encoding.
+ */
+static int getEncoding(arrayP)
+ psobj *arrayP;
+{
+
+ scan_token(inputP);
+ if ((tokenType == TOKEN_NAME)
+ &&
+ (((tokenLength==16) && (!strncmp(tokenStartP,"StandardEncoding",16))) ||
+ (((tokenLength==17) && (!strncmp(tokenStartP,"ISOLatin1Encoding",17))))))
+ {
+ /* Adobe Standard Encoding */
+
+ if (tokenLength == 16)
+ arrayP->data.valueP = (char *) StdEncArrayP;
+ else
+ arrayP->data.valueP = (char *) ISOLatin1EncArrayP;
+
+ arrayP->len = 256;
+ return(SCAN_OK);
+ }
+ else if ( (tokenType == TOKEN_LEFT_BRACE) ||
+ (tokenType == TOKEN_LEFT_BRACKET) )
+ {
+ /* Array of literal names */
+
+ psobj *objP;
+ int i;
+
+ objP = (psobj *)vm_alloc(256*(sizeof(psobj)));
+ if (!(objP)) return(SCAN_OUT_OF_MEMORY);
+
+ arrayP->data.valueP = (char *) objP;
+ arrayP->len = 256;
+
+ for (i=0; i<256; i++, objP++)
+ {
+ scan_token(inputP);
+
+ if (tokenType != TOKEN_LITERAL_NAME)
+ return(SCAN_ERROR);
+
+ if (!(vm_alloc(tokenLength)) ) return(SCAN_OUT_OF_MEMORY);
+ objFormatName(objP,tokenLength,tokenStartP);
+ }
+
+ scan_token(inputP);
+ if ( (tokenType == TOKEN_RIGHT_BRACE) ||
+ (tokenType == TOKEN_RIGHT_BRACKET) )
+ return(SCAN_OK);
+ }
+ else
+ {
+ /* Must be sequences of ``dup <index> <charactername> put" */
+
+ psobj *objP;
+ int i;
+
+ objP = (psobj *)vm_alloc(256*(sizeof(psobj)));
+ if (!(objP)) return(SCAN_OUT_OF_MEMORY);
+
+ arrayP->data.valueP = (char *) objP;
+ arrayP->len = 256;
+
+ for (i=0; i<256; i++)
+ objFormatName(objP + i, 7, ".notdef");
+
+ while (TRUE)
+ {
+ scan_token(inputP);
+
+ switch (tokenType)
+ {
+ case TOKEN_NAME:
+ if (tokenLength == 3)
+ {
+ if (strncmp(tokenStartP,"dup",3) == 0)
+ {
+ /* get <index> */
+ scan_token(inputP);
+ if (tokenType != TOKEN_INTEGER ||
+ tokenValue.integer < 0 ||
+ tokenValue.integer > 255)
+ return (SCAN_ERROR);
+ i = tokenValue.integer;
+
+ /* get <characer_name> */
+ scan_token(inputP);
+ if (tokenType != TOKEN_LITERAL_NAME)
+ return(SCAN_ERROR);
+
+ if (!(vm_alloc(tokenLength)) )
+ return(SCAN_OUT_OF_MEMORY);
+ objFormatName(objP + i,tokenLength,tokenStartP);
+
+ /* get "put" */
+ scan_token(inputP);
+ if (tokenType != TOKEN_NAME)
+ return(SCAN_ERROR);
+ }
+ else if (strncmp(tokenStartP,"def",3) == 0)
+ return (SCAN_OK);
+ }
+ break;
+ case TOKEN_EOF:
+ case TOKEN_NONE:
+ case TOKEN_INVALID:
+ return (SCAN_ERROR);
+ }
+ }
+ }
+
+ return (SCAN_ERROR);
+}
+/***================================================================***/
+static int getArray(arrayP)
+ psobj *arrayP;
+{
+ int N; /* count the items in the array */
+ psobj *objP;
+ int scanning;
+ char *tmp; /* If some font file has /foo/foo,
+ * e.g. ftp://ftp.cdrom.com/pub/os2/fonts/future.zip
+ * we will treat it as /foo.
+ */
+
+ if (!(tmp = strdup(tokenStartP)))
+ return(SCAN_OUT_OF_MEMORY);
+
+ scanning = 1;
+ while (scanning == 1) {
+ scan_token(inputP);
+ switch (tokenType)
+ {
+ case TOKEN_LEFT_BRACE:
+ case TOKEN_LEFT_BRACKET:
+ scanning = 0;
+ break;
+
+ case TOKEN_LITERAL_NAME:
+ tokenStartP[tokenLength] = '\0';
+ if (strcmp (tokenStartP, tmp) == 0) {
+ /* Ok, if we see /foo/foo, let's go back to the top of the loop,
+ * otherwise drop out of the loop. */
+ continue;
+ }
+
+ default:
+ free(tmp);
+ return(SCAN_ERROR);
+ }
+ }
+ free(tmp);
+
+ /* format the array in memory, save pointer to the beginning */
+ arrayP->data.valueP = tokenStartP;
+ /* loop, picking up next object, until right BRACE or BRACKET */
+ N = 0;
+ do {
+ scan_token(inputP);
+ if ( (tokenType == TOKEN_RIGHT_BRACE) ||
+ (tokenType == TOKEN_RIGHT_BRACKET) ) {
+ /* save then number of items in the array */
+ arrayP->len = N;
+ return(SCAN_OK);
+ }
+ /* allocate the space for the object */
+ objP = (psobj *)vm_alloc(sizeof(psobj));
+ if (!(objP)) return(SCAN_OUT_OF_MEMORY);
+
+ /* array is an array of numbers, (real or integer) */
+ if (tokenType == TOKEN_REAL) {
+ objFormatReal(objP, tokenValue.real);
+ }
+ else
+ if (tokenType == TOKEN_INTEGER) {
+ objFormatInteger(objP, tokenValue.integer);
+ }
+ else return(SCAN_ERROR);
+ N++;
+ } while ( 1>0 );
+ /* NOTREACHED*/
+}
+/***================================================================***/
+static int getName(nameP)
+ char *nameP;
+{
+ do {
+ scan_token(inputP);
+ if (tokenType <= TOKEN_NONE) {
+ if (tokenTooLong) return(SCAN_OUT_OF_MEMORY);
+ return(SCAN_ERROR);
+ }
+ } while ((tokenType != TOKEN_NAME) ||
+ (0 != strncmp(tokenStartP,nameP,strlen(nameP))) );
+ /* found */
+ return(SCAN_OK);
+}
+/***================================================================***/
+static int getNbytes(N)
+ int N;
+{
+ int I;
+
+
+ tokenStartP = vm_next_byte();
+ tokenMaxP = tokenStartP + MIN(vm_free_bytes(), MAX_STRING_LEN);
+ if (N > vm_free_bytes()) {
+ return(SCAN_OUT_OF_MEMORY);
+ }
+ I = T1Read(tokenStartP,1,N,inputP->data.fileP);
+ if ( I != N ) return(SCAN_FILE_EOF);
+ return(SCAN_OK);
+}
+
+/***================================================================***/
+/* getLiteralName(nameObjP) */
+/* scan for next literal. */
+/* if we encounter the name 'end' then terminate and say ok. */
+/* It means that the CharStrings does not have as many characters */
+/* as the dictionary said it would and that is ok. */
+/***================================================================***/
+static int getLiteralName(nameObjP)
+ psobj *nameObjP;
+{
+ do {
+ scan_token(inputP);
+ if (tokenType <= TOKEN_NONE) {
+ if (tokenTooLong) return(SCAN_OUT_OF_MEMORY);
+ return(SCAN_ERROR);
+ }
+ if (tokenType == TOKEN_NAME) {
+ if (0 == strncmp(tokenStartP,"end",3) ) {
+ return(SCAN_END);
+ }
+ }
+ } while (tokenType != TOKEN_LITERAL_NAME) ;
+ nameObjP->len = tokenLength;
+ /* allocate all the names in the CharStrings Structure */
+ if (!(vm_alloc(tokenLength)) ) return(SCAN_OUT_OF_MEMORY);
+ nameObjP->data.valueP = tokenStartP;
+ /* found */
+ return(SCAN_OK);
+}
+
+/***================================================================***/
+/*
+ * BuildSubrs routine
+ */
+/***================================================================***/
+
+static int BuildSubrs(FontP)
+ psfont *FontP;
+{
+ int N; /* number of values in Subrs */
+ int I; /* index into Subrs */
+ int i; /* loop thru Subrs */
+ int J; /* length of Subrs entry */
+ psobj *arrayP;
+
+ /* next token should be a positive int */
+ /* note: rc is set by getInt. */
+ N = getInt();
+ if (rc) return(rc);
+ if (N < 0 ) return(SCAN_ERROR);
+ /* if we already have a Subrs, then skip the second one */
+ /* The second one is for hiresolution devices. */
+ if (FontP->Subrs.data.arrayP != NULL) {
+ TwoSubrs = TRUE;
+ /* process all the Subrs, but do not update anything */
+ /* can not just skip them because of the binary data */
+ for (i=0;i<N;i++) {
+ /* look for dup */
+ rc = getName("dup");
+ if (rc) return(rc);
+ /* get 2 integers */
+ I = getInt();
+ if (rc) return(rc);
+ J = getInt();
+ if (rc) return(rc);
+ if ( (I < 0) || (J < 0 ) ) return (SCAN_ERROR);
+ /* get the next token, it should be RD or -|, either is ok */
+ rc = getNextValue(TOKEN_NAME);
+ if ( rc != SCAN_OK ) return(rc);
+ rc = getNbytes(J);
+ if (rc) return(rc);
+ }
+ return(SCAN_OK);
+ }
+
+ arrayP = (psobj *)vm_alloc(N*sizeof(psobj));
+ if (!(arrayP) ) return(SCAN_OUT_OF_MEMORY);
+ FontP->Subrs.len = N;
+ FontP->Subrs.data.arrayP = arrayP;
+ /* get N values for Subrs */
+ for (i=0;i<N;i++) {
+ /* look for dup */
+ rc = getName("dup");
+ if (rc) return(rc);
+ /* get 2 integers */
+ I = getInt();
+ if (rc) return(rc);
+ J = getInt();
+ if (rc) return(rc);
+ if ( (I < 0) || (J < 0 ) ) return (SCAN_ERROR);
+ arrayP[I].len = J;
+ /* get the next token, it should be RD or -|, either is ok */
+ rc = getNextValue(TOKEN_NAME);
+ if ( rc != SCAN_OK ) return(rc);
+ rc = getNbytes(J);
+ if (rc == SCAN_OK) {
+ arrayP[I].data.valueP = tokenStartP;
+ if ( !(vm_alloc(J)) ) return(SCAN_OUT_OF_MEMORY);
+ }
+ else return(rc);
+ }
+ return(SCAN_OK);
+
+}
+/***================================================================***/
+/***================================================================***/
+/*
+ * BuildCharStrings routine
+ */
+/***================================================================***/
+
+static int BuildCharStrings(FontP)
+ psfont *FontP;
+{
+ int N; /* number of values in CharStrings */
+ int i; /* loop thru Subrs */
+ int J; /* length of Subrs entry */
+ psdict *dictP;
+
+ /* next token should be a positive int */
+ N = getInt();
+ if (rc) {
+ /* check if file had TwoSubrs, hi resolution stuff is in file*/
+ if (TwoSubrs) {
+ do {
+ scan_token(inputP);
+ if (tokenType <= TOKEN_NONE) {
+ if (tokenTooLong) return(SCAN_OUT_OF_MEMORY);
+ return(SCAN_ERROR);
+ }
+ } while (tokenType != TOKEN_INTEGER);
+ N = tokenValue.integer;
+ }
+ else return(rc); /* if next token was not an Int */
+ }
+ if (N<=0) return(SCAN_ERROR);
+ /* save number of entries in the dictionary */
+
+ dictP = (psdict *)vm_alloc((N+1)*sizeof(psdict));
+ if (!(dictP)) return(SCAN_OUT_OF_MEMORY);
+ FontP->CharStringsP = dictP;
+ dictP[0].key.len = N;
+ /* get N values for CharStrings */
+ for (i=1;i<=N;i++) {
+ /* look for next literal name */
+ rc = getLiteralName(&(dictP[i].key));
+ if (rc) return(rc);
+ /* get 1 integer */
+ J = getInt();
+ if (rc) return(rc); /* if next token was not an Int */
+ if (J<0) return (SCAN_ERROR);
+ dictP[i].value.len = J;
+ /* get the next token, it should be RD or -|, either is ok */
+ rc = getNextValue(TOKEN_NAME);
+ if ( rc != SCAN_OK ) return(rc);
+ rc = getNbytes(J);
+ if (rc == SCAN_OK) {
+ dictP[i].value.data.valueP = tokenStartP;
+ if ( !(vm_alloc(J)) ) return(SCAN_OUT_OF_MEMORY);
+ }
+ else return(rc);
+ }
+ return(SCAN_OK);
+
+}
+/***================================================================***/
+/***================================================================***/
+/*
+ * BuildFontInfo Dictionary
+ */
+/***================================================================***/
+static int BuildFontInfo(fontP)
+ psfont *fontP;
+{
+ psdict *dictP;
+
+ /* allocate the private dictionary */
+ dictP = (psdict *)vm_alloc(20*sizeof(psdict));
+ if (!(dictP)) return(SCAN_OUT_OF_MEMORY);
+
+ fontP->fontInfoP = dictP;
+ fontP->fontInfoP[0].key.len = 17; /* number of actual entries */
+ objFormatName(&(dictP[FONTNAME].key),8,"FontName");
+ objFormatName(&(dictP[FONTNAME].value),0,NULL);
+ objFormatName(&(dictP[PAINTTYPE].key),9,"PaintType");
+ objFormatInteger(&(dictP[PAINTTYPE].value),0);
+ objFormatName(&(dictP[FONTTYPENUM].key),8,"FontType");
+ objFormatInteger(&(dictP[FONTTYPENUM].value),0);
+ objFormatName(&(dictP[FONTMATRIX].key),10,"FontMatrix");
+ objFormatArray(&(dictP[FONTMATRIX].value),0,NULL);
+ objFormatName(&(dictP[FONTBBOX].key),8,"FontBBox");
+ objFormatArray(&(dictP[FONTBBOX].value),0,NULL);
+ objFormatName(&(dictP[ENCODING].key),8,"Encoding");
+ objFormatEncoding(&(dictP[ENCODING].value),0,NULL);
+ objFormatName(&(dictP[UNIQUEID].key),8,"UniqueID");
+ objFormatInteger(&(dictP[UNIQUEID].value),0);
+ objFormatName(&(dictP[STROKEWIDTH].key),11,"StrokeWidth");
+ objFormatReal(&(dictP[STROKEWIDTH].value),0.0);
+ objFormatName(&(dictP[VERSION].key),7,"version");
+ objFormatString(&(dictP[VERSION].value),0,NULL);
+ objFormatName(&(dictP[NOTICE].key),6,"Notice");
+ objFormatString(&(dictP[NOTICE].value),0,NULL);
+ objFormatName(&(dictP[FULLNAME].key),8,"FullName");
+ objFormatString(&(dictP[FULLNAME].value),0,NULL);
+ objFormatName(&(dictP[FAMILYNAME].key),10,"FamilyName");
+ objFormatString(&(dictP[FAMILYNAME].value),0,NULL);
+ objFormatName(&(dictP[WEIGHT].key),6,"Weight");
+ objFormatString(&(dictP[WEIGHT].value),0,NULL);
+ objFormatName(&(dictP[ITALICANGLE].key),11,"ItalicAngle");
+ objFormatReal(&(dictP[ITALICANGLE].value),0.0);
+ objFormatName(&(dictP[ISFIXEDPITCH].key),12,"isFixedPitch");
+ objFormatBoolean(&(dictP[ISFIXEDPITCH].value),FALSE);
+ objFormatName(&(dictP[UNDERLINEPOSITION].key),17,"UnderlinePosition");
+ objFormatReal(&(dictP[UNDERLINEPOSITION].value),0.0);
+ objFormatName(&(dictP[UNDERLINETHICKNESS].key),18,"UnderlineThickness");
+ objFormatReal(&(dictP[UNDERLINETHICKNESS].value),0.0);
+ return(SCAN_OK);
+}
+/***================================================================***/
+/*
+ * BuildPrivate Dictionary
+ */
+/***================================================================***/
+static int BuildPrivate(fontP)
+ psfont *fontP;
+{
+ psdict *Private;
+
+ /* allocate the private dictionary */
+ Private = (psdict *)vm_alloc(20*sizeof(psdict));
+
+ if (!(Private)) return(SCAN_OUT_OF_MEMORY);
+
+ fontP->Private = Private;
+ fontP->Private[0].key.len = 16; /* number of actual entries */
+
+ objFormatName(&(Private[BLUEVALUES].key),10,"BlueValues");
+ objFormatArray(&(Private[BLUEVALUES].value),0,NULL);
+ objFormatName(&(Private[OTHERBLUES].key),10,"OtherBlues");
+ objFormatArray(&(Private[OTHERBLUES].value),0,NULL);
+ objFormatName(&(Private[FAMILYBLUES].key),11,"FamilyBlues");
+ objFormatArray(&(Private[FAMILYBLUES].value),0,NULL);
+ objFormatName(&(Private[FAMILYOTHERBLUES].key),16,"FamilyOtherBlues");
+ objFormatArray(&(Private[FAMILYOTHERBLUES].value),0,NULL);
+ objFormatName(&(Private[BLUESCALE].key),9,"BlueScale");
+ objFormatReal(&(Private[BLUESCALE].value),DEFAULTBLUESCALE);
+ objFormatName(&(Private[BLUESHIFT].key),9,"BlueShift");
+ objFormatInteger(&(Private[BLUESHIFT].value),DEFAULTBLUESHIFT);
+ objFormatName(&(Private[BLUEFUZZ].key),8,"BlueFuzz");
+ objFormatInteger(&(Private[BLUEFUZZ].value),DEFAULTBLUEFUZZ);
+ objFormatName(&(Private[STDHW].key),5,"StdHW");
+ objFormatArray(&(Private[STDHW].value),0,NULL);
+ objFormatName(&(Private[STDVW].key),5,"StdVW");
+ objFormatArray(&(Private[STDVW].value),0,NULL);
+ objFormatName(&(Private[STEMSNAPH].key),9,"StemSnapH");
+ objFormatArray(&(Private[STEMSNAPH].value),0,NULL);
+ objFormatName(&(Private[STEMSNAPV].key),9,"StemSnapV");
+ objFormatArray(&(Private[STEMSNAPV].value),0,NULL);
+ objFormatName(&(Private[FORCEBOLD].key),9,"ForceBold");
+ objFormatBoolean(&(Private[FORCEBOLD].value),DEFAULTFORCEBOLD);
+ objFormatName(&(Private[LANGUAGEGROUP].key),13,"LanguageGroup");
+ objFormatInteger(&(Private[LANGUAGEGROUP].value),DEFAULTLANGUAGEGROUP);
+ objFormatName(&(Private[LENIV].key),5,"lenIV");
+ objFormatInteger(&(Private[LENIV].value),DEFAULTLENIV);
+ objFormatName(&(Private[RNDSTEMUP].key),9,"RndStemUp");
+ objFormatBoolean(&(Private[RNDSTEMUP].value),DEFAULTRNDSTEMUP);
+ objFormatName(&(Private[EXPANSIONFACTOR].key),9,"ExpansionFactor");
+ objFormatReal(&(Private[EXPANSIONFACTOR].value),
+ DEFAULTEXPANSIONFACTOR);
+ return(SCAN_OK);
+}
+/***================================================================***/
+/**********************************************************************/
+/* GetType1Blues(fontP) */
+/* */
+/* Routine to support font-level hints. */
+/* */
+/* Gets all the Blues information from the Private dictionary */
+/* for the font. */
+/* */
+/* */
+/**********************************************************************/
+static int GetType1Blues(fontP)
+ psfont *fontP;
+{
+ psdict *PrivateDictP; /* the Private dict relating to hints */
+ struct blues_struct *blues; /* ptr for the blues struct we will allocate */
+ int i;
+ psobj *HintEntryP;
+
+
+
+ /* get the Private dictionary pointer */
+ PrivateDictP = fontP->Private;
+
+ /* allocate the memory for the blues structure */
+ blues = (struct blues_struct *) vm_alloc(sizeof(struct blues_struct));
+
+ if (!blues) return(SCAN_OUT_OF_MEMORY);
+
+ /* Make fontP's blues ptr point to this newly allocated structure. */
+ fontP->BluesP = blues;
+
+ /* fill in the BlueValues array */
+ HintEntryP = &(PrivateDictP[BLUEVALUES].value);
+ /* check to see if the entry exists and if it's an array */
+ if ( !objPIsArray(HintEntryP) || (HintEntryP->len == 0 ))
+ blues->numBlueValues = 0;
+ else {
+ /* get the number of values in the array */
+ if (HintEntryP->len > NUMBLUEVALUES) {
+ blues->numBlueValues = NUMBLUEVALUES;
+ } else
+ blues->numBlueValues = HintEntryP->len;
+ for (i = 0; i<= blues->numBlueValues-1; ++i) {
+ if (objPIsInteger(&HintEntryP->data.arrayP[i]))
+ blues->BlueValues[i] =
+ HintEntryP->data.arrayP[i].data.integer;
+ else if (objPIsReal(&HintEntryP->data.arrayP[i]))
+ blues->BlueValues[i] =
+ HintEntryP->data.arrayP[i].data.real;
+ else
+ blues->BlueValues[i] = 0;
+ }
+ }
+
+ /* fill in the OtherBlues array */
+ HintEntryP = &(PrivateDictP[OTHERBLUES].value);
+ /* check to see if the entry exists and if it's an array */
+ if ( !objPIsArray(HintEntryP) || (HintEntryP->len == 0 ))
+ blues->numOtherBlues = 0;
+ else {
+ /* get the number of values in the array */
+ if (HintEntryP->len > NUMOTHERBLUES) {
+ blues->numOtherBlues = NUMOTHERBLUES;
+ } else
+ blues->numOtherBlues = HintEntryP->len;
+ for (i = 0; i<= blues->numOtherBlues-1; ++i) {
+ if (objPIsInteger(&HintEntryP->data.arrayP[i]))
+ blues->OtherBlues[i] =
+ HintEntryP->data.arrayP[i].data.integer;
+ else if (objPIsReal(&HintEntryP->data.arrayP[i]))
+ blues->OtherBlues[i] =
+ HintEntryP->data.arrayP[i].data.real;
+ else
+ blues->OtherBlues[i] = 0;
+ }
+ }
+
+ /* fill in the FamilyBlues array */
+ HintEntryP = &(PrivateDictP[FAMILYBLUES].value);
+ /* check to see if the entry exists and if it's an array */
+ if ( !objPIsArray(HintEntryP) || (HintEntryP->len == 0 ))
+ blues->numFamilyBlues = 0;
+ else {
+ /* get the number of values in the array */
+ if (HintEntryP->len > NUMFAMILYBLUES) {
+ blues->numFamilyBlues = NUMFAMILYBLUES;
+ } else
+ blues->numFamilyBlues = HintEntryP->len;
+ for (i = 0; i<= blues->numFamilyBlues-1; ++i) {
+ if (objPIsInteger(&HintEntryP->data.arrayP[i]))
+ blues->FamilyBlues[i] =
+ HintEntryP->data.arrayP[i].data.integer;
+ else if (objPIsReal(&HintEntryP->data.arrayP[i]))
+ blues->FamilyBlues[i] =
+ HintEntryP->data.arrayP[i].data.real;
+ else
+ blues->FamilyBlues[i] = 0;
+ }
+ }
+
+ /* fill in the FamilyOtherBlues array */
+ HintEntryP = &(PrivateDictP[FAMILYOTHERBLUES].value);
+ /* check to see if the entry exists and if it's an array */
+ if ( !objPIsArray(HintEntryP) || (HintEntryP->len == 0 ))
+ blues->numFamilyOtherBlues = 0;
+ else {
+ /* get the number of values in the array */
+ if (HintEntryP->len > NUMFAMILYOTHERBLUES) {
+ blues->numFamilyOtherBlues = NUMFAMILYOTHERBLUES;
+ } else
+ blues->numFamilyOtherBlues = HintEntryP->len;
+ for (i = 0; i<= blues->numFamilyOtherBlues-1; ++i) {
+ if (objPIsInteger(&HintEntryP->data.arrayP[i]))
+ blues->FamilyOtherBlues[i] =
+ HintEntryP->data.arrayP[i].data.integer;
+ else if (objPIsReal(&HintEntryP->data.arrayP[i]))
+ blues->FamilyOtherBlues[i] =
+ HintEntryP->data.arrayP[i].data.real;
+ else
+ blues->FamilyOtherBlues[i] = 0;
+ }
+ }
+
+ /* fill in the StemSnapH array */
+ HintEntryP = &(PrivateDictP[STEMSNAPH].value);
+ /* check to see if the entry exists and if it's an array */
+ if ( !objPIsArray(HintEntryP) || (HintEntryP->len == 0 ))
+ blues->numStemSnapH = 0;
+ else {
+ /* get the number of values in the array */
+ if (HintEntryP->len > NUMSTEMSNAPH) {
+ blues->numStemSnapH = NUMSTEMSNAPH;
+ } else
+ blues->numStemSnapH = HintEntryP->len;
+ for (i = 0; i<= blues->numStemSnapH-1; ++i) {
+ if (objPIsInteger(&HintEntryP->data.arrayP[i]))
+ blues->StemSnapH[i] =
+ HintEntryP->data.arrayP[i].data.integer;
+ else if (objPIsReal(&HintEntryP->data.arrayP[i]))
+ blues->StemSnapH[i] =
+ HintEntryP->data.arrayP[i].data.real;
+ else
+ blues->StemSnapH[i] = 0;
+ }
+ }
+
+ /* fill in the StemSnapV array */
+ HintEntryP = &(PrivateDictP[STEMSNAPV].value);
+ /* check to see if the entry exists and if it's an array */
+ if ( !objPIsArray(HintEntryP) || (HintEntryP->len == 0 ))
+ blues->numStemSnapV = 0;
+ else {
+ /* get the number of values in the array */
+ if (HintEntryP->len > NUMSTEMSNAPV) {
+ blues->numStemSnapV = NUMSTEMSNAPV;
+ } else
+ blues->numStemSnapV = HintEntryP->len;
+ for (i = 0; i<= blues->numStemSnapV-1; ++i) {
+ if (objPIsInteger(&HintEntryP->data.arrayP[i]))
+ blues->StemSnapV[i] =
+ HintEntryP->data.arrayP[i].data.integer;
+ else if (objPIsReal(&HintEntryP->data.arrayP[i]))
+ blues->StemSnapV[i] =
+ HintEntryP->data.arrayP[i].data.real;
+ else
+ blues->StemSnapV[i] = 0;
+ }
+ }
+
+ /* fill in the StdVW array */
+ HintEntryP = &(PrivateDictP[STDVW].value);
+ /* check to see if the entry exists and if it's an array */
+ if ( !objPIsArray(HintEntryP) || (HintEntryP->len == 0 ))
+ /* a value of zero signifies no entry */
+ blues->StdVW = 0;
+ else {
+ if (HintEntryP->len > NUMSTDVW) {
+ }
+ if (objPIsInteger(&HintEntryP->data.arrayP[0]))
+ blues->StdVW = HintEntryP->data.arrayP[0].data.integer;
+ else if (objPIsReal(&HintEntryP->data.arrayP[0]))
+ blues->StdVW = HintEntryP->data.arrayP[0].data.real;
+ else
+ blues->StdVW = 0;
+ }
+
+ /* fill in the StdHW array */
+ HintEntryP = &(PrivateDictP[STDHW].value);
+ /* check to see if the entry exists and if it's an array */
+ if ( !objPIsArray(HintEntryP) || (HintEntryP->len == 0 ))
+ /* a value of zero signifies no entry */
+ blues->StdHW = 0;
+ else {
+ if (HintEntryP->len > NUMSTDHW) {
+ }
+ if (objPIsInteger(&HintEntryP->data.arrayP[0]))
+ blues->StdHW = HintEntryP->data.arrayP[0].data.integer;
+ else if (objPIsReal(&HintEntryP->data.arrayP[0]))
+ blues->StdHW = HintEntryP->data.arrayP[0].data.real;
+ else
+ blues->StdHW = 0;
+ }
+
+
+ /* get the ptr to the BlueScale entry */
+ HintEntryP = &(PrivateDictP[BLUESCALE].value);
+ /* put the BlueScale in the blues structure */
+ if (objPIsInteger(HintEntryP)) /* Must be integer! */
+ blues->BlueScale = HintEntryP->data.integer;
+ else if (objPIsReal(HintEntryP)) /* Error? */
+ blues->BlueScale = HintEntryP->data.real;
+ else
+ blues->BlueScale = DEFAULTBLUESCALE;
+
+ /* get the ptr to the BlueShift entry */
+ HintEntryP = &(PrivateDictP[BLUESHIFT].value);
+ if (objPIsInteger(HintEntryP)) /* Must be integer! */
+ blues->BlueShift = HintEntryP->data.integer;
+ else if (objPIsReal(HintEntryP)) /* Error? */
+ blues->BlueShift = HintEntryP->data.real;
+ else
+ blues->BlueShift = DEFAULTBLUESHIFT;
+
+ /* get the ptr to the BlueFuzz entry */
+ HintEntryP = &(PrivateDictP[BLUEFUZZ].value);
+ if (objPIsInteger(HintEntryP)) /* Must be integer! */
+ blues->BlueFuzz = HintEntryP->data.integer;
+ else if (objPIsReal(HintEntryP)) /* Error? */
+ blues->BlueFuzz = HintEntryP->data.real;
+ else
+ blues->BlueFuzz = DEFAULTBLUEFUZZ;
+
+ /* get the ptr to the ForceBold entry */
+ HintEntryP = &(PrivateDictP[FORCEBOLD].value);
+ if (objPIsBoolean(HintEntryP)) /* Must be integer! */
+ blues->ForceBold = HintEntryP->data.boolean;
+ else
+ blues->ForceBold = DEFAULTFORCEBOLD;
+
+ /* get the ptr to the LanguageGroup entry */
+ HintEntryP = &(PrivateDictP[LANGUAGEGROUP].value);
+ if (objPIsInteger(HintEntryP)) /* Must be integer! */
+ blues->LanguageGroup = HintEntryP->data.integer;
+ else
+ blues->LanguageGroup = DEFAULTLANGUAGEGROUP;
+
+ /* get the ptr to the RndStemUp entry */
+ HintEntryP = &(PrivateDictP[RNDSTEMUP].value);
+ if (objPIsBoolean(HintEntryP)) /* Must be integer! */
+ blues->RndStemUp = HintEntryP->data.boolean;
+ else
+ blues->RndStemUp = DEFAULTRNDSTEMUP;
+
+ /* get the ptr to the lenIV entry */
+ HintEntryP = &(PrivateDictP[LENIV].value);
+ if (objPIsInteger(HintEntryP)) /* Must be integer! */
+ blues->lenIV = HintEntryP->data.integer;
+ else
+ blues->lenIV = DEFAULTLENIV;
+
+ /* get the ptr to the ExpansionFactor entry */
+ HintEntryP = &(PrivateDictP[EXPANSIONFACTOR].value);
+ if (objPIsInteger(HintEntryP))
+ blues->ExpansionFactor = HintEntryP->data.integer;
+ else if (objPIsReal(HintEntryP))
+ blues->ExpansionFactor = HintEntryP->data.real;
+ else
+ blues->ExpansionFactor = DEFAULTEXPANSIONFACTOR;
+ return(SCAN_OK);
+}
+/**********************************************************************/
+/* GetType1CharString(fontP,code) */
+/* */
+/* Look up code in the standard encoding vector and return */
+/* the charstring associated with the character name. */
+/* */
+/* fontP is the psfont structure. */
+/* */
+/* Returns a psobj (string) */
+/**********************************************************************/
+psobj *GetType1CharString(fontP, code)
+psfont *fontP;
+unsigned char code;
+{
+ int N; /* the 'Nth' entry in the CharStrings */
+ psobj *charnameP; /* points to psobj that is name of character*/
+
+ psdict *CharStringsDictP; /* dictionary with char strings */
+ psobj *theStringP; /* the definition for the code */
+
+
+
+ if (StdEncArrayP == NULL) {
+ return(NULL);
+ }
+ /* use the code to index into the standard encoding vector */
+ charnameP = &(StdEncArrayP[code]);
+
+ /* test if the encoding array points to a name */
+ if (!(objPIsName(charnameP)) ) {
+ return(NULL);
+ }
+
+ /* Now that we have the character name out of the standardencoding */
+ /* get the character definition out of the current font */
+ CharStringsDictP = fontP->CharStringsP;
+
+ /* search the chars string for this charname as key */
+ N = SearchDictName(CharStringsDictP,charnameP);
+ if (N<=0) {
+ return(NULL);
+ }
+ /* OK, the nth item is the psobj that is the string for this char */
+ theStringP = &(CharStringsDictP[N].value);
+
+ return(theStringP);
+}
+
+/***================================================================***/
+/*
+ * FindDictValue
+ */
+/***================================================================***/
+
+static int FindDictValue(dictP)
+ psdict *dictP;
+{
+ psobj LitName;
+ int N;
+ int V;
+
+ /* we have just scanned a token and it is a literal name */
+ /* need to check if that name is in Private dictionary */
+ objFormatName(&LitName,tokenLength,tokenStartP);
+ /* is it in the dictP */
+ N = SearchDictName(dictP,&LitName);
+ /* if found */
+ if ( N > 0 ) {
+ /* what type */
+ switch (dictP[N].value.type) {
+ case OBJ_ENCODING:
+ V = getEncoding(&(dictP[N].value));
+ if ( V != SCAN_OK ) return(V);
+ break;
+ case OBJ_ARRAY:
+ V = getArray(&(dictP[N].value));
+ if ( V != SCAN_OK ) return(V);
+ break;
+ case OBJ_INTEGER:
+ /* next value in integer */
+ dictP[N].value.data.integer = getInt();
+ if (rc) return(rc); /* if next token was not an Int */
+ break;
+ case OBJ_REAL:
+ /* next value must be real or int, store as a real */
+ scan_token(inputP);
+ if (tokenType == TOKEN_REAL) {
+ dictP[N].value.data.real = tokenValue.real;
+ }
+ else
+ if (tokenType == TOKEN_INTEGER) {
+ dictP[N].value.data.real = tokenValue.integer;
+ }
+ else return(SCAN_ERROR);
+ break;
+ case OBJ_NAME:
+ V = getNextValue(TOKEN_LITERAL_NAME);
+ if ( V != SCAN_OK ) return(V);
+ if (!(vm_alloc(tokenLength)) ) return(SCAN_OUT_OF_MEMORY);
+ objFormatName(&(dictP[N].value),tokenLength,tokenStartP);
+ break;
+ case OBJ_STRING:
+ V = getNextValue(TOKEN_STRING);
+ if ( V != SCAN_OK ) return(V);
+ if (!(vm_alloc(tokenLength)) ) return(SCAN_OUT_OF_MEMORY);
+ objFormatString(&(dictP[N].value),tokenLength,tokenStartP);
+ break;
+ case OBJ_BOOLEAN:
+ scan_token(inputP);
+ if (tokenType != TOKEN_NAME) {
+ return(SCAN_ERROR);
+ }
+ if (0 == strncmp(tokenStartP,"true",4) ) {
+ dictP[N].value.data.boolean =TRUE;
+ }
+ else
+ if (0 == strncmp(tokenStartP,"false",5) ) {
+ dictP[N].value.data.boolean =FALSE;
+ }
+ else return(SCAN_ERROR);
+ break;
+
+ default:
+ return(SCAN_ERROR);
+ }
+ }
+ /* Name is not in dictionary. That is ok. */
+ return(SCAN_OK);
+
+}
+/***================================================================***/
+
+/*
+ * -------------------------------------------------------------------
+ * Scan the next token and convert it into an object
+ * Result is placed on the Operand Stack as next object
+ * -------------------------------------------------------------------
+ */
+int scan_font(FontP)
+ psfont *FontP;
+{
+
+
+ char filename[128];
+ char filetype[3];
+ FILE *fileP;
+ char *nameP;
+ int namelen;
+ int V;
+ int i;
+ boolean starthex80;
+
+ starthex80 = FALSE;
+ filetype[0] = 'r';
+ filetype[1] = 'b';
+ filetype[2] = '\0';
+ /* copy the filename and remove leading or trailing blanks */
+ /* point to name and search for leading blanks */
+ nameP= FontP->FontFileName.data.nameP;
+ namelen = FontP->FontFileName.len;
+ while (nameP[0] == ' ') {
+ nameP++;
+ namelen--;
+ }
+ /* now remove any trailing blanks */
+ while ((namelen>0) && ( nameP[namelen-1] == ' ')) {
+ namelen--;
+ }
+ strncpy(filename,nameP,namelen);
+ filename[namelen] = '\0';
+ /* file name is now constructed */
+ inputFile.data.fileP = NULL;
+ filterFile.data.fileP = NULL;
+
+ inputP = &inputFile;
+ if (fileP = T1Open(filename,filetype)) {
+ /* get the first byte of file */
+ V = _XT1getc(fileP);
+ /* if file starts with x'80' then skip next 5 bytes */
+ if ( V == 0X80 ) {
+ for (i=0;i<5;i++) V = _XT1getc(fileP);
+ starthex80 = TRUE;
+ }
+ else T1Ungetc(V,fileP);
+ objFormatFile(inputP,fileP);
+ }
+ else {
+ return(SCAN_FILE_OPEN_ERROR);
+ };
+
+ WantFontInfo = TRUE;
+ InPrivateDict = FALSE;
+ TwoSubrs = FALSE;
+ rc = BuildFontInfo(FontP);
+ if (rc != 0) return(rc);
+
+ /* Assume everything will be OK */
+ rc = 0;
+
+ /* Loop until complete font is read */
+ do {
+ /* Scan the next token */
+ scan_token(inputP);
+
+ /* ==> tokenLength, tokenTooLong, tokenType, and tokenValue are */
+ /* now set */
+
+ switch (tokenType) {
+ case TOKEN_EOF:
+ case TOKEN_NONE:
+ case TOKEN_INVALID:
+ /* in this case we are done */
+ if (tokenTooLong) return(SCAN_OUT_OF_MEMORY);
+ rc = SCAN_ERROR;
+ break;
+ case TOKEN_LITERAL_NAME:
+ /* Look up the name */
+ tokenStartP[tokenLength] = '\0';
+ if (InPrivateDict ) {
+ if (0== strncmp(tokenStartP,"Subrs",5) ) {
+ rc = BuildSubrs(FontP);
+ break;
+ }
+ if (0== strncmp(tokenStartP,"CharStrings",11) ) {
+ rc = BuildCharStrings(FontP);
+ if ( (rc == SCAN_OK) ||(rc == SCAN_END) ) {
+ T1Close(inputP->data.fileP);
+ /* Build the Blues Structure */
+ rc = GetType1Blues(FontP);
+ /* whatever the return code, return it */
+ /* all the work is done. This is the normal exit.*/
+ return(rc);
+ }
+ break;
+ }
+ rc = FindDictValue(FontP->Private);
+ /* we are not going to report errors */
+ /* Sometimes the font file may test a value such as */
+ /* testing to see if the font is alreadly loaded with */
+ /* same UniqueID. We would faile on /UniqueID get */
+ /* because we are expecting a int to follow UniqueID*/
+ /* If the correct object type does not follow a Name*/
+ /* then we will skip over it without reporting error*/
+ rc = SCAN_OK;
+ break;
+ } /* end of reading Private dictionary */
+ else
+ if (0== strncmp(tokenStartP,"Private",7) ) {
+ InPrivateDict = TRUE;
+ rc = BuildPrivate(FontP);
+ break;
+ }
+ else
+ if (WantFontInfo) {
+ rc = FindDictValue(FontP->fontInfoP);
+ /* we are not going to report errors */
+ rc = SCAN_OK;
+ break;
+ }
+ break;
+ case TOKEN_NAME:
+ if (0 == strncmp(tokenStartP,"eexec",5) ) {
+ /* if file started with x'80', check next 5 bytes */
+ if (starthex80) {
+ V = _XT1getc(fileP);
+ if ( V == 0X80 ) {
+ for (i=0;i<5;i++) V = _XT1getc(fileP);
+ }
+ else T1Ungetc(V,fileP);
+ }
+ filterFile.data.fileP = T1eexec(inputP->data.fileP);
+ if (filterFile.data.fileP == NULL) {
+ T1Close(inputFile.data.fileP);
+ return(SCAN_FILE_OPEN_ERROR);
+ }
+ inputP = &filterFile;
+
+ WantFontInfo = FALSE;
+ }
+ break;
+ }
+
+ }
+ while (rc ==0);
+ T1Close(inputP->data.fileP);
+ if (tokenTooLong) return(SCAN_OUT_OF_MEMORY);
+ return(rc);
+}
+
diff --git a/src/Type1/spaces.c b/src/Type1/spaces.c
new file mode 100644
index 0000000..8b28d37
--- /dev/null
+++ b/src/Type1/spaces.c
@@ -0,0 +1,998 @@
+/* $Xorg: spaces.c,v 1.4 2000/08/17 19:46:32 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+ /* SPACES CWEB V0021 ******** */
+/*
+:h1 id=spaces.SPACES Module - Handles Coordinate Spaces
+
+This module is responsible for handling the TYPE1IMAGER "XYspace" object.
+
+&author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
+
+
+:h3.Include Files
+*/
+#include "objects.h"
+#include "spaces.h"
+#include "paths.h"
+#include "pictures.h"
+#include "fonts.h"
+#include "arith.h"
+#include "trig.h"
+
+static void FindFfcn();
+static void FindIfcn();
+/*
+:h3.Entry Points Provided to the TYPE1IMAGER User
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h3.Entry Points Provided to Other Modules
+*/
+
+/*
+In addition, other modules call the SPACES module through function
+vectors in the "XYspace" structure. The entry points accessed that
+way are "FConvert()", "IConvert()", and "ForceFloat()".
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h3.Macros and Typedefs Provided to Other Modules
+
+:h4.Duplicating and Killing Spaces
+
+Destroying XYspaces is so simple we can do it with a
+macro:
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+On the other hand, duplicating XYspaces is slightly more difficult
+because of the need to keep a unique ID in the space, see
+:hdref refid=dupspace..
+
+:h4.Fixed Point Pel Representation
+
+We represent pel positions with fixed point numbers. This does NOT
+mean integer, but truly means fixed point, with a certain number
+of binary digits (FRACTBITS) representing the fractional part of the
+pel.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+/*
+:h2.Data Structures for Coordinate Spaces and Points
+*/
+/*
+:h3 id=matrix.Matrices
+
+TYPE1IMAGER uses 2x2 transformation matrices. We'll use C notation for
+such a matrix (M[2][2]), the first index being rows, the second columns.
+*/
+
+/*
+:h3.The "doublematrix" Structure
+
+We frequently find it desirable to store both a matrix and its
+inverse. We store these in a "doublematrix" structure.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h3.The "XYspace" Structure
+
+The XYspace structure represents the XYspace object.
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+#define RESERVED 10 /* 'n' IDs are reserved for invalid & immortal spaces */
+/*
+*/
+#define NEXTID ((SpaceID < RESERVED) ? (SpaceID = RESERVED) : ++SpaceID)
+
+static unsigned int SpaceID = 1;
+
+struct XYspace *CopySpace(S)
+ register struct XYspace *S;
+{
+ S = (struct XYspace *)Allocate(sizeof(struct XYspace), S, 0);
+ S->ID = NEXTID;
+ return(S);
+}
+/*
+:h3.The "fractpoint" Structure
+
+A fractional point is just a "fractpel" x and y:
+*/
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+/*
+:h3.Lazy Evaluation of Matrix Inverses
+
+Calculating the inverse of a matrix is somewhat involved, and we usually
+do not need them. So, we flag whether or not the space has the inverse
+already calculated:
+*/
+
+#define HASINVERSE(flag) ((flag)&0x80)
+
+/*
+The following macro forces a space to have an inverse:
+*/
+
+#define CoerceInverse(S) if (!HASINVERSE((S)->flag)) { \
+ MatrixInvert((S)->tofract.normal, (S)->tofract.inverse); (S)->flag |= HASINVERSE(ON); }
+/*
+:h3.IDENTITY Space
+
+IDENTITY space is (logically) the space corresponding to the identity
+transformation matrix. However, since all our transformation matrices
+have a common FRACTFLOAT scale factor to convert to 'fractpel's, that
+is actually what we store in 'tofract' matrix of IDENTITY:
+*/
+
+static struct XYspace identity = { SPACETYPE, ISPERMANENT(ON) + ISIMMORTAL(ON)
+ + HASINVERSE(ON), 2, /* added 3-26-91 PNM */
+ NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ INVALIDID + 1, 0,
+ FRACTFLOAT, 0.0, 0.0, FRACTFLOAT,
+ 1.0/FRACTFLOAT, 0.0, 0.0, 1.0/FRACTFLOAT,
+ 0, 0, 0, 0 };
+struct XYspace *IDENTITY = &identity;
+
+/*
+*/
+#define MAXCONTEXTS 16
+
+static struct doublematrix contexts[MAXCONTEXTS];
+
+#ifdef notdef
+
+static int nextcontext = 1;
+
+/*SHARED LINE(S) ORIGINATED HERE*/
+
+#ifdef __STDC__
+#define pointer void *
+#else
+#define pointer char *
+#endif
+
+/*
+:h3.FindDeviceContext() - Find the Context Given a Device
+
+This routine, given a device, returns the index of the device's
+transformation matrix in the context array. If it cannot find it,
+it will allocate a new array entry and fill it out.
+*/
+
+static int FindDeviceContext(device)
+ pointer device; /* device token */
+{
+ double M[2][2]; /* temporary matrix */
+ float Xres,Yres; /* device resolution */
+ int orient = -1; /* device orientation */
+ int rc = -1; /* return code for QueryDeviceState */
+
+ if (rc != 0) /* we only bother with this check once */
+ abort("Context: QueryDeviceState didn't work");
+
+ M[0][0] = M[1][0] = M[0][1] = M[1][1] = 0.0;
+
+ switch (orient) {
+ case 0:
+ M[0][0] = Xres; M[1][1] = -Yres;
+ break;
+ case 1:
+ M[1][0] = Yres; M[0][1] = Xres;
+ break;
+ case 2:
+ M[0][0] = -Xres; M[1][1] = Yres;
+ break;
+ case 3:
+ M[1][0] = -Yres; M[0][1] = -Xres;
+ break;
+ default:
+ abort("QueryDeviceState returned invalid orientation");
+ }
+ return(FindContext(M));
+}
+
+/*
+:h3.FindContext() - Find the Context Given a Matrix
+
+This routine, given a matrix, returns the index of that matrix matrix in
+the context array. If it cannot find it, it will allocate a new array
+entry and fill it out.
+*/
+
+int FindContext(M)
+ double M[2][2]; /* array to search for */
+{
+ register int i; /* loop variable for search */
+ for (i=0; i < nextcontext; i++)
+ if (M[0][0] == contexts[i].normal[0][0] && M[1][0] == contexts[i].normal[1][0]
+ && M[0][1] == contexts[i].normal[0][1] && M[1][1] == contexts[i].normal[1][1])
+ break;
+
+ if (i >= nextcontext) {
+ if (i >= MAXCONTEXTS)
+ abort("Context: out of them");
+ LONGCOPY(contexts[i].normal, M, sizeof(contexts[i].normal));
+ MatrixInvert(M, contexts[i].inverse);
+ nextcontext++;
+ }
+
+ return(i);
+}
+
+/*
+:h3.Context() - Create a Coordinate Space for a Device
+
+This user operator is implemented by first finding the device context
+array index, then transforming IDENTITY space to create an appropriate
+cooridnate space.
+*/
+
+struct XYspace *Context(device, units)
+ pointer device; /* device token */
+ double units; /* multiples of one inch */
+{
+ double M[2][2]; /* device transformation matrix */
+ register int n; /* will hold device context number */
+ register struct XYspace *S; /* XYspace constructed */
+
+ IfTrace2((MustTraceCalls),"Context(%x, %f)\n", device, &units);
+
+ ARGCHECK((device == NULL), "Context of NULLDEVICE not allowed",
+ NULL, IDENTITY, (0), struct XYspace *);
+ ARGCHECK((units == 0.0), "Context: bad units", NULL, IDENTITY, (0), struct XYspace *);
+
+ n = FindDeviceContext(device);
+
+ LONGCOPY(M, contexts[n].normal, sizeof(M));
+
+ M[0][0] *= units;
+ M[0][1] *= units;
+ M[1][0] *= units;
+ M[1][1] *= units;
+
+ S = (struct XYspace *)Xform(IDENTITY, M);
+
+ S->context = n;
+ return(S);
+}
+#endif
+
+/*
+:h3.ConsiderContext() - Adjust a Matrix to Take Out Device Transform
+
+Remember, we have :f/x times U times D/ and :f/M/ and and we want :f/x
+times U times M times D/. An easy way to do this is to calculate
+:f/D sup <-1> times M times D/, because:
+:formula.
+x times U times D times D sup <-1> times M times D = x times U times M times D
+:formula.
+So this subroutine, given an :f/M/and an object, finds the :f/D/ for that
+object and modifies :f/M/ so it is :f/D sup <-1> times M times D/.
+*/
+
+static void ConsiderContext(obj, M)
+ register struct xobject *obj; /* object to be transformed */
+ register double M[2][2]; /* matrix (may be changed) */
+{
+ register int context; /* index in contexts array */
+
+ if (obj == NULL) return;
+
+ if (ISPATHTYPE(obj->type)) {
+ struct segment *path = (struct segment *) obj;
+
+ context = path->context;
+ }
+ else if (obj->type == SPACETYPE) {
+ struct XYspace *S = (struct XYspace *) obj;
+
+ context = S->context;
+ }
+ else if (obj->type == PICTURETYPE) {
+
+ }
+ else
+ context = NULLCONTEXT;
+
+ if (context != NULLCONTEXT) {
+ MatrixMultiply(contexts[context].inverse, M, M);
+ MatrixMultiply(M, contexts[context].normal, M);
+ }
+}
+
+/*
+:h2.Conversion from User's X,Y to "fractpel" X,Y
+
+When the user is building paths (lines, moves, curves, etc.) he passes
+the control points (x,y) for the paths together with an XYspace. We
+must convert from the user's (x,y) to our internal representation
+which is in pels (fractpels, actually). This involves transforming
+the user's (x,y) under the coordinate space transformation. It is
+important that we do this quickly. So, we store pointers to different
+conversion functions right in the XYspace structure. This allows us
+to have simpler special case functions for the more commonly
+encountered types of transformations.
+
+:h3.Convert(), IConvert(), and ForceFloat() - Called Through "XYspace" Structure
+
+These are functions that fit in the "convert" and "iconvert" function
+pointers in the XYspace structure. They call the "xconvert", "yconvert",
+"ixconvert", and "iyconvert" as appropriate to actually do the work.
+These secondary routines come in many flavors to handle different
+special cases as quickly as possible.
+*/
+
+static void FXYConvert(pt, S, x, y)
+ register struct fractpoint *pt; /* point to set */
+ register struct XYspace *S; /* relevant coordinate space */
+ register double x,y; /* user's coordinates of point */
+{
+ pt->x = (*S->xconvert)(S->tofract.normal[0][0], S->tofract.normal[1][0], x, y);
+ pt->y = (*S->yconvert)(S->tofract.normal[0][1], S->tofract.normal[1][1], x, y);
+}
+
+static void IXYConvert(pt, S, x, y)
+ register struct fractpoint *pt; /* point to set */
+ register struct XYspace *S; /* relevant coordinate space */
+ register long x,y; /* user's coordinates of point */
+{
+ pt->x = (*S->ixconvert)(S->itofract[0][0], S->itofract[1][0], x, y);
+ pt->y = (*S->iyconvert)(S->itofract[0][1], S->itofract[1][1], x, y);
+}
+
+/*
+ForceFloat is a substitute for IConvert(), when we just do not have
+enough significant digits in the coefficients to get high enough
+precision in the answer with fixed point arithmetic. So, we force the
+integers to floats, and do the arithmetic all with floats:
+*/
+
+static void ForceFloat(pt, S, x, y)
+ register struct fractpoint *pt; /* point to set */
+ register struct XYspace *S; /* relevant coordinate space */
+ register long x,y; /* user's coordinates of point */
+{
+ (*S->convert)(pt, S, (double) x, (double) y);
+}
+
+/*
+:h3.FXYboth(), FXonly(), FYonly() - Floating Point Conversion
+
+These are the routines we use when the user has given us floating
+point numbers for x and y. FXYboth() is the general purpose routine;
+FXonly() and FYonly() are special cases when one of the coefficients
+is 0.0.
+*/
+
+static fractpel FXYboth(cx, cy, x, y)
+ register double cx,cy; /* x and y coefficients */
+ register double x,y; /* user x,y */
+{
+ register double r; /* temporary float */
+
+ r = x * cx + y * cy;
+ return((fractpel) r);
+}
+
+/*ARGSUSED*/
+static fractpel FXonly(cx, cy, x, y)
+ register double cx,cy; /* x and y coefficients */
+ register double x,y; /* user x,y */
+{
+ register double r; /* temporary float */
+
+ r = x * cx;
+ return((fractpel) r);
+}
+
+/*ARGSUSED*/
+static fractpel FYonly(cx, cy, x, y)
+ register double cx,cy; /* x and y coefficients */
+ register double x,y; /* user x,y */
+{
+ register double r; /* temporary float */
+
+ r = y * cy;
+ return((fractpel) r);
+}
+
+/*
+:h3.IXYboth(), IXonly(), IYonly() - Simple Integer Conversion
+
+These are the routines we use when the user has given us integers for
+x and y, and the coefficients have enough significant digits to
+provide precise answers with only "long" (32 bit?) multiplication.
+IXYboth() is the general purpose routine; IXonly() and IYonly() are
+special cases when one of the coefficients is 0.
+*/
+
+static fractpel IXYboth(cx, cy, x, y)
+ register fractpel cx,cy; /* x and y coefficients */
+ register long x,y; /* user x,y */
+{
+ return(x * cx + y * cy);
+}
+
+/*ARGSUSED*/
+static fractpel IXonly(cx, cy, x, y)
+ register fractpel cx,cy; /* x and y coefficients */
+ register long x,y; /* user x,y */
+{
+ return(x * cx);
+}
+
+/*ARGSUSED*/
+static fractpel IYonly(cx, cy, x, y)
+ register fractpel cx,cy; /* x and y coefficients */
+ register long x,y; /* user x,y */
+{
+ return(y * cy);
+}
+
+
+/*
+:h3.FPXYboth(), FPXonly(), FPYonly() - More Involved Integer Conversion
+
+These are the routines we use when the user has given us integers for
+x and y, but the coefficients do not have enough significant digits to
+provide precise answers with only "long" (32 bit?) multiplication.
+We have increased the number of significant bits in the coefficients
+by FRACTBITS; therefore we must use "double long" (64 bit?)
+multiplication by calling FPmult(). FPXYboth() is the general purpose
+routine; FPXonly() and FPYonly() are special cases when one of the
+coefficients is 0.
+
+Note that it is perfectly possible for us to calculate X with the
+"FP" method and Y with the "I" method, or vice versa. It all depends
+on how the functions in the XYspace structure are filled out.
+*/
+
+static fractpel FPXYboth(cx, cy, x, y)
+ register fractpel cx,cy; /* x and y coefficients */
+ register long x,y; /* user x,y */
+{
+ return( FPmult(x, cx) + FPmult(y, cy) );
+}
+
+/*ARGSUSED*/
+static fractpel FPXonly(cx, cy, x, y)
+ register fractpel cx,cy; /* x and y coefficients */
+ register long x,y; /* user x,y */
+{
+ return( FPmult(x, cx) );
+}
+
+/*ARGSUSED*/
+static fractpel FPYonly(cx, cy, x, y)
+ register fractpel cx,cy; /* x and y coefficients */
+ register long x,y; /* user x,y */
+{
+ return( FPmult(y, cy) );
+}
+
+
+
+/*
+:h3.FillOutFcns() - Determine the Appropriate Functions to Use for Conversion
+
+This function fills out the "convert" and "iconvert" function pointers
+in an XYspace structure, and also fills the "helper"
+functions that actually do the work.
+*/
+
+static void FillOutFcns(S)
+ register struct XYspace *S; /* functions will be set in this structure */
+{
+ S->convert = FXYConvert;
+ S->iconvert = IXYConvert;
+
+ FindFfcn(S->tofract.normal[0][0], S->tofract.normal[1][0], &S->xconvert);
+ FindFfcn(S->tofract.normal[0][1], S->tofract.normal[1][1], &S->yconvert);
+ FindIfcn(S->tofract.normal[0][0], S->tofract.normal[1][0],
+ &S->itofract[0][0], &S->itofract[1][0], &S->ixconvert);
+ FindIfcn(S->tofract.normal[0][1], S->tofract.normal[1][1],
+ &S->itofract[0][1], &S->itofract[1][1], &S->iyconvert);
+
+ if (S->ixconvert == NULL || S->iyconvert == NULL)
+ S->iconvert = ForceFloat;
+}
+
+/*
+:h4.FindFfcn() - Subroutine of FillOutFcns() to Fill Out Floating Functions
+
+This function tests for the special case of one of the coefficients
+being zero:
+*/
+
+static void FindFfcn(cx, cy, fcnP)
+ register double cx,cy; /* x and y coefficients */
+ register fractpel (**fcnP)(); /* pointer to function to set */
+{
+ if (cx == 0.0)
+ *fcnP = FYonly;
+ else if (cy == 0.0)
+ *fcnP = FXonly;
+ else
+ *fcnP = FXYboth;
+}
+
+/*
+:h4.FindIfcn() - Subroutine of FillOutFcns() to Fill Out Integer Functions
+
+There are two types of integer functions, the 'I' type and the 'FP' type.
+We use the I type functions when we are satisfied with simple integer
+arithmetic. We used the FP functions when we feel we need higher
+precision (but still fixed point) arithmetic. If all else fails,
+we store a NULL indicating that this we should do the conversion in
+floating point.
+*/
+
+static void FindIfcn(cx, cy, icxP, icyP, fcnP)
+ register double cx,cy; /* x and y coefficients */
+ register fractpel *icxP,*icyP; /* fixed point coefficients to set */
+ register fractpel (**fcnP)(); /* pointer to function to set */
+{
+ register fractpel imax; /* maximum of cx and cy */
+
+ *icxP = cx;
+ *icyP = cy;
+
+ if (cx != (float) (*icxP) || cy != (float) (*icyP)) {
+/*
+At this point we know our integer approximations of the coefficients
+are not exact. However, we will still use them if the maximum
+coefficient will not fit in a 'fractpel'. Of course, we have little
+choice at that point, but we haven't lost that much precision by
+staying with integer arithmetic. We have enough significant digits
+so that
+any error we introduce is less than one part in 2:sup/16/.
+*/
+
+ imax = MAX(ABS(*icxP), ABS(*icyP));
+ if (imax < (fractpel) (1<<(FRACTBITS-1)) ) {
+/*
+At this point we know our integer approximations just do not have
+enough significant digits for accuracy. We will add FRACTBITS
+significant digits to the coefficients (by multiplying them by
+1<<FRACTBITS) and go to the "FP" form of the functions. First, we
+check to see if we have ANY significant digits at all (that is, if
+imax == 0). If we don't, we suspect that adding FRACTBITS digits
+won't help, so we punt the whole thing.
+*/
+ if (imax == 0) {
+ *fcnP = NULL;
+ return;
+ }
+ cx *= FRACTFLOAT;
+ cy *= FRACTFLOAT;
+ *icxP = cx;
+ *icyP = cy;
+ *fcnP = FPXYboth;
+ }
+ else
+ *fcnP = IXYboth;
+ }
+ else
+ *fcnP = IXYboth;
+/*
+Now we check for special cases where one coefficient is zero (after
+integer conversion):
+*/
+ if (*icxP == 0)
+ *fcnP = (*fcnP == FPXYboth) ? FPYonly : IYonly;
+ else if (*icyP == 0)
+ *fcnP = (*fcnP == FPXYboth) ? FPXonly : IXonly;
+}
+/*
+:h3.UnConvert() - Find User Coordinates From FractPoints
+
+The interesting thing with this routine is that we avoid calculating
+the matrix inverse of the device transformation until we really need
+it, which is to say, until this routine is called for the first time
+with a given coordinate space.
+
+We also only calculate it only once. If the inverted matrix is valid,
+we don't calculate it; if not, we do. We never expect matrices with
+zero determinants, so by convention, we mark the matrix is invalid by
+marking both X terms zero.
+*/
+
+void UnConvert(S, pt, xp, yp)
+ register struct XYspace *S; /* relevant coordinate space */
+ register struct fractpoint *pt; /* device coordinates */
+ double *xp,*yp; /* where to store resulting x,y */
+{
+ double x,y;
+
+ CoerceInverse(S);
+ x = pt->x;
+ y = pt->y;
+ *xp = S->tofract.inverse[0][0] * x + S->tofract.inverse[1][0] * y;
+ *yp = S->tofract.inverse[0][1] * x + S->tofract.inverse[1][1] * y;
+}
+
+/*
+:h2.Transformations
+*/
+/*
+:h3 id=xform.Xform() - Transform Object in X and Y
+
+TYPE1IMAGER wants transformations of objects like paths to be identical
+to transformations of spaces. For example, if you scale a line(1,1)
+by 10 it should yield the same result as generating the line(1,1) in
+a coordinate space that has been scaled by 10.
+
+We handle fonts by storing the accumulated transform, for example, SR
+(accumulating on the right). Then when we map the font through space TD,
+for example, we multiply the accumulated font transform on the left by
+the space transform on the right, yielding SRTD in this case. We will
+get the same result if we did S, then R, then T on the space and mapping
+an unmodified font through that space.
+*/
+
+struct xobject *t1_Xform(obj, M)
+ register struct xobject *obj; /* object to transform */
+ register double M[2][2]; /* transformation matrix */
+{
+ if (obj == NULL)
+ return(NULL);
+
+ if (obj->type == FONTTYPE) {
+ register struct font *F = (struct font *) obj;
+
+ F = UniqueFont(F);
+ return((struct xobject*)F);
+ }
+ if (obj->type == PICTURETYPE) {
+/*
+In the case of a picture, we choose both to update the picture's
+transformation matrix and keep the handles up to date.
+*/
+ register struct picture *P = (struct picture *) obj;
+ register struct segment *handles; /* temporary path to transform handles */
+
+ P = UniquePicture(P);
+ handles = PathSegment(LINETYPE, P->origin.x, P->origin.y);
+ handles = Join(handles,
+ PathSegment(LINETYPE, P->ending.x, P->ending.y) );
+ handles = (struct segment *)Xform((struct xobject *) handles, M);
+ P->origin = handles->dest;
+ P->ending = handles->link->dest;
+ KillPath(handles);
+ return((struct xobject *)P);
+ }
+
+ if (ISPATHTYPE(obj->type)) {
+ struct XYspace pseudo; /* local temporary space */
+ PseudoSpace(&pseudo, M);
+ return((struct xobject *) PathTransform(obj, &pseudo));
+ }
+
+
+ if (obj->type == SPACETYPE) {
+ register struct XYspace *S = (struct XYspace *) obj;
+
+/* replaced ISPERMANENT(S->flag) with S->references > 1 3-26-91 PNM */
+ if (S->references > 1)
+ S = CopySpace(S);
+ else
+ S->ID = NEXTID;
+
+ MatrixMultiply(S->tofract.normal, M, S->tofract.normal);
+ /*
+ * mark inverted matrix invalid:
+ */
+ S->flag &= ~HASINVERSE(ON);
+
+ FillOutFcns(S);
+ return((struct xobject *) S);
+ }
+
+ return(ArgErr("Untransformable object", obj, obj));
+}
+
+/*
+:h3.Transform() - Transform an Object
+
+This is the external user's entry point.
+*/
+struct xobject *t1_Transform(obj, cxx, cyx, cxy, cyy)
+ struct xobject *obj;
+ double cxx,cyx,cxy,cyy; /* 2x2 transform matrix elements in row order */
+{
+ double M[2][2];
+
+ IfTrace1((MustTraceCalls),"Transform(%z,", obj);
+ IfTrace4((MustTraceCalls)," %f %f %f %f)\n", &cxx, &cyx, &cxy, &cyy);
+
+ M[0][0] = cxx;
+ M[0][1] = cyx;
+ M[1][0] = cxy;
+ M[1][1] = cyy;
+ ConsiderContext(obj, M);
+ return(Xform(obj, M));
+}
+/*
+:h3.Scale() - Special Case of Transform()
+
+This is a user operator.
+*/
+
+struct xobject *t1_Scale(obj, sx, sy)
+ struct xobject *obj; /* object to scale */
+ double sx,sy; /* scale factors in x and y */
+{
+ double M[2][2];
+ IfTrace3((MustTraceCalls),"Scale(%z, %f, %f)\n", obj, &sx, &sy);
+ M[0][0] = sx;
+ M[1][1] = sy;
+ M[1][0] = M[0][1] = 0.0;
+ ConsiderContext(obj, M);
+ return(Xform(obj, M));
+}
+
+/*
+:h3 id=rotate.Rotate() - Special Case of Transform()
+
+We special-case different settings of 'degrees' for performance
+and accuracy within the DegreeSin() and DegreeCos() routines themselves.
+*/
+
+#ifdef notdef
+struct xobject *xiRotate(obj, degrees)
+ struct xobject *obj; /* object to be transformed */
+ double degrees; /* degrees of COUNTER-clockwise rotation */
+{
+ double M[2][2];
+
+
+ IfTrace2((MustTraceCalls),"Rotate(%z, %f)\n", obj, &degrees);
+
+ M[0][0] = M[1][1] = DegreeCos(degrees);
+ M[1][0] = - (M[0][1] = DegreeSin(degrees));
+ ConsiderContext(obj, M);
+ return(Xform(obj, M));
+}
+#endif
+
+/*
+:h3.PseudoSpace() - Build a Coordinate Space from a Matrix
+
+Since we have built all this optimized code that, given an (x,y) and
+a coordinate space, yield transformed (x,y), it seems a shame not to
+use the same logic when we need to multiply an (x,y) by an arbitrary
+matrix that is not (initially) part of a coordinate space. This
+subroutine takes the arbitrary matrix and builds a coordinate
+space, with all its nifty function pointers.
+*/
+
+void PseudoSpace(S, M)
+ struct XYspace *S; /* coordinate space structure to fill out */
+ double M[2][2]; /* matrix that will become 'tofract.normal' */
+{
+ S->type = SPACETYPE;
+ S->flag = ISPERMANENT(ON) + ISIMMORTAL(ON);
+ S->references = 2; /* 3-26-91 added PNM */
+ S->tofract.normal[0][0] = M[0][0];
+ S->tofract.normal[1][0] = M[1][0];
+ S->tofract.normal[0][1] = M[0][1];
+ S->tofract.normal[1][1] = M[1][1];
+
+ FillOutFcns(S);
+}
+
+/*
+:h2 id=matrixa.Matrix Arithmetic
+
+Following the convention in Newman and Sproull, :hp1/Interactive
+Computer Graphics/,
+matrices are organized:
+:xmp.
+ | cxx cyx |
+ | cxy cyy |
+:exmp.
+A point is horizontal, for example:
+:xmp.
+ [ x y ]
+:exmp.
+This means that:
+:formula/x prime = cxx times x + cxy times y/
+:formula/y prime = cyx times x + cyy times y/
+I've seen the other convention, where transform matrices are
+transposed, equally often in the literature.
+*/
+
+/*
+:h3.MatrixMultiply() - Implements Multiplication of Two Matrices
+
+Implements matrix multiplication, A * B = C.
+
+To remind myself, matrix multiplication goes rows of A times columns
+of B.
+The output matrix may be the same as one of the input matrices.
+*/
+void MatrixMultiply(A, B, C)
+ register double A[2][2],B[2][2]; /* input matrices */
+ register double C[2][2]; /* output matrix */
+{
+ register double txx,txy,tyx,tyy;
+
+ txx = A[0][0] * B[0][0] + A[0][1] * B[1][0];
+ txy = A[1][0] * B[0][0] + A[1][1] * B[1][0];
+ tyx = A[0][0] * B[0][1] + A[0][1] * B[1][1];
+ tyy = A[1][0] * B[0][1] + A[1][1] * B[1][1];
+
+ C[0][0] = txx;
+ C[1][0] = txy;
+ C[0][1] = tyx;
+ C[1][1] = tyy;
+}
+/*
+:h3.MatrixInvert() - Invert a Matrix
+
+My reference for matrix inversion was :hp1/Elementary Linear Algebra/
+by Paul C. Shields, Worth Publishers, Inc., 1968.
+*/
+void MatrixInvert(M, Mprime)
+ double M[2][2]; /* input matrix */
+ double Mprime[2][2]; /* output inverted matrix */
+{
+ register double D; /* determinant of matrix M */
+ register double txx,txy,tyx,tyy;
+
+ txx = M[0][0];
+ txy = M[1][0];
+ tyx = M[0][1];
+ tyy = M[1][1];
+
+ D = M[1][1] * M[0][0] - M[1][0] * M[0][1];
+ if (D == 0.0)
+ abort("MatrixInvert: can't");
+
+ Mprime[0][0] = tyy / D;
+ Mprime[1][0] = -txy / D;
+ Mprime[0][1] = -tyx / D;
+ Mprime[1][1] = txx / D;
+}
+/*
+:h2.Initialization, Queries, and Debug
+*/
+/*
+:h3.InitSpaces() - Initialize Constant Spaces
+
+For compatibility, we initialize a coordinate space called USER which
+maps 72nds of an inch to pels on the default device.
+*/
+
+struct XYspace *USER = &identity;
+
+void InitSpaces()
+{
+ IDENTITY->type = SPACETYPE;
+ FillOutFcns(IDENTITY);
+
+ contexts[NULLCONTEXT].normal[1][0]
+ = contexts[NULLCONTEXT].normal[0][1]
+ = contexts[NULLCONTEXT].inverse[1][0]
+ = contexts[NULLCONTEXT].inverse[0][1] = 0.0;
+ contexts[NULLCONTEXT].normal[0][0]
+ = contexts[NULLCONTEXT].normal[1][1]
+ = contexts[NULLCONTEXT].inverse[0][0]
+ = contexts[NULLCONTEXT].inverse[1][1] = 1.0;
+
+ USER->flag |= ISIMMORTAL(ON);
+ CoerceInverse(USER);
+}
+/*
+:h3.QuerySpace() - Returns the Transformation Matrix of a Space
+
+Since the tofract matrix of an XYspace includes the scale factor
+necessary to produce fractpel results (i.e., FRACTFLOAT), this
+must be taken out before we return the matrix to the user. Fortunately,
+this is simple: just multiply by the inverse of IDENTITY!
+*/
+
+void QuerySpace(S, cxxP, cyxP, cxyP, cyyP)
+ register struct XYspace *S; /* space asked about */
+ register double *cxxP,*cyxP,*cxyP,*cyyP; /* where to put answer */
+{
+ double M[2][2]; /* temp matrix to build user's answer */
+
+ if (S->type != SPACETYPE) {
+ ArgErr("QuerySpace: not a space", S, NULL);
+ return;
+ }
+ MatrixMultiply(S->tofract.normal, IDENTITY->tofract.inverse, M);
+ *cxxP = M[0][0];
+ *cxyP = M[1][0];
+ *cyxP = M[0][1];
+ *cyyP = M[1][1];
+}
+
+/*
+:h3.FormatFP() - Format a Fixed Point Pel
+
+We format the pel as "dddd.XXXX", where XX's are hexidecimal digits,
+and the dd's are decimal digits. This might be a little confusing
+mixing hexidecimal and decimal like that, but it is convenient
+to use for debug.
+
+We make sure we have N (FRACTBITS/4) digits past the decimal point.
+*/
+#define FRACTMASK ((1<<FRACTBITS)-1) /* mask for fractional part */
+
+void FormatFP(string, fpel)
+ register char *string; /* output string */
+ register fractpel fpel; /* fractional pel input */
+{
+ char temp[8];
+ register char *s;
+ register char *sign;
+
+ if (fpel < 0) {
+ sign = "-";
+ fpel = -fpel;
+ }
+ else
+ sign = "";
+
+ sprintf(temp, "000%x", fpel & FRACTMASK);
+ s = temp + strlen(temp) - (FRACTBITS/4);
+
+ sprintf(string, "%s%d.%sx", sign, fpel >> FRACTBITS, s);
+}
+
+/*
+:h3.DumpSpace() - Display a Coordinate Space
+*/
+/*ARGSUSED*/
+void DumpSpace(S)
+ register struct XYspace *S;
+{
+ IfTrace4(TRUE,"--Coordinate space at %x,ID=%d,convert=%x,iconvert=%x\n",
+ S, S->ID, S->convert, S->iconvert);
+ IfTrace2(TRUE," | %12.3f %12.3f |",
+ &S->tofract.normal[0][0], &S->tofract.normal[0][1]);
+ IfTrace2(TRUE," [ %p %p ]\n", S->itofract[0][0], S->itofract[0][1]);
+ IfTrace2(TRUE," | %12.3f %12.3f |",
+ &S->tofract.normal[1][0], &S->tofract.normal[1][1]);
+ IfTrace2(TRUE," [ %p %p ]\n", S->itofract[1][0], S->itofract[1][1]);
+}
diff --git a/src/Type1/spaces.h b/src/Type1/spaces.h
new file mode 100644
index 0000000..21eee17
--- /dev/null
+++ b/src/Type1/spaces.h
@@ -0,0 +1,140 @@
+/* $Xorg: spaces.h,v 1.3 2000/08/17 19:46:32 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+/*SHARED*/
+
+#define USER t1_User
+#define IDENTITY t1_Identity
+
+#define Context(d,u) t1_Context(d,u)
+#define Transform(o,f1,f2,f3,f4) t1_Transform(o,f1,f2,f3,f4)
+#define Rotate(o,d) t1_Rotate(o,d)
+#define Scale(o,sx,sy) t1_Scale(o,sx,sy)
+#define QuerySpace(S,f1,f2,f3,f4) t1_QuerySpace(S,f1,f2,f3,f4)
+#define Warp(s1,o,s2) t1_Warp(s1,o,s2)
+
+struct XYspace *t1_Context(); /* creates a coordinate space for a device */
+struct xobject *t1_Transform(); /* transform an object */
+struct xobject *t1_Rotate(); /* rotate an object */
+struct xobject *t1_Scale(); /* scale an object */
+struct xobject *t1_Warp(); /* transform like delta of two spaces */
+void t1_QuerySpace(); /* returns coordinate space matrix */
+
+/*END SHARED*/
+/*SHARED*/
+
+#define DeviceResolution t1_DeviceResolution
+#define InitSpaces() t1_InitSpaces()
+#define CopySpace(s) t1_CopySpace(s)
+#define Xform(o,M) t1_Xform(o,M)
+#define UnConvert(S,pt,xp,yp) t1_UnConvert(S,pt,xp,yp)
+#define MatrixMultiply(A,B,C) t1_MMultiply(A,B,C)
+#define MatrixInvert(A,B) t1_MInvert(A,B)
+#define PseudoSpace(S,M) t1_PseudoSpace(S,M)
+#define FindContext(M) t1_FindContext(M)
+
+void t1_InitSpaces(); /* initialize pre-defined coordinate spaces */
+struct XYspace *t1_CopySpace(); /* duplicate a coordinate space */
+struct xobject *t1_Xform(); /* transform object by matrix */
+void t1_UnConvert(); /* return user coordinates from device coordinates */
+void t1_MMultiply(); /* multiply two matrices */
+void t1_MInvert(); /* invert a matrix */
+void t1_PseudoSpace(); /* force a coordinate space from a matrix */
+int t1_FindContext(); /* return the "context" represented by a matrix */
+
+/*END SHARED*/
+/*SHARED*/
+
+/* #define KillSpace(s) Free(s)
+Note - redefined KillSpace() to check references !
+3-26-91 PNM */
+
+#define KillSpace(s) if ( (--(s->references) == 0) ||\
+ ( (s->references == 1) && ISPERMANENT(s->flag) ) )\
+ Free(s)
+
+#define ConsumeSpace(s) MAKECONSUME(s,KillSpace(s))
+#define UniqueSpace(s) MAKEUNIQUE(s,CopySpace(s))
+
+/*END SHARED*/
+/*SHARED*/
+
+typedef short pel; /* integer pel locations */
+typedef long fractpel; /* fractional pel locations */
+
+#define FRACTBITS 16 /* number of fractional bits in 'fractpel' */
+/*
+We define the following macros to convert from 'fractpel' to 'pel' and
+vice versa:
+*/
+#define TOFRACTPEL(p) (((fractpel)p)<<FRACTBITS)
+#define FPHALF (1<<(FRACTBITS-1))
+#define NEARESTPEL(fp) (((fp)+FPHALF)>>FRACTBITS)
+#define FRACTFLOAT (double)(1L<<FRACTBITS)
+
+/*END SHARED*/
+/*SHARED*/
+
+struct doublematrix {
+ double normal[2][2];
+ double inverse[2][2];
+} ;
+
+/*END SHARED*/
+/*SHARED*/
+
+struct XYspace {
+ XOBJ_COMMON /* xobject common data define 3-26-91 PNM */
+ /* type = SPACETYPE */
+ void (*convert)(); /* calculate "fractpoint" X,Y from float X,Y */
+ void (*iconvert)(); /* calculate "fractpoint" X,Y from int X,Y */
+ fractpel (*xconvert)(); /* subroutine of convert */
+ fractpel (*yconvert)(); /* subroutine of convert */
+ fractpel (*ixconvert)(); /* subroutine of iconvert */
+ fractpel (*iyconvert)(); /* subroutine of iconvert */
+ int ID; /* unique identifier (used in font caching) */
+ unsigned char context; /* device context of coordinate space */
+ struct doublematrix tofract; /* xform to get to fractional pels */
+ fractpel itofract[2][2]; /* integer version of "tofract.normal" */
+} ;
+
+#define INVALIDID 0 /* no valid space will have this ID */
+
+/*END SHARED*/
+/*SHARED*/
+
+struct fractpoint {
+ fractpel x,y;
+} ;
+
+/*END SHARED*/
+/*SHARED*/
+
+#define NULLCONTEXT 0
+
+/*END SHARED*/
diff --git a/src/Type1/strokes.h b/src/Type1/strokes.h
new file mode 100644
index 0000000..c374e16
--- /dev/null
+++ b/src/Type1/strokes.h
@@ -0,0 +1,38 @@
+/* $Xorg: strokes.h,v 1.3 2000/08/17 19:46:32 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/*STUB*/
+
+#define CopyLineStyle(s) s
+#define CopyStrokePath(p) p
+#define KillStrokePath(p)
+#define KillLineStyle(s)
+#define CoercePath(sp) sp
+#define DoStroke(sp) sp
+
diff --git a/src/Type1/t1funcs.c b/src/Type1/t1funcs.c
new file mode 100644
index 0000000..ef113db
--- /dev/null
+++ b/src/Type1/t1funcs.c
@@ -0,0 +1,694 @@
+/* $Xorg: t1funcs.c,v 1.5 2001/02/09 02:04:01 xorgcvs Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License, subject to the license given below, to use,
+ * copy, modify, and distribute this software * and its
+ * documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear
+ * in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Author: Jeffrey B. Lotspiech, IBM Almaden Research Center
+ * Modeled on spfuncs.c by Dave Lemke, Network Computing Devices, Inc
+ * which contains the following copyright and permission notices:
+ *
+ * Copyright 1990, 1991 Network Computing Devices;
+ * Portions Copyright 1987 by Digital Equipment Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the names of Network Computing Devices
+ * or Digital not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Network Computing Devices or Digital make no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * NETWORK COMPUTING DEVICES AND DIGITAL DISCLAIM ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES OR DIGITAL BE
+ * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+
+Copyright 1987, 1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+#include <string.h>
+#ifdef _XOPEN_SOURCE
+#include <math.h>
+#else
+#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
+#include <math.h>
+#undef _XOPEN_SOURCE
+#endif
+#include "X11/Xfuncs.h"
+#include "fntfilst.h"
+#include "FSproto.h"
+#include "t1intf.h"
+
+#include "objects.h"
+#include "spaces.h"
+#include "regions.h"
+#include "t1stdio.h"
+#include "util.h"
+#include "fontfcn.h"
+
+int Type1OpenScalable ();
+static int Type1GetGlyphs();
+void Type1CloseFont();
+extern int Type1GetInfoScalable ();
+
+static int Type1GetMetrics ();
+
+#define minchar(p) ((p).min_char_low + ((p).min_char_high << 8))
+#define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8))
+
+static void fillrun();
+
+
+extern psfont *FontP;
+extern psobj *ISOLatin1EncArrayP;
+
+extern unsigned long *Xalloc();
+static void fill();
+
+/*ARGSUSED*/
+int Type1OpenScalable (fpe, ppFont, flags, entry, fileName, vals, format,
+ fmask, non_cachable_font)
+ FontPathElementPtr fpe;
+ FontPtr *ppFont;
+ int flags;
+ FontEntryPtr entry;
+ char *fileName;
+ FontScalablePtr vals;
+ fsBitmapFormat format;
+ fsBitmapFormatMask fmask;
+ FontPtr non_cachable_font; /* We don't do licensing */
+{
+ extern struct XYspace *IDENTITY;
+ extern Bool fontfcnA();
+ extern struct region *fontfcnB();
+
+
+ FontPtr pFont;
+ int bit,
+ byte,
+ glyph,
+ scan,
+ image;
+ int pad,wordsize; /* scan & image in bits */
+ unsigned long *pool; /* memory pool for ximager objects */
+ int size; /* for memory size calculations */
+ struct XYspace *S; /* coordinate space for character */
+ struct region *area;
+ CharInfoRec *glyphs;
+ register int i;
+ int len, rc, count = 0;
+ struct type1font *type1;
+ char *p;
+ psobj *fontencoding = NULL;
+ psobj *fontmatrix;
+ long x0, total_width = 0, total_raw_width = 0;
+ double x1, y1, t1 = .001, t2 = 0.0, t3 = 0.0, t4 = .001;
+ double sxmult;
+
+ /* Reject ridiculously small font sizes that will blow up the math */
+ if (hypot(vals->pixel_matrix[0], vals->pixel_matrix[1]) < 1.0 ||
+ hypot(vals->pixel_matrix[2], vals->pixel_matrix[3]) < 1.0)
+ return BadFontName;
+
+ /* set up default values */
+ FontDefaultFormat(&bit, &byte, &glyph, &scan);
+ /* get any changes made from above */
+ rc = CheckFSFormat(format, fmask, &bit, &byte, &scan, &glyph, &image);
+ if (rc != Successful)
+ return rc;
+
+ pad = glyph * 8;
+ wordsize = scan * 8;
+
+#define PAD(bits, pad) (((bits)+(pad)-1)&-(pad))
+
+ pFont = (FontPtr) xalloc(sizeof(FontRec));
+ if (pFont == NULL)
+ return AllocError;
+
+ type1 = (struct type1font *)xalloc(sizeof(struct type1font));
+ if (type1 == NULL) {
+ xfree(pFont);
+ return AllocError;
+ }
+ bzero(type1, sizeof(struct type1font));
+
+ /* heuristic for "maximum" size of pool we'll need: */
+ size = 200000 + 120 *
+ (int)hypot(vals->pixel_matrix[2], vals->pixel_matrix[3])
+ * sizeof(short);
+ if (size < 0 || NULL == (pool = (unsigned long *) xalloc(size))) {
+ xfree(type1);
+ xfree(pFont);
+ return AllocError;
+ }
+
+ addmemory(pool, size);
+
+
+ glyphs = type1->glyphs;
+
+ /* load font if not already loaded */
+ if (!fontfcnA(fileName, &rc)) {
+ delmemory();
+ xfree(type1);
+ xfree(pFont);
+ xfree(pool);
+ return Type1ReturnCodeToXReturnCode(rc);
+ }
+
+ fontmatrix = &FontP->fontInfoP[FONTMATRIX].value;
+ if (objPIsArray(fontmatrix) && fontmatrix->len == 6)
+ {
+#define assign(n,d,f) if (objPIsInteger(fontmatrix->data.arrayP + n)) \
+ d = fontmatrix->data.arrayP[n].data.integer; \
+ else if (objPIsReal(fontmatrix->data.arrayP + n)) \
+ d = fontmatrix->data.arrayP[n].data.real; \
+ else d = f;
+
+ assign(0, t1, .001);
+ assign(1, t2, 0.0);
+ assign(2, t3, 0.0);
+ assign(3, t4, .001);
+ }
+
+ S = (struct XYspace *) t1_Transform(IDENTITY, t1, t2, t3, t4);
+
+ S = (struct XYspace *) Permanent(t1_Transform(S, vals->pixel_matrix[0],
+ -vals->pixel_matrix[1],
+ vals->pixel_matrix[2],
+ -vals->pixel_matrix[3]));
+
+
+ /* multiplier for computation of raw values */
+ sxmult = hypot(vals->pixel_matrix[0], vals->pixel_matrix[1]);
+ if (sxmult > EPS) sxmult = 1000.0 / sxmult;
+
+ p = entry->name.name + entry->name.length - 19;
+ if (entry->name.ndashes == 14 &&
+ p >= entry->name.name &&
+ !strcmp (p, "-adobe-fontspecific"))
+ {
+ fontencoding = FontP->fontInfoP[ENCODING].value.data.arrayP;
+ }
+
+ if (!fontencoding)
+ fontencoding = ISOLatin1EncArrayP;
+
+ pFont->info.firstCol = 255;
+ pFont->info.lastCol = FIRSTCOL;
+
+ for (i=0; i < 256-FIRSTCOL; i++) {
+ long h,w;
+ long paddedW;
+ int j;
+ char *codename;
+
+ codename = fontencoding[i + FIRSTCOL].data.valueP;
+ len = fontencoding[i + FIRSTCOL].len;
+ if (len == 7 && strcmp(codename,".notdef")==0)
+ continue;
+
+ /* See if this character is in the list of ranges specified
+ in the XLFD name */
+ for (j = 0; j < vals->nranges; j++)
+ if (i + FIRSTCOL >= minchar(vals->ranges[j]) &&
+ i + FIRSTCOL <= maxchar(vals->ranges[j]))
+ break;
+
+ /* If not, don't realize it. */
+ if (vals->nranges && j == vals->nranges)
+ continue;
+
+ if (pFont->info.firstCol > i + FIRSTCOL)
+ pFont->info.firstCol = i + FIRSTCOL;
+ if (pFont->info.lastCol < i + FIRSTCOL)
+ pFont->info.lastCol = i + FIRSTCOL;
+
+ rc = 0;
+ area = fontfcnB(S, codename, &len, &rc);
+ if (rc < 0) {
+ rc = Type1ReturnCodeToXReturnCode(rc);
+ break;
+ }
+ else if (rc > 0)
+ continue;
+
+ if (area == NULL)
+ continue;
+
+ h = area->ymax - area->ymin;
+ w = area->xmax - area->xmin;
+ paddedW = PAD(w, pad);
+
+ if (h > 0 && w > 0) {
+ size = h * paddedW / 8;
+ glyphs[i].bits = (char *)xalloc(size);
+ if (glyphs[i].bits == NULL) {
+ rc = AllocError;
+ break;
+ }
+ }
+ else {
+ size = 0;
+ h = w = 0;
+ area->xmin = area->xmax = 0;
+ area->ymax = area->ymax = 0;
+ }
+
+ glyphs[i].metrics.leftSideBearing = area->xmin;
+ x1 = (double)(x0 = area->ending.x - area->origin.x);
+ y1 = (double)(area->ending.y - area->origin.y);
+ glyphs[i].metrics.characterWidth =
+ (x0 + (x0 > 0 ? FPHALF : -FPHALF)) / (1 << FRACTBITS);
+ if (!glyphs[i].metrics.characterWidth && size == 0)
+ {
+ /* Zero size and zero extents: presumably caused by
+ the choice of transformation. Let's create a
+ small bitmap so we're not mistaken for an undefined
+ character. */
+ h = w = 1;
+ size = paddedW = PAD(w, pad);
+ glyphs[i].bits = (char *)xalloc(size);
+ if (glyphs[i].bits == NULL) {
+ rc = AllocError;
+ break;
+ }
+ }
+ glyphs[i].metrics.attributes =
+ NEARESTPEL((long)(hypot(x1, y1) * sxmult));
+ total_width += glyphs[i].metrics.attributes;
+ total_raw_width += abs((int)(INT16)glyphs[i].metrics.attributes);
+ count++;
+ glyphs[i].metrics.rightSideBearing = w + area->xmin;
+ glyphs[i].metrics.descent = area->ymax - NEARESTPEL(area->origin.y);
+ glyphs[i].metrics.ascent = h - glyphs[i].metrics.descent;
+
+
+ bzero(glyphs[i].bits, size);
+ if (h > 0 && w > 0) {
+ fill(glyphs[i].bits, h, paddedW, area, byte, bit, wordsize );
+ }
+
+ Destroy(area);
+ }
+
+ delmemory();
+ xfree(pool);
+
+ if (pFont->info.firstCol > pFont->info.lastCol)
+ {
+ xfree(type1);
+ xfree(pFont);
+ return BadFontName;
+ }
+
+ if (i != 256 - FIRSTCOL) {
+ for (i--; i >= 0; i--)
+ if (glyphs[i].bits != NULL)
+ xfree(glyphs[i].bits);
+ xfree(type1);
+ xfree(pFont);
+ return rc;
+ }
+ type1->pDefault = NULL;
+
+ pFont->format = format;
+
+ pFont->bit = bit;
+ pFont->byte = byte;
+ pFont->glyph = glyph;
+ pFont->scan = scan;
+
+ pFont->info.firstRow = 0;
+ pFont->info.lastRow = 0;
+
+ pFont->get_metrics = Type1GetMetrics;
+ pFont->get_glyphs = Type1GetGlyphs;
+ pFont->unload_font = Type1CloseFont;
+ pFont->unload_glyphs = NULL;
+ pFont->refcnt = 0;
+ pFont->maxPrivate = -1;
+ pFont->devPrivates = 0;
+
+ pFont->fontPrivate = (unsigned char *) type1;
+
+ if (count)
+ {
+ total_raw_width = (total_raw_width * 10 + count / 2) / count;
+ if (total_width < 0)
+ {
+ /* Predominant direction is R->L */
+ total_raw_width = -total_raw_width;
+ }
+ vals->width = (int)((double)total_raw_width *
+ vals->pixel_matrix[0] / 1000.0 +
+ (vals->pixel_matrix[0] > 0 ? .5 : -.5));
+ }
+
+ T1FillFontInfo(pFont, vals, fileName, entry->name.name, total_raw_width);
+
+ *ppFont = pFont;
+ return Successful;
+}
+
+static int
+Type1GetGlyphs(pFont, count, chars, charEncoding, glyphCount, glyphs)
+ FontPtr pFont;
+ unsigned long count;
+ register unsigned char *chars;
+ FontEncoding charEncoding;
+ unsigned long *glyphCount; /* RETURN */
+ CharInfoPtr *glyphs; /* RETURN */
+{
+ unsigned int firstRow;
+ unsigned int numRows;
+ CharInfoPtr *glyphsBase;
+ register unsigned int c;
+ register CharInfoPtr pci;
+ unsigned int r;
+ CharInfoPtr pDefault;
+ register struct type1font *type1Font;
+ register int firstCol;
+
+ type1Font = (struct type1font *) pFont->fontPrivate;
+ firstCol = pFont->info.firstCol;
+ pDefault = type1Font->pDefault;
+ glyphsBase = glyphs;
+
+ switch (charEncoding) {
+
+#define EXIST(pci) \
+ ((pci)->metrics.attributes || \
+ (pci)->metrics.ascent != -(pci)->metrics.descent || \
+ (pci)->metrics.leftSideBearing != (pci)->metrics.rightSideBearing)
+
+ case Linear8Bit:
+ case TwoD8Bit:
+ if (pFont->info.firstRow > 0)
+ break;
+ while (count--) {
+ c = (*chars++);
+ if (c >= firstCol &&
+ (pci = &type1Font->glyphs[c-FIRSTCOL]) &&
+ EXIST(pci))
+ *glyphs++ = pci;
+ else if (pDefault)
+ *glyphs++ = pDefault;
+ }
+ break;
+ case Linear16Bit:
+ while (count--) {
+ c = *chars++ << 8;
+ c = (c | *chars++);
+ if (c < 256 && c >= firstCol &&
+ (pci = &type1Font->glyphs[c-FIRSTCOL]) &&
+ EXIST(pci))
+ *glyphs++ = pci;
+ else if (pDefault)
+ *glyphs++ = pDefault;
+ }
+ break;
+
+ case TwoD16Bit:
+ firstRow = pFont->info.firstRow;
+ numRows = pFont->info.lastRow - firstRow + 1;
+ while (count--) {
+ r = (*chars++) - firstRow;
+ c = (*chars++);
+ if (r < numRows && c < 256 && c >= firstCol &&
+ (pci = &type1Font->glyphs[(r << 8) + c - FIRSTCOL]) &&
+ EXIST(pci))
+ *glyphs++ = pci;
+ else if (pDefault)
+ *glyphs++ = pDefault;
+ }
+ break;
+ }
+ *glyphCount = glyphs - glyphsBase;
+ return Successful;
+
+#undef EXIST
+}
+
+static int
+Type1GetMetrics(pFont, count, chars, charEncoding, glyphCount, glyphs)
+ FontPtr pFont;
+ unsigned long count;
+ register unsigned char *chars;
+ FontEncoding charEncoding;
+ unsigned long *glyphCount; /* RETURN */
+ xCharInfo **glyphs; /* RETURN */
+{
+ static CharInfoRec nonExistantChar;
+
+ int ret;
+ struct type1font *type1Font;
+ CharInfoPtr oldDefault;
+
+ type1Font = (struct type1font *) pFont->fontPrivate;
+ oldDefault = type1Font->pDefault;
+ type1Font->pDefault = &nonExistantChar;
+ ret = Type1GetGlyphs(pFont, count, chars, charEncoding, glyphCount, (CharInfoPtr *) glyphs);
+ type1Font->pDefault = oldDefault;
+ return ret;
+}
+
+void Type1CloseFont(pFont)
+ FontPtr pFont;
+{
+ register int i;
+ struct type1font *type1;
+
+ type1 = (struct type1font *) pFont->fontPrivate;
+ for (i=0; i < 256 - FIRSTCOL; i++)
+ if (type1->glyphs[i].bits != NULL)
+ xfree(type1->glyphs[i].bits);
+ xfree(type1);
+
+ if (pFont->info.props)
+ xfree(pFont->info.props);
+
+ if (pFont->info.isStringProp)
+ xfree(pFont->info.isStringProp);
+
+ if (pFont->devPrivates)
+ xfree(pFont->devPrivates);
+
+ xfree(pFont);
+}
+
+
+
+static void fill(dest, h, w, area, byte, bit, wordsize)
+ register char *dest; /* destination bitmap */
+ int h,w; /* dimensions of 'dest', w padded */
+ register struct region *area; /* region to write to 'dest' */
+ int byte,bit; /* flags; LSBFirst or MSBFirst */
+ int wordsize; /* number of bits per word for LSB/MSB purposes */
+{
+ register struct edgelist *edge; /* for looping through edges */
+ register char *p; /* current scan line in 'dest' */
+ register int y; /* for looping through scans */
+ register int wbytes = w / 8; /* number of bytes in width */
+ register pel *leftP,*rightP; /* pointers to X values, left and right */
+ int xmin = area->xmin; /* upper left X */
+ int ymin = area->ymin; /* upper left Y */
+
+ for (edge = area->anchor; VALIDEDGE(edge); edge = edge->link->link) {
+
+ p = dest + (edge->ymin - ymin) * wbytes;
+ leftP = edge->xvalues;
+ rightP = edge->link->xvalues;
+
+ for (y = edge->ymin; y < edge->ymax; y++) {
+ fillrun(p, *leftP++ - xmin, *rightP++ - xmin, bit);
+ p += wbytes;
+ }
+ }
+/*
+Now, as an afterthought, we'll go reorganize if odd byte order requires
+it:
+*/
+ if (byte == LSBFirst && wordsize != 8) {
+ register int i;
+
+ switch (wordsize) {
+ case 16:
+ {
+ register unsigned short data,*p;
+
+ p = (unsigned short *) dest;
+
+ for (i = h * w /16; --i >= 0;) {
+ data = *p;
+ *p++ = (data << 8) + (data >> 8);
+ }
+ break;
+ }
+ case 64:
+ case 32:
+ {
+ register unsigned long data,*p;
+
+ p = (unsigned long *) dest;
+
+ for (i = h * w / 32; --i >= 0;) {
+ data = *p;
+ *p++ = (data << 24) + (data >> 24)
+ + (0xFF00 & (data >> 8))
+ + (0xFF0000 & (data << 8));
+ }
+ if (wordsize == 64) {
+
+ p = (unsigned long *) dest;
+
+ for (i = h * w / 64; --i >= 0;) {
+ data = *p++;
+ p[-1] = p[0];
+ *p++ = data;
+ }
+ }
+ break;
+ }
+ default:
+ abort("xiFill: unknown format");
+ }
+ }
+
+}
+
+#define ALLONES 0xFF
+
+static void fillrun(p, x0, x1, bit)
+ register char *p; /* address of this scan line */
+ pel x0,x1; /* left and right X */
+ int bit; /* format: LSBFirst or MSBFirst */
+{
+ register int startmask,endmask; /* bits to set in first and last char*/
+ register int middle; /* number of chars between start and end + 1 */
+
+ if (x1 <= x0)
+ return;
+ middle = x1/8 - x0/8;
+ p += x0/8;
+ x0 &= 7; x1 &= 7;
+ if (bit == LSBFirst) {
+ startmask = ALLONES << x0;
+ endmask = ~(ALLONES << x1);
+ }
+ else {
+ startmask = ALLONES >> x0;
+ endmask = ~(ALLONES >> x1);
+ }
+ if (middle == 0)
+ *p++ |= startmask & endmask;
+ else {
+ *p++ |= startmask;
+ while (--middle > 0)
+ *p++ = ALLONES;
+ *p |= endmask;
+ }
+}
+
+#define CAPABILITIES (CAP_MATRIX | CAP_CHARSUBSETTING)
+
+static FontRendererRec renderers[] = {
+ { ".pfa", 4, (int (*)()) 0, Type1OpenScalable,
+ (int (*)()) 0, Type1GetInfoScalable, 0, CAPABILITIES },
+ { ".pfb", 4, (int (*)()) 0, Type1OpenScalable,
+ (int (*)()) 0, Type1GetInfoScalable, 0, CAPABILITIES }
+};
+
+
+void
+Type1RegisterFontFileFunctions()
+{
+ int i;
+
+ T1InitStdProps();
+ for (i=0; i < sizeof(renderers) / sizeof(FontRendererRec); i++)
+ FontFileRegisterRenderer(&renderers[i]);
+}
+
+int Type1ReturnCodeToXReturnCode(rc)
+ int rc;
+{
+ switch(rc) {
+ case SCAN_OK:
+ return Successful;
+ case SCAN_FILE_EOF:
+ /* fall through to BadFontFormat */
+ case SCAN_ERROR:
+ return BadFontFormat;
+ case SCAN_OUT_OF_MEMORY:
+ return AllocError;
+ case SCAN_FILE_OPEN_ERROR:
+ return BadFontName;
+ case SCAN_TRUE:
+ case SCAN_FALSE:
+ case SCAN_END:
+ /* fall through */
+ default:
+ /* this should not happen */
+ ErrorF("Type1 return code not convertable to X return code: %d\n", rc);
+ return rc;
+ }
+}
diff --git a/src/Type1/t1hdigit.h b/src/Type1/t1hdigit.h
new file mode 100644
index 0000000..e05f0de
--- /dev/null
+++ b/src/Type1/t1hdigit.h
@@ -0,0 +1,40 @@
+/* $Xorg: t1hdigit.h,v 1.3 2000/08/17 19:46:33 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* Indicators for special characters in the p_hdigit.h tables */
+#define HERROR (0xfe)
+#define HWHITE_SPACE (0xfd)
+#define HRIGHT_ANGLE (0xfc)
+#define LAST_HDIGIT (0xf0)
+
+/* Declarations for the tables */
+#define HighHexP (HighHex+1)
+extern unsigned char HighHex[];
+#define LowHexP (LowHex+1)
+extern unsigned char LowHex[];
diff --git a/src/Type1/t1imager.h b/src/Type1/t1imager.h
new file mode 100644
index 0000000..472b36f
--- /dev/null
+++ b/src/Type1/t1imager.h
@@ -0,0 +1,148 @@
+/* $Xorg: t1imager.h,v 1.3 2000/08/17 19:46:33 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "fontmisc.h"
+
+typedef pointer xobject;
+typedef pointer location;
+typedef pointer path;
+typedef pointer region;
+typedef pointer XYspace;
+
+#ifndef NOEXTERNS
+/*
+The following are the user entry locations to TYPE1IMAGER
+*/
+extern path t1_Bezier();
+extern path t1_ClosePath();
+extern xobject t1_Destroy();
+extern xobject t1_Dup();
+extern char *t1_ErrorMsg();
+extern void t1_InitImager();
+extern region t1_Interior();
+extern location t1_ILoc();
+extern xobject t1_Join();
+extern path t1_Line();
+extern xobject t1_Permanent();
+extern path t1_Phantom();
+extern location t1_Loc();
+extern xobject t1_Scale();
+extern xobject t1_Snap();
+extern location t1_SubLoc();
+extern xobject t1_Temporary();
+
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*
+Here are some TYPE1IMAGER functions that are defined in terms of others:
+*/
+
+#define t1_AddLoc(p1,p2) t1_Join(p1,p2)
+
+#ifndef NONAMES
+/*
+Define the simple form of all the subroutine names:
+*/
+#define AddLoc(p1,p2) t1_AddLoc(p1,p2)
+#define Bezier(B,C,D) t1_Bezier(B,C,D)
+#define ClosePath(p) t1_ClosePath(p,0)
+#define Complement(area) t1_Complement(area)
+#define Destroy(o) t1_Destroy(o)
+#define Dup(o) t1_Dup(o)
+#define ErrorMsg() t1_ErrorMsg()
+#define HeadSegment(p) t1_HeadSegment(p)
+#define InitImager() t1_InitImager()
+#define Interior(p,rule) t1_Interior(p,rule)
+#define ILoc(S,x,y) t1_ILoc(S,x,y)
+#define Join(p1,p2) t1_Join(p1,p2)
+#define Line(P) t1_Line(P)
+#define Permanent(o) t1_Permanent(o)
+#define Phantom(o) t1_Phantom(o)
+#define Loc(S,x,y) t1_Loc(S,(double)x,(double)y)
+#define Scale(o,sx,sy) t1_Scale(o,(double)sx,(double)sy)
+#define Snap(o) t1_Snap(o)
+#define SubLoc(a,b) t1_SubLoc(a,b)
+#define Temporary(o) t1_Temporary(o)
+#define TermImager() t1_TermImager()
+#define Transform(o,cxx,cyx,cxy,cyy) t1_Transform(o,(double)cxx,(double)cyx,\
+ (double)cxy,(double)cyy)
+
+#endif
+
+#define WINDINGRULE -2
+#define EVENODDRULE -3
+
+#define CONTINUITY 0x80 /* can be added to above rules; e.g. WINDINGRULE+CONTINUITY */
+
+/*
+Stroke() line style constants:
+*/
+
+/*
+Coordinate space constants:
+*/
+#define IDENTITY t1_Identity
+extern XYspace *IDENTITY;
+
+/*
+Generic null object definition:
+*/
+#define NULLOBJECT ((xobject)NULL)
+
+/*
+Null path definition:
+*/
+#define NULLPATH NULLOBJECT
+
+/*
+Full page and null region definition:
+*/
+#define INFINITY t1_Infinity
+#ifndef NOEXTERNS
+extern region *INFINITY;
+#endif
+#define NULLREGION NULLOBJECT
+
+#define FF_PARSE_ERROR 5
+#define FF_PATH 1
+
+extern pointer xiStub();
diff --git a/src/Type1/t1info.c b/src/Type1/t1info.c
new file mode 100644
index 0000000..dff6257
--- /dev/null
+++ b/src/Type1/t1info.c
@@ -0,0 +1,488 @@
+/* $Xorg: t1info.c,v 1.4 2001/02/09 02:04:01 xorgcvs Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License, subject to the license given below, to use,
+ * copy, modify, and distribute this software * and its
+ * documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear
+ * in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Author: Carol H. Thompson IBM Almaden Research Center
+ * Modeled on spinfo.c by Dave Lemke, Network Computing Devices, Inc
+ * which contains the following copyright and permission notices:
+ *
+ * Copyright 1990, 1991 Network Computing Devices;
+ * Portions Copyright 1987 by Digital Equipment Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the names of Network Computing Devices or Digital
+ * not be used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. Network Computing
+ * Devices and Digital make no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NETWORK COMPUTING DEVICES AND DIGITAL DISCLAIM ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES OR DIGITAL BE
+ * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+
+Copyright 1987, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+#include <stdio.h>
+#include "fntfilst.h"
+#include "FSproto.h"
+#include "t1intf.h"
+#include <math.h>
+
+#define DECIPOINTSPERINCH 722.7
+#define DEFAULTRES 75
+#define DEFAULTPOINTSIZE 120
+
+enum scaleType {
+ atom, truncate_atom, pixel_size, point_size, resolution_x,
+ resolution_y, average_width
+};
+
+typedef struct _fontProp {
+ char *name;
+ long atom;
+ enum scaleType type;
+} fontProp;
+
+static fontProp fontNamePropTable[] = { /* Example: */
+ { "FOUNDRY", 0, atom }, /* adobe */
+ { "FAMILY_NAME", 0, atom }, /* times roman */
+ { "WEIGHT_NAME", 0, atom }, /* bold */
+ { "SLANT", 0, atom }, /* i */
+ { "SETWIDTH_NAME", 0, atom }, /* normal */
+ { "ADD_STYLE_NAME", 0, atom }, /* */
+ { "PIXEL_SIZE", 0, pixel_size }, /* 18 */
+ { "POINT_SIZE", 0, point_size }, /* 180 */
+ { "RESOLUTION_X", 0, resolution_x }, /* 72 */
+ { "RESOLUTION_Y", 0, resolution_y }, /* 72 */
+ { "SPACING", 0, atom }, /* p */
+ { "AVERAGE_WIDTH", 0, average_width }, /* 0 */
+ { "CHARSET_REGISTRY", 0, atom }, /* ISO8859 */
+ { "CHARSET_ENCODING", 0, truncate_atom } /* 1 */
+};
+
+/* NOTICE: Following array is closely related to the sequence of defines
+ following it. */
+static fontProp extraProps[] = {
+ { "FONT", 0, },
+ { "COPYRIGHT", 0, },
+ { "RAW_PIXEL_SIZE", 0, },
+ { "RAW_POINT_SIZE", 0, },
+ { "RAW_ASCENT", 0, },
+ { "RAW_DESCENT", 0, },
+ { "RAW_AVERAGE_WIDTH", 0, },
+ { "FACE_NAME", 0, }
+};
+
+/* this is a bit kludgy */
+#define FONTPROP 0
+#define COPYRIGHTPROP 1
+#define RAWPIXELPROP 2
+#define RAWPOINTPROP 3
+#define RAWASCENTPROP 4
+#define RAWDESCENTPROP 5
+#define RAWWIDTHPROP 6
+#define FACE_NAMEPROP 7
+
+#define NNAMEPROPS (sizeof(fontNamePropTable) / sizeof(fontProp))
+#define NEXTRAPROPS (sizeof(extraProps) / sizeof(fontProp))
+
+#define NPROPS (NNAMEPROPS + NEXTRAPROPS)
+
+/*ARGSUSED*/
+static void
+FillHeader(pInfo, Vals)
+ FontInfoPtr pInfo;
+ FontScalablePtr Vals;
+{
+ /* OpenScalable in T1FUNCS sets the following:
+ pInfo->firstCol,
+ pInfo->firstRow,
+ pInfo->lastCol, and
+ pInfo->lastRow. */
+ /* the following are ununsed
+ pInfo->pad. */
+
+ /* Items we should handle better someday +++ */
+ pInfo->defaultCh = 0;
+ pInfo->drawDirection = LeftToRight;
+ if (Vals->point_matrix[0] == Vals->point_matrix[3])
+ pInfo->anamorphic = 0;
+ else
+ pInfo->anamorphic = 1;
+ pInfo->inkMetrics = 0; /* no ink metrics here */
+ pInfo->cachable = 1; /* no licensing (yet) */
+}
+
+static void
+adjust_min_max(minc, maxc, tmp)
+ xCharInfo *minc,
+ *maxc,
+ *tmp;
+{
+#define MINMAX(field,ci) \
+ if (minc->field > (ci)->field) \
+ minc->field = (ci)->field; \
+ if (maxc->field < (ci)->field) \
+ maxc->field = (ci)->field;
+
+ MINMAX(ascent, tmp);
+ MINMAX(descent, tmp);
+ MINMAX(leftSideBearing, tmp);
+ MINMAX(rightSideBearing, tmp);
+ MINMAX(characterWidth, tmp);
+
+ /* Do MINMAX for attributes field. Since that field is CARD16,
+ we'll cast to a signed integer */
+ if ((INT16)minc->attributes > (INT16)tmp->attributes)
+ minc->attributes = tmp->attributes;
+ if ((INT16)maxc->attributes < (INT16)tmp->attributes)
+ maxc->attributes = tmp->attributes;
+
+#undef MINMAX
+}
+
+static void
+ComputeBounds(pInfo, pChars, Vals)
+ FontInfoPtr pInfo;
+ CharInfoPtr pChars;
+ FontScalablePtr Vals;
+{
+ int i;
+ xCharInfo minchar, maxchar;
+ int numchars = 0;
+ int totchars;
+ int overlap;
+ int maxlap;
+
+ minchar.ascent = minchar.descent =
+ minchar.leftSideBearing = minchar.rightSideBearing =
+ minchar.characterWidth = minchar.attributes = 32767;
+ maxchar.ascent = maxchar.descent =
+ maxchar.leftSideBearing = maxchar.rightSideBearing =
+ maxchar.characterWidth = maxchar.attributes = -32767;
+
+ maxlap = -32767;
+ totchars = pInfo->lastCol - pInfo->firstCol + 1;
+ pChars += pInfo->firstCol - FIRSTCOL;
+ pInfo->allExist = 1;
+ for (i = 0; i < totchars; i++,pChars++) {
+ xCharInfo *pmetrics = &pChars->metrics;
+
+ if (pmetrics->attributes ||
+ pmetrics->ascent != -pmetrics->descent ||
+ pmetrics->leftSideBearing != pmetrics->rightSideBearing) {
+ numchars++;
+ adjust_min_max(&minchar, &maxchar, pmetrics);
+ overlap = pmetrics->rightSideBearing - pmetrics->characterWidth;
+ if (overlap > maxlap) maxlap = overlap;
+ }
+ else pInfo->allExist = 0;
+ }
+
+ /* If we're monospaced, round the average width field to the
+ nearest pixel */
+ if (minchar.characterWidth == maxchar.characterWidth)
+ Vals->width = minchar.characterWidth * 10;
+
+ pInfo->maxbounds = maxchar;
+ pInfo->minbounds = minchar;
+ pInfo->ink_maxbounds = maxchar;
+ pInfo->ink_minbounds = minchar;
+ pInfo->maxOverlap = maxlap + -(minchar.leftSideBearing);
+
+ /* Set the pInfo flags */
+ /* Properties set by FontComputeInfoAccelerators:
+ pInfo->noOverlap;
+ pInfo->terminalFont;
+ pInfo->constantMetrics;
+ pInfo->constantWidth;
+ pInfo->inkInside;
+
+ */
+ FontComputeInfoAccelerators (pInfo);
+}
+
+static void
+ComputeProps(pInfo, Vals, Filename, sAscent, sDescent)
+ FontInfoPtr pInfo;
+ FontScalablePtr Vals;
+ char *Filename;
+ long *sAscent;
+ long *sDescent;
+{
+ int infoint;
+ int infoBBox[4];
+ int rc;
+
+ QueryFontLib(Filename, "isFixedPitch", &infoint, &rc);
+ if (!rc) {
+ pInfo->constantWidth = infoint;
+ }
+ QueryFontLib((char *)0, "FontBBox", infoBBox, &rc);
+ if (!rc) {
+ pInfo->fontAscent =
+ (int)((double)infoBBox[3] * Vals->pixel_matrix[3] +
+ (infoBBox[3] > 0 ? 500 : -500)) / 1000;
+ pInfo->fontDescent =
+ -(int)((double)infoBBox[1] * Vals->pixel_matrix[3] +
+ (infoBBox[1] > 0 ? 500 : -500)) / 1000;
+ *sAscent = infoBBox[3];
+ *sDescent = -infoBBox[1];
+ }
+}
+
+static void
+ComputeStdProps(pInfo, Vals, Filename, Fontname, sAscent, sDescent, sWidth)
+ FontInfoPtr pInfo;
+ FontScalablePtr Vals;
+ char *Filename;
+ char *Fontname;
+ long sAscent;
+ long sDescent;
+ long sWidth;
+{
+ FontPropPtr pp;
+ int i,
+ nprops;
+ fontProp *fpt;
+ char *is_str;
+ char *ptr1,
+ *ptr2;
+ char *ptr3;
+ char *infostrP;
+ long rc;
+ char scaledName[MAXFONTNAMELEN];
+
+ strcpy (scaledName, Fontname);
+ /* Fill in our copy of the fontname from the Vals structure */
+ FontParseXLFDName (scaledName, Vals, FONT_XLFD_REPLACE_VALUE);
+
+ /* This form of the properties is used by the X-client; the X-server
+ doesn't care what they are. */
+ nprops = pInfo->nprops = NPROPS;
+ pInfo->isStringProp = (char *) xalloc(sizeof(char) * nprops);
+ pInfo->props = (FontPropPtr) xalloc(sizeof(FontPropRec) * nprops);
+ if (!pInfo->isStringProp || !pInfo->props) {
+ xfree(pInfo->isStringProp);
+ pInfo->isStringProp = (char *) 0;
+ xfree(pInfo->props);
+ pInfo->props = (FontPropPtr) 0;
+ return;
+ }
+ bzero(pInfo->isStringProp, (sizeof(char) * nprops));
+
+ ptr2 = scaledName;
+ for (i = NNAMEPROPS, pp = pInfo->props, fpt = fontNamePropTable, is_str = pInfo->isStringProp;
+ i;
+ i--, pp++, fpt++, is_str++) {
+
+ if (*ptr2)
+ {
+ ptr1 = ptr2 + 1;
+ if (!(ptr2 = strchr(ptr1, '-'))) ptr2 = strchr(ptr1, '\0');
+ }
+
+ pp->name = fpt->atom;
+ switch (fpt->type) {
+ case atom: /* Just copy info from scaledName */
+ *is_str = TRUE;
+ pp->value = MakeAtom(ptr1, ptr2 - ptr1, TRUE);
+ break;
+ case truncate_atom:
+ *is_str = TRUE;
+ for (ptr3 = ptr1; *ptr3; ptr3++)
+ if (*ptr3 == '[')
+ break;
+ pp->value = MakeAtom(ptr1, ptr3 - ptr1, TRUE);
+ break;
+ case pixel_size:
+ pp->value = (int)(fabs(Vals->pixel_matrix[3]) + .5);
+ break;
+ case point_size:
+ pp->value = (int)(fabs(Vals->point_matrix[3]) * 10.0 + .5);
+ break;
+ case resolution_x:
+ pp->value = Vals->x;
+ break;
+ case resolution_y:
+ pp->value = Vals->y;
+ break;
+ case average_width:
+ pp->value = Vals->width;
+ break;
+ }
+ }
+
+ for (i = 0, fpt = extraProps;
+ i < NEXTRAPROPS;
+ i++, is_str++, pp++, fpt++) {
+ pp->name = fpt->atom;
+ switch (i) {
+ case FONTPROP:
+ *is_str = TRUE;
+ pp->value = MakeAtom(scaledName, strlen(scaledName), TRUE);
+ break;
+ case COPYRIGHTPROP:
+ *is_str = TRUE;
+ QueryFontLib(Filename, "Notice", &infostrP, &rc);
+ if (rc || !infostrP) {
+ infostrP = "Copyright Notice not available";
+ }
+ pp->value = MakeAtom(infostrP, strlen(infostrP), TRUE);
+ break;
+ case FACE_NAMEPROP:
+ *is_str = TRUE;
+ QueryFontLib(Filename, "FontName", &infostrP, &rc);
+ if (rc || !infostrP) {
+ infostrP = "(unknown)";
+ }
+ pp->value = MakeAtom(infostrP, strlen(infostrP), TRUE);
+ break;
+ case RAWPIXELPROP:
+ *is_str = FALSE;
+ pp->value = 1000;
+ break;
+ case RAWPOINTPROP:
+ *is_str = FALSE;
+ pp->value = (long)(72270.0 / (double)Vals->y + .5);
+ break;
+ case RAWASCENTPROP:
+ *is_str = FALSE;
+ pp->value = sAscent;
+ break;
+ case RAWDESCENTPROP:
+ *is_str = FALSE;
+ pp->value = sDescent;
+ break;
+ case RAWWIDTHPROP:
+ *is_str = FALSE;
+ pp->value = sWidth;
+ break;
+ }
+ }
+}
+
+/*ARGSUSED*/
+int
+Type1GetInfoScalable(fpe, pInfo, entry, fontName, fileName, Vals)
+ FontPathElementPtr fpe;
+ FontInfoPtr pInfo;
+ FontEntryPtr entry;
+ FontNamePtr fontName;
+ char *fileName;
+ FontScalablePtr Vals;
+{
+ FontPtr pfont;
+ int flags = 0;
+ long format = 0; /* It doesn't matter what format for just info */
+ long fmask = 0;
+ int ret;
+
+ ret = Type1OpenScalable(fpe, &pfont, flags, entry, fileName, Vals, format, fmask);
+ if (ret != Successful)
+ return ret;
+ *pInfo = pfont->info;
+
+ /* XXX - Set pointers in pfont->info to NULL so they are not freed. */
+ pfont->info.props = NULL;
+ pfont->info.isStringProp = NULL;
+
+ Type1CloseFont(pfont);
+ return Successful;
+}
+
+void
+T1FillFontInfo(pFont, Vals, Filename, Fontname, sWidth)
+ FontPtr pFont;
+ FontScalablePtr Vals;
+ char *Filename;
+ char *Fontname;
+ long sWidth;
+{
+ FontInfoPtr pInfo = &pFont->info;
+ struct type1font *p = (struct type1font *)pFont->fontPrivate;
+ long sAscent, sDescent; /* Scalable 1000-pixel values */
+
+ FillHeader(pInfo, Vals);
+
+ ComputeBounds(pInfo, p->glyphs, Vals);
+
+ ComputeProps(pInfo, Vals, Filename, &sAscent, &sDescent);
+ ComputeStdProps(pInfo, Vals, Filename, Fontname, sAscent, sDescent, sWidth);
+}
+
+/* Called once, at renderer registration time */
+void
+T1InitStdProps()
+{
+ int i;
+ fontProp *t;
+
+ i = sizeof(fontNamePropTable) / sizeof(fontProp);
+ for (t = fontNamePropTable; i; i--, t++)
+ t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
+ i = sizeof(extraProps) / sizeof(fontProp);
+ for (t = extraProps; i; i--, t++)
+ t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
+}
diff --git a/src/Type1/t1intf.h b/src/Type1/t1intf.h
new file mode 100644
index 0000000..52cedb7
--- /dev/null
+++ b/src/Type1/t1intf.h
@@ -0,0 +1,36 @@
+/* $Xorg: t1intf.h,v 1.3 2000/08/17 19:46:33 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#define FIRSTCOL 32
+
+struct type1font {
+ CharInfoPtr pDefault;
+ CharInfoRec glyphs[256-FIRSTCOL];
+};
diff --git a/src/Type1/t1io.c b/src/Type1/t1io.c
new file mode 100644
index 0000000..cd5b77a
--- /dev/null
+++ b/src/Type1/t1io.c
@@ -0,0 +1,294 @@
+/* $Xorg: t1io.c,v 1.3 2000/08/17 19:46:33 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * Author: Carol H. Thompson IBM Almaden Research Center
+ */
+/*******************************************************************
+* I/O package for Type 1 font reading
+********************************************************************/
+
+#ifndef STATIC
+#define STATIC static
+#endif
+
+#include <fcntl.h>
+#include "t1stdio.h"
+#include "t1hdigit.h"
+#ifdef WIN32
+#include <X11/Xw32defs.h>
+#endif
+
+/* Constants and variables used in the decryption */
+#define c1 ((unsigned short)52845)
+#define c2 ((unsigned short)22719)
+static unsigned short r;
+static int asc, Decrypt;
+static int extrach;
+static int haveextrach;
+
+/* Our single FILE structure and buffer for this package */
+STATIC F_FILE TheFile;
+STATIC unsigned char TheBuffer[F_BUFSIZ];
+
+/* Our routines */
+F_FILE *T1Open(), *T1Eexec();
+int T1Close();
+int T1Read(), T1Getc(), T1Ungetc();
+STATIC int T1Decrypt(), T1Fill();
+
+/* -------------------------------------------------------------- */
+/*ARGSUSED*/
+F_FILE *T1Open(fn, mode)
+ char *fn; /* Pointer to filename */
+ char *mode; /* Pointer to open mode string */
+{
+ F_FILE *of = &TheFile;
+ int oflags = O_RDONLY; /* We know we are only reading */
+
+ Decrypt = 0;
+
+#ifdef O_BINARY /* VMS or DOS */
+ oflags |= O_BINARY;
+#endif
+ of->fd = open(fn, oflags);
+ if (of->fd < 0)
+ return NULL;
+
+ /* Initialize the buffer information of our file descriptor */
+ of->b_base = TheBuffer;
+ of->b_size = F_BUFSIZ;
+ of->b_ptr = NULL;
+ of->b_cnt = 0;
+ of->flags = 0;
+ of->error = 0;
+ haveextrach = 0;
+ return &TheFile;
+} /* end Open */
+
+/* -------------------------------------------------------------- */
+int T1Getc(f) /* Read one character */
+ F_FILE *f; /* Stream descriptor */
+{
+ if (f->b_base == NULL) return EOF; /* already closed */
+
+ if (f->flags & UNGOTTENC) { /* there is an ungotten c */
+ f->flags &= ~UNGOTTENC;
+ return (int) f->ungotc;
+ }
+
+ if (f->b_cnt == 0) /* Buffer needs to be (re)filled */
+ f->b_cnt = T1Fill(f);
+ if (f->b_cnt > 0) return (f->b_cnt--, (int) *(f->b_ptr++));
+ else {
+ f->flags |= FIOEOF;
+ return EOF;
+ }
+} /* end Getc */
+
+/* -------------------------------------------------------------- */
+int T1Ungetc(c, f) /* Put back one character */
+ int c;
+ F_FILE *f; /* Stream descriptor */
+{
+ if (c != EOF) {
+ f->ungotc = c;
+ f->flags |= UNGOTTENC; /* set flag */
+ f->flags &= ~FIOEOF; /* reset EOF */
+ }
+ return c;
+} /* end Ungetc */
+
+/* -------------------------------------------------------------- */
+int T1Read(buffP, size, n, f) /* Read n items into caller's buffer */
+ char *buffP; /* Buffer to be filled */
+ int size; /* Size of each item */
+ int n; /* Number of items to read */
+ F_FILE *f; /* Stream descriptor */
+{
+ int bytelen, cnt, i;
+ F_char *p = (F_char *)buffP;
+ int icnt; /* Number of characters to read */
+
+ if (f->b_base == NULL) return 0; /* closed */
+ icnt = (size!=1)?n*size:n; /* Number of bytes we want */
+
+ if (f->flags & UNGOTTENC) { /* there is an ungotten c */
+ f->flags &= ~UNGOTTENC;
+ *(p++) = f->ungotc;
+ icnt--; bytelen = 1;
+ }
+ else bytelen = 0;
+
+ while (icnt > 0) {
+ /* First use any bytes we have buffered in the stream buffer */
+ if ((cnt=f->b_cnt) > 0) {
+ if (cnt > icnt) cnt = icnt;
+ for (i=0; i<cnt; i++) *(p++) = *(f->b_ptr++);
+ f->b_cnt -= cnt;
+ icnt -= cnt;
+ bytelen += cnt;
+ }
+
+ if ((icnt == 0) || (f->flags & FIOEOF)) break;
+
+ f->b_cnt = T1Fill(f);
+ }
+ return ((size!=1)?bytelen/size:bytelen);
+} /* end Read */
+
+/* -------------------------------------------------------------- */
+int T1Close(f) /* Close the file */
+ F_FILE *f; /* Stream descriptor */
+{
+ if (f->b_base == NULL) return 0; /* already closed */
+ f->b_base = NULL; /* no valid stream */
+ return close(f->fd);
+} /* end Close */
+
+#ifdef __STDC__
+#define pointer void *
+#else
+#define pointer char *
+#endif
+
+/* -------------------------------------------------------------- */
+F_FILE *T1eexec(f) /* Initialization */
+ F_FILE *f; /* Stream descriptor */
+{
+ int i, c;
+ int H;
+ unsigned char *p;
+ unsigned char randomP[8];
+
+ r = 55665; /* initial key */
+ asc = 1; /* indicate ASCII form */
+
+ /* Consume the 4 random bytes, determining if we are also to
+ ASCIIDecodeHex as we process our input. (See pages 63-64
+ of the Adobe Type 1 Font Format book.) */
+
+ /* Skip over any initial white space chars */
+ while (HighHexP[c=_XT1getc(f)] == HWHITE_SPACE) ;
+
+ /* If ASCII, the next 7 chars are guaranteed consecutive */
+ randomP[0] = c; /* store first non white space char */
+ T1Read((pointer)(randomP+1), 1, 3, f); /* read 3 more, for a total of 4 */
+ /* store first four chars */
+ for (i=0,p=randomP; i<4; i++) { /* Check 4 valid ASCIIEncode chars */
+ if (HighHexP[*p++] > LAST_HDIGIT) { /* non-ASCII byte */
+ asc = 0;
+ break;
+ }
+ }
+ if (asc) { /* ASCII form, convert first eight bytes to binary */
+ T1Read((pointer)(randomP+4), 1, 4, f); /* Need four more */
+ for (i=0,p=randomP; i<4; i++) { /* Convert */
+ H = HighHexP[*p++];
+ randomP[i] = H | LowHexP[*p++];
+ }
+ }
+
+ /* Adjust our key */
+ for (i=0,p=randomP; i<4; i++) {
+ r = (*p++ + r) * c1 + c2;
+ }
+
+ /* Decrypt the remaining buffered bytes */
+ f->b_cnt = T1Decrypt(f->b_ptr, f->b_cnt);
+ Decrypt = 1;
+ return (T1Feof(f))?NULL:f;
+} /* end eexec */
+
+/* -------------------------------------------------------------- */
+STATIC int T1Decrypt(p, len)
+ unsigned char *p;
+ int len;
+{
+ int n;
+ int H, L;
+ unsigned char *inp = p;
+ unsigned char *tblP;
+
+ if (asc) {
+ if (haveextrach) {
+ H = extrach;
+ tblP = LowHexP;
+ }
+ else tblP = HighHexP;
+ for (n=0; len>0; len--) {
+ L = tblP[*inp++];
+ if (L == HWHITE_SPACE) continue;
+ if (L > LAST_HDIGIT) break;
+ if (tblP == HighHexP) { /* Got first hexit value */
+ H = L;
+ tblP = LowHexP;
+ } else { /* Got second hexit value; compute value and store it */
+ n++;
+ tblP = HighHexP;
+ H |= L;
+ /* H is an int, 0 <= H <= 255, so all of this will work */
+ *p++ = H ^ (r >> 8);
+ r = (H + r) * c1 + c2;
+ }
+ }
+ if (tblP != HighHexP) { /* We had an odd number of hexits */
+ extrach = H;
+ haveextrach = 1;
+ } else haveextrach = 0;
+ return n;
+ } else {
+ for (n = len; n>0; n--) {
+ H = *inp++;
+ *p++ = H ^ (r >> 8);
+ r = (H + r) * c1 + c2;
+ }
+ return len;
+ }
+} /* end Decrypt */
+
+/* -------------------------------------------------------------- */
+STATIC int T1Fill(f) /* Refill stream buffer */
+ F_FILE *f; /* Stream descriptor */
+{
+ int rc;
+
+ rc = read(f->fd, f->b_base, F_BUFSIZ);
+ /* propagate any error or eof to current file */
+ if (rc <= 0) {
+ if (rc == 0) /* means EOF */
+ f->flags |= FIOEOF;
+ else {
+ f->error = (short)-rc;
+ f->flags |= FIOERROR;
+ rc = 0;
+ }
+ }
+ f->b_ptr = f->b_base;
+ if (Decrypt) rc = T1Decrypt(f->b_base, rc);
+ return rc;
+} /* end Fill */
diff --git a/src/Type1/t1malloc.c b/src/Type1/t1malloc.c
new file mode 100644
index 0000000..5028c8c
--- /dev/null
+++ b/src/Type1/t1malloc.c
@@ -0,0 +1,735 @@
+/* $Xorg: t1malloc.c,v 1.3 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
+ * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+ * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
+ * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
+ * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
+ * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
+ * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+ /* MALLOC CWEB V0004 LOTS */
+/*
+:h1.MALLOC - Fast Memory Allocation
+
+This module is meant to provide portable C-style memory allocation
+routines (malloc/free).
+
+&author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
+
+*/
+
+#include "objects.h" /* get #define for abort() */
+
+static void combine();
+static void freeuncombinable();
+static void unhook();
+static void dumpchain();
+
+/*
+:h3.Define NULL
+
+In the beginning, C compilers made no assumptions about NULL. It was
+even theoretically possible that NULL would not be 0. ANSI has tied
+this down a bit. The following definition seems to be the most
+popular (in terms of reducing compiler complaints), however, if your
+compiler is unhappy about it, you can redefine it on the command line:
+*/
+#ifndef NULL
+#define NULL 0
+#endif
+/*
+Of course, NULL is important because xiMalloc() is defined to return
+NULL when out of memory.
+
+:h2.Data Structures Used to Manage Free Memory
+
+:h3.The "freeblock" Structure
+
+The list of available memory blocks is a doubly-linked list. Each
+block begins with the following structure:
+*/
+
+struct freeblock {
+ long size; /* number of 'longs' in block,
+ including this header */
+ struct freeblock *fore; /* forward in doubly-linked list */
+ struct freeblock *back; /* backward in doubly-linked list */
+} ;
+/*
+In addition, each free block has a TRAILER that is simply the 'size'
+repeated. Thus 'size' is found at the beginning of the block and at the
+end of the block (size-1 longs away). 'size' includes both the header
+and the trailer.
+
+When a block is allocated, its 'size' is turned negative (both at the
+beginning and at the end). Thus, checking whether two blocks may be
+combined is very simple. We merely examine both neighboring blocks'
+size to see if they are positive (and hence available for combination).
+
+The memory address returned to the user is therefore one "long" below the
+size, and one extra "long" is added to the end of the block (beyond what
+the user requested) to store the trailing size.
+
+:h3."firstfree" and "lastfree", the Anchors to the Free List
+
+"firstfree" points to the first available free block; "lastfree" points
+to the end of the chain of available blocks. These are linked together
+by initialization code; see :hdref refid=addmem..
+*/
+
+static struct freeblock firstfree = { 0L, NULL, NULL };
+static struct freeblock lastfree = { 0L, NULL, NULL };
+
+/*
+:h3."firstcombined" and "uncombined", Keeping Track of Uncombined Blocks
+
+This module is designed to make the combining of adjacent free memory
+blocks be very fast. Nonetheless, combining blocks is naturally the
+most expensive part of any memory system. In an X system,
+it is worthwhile to defer the combination for a while, because
+frequently we will end up asking for a block of exactly the same
+size that we recently returned and we can save ourselves some work.
+
+"MAXUNCOMBINED" is the maximum number of uncombined blocks that we will
+allow at any time:
+*/
+
+#define MAXUNCOMBINED 3
+
+/*
+"firstcombined" is a pointer into the free list. The uncombined blocks
+are always at the front of the list. "firstcombined" points to the
+first block that has been combined.
+*/
+static struct freeblock *firstcombined = &lastfree;
+static short uncombined = 0; /* current number of uncombined blocks */
+
+/*
+Uncombined blocks have a negative 'size'; in this they are like
+allocated blocks.
+
+We store a distinctive hex pattern in 'size' when we combine a block
+to help us debug:
+*/
+#define COMBINED 0xBADBAD
+
+/*
+:h3.DEBUGWORDS - Extra Memory Saved With Each Block for Debug
+
+We add 'DEBUGWORDS' words to each allocated block to put interesting
+debug information:
+*/
+#ifndef DEBUGWORDS
+#define DEBUGWORDS 0
+#endif
+
+/*
+:h3.MINEXCESS - Amount of "Excess" We Would be Willing to Ignore
+
+When we search the free list to find memory for a user request, we
+frequently find an area that is bigger than what the user has asked for.
+Normally we put the remaining words (the excess) back on the free list.
+However, if the area is just slightly bigger than what the user needs,
+it is counter-productive to do this, as the small amount recovered tends
+to hurt by increasing memory fragmentation rather than help by providing
+more available memory. "MINEXCESS" is the number of words that must be
+recovered before we would bother to put the excess back on the free
+list. If there is not enough excess, we just give the user more than he
+asked for.
+*/
+
+#define MINEXCESS (7 + DEBUGWORDS)
+
+/*
+:h3.Some Flags for Debug
+*/
+
+long AvailableWords = 0; /* number of words available in memory */
+char mallocdebug = 0; /* a flag that enables some chatty printf's */
+
+/*
+:h3.whocalledme() - Debug for Memory Leaks
+
+This routine is 68000-specific; it copies the value of the application's
+curOper variable (which is often a pointer to a character string), and
+the first part of the stack at the time malloc was called into the
+DEBUGWORDS area reserved with each block.
+We use it to see who is malloc-ing memory without free-ing it.
+*/
+
+#if DEBUGWORDS
+
+static whocalledme(addr, stack)
+ long *addr; /* address of memory block */
+ long *stack; /* address of malloc's parameter on stack */
+{
+ register long size; /* size of memory block */
+ register int i; /* loop index */
+ extern char *curOper; /* ptr to last operator (kept by appl.) */
+
+ stack--;
+ size = - *addr;
+
+ addr += size - 1 - DEBUGWORDS;
+ *addr++ = (long) curOper;
+ for (i=0; i < DEBUGWORDS-1; i++)
+ *addr++ = *stack++;
+}
+#else
+
+#define whocalledme(addr, stack)
+
+#endif
+/*
+:h2.xiFree() - User-Callable "Return Memory" Routine
+
+The actual beginning of the block is one 'long' before the address we
+gave to the user. The block begins and ends with '-size' in words.
+*/
+
+void xiFree(addr)
+ register long *addr; /* user's memory to be returned */
+{
+ register long size; /* amount of memory in this block */
+ register struct freeblock *p; /* identical to 'addr' */
+
+ if (addr == NULL) { /* common "mistake", so allow it (CHT) */
+ printf("\nxiFree(NULL)?\n");
+ return;
+ }
+
+ size = *--addr;
+/*
+Make sure this address looks OK; 'size' must be less than zero (meaning
+the block is allocated) and should be repeated at the end of the block.
+*/
+ if (size >= 0)
+ abort("free: bad size");
+ if (addr[-1 - size] != size)
+ abort("free: mismatched size");
+/*
+Now make this a 'freeblock' structure and tack it on the FRONT of the
+free list (where uncombined blocks go):
+*/
+ AvailableWords -= size; /* actually INCREASES AvailableWords */
+ p = (struct freeblock *) addr;
+ p->back = &firstfree;
+ (p->fore = firstfree.fore)->back = p;
+ firstfree.fore = p;
+/*
+If we have too many uncombined blocks, call combine() to combine one.
+*/
+ if (++uncombined > MAXUNCOMBINED) {
+ combine();
+ if (mallocdebug) {
+ printf("xiFree(%p) with combine, ", addr);
+ dumpchain();
+ }
+ }
+ else {
+ if (mallocdebug) {
+ printf("xiFree(%p), ", addr);
+ dumpchain();
+ }
+ }
+
+ return;
+}
+
+/*
+:h3.combine() - Subroutine of xiFree() to Combine Blocks
+
+This routine tries to combine the block just before 'firstcombined'.
+In any event, that block will be moved to the end of the list (after
+'firstcombined').
+*/
+
+static void
+combine()
+{
+ register struct freeblock *p; /* block we will try to combine */
+ register long *addr; /* identical to 'p' for 'long' access */
+ register long size; /* size of this block */
+ register long size2; /* size of potential combinee */
+
+ p = firstcombined->back;
+ if (p == &firstfree)
+ abort("why are we combining?");
+
+ addr = (long *) p;
+ size = - p->size;
+ if (--uncombined < 0)
+ abort("too many combine()s");
+
+ if (addr[-1] < 0 && addr[size] < 0) {
+/*
+We special case the situation where no combining can be done. Then, we
+just mark the chain "combined" (i.e., positive size), move the
+'firstcombined' pointer back in the chain, and return.
+*/
+ addr[0] = addr[size - 1] = size;
+ firstcombined = (struct freeblock *) addr;
+ return;
+ }
+/*
+Otherwise, we unhook this pointer from the chain:
+*/
+ unhook(p);
+/*
+First we attempt to combine this with the block immediately above:
+*/
+ size2 = addr[-1];
+ if (size2 > 0) { /* i.e., block above is free */
+ *addr = COMBINED; /* might help debug */
+ addr -= size2;
+ if (addr[0] != size2)
+ abort("bad block above");
+ unhook(addr);
+ size += size2;
+ }
+/*
+At this point 'addr' and 'size' may be the original block, or it may be
+the newly combined block. Now we attempt to combine it with the block
+below:
+*/
+ p = (struct freeblock *) (addr + size);
+ size2 = p->size;
+
+ if (size2 > 0) { /* i.e., block below is free */
+ p->size = COMBINED;
+ if (size2 != ((long *) p)[size2 - 1])
+ abort("bad block below");
+ unhook(p);
+ size += size2;
+ }
+/*
+Finally we take the newly combined block and put it on the end of the
+chain by calling the "freeuncombinable" subroutine:
+*/
+ freeuncombinable(addr, size);
+}
+
+/*
+:h3.freeuncombinable() - Free a Block That Need Not be Combined
+
+This block is "uncombinable" either because we have already combined
+it with its eligible neighbors, or perhaps because we know it has
+no neighbors.
+*/
+
+static void
+freeuncombinable(addr, size)
+ register long *addr; /* address of the block to be freed */
+ register long size; /* size of block in words */
+{
+ register struct freeblock *p; /* a convenient synonym for 'addr' */
+
+/*
+Mark block allocated and combined by setting its 'size' positive:
+*/
+ addr[size - 1] = addr[0] = size;
+/*
+Now tack the block on the end of the doubly-linked free list:
+*/
+ p = (struct freeblock *) addr;
+ p->fore = &lastfree;
+ (p->back = lastfree.back)->fore = p;
+ lastfree.back = p;
+/*
+If we have previously had no combined blocks, we must update
+'firstcombined' to point to this block:
+*/
+ if (firstcombined->fore == NULL)
+ firstcombined = p;
+}
+
+/*
+:h3.unhook() - Unhook a Block from the Doubly-linked List
+
+The only tricky thing here is to make sure that 'firstcombined' is
+updated if this block happened to be the old 'firstcombined'. (We
+would never be unhooking 'firstfree' or 'lastfree', so we do not
+have to worry about the end cases.)
+*/
+
+static void
+unhook(p)
+ register struct freeblock *p; /* block to unhook */
+{
+ p->back->fore = p->fore;
+ p->fore->back = p->back;
+
+ if (firstcombined == p)
+ firstcombined = p->fore;
+}
+/*
+:h2.xiMalloc() - Main User Entry Point for Getting Memory
+
+We have two slightly different versions of xiMalloc(). In the case
+where we have TYPE1IMAGER and a font cache, we are prepared, when nominally
+out of memory, to loop calling TYPE1IMAGER's GimeSpace() to release font
+cache.
+*/
+
+/* The following code put in by MDC on 11/10/90 */
+
+#ifdef TYPE1IMAGER
+
+static char *malloc_local();
+
+char *xiMalloc(size)
+ register unsigned size;
+{
+ char *memaddr;
+
+ while ( (memaddr = malloc_local(size)) == NULL ) {
+ /* Ask TYPE1IMAGER to give us some of its cache back */
+ if ( I_GimeSpace() == 0 ) break; /* We are really, really, out of memory */
+ }
+
+ return(memaddr);
+}
+#endif
+
+/*
+Now begins the real workhorse xiMalloc() (called 'malloc_local' if
+we are taking advantage of TYPE1IMAGER). Its argument is an unsigned;
+at least that lets users with 16-bit integers get a 64K chunk of
+memory, and it is also compatible with the definition of a "size_t"
+in most systems.
+*/
+#ifdef TYPE1IMAGER
+static char *malloc_local(Size)
+#else
+char *xiMalloc(Size)
+#endif
+ unsigned Size; /* number of bytes the user requested */
+{
+ register long size = (long)Size; /* a working register for size */
+ register struct freeblock *p; /* tentative block to be returned */
+ register long excess; /* words in excess of user request */
+ register long *area; /* a convenient synonym for 'p' */
+
+/*
+First, we increase 'size' to allow for the two size fields we will
+save with the block, plus any information for debug purposes.
+Then we ensure that the block will be large enough to hold our
+'freeblock' information. Finally we convert it to be in words
+(longs), not bytes, increased to span an integral number of double
+words, so that all memory blocks dispensed with be properly aligned.
+*/
+ size += 2*sizeof(long) + DEBUGWORDS*sizeof(long);
+ if (size < sizeof(struct freeblock) + sizeof(long))
+ size = sizeof(struct freeblock) + sizeof(long);
+ size = ((unsigned) (size + sizeof(double) - 1) / sizeof(double)) * (sizeof(double)/sizeof(long));
+
+/*
+For speed, we will try first to give the user back a very recently
+returned block--one that is on the front of the chain before
+'firstcombined'. These blocks still have negative sizes, and need
+only to be "unhook"ed:
+*/
+ size = -size;
+ for (p=firstfree.fore; p != firstcombined; p=p->fore) {
+ if (p->size == size) {
+ unhook(p);
+ uncombined--;
+ if (mallocdebug) {
+ printf("fast xiMalloc(%d) = %p, ", size, p);
+ dumpchain();
+ }
+ AvailableWords += size; /* decreases AvailableWords */
+ whocalledme(p, &Size);
+ return((char *)&p->fore);
+ }
+ }
+/*
+Well, if we get here, there are no uncombined blocks matching the user's
+request. So, we search the rest of the chain for a block that is big
+enough. ('size' becomes positive again):
+*/
+ size = -size;
+ for (;; p = p->fore) {
+/*
+If we hit the end of the chain (p->size == 0), we are probably out of
+memory. However, we should first try to combine any memory that has
+not yet been combined before we give that pessimistic answer. If
+we succeed in combining, we can call ourselves recursively to try to
+allocate the requested amount:
+*/
+ if (p->size == 0) {
+ if (uncombined <= 0)
+ return(NULL);
+ while (firstfree.fore != firstcombined)
+ combine();
+ return(xiMalloc(sizeof(long) * (size - 2 - DEBUGWORDS)));
+ }
+/*
+Otherwise, we keep searching until we find a big enough block:
+*/
+ if (p->size >= size)
+ break;
+ }
+/*
+At this point, 'p' contains a block at least as big as what the user
+requested, so we take it off the free chain. If it is excessively big,
+we return the excess to the free chain:
+*/
+ unhook(p);
+ excess = p->size - size;
+ area = (long *) p;
+
+ if (excess > MINEXCESS)
+ freeuncombinable(area + size, excess);
+ else
+ size = p->size;
+
+ AvailableWords -= size;
+/*
+Mark first and last word of block with the negative of the size, to
+flag that this block is allocated:
+*/
+ area[size - 1] = area[0] = - size;
+
+ if (mallocdebug) {
+ printf("slow xiMalloc(%d) @ %08x, ", size, area);
+ dumpchain();
+ }
+ whocalledme(area, &Size);
+/*
+The address we return to the user is one 'long' BELOW the address of
+the block. This protects our 'size' field, so we can tell the size
+of the block when he returns it to us with xiFree(). Also, he better not
+touch the 'size' field at the end of the block either. (That would be
+nasty of him, as he would be touching memory outside of the bytes he
+requested).
+*/
+ return((char *) (area + 1));
+}
+
+/*
+:h2 id=addmem.addmemory() - Initialize Free Memory
+
+This routine should be called at initialization to initialize the
+free chain. There is no standard way to do this in C.
+We want the memory dispensed by malloc to be aligned on a double word
+boundary (because some machines either require alignment, or are
+more efficient if accesses are aligned). Since the total size of
+any block created by malloc is an integral number of double words,
+all we have to do to ensure alignment is to adjust each large block
+added to the free chain to start on an odd long-word boundary.
+(Malloc's size field will occupy the odd long and the user's memory
+will then begin on an even boundary.) Since we fill in additional
+size fields at the beginning and end of each of the large freeblocks,
+we need only adjust the address passed to addmemory to a double word
+boundary.
+*/
+
+#define MAXAREAS 10 /* there can be this many calls to addmemory() */
+
+static long *freearea[MAXAREAS] = { NULL }; /* so we can report later */
+
+void addmemory(addr, size)
+ register long *addr; /* beginning of free area */
+ register long size; /* number of bytes of free area */
+{
+ register int i; /* loop index variable */
+ register long *aaddr; /* aligned beginning of free area */
+
+#if DEBUGWORDS
+ printf("malloc has DEBUGWORDS=%d\n", DEBUGWORDS);
+#endif
+/*
+First link together firstfree and lastfree if necessary:
+*/
+ if (firstfree.fore == NULL) {
+ firstfree.fore = &lastfree;
+ lastfree.back = &firstfree;
+ }
+/*
+We'll record where the area was that was given to us for later reports:
+*/
+ for (i=0; i < MAXAREAS; i++)
+ if (freearea[i] == NULL) break;
+ if (i >= MAXAREAS)
+ abort("too many addmemory()s");
+ aaddr = (long *) ( ((long) addr + sizeof(double) - 1) & - (long)sizeof(double) );
+ size -= (char *) aaddr - (char *) addr;
+ freearea[i] = aaddr;
+/*
+Convert 'size' to number of longs, and store '-size' guards at the
+beginning and end of this area so we will not accidentally recombine the
+first or last block:
+*/
+ size /= sizeof(long);
+
+ AvailableWords += size - 2;
+
+ aaddr[size - 1] = aaddr[0] = -size;
+/*
+Finally, call 'freeuncombinable' to put the remaining memory on the
+free list:
+*/
+ freeuncombinable(aaddr + 1, size - 2);
+}
+
+/*
+:h3.delmemory() - Delete Memory Pool
+*/
+void delmemory()
+{
+ register int i;
+
+ AvailableWords = 0;
+ firstfree.fore = &lastfree;
+ lastfree.back = &firstfree;
+ firstcombined = &lastfree;
+ uncombined = 0;
+ for (i=0; i<MAXAREAS; i++)
+ freearea[i] = NULL;
+}
+
+/*
+:h2.Debug Routines
+
+:h3.dumpchain() - Print the Chain of Free Blocks
+*/
+
+static void
+dumpchain()
+{
+ register struct freeblock *p; /* current free block */
+ register long size; /* size of block */
+ register struct freeblock *back; /* block before 'p' */
+ register int i; /* temp variable for counting */
+
+ printf("DUMPING FAST FREE LIST:\n");
+ back = &firstfree;
+ for (p = firstfree.fore, i=uncombined; p != firstcombined;
+ p = p->fore) {
+ if (--i < 0)
+ abort("too many uncombined areas");
+ size = p->size;
+ printf(". . . area @ %p, size = %ld\n", p, -size);
+ if (size >= 0 || size != ((int *) p)[-1 - size])
+ abort("dumpchain: bad size");
+ if (p->back != back)
+ abort("dumpchain: bad back");
+ back = p;
+ }
+ printf("DUMPING COMBINED FREE LIST:\n");
+ for (; p != &lastfree; p = p->fore) {
+ size = p->size;
+ printf(". . . area @ %p, size = %d\n", p, size);
+ if (size <= 0 || size != ((int *) p)[size - 1])
+ abort("dumpchain: bad size");
+ if (p->back != back)
+ abort("dumpchain: bad back");
+ back = p;
+ }
+ if (back != lastfree.back)
+ abort("dumpchain: bad lastfree");
+}
+
+/*
+:h3.reportarea() - Display a Contiguous Set of Memory Blocks
+*/
+
+static void
+reportarea(area)
+ register long *area; /* start of blocks (from addmemory) */
+{
+ register long size; /* size of current block */
+ register long wholesize; /* size of original area */
+ register struct freeblock *p; /* pointer to block */
+
+ if (area == NULL)
+ return;
+ wholesize = - *area++;
+ wholesize -= 2;
+
+ while (wholesize > 0) {
+ size = *area;
+ if (size < 0) {
+ register int i,j;
+
+ size = -size;
+ printf("Allocated %5d bytes at %08x, first words=%08x %08x\n",
+ size * sizeof(long), area + 1, area[1], area[2]);
+#if DEBUGWORDS
+ printf(" ...Last operator: %s\n",
+ (char *)area[size-DEBUGWORDS-1]);
+#endif
+ for (i = size - DEBUGWORDS; i < size - 2; i += 8) {
+ printf(" ...");
+ for (j=0; j<8; j++)
+ printf(" %08x", area[i+j]);
+ printf("\n");
+ }
+
+ }
+ else {
+ printf("Free %d bytes at %x\n", size * sizeof(long),
+ area);
+ if (size == 0)
+ abort("zero sized memory block");
+
+ for (p = firstfree.fore; p != NULL; p = p->fore)
+ if ((long *) p == area) break;
+ if ((long *) p != area)
+ abort("not found on forward chain");
+
+ for (p = lastfree.back; p != NULL; p = p->back)
+ if ((long *) p == area) break;
+ if ((long *) p != area)
+ abort("not found on backward chain");
+ }
+ if (area[0] != area[size - 1])
+ abort("unmatched check sizes");
+ area += size;
+ wholesize -= size;
+ }
+}
+
+/*
+:h3.MemReport() - Display All of Memory
+*/
+
+void MemReport()
+{
+ register int i;
+
+ dumpchain();
+
+ for (i=0; i<MAXAREAS; i++)
+ reportarea(freearea[i]);
+}
+
+/*
+:h3.MemBytesAvail - Display Number of Bytes Now Available
+*/
+
+void MemBytesAvail()
+{
+ printf("There are now %d bytes available\n", AvailableWords *
+ sizeof(long) );
+}
diff --git a/src/Type1/t1snap.c b/src/Type1/t1snap.c
new file mode 100644
index 0000000..fd26e36
--- /dev/null
+++ b/src/Type1/t1snap.c
@@ -0,0 +1,79 @@
+/* $Xorg: t1snap.c,v 1.3 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "objects.h"
+#include "spaces.h"
+#include "paths.h"
+
+/*
+:h2.Handle Functions
+
+:h3.Phantom() - Returns a Move Segment Equivalent to Handles
+
+This is a user operator. Its new name is QueryHandle.
+*/
+
+struct segment *t1_Phantom(obj)
+ register struct xobject *obj; /* object to take the Phantom of */
+{
+ struct fractpoint pt; /* handle size will built here */
+
+ if (obj == NULL)
+ pt.x = pt.y = 0;
+ else
+ PathDelta(obj, &pt);
+
+ return(PathSegment(MOVETYPE, pt.x, pt.y));
+}
+
+/*
+:h3.Snap() - Force Ending Handle of Object to Origin
+
+This is a user operator.
+*/
+
+struct xobject *t1_Snap(p)
+ register struct segment *p; /* path to snap */
+{
+ struct fractpoint pt; /* for finding length of path */
+
+ if (p == NULL)
+ return(NULL);
+ p = UniquePath(p);
+
+ PathDelta(p, &pt);
+ if (p->last->type == MOVETYPE) {
+ p->last->dest.x -= pt.x;
+ p->last->dest.y -= pt.y;
+ }
+ else
+ p = JoinSegment(p, MOVETYPE, -pt.x, -pt.y, NULL);
+ return((struct xobject *)p);
+}
diff --git a/src/Type1/t1stdio.h b/src/Type1/t1stdio.h
new file mode 100644
index 0000000..b18ac5c
--- /dev/null
+++ b/src/Type1/t1stdio.h
@@ -0,0 +1,68 @@
+/* $Xorg: t1stdio.h,v 1.3 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* T1IO FILE structure and related stuff */
+#define FILE F_FILE
+typedef unsigned char F_char;
+
+typedef struct F_FILE {
+ F_char *b_base; /* Pointer to beginning of buffer */
+ long b_size; /* Size of the buffer */
+ F_char *b_ptr; /* Pointer to next char in buffer */
+ long b_cnt; /* Number of chars remaining in buffer */
+ F_char flags; /* other flags; != 0 means getc must call fgetc */
+ F_char ungotc; /* Place for ungotten char; flag set if present */
+ short error; /* error status */
+ int fd; /* underlying file descriptor */
+} F_FILE;
+
+
+/* defines for flags */
+#define UNGOTTENC (0x01)
+#define FIOEOF (0x80)
+#define FIOERROR (0x40)
+
+#ifndef NULL
+#define NULL 0 /* null pointer */
+#endif
+#define EOF (-1) /* end of file */
+#define F_BUFSIZ (512)
+
+#define _XT1getc(f) \
+ ( \
+ ( ((f)->b_cnt > 0) && ((f)->flags == 0) ) ? \
+ ( (f)->b_cnt--, (unsigned int)*( (f)->b_ptr++ ) ) : \
+ T1Getc(f) \
+ )
+
+#define T1Feof(f) (((f)->flags & FIOEOF) && ((f)->b_cnt==0))
+
+extern FILE *T1Open(), *T1eexec();
+extern int T1Close(), T1Ungetc(), T1Read();
+
diff --git a/src/Type1/t1stub.c b/src/Type1/t1stub.c
new file mode 100644
index 0000000..82be9b3
--- /dev/null
+++ b/src/Type1/t1stub.c
@@ -0,0 +1,42 @@
+/* $Xorg: t1stub.c,v 1.3 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "objects.h" /* get #define for abort() */
+
+xiStub()
+{
+ printf("xiStub called\n");
+ abort("xiStub called");
+}
+
+void t1_DumpText()
+{
+ xiStub();
+}
diff --git a/src/Type1/token.c b/src/Type1/token.c
new file mode 100644
index 0000000..054e1ea
--- /dev/null
+++ b/src/Type1/token.c
@@ -0,0 +1,1212 @@
+/* $Xorg: token.c,v 1.4 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* Authors: Sig Nin & Carol Thompson IBM Almaden Research Laboratory */
+#include "t1stdio.h"
+#include "util.h"
+#include "digit.h"
+#include "token.h"
+#include "tokst.h"
+#include "hdigit.h"
+
+/*
+ * -------------------------------------------------------------------
+ * Globals
+ * -------------------------------------------------------------------
+ */
+
+/* These variables are set by the caller */
+char *tokenStartP; /* Pointer to token buffer in VM */
+char *tokenMaxP; /* Pointer to last byte in buffer + 1 */
+
+/* These variables are set by TOKEN */
+int tokenLength; /* Characters in token */
+boolean tokenTooLong; /* Token too long for buffer */
+int tokenType; /* Type of token identified */
+psvalue tokenValue; /* Token value */
+
+/*
+ * -------------------------------------------------------------------
+ * Private variables
+ * -------------------------------------------------------------------
+ */
+
+static FILE *inputFileP; /* Current input file */
+
+
+/* Token */
+static char *tokenCharP; /* Pointer to next character in token */
+
+/*
+ * -------------------------------------------------------------------
+ * Private routines for manipulating numbers
+ * -------------------------------------------------------------------
+ */
+
+#define Exp10(e) \
+((e) == 0\
+ ? (double)(1.0)\
+ : (-64 <= (e) && (e) <= 63\
+ ? Exp10T[(e)+64]\
+ : P10(e)\
+ )\
+)
+
+static double Exp10T[128] = {
+ 1e-64, 1e-63, 1e-62, 1e-61, 1e-60, 1e-59, 1e-58, 1e-57,
+ 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49,
+ 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41,
+ 1e-40, 1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33,
+ 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25,
+ 1e-24, 1e-23, 1e-22, 1e-21, 1e-20, 1e-19, 1e-18, 1e-17,
+ 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9,
+ 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
+ 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
+ 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23,
+ 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31,
+ 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
+ 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47,
+ 1e48, 1e49, 1e50, 1e51, 1e52, 1e53, 1e54, 1e55,
+ 1e56, 1e57, 1e58, 1e59, 1e60, 1e61, 1e62, 1e63
+};
+
+static double P10(exponent)
+ long exponent;
+{
+ double value, power;
+
+ if (exponent < 0) {
+ power = 0.1;
+ value = (exponent & 1 ? power : 1.0);
+ exponent++;
+ exponent = -(exponent >> 1); /* portable C for -(exponent/2) */
+ }
+ else {
+ power = 10.0;
+ value = (exponent & 1 ? power : 1.0);
+ exponent = exponent >> 1;
+ }
+
+ while(exponent > 0) {
+ power *= power;
+ if (exponent & 1)
+ value *= power;
+ exponent >>= 1;
+ }
+
+ return(value);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Private routines and macros for manipulating the input
+ * -------------------------------------------------------------------
+ */
+
+/* Get next character from the input --
+ *
+ */
+#define next_ch() (_XT1getc(inputFileP))
+
+/* Push a character back into the input --
+ *
+ * Ungetc of EOF will fail, but that's ok: the next getc will
+ * return EOF.
+ *
+ * NOTE: These macros are presently written to return the character
+ * pushed, or EOF if none was pushed. However, they are not
+ * required to return anything in particular, and callers should
+ * not rely on the returned value.
+ */
+#define back_ch(ch) (T1Ungetc(ch, inputFileP))
+
+/* Push a character back into the input if it was not white space.
+ * If it is a carriage return (\r) then check next char for
+ * linefeed and consume them both, otherwise put next char back.
+ *
+ */
+#define back_ch_not_white(ch) \
+(\
+isWHITE_SPACE(ch)\
+ ? ((ch == '\r')\
+ ? (((ch = next_ch()) == '\n')\
+ ? EOF\
+ : back_ch(ch)\
+ )\
+ : EOF\
+ )\
+ : back_ch(ch)\
+)
+
+/*
+ * -------------------------------------------------------------------
+ * Private routines and macros for manipulating the token buffer
+ * -------------------------------------------------------------------
+ */
+
+/* Add a character to the token
+ * ---- use ONLY when you KNOW that this character will
+ * be stored within the token buffer.
+ */
+#define save_unsafe_ch(ch) (*tokenCharP++ = ch)
+
+/* Add a character to the token, if not too long to fit */
+#define save_ch(ch) \
+((tokenCharP < tokenMaxP)\
+ ? save_unsafe_ch(ch)\
+ : (tokenTooLong = TRUE)\
+)
+
+#define save_ch_no_inc(ch) \
+((tokenCharP < tokenMaxP) && (*tokenCharP = ch))
+
+/*
+ * -------------------------------------------------------------------
+ * Action Routines
+ *
+ * These routines all
+ * -- take int ch as a parameter
+ * -- return int ch if no token was recognized, DONE otherwise
+ * -- leave the next character in the input, if returning DONE
+ * -------------------------------------------------------------------
+ */
+
+#define DONE (256)
+
+/* Get the next input character */
+static int next_char(ch)
+ int ch;
+{
+ return(next_ch());
+}
+
+/* Add character to token */
+static int add_char(ch)
+ int ch;
+{
+ save_ch(ch);
+ return(next_ch());
+}
+
+
+/* -------------------------------------------------------------------
+ * Skip white space and comments
+ */
+
+/* Skip white space */
+static int skip_space(ch)
+ int ch;
+{
+ do {
+ ch = next_ch();
+ } while(isWHITE_SPACE(ch));
+ return(ch);
+}
+
+/* Skip comments */
+static int skip_comment(ch)
+ int ch;
+{
+ do {
+ ch = next_ch();
+ } while(isCOMMENT(ch));
+ return(ch);
+}
+
+/* -------------------------------------------------------------------
+ * Collect value elements for a number
+ */
+
+/* decimal integer or real number mantissa */
+static int m_sign;
+static long m_value;
+static long m_scale;
+
+/* real number exponent */
+static int e_sign;
+static long e_value;
+static long e_scale;
+
+/* radix number */
+static long r_base;
+static long r_value;
+static long r_scale;
+
+static int add_sign(ch)
+ int ch;
+{
+ m_sign = ch;
+ save_unsafe_ch(ch);
+ return(next_ch());
+}
+
+static int add_1st_digits(ch)
+ int ch;
+{
+ m_sign = '+';
+ return(add_digits(ch));
+}
+
+static int add_digits(ch)
+ int ch;
+{
+ long value, p_value, scale;
+ int digit;
+
+ /* On entry, expect m_sign to be set to '+' or '-';
+ * ch is a decimal digit.
+ * Expect at most one character saved at this point,
+ * a sign. This routine will save up to 10 more
+ * characters without checking the buffer boundary.
+ */
+
+ value = ch - '0';
+ save_unsafe_ch(ch);
+ ch = next_ch();
+
+ while(isDECIMAL_DIGIT(ch) && value < (MAX_INTEGER/10)) {
+ value = (value << 3) + (value << 1) + (ch - '0');
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ }
+
+ /* Quick exit for small integers --
+ * |x| <= 10*((MAX_INTEGER/10)-1)+9
+ * |x| <= 2,147,483,639 for 32 bit integers
+ */
+ if (isNUMBER_ENDER(ch)) {
+ back_ch_not_white(ch);
+ tokenValue.integer = (m_sign == '-' ? -value : value);
+ tokenType = TOKEN_INTEGER;
+ return(DONE);
+ }
+
+ /* Handle additional digits. Beyond the boundary case,
+ * 10*(MAX_INTEGER/10) <= |number| <= MAX_INTEGER
+ * just count the digits: the number is too large to
+ * represent as an integer and will be returned as a real.
+ * The mantissa of a real holds fewer bits than an integer.
+ */
+ p_value = value;
+ value = (m_sign == '-' ? -value : value);
+ scale = 0;
+
+ if (isDECIMAL_DIGIT(ch)) {
+
+ /* Handle the boundary case */
+ if (p_value == (MAX_INTEGER/10)) {
+ digit = ch - '0';
+
+ /* Must handle positive and negative values separately */
+ /* for 2's complement arithmetic */
+ if (value > 0) {
+ if (digit <= MAX_INTEGER%10)
+ value = (value << 3) + (value << 1) + digit;
+ else
+ ++scale; /* Too big, just count it */
+ }
+ else {
+ /* Use positive % operands for portability */
+ if (digit <= -(MIN_INTEGER+10)%10)
+ value = (value << 3) + (value << 1) - digit;
+ else
+ ++scale; /* Too big, just count it */
+ }
+ }
+ else
+ ++scale; /* Not boundary case, just count digit */
+
+ save_unsafe_ch(ch);
+ ch = next_ch();
+
+ /* Continue scanning digits, but can't store them */
+ while(isDECIMAL_DIGIT(ch)) {
+ ++scale;
+ save_ch(ch);
+ ch = next_ch();
+ }
+ }
+
+ /* Continue from here scanning radix integer or real */
+ m_value = value;
+ m_scale = scale;
+
+ /* Initialize for possible real */
+ e_sign = '+';
+ e_value = 0;
+ e_scale = 0;
+
+ return(ch);
+}
+
+static int add_1st_decpt(ch)
+ int ch;
+{
+ m_sign = '+';
+ return(add_decpt(ch));
+}
+
+static int add_decpt(ch)
+ int ch;
+{
+ /* On entry, expect m_sign to be set to '+' or '-' */
+ m_value = 0;
+ m_scale = 0;
+ save_unsafe_ch(ch);
+ return(next_ch());
+}
+
+static int add_fraction(ch)
+ int ch;
+{
+ long value, scale;
+ int digit;
+
+ /* On entry, expect m_value and m_scale to be initialized,
+ * and m_sign to be set to '+' or '-'. Expect m_value and m_sign
+ * to be consistent (this is not checked).
+ */
+ value = m_value;
+ scale = m_scale;
+
+ /* Scan leading zeroes */
+ if (value == 0) {
+ while(ch == '0') {
+ --scale;
+ save_ch(ch);
+ ch = next_ch();
+ }
+
+ /* Scan first significant digit */
+ if (isDECIMAL_DIGIT(ch)) {
+ --scale;
+ value = ch - '0';
+ value = (m_sign == '-' ? -value : value);
+ save_ch(ch);
+ ch = next_ch();
+ }
+ else
+ /* no significant digits -- number is zero */
+ scale = 0;
+ }
+ /* value != 0 || value == 0 && !isDECIMAL_DIGIT(ch) */
+
+ /* Scan additional significant digits */
+ if (isDECIMAL_DIGIT(ch)) {
+ if (value > 0) {
+ while(isDECIMAL_DIGIT(ch) && value < (MAX_INTEGER/10)) {
+ --scale;
+ value = (value << 3) + (value << 1) + (ch - '0');
+ save_ch(ch);
+ ch = next_ch();
+ }
+ /* Check boundary case */
+ if (isDECIMAL_DIGIT(ch) && value == (MAX_INTEGER/10)) {
+ digit = ch - '0';
+ if (digit <= MAX_INTEGER%10) {
+ --scale;
+ value = (value << 3) + (value << 1) + digit;
+ save_ch(ch);
+ ch = next_ch();
+ }
+ }
+ }
+ else {
+ /* value < 0 */
+ while(isDECIMAL_DIGIT(ch) && value > -(-(MIN_INTEGER+10)/10+1)) {
+ /* Use positive / operands for portability */
+ --scale;
+ value = (value << 3) + (value << 1) - (ch - '0');
+ save_ch(ch);
+ ch = next_ch();
+ }
+ /* Check boundary case */
+ if (isDECIMAL_DIGIT(ch)
+ && value == -(-(MIN_INTEGER+10)/10+1)) {
+ digit = ch - '0';
+ if (digit <= -(MIN_INTEGER+10)%10) {
+ /* Use positive % operands for portability */
+ --scale;
+ value = (value << 3) + (value << 1) - digit;
+ save_ch(ch);
+ ch = next_ch();
+ }
+ }
+ }
+
+ /* Additional digits can be discarded */
+ while(isDECIMAL_DIGIT(ch)) {
+ save_ch(ch);
+ ch = next_ch();
+ }
+ }
+
+ /* Store results */
+ m_value = value;
+ m_scale = scale;
+
+ /* Initialize for possible real */
+ e_sign = '+';
+ e_value = 0;
+ e_scale = 0;
+
+ return(ch);
+}
+
+static int add_e_sign(ch)
+ int ch;
+{
+ e_sign = ch;
+ save_ch(ch);
+ return(next_ch());
+}
+
+static int add_exponent(ch)
+ int ch;
+{
+ long value, p_value;
+ long scale = 0;
+ int digit;
+
+ /* On entry, expect e_sign to be set to '+' or '-' */
+
+ value = ch - '0';
+ save_ch(ch);
+ ch = next_ch();
+
+ while(isDECIMAL_DIGIT(ch) && value < (MAX_INTEGER/10)) {
+ value = (value << 3) + (value << 1) + (ch - '0');
+ save_ch(ch);
+ ch = next_ch();
+ }
+
+ p_value = value;
+ value = (e_sign == '-' ? -value : value);
+
+ /* Handle additional digits. Beyond the boundary case,
+ * 10*(MAX_INTEGER/10) <= |number| <= MAX_INTEGER
+ * just count the digits: the number is too large to
+ * represent as an integer.
+ */
+ if (isDECIMAL_DIGIT(ch)) {
+
+ /* Examine boundary case */
+ if (p_value == (MAX_INTEGER/10)) {
+ digit = ch - '0';
+
+ /* Must handle positive and negative values separately */
+ /* for 2's complement arithmetic */
+ if (value > 0) {
+ if (digit <= MAX_INTEGER%10)
+ value = (value << 3) + (value << 1) + digit;
+ else
+ ++scale; /* Too big, just count it */
+ }
+ else {
+ /* Use positive % operands for portability */
+ if (digit <= -(MIN_INTEGER+10)%10)
+ value = (value << 3) + (value << 1) - digit;
+ else
+ ++scale; /* Too big, just count it */
+ }
+ }
+ else
+ ++scale; /* Not boundary case, just count digit */
+
+ save_ch(ch);
+ ch = next_ch();
+
+ /* Continue scanning digits, but can't store any more */
+ while(isDECIMAL_DIGIT(ch)) {
+ ++scale;
+ save_ch(ch);
+ ch = next_ch();
+ }
+ }
+
+ /* Store results */
+ e_value = value;
+ e_scale = scale;
+
+ return(ch);
+}
+
+static int add_radix(ch)
+ int ch;
+{
+ if (2 <= m_value && m_value <= 36 && m_scale == 0) {
+ r_base = m_value;
+ save_ch(ch);
+ return(next_ch());
+ }
+ else {
+ /* Radix invalid, complete a name token */
+ return(AAH_NAME(ch));
+ }
+}
+
+static int add_r_digits(ch)
+ int ch;
+{
+ unsigned long value;
+ long radix, scale;
+ int digit;
+
+ /* NOTE: The syntax of a radix number allows only for
+ * values of zero or more. The value will be stored as
+ * a 32 bit integer, which PostScript then interprets
+ * as signed. This means, for example, that the numbers:
+ *
+ * 8#37777777777
+ * 10#4294967295
+ * 16#FFFFFFFF
+ * 36#1Z141Z3
+ *
+ * are all interpreted as -1. This routine implements this
+ * idea explicitly: it accumulates the number's value
+ * as unsigned, then casts it to signed when done.
+ */
+
+ /* Expect r_base to be initialized */
+ radix = r_base;
+ value = 0;
+ scale = 0;
+
+ /* Scan leading zeroes */
+ while(ch == '0') {
+ save_ch(ch);
+ ch = next_ch();
+ }
+
+ /* Handle first non-zero digit */
+ if ((digit=digit_value[ch]) < radix) {
+ value = digit;
+ save_ch(ch);
+ ch = next_ch();
+
+ /* Add digits until boundary case reached */
+ while((digit=digit_value[ch]) < radix
+ && value < (MAX_ULONG / radix)) {
+ value = value * radix + digit;
+ save_ch(ch);
+ ch = next_ch();
+ };
+
+ /* Scan remaining digits */
+ if ((digit=digit_value[ch]) < radix) {
+
+ /* Examine boundary case ---
+ * radix*(MAX_ULONG/radix) <= number <= MAX_ULONG
+ */
+ if (value == (MAX_ULONG/radix) && digit <= MAX_ULONG%radix)
+ value = value * radix + digit;
+ else
+ ++scale;
+
+ /* Continue scanning digits, but can't store them */
+ save_ch(ch);
+ ch = next_ch();
+ while(digit_value[ch] < radix) {
+ ++scale;
+ save_ch(ch);
+ ch = next_ch();
+ }
+ }
+ }
+
+ /* Store result */
+ r_value = (long) value; /* result is signed */
+ r_scale = scale;
+
+ return(ch);
+}
+
+/* -------------------------------------------------------------------
+ * Complete a number; set token type and done flag.
+ * Put current input character back, if it is not white space.
+ */
+
+/* Done: Radix Number */
+static int RADIX_NUMBER(ch)
+ int ch;
+{
+ back_ch_not_white(ch);
+ if (r_scale == 0) {
+ tokenValue.integer = r_value;
+ tokenType = TOKEN_INTEGER;
+ }
+ else {
+ tokenType = TOKEN_NAME;
+ }
+ return(DONE);
+}
+
+/* Done: Integer */
+static int INTEGER(ch)
+ int ch;
+{
+ back_ch_not_white(ch);
+ if (m_scale == 0) {
+ tokenValue.integer = m_value;
+ tokenType = TOKEN_INTEGER;
+ }
+ else {
+ tokenValue.real = (double)(m_value) * Exp10(m_scale);
+ tokenType = TOKEN_REAL;
+ }
+ return(DONE);
+}
+
+/* Done: Real */
+static int REAL(ch)
+ int ch;
+{
+ double temp;
+
+ back_ch_not_white(ch);
+
+ /* NOTE: ignore e_scale, since e_value alone will cause
+ * exponent overflow if e_scale > 0.
+ */
+
+ /* HAZARD: exponent overflow of intermediate result
+ * (e.g., in 370 floating point); this should not be a problem
+ * with IEEE floating point. Reduce exponent overflow hazard by
+ * combining m_scale and e_value first, if they have different signs,
+ * or multiplying m_value and one of the other factors, if both
+ * m_scale and e_value are negative.
+ */
+ if ((m_scale >= 0 && e_value <= 0)
+ || (m_scale <= 0 && e_value >= 0)) {
+ tokenValue.real = (double)(m_value) * Exp10(m_scale + e_value);
+ }
+ else {
+ temp = (double)(m_value) * Exp10(m_scale);
+ tokenValue.real = temp * Exp10(e_value);
+ }
+
+ tokenType = TOKEN_REAL;
+ return(DONE);
+}
+
+
+/* -------------------------------------------------------------------
+ * Assemble a hex string; set token type and done flag.
+ */
+
+/* Done: Hex String */
+static int HEX_STRING(ch)
+ int ch;
+{
+ int value;
+
+ while(TRUE) {
+
+ /* Process odd digit */
+ ch = next_ch();
+ if (!isHEX_DIGIT(ch)) {
+
+ /* Skip white space */
+ while(isWHITE_SPACE(ch))
+ ch = next_ch();
+
+ /* Check for terminator */
+ if (!isHEX_DIGIT(ch)) {
+ break;
+ }
+ }
+ value = digit_value[ch] << 4;
+
+ /* Process even digit */
+ ch = next_ch();
+ if (!isHEX_DIGIT(ch)) {
+
+ /* Skip white space */
+ while(isWHITE_SPACE(ch))
+ ch = next_ch();
+
+ /* Check for terminator */
+ if (!isHEX_DIGIT(ch)) {
+ save_ch(value);
+ break;
+ }
+ }
+ save_ch(value + digit_value[ch]);
+ }
+
+ /* Classify result, based on why loop ended */
+ if (ch == '>')
+ tokenType = TOKEN_HEX_STRING;
+ else {
+ /* save the invalid character for error reporting */
+ save_ch(ch);
+ tokenType = TOKEN_INVALID;
+ }
+
+ return(DONE);
+}
+
+/* -------------------------------------------------------------------
+ * Assemble a string; set token type and done flag
+ */
+
+/* Save a backslash-coded character in a string --
+ *
+ * Store the proper character for special cases
+ * "\b", "\f", "\n", "\r", and "\t".
+ *
+ * Decode and store octal-coded character, up to
+ * three octal digits, "\o", "\oo", and "\ooo".
+ *
+ * The sequence "\<newline>" is a line continuation,
+ * so consume both without storing anything.
+ *
+ * The sequence "\<EOF>" is an error; exit without
+ * storing anything and let the caller handle it.
+ *
+ * For other characters, including the sequences
+ * "\\", "\(", and "\)", simply store the second
+ * character.
+ */
+static void save_digraph(ch)
+ int ch;
+{
+ int value;
+
+ switch (ch) {
+
+ case 'b': /* backspace */
+ ch = '\b';
+ break;
+
+ case 'f': /* formfeed */
+ ch = '\f';
+ break;
+
+ case 'n': /* newline */
+ ch = '\n';
+ break;
+
+ case 'r': /* carriage return */
+ ch = '\r';
+ break;
+
+ case 't': /* horizontal tab */
+ ch = '\t';
+ break;
+
+ case '\n': /* line continuation -- consume it */
+ return;
+
+ case '\r': /* carriage return -- consume it */
+ ch = next_ch(); /* look at next character, is it \n? */
+ if (ch == '\n') return;
+ back_ch(ch); /* if not a line feed, then return it */
+ return;
+
+ case EOF: /* end of file -- forget it */
+ return;
+
+ default:
+ /* scan up to three octal digits to get value */
+ if (isOCTAL_DIGIT(ch)) {
+ value = digit_value[ch];
+ ch = next_ch();
+ if (isOCTAL_DIGIT(ch)) {
+ value = (value << 3) + digit_value[ch];
+ ch = next_ch();
+ if (isOCTAL_DIGIT(ch))
+ value = (value << 3) + digit_value[ch];
+ else
+ back_ch(ch);
+ }
+ else
+ back_ch(ch);
+ ch = value;
+ }
+ }
+
+ /* Found a character to save */
+ save_ch(ch);
+}
+
+/* Done: String */
+static int STRING(ch)
+ int ch;
+{
+ int nest_level = 1;
+
+ tokenType = TOKEN_STRING;
+
+ do {
+
+ ch = next_ch();
+ while(!isSTRING_SPECIAL(ch)) {
+ save_ch(ch);
+ ch = next_ch();
+ };
+
+ switch (ch) {
+
+ case '(':
+ ++nest_level;
+ save_ch(ch);
+ break;
+
+ case ')':
+ if (--nest_level > 0)
+ save_ch(ch);
+ break;
+
+ case '\\':
+ save_digraph(next_ch());
+ break;
+
+ case '\r':
+ /* All carriage returns (\r) are turned into linefeeds (\n)*/
+ ch = next_ch(); /* get the next one, is it \n? */
+ if (ch != '\n') { /* if not, then put it back. */
+ back_ch(ch);
+ }
+ save_ch('\n'); /* in either case, save a linefeed */
+ break;
+
+
+ case EOF:
+ tokenType = TOKEN_INVALID; /* Unterminated string */
+ nest_level = 0;
+ break;
+ }
+
+ } while(nest_level > 0);
+
+ /* If there's room, add a 0-byte termination without increasing string
+ length. This fixes certain dependencies on 0-terminated strings */
+ save_ch_no_inc(0);
+
+ return(DONE);
+}
+
+
+/* -------------------------------------------------------------------
+ * Assemble a name; set token type and done flag.
+ * Put current input character back, if it is not white space.
+ */
+
+/* Done: Name
+ * (Safe version used to complete name tokens that
+ * start out looking like something else).
+ */
+
+static int AAH_NAME(ch)
+ int ch;
+{
+ do {
+ save_ch(ch);
+ ch = next_ch();
+ } while(isNAME(ch));
+
+ back_ch_not_white(ch);
+ tokenType = TOKEN_NAME;
+ return(DONE);
+}
+
+/* Done: Name */
+static int NAME(ch)
+ int ch;
+{
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ while(isNAME(ch)) {
+ save_ch(ch);
+ ch = next_ch();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ back_ch_not_white(ch);
+ tokenType = TOKEN_NAME;
+ return(DONE);
+}
+
+/* Done: Literal Name */
+static int LITERAL_NAME(ch)
+ int ch;
+{
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ while(isNAME(ch)) {
+ save_ch(ch);
+ ch = next_ch();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ back_ch_not_white(ch);
+ tokenType = TOKEN_LITERAL_NAME;
+ return(DONE);
+}
+
+/* Done: immediate Name */
+static int IMMED_NAME(ch)
+ int ch;
+{
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ if (isNAME(ch)) {
+ save_unsafe_ch(ch);
+ ch = next_ch();
+ while(isNAME(ch)) {
+ save_ch(ch);
+ ch = next_ch();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ back_ch_not_white(ch);
+ tokenType = TOKEN_IMMED_NAME;
+ return(DONE);
+}
+
+/* Done: Name found while looking for something else */
+static int OOPS_NAME(ch)
+ int ch;
+{
+ back_ch_not_white(ch);
+ tokenType = TOKEN_NAME;
+ return(DONE);
+}
+
+
+/* -------------------------------------------------------------------
+ * Complete a miscellaneous token; set token type and done flag.
+ */
+
+/* Done: Unmatched Right Angle-Bracket */
+static int RIGHT_ANGLE(ch)
+ int ch;
+{
+ tokenType = TOKEN_RIGHT_ANGLE;
+ return(DONE);
+}
+
+/* Done: Unmatched Right Parenthesis */
+static int RIGHT_PAREN(ch)
+ int ch;
+{
+ tokenType = TOKEN_RIGHT_PAREN;
+ return(DONE);
+}
+
+/* Done: Left Brace */
+static int LEFT_BRACE(ch)
+ int ch;
+{
+ tokenType = TOKEN_LEFT_BRACE;
+ return(DONE);
+}
+
+/* Done: Right Brace */
+static int RIGHT_BRACE(ch)
+ int ch;
+{
+ tokenType = TOKEN_RIGHT_BRACE;
+ return(DONE);
+}
+
+/* Done: Left Bracket */
+static int LEFT_BRACKET(ch)
+ int ch;
+{
+ save_unsafe_ch(ch);
+ tokenType = TOKEN_LEFT_BRACKET;
+ return(DONE);
+}
+
+/* Done: Right Bracket */
+static int RIGHT_BRACKET(ch)
+ int ch;
+{
+ save_unsafe_ch(ch);
+ tokenType = TOKEN_RIGHT_BRACKET;
+ return(DONE);
+}
+
+/* Done: Break */
+static int BREAK_SIGNAL(ch)
+ int ch;
+{
+ tokenType = TOKEN_BREAK;
+ return(DONE);
+}
+
+/* Done: No Token Found */
+static int NO_TOKEN(ch)
+ int ch;
+{
+ tokenType = TOKEN_EOF;
+ return(DONE);
+}
+
+
+/*
+ * -------------------------------------------------------------------
+ * scan_token -- scan one token from the input. It uses a simple
+ * finite state machine to recognize token classes.
+ *
+ * The input is from a file.
+ *
+ * On entry --
+ *
+ * inputP -> input PostScript object, a file.
+ * tokenStartP -> buffer in VM for accumulating the token.
+ * tokenMaxP -> last character in the token buffer
+ *
+ * On exit --
+ *
+ * tokenLength = number of characters in the token
+ * tokenTooLong = TRUE if the token did not fit in the buffer
+ * tokenType = code for the type of token parsed.
+ * tokenValue = converted value of a numeric token.
+ *
+ *
+ * -------------------------------------------------------------------
+ */
+void scan_token(inputP)
+ psobj *inputP;
+{
+ int ch;
+ unsigned char *stateP = s0;
+ unsigned char entry;
+ int (*actionP)();
+
+ /* Define input source */
+ inputFileP = inputP->data.fileP;
+ if (inputFileP == NULL) {
+ tokenType = TOKEN_EOF;
+ return;
+ }
+
+ /* Ensure enough space for most cases
+ * (so we don't have to keep checking)
+ * The length needs to cover the maximum number
+ * of save_unsafe_ch() calls that might be executed.
+ * That number is 11 (a sign and 10 decimal digits, e.g.,
+ * when scanning -2147483648), but use MAX_NAME_LEN
+ * in case someone changes that without checking.
+ */
+ tokenStartP = vm_next_byte();
+ tokenMaxP = tokenStartP + MIN(vm_free_bytes(), MAX_STRING_LEN);
+
+ if ((tokenMaxP-tokenStartP) < (MAX_NAME_LEN)) {
+ tokenLength = 0;
+ tokenTooLong = TRUE;
+ tokenType = TOKEN_NONE;
+ tokenValue.integer = 0;
+ return;
+ }
+
+ /* Reset token */
+ tokenCharP = tokenStartP;
+ tokenTooLong = FALSE;
+
+ /* Scan one token */
+ ch = next_ch();
+ do {
+ entry = stateP[ch];
+ stateP = classActionTable[entry].nextStateP;
+ actionP = classActionTable[entry].actionRoutineP;
+ ch = (*actionP)(ch);
+ } while(ch != DONE);
+
+
+ /* Return results */
+ tokenLength = tokenCharP - tokenStartP;
+}
diff --git a/src/Type1/token.h b/src/Type1/token.h
new file mode 100644
index 0000000..2dfe3fa
--- /dev/null
+++ b/src/Type1/token.h
@@ -0,0 +1,77 @@
+/* $Xorg: token.h,v 1.3 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+#ifndef TOKEN_H
+#define TOKEN_H
+
+/* Special characters */
+#define CONTROL_C (3)
+
+/* Token type codes */
+#define TOKEN_INVALID (-3)
+#define TOKEN_BREAK (-2)
+#define TOKEN_EOF (-1)
+#define TOKEN_NONE (0)
+#define TOKEN_LEFT_PAREN (1)
+#define TOKEN_RIGHT_PAREN (2)
+#define TOKEN_LEFT_ANGLE (3)
+#define TOKEN_RIGHT_ANGLE (4)
+#define TOKEN_LEFT_BRACE (5)
+#define TOKEN_RIGHT_BRACE (6)
+#define TOKEN_LEFT_BRACKET (7)
+#define TOKEN_RIGHT_BRACKET (8)
+#define TOKEN_NAME (9)
+#define TOKEN_LITERAL_NAME (10)
+#define TOKEN_INTEGER (11)
+#define TOKEN_REAL (12)
+#define TOKEN_RADIX_NUMBER (13)
+#define TOKEN_HEX_STRING (14)
+#define TOKEN_STRING (15)
+#define TOKEN_IMMED_NAME (16)
+
+/* Token routines */
+extern void scan_token();
+
+/*
+ * -------------------------------------------------------------------------
+ * Globals shared -- (everyone else KEEP YOUR MITTS OFF THEM!)
+ * -------------------------------------------------------------------------
+ */
+
+/* These variables are set by the caller */
+extern char *tokenStartP; /* Pointer to token buffer in VM */
+extern char *tokenMaxP; /* Pointer to end of VM we may use + 1 */
+
+/* These variables are set by P_TOKEN */
+extern int tokenLength; /* Characters in token */
+extern boolean tokenTooLong; /* Token too long for space available */
+extern int tokenType; /* Type of token identified */
+extern psvalue tokenValue; /* Token value */
+
+#endif /* TOKEN_H */
diff --git a/src/Type1/tokst.h b/src/Type1/tokst.h
new file mode 100644
index 0000000..de3f0ec
--- /dev/null
+++ b/src/Type1/tokst.h
@@ -0,0 +1,508 @@
+/* $Xorg: tokst.h,v 1.3 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* -------------------------------------- */
+/* --- MACHINE GENERATED, DO NOT EDIT --- */
+/* -------------------------------------- */
+
+#ifndef TOKST
+#define TOKST 1
+
+/*
+ * State Index Tables --
+ *
+ * These tables map the input character to the
+ * proper entry in the Class Action Table.
+ * There is one table for each state.
+ *
+ */
+#define s0 (si0+2)
+static unsigned char si0[258] = { 0x10,0x11,
+ 0x02,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x02,0x02,0x0F,0x0F,0x02,0x0F,0x0F,
+ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+ 0x02,0x0F,0x0F,0x0F,0x0F,0x03,0x0F,0x0F,0x05,0x0B,0x0F,0x0D,0x0F,0x0D,0x0E,0x04,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x0F,0x0F,0x08,0x0F,0x0C,0x0F,
+ 0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x0F,0x0A,0x0F,0x0F,
+ 0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0F,0x09,0x0F,0x0F,
+ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F
+};
+
+#define s1 (si1+2)
+static unsigned char si1[258] = { 0x14,0x15,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x12,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,
+ 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13
+};
+
+#define s2 (si2+2)
+static unsigned char si2[258] = { 0x1B,0x1C,
+ 0x16,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x16,0x16,0x1A,0x1A,0x16,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,
+ 0x16,0x1A,0x1A,0x1A,0x1A,0x17,0x1A,0x1A,0x17,0x17,0x1A,0x1A,0x1A,0x1A,0x19,0x17,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1A,0x1A,0x17,0x1A,0x17,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x17,0x1A,0x17,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x17,0x1A,0x17,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,
+ 0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A,0x1A
+};
+
+#define s3 (si3+2)
+static unsigned char si3[258] = { 0x23,0x24,
+ 0x1D,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x1D,0x1D,0x22,0x22,0x1D,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
+ 0x1D,0x22,0x22,0x20,0x22,0x1E,0x22,0x22,0x1E,0x1E,0x22,0x22,0x22,0x22,0x1F,0x1E,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x1E,0x22,0x1E,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x21,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x1E,0x22,0x1E,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x21,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x1E,0x22,0x1E,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22
+};
+
+#define s4 (si4+2)
+static unsigned char si4[258] = { 0x29,0x2A,
+ 0x25,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x25,0x25,0x28,0x28,0x25,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
+ 0x25,0x28,0x28,0x28,0x28,0x26,0x28,0x28,0x26,0x26,0x28,0x28,0x28,0x28,0x28,0x26,
+ 0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x28,0x28,0x26,0x28,0x26,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x26,0x28,0x26,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x26,0x28,0x26,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,
+ 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28
+};
+
+#define s5 (si5+2)
+static unsigned char si5[258] = { 0x30,0x31,
+ 0x2B,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2B,0x2B,0x2F,0x2F,0x2B,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,
+ 0x2B,0x2F,0x2F,0x2F,0x2F,0x2C,0x2F,0x2F,0x2C,0x2C,0x2F,0x2F,0x2F,0x2F,0x2F,0x2C,
+ 0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2F,0x2F,0x2C,0x2F,0x2C,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2D,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2C,0x2F,0x2C,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2D,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2C,0x2F,0x2C,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,
+ 0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F
+};
+
+#define s6 (si6+2)
+static unsigned char si6[258] = { 0x36,0x37,
+ 0x32,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x32,0x32,0x35,0x35,0x32,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
+ 0x32,0x35,0x35,0x35,0x35,0x33,0x35,0x35,0x33,0x33,0x35,0x35,0x35,0x35,0x35,0x33,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x33,0x35,0x33,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x34,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x33,0x35,0x33,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x34,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x33,0x35,0x33,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
+ 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35
+};
+
+#define s7 (si7+2)
+static unsigned char si7[258] = { 0x3D,0x3E,
+ 0x38,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x38,0x38,0x3C,0x3C,0x38,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
+ 0x38,0x3C,0x3C,0x3C,0x3C,0x39,0x3C,0x3C,0x39,0x39,0x3C,0x3A,0x3C,0x3A,0x3C,0x39,
+ 0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3C,0x3C,0x39,0x3C,0x39,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x39,0x3C,0x39,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x39,0x3C,0x39,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
+ 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C
+};
+
+#define s8 (si8+2)
+static unsigned char si8[258] = { 0x43,0x44,
+ 0x3F,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3F,0x3F,0x42,0x42,0x3F,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
+ 0x3F,0x42,0x42,0x42,0x42,0x40,0x42,0x42,0x40,0x40,0x42,0x42,0x42,0x42,0x42,0x40,
+ 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x42,0x42,0x40,0x42,0x40,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x40,0x42,0x40,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x40,0x42,0x40,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
+ 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42
+};
+
+#define s9 (si9+2)
+static unsigned char si9[258] = { 0x48,0x49,
+ 0x45,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x45,0x45,0x47,0x47,0x45,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,
+ 0x45,0x47,0x47,0x47,0x47,0x46,0x47,0x47,0x46,0x46,0x47,0x47,0x47,0x47,0x47,0x46,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x46,0x47,0x46,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x46,0x47,0x46,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x46,0x47,0x46,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,
+ 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47
+};
+
+#define s10 (si10+2)
+static unsigned char si10[258] = { 0x4E,0x4F,
+ 0x4A,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4A,0x4A,0x4D,0x4D,0x4A,0x4D,0x4D,
+ 0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,
+ 0x4A,0x4D,0x4D,0x4D,0x4D,0x4B,0x4D,0x4D,0x4B,0x4B,0x4D,0x4D,0x4D,0x4D,0x4D,0x4B,
+ 0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4D,0x4D,0x4B,0x4D,0x4B,0x4D,
+ 0x4D,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,
+ 0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4B,0x4D,0x4B,0x4D,0x4D,
+ 0x4D,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,
+ 0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4C,0x4B,0x4D,0x4B,0x4D,0x4D,
+ 0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,
+ 0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,
+ 0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,
+ 0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,
+ 0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,
+ 0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,
+ 0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,
+ 0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D
+};
+
+#define s11 (si11+2)
+static unsigned char si11[258] = { 0x53,0x54,
+ 0x50,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x50,0x50,0x52,0x52,0x50,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
+ 0x50,0x52,0x52,0x52,0x52,0x51,0x52,0x52,0x51,0x51,0x52,0x52,0x52,0x52,0x52,0x51,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x51,0x52,0x51,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x51,0x52,0x51,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x51,0x52,0x51,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
+ 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52
+};
+
+/*
+ * Class Action Table --
+ *
+ * The entries in the Class Action Table indicate the
+ * action routine to be called, and the next state to
+ * enter, for each relevant character class in each.
+ * state. There are several entries for each state.
+ *
+ */
+static int AAH_NAME();
+static int BREAK_SIGNAL();
+static int HEX_STRING();
+static int IMMED_NAME();
+static int INTEGER();
+static int LEFT_BRACE();
+static int LEFT_BRACKET();
+static int LITERAL_NAME();
+static int NAME();
+static int NO_TOKEN();
+static int OOPS_NAME();
+static int RADIX_NUMBER();
+static int REAL();
+static int RIGHT_ANGLE();
+static int RIGHT_BRACE();
+static int RIGHT_BRACKET();
+static int RIGHT_PAREN();
+static int STRING();
+static int add_1st_decpt();
+static int add_1st_digits();
+static int add_char();
+static int add_decpt();
+static int add_digits();
+static int add_e_sign();
+static int add_exponent();
+static int add_fraction();
+static int add_r_digits();
+static int add_radix();
+static int add_sign();
+static int next_char();
+static int skip_comment();
+static int skip_space();
+
+static struct cat {
+ int (*actionRoutineP)();
+ unsigned char *nextStateP;
+} classActionTable[] = {
+
+ /* s0: Classify initial character */
+ /* 00 ALPHA */ {NAME, s0}, /* executable name */
+ /* 01 DIGIT */ {add_1st_digits, s3}, /* number? */
+ /* 02 WHITE_SPACE */ {skip_space, s0}, /* skip white space */
+ /* 03 PERCENT */ {skip_comment, s0}, /* comment? */
+ /* 04 SLASH */ {next_char, s1}, /* literal or imm name */
+ /* 05 LEFT_PAREN */ {STRING, s0}, /* string */
+ /* 06 LEFT_BRACE */ {LEFT_BRACE, s0}, /* begin procedure body */
+ /* 07 LEFT_BRACKET */ {LEFT_BRACKET, s0}, /* begin array */
+ /* 08 LEFT_ANGLE */ {HEX_STRING, s0}, /* hex string? */
+ /* 09 RIGHT_BRACE */ {RIGHT_BRACE, s0}, /* end procedure body */
+ /* 0A RIGHT_BRACKET */ {RIGHT_BRACKET, s0}, /* end array */
+ /* 0B RIGHT_PAREN */ {RIGHT_PAREN, s0}, /* unmatched right paren */
+ /* 0C RIGHT_ANGLE */ {RIGHT_ANGLE, s0}, /* unmatched right angle */
+ /* 0D SIGN */ {add_sign, s2}, /* signed number? */
+ /* 0E DECIMAL_POINT */ {add_1st_decpt, s4}, /* real number? */
+ /* 0F ANY */ {NAME, s0}, /* executable name */
+ /* 10 BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 11 EOF */ {NO_TOKEN, s0}, /* no token found */
+
+ /* s1: Further classify a '/' */
+ /* 12 SLASH */ {IMMED_NAME, s0}, /* immediate name */
+ /* 13 ANY */ {LITERAL_NAME, s0}, /* literal name */
+ /* 14 BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 15 EOF */ {OOPS_NAME, s0}, /* isolated sign */
+
+ /* s2: sign */
+ /* 16 WHITE_SPACE */ {OOPS_NAME, s0}, /* isolated sign */
+ /* 17 SPECIAL */ {OOPS_NAME, s0}, /* isolated sign */
+ /* 18 DIGIT */ {add_digits, s3}, /* number? */
+ /* 19 DECIMAL_POINT */ {add_decpt, s4}, /* real number? */
+ /* 1A ANY */ {NAME, s0}, /* executable name */
+ /* 1B BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 1C EOF */ {OOPS_NAME, s0}, /* isolated sign */
+
+ /* s3: sign? digit+ */
+ /* 1D WHITE_SPACE */ {INTEGER, s0}, /* n-digit integer */
+ /* 1E SPECIAL */ {INTEGER, s0}, /* n-digit integer */
+ /* 1F DECIMAL_POINT */ {add_char, s5}, /* real number? */
+ /* 20 POUND */ {add_radix, s10}, /* radix number? */
+ /* 21 eE */ {add_char, s7}, /* real with exponent? */
+ /* 22 ANY */ {AAH_NAME, s0}, /* executable name */
+ /* 23 BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 24 EOF */ {INTEGER, s0}, /* n-digit integer */
+
+ /* s4: sign? . */
+ /* 25 WHITE_SPACE */ {OOPS_NAME, s0}, /* isolated +. or -. */
+ /* 26 SPECIAL */ {OOPS_NAME, s0}, /* isolated +. or -. */
+ /* 27 DIGIT */ {add_fraction, s6}, /* number? */
+ /* 28 ANY */ {NAME, s0}, /* executable name */
+ /* 29 BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 2A EOF */ {OOPS_NAME, s0}, /* isolated +. or -. */
+
+ /* s5: sign? digit+ . */
+ /* 2B WHITE_SPACE */ {REAL, s0}, /* real with fraction */
+ /* 2C SPECIAL */ {REAL, s0}, /* real with fraction */
+ /* 2D eE */ {add_char, s7}, /* real with exponent? */
+ /* 2E DIGIT */ {add_fraction, s6}, /* number? */
+ /* 2F ANY */ {AAH_NAME, s0}, /* executable name */
+ /* 30 BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 31 EOF */ {REAL, s0}, /* real with fraction */
+
+ /* s6: sign? (digit+ . digit+) | (. digit+) */
+ /* 32 WHITE_SPACE */ {REAL, s0}, /* real with fraction */
+ /* 33 SPECIAL */ {REAL, s0}, /* real with fraction */
+ /* 34 eE */ {add_char, s7}, /* real with exponent? */
+ /* 35 ANY */ {AAH_NAME, s0}, /* executable name */
+ /* 36 BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 37 EOF */ {REAL, s0}, /* real with fraction */
+
+ /* s7: sign? ((digit+ (. digit*)?) | (. digit+)) Ee */
+ /* 38 WHITE_SPACE */ {OOPS_NAME, s0}, /* invalid real number */
+ /* 39 SPECIAL */ {OOPS_NAME, s0}, /* invalid real number */
+ /* 3A SIGN */ {add_e_sign, s8}, /* real w signed exponent? */
+ /* 3B DIGIT */ {add_exponent, s9}, /* real w exponent ? */
+ /* 3C ANY */ {AAH_NAME, s0}, /* executable name */
+ /* 3D BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 3E EOF */ {OOPS_NAME, s0}, /* invalid real number */
+
+ /* s8: sign? (digit+ (. digit*)? | (digit* . digit+) Ee sign */
+ /* 3F WHITE_SPACE */ {OOPS_NAME, s0}, /* invalid real number */
+ /* 40 SPECIAL */ {OOPS_NAME, s0}, /* invalid real number */
+ /* 41 DIGIT */ {add_exponent, s9}, /* real w exponent? */
+ /* 42 ANY */ {AAH_NAME, s0}, /* executable name */
+ /* 43 BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 44 EOF */ {OOPS_NAME, s0}, /* invalid real number */
+
+ /* s9: sign? (digit+ (. digit*)? | (digit* . digit+) Ee sign? digit+ */
+ /* 45 WHITE_SPACE */ {REAL, s0}, /* real w exponent */
+ /* 46 SPECIAL */ {REAL, s0}, /* real w exponent */
+ /* 47 ANY */ {AAH_NAME, s0}, /* executable name */
+ /* 48 BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 49 EOF */ {REAL, s0}, /* real w exponent */
+
+ /* s10: digit+ # */
+ /* 4A WHITE_SPACE */ {OOPS_NAME, s0}, /* invalid radix number */
+ /* 4B SPECIAL */ {OOPS_NAME, s0}, /* invalid radix number */
+ /* 4C R_DIGIT */ {add_r_digits, s11}, /* radix number? */
+ /* 4D ANY */ {AAH_NAME, s0}, /* executable name */
+ /* 4E BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 4F EOF */ {OOPS_NAME, s0}, /* invalid radix number */
+
+ /* s11: digit+ # r_digit+ */
+ /* 50 WHITE_SPACE */ {RADIX_NUMBER, s0}, /* radix number */
+ /* 51 SPECIAL */ {RADIX_NUMBER, s0}, /* radix number */
+ /* 52 ANY */ {AAH_NAME, s0}, /* executable name */
+ /* 53 BREAK */ {BREAK_SIGNAL, s0}, /* break signalled */
+ /* 54 EOF */ {RADIX_NUMBER, s0} /* radix number */
+};
+
+/*
+ * Character Classification Tables --
+ *
+ * The entries in the Character Classification Tables
+ * map character codes to character classes. The
+ * tables contains one entry per code. The bits in
+ * each entry indicate which classes the character
+ * code belongs to.
+ *
+ * The macros 'isInCLASS(ch)' generate code to test
+ * whether 'ch' is a character in 'CLASS'.
+ *
+ */
+/* Membership macros for classes defined in table 1 ... */
+#define isRADIX_DIGIT(c) ((isInP1[c] & 0x80) != 0)
+#define isHEX_DIGIT(c) ((isInP1[c] & 0x40) != 0)
+#define isDECIMAL_DIGIT(c) ((isInP1[c] & 0x10) != 0)
+#define isOCTAL_DIGIT(c) ((isInP1[c] & 0x20) != 0)
+
+/* Membership macros for classes defined in table 2 ... */
+#define isWHITE_SPACE(c) ((isInP2[c] & 0x80) != 0)
+#define isCOMMENT(c) ((isInP2[c] & 0x40) != 0)
+#define isNAME(c) ((isInP2[c] & 0x20) != 0)
+#define isSTRING_SPECIAL(c) ((isInP2[c] & 0x10) != 0)
+#define isNUMBER_ENDER(c) ((isInP2[c] & 0x08) != 0)
+
+#define isInP1 (isInT1+2)
+static unsigned char isInT1[258] = { 0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xD0,0xD0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+#define isInP2 (isInT2+2)
+static unsigned char isInT2[258] = { 0x18,0x18,
+ 0xC8,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xC8,0x88,0x60,0x60,0x98,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+ 0xC8,0x60,0x60,0x60,0x60,0x48,0x60,0x60,0x58,0x58,0x60,0x60,0x60,0x60,0x60,0x48,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x48,0x60,0x48,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x48,0x70,0x48,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x48,0x60,0x48,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+ 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60
+};
+
+#endif
diff --git a/src/Type1/trig.h b/src/Type1/trig.h
new file mode 100644
index 0000000..c742f96
--- /dev/null
+++ b/src/Type1/trig.h
@@ -0,0 +1,35 @@
+/* $Xorg: trig.h,v 1.3 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/*SHARED*/
+
+#define DegreeCos(d) xiStub()
+#define DegreeSin(d) xiStub()
+#define sqrt(d) xiStub()
+
diff --git a/src/Type1/type1.c b/src/Type1/type1.c
new file mode 100644
index 0000000..f1b11c0
--- /dev/null
+++ b/src/Type1/type1.c
@@ -0,0 +1,1810 @@
+/* $Xorg: type1.c,v 1.4 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines, Corp. 1991
+ * All Rights Reserved
+ * Copyright Lexmark International, Inc. 1991
+ * All Rights Reserved
+ * Portions Copyright (c) 1990 Adobe Systems Incorporated.
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of IBM or Lexmark or Adobe
+ * not be used in advertising or publicity pertaining to distribution of
+ * the software without specific, written prior permission.
+ *
+ * IBM, LEXMARK, AND ADOBE PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY
+ * WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE
+ * ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING
+ * ANY DUTY TO SUPPORT OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY
+ * PORTION OF THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM,
+ * LEXMARK, OR ADOBE) ASSUMES THE ENTIRE COST OF ALL SERVICING, REPAIR AND
+ * CORRECTION. IN NO EVENT SHALL IBM, LEXMARK, OR ADOBE BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*********************************************************************/
+/* */
+/* Type 1 module - Converting fonts in Adobe Type 1 Font Format */
+/* to scaled and hinted paths for rasterization. */
+/* Files: type1.c, type1.h, and blues.h. */
+/* */
+/* Authors: Sten F. Andler, IBM Almaden Research Center */
+/* (Type 1 interpreter, stem & flex hints) */
+/* */
+/* Patrick A. Casey, Lexmark International, Inc. */
+/* (Font level hints & stem hints) */
+/* */
+/*********************************************************************/
+
+/******************/
+/* Include Files: */
+/******************/
+#include <stdio.h> /* a system-dependent include, usually */
+
+#include "objects.h"
+#include "spaces.h"
+#include "paths.h"
+#include "fonts.h" /* understands about TEXTTYPEs */
+#include "pictures.h" /* understands about handles */
+
+typedef struct xobject xobject;
+#include "util.h" /* PostScript objects */
+#include "blues.h" /* Blues structure for font-level hints */
+
+/**********************************/
+/* Type1 Constants and Structures */
+/**********************************/
+#define MAXSTACK 24 /* Adobe Type1 limit */
+#define MAXCALLSTACK 10 /* Adobe Type1 limit */
+#define MAXPSFAKESTACK 32 /* Max depth of fake PostScript stack (local) */
+#define MAXSTRLEN 512 /* Max length of a Type 1 string (local) */
+#define MAXLABEL 256 /* Maximum number of new hints */
+#define MAXSTEMS 128 /* Maximum number of VSTEM and HSTEM hints */
+#define EPS 0.001 /* Small number for comparisons */
+
+/************************************/
+/* Adobe Type 1 CharString commands */
+/************************************/
+#define HSTEM 1
+#define VSTEM 3
+#define VMOVETO 4
+#define RLINETO 5
+#define HLINETO 6
+#define VLINETO 7
+#define RRCURVETO 8
+#define CLOSEPATH 9
+#define CALLSUBR 10
+#define RETURN 11
+#define ESCAPE 12
+#define HSBW 13
+#define ENDCHAR 14
+#define RMOVETO 21
+#define HMOVETO 22
+#define VHCURVETO 30
+#define HVCURVETO 31
+
+/*******************************************/
+/* Adobe Type 1 CharString Escape commands */
+/*******************************************/
+#define DOTSECTION 0
+#define VSTEM3 1
+#define HSTEM3 2
+#define SEAC 6
+#define SBW 7
+#define DIV 12
+#define CALLOTHERSUBR 16
+#define POP 17
+#define SETCURRENTPOINT 33
+
+/*****************/
+/* Useful macros */
+/*****************/
+static double tmpx; /* Store macro argument in tmpx to avoid re-evaluation */
+static long tmpi; /* Store converted value in tmpi to avoid re-evaluation */
+
+#define FABS(x) (((tmpx = (x)) < 0.0) ? -tmpx : tmpx)
+
+#define CEIL(x) (((tmpi = (long) (tmpx = (x))) < (x)) ? ++tmpi : tmpi)
+
+#define FLOOR(x) (((tmpi = (long) (tmpx = (x))) > (x)) ? --tmpi : tmpi)
+
+#define ROUND(x) FLOOR((x) + 0.5)
+
+#define ODD(x) (((int)(x)) & 01)
+
+#define Error {errflag = TRUE; return;}
+#define ErrorRet(ret) {errflag = TRUE; return (ret);}
+
+#define Error0(errmsg) {IfTrace0(TRUE, errmsg); Error;}
+#define Error0Ret(errmsg, ret) {IfTrace0(TRUE, errmsg); ErrorRet(ret);}
+
+#define Error1(errmsg,arg) {IfTrace1(TRUE, errmsg, arg); Error;}
+
+/********************/
+/* global variables */
+/********************/
+struct stem { /* representation of a STEM hint */
+ int vertical; /* TRUE if vertical, FALSE otherwise */
+ double x, dx; /* interval of vertical stem */
+ double y, dy; /* interval of horizontal stem */
+ struct segment *lbhint, *lbrevhint; /* left or bottom hint adjustment */
+ struct segment *rthint, *rtrevhint; /* right or top hint adjustment */
+};
+
+extern struct XYspace *IDENTITY;
+
+static double escapementX, escapementY;
+static double sidebearingX, sidebearingY;
+static double accentoffsetX, accentoffsetY;
+
+static struct segment *path;
+static int errflag;
+
+/*************************************************/
+/* Global variables to hold Type1Char parameters */
+/*************************************************/
+static char *Environment;
+static struct XYspace *CharSpace;
+static psobj *CharStringP, *SubrsP, *OtherSubrsP;
+static int *ModeP;
+
+/************************/
+/* Forward declarations */
+/************************/
+static double Div();
+static double PSFakePop();
+static void DoCommand();
+static void Escape();
+static void HStem();
+static void VStem();
+static void RLineTo();
+static void RRCurveTo();
+static void DoClosePath();
+static void CallSubr();
+static void Return();
+static void EndChar();
+static void RMoveTo();
+static void DotSection();
+static void Seac();
+static void Sbw();
+static void CallOtherSubr();
+static void SetCurrentPoint();
+
+/*****************************************/
+/* statics for Flex procedures (FlxProc) */
+/*****************************************/
+static struct segment *FlxOldPath; /* save path before Flex feature */
+
+/******************************************************/
+/* statics for Font level hints (Blues) (see blues.h) */
+/******************************************************/
+static struct blues_struct *blues; /* the blues structure */
+static struct alignmentzone alignmentzones[MAXALIGNMENTZONES];
+static int numalignmentzones; /* total number of alignment zones */
+
+/****************************************************************/
+/* Subroutines for the Font level hints (Alignment zones, etc.) */
+/****************************************************************/
+
+/******************************************/
+/* Fill in the alignment zone structures. */
+/******************************************/
+static void
+ComputeAlignmentZones()
+{
+ int i;
+ double dummy, bluezonepixels, familyzonepixels;
+ struct segment *p;
+
+ numalignmentzones = 0; /* initialize total # of zones */
+
+ /* do the BlueValues zones */
+ for (i = 0; i < blues->numBlueValues; i +=2, ++numalignmentzones) {
+ /* the 0th & 1st numbers in BlueValues are for a bottom zone */
+ /* the rest are topzones */
+ if (i == 0) /* bottom zone */
+ alignmentzones[numalignmentzones].topzone = FALSE;
+ else /* top zone */
+ alignmentzones[numalignmentzones].topzone = TRUE;
+ if (i < blues->numFamilyBlues) { /* we must consider FamilyBlues */
+ p = ILoc(CharSpace,0,blues->BlueValues[i] - blues->BlueValues[i+1]);
+ QueryLoc(p, IDENTITY, &dummy, &bluezonepixels);
+ Destroy(p);
+ p = ILoc(CharSpace,0,blues->FamilyBlues[i]-blues->FamilyBlues[i+1]);
+ QueryLoc(p, IDENTITY, &dummy, &familyzonepixels);
+ Destroy(p);
+ /* is the difference in size of the zones less than 1 pixel? */
+ if (FABS(bluezonepixels - familyzonepixels) < 1.0) {
+ /* use the Family zones */
+ alignmentzones[numalignmentzones].bottomy =
+ blues->FamilyBlues[i];
+ alignmentzones[numalignmentzones].topy =
+ blues->FamilyBlues[i+1];
+ continue;
+ }
+ }
+ /* use this font's Blue zones */
+ alignmentzones[numalignmentzones].bottomy = blues->BlueValues[i];
+ alignmentzones[numalignmentzones].topy = blues->BlueValues[i+1];
+ }
+
+ /* do the OtherBlues zones */
+ for (i = 0; i < blues->numOtherBlues; i +=2, ++numalignmentzones) {
+ /* all of the OtherBlues zones are bottom zones */
+ alignmentzones[numalignmentzones].topzone = FALSE;
+ if (i < blues->numFamilyOtherBlues) {/* consider FamilyOtherBlues */
+ p = ILoc(CharSpace,0,blues->OtherBlues[i] - blues->OtherBlues[i+1]);
+ QueryLoc(p, IDENTITY, &dummy, &bluezonepixels);
+ Destroy(p);
+ p = ILoc(CharSpace,0,blues->FamilyOtherBlues[i] -
+ blues->FamilyOtherBlues[i+1]);
+ QueryLoc(p, IDENTITY, &dummy, &familyzonepixels);
+ Destroy(p);
+ /* is the difference in size of the zones less than 1 pixel? */
+ if (FABS(bluezonepixels - familyzonepixels) < 1.0) {
+ /* use the Family zones */
+ alignmentzones[numalignmentzones].bottomy =
+ blues->FamilyOtherBlues[i];
+ alignmentzones[numalignmentzones].topy =
+ blues->FamilyOtherBlues[i+1];
+ continue;
+ }
+ }
+ /* use this font's Blue zones (as opposed to the Family Blues */
+ alignmentzones[numalignmentzones].bottomy = blues->OtherBlues[i];
+ alignmentzones[numalignmentzones].topy = blues->OtherBlues[i+1];
+ }
+}
+
+/**********************************************************************/
+/* Subroutines and statics for handling of the VSTEM and HSTEM hints. */
+/**********************************************************************/
+static int InDotSection; /* DotSection flag */
+static struct stem stems[MAXSTEMS]; /* All STEM hints */
+static int numstems; /* Number of STEM hints */
+static int currstartstem; /* The current starting stem. */
+static int oldvert, oldhor; /* Remember hint in effect */
+static int oldhorhalf, oldverthalf; /* Remember which half of the stem */
+static double wsoffsetX, wsoffsetY; /* White space offset - for VSTEM3,HSTEM3 */
+static int wsset; /* Flag for whether we've set wsoffsetX,Y */
+
+static void
+InitStems() /* Initialize the STEM hint data structures */
+{
+ InDotSection = FALSE;
+ currstartstem = numstems = 0;
+ oldvert = oldhor = -1;
+}
+
+static void
+FinitStems() /* Terminate the STEM hint data structures */
+{
+ int i;
+
+ for (i = 0; i < numstems; i++) {
+ Destroy(stems[i].lbhint);
+ Destroy(stems[i].lbrevhint);
+ Destroy(stems[i].rthint);
+ Destroy(stems[i].rtrevhint);
+ }
+}
+
+/*******************************************************************/
+/* Compute the dislocation that a stemhint should cause for points */
+/* inside the stem. */
+/*******************************************************************/
+static void
+ComputeStem(stemno)
+ int stemno;
+{
+ int verticalondevice, idealwidth;
+ double stemstart, stemwidth;
+ struct segment *p;
+ int i;
+ double stembottom, stemtop, flatposition;
+ double Xpixels, Ypixels;
+ double unitpixels, onepixel;
+ int suppressovershoot, enforceovershoot;
+ double stemshift, flatpospixels, overshoot;
+ double widthdiff; /* Number of character space units to adjust width */
+ double lbhintvalue, rthintvalue;
+ double cxx, cyx, cxy, cyy; /* Transformation matrix */
+ int rotated; /* TRUE if character is on the side, FALSE if upright */
+
+ /************************************************/
+ /* DETERMINE ORIENTATION OF CHARACTER ON DEVICE */
+ /************************************************/
+
+ QuerySpace(CharSpace, &cxx, &cyx, &cxy, &cyy); /* Transformation matrix */
+
+ if (FABS(cxx) < 0.00001 || FABS(cyy) < 0.00001)
+ rotated = TRUE; /* Char is on side (90 or 270 degrees), possibly oblique. */
+ else if (FABS(cyx) < 0.00001 || FABS(cxy) < 0.00001)
+ rotated = FALSE; /* Char is upright (0 or 180 degrees), possibly oblique. */
+ else {
+ stems[stemno].lbhint = NULL; /* Char is at non-axial angle, ignore hints. */
+ stems[stemno].lbrevhint = NULL;
+ stems[stemno].rthint = NULL;
+ stems[stemno].rtrevhint = NULL;
+ return;
+ }
+
+ /* Determine orientation of stem */
+
+ if (stems[stemno].vertical) {
+ verticalondevice = !rotated;
+ stemstart = stems[stemno].x;
+ stemwidth = stems[stemno].dx;
+ } else {
+ verticalondevice = rotated;
+ stemstart = stems[stemno].y;
+ stemwidth = stems[stemno].dy;
+ }
+
+ /* Determine how many pixels (non-negative) correspond to 1 character space
+ unit (unitpixels), and how many character space units (non-negative)
+ correspond to one pixel (onepixel). */
+
+ if (stems[stemno].vertical)
+ p = ILoc(CharSpace, 1, 0);
+ else
+ p = ILoc(CharSpace, 0, 1);
+ QueryLoc(p, IDENTITY, &Xpixels, &Ypixels);
+ Destroy(p);
+ if (verticalondevice)
+ unitpixels = FABS(Xpixels);
+ else
+ unitpixels = FABS(Ypixels);
+
+ onepixel = 1.0 / unitpixels;
+
+ /**********************/
+ /* ADJUST STEM WIDTHS */
+ /**********************/
+
+ widthdiff = 0.0;
+
+ /* Find standard stem with smallest width difference from this stem */
+ if (stems[stemno].vertical) { /* vertical stem */
+ if (blues->StdVW != 0) /* there is an entry for StdVW */
+ widthdiff = blues->StdVW - stemwidth;
+ for (i = 0; i < blues->numStemSnapV; ++i) { /* now look at StemSnapV */
+ if (blues->StemSnapV[i] - stemwidth < widthdiff)
+ /* this standard width is the best match so far for this stem */
+ widthdiff = blues->StemSnapV[i] - stemwidth;
+ }
+ } else { /* horizontal stem */
+ if (blues->StdHW != 0) /* there is an entry for StdHW */
+ widthdiff = blues->StdHW - stemwidth;
+ for (i = 0; i < blues->numStemSnapH; ++i) { /* now look at StemSnapH */
+ if (blues->StemSnapH[i] - stemwidth < widthdiff)
+ /* this standard width is the best match so far for this stem */
+ widthdiff = blues->StemSnapH[i] - stemwidth;
+ }
+ }
+
+ /* Only expand or contract stems if they differ by less than 1 pixel from
+ the closest standard width, otherwise make the width difference = 0. */
+ if (FABS(widthdiff) > onepixel)
+ widthdiff = 0.0;
+
+ /* Expand or contract stem to the nearest integral number of pixels. */
+ idealwidth = ROUND((stemwidth + widthdiff) * unitpixels);
+ /* Ensure that all stems are at least one pixel wide. */
+ if (idealwidth == 0)
+ idealwidth = 1;
+ /* Apply ForceBold to vertical stems. */
+ if (blues->ForceBold && stems[stemno].vertical)
+ /* Force this vertical stem to be at least DEFAULTBOLDSTEMWIDTH wide. */
+ if (idealwidth < DEFAULTBOLDSTEMWIDTH)
+ idealwidth = DEFAULTBOLDSTEMWIDTH;
+ /* Now compute the number of character space units necessary */
+ widthdiff = idealwidth * onepixel - stemwidth;
+
+ /*********************************************************************/
+ /* ALIGNMENT ZONES AND OVERSHOOT SUPPRESSION - HORIZONTAL STEMS ONLY */
+ /*********************************************************************/
+
+ stemshift = 0.0;
+
+ if (!stems[stemno].vertical) {
+
+ /* Get bottom and top boundaries of the stem. */
+ stembottom = stemstart;
+ stemtop = stemstart + stemwidth;
+
+ /* Find out if this stem intersects an alignment zone (the BlueFuzz */
+ /* entry in the Private dictionary specifies the number of character */
+ /* units to extend (in both directions) the effect of an alignment */
+ /* zone on a horizontal stem. The default value of BlueFuzz is 1. */
+ for (i = 0; i < numalignmentzones; ++i) {
+ if (alignmentzones[i].topzone) {
+ if (stemtop >= alignmentzones[i].bottomy &&
+ stemtop <= alignmentzones[i].topy + blues->BlueFuzz) {
+ break; /* We found a top-zone */
+ }
+ } else {
+ if (stembottom <= alignmentzones[i].topy &&
+ stembottom >= alignmentzones[i].bottomy - blues->BlueFuzz) {
+ break; /* We found a bottom-zone */
+ }
+ }
+ }
+
+ if (i < numalignmentzones) { /* We found an intersecting zone (number i). */
+ suppressovershoot = FALSE;
+ enforceovershoot = FALSE;
+
+ /* When 1 character space unit is rendered smaller than BlueScale
+ device units (pixels), we must SUPPRESS overshoots. Otherwise,
+ if the top (or bottom) of this stem is more than BlueShift character
+ space units away from the flat position, we must ENFORCE overshoot. */
+
+ if (unitpixels < blues->BlueScale)
+ suppressovershoot = TRUE;
+ else
+ if (alignmentzones[i].topzone)
+ if (stemtop >= alignmentzones[i].bottomy + blues->BlueShift)
+ enforceovershoot = TRUE;
+ else
+ if (stembottom <= alignmentzones[i].topy - blues->BlueShift)
+ enforceovershoot = TRUE;
+
+ /*************************************************/
+ /* ALIGN THE FLAT POSITION OF THE ALIGNMENT ZONE */
+ /*************************************************/
+
+ /* Compute the position of the alignment zone's flat position in
+ device space and the amount of shift needed to align it on a
+ pixel boundary. Move all stems this amount. */
+
+ if (alignmentzones[i].topzone)
+ flatposition = alignmentzones[i].bottomy;
+ else
+ flatposition = alignmentzones[i].topy;
+
+ /* Find the flat position in pixels */
+ flatpospixels = flatposition * unitpixels;
+
+ /* Find the stem shift necessary to align the flat
+ position on a pixel boundary, and use this shift for all stems */
+ stemshift = (ROUND(flatpospixels) - flatpospixels) * onepixel;
+
+ /************************************************/
+ /* HANDLE OVERSHOOT ENFORCEMENT AND SUPPRESSION */
+ /************************************************/
+
+ /* Compute overshoot amount (non-negative) */
+ if (alignmentzones[i].topzone)
+ overshoot = stemtop - flatposition;
+ else
+ overshoot = flatposition - stembottom;
+
+ if (overshoot > 0.0) {
+ /* ENFORCE overshoot by shifting the entire stem (if necessary) so that
+ it falls at least one pixel beyond the flat position. */
+
+ if (enforceovershoot)
+ if (overshoot < onepixel)
+ if (alignmentzones[i].topzone)
+ stemshift += onepixel - overshoot;
+ else
+ stemshift -= onepixel - overshoot;
+
+ /* SUPPRESS overshoot by aligning the stem to the alignment zone's
+ flat position. */
+
+ if (suppressovershoot)
+ if (alignmentzones[i].topzone)
+ stemshift -= overshoot;
+ else
+ stemshift += overshoot;
+ }
+
+ /************************************************************/
+ /* COMPUTE HINT VALUES FOR EACH SIDE OF THE HORIZONTAL STEM */
+ /************************************************************/
+
+ /* If the stem was aligned by a topzone, we expand or contract the stem
+ only at the bottom - since the stem top was aligned by the zone.
+ If the stem was aligned by a bottomzone, we expand or contract the stem
+ only at the top - since the stem bottom was aligned by the zone. */
+ if (alignmentzones[i].topzone) {
+ lbhintvalue = stemshift - widthdiff; /* bottom */
+ rthintvalue = stemshift; /* top */
+ } else {
+ lbhintvalue = stemshift; /* bottom */
+ rthintvalue = stemshift + widthdiff; /* top */
+ }
+
+ stems[stemno].lbhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, lbhintvalue));
+ stems[stemno].lbrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -lbhintvalue));
+ stems[stemno].rthint = (struct segment *)Permanent(Loc(CharSpace, 0.0, rthintvalue));
+ stems[stemno].rtrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -rthintvalue));
+
+ return;
+
+ } /* endif (i < numalignmentzones) */
+
+ /* We didn't find any alignment zones intersecting this stem, so
+ proceed with normal stem alignment below. */
+
+ } /* endif (!stems[stemno].vertical) */
+
+ /* Align stem with pixel boundaries on device */
+ stemstart = stemstart - widthdiff / 2;
+ stemshift = ROUND(stemstart * unitpixels) * onepixel - stemstart;
+
+ /* Adjust the boundaries of the stem */
+ lbhintvalue = stemshift - widthdiff / 2; /* left or bottom */
+ rthintvalue = stemshift + widthdiff / 2; /* right or top */
+
+ if (stems[stemno].vertical) {
+ stems[stemno].lbhint = (struct segment *)Permanent(Loc(CharSpace, lbhintvalue, 0.0));
+ stems[stemno].lbrevhint = (struct segment *)Permanent(Loc(CharSpace, -lbhintvalue, 0.0));
+ stems[stemno].rthint = (struct segment *)Permanent(Loc(CharSpace, rthintvalue, 0.0));
+ stems[stemno].rtrevhint = (struct segment *)Permanent(Loc(CharSpace, -rthintvalue, 0.0));
+ } else {
+ stems[stemno].lbhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, lbhintvalue));
+ stems[stemno].lbrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -lbhintvalue));
+ stems[stemno].rthint = (struct segment *)Permanent(Loc(CharSpace, 0.0, rthintvalue));
+ stems[stemno].rtrevhint = (struct segment *)Permanent(Loc(CharSpace, 0.0, -rthintvalue));
+ }
+}
+
+#define LEFT 1
+#define RIGHT 2
+#define BOTTOM 3
+#define TOP 4
+
+/*********************************************************************/
+/* Adjust a point using the given stem hint. Use the left/bottom */
+/* hint value or the right/top hint value depending on where the */
+/* point lies in the stem. */
+/*********************************************************************/
+static struct segment *Applyhint(p, stemnumber, half)
+struct segment *p;
+int stemnumber, half;
+{
+ if (half == LEFT || half == BOTTOM)
+ return Join(p, stems[stemnumber].lbhint); /* left or bottom hint */
+ else
+ return Join(p, stems[stemnumber].rthint); /* right or top hint */
+}
+
+/*********************************************************************/
+/* Adjust a point using the given reverse hint. Use the left/bottom */
+/* hint value or the right/top hint value depending on where the */
+/* point lies in the stem. */
+/*********************************************************************/
+static struct segment *Applyrevhint(p, stemnumber, half)
+struct segment *p;
+int stemnumber, half;
+{
+ if (half == LEFT || half == BOTTOM)
+ return Join(p, stems[stemnumber].lbrevhint); /* left or bottom hint */
+ else
+ return Join(p, stems[stemnumber].rtrevhint); /* right or top hint */
+}
+
+/***********************************************************************/
+/* Find the vertical and horizontal stems that the current point */
+/* (x, y) may be involved in. At most one horizontal and one vertical */
+/* stem can apply to a single point, since there are no overlaps */
+/* allowed. */
+/* The actual hintvalue is returned as a location. */
+/* Hints are ignored inside a DotSection. */
+/***********************************************************************/
+static struct segment *FindStems(x, y, dx, dy)
+double x, y, dx, dy;
+{
+ int i;
+ int newvert, newhor;
+ struct segment *p;
+ int newhorhalf, newverthalf;
+
+ if (InDotSection) return(NULL);
+
+ newvert = newhor = -1;
+ newhorhalf = newverthalf = -1;
+
+ for (i = currstartstem; i < numstems; i++) {
+ if (stems[i].vertical) { /* VSTEM hint */
+ if ((x >= stems[i].x - EPS) &&
+ (x <= stems[i].x+stems[i].dx + EPS)) {
+ newvert = i;
+ if (dy != 0.0) {
+ if (dy < 0) newverthalf = LEFT;
+ else newverthalf = RIGHT;
+ } else {
+ if (x < stems[i].x+stems[i].dx / 2) newverthalf = LEFT;
+ else newverthalf = RIGHT;
+ }
+ }
+ } else { /* HSTEM hint */
+ if ((y >= stems[i].y - EPS) &&
+ (y <= stems[i].y+stems[i].dy + EPS)) {
+ newhor = i;
+ if (dx != 0.0) {
+ if (dx < 0) newhorhalf = TOP;
+ else newhorhalf = BOTTOM;
+ } else {
+ if (y < stems[i].y+stems[i].dy / 2) newhorhalf = BOTTOM;
+ else newhorhalf = TOP;
+ }
+ }
+ }
+ }
+
+ p = NULL;
+
+ if (newvert == -1 && oldvert == -1) ; /* Outside of any hints */
+ else if (newvert == oldvert &&
+ newverthalf == oldverthalf); /* No hint change */
+ else if (oldvert == -1) { /* New vertical hint in effect */
+ p = Applyhint(p, newvert, newverthalf);
+ } else if (newvert == -1) { /* Old vertical hint no longer in effect */
+ p = Applyrevhint(p, oldvert, oldverthalf);
+ } else { /* New vertical hint in effect, old hint no longer in effect */
+ p = Applyrevhint(p, oldvert, oldverthalf);
+ p = Applyhint(p, newvert, newverthalf);
+ }
+
+ if (newhor == -1 && oldhor == -1) ; /* Outside of any hints */
+ else if (newhor == oldhor &&
+ newhorhalf == oldhorhalf) ; /* No hint change */
+ else if (oldhor == -1) { /* New horizontal hint in effect */
+ p = Applyhint(p, newhor, newhorhalf);
+ } else if (newhor == -1) { /* Old horizontal hint no longer in effect */
+ p = Applyrevhint(p, oldhor, oldhorhalf);
+ }
+ else { /* New horizontal hint in effect, old hint no longer in effect */
+ p = Applyrevhint(p, oldhor, oldhorhalf);
+ p = Applyhint(p, newhor, newhorhalf);
+ }
+
+ oldvert = newvert; oldverthalf = newverthalf;
+ oldhor = newhor; oldhorhalf = newhorhalf;
+
+ return p;
+}
+
+/******************************************************/
+/* Subroutines and statics for the Type1Char routines */
+/******************************************************/
+
+static int strindex; /* index into PostScript string being interpreted */
+static double currx, curry; /* accumulated x and y values for hints */
+
+struct callstackentry {
+ psobj *currstrP; /* current CharStringP */
+ int currindex; /* current strindex */
+ unsigned short currkey; /* current decryption key */
+ };
+
+static double Stack[MAXSTACK];
+static int Top;
+static struct callstackentry CallStack[MAXCALLSTACK];
+static int CallTop;
+static double PSFakeStack[MAXPSFAKESTACK];
+static int PSFakeTop;
+
+static void
+ClearStack()
+{
+ Top = -1;
+}
+
+static void
+Push(Num)
+ double Num;
+{
+ if (++Top < MAXSTACK) Stack[Top] = Num;
+ else Error0("Push: Stack full\n");
+}
+
+static void
+ClearCallStack()
+{
+ CallTop = -1;
+}
+
+static void
+PushCall(CurrStrP, CurrIndex, CurrKey)
+ psobj *CurrStrP;
+ int CurrIndex;
+ unsigned short CurrKey;
+{
+ if (++CallTop < MAXCALLSTACK) {
+ CallStack[CallTop].currstrP = CurrStrP; /* save CharString pointer */
+ CallStack[CallTop].currindex = CurrIndex; /* save CharString index */
+ CallStack[CallTop].currkey = CurrKey; /* save decryption key */
+ }
+ else Error0("PushCall: Stack full\n");
+}
+
+static void
+PopCall(CurrStrPP, CurrIndexP, CurrKeyP)
+ psobj **CurrStrPP;
+ int *CurrIndexP;
+ unsigned short *CurrKeyP;
+{
+ if (CallTop >= 0) {
+ *CurrStrPP = CallStack[CallTop].currstrP; /* restore CharString pointer */
+ *CurrIndexP = CallStack[CallTop].currindex; /* restore CharString index */
+ *CurrKeyP = CallStack[CallTop--].currkey; /* restore decryption key */
+ }
+ else Error0("PopCall: Stack empty\n");
+}
+
+static void
+ClearPSFakeStack()
+{
+ PSFakeTop = -1;
+}
+
+/* PSFakePush: Pushes a number onto the fake PostScript stack */
+static void
+PSFakePush(Num)
+ double Num;
+{
+ if (++PSFakeTop < MAXPSFAKESTACK) PSFakeStack[PSFakeTop] = Num;
+ else Error0("PSFakePush: Stack full\n");
+}
+
+/* PSFakePop: Removes a number from the top of the fake PostScript stack */
+static double
+PSFakePop ()
+{
+ if (PSFakeTop >= 0) return(PSFakeStack[PSFakeTop--]);
+ else Error0Ret("PSFakePop : Stack empty\n", 0.0);
+ /*NOTREACHED*/
+}
+
+/***********************************************************************/
+/* Center a stem on the pixel grid -- used by HStem3 and VStem3 */
+/***********************************************************************/
+static struct segment *CenterStem(edge1, edge2)
+ double edge1;
+ double edge2;
+{
+ int idealwidth, verticalondevice;
+ double leftx, lefty, rightx, righty, center, width;
+ double widthx, widthy;
+ double shift, shiftx, shifty;
+ double Xpixels, Ypixels;
+ struct segment *p;
+
+ p = Loc(CharSpace, edge1, 0.0);
+ QueryLoc(p, IDENTITY, &leftx, &lefty);
+
+ p = Join(p, Loc(CharSpace, edge2, 0.0));
+ QueryLoc(p, IDENTITY, &rightx, &righty);
+ Destroy(p);
+
+ widthx = FABS(rightx - leftx);
+ widthy = FABS(righty - lefty);
+
+ if (widthy <= EPS) { /* verticalondevice hint */
+ verticalondevice = TRUE;
+ center = (rightx + leftx) / 2.0;
+ width = widthx;
+ }
+ else if (widthx <= EPS) { /* horizontal hint */
+ verticalondevice = FALSE;
+ center = (righty + lefty) / 2.0;
+ width = widthy;
+ }
+ else { /* neither horizontal nor verticalondevice and not oblique */
+ return (NULL);
+ }
+
+ idealwidth = ROUND(width);
+ if (idealwidth == 0) idealwidth = 1;
+ if (ODD(idealwidth)) { /* is ideal width odd? */
+ /* center stem over pixel */
+ shift = FLOOR(center) + 0.5 - center;
+ }
+ else {
+ /* align stem on pixel boundary */
+ shift = ROUND(center) - center;
+ }
+
+ if (verticalondevice) {
+ shiftx = shift;
+ shifty = 0.0;
+ } else {
+ shifty = shift;
+ shiftx = 0.0;
+ }
+
+ p = Loc(IDENTITY, shiftx, shifty);
+ QueryLoc(p, CharSpace, &Xpixels, &Ypixels);
+ wsoffsetX = Xpixels; wsoffsetY = Ypixels;
+ currx += wsoffsetX; curry += wsoffsetY;
+
+ return (p);
+}
+
+/*-----------------------------------------------------------------------
+ Decrypt - From Adobe Type 1 book page 63, with some modifications
+-----------------------------------------------------------------------*/
+#define KEY 4330 /* Initial key (seed) for CharStrings decryption */
+#define C1 52845 /* Multiplier for pseudo-random number generator */
+#define C2 22719 /* Constant for pseudo-random number generator */
+
+static unsigned short r; /* Pseudo-random sequence of keys */
+
+static unsigned char Decrypt(cipher)
+unsigned char cipher;
+{
+ unsigned char plain;
+
+ plain = cipher ^ (r >> 8);
+ r = (cipher + r) * C1 + C2;
+ return plain;
+}
+
+/* Get the next byte from the codestring being interpreted */
+static int DoRead(CodeP)
+ int *CodeP;
+{
+ if (strindex >= CharStringP->len) return(FALSE); /* end of string */
+ *CodeP = Decrypt((unsigned char) CharStringP->data.stringP[strindex++]);
+ return(TRUE);
+}
+
+/* Strip blues->lenIV bytes from CharString and update encryption key */
+/* (the lenIV entry in the Private dictionary specifies the number of */
+/* random bytes at the beginning of each CharString; default is 4) */
+static void StartDecrypt()
+{
+ int Code;
+
+ r = KEY; /* Initial key (seed) for CharStrings decryption */
+ for (strindex = 0; strindex < blues->lenIV;)
+ if (!DoRead(&Code)) /* Read a byte and update decryption key */
+ Error0("StartDecrypt: Premature end of CharString\n");
+}
+
+static void
+Decode(Code)
+ int Code;
+{
+ int Code1, Code2, Code3, Code4;
+
+ if (Code <= 31) /* Code is [0,31] */
+ DoCommand(Code);
+ else if (Code <= 246) /* Code is [32,246] */
+ Push((double)(Code - 139));
+ else if (Code <= 250) { /* Code is [247,250] */
+ if (!DoRead(&Code2)) goto ended;
+ Push((double)(((Code - 247) << 8) + Code2 + 108));
+ }
+ else if (Code <= 254) { /* Code is [251,254] */
+ if (!DoRead(&Code2)) goto ended;
+ Push((double)( -((Code - 251) << 8) - Code2 - 108));
+ }
+ else { /* Code is 255 */
+ if (!DoRead(&Code1)) goto ended;
+ if (!DoRead(&Code2)) goto ended;
+ if (!DoRead(&Code3)) goto ended;
+ if (!DoRead(&Code4)) goto ended;
+ Push((double)((((((Code1<<8) + Code2)<<8) + Code3)<<8) + Code4));
+ }
+ return;
+
+ended: Error0("Decode: Premature end of Type 1 CharString");
+}
+
+/* Interpret a command code */
+static void
+DoCommand(Code)
+ int Code;
+{
+ switch(Code) {
+ case HSTEM: /* |- y dy HSTEM |- */
+ /* Vertical range of a horizontal stem zone */
+ if (Top < 1) Error0("DoCommand: Stack low\n");
+ HStem(Stack[0], Stack[1]);
+ ClearStack();
+ break;
+ case VSTEM: /* |- x dx VSTEM |- */
+ /* Horizontal range of a vertical stem zone */
+ if (Top < 1) Error0("DoCommand: Stack low\n");
+ VStem(Stack[0], Stack[1]);
+ ClearStack();
+ break;
+ case VMOVETO: /* |- dy VMOVETO |- */
+ /* Vertical MOVETO, equivalent to 0 dy RMOVETO */
+ if (Top < 0) Error0("DoCommand: Stack low\n");
+ RMoveTo(0.0, Stack[0]);
+ ClearStack();
+ break;
+ case RLINETO: /* |- dx dy RLINETO |- */
+ /* Like RLINETO in PostScript */
+ if (Top < 1) Error0("DoCommand: Stack low\n");
+ RLineTo(Stack[0], Stack[1]);
+ ClearStack();
+ break;
+ case HLINETO: /* |- dx HLINETO |- */
+ /* Horizontal LINETO, equivalent to dx 0 RLINETO */
+ if (Top < 0) Error0("DoCommand: Stack low\n");
+ RLineTo(Stack[0], 0.0);
+ ClearStack();
+ break;
+ case VLINETO: /* |- dy VLINETO |- */
+ /* Vertical LINETO, equivalent to 0 dy RLINETO */
+ if (Top < 0) Error0("DoCommand: Stack low\n");
+ RLineTo(0.0, Stack[0]);
+ ClearStack();
+ break;
+ case RRCURVETO:
+ /* |- dx1 dy1 dx2 dy2 dx3 dy3 RRCURVETO |- */
+ /* Relative RCURVETO, equivalent to dx1 dy1 */
+ /* (dx1+dx2) (dy1+dy2) (dx1+dx2+dx3) */
+ /* (dy1+dy2+dy3) RCURVETO in PostScript */
+ if (Top < 5) Error0("DoCommand: Stack low\n");
+ RRCurveTo(Stack[0], Stack[1], Stack[2], Stack[3],
+ Stack[4], Stack[5]);
+ ClearStack();
+ break;
+ case CLOSEPATH: /* - CLOSEPATH |- */
+ /* Closes a subpath without repositioning the */
+ /* current point */
+ DoClosePath();
+ ClearStack();
+ break;
+ case CALLSUBR: /* subr# CALLSUBR - */
+ /* Calls a CharString subroutine with index */
+ /* subr# from the Subrs array */
+ if (Top < 0) Error0("DoCommand: Stack low\n");
+ CallSubr((int)Stack[Top--]);
+ break;
+ case RETURN: /* - RETURN - */
+ /* Returns from a Subrs array CharString */
+ /* subroutine called with CALLSUBR */
+ Return();
+ break;
+ case ESCAPE: /* ESCAPE to two-byte command code */
+ if (!DoRead(&Code)) Error0("DoCommand: ESCAPE is last byte\n");
+ Escape(Code);
+ break;
+ case HSBW: /* |- sbx wx HSBW |- */
+ /* Set the left sidebearing point to (sbx,0), */
+ /* set the character width vector to (wx,0). */
+ /* Equivalent to sbx 0 wx 0 SBW. Space */
+ /* character should have sbx = 0 */
+ if (Top < 1) Error0("DoCommand: Stack low\n");
+ Sbw(Stack[0], 0.0, Stack[1], 0.0);
+ ClearStack();
+ break;
+ case ENDCHAR: /* - ENDCHAR |- */
+ /* Finishes a CharString outline */
+ EndChar();
+ ClearStack();
+ break;
+ case RMOVETO: /* |- dx dy RMOVETO |- */
+ /* Behaves like RMOVETO in PostScript */
+ if (Top < 1) Error0("DoCommand: Stack low\n");
+ RMoveTo(Stack[0], Stack[1]);
+ ClearStack();
+ break;
+ case HMOVETO: /* |- dx HMOVETO |- */
+ /* Horizontal MOVETO. Equivalent to dx 0 RMOVETO */
+ if (Top < 0) Error0("DoCommand: Stack low\n");
+ RMoveTo(Stack[0], 0.0);
+ ClearStack();
+ break;
+ case VHCURVETO: /* |- dy1 dx2 dy2 dx3 VHCURVETO |- */
+ /* Vertical-Horizontal CURVETO, equivalent to */
+ /* 0 dy1 dx2 dy2 dx3 0 RRCURVETO */
+ if (Top < 3) Error0("DoCommand: Stack low\n");
+ RRCurveTo(0.0, Stack[0], Stack[1], Stack[2],
+ Stack[3], 0.0);
+ ClearStack();
+ break;
+ case HVCURVETO: /* |- dx1 dx2 dy2 dy3 HVCURVETO |- */
+ /* Horizontal-Vertical CURVETO, equivalent to */
+ /* dx1 0 dx2 dy2 0 dy3 RRCURVETO */
+ if (Top < 3) Error0("DoCommand: Stack low\n");
+ RRCurveTo(Stack[0], 0.0, Stack[1], Stack[2], 0.0, Stack[3]);
+ ClearStack();
+ break;
+ default: /* Unassigned command code */
+ ClearStack();
+ Error1("DoCommand: Unassigned code %d\n", Code);
+ }
+}
+
+static void
+Escape(Code)
+ int Code;
+{
+ int i, Num;
+ struct segment *p;
+
+ switch(Code) {
+ case DOTSECTION: /* - DOTSECTION |- */
+ /* Brackets an outline section for the dots in */
+ /* letters such as "i", "j", and "!". */
+ DotSection();
+ ClearStack();
+ break;
+ case VSTEM3: /* |- x0 dx0 x1 dx1 x2 dx2 VSTEM3 |- */
+ /* Declares the horizontal ranges of three */
+ /* vertical stem zones between x0 and x0+dx0, */
+ /* x1 and x1+dx1, and x2 and x2+dx2. */
+ if (Top < 5) Error0("DoCommand: Stack low\n");
+ if (!wsset && ProcessHints) {
+ /* Shift the whole character so that the middle stem is centered. */
+ p = CenterStem(Stack[2] + sidebearingX, Stack[3]);
+ path = Join(path, p);
+ wsset = 1;
+ }
+
+ VStem(Stack[0], Stack[1]);
+ VStem(Stack[2], Stack[3]);
+ VStem(Stack[4], Stack[5]);
+ ClearStack();
+ break;
+ case HSTEM3: /* |- y0 dy0 y1 dy1 y2 dy2 HSTEM3 |- */
+ /* Declares the vertical ranges of three hori- */
+ /* zontal stem zones between y0 and y0+dy0, */
+ /* y1 and y1+dy1, and y2 and y2+dy2. */
+ if (Top < 5) Error0("DoCommand: Stack low\n");
+ HStem(Stack[0], Stack[1]);
+ HStem(Stack[2], Stack[3]);
+ HStem(Stack[4], Stack[5]);
+ ClearStack();
+ break;
+ case SEAC: /* |- asb adx ady bchar achar SEAC |- */
+ /* Standard Encoding Accented Character. */
+ if (Top < 4) Error0("DoCommand: Stack low\n");
+ Seac(Stack[0], Stack[1], Stack[2],
+ (unsigned char) Stack[3],
+ (unsigned char) Stack[4]);
+ ClearStack();
+ break;
+ case SBW: /* |- sbx sby wx wy SBW |- */
+ /* Set the left sidebearing point to (sbx,sby), */
+ /* set the character width vector to (wx,wy). */
+ if (Top < 3) Error0("DoCommand: Stack low\n");
+ Sbw(Stack[0], Stack[1], Stack[2], Stack[3]);
+ ClearStack();
+ break;
+ case DIV: /* num1 num2 DIV quotient */
+ /* Behaves like DIV in the PostScript language */
+ if (Top < 1) Error0("DoCommand: Stack low\n");
+ Stack[Top-1] = Div(Stack[Top-1], Stack[Top]);
+ Top--;
+ break;
+ case CALLOTHERSUBR:
+ /* arg1 ... argn n othersubr# CALLOTHERSUBR - */
+ /* Make calls on the PostScript interpreter */
+ if (Top < 1) Error0("DoCommand: Stack low\n");
+ Num = Stack[Top-1];
+ if (Top < Num+1) Error0("DoCommand: Stack low\n");
+ for (i = 0; i < Num; i++) PSFakePush(Stack[Top - i - 2]);
+ Top -= Num + 2;
+ CallOtherSubr((int)Stack[Top + Num + 2]);
+ break;
+ case POP: /* - POP number */
+ /* Removes a number from the top of the */
+ /* PostScript interpreter stack and pushes it */
+ /* onto the Type 1 BuildChar operand stack */
+ Push(PSFakePop());
+ break;
+ case SETCURRENTPOINT: /* |- x y SETCURRENTPOINT |- */
+ /* Sets the current point to (x,y) in absolute */
+ /* character space coordinates without per- */
+ /* forming a CharString MOVETO command */
+ if (Top < 1) Error0("DoCommand: Stack low\n");
+ SetCurrentPoint(Stack[0], Stack[1]);
+ ClearStack();
+ break;
+ default: /* Unassigned escape code command */
+ ClearStack();
+ Error1("Escape: Unassigned code %d\n", Code);
+ }
+}
+
+/* |- y dy HSTEM |- */
+/* Declares the vertical range of a horizontal stem zone */
+/* between coordinates y and y + dy */
+/* y is relative to the left sidebearing point */
+static void
+HStem(y, dy)
+ double y, dy;
+{
+ IfTrace2((FontDebug), "Hstem %f %f\n", &y, &dy);
+ if (ProcessHints) {
+ if (numstems >= MAXSTEMS) Error0("HStem: Too many hints\n");
+ if (dy < 0.0) {y += dy; dy = -dy;}
+ stems[numstems].vertical = FALSE;
+ stems[numstems].x = 0.0;
+ stems[numstems].y = sidebearingY + y + wsoffsetY;
+ stems[numstems].dx = 0.0;
+ stems[numstems].dy = dy;
+ ComputeStem(numstems);
+ numstems++;
+ }
+}
+
+/* |- x dx VSTEM |- */
+/* Declares the horizontal range of a vertical stem zone */
+/* between coordinates x and x + dx */
+/* x is relative to the left sidebearing point */
+static void
+VStem(x, dx)
+ double x, dx;
+{
+ IfTrace2((FontDebug), "Vstem %f %f\n", &x, &dx);
+ if (ProcessHints) {
+ if (numstems >= MAXSTEMS) Error0("VStem: Too many hints\n");
+ if (dx < 0.0) {x += dx; dx = -dx;}
+ stems[numstems].vertical = TRUE;
+ stems[numstems].x = sidebearingX + x + wsoffsetX;
+ stems[numstems].y = 0.0;
+ stems[numstems].dx = dx;
+ stems[numstems].dy = 0.0;
+ ComputeStem(numstems);
+ numstems++;
+ }
+}
+
+/* |- dx dy RLINETO |- */
+/* Behaves like RLINETO in PostScript */
+static void
+RLineTo(dx, dy)
+ double dx, dy;
+{
+ struct segment *B;
+
+ IfTrace2((FontDebug), "RLineTo %f %f\n", &dx, &dy);
+
+ B = Loc(CharSpace, dx, dy);
+
+ if (ProcessHints) {
+ currx += dx;
+ curry += dy;
+ /* B = Join(B, FindStems(currx, curry)); */
+ B = Join(B, FindStems(currx, curry, dx, dy));
+ }
+
+ path = Join(path, Line(B));
+}
+
+/* |- dx1 dy1 dx2 dy2 dx3 dy3 RRCURVETO |- */
+/* Relative RCURVETO, equivalent to dx1 dy1 */
+/* (dx1+dx2) (dy1+dy2) (dx1+dx2+dx3) */
+/* (dy1+dy2+dy3) RCURVETO in PostScript */
+static void
+RRCurveTo(dx1, dy1, dx2, dy2, dx3, dy3)
+ double dx1, dy1, dx2, dy2, dx3, dy3;
+{
+ struct segment *B, *C, *D;
+
+ IfTrace4((FontDebug), "RRCurveTo %f %f %f %f ", &dx1, &dy1, &dx2, &dy2);
+ IfTrace2((FontDebug), "%f %f\n", &dx3, &dy3);
+
+ B = Loc(CharSpace, dx1, dy1);
+ C = Loc(CharSpace, dx2, dy2);
+ D = Loc(CharSpace, dx3, dy3);
+
+ if (ProcessHints) {
+ /* For a Bezier curve, we apply the full hint value to
+ the Bezier C point (and thereby D point). */
+ currx += dx1 + dx2 + dx3;
+ curry += dy1 + dy2 + dy3;
+ /* C = Join(C, FindStems(currx, curry)); */
+ C = Join(C, FindStems(currx, curry, dx3, dy3));
+ }
+
+ /* Since XIMAGER is not completely relative, */
+ /* we need to add up the delta values */
+
+ C = Join(C, Dup(B));
+ D = Join(D, Dup(C));
+
+ path = Join(path, Bezier(B, C, D));
+}
+
+/* - CLOSEPATH |- */
+/* Closes a subpath WITHOUT repositioning the */
+/* current point */
+static void
+DoClosePath()
+{
+ struct segment *CurrentPoint;
+
+ IfTrace0((FontDebug), "DoClosePath\n");
+ CurrentPoint = Phantom(path);
+ path = ClosePath(path);
+ path = Join(Snap(path), CurrentPoint);
+}
+
+/* subr# CALLSUBR - */
+/* Calls a CharString subroutine with index */
+/* subr# from the Subrs array */
+static void
+CallSubr(subrno)
+ int subrno;
+{
+ IfTrace1((FontDebug), "CallSubr %d\n", subrno);
+ if ((subrno < 0) || (subrno >= SubrsP->len))
+ Error0("CallSubr: subrno out of range\n");
+ PushCall(CharStringP, strindex, r);
+ CharStringP = &SubrsP->data.arrayP[subrno];
+ StartDecrypt();
+}
+
+/* - RETURN - */
+/* Returns from a Subrs array CharString */
+/* subroutine called with CALLSUBR */
+static void
+Return()
+{
+ IfTrace0((FontDebug), "Return\n");
+ PopCall(&CharStringP, &strindex, &r);
+}
+
+/* - ENDCHAR |- */
+/* Finishes a CharString outline */
+/* Executes SETCHACHEDEVICE using a bounding box */
+/* it computes directly from the character outline */
+/* and using the width information acquired from a previous */
+/* HSBW or SBW. It then calls a special version of FILL */
+/* or STROKE depending on the value of PaintType in the */
+/* font dictionary */
+static void
+EndChar()
+{
+ IfTrace0((FontDebug), "EndChar\n");
+
+ /* There is no need to compute and set bounding box for
+ the cache, since XIMAGER does that on the fly. */
+
+ /* Perform a Closepath just in case the command was left out */
+ path = ClosePath(path);
+
+ /* Set character width */
+ path = Join(Snap(path), Loc(CharSpace, escapementX, escapementY));
+
+}
+
+/* |- dx dy RMOVETO |- */
+/* Behaves like RMOVETO in PostScript */
+static void
+RMoveTo(dx,dy)
+ double dx,dy;
+{
+ struct segment *B;
+
+ IfTrace2((FontDebug), "RMoveTo %f %f\n", &dx, &dy);
+
+ B = Loc(CharSpace, dx, dy);
+
+ if (ProcessHints) {
+ currx += dx;
+ curry += dy;
+ /* B = Join(B, FindStems(currx, curry)); */
+ B = Join(B, FindStems(currx, curry, 0.0, 0.0));
+ }
+
+ path = Join(path, B);
+}
+
+/* - DOTSECTION |- */
+/* Brackets an outline section for the dots in */
+/* letters such as "i", "j", and "!". */
+static void
+DotSection()
+{
+ IfTrace0((FontDebug), "DotSection\n");
+ InDotSection = !InDotSection;
+}
+
+/* |- asb adx ady bchar achar SEAC |- */
+/* Standard Encoding Accented Character. */
+static void
+Seac(asb, adx, ady, bchar, achar)
+ double asb, adx, ady;
+ unsigned char bchar, achar;
+{
+ int Code;
+ struct segment *mypath;
+
+ IfTrace4((FontDebug), "SEAC %f %f %f %d ", &asb, &adx, &ady, bchar);
+ IfTrace1((FontDebug), "%d\n", achar);
+
+ /* Move adx - asb, ady over and up from base char's sbpoint. */
+ /* (We use adx - asb to counteract the accents sb shift.) */
+ /* The variables accentoffsetX/Y modify sidebearingX/Y in Sbw(). */
+ /* Note that these incorporate the base character's sidebearing shift by */
+ /* using the current sidebearingX, Y values. */
+ accentoffsetX = sidebearingX + adx - asb;
+ accentoffsetY = sidebearingY + ady;
+
+ /* Set path = NULL to avoid complaints from Sbw(). */
+ path = NULL;
+
+ /* Go find the CharString for the accent's code via an upcall */
+ CharStringP = GetType1CharString(Environment, achar);
+ StartDecrypt();
+
+ ClearStack();
+ ClearPSFakeStack();
+ ClearCallStack();
+
+ for (;;) {
+ if (!DoRead(&Code)) break;
+ Decode(Code);
+ if (errflag) return;
+ }
+ /* Copy snapped path to mypath and set path to NULL as above. */
+ mypath = Snap(path);
+ path = NULL;
+
+ /* We must reset these to null now. */
+ accentoffsetX = accentoffsetY = 0;
+
+ /* go find the CharString for the base char's code via an upcall */
+ CharStringP = GetType1CharString(Environment, bchar);
+ StartDecrypt();
+
+ ClearStack();
+ ClearPSFakeStack();
+ ClearCallStack();
+
+ FinitStems();
+ InitStems();
+
+ for (;;) {
+ if (!DoRead(&Code)) break;
+ Decode(Code);
+ if (errflag) return;
+ }
+ path = Join(mypath, path);
+}
+
+
+/* |- sbx sby wx wy SBW |- */
+/* Set the left sidebearing point to (sbx,sby), */
+/* set the character width vector to (wx,wy). */
+static void
+Sbw(sbx, sby, wx, wy)
+ double sbx, sby, wx, wy;
+{
+ IfTrace4((FontDebug), "SBW %f %f %f %f\n", &sbx, &sby, &wx, &wy);
+
+ escapementX = wx; /* Character width vector */
+ escapementY = wy;
+
+ /* Sidebearing values are sbx, sby args, plus accent offset from Seac(). */
+ sidebearingX = sbx + accentoffsetX;
+ sidebearingY = sby + accentoffsetY;
+
+ path = Join(path, Loc(CharSpace, sidebearingX, sidebearingY));
+ if (ProcessHints) {currx = sidebearingX; curry = sidebearingY;}
+}
+
+ /* num1 num2 DIV quotient */
+/* Behaves like DIV in the PostScript language */
+static double Div(num1, num2)
+ double num1, num2;
+{
+ IfTrace2((FontDebug), "Div %f %f\n", &num1, &num2);
+ return(num1 / num2);
+}
+
+/*
+ The following four subroutines (FlxProc, FlxProc1, FlxProc2, and
+ HintReplace) are C versions of the OtherSubrs Programs, which were
+ were published in the Adobe Type 1 Font Format book.
+
+ The Flex outline fragment is described by
+ c1: (x0, y0) = c3: (x0, yshrink(y0)) or (xshrink(x0), y0)
+ " (x1, y1) = " (x1, yshrink(y1)) or (xshrink(x1), y1)
+ " (x2, y2) - reference point
+ c2: (x0, y0) = c4: (x0, yshrink(y0)) or (xshrink(x0), y0)
+ " (x1, y1) = " (x1, yshrink(y1)) or (xshrink(x1), y1)
+ " (x2, y2) = " (x2, y2), rightmost endpoint
+ c3: (x0, y0) - control point, 1st Bezier curve
+ " (x1, y1) - control point, -"-
+ " (x2, y2) - end point, -"-
+ c4: (x0, y0) - control point, 2nd Bezier curve
+ " (x1, y1) - control point, -"-
+ " (x2, y2) - end point, -"-
+ ep: (epY, epX) - final endpoint (should be same as c4: (x2, y2))
+ idmin - minimum Flex height (1/100 pixel) at which to render curves
+*/
+
+#define dtransform(dxusr,dyusr,dxdev,dydev) { \
+ register struct segment *point = Loc(CharSpace, dxusr, dyusr); \
+ QueryLoc(point, IDENTITY, dxdev, dydev); \
+ Destroy(point); \
+}
+
+#define itransform(xdev,ydev,xusr,yusr) { \
+ register struct segment *point = Loc(IDENTITY, xdev, ydev); \
+ QueryLoc(point, CharSpace, xusr, yusr); \
+ Destroy(point); \
+}
+
+#define transform(xusr,yusr,xdev,ydev) dtransform(xusr,yusr,xdev,ydev)
+
+#define PaintType (0)
+
+#define lineto(x,y) { \
+ struct segment *CurrentPoint; \
+ double CurrentX, CurrentY; \
+ CurrentPoint = Phantom(path); \
+ QueryLoc(CurrentPoint, CharSpace, &CurrentX, &CurrentY); \
+ Destroy(CurrentPoint); \
+ RLineTo(x - CurrentX, y - CurrentY); \
+}
+
+#define curveto(x0,y0,x1,y1,x2,y2) { \
+ struct segment *CurrentPoint; \
+ double CurrentX, CurrentY; \
+ CurrentPoint = Phantom(path); \
+ QueryLoc(CurrentPoint, CharSpace, &CurrentX, &CurrentY); \
+ Destroy(CurrentPoint); \
+ RRCurveTo(x0 - CurrentX, y0 - CurrentY, x1 - x0, y1 - y0, x2 - x1, y2 - y1); \
+}
+
+#define xshrink(x) ((x - c4x2) * shrink +c4x2)
+#define yshrink(y) ((y - c4y2) * shrink +c4y2)
+
+#define PickCoords(flag) \
+ if (flag) { /* Pick "shrunk" coordinates */ \
+ x0 = c1x0; y0 = c1y0; \
+ x1 = c1x1; y1 = c1y1; \
+ x2 = c1x2; y2 = c1y2; \
+ x3 = c2x0; y3 = c2y0; \
+ x4 = c2x1; y4 = c2y1; \
+ x5 = c2x2; y5 = c2y2; \
+ } else { /* Pick original coordinates */ \
+ x0 = c3x0; y0 = c3y0; \
+ x1 = c3x1; y1 = c3y1; \
+ x2 = c3x2; y2 = c3y2; \
+ x3 = c4x0; y3 = c4y0; \
+ x4 = c4x1; y4 = c4y1; \
+ x5 = c4x2; y5 = c4y2; \
+ }
+
+/* FlxProc() = OtherSubrs[0]; Main part of Flex */
+/* Calling sequence: 'idmin epX epY 3 0 callothersubr' */
+/* Computes Flex values, and renders the Flex path, */
+/* and returns (leaves) ending coordinates on stack */
+static void
+FlxProc(c1x2, c1y2, c3x0, c3y0, c3x1, c3y1, c3x2, c3y2,
+ c4x0, c4y0, c4x1, c4y1, c4x2, c4y2, epY, epX, idmin)
+ double c1x2, c1y2;
+ double c3x0, c3y0, c3x1, c3y1, c3x2, c3y2;
+ double c4x0, c4y0, c4x1, c4y1, c4x2, c4y2;
+ double epX, epY;
+ int idmin;
+{
+ double dmin;
+ double c1x0, c1y0, c1x1, c1y1;
+ double c2x0, c2y0, c2x1, c2y1, c2x2, c2y2;
+ char yflag;
+ double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5;
+ double cxx, cyx, cxy, cyy; /* Transformation matrix */
+ int flipXY;
+ double x, y;
+ double erosion = 1; /* Device parameter */
+ /* Erosion may have different value specified in 'internaldict' */
+ double shrink;
+ double dX, dY;
+ char erode;
+ double eShift;
+ double cx, cy;
+ double ex, ey;
+
+ c1x0 = c1y0 = c1x1 = c1y1 = c2x0 = c2y0 = c2x1 = c2y1 = c2x2 = c2y2 = 0.0;
+
+ Destroy(path);
+ path = FlxOldPath; /* Restore previous path (stored in FlxProc1) */
+
+ if (ProcessHints) {
+ dmin = ABS(idmin) / 100.0; /* Minimum Flex height in pixels */
+
+ c2x2 = c4x2; c2y2 = c4y2; /* Point c2 = c4 */
+
+ yflag = FABS(c1y2 - c3y2) > FABS(c1x2 - c3x2); /* Flex horizontal? */
+
+ QuerySpace(CharSpace, &cxx, &cyx, &cxy, &cyy); /* Transformation matrix */
+
+ if (FABS(cxx) < 0.00001 || FABS(cyy) < 0.00001)
+ flipXY = -1; /* Char on side */
+ else if (FABS(cyx) < 0.00001 || FABS(cxy) < 0.00001)
+ flipXY = 1; /* Char upright */
+ else
+ flipXY = 0; /* Char at angle */
+
+ if (yflag) { /* Flex horizontal */
+ if (flipXY == 0 || c3y2 == c4y2) { /* Char at angle or Flex height = 0 */
+ PickCoords(FALSE); /* Pick original control points */
+ } else {
+ shrink = FABS((c1y2 - c4y2) / (c3y2 - c4y2)); /* Slope */
+
+ c1x0 = c3x0; c1y0 = yshrink(c3y0);
+ c1x1 = c3x1; c1y1 = yshrink(c3y1);
+ c2x0 = c4x0; c2y0 = yshrink(c4y0);
+ c2x1 = c4x1; c2y1 = yshrink(c4y1);
+
+ dtransform(0.0, ROUND(c3y2-c1y2), &x, &y); /* Flex height in pixels */
+ dY = FABS((flipXY == 1) ? y : x);
+ PickCoords(dY < dmin); /* If Flex small, pick 'shrunk' control points */
+
+ if (FABS(y2 - c1y2) > 0.001) { /* Flex 'non-zero'? */
+ transform(c1x2, c1y2, &x, &y);
+
+ if (flipXY == 1) {
+ cx = x; cy = y;
+ } else {
+ cx = y; cy = x;
+ }
+
+ dtransform(0.0, ROUND(y2-c1y2), &x, &y);
+ dY = (flipXY == 1) ? y : x;
+ if (ROUND(dY) != 0)
+ dY = ROUND(dY);
+ else
+ dY = (dY < 0) ? -1 : 1;
+
+ erode = PaintType != 2 && erosion >= 0.5;
+ if (erode)
+ cy -= 0.5;
+ ey = cy + dY;
+ ey = CEIL(ey) - ey;
+ ey = ey + FLOOR(cy + dY);
+ if (erode)
+ ey += 0.5;
+
+ if (flipXY == 1) {
+ itransform(cx, ey, &x, &y);
+ } else {
+ itransform(ey, cx, &x, &y);
+ }
+
+ eShift = y - y2;
+ y1 += eShift;
+ y2 += eShift;
+ y3 += eShift;
+ }
+ }
+ } else { /* Flex vertical */
+ if (flipXY == 0 || c3x2 == c4x2) { /* Char at angle or Flex height = 0 */
+ PickCoords(FALSE); /* Pick original control points */
+ } else {
+ shrink = FABS((c1x2 - c4x2) / (c3x2 - c4x2)); /* Slope */
+
+ c1x0 = xshrink(c3x0); c1y0 = c3y0;
+ c1x1 = xshrink(c3x1); c1y1 = c3y1;
+ c2x0 = xshrink(c4x0); c2y0 = c4y0;
+ c2x1 = xshrink(c4x1); c2y1 = c4y1;
+
+ dtransform(ROUND(c3x2 - c1x2), 0.0, &x, &y); /* Flex height in pixels */
+ dX = FABS((flipXY == -1) ? y : x);
+ PickCoords(dX < dmin); /* If Flex small, pick 'shrunk' control points */
+
+ if (FABS(x2 - c1x2) > 0.001) {
+ transform(c1x2, c1y2, &x, &y);
+ if (flipXY == -1) {
+ cx = y; cy = x;
+ } else {
+ cx = x; cy = y;
+ }
+
+ dtransform(ROUND(x2-c1x2), 0.0, &x, &y);
+ dX = (flipXY == -1) ? y : x;
+ if (ROUND(dX) != 0)
+ dX = ROUND(dX);
+ else
+ dX = (dX < 0) ? -1 : 1;
+
+ erode = PaintType != 2 && erosion >= 0.5;
+ if (erode)
+ cx -= 0.5;
+ ex = cx + dX;
+ ex = CEIL(ex) - ex;
+ ex = ex + FLOOR(cx + dX);
+ if (erode)
+ ex += 0.5;
+
+ if (flipXY == -1) {
+ itransform(cy, ex, &x, &y);
+ } else {
+ itransform(ex, cy, &x, &y);
+ }
+
+ eShift = x - x2;
+ x1 += eShift;
+ x2 += eShift;
+ x3 += eShift;
+ }
+ }
+ }
+
+ if (x2 == x5 || y2 == y5) {
+ lineto(x5, y5);
+ } else {
+ curveto(x0, y0, x1, y1, x2, y2);
+ curveto(x3, y3, x4, y4, x5, y5);
+ }
+ } else { /* ProcessHints is off */
+ PickCoords(FALSE); /* Pick original control points */
+ curveto(x0, y0, x1, y1, x2, y2);
+ curveto(x3, y3, x4, y4, x5, y5);
+ }
+
+ PSFakePush(epY);
+ PSFakePush(epX);
+}
+
+/* FlxProc1() = OtherSubrs[1]; Part of Flex */
+/* Calling sequence: '0 1 callothersubr' */
+/* Saves and clears path, then restores currentpoint */
+static void FlxProc1()
+{
+ struct segment *CurrentPoint;
+
+ CurrentPoint = Phantom(path);
+
+ FlxOldPath = path;
+ path = CurrentPoint;
+}
+
+/* FlxProc2() = OtherSubrs[2]; Part of Flex */
+/* Calling sequence: '0 2 callothersubr' */
+/* Returns currentpoint on stack */
+static void FlxProc2()
+{
+ struct segment *CurrentPoint;
+ double CurrentX, CurrentY;
+
+ CurrentPoint = Phantom(path);
+ QueryLoc(CurrentPoint, CharSpace, &CurrentX, &CurrentY);
+ Destroy(CurrentPoint);
+
+ /* Push CurrentPoint on fake PostScript stack */
+ PSFakePush(CurrentX);
+ PSFakePush(CurrentY);
+}
+
+/* HintReplace() = OtherSubrs[3]; Hint Replacement */
+/* Calling sequence: 'subr# 1 3 callothersubr pop callsubr' */
+/* Reinitializes stem hint structure */
+static void HintReplace()
+{
+ /* Effectively retire the current stems, but keep them around for */
+ /* revhint use in case we are in a stem when we replace hints. */
+ currstartstem = numstems;
+
+ /* 'subr#' is left on PostScript stack (for 'pop callsubr') */
+}
+
+/* arg1 ... argn n othersubr# CALLOTHERSUBR - */
+/* Make calls on the PostScript interpreter (or call equivalent C code) */
+/* NOTE: The n arguments have been pushed on the fake PostScript stack */
+static void
+CallOtherSubr(othersubrno)
+ int othersubrno;
+{
+ IfTrace1((FontDebug), "CallOtherSubr %d\n", othersubrno);
+
+ switch(othersubrno) {
+ case 0: /* OtherSubrs[0]; Main part of Flex */
+ if (PSFakeTop < 16) Error0("CallOtherSubr: PSFakeStack low");
+ ClearPSFakeStack();
+ FlxProc(
+ PSFakeStack[0], PSFakeStack[1], PSFakeStack[2], PSFakeStack[3],
+ PSFakeStack[4], PSFakeStack[5], PSFakeStack[6], PSFakeStack[7],
+ PSFakeStack[8], PSFakeStack[9], PSFakeStack[10], PSFakeStack[11],
+ PSFakeStack[12], PSFakeStack[13], PSFakeStack[14], PSFakeStack[15],
+ (int) PSFakeStack[16]
+ );
+ break;
+ case 1: /* OtherSubrs[1]; Part of Flex */
+ FlxProc1();
+ break;
+ case 2: /* OtherSubrs[2]; Part of Flex */
+ FlxProc2();
+ break;
+ case 3: /* OtherSubrs[3]; Hint Replacement */
+ HintReplace();
+ break;
+ default: { /* call OtherSubrs[4] or higher if PostScript is present */
+ }
+ }
+}
+
+/* |- x y SETCURRENTPOINT |- */
+/* Sets the current point to (x,y) in absolute */
+/* character space coordinates without per- */
+/* forming a CharString MOVETO command */
+static void
+SetCurrentPoint(x, y)
+ double x, y;
+{
+ IfTrace2((FontDebug), "SetCurrentPoint %f %f\n", &x, &y);
+
+ currx = x;
+ curry = y;
+}
+
+/* The Type1Char routine for use by PostScript. */
+/************************************************/
+struct xobject *Type1Char(env, S, charstrP, subrsP, osubrsP, bluesP, modeP)
+ char *env;
+ struct XYspace *S;
+ psobj *charstrP;
+ psobj *subrsP;
+ psobj *osubrsP;
+ struct blues_struct *bluesP; /* FontID's ptr to the blues struct */
+ int *modeP;
+{
+ int Code;
+
+ path = NULL;
+ errflag = FALSE;
+
+ /* Make parameters available to all Type1 routines */
+ Environment = env;
+ CharSpace = S; /* used when creating path elements */
+ CharStringP = charstrP;
+ SubrsP = subrsP;
+ OtherSubrsP = osubrsP;
+ ModeP = modeP;
+
+ blues = bluesP;
+
+ /* compute the alignment zones */
+ ComputeAlignmentZones();
+
+ StartDecrypt();
+
+ ClearStack();
+ ClearPSFakeStack();
+ ClearCallStack();
+
+ InitStems();
+
+ currx = curry = 0;
+ escapementX = escapementY = 0;
+ sidebearingX = sidebearingY = 0;
+ accentoffsetX = accentoffsetY = 0;
+ wsoffsetX = wsoffsetY = 0; /* No shift to preserve whitspace. */
+ wsset = 0; /* wsoffsetX,Y haven't been set yet. */
+
+ for (;;) {
+ if (!DoRead(&Code)) break;
+ Decode(Code);
+ if (errflag) break;
+ }
+
+ FinitStems();
+
+
+ /* Clean up if an error has occurred */
+ if (errflag) {
+ if (path != NULL) {
+ Destroy(path); /* Reclaim storage */
+ path = NULL; /* Indicate that character could not be built */
+ }
+ }
+
+ return((struct xobject *) path);
+}
+
diff --git a/src/Type1/util.c b/src/Type1/util.c
new file mode 100644
index 0000000..aafe7c5
--- /dev/null
+++ b/src/Type1/util.c
@@ -0,0 +1,195 @@
+/* $Xorg: util.c,v 1.3 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* Author: Katherine A. Hitchcock IBM Almaden Research Laboratory */
+
+#include <stdio.h>
+#include "util.h"
+#include "fontmisc.h"
+
+static char *vm_base = NULL; /* Start of virtual memory area */
+ char *vm_next = NULL; /* Pointer to first free byte */
+ long vm_free = 0; /* Count of free bytes */
+ long vm_size = 0; /* Total size of memory */
+
+/*
+ * Initialize memory.
+ */
+boolean vm_init(cnt)
+int cnt;
+{
+ vm_next = vm_base = (char *)xalloc (cnt);
+
+ if (vm_base != NULL) {
+ vm_free = cnt;
+ vm_size = cnt;
+ return(TRUE);
+ }
+ else
+ return(FALSE);
+
+}
+
+char *vm_alloc(bytes)
+ int bytes;
+{
+ char *answer;
+
+ /* Round to next word multiple */
+ bytes = (bytes + 7) & ~7;
+
+ /* Allocate the space, if it is available */
+ if (bytes <= vm_free) {
+ answer = vm_next;
+ vm_free -= bytes;
+ vm_next += bytes;
+ }
+ else
+ answer = NULL;
+
+ return(answer);
+}
+
+/*
+ * Format an Integer object
+ */
+void objFormatInteger(objP,value)
+ psobj *objP;
+ int value;
+{
+ if (objP != NULL) {
+ objP->type = OBJ_INTEGER;
+ objP->len = 0;
+ objP->data.integer = value;
+ }
+}
+
+/*
+ * Format a Real object
+ */
+void objFormatReal(objP,value)
+ psobj *objP;
+ float value;
+{
+ if (objP != NULL) {
+ objP->type = OBJ_REAL;
+ objP->len = 0;
+ objP->data.real = value;
+ }
+}
+
+/*
+ * Format a Boolean object
+ */
+void objFormatBoolean(objP,value)
+ psobj *objP;
+ boolean value;
+{
+ if (objP != NULL) {
+ objP->type = OBJ_BOOLEAN;
+ objP->len = 0;
+ objP->data.boolean = value;
+ }
+}
+
+/*
+ * Format an Encoding object
+ */
+void objFormatEncoding(objP,length,valueP)
+ psobj *objP;
+ int length;
+ psobj *valueP;
+{
+ if (objP != NULL) {
+ objP->type = OBJ_ENCODING;
+ objP->len = length;
+ objP->data.arrayP = valueP;
+ }
+}
+
+/*
+ * Format an Array object
+ */
+void objFormatArray(objP,length,valueP)
+ psobj *objP;
+ int length;
+ psobj *valueP;
+{
+ if (objP != NULL) {
+ objP->type = OBJ_ARRAY;
+ objP->len = length;
+ objP->data.arrayP = valueP;
+ }
+}
+
+
+/*
+ * Format a String object
+ */
+void objFormatString(objP,length,valueP)
+ psobj *objP;
+ int length;
+ char *valueP;
+{
+ if (objP != NULL) {
+ objP->type = OBJ_STRING;
+ objP->len = length;
+ objP->data.valueP = valueP;
+ }
+}
+
+/*
+ * Format a Name object
+ */
+void objFormatName(objP,length,valueP)
+ psobj *objP;
+ int length;
+ char *valueP;
+{
+ if (objP != NULL) {
+ objP->type = OBJ_NAME;
+ objP->len = length;
+ objP->data.nameP = valueP;
+ }
+}
+
+/*
+ * Format a File object
+ */
+void objFormatFile(objP,valueP)
+ psobj *objP;
+ FILE *valueP;
+{
+ if (objP != NULL) {
+ objP->type = OBJ_FILE;
+ objP->len = 0;
+ objP->data.fileP = valueP;
+ }
+}
+
diff --git a/src/Type1/util.h b/src/Type1/util.h
new file mode 100644
index 0000000..20c14c4
--- /dev/null
+++ b/src/Type1/util.h
@@ -0,0 +1,182 @@
+/* $Xorg: util.h,v 1.3 2000/08/17 19:46:34 cpqbld Exp $ */
+/* Copyright International Business Machines,Corp. 1991
+ * All Rights Reserved
+ *
+ * License to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the name of IBM not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.
+ *
+ * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
+ * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+ * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND
+ * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
+ * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF
+ * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
+ * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN
+ * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+#ifndef UTIL_H
+#define UTIL_H
+
+
+#ifndef boolean
+typedef int boolean;
+#endif
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/***================================================================***/
+/* Portable definitions for 2's complement machines.
+ * NOTE: These really should be based on PostScript types,
+ * for example, sizeof(ps_integer), or sizeof(ps_unsigned)
+ */
+#define MAX_ULONG (~(unsigned long)(0))
+/* This code is portable, assuming K&R C and 2's complement arithmetic */
+#define MAX_INTEGER \
+ ((long)((((unsigned long) 1)<<(sizeof(unsigned long)*8-1))-1))
+#define MIN_INTEGER ((-MAX_INTEGER)-1)
+
+#define MAX_ARRAY_CNT (65535)
+#define MAX_DICT_CNT (65535)
+#define MAX_STRING_LEN (65535)
+#define MAX_NAME_LEN (128)
+
+/* this is the size of memory allocated for reading fonts */
+
+#define VM_SIZE (50*1024)
+/***================================================================***/
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b)) ? a : b )
+#endif
+
+/***================================================================***/
+/* Routines for managing virtual memory */
+/***================================================================***/
+extern boolean vm_init();
+extern long vm_free;
+extern long vm_size;
+extern char *vm_next;
+extern char *vm_alloc();
+/***================================================================***/
+/* Macros for managing virtual memory */
+/***================================================================***/
+#define vm_next_byte() (vm_next)
+#define vm_free_bytes() (vm_free)
+#define vm_avail(B) (B <= vm_free)
+
+
+
+/***================================================================***/
+/* Types of PostScript objects */
+/***================================================================***/
+#define OBJ_INTEGER (0)
+#define OBJ_REAL (1)
+#define OBJ_BOOLEAN (2)
+#define OBJ_ARRAY (3)
+#define OBJ_STRING (4)
+#define OBJ_NAME (5)
+#define OBJ_FILE (6)
+#define OBJ_ENCODING (7)
+
+/***================================================================***/
+/* Value of PostScript objects */
+/***================================================================***/
+typedef union ps_value {
+ char *valueP; /* value pointer for unspecified type */
+ int value; /* value for unspecified type */
+ int integer; /* when type is OBJ_INTEGER */
+ float real; /* when type is OBJ_REAL */
+ int boolean; /* when type is OBJ_BOOLEAN */
+ struct ps_obj *arrayP; /* when type is OBJ_ARRAY */
+ unsigned char *stringP; /* when type is OBJ_STRING */
+ char *nameP; /* when type is OBJ_NAME */
+ FILE *fileP; /* when type is OBJ_FILE */
+} psvalue;
+
+/***================================================================***/
+/* Definition of a PostScript object */
+/***================================================================***/
+typedef struct ps_obj {
+ char type;
+ char unused;
+ unsigned short len;
+ union ps_value data;
+} psobj;
+
+/***================================================================***/
+/* Definition of a PostScript Dictionary Entry */
+/***================================================================***/
+typedef struct ps_dict {
+ psobj key;
+ psobj value;
+} psdict;
+
+/***================================================================***/
+/* Macros for testing type of PostScript objects */
+/***================================================================***/
+#define objIsInteger(o) ((o).type == OBJ_INTEGER)
+#define objIsReal(o) ((o).type == OBJ_REAL)
+#define objIsBoolean(o) ((o).type == OBJ_BOOLEAN)
+#define objIsArray(o) ((o).type == OBJ_ARRAY)
+#define objIsString(o) ((o).type == OBJ_STRING)
+#define objIsName(o) ((o).type == OBJ_NAME)
+#define objIsFile(o) ((o).type == OBJ_FILE)
+
+/***================================================================***/
+/* Macros for setting type of PostScript objects */
+/***================================================================***/
+#define objSetInteger(o) ((o).type = OBJ_INTEGER)
+#define objSetReal(o) ((o).type = OBJ_REAL)
+#define objSetBoolean(o) ((o).type = OBJ_BOOLEAN)
+#define objSetArray(o) ((o).type = OBJ_ARRAY)
+#define objSetString(o) ((o).type = OBJ_STRING)
+#define objSetName(o) ((o).type = OBJ_NAME)
+#define objSetFile(o) ((o).type = OBJ_FILE)
+
+/***================================================================***/
+/* Macros for testing type of PostScript objects (pointer access) */
+/***================================================================***/
+#define objPIsInteger(o) ((o)->type == OBJ_INTEGER)
+#define objPIsReal(o) ((o)->type == OBJ_REAL)
+#define objPIsBoolean(o) ((o)->type == OBJ_BOOLEAN)
+#define objPIsArray(o) ((o)->type == OBJ_ARRAY)
+#define objPIsString(o) ((o)->type == OBJ_STRING)
+#define objPIsName(o) ((o)->type == OBJ_NAME)
+#define objPIsFile(o) ((o)->type == OBJ_FILE)
+
+/***================================================================***/
+/* Macros for setting type of PostScript objects (pointer access) */
+/***================================================================***/
+#define objPSetInteger(o) ((o)->type = OBJ_INTEGER)
+#define objPSetReal(o) ((o)->type = OBJ_REAL)
+#define objPSetBoolean(o) ((o)->type = OBJ_BOOLEAN)
+#define objPSetArray(o) ((o)->type = OBJ_ARRAY)
+#define objPSetString(o) ((o)->type = OBJ_STRING)
+#define objPSetName(o) ((o)->type = OBJ_NAME)
+#define objPSetFile(o) ((o)->type = OBJ_FILE)
+
+/***================================================================***/
+/* Entry point for Type1Char to get entry from CharStrings */
+/***================================================================***/
+extern psobj *GetType1CharString();
+
+#endif