summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2005-03-30 08:30:22 +0200
committerTor Andersson <tor@ghostscript.com>2005-03-30 08:30:22 +0200
commitee154f16bd09a43359967f7e7b86c3677c09461d (patch)
tree08896cfa9ff55e05bfe7855965c620d45115d4d5 /base
parent460ad7040d67a4a93a153f98095ff952a2b15d37 (diff)
downloadmupdf-ee154f16bd09a43359967f7e7b86c3677c09461d.tar.xz
rename part 1 -- files
Diffstat (limited to 'base')
-rw-r--r--base/arc4.c95
-rw-r--r--base/base_cpudep.c (renamed from base/cpudep.c)0
-rw-r--r--base/base_error.c (renamed from base/error.c)0
-rw-r--r--base/base_hash.c (renamed from base/hash.c)0
-rw-r--r--base/base_matrix.c (renamed from base/matrix.c)0
-rw-r--r--base/base_memory.c (renamed from base/memory.c)0
-rw-r--r--base/base_rect.c (renamed from base/rect.c)0
-rw-r--r--base/base_rune.c (renamed from base/rune.c)0
-rw-r--r--base/md5.c269
-rw-r--r--base/node_debug.c191
-rw-r--r--base/node_misc1.c167
-rw-r--r--base/node_misc2.c338
-rw-r--r--base/node_optimize.c310
-rw-r--r--base/node_path.c305
-rw-r--r--base/node_text.c141
-rw-r--r--base/node_tree.c107
-rw-r--r--base/res_cmap.c466
-rw-r--r--base/res_colorspace.c89
-rw-r--r--base/res_font.c269
-rw-r--r--base/res_image.c22
-rw-r--r--base/res_shade.c28
-rw-r--r--base/util_getopt.c116
-rw-r--r--base/util_strlcat.c35
-rw-r--r--base/util_strlcpy.c32
-rw-r--r--base/util_strsep.c11
25 files changed, 2627 insertions, 364 deletions
diff --git a/base/arc4.c b/base/arc4.c
deleted file mode 100644
index 86c9afd8..00000000
--- a/base/arc4.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/* This code illustrates a sample implementation
- * of the Arcfour algorithm
- * Copyright (c) April 29, 1997 Kalle Kaukonen.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that this copyright
- * notice and disclaimer are retained.
- *
- * THIS SOFTWARE IS PROVIDED BY KALLE KAUKONEN AND CONTRIBUTORS ``AS
- * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KALLE
- * KAUKONEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <fitz.h>
-
-void
-fz_arc4init(fz_arc4 *arc4, unsigned char *key, unsigned keylen)
-{
- unsigned int t, u;
- unsigned int keyindex;
- unsigned int stateindex;
- unsigned char *state;
- unsigned int counter;
-
- state = arc4->state;
-
- arc4->x = 0;
- arc4->y = 0;
-
- for (counter = 0; counter < 256; counter++) {
- state[counter] = counter;
- }
-
- keyindex = 0;
- stateindex = 0;
-
- for (counter = 0; counter < 256; counter++) {
- t = state[counter];
- stateindex = (stateindex + key[keyindex] + t) & 0xff;
- u = state[stateindex];
-
- state[stateindex] = t;
- state[counter] = u;
-
- if (++keyindex >= keylen) {
- keyindex = 0;
- }
- }
-}
-
-unsigned char
-fz_arc4next(fz_arc4 *arc4)
-{
- unsigned int x;
- unsigned int y;
- unsigned int sx, sy;
- unsigned char *state;
-
- state = arc4->state;
-
- x = (arc4->x + 1) & 0xff;
- sx = state[x];
- y = (sx + arc4->y) & 0xff;
- sy = state[y];
-
- arc4->x = x;
- arc4->y = y;
-
- state[y] = sx;
- state[x] = sy;
-
- return state[(sx + sy) & 0xff];
-}
-
-void
-fz_arc4encrypt(fz_arc4 *arc4, unsigned char *dest, unsigned char *src, unsigned len)
-{
- unsigned int i;
- for (i = 0; i < len; i++) {
- unsigned char x;
- x = fz_arc4next(arc4);
- dest[i] = src[i] ^ x;
- }
-}
-
diff --git a/base/cpudep.c b/base/base_cpudep.c
index 0db2e331..0db2e331 100644
--- a/base/cpudep.c
+++ b/base/base_cpudep.c
diff --git a/base/error.c b/base/base_error.c
index 926c48dc..926c48dc 100644
--- a/base/error.c
+++ b/base/base_error.c
diff --git a/base/hash.c b/base/base_hash.c
index 65bc7130..65bc7130 100644
--- a/base/hash.c
+++ b/base/base_hash.c
diff --git a/base/matrix.c b/base/base_matrix.c
index 7d7097c4..7d7097c4 100644
--- a/base/matrix.c
+++ b/base/base_matrix.c
diff --git a/base/memory.c b/base/base_memory.c
index 2c2f8e0d..2c2f8e0d 100644
--- a/base/memory.c
+++ b/base/base_memory.c
diff --git a/base/rect.c b/base/base_rect.c
index 2efb11f7..2efb11f7 100644
--- a/base/rect.c
+++ b/base/base_rect.c
diff --git a/base/rune.c b/base/base_rune.c
index 4aa81df3..4aa81df3 100644
--- a/base/rune.c
+++ b/base/base_rune.c
diff --git a/base/md5.c b/base/md5.c
deleted file mode 100644
index 03601e5b..00000000
--- a/base/md5.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
-MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
-
-Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991.
-All rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
-*/
-
-#include <fitz.h>
-
-/* Constants for MD5Transform routine */
-enum
-{
- S11 = 7, S12 = 12, S13 = 17, S14 = 22,
- S21 = 5, S22 = 9, S23 = 14, S24 = 20,
- S31 = 4, S32 = 11, S33 = 16, S34 = 23,
- S41 = 6, S42 = 10, S43 = 15, S44 = 21
-};
-
-static void encode(unsigned char *, unsigned long *, unsigned);
-static void decode(unsigned long *, unsigned char *, unsigned);
-static void transform(unsigned long state[4], unsigned char block[64]);
-
-static unsigned char padding[64] =
-{
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* F, G, H and I are basic MD5 functions */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/* ROTATE rotates x left n bits */
-#define ROTATE(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
- * Rotation is separate from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (unsigned long)(ac); \
- (a) = ROTATE ((a), (s)); \
- (a) += (b); \
- }
-#define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (unsigned long)(ac); \
- (a) = ROTATE ((a), (s)); \
- (a) += (b); \
- }
-#define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (unsigned long)(ac); \
- (a) = ROTATE ((a), (s)); \
- (a) += (b); \
- }
-#define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (unsigned long)(ac); \
- (a) = ROTATE ((a), (s)); \
- (a) += (b); \
- }
-
-static void encode(unsigned char *output, unsigned long *input, unsigned len)
-{
- unsigned i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4) {
- output[j] = (unsigned char)(input[i] & 0xff);
- output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
- output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
- output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
- }
-}
-
-static void decode(unsigned long *output, unsigned char *input, unsigned len)
-{
- unsigned i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4) {
- output[i] = ((unsigned long)input[j]) |
- (((unsigned long)input[j+1]) << 8) |
- (((unsigned long)input[j+2]) << 16) |
- (((unsigned long)input[j+3]) << 24);
- }
-}
-
-static void transform(unsigned long state[4], unsigned char block[64])
-{
- unsigned long a = state[0];
- unsigned long b = state[1];
- unsigned long c = state[2];
- unsigned long d = state[3];
- unsigned long x[16];
-
- decode(x, block, 64);
-
- /* Round 1 */
- FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
- FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
- FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
- FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
- FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
- FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
- FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
- FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
- FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
- FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
- FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
- FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
- FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
- FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
- FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
- FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-
- /* Round 2 */
- GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
- GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
- GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
- GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
- GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
- GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
- GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
- GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
- GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
- GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
- GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
- GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
- GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
- GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
- GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
- GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-
- /* Round 3 */
- HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
- HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
- HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
- HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
- HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
- HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
- HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
- HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
- HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
- HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
- HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
- HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
- HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
- HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
- HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
- HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
-
- /* Round 4 */
- II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
- II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
- II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
- II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
- II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
- II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
- II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
- II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
- II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
- II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
- II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
- II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
- II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
- II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
- II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
- II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
-
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
-
- /* Zeroize sensitive information */
- memset(x, 0, sizeof (x));
-}
-
-/* MD5 initialization. Begins an MD5 operation, writing a new context. */
-void fz_md5init(fz_md5 *context)
-{
- context->count[0] = context->count[1] = 0;
-
- /* Load magic initialization constants */
- context->state[0] = 0x67452301;
- context->state[1] = 0xefcdab89;
- context->state[2] = 0x98badcfe;
- context->state[3] = 0x10325476;
-}
-
-/* MD5 block update operation. Continues an MD5 message-digest operation,
- * processing another message block, and updating the context.
- */
-void fz_md5update(fz_md5 *context, unsigned char *input, unsigned inlen)
-{
- unsigned i, index, partlen;
-
- /* Compute number of bytes mod 64 */
- index = (unsigned)((context->count[0] >> 3) & 0x3F);
-
- /* Update number of bits */
- context->count[0] += (unsigned long) inlen << 3;
- if (context->count[0] < (unsigned long) inlen << 3)
- context->count[1] ++;
- context->count[1] += (unsigned long) inlen >> 29;
-
- partlen = 64 - index;
-
- /* Transform as many times as possible. */
- if (inlen >= partlen) {
- memcpy(context->buffer + index, input, partlen);
- transform(context->state, context->buffer);
-
- for (i = partlen; i + 63 < inlen; i += 64)
- transform(context->state, input + i);
-
- index = 0;
- }
- else {
- i = 0;
- }
-
- /* Buffer remaining input */
- memcpy(context->buffer + index, input + i, inlen - i);
-}
-
-/* MD5 finalization. Ends an MD5 message-digest operation, writing the
- * the message digest and zeroizing the context.
- */
-void fz_md5final(fz_md5 *context, unsigned char digest[16])
-{
- unsigned char bits[8];
- unsigned index, padlen;
-
- /* Save number of bits */
- encode(bits, context->count, 8);
-
- /* Pad out to 56 mod 64 */
- index = (unsigned)((context->count[0] >> 3) & 0x3f);
- padlen = index < 56 ? 56 - index : 120 - index;
- fz_md5update(context, padding, padlen);
-
- /* Append length (before padding) */
- fz_md5update(context, bits, 8);
-
- /* Store state in digest */
- encode(digest, context->state, 16);
-
- /* Zeroize sensitive information */
- memset(context, 0, sizeof(fz_md5));
-}
-
diff --git a/base/node_debug.c b/base/node_debug.c
new file mode 100644
index 00000000..b03d4e28
--- /dev/null
+++ b/base/node_debug.c
@@ -0,0 +1,191 @@
+#include <fitz.h>
+
+static void indent(int level)
+{
+ while (level--)
+ putchar(' ');
+}
+
+static void lispnode(fz_node *node, int level);
+
+static void lispmeta(fz_metanode *node, int level)
+{
+ fz_node *child;
+ indent(level);
+ printf("(meta ");
+ if (node->name) { fz_debugobj(node->name); }
+ if (node->dict) { printf("\n"); fz_debugobj(node->dict); }
+ printf("\n");
+ for (child = node->super.first; child; child = child->next)
+ lispnode(child, level + 1);
+ indent(level);
+ printf(")\n");
+}
+
+static void lispover(fz_overnode *node, int level)
+{
+ fz_node *child;
+ indent(level);
+ printf("(over\n");
+ for (child = node->super.first; child; child = child->next)
+ lispnode(child, level + 1);
+ indent(level);
+ printf(")\n");
+}
+
+static void lispmask(fz_masknode *node, int level)
+{
+ fz_node *child;
+ indent(level);
+ printf("(mask\n");
+ for (child = node->super.first; child; child = child->next)
+ lispnode(child, level + 1);
+ indent(level);
+ printf(")\n");
+}
+
+static void lispblend(fz_blendnode *node, int level)
+{
+ fz_node *child;
+ indent(level);
+ printf("(blend-%d\n", node->mode);
+ for (child = node->super.first; child; child = child->next)
+ lispnode(child, level + 1);
+ indent(level);
+ printf(")\n");
+}
+
+static void lisptransform(fz_transformnode *node, int level)
+{
+ indent(level);
+ printf("(transform %g %g %g %g %g %g\n",
+ node->m.a, node->m.b,
+ node->m.c, node->m.d,
+ node->m.e, node->m.f);
+ lispnode(node->super.first, level + 1);
+ indent(level);
+ printf(")\n");
+}
+
+static void lispcolor(fz_colornode *node, int level)
+{
+ int i;
+ indent(level);
+ printf("(color %s ", node->cs->name);
+ for (i = 0; i < node->n; i++)
+ printf("%g ", node->samples[i]);
+ printf(")\n");
+}
+
+static void lisplink(fz_linknode *node, int level)
+{
+ indent(level);
+ printf("(link %p)\n", node->tree);
+}
+
+static void lisppath(fz_pathnode *node, int level)
+{
+ int i;
+
+ indent(level);
+
+ if (node->paint == FZ_STROKE)
+ {
+ printf("(path 'stroke %d %d %g %g ",
+ node->linecap,
+ node->linejoin,
+ node->linewidth,
+ node->miterlimit);
+ if (node->dash)
+ {
+ printf("%g '( ", node->dash->phase);
+ for (i = 0; i < node->dash->len; i++)
+ printf("%g ", node->dash->array[i]);
+ printf(")");
+ }
+ else
+ printf("0 '()");
+ }
+ else
+ {
+ printf("(path '%s", node->paint == FZ_FILL ? "fill" : "eofill");
+ }
+
+ printf("\n");
+ fz_debugpathnode(node);
+
+ indent(level);
+ printf(")\n");
+}
+
+static void lisptext(fz_textnode *node, int level)
+{
+ int i;
+
+ indent(level);
+ printf("(text %s [%g %g %g %g]\n", node->font->name,
+ node->trm.a, node->trm.b, node->trm.c, node->trm.d);
+
+ for (i = 0; i < node->len; i++)
+ {
+ indent(level + 1);
+ if (node->els[i].cid >= 32 && node->els[i].cid < 128)
+ printf("(cid '%c' %g %g)\n", node->els[i].cid, node->els[i].x, node->els[i].y);
+ else
+ printf("(cid <%04x> %g %g)\n", node->els[i].cid, node->els[i].x, node->els[i].y);
+ }
+
+ indent(level);
+ printf(")\n");
+}
+
+static void lispimage(fz_imagenode *node, int level)
+{
+ fz_image *image = node->image;
+ indent(level);
+ printf("(image %dx%d %d+%d)\n", image->w, image->h, image->n, image->a);
+}
+
+static void lispshade(fz_shadenode *node, int level)
+{
+ indent(level);
+ printf("(shade)\n");
+}
+
+static void lispnode(fz_node *node, int level)
+{
+ if (!node)
+ {
+ indent(level);
+ printf("(nil)\n");
+ return;
+ }
+
+ switch (node->kind)
+ {
+ case FZ_NMETA: lispmeta((fz_metanode*)node, level); break;
+ case FZ_NOVER: lispover((fz_overnode*)node, level); break;
+ case FZ_NMASK: lispmask((fz_masknode*)node, level); break;
+ case FZ_NBLEND: lispblend((fz_blendnode*)node, level); break;
+ case FZ_NTRANSFORM: lisptransform((fz_transformnode*)node, level); break;
+ case FZ_NCOLOR: lispcolor((fz_colornode*)node, level); break;
+ case FZ_NPATH: lisppath((fz_pathnode*)node, level); break;
+ case FZ_NTEXT: lisptext((fz_textnode*)node, level); break;
+ case FZ_NIMAGE: lispimage((fz_imagenode*)node, level); break;
+ case FZ_NSHADE: lispshade((fz_shadenode*)node, level); break;
+ case FZ_NLINK: lisplink((fz_linknode*)node, level); break;
+ }
+}
+
+void
+fz_debugnode(fz_node *node)
+{
+ lispnode(node, 0);
+}
+
+void
+fz_debugtree(fz_tree *tree)
+{
+ lispnode(tree->root, 0);
+}
+
diff --git a/base/node_misc1.c b/base/node_misc1.c
new file mode 100644
index 00000000..c2d6e876
--- /dev/null
+++ b/base/node_misc1.c
@@ -0,0 +1,167 @@
+#include <fitz.h>
+
+void fz_dropmetanode(fz_metanode* node);
+void fz_droplinknode(fz_linknode* node);
+void fz_droppathnode(fz_pathnode* node);
+void fz_droptextnode(fz_textnode* node);
+void fz_dropimagenode(fz_imagenode* node);
+void fz_dropshadenode(fz_shadenode* node);
+
+fz_rect fz_boundtransformnode(fz_transformnode* node, fz_matrix ctm);
+fz_rect fz_boundovernode(fz_overnode* node, fz_matrix ctm);
+fz_rect fz_boundmasknode(fz_masknode* node, fz_matrix ctm);
+fz_rect fz_boundblendnode(fz_blendnode* node, fz_matrix ctm);
+fz_rect fz_boundcolornode(fz_colornode* node, fz_matrix ctm);
+fz_rect fz_boundpathnode(fz_pathnode* node, fz_matrix ctm);
+fz_rect fz_boundtextnode(fz_textnode* node, fz_matrix ctm);
+fz_rect fz_boundimagenode(fz_imagenode* node, fz_matrix ctm);
+fz_rect fz_boundshadenode(fz_shadenode* node, fz_matrix ctm);
+fz_rect fz_boundlinknode(fz_linknode* node, fz_matrix ctm);
+fz_rect fz_boundmetanode(fz_metanode* node, fz_matrix ctm);
+
+void
+fz_initnode(fz_node *node, fz_nodekind kind)
+{
+ node->kind = kind;
+ node->parent = nil;
+ node->first = nil;
+ node->last = nil;
+ node->next = nil;
+}
+
+void
+fz_dropnode(fz_node *node)
+{
+ if (node->first)
+ fz_dropnode(node->first);
+ if (node->next)
+ fz_dropnode(node->next);
+
+ switch (node->kind)
+ {
+ case FZ_NTRANSFORM:
+ case FZ_NOVER:
+ case FZ_NMASK:
+ case FZ_NBLEND:
+ case FZ_NCOLOR:
+ break;
+ case FZ_NPATH:
+ fz_droppathnode((fz_pathnode *) node);
+ break;
+ case FZ_NTEXT:
+ fz_droptextnode((fz_textnode *) node);
+ break;
+ case FZ_NIMAGE:
+ fz_dropimagenode((fz_imagenode *) node);
+ break;
+ case FZ_NSHADE:
+ fz_dropshadenode((fz_shadenode *) node);
+ break;
+ case FZ_NLINK:
+ fz_droplinknode((fz_linknode *) node);
+ break;
+ case FZ_NMETA:
+ fz_dropmetanode((fz_metanode *) node);
+ break;
+ }
+
+ fz_free(node);
+}
+
+fz_rect
+fz_boundnode(fz_node *node, fz_matrix ctm)
+{
+ switch (node->kind)
+ {
+ case FZ_NTRANSFORM:
+ return fz_boundtransformnode((fz_transformnode *) node, ctm);
+ case FZ_NOVER:
+ return fz_boundovernode((fz_overnode *) node, ctm);
+ case FZ_NMASK:
+ return fz_boundmasknode((fz_masknode *) node, ctm);
+ case FZ_NBLEND:
+ return fz_boundblendnode((fz_blendnode *) node, ctm);
+ case FZ_NCOLOR:
+ return fz_boundcolornode((fz_colornode *) node, ctm);
+ case FZ_NPATH:
+ return fz_boundpathnode((fz_pathnode *) node, ctm);
+ case FZ_NTEXT:
+ return fz_boundtextnode((fz_textnode *) node, ctm);
+ case FZ_NIMAGE:
+ return fz_boundimagenode((fz_imagenode *) node, ctm);
+ case FZ_NSHADE:
+ return fz_boundshadenode((fz_shadenode *) node, ctm);
+ case FZ_NLINK:
+ return fz_boundlinknode((fz_linknode *) node, ctm);
+ case FZ_NMETA:
+ return fz_boundmetanode((fz_metanode *) node, ctm);
+ }
+ return fz_emptyrect;
+}
+
+int
+fz_istransformnode(fz_node *node)
+{
+ return node ? node->kind == FZ_NTRANSFORM : 0;
+}
+
+int
+fz_isovernode(fz_node *node)
+{
+ return node ? node->kind == FZ_NOVER : 0;
+}
+
+int
+fz_ismasknode(fz_node *node)
+{
+ return node ? node->kind == FZ_NMASK : 0;
+}
+
+int
+fz_isblendnode(fz_node *node)
+{
+ return node ? node->kind == FZ_NBLEND : 0;
+}
+
+int
+fz_iscolornode(fz_node *node)
+{
+ return node ? node->kind == FZ_NCOLOR : 0;
+}
+
+int
+fz_ispathnode(fz_node *node)
+{
+ return node ? node->kind == FZ_NPATH : 0;
+}
+
+int
+fz_istextnode(fz_node *node)
+{
+ return node ? node->kind == FZ_NTEXT : 0;
+}
+
+int
+fz_isimagenode(fz_node *node)
+{
+ return node ? node->kind == FZ_NIMAGE : 0;
+}
+
+int
+fz_isshadenode(fz_node *node)
+{
+ return node ? node->kind == FZ_NSHADE : 0;
+}
+
+int
+fz_islinknode(fz_node *node)
+{
+ return node ? node->kind == FZ_NLINK : 0;
+}
+
+int
+fz_ismetanode(fz_node *node)
+{
+ return node ? node->kind == FZ_NMETA : 0;
+}
+
diff --git a/base/node_misc2.c b/base/node_misc2.c
new file mode 100644
index 00000000..f21ebf36
--- /dev/null
+++ b/base/node_misc2.c
@@ -0,0 +1,338 @@
+#include <fitz.h>
+
+/*
+ * Over
+ */
+
+fz_error *
+fz_newovernode(fz_node **nodep)
+{
+ fz_node *node;
+
+ node = *nodep = fz_malloc(sizeof (fz_overnode));
+ if (!node)
+ return fz_outofmem;
+
+ fz_initnode(node, FZ_NOVER);
+
+ return nil;
+}
+
+fz_rect
+fz_boundovernode(fz_overnode *node, fz_matrix ctm)
+{
+ fz_node *child;
+ fz_rect bbox;
+ fz_rect temp;
+
+ child = node->super.first;
+ if (!child)
+ return fz_emptyrect;
+
+ bbox = fz_boundnode(child, ctm);
+
+ child = child->next;
+ while (child)
+ {
+ temp = fz_boundnode(child, ctm);
+ bbox = fz_mergerects(temp, bbox);
+ child = child->next;
+ }
+
+ return bbox;
+}
+
+/*
+ * Mask
+ */
+
+fz_error *
+fz_newmasknode(fz_node **nodep)
+{
+ fz_node *node;
+
+ node = *nodep = fz_malloc(sizeof (fz_masknode));
+ if (!node)
+ return fz_outofmem;
+
+ fz_initnode(node, FZ_NMASK);
+
+ return nil;
+}
+
+fz_rect
+fz_boundmasknode(fz_masknode *node, fz_matrix ctm)
+{
+ fz_node *shape;
+ fz_node *color;
+ fz_rect one, two;
+
+ shape = node->super.first;
+ color = shape->next;
+
+ one = fz_boundnode(shape, ctm);
+ two = fz_boundnode(color, ctm);
+ return fz_intersectrects(one, two);
+}
+
+/*
+ * Blend
+ */
+
+fz_error *
+fz_newblendnode(fz_node **nodep, fz_colorspace *cs, fz_blendkind b, int k, int i)
+{
+ fz_blendnode *node;
+
+ node = fz_malloc(sizeof (fz_blendnode));
+ if (!node)
+ return fz_outofmem;
+ *nodep = (fz_node*)node;
+
+ fz_initnode((fz_node*)node, FZ_NBLEND);
+ node->cs = fz_keepcolorspace(cs);
+ node->mode = b;
+ node->knockout = k;
+ node->isolated = i;
+
+ return nil;
+}
+
+fz_rect
+fz_boundblendnode(fz_blendnode *node, fz_matrix ctm)
+{
+ fz_node *child;
+ fz_rect bbox;
+ fz_rect temp;
+
+ child = node->super.first;
+ if (!child)
+ return fz_emptyrect;
+
+ bbox = fz_boundnode(child, ctm);
+
+ child = child->next;
+ while (child)
+ {
+ temp = fz_boundnode(child, ctm);
+ bbox = fz_mergerects(temp, bbox);
+ child = child->next;
+ }
+
+ return bbox;
+}
+
+void
+fz_dropblendnode(fz_blendnode *node)
+{
+ fz_dropcolorspace(node->cs);
+}
+
+/*
+ * Transform
+ */
+
+fz_error *
+fz_newtransformnode(fz_node **nodep, fz_matrix m)
+{
+ fz_transformnode *node;
+
+ node = fz_malloc(sizeof (fz_transformnode));
+ if (!node)
+ return fz_outofmem;
+ *nodep = (fz_node*)node;
+
+ fz_initnode((fz_node*)node, FZ_NTRANSFORM);
+ node->m = m;
+
+ return nil;
+}
+
+fz_rect
+fz_boundtransformnode(fz_transformnode *node, fz_matrix ctm)
+{
+ if (!node->super.first)
+ return fz_emptyrect;
+ return fz_boundnode(node->super.first, fz_concat(node->m, ctm));
+}
+
+/*
+ * Meta info
+ */
+
+fz_error *
+fz_newmetanode(fz_node **nodep, fz_obj *name, fz_obj *dict)
+{
+ fz_metanode *node;
+
+ node = fz_malloc(sizeof (fz_metanode));
+ if (!node)
+ return fz_outofmem;
+ *nodep = (fz_node*)node;
+
+ fz_initnode((fz_node*)node, FZ_NMETA);
+ node->name = nil;
+ node->dict = nil;
+
+ if (name)
+ node->name = fz_keepobj(name);
+ if (dict)
+ node->dict = fz_keepobj(dict);
+
+ return nil;
+}
+
+void
+fz_dropmetanode(fz_metanode *node)
+{
+ if (node->name)
+ fz_dropobj(node->name);
+ if (node->dict)
+ fz_dropobj(node->dict);
+}
+
+fz_rect
+fz_boundmetanode(fz_metanode *node, fz_matrix ctm)
+{
+ if (!node->super.first)
+ return fz_emptyrect;
+ return fz_boundnode(node->super.first, ctm);
+}
+
+/*
+ * Link to tree
+ */
+
+fz_error *
+fz_newlinknode(fz_node **nodep, fz_tree *subtree)
+{
+ fz_linknode *node;
+
+ node = fz_malloc(sizeof (fz_linknode));
+ if (!node)
+ return fz_outofmem;
+ *nodep = (fz_node*)node;
+
+ fz_initnode((fz_node*)node, FZ_NLINK);
+ node->tree = fz_keeptree(subtree);
+
+ return nil;
+}
+
+void
+fz_droplinknode(fz_linknode *node)
+{
+ fz_droptree(node->tree);
+}
+
+fz_rect
+fz_boundlinknode(fz_linknode *node, fz_matrix ctm)
+{
+ return fz_boundtree(node->tree, ctm);
+}
+
+/*
+ * Solid color
+ */
+
+fz_error *
+fz_newcolornode(fz_node **nodep, fz_colorspace *cs, int n, float *v)
+{
+ fz_colornode *node;
+ int i;
+
+ node = fz_malloc(sizeof(fz_colornode) + sizeof(float) * n);
+ if (!node)
+ return fz_outofmem;
+ *nodep = (fz_node*)node;
+
+ fz_initnode((fz_node*)node, FZ_NCOLOR);
+ node->cs = fz_keepcolorspace(cs);
+ node->n = n;
+ for (i = 0; i < n; i++)
+ node->samples[i] = v[i];
+
+ return nil;
+}
+
+fz_rect
+fz_boundcolornode(fz_colornode *node, fz_matrix ctm)
+{
+ return fz_infiniterect;
+}
+
+void
+fz_dropcolornode(fz_colornode *node)
+{
+ fz_dropcolorspace(node->cs);
+}
+
+/*
+ * Image node
+ */
+
+fz_error *
+fz_newimagenode(fz_node **nodep, fz_image *image)
+{
+ fz_imagenode *node;
+
+ node = fz_malloc(sizeof (fz_imagenode));
+ if (!node)
+ return fz_outofmem;
+ *nodep = (fz_node*)node;
+
+ fz_initnode((fz_node*)node, FZ_NIMAGE);
+ node->image = fz_keepimage(image);
+
+ return nil;
+}
+
+void
+fz_dropimagenode(fz_imagenode *node)
+{
+ fz_dropimage(node->image);
+}
+
+fz_rect
+fz_boundimagenode(fz_imagenode *node, fz_matrix ctm)
+{
+ fz_rect bbox;
+ bbox.min.x = 0;
+ bbox.min.y = 0;
+ bbox.max.x = 1;
+ bbox.max.y = 1;
+ return fz_transformaabb(ctm, bbox);
+}
+
+/*
+ * Shade node
+ */
+
+fz_error *
+fz_newshadenode(fz_node **nodep, fz_shade *shade)
+{
+ fz_shadenode *node;
+
+ node = fz_malloc(sizeof (fz_shadenode));
+ if (!node)
+ return fz_outofmem;
+ *nodep = (fz_node*)node;
+
+ fz_initnode((fz_node*)node, FZ_NSHADE);
+ node->shade = fz_keepshade(shade);
+
+ return nil;
+}
+
+void
+fz_dropshadenode(fz_shadenode *node)
+{
+ fz_dropshade(node->shade);
+}
+
+fz_rect
+fz_boundshadenode(fz_shadenode *node, fz_matrix ctm)
+{
+ return fz_boundshade(node->shade, ctm);
+}
+
diff --git a/base/node_optimize.c b/base/node_optimize.c
new file mode 100644
index 00000000..d92aa812
--- /dev/null
+++ b/base/node_optimize.c
@@ -0,0 +1,310 @@
+#include <fitz.h>
+
+/*
+ * Remove (mask ... white) until we get something not white
+ */
+
+static int iswhitenode(fz_colornode *node)
+{
+ if (!strcmp(node->cs->name, "DeviceGray"))
+ return fabs(node->samples[0] - 1.0) < FLT_EPSILON;
+ if (!strcmp(node->cs->name, "DeviceRGB"))
+ return fabs(node->samples[0] - 1.0) < FLT_EPSILON &&
+ fabs(node->samples[1] - 1.0) < FLT_EPSILON &&
+ fabs(node->samples[2] - 1.0) < FLT_EPSILON;
+ if (!strcmp(node->cs->name, "DeviceCMYK"))
+ return fabs(node->samples[0]) < FLT_EPSILON &&
+ fabs(node->samples[1]) < FLT_EPSILON &&
+ fabs(node->samples[2]) < FLT_EPSILON &&
+ fabs(node->samples[3]) < FLT_EPSILON;
+ return 0;
+}
+
+static int cleanwhite(fz_node *node)
+{
+ fz_node *current;
+ fz_node *next;
+ fz_node *shape;
+ fz_node *color;
+
+ for (current = node->first; current; current = next)
+ {
+ next = current->next;
+
+ if (fz_islinknode(current))
+ return 1;
+ else if (fz_isimagenode(current))
+ return 1;
+ else if (fz_isshadenode(current))
+ return 1;
+ else if (fz_iscolornode(current))
+ {
+ if (!iswhitenode((fz_colornode*)current))
+ return 1;
+ }
+
+ else if (fz_ismasknode(current))
+ {
+ shape = current->first;
+ color = shape->next;
+ if (fz_iscolornode(color))
+ {
+ if (iswhitenode((fz_colornode*)color))
+ fz_removenode(current);
+ else
+ return 1;
+ }
+ else
+ {
+ if (cleanwhite(current))
+ return 1;
+ }
+ }
+
+ else
+ {
+ if (cleanwhite(current))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Remove useless overs that only have one child.
+ */
+
+static void cleanovers(fz_node *node)
+{
+ fz_node *prev;
+ fz_node *next;
+ fz_node *current;
+ fz_node *child;
+
+ prev = nil;
+ for (current = node->first; current; current = next)
+ {
+ next = current->next;
+
+ if (fz_isovernode(current))
+ {
+ if (current->first == current->last)
+ {
+ child = current->first;
+ fz_removenode(current);
+ if (child)
+ {
+ if (prev)
+ fz_insertnodeafter(prev, child);
+ else
+ fz_insertnodefirst(node, child);
+ }
+ current = child;
+ }
+ }
+
+ if (current)
+ prev = current;
+ }
+
+ for (current = node->first; current; current = current->next)
+ cleanovers(current);
+}
+
+/*
+ * Remove rectangular clip-masks whose contents fit...
+ */
+
+static int getrect(fz_pathnode *path, fz_rect *bboxp)
+{
+ float x, y, w, h;
+
+ /* move x y, line x+w y, line x+w y+h, line x y+h, close */
+
+ if (path->len != 13)
+ return 0;
+
+ if (path->els[0].k != FZ_MOVETO) return 0;
+ x = path->els[1].v;
+ y = path->els[2].v;
+
+ if (path->els[3].k != FZ_LINETO) return 0;
+ w = path->els[4].v - x;
+ if (path->els[5].v != y) return 0;
+
+ if (path->els[6].k != FZ_LINETO) return 0;
+ if (path->els[7].v != x + w) return 0;
+ h = path->els[8].v - y;
+
+ if (path->els[9].k != FZ_LINETO) return 0;
+ if (path->els[10].v != x) return 0;
+ if (path->els[11].v != y + h) return 0;
+
+ if (path->els[12].k != FZ_CLOSEPATH) return 0;
+
+ bboxp->min.x = MIN(x, x + w);
+ bboxp->min.y = MIN(y, y + h);
+ bboxp->max.x = MAX(x, x + w);
+ bboxp->max.y = MAX(y, y + h);
+
+ return 1;
+}
+
+static int fitsinside(fz_node *node, fz_rect clip)
+{
+ fz_rect bbox;
+ bbox = fz_boundnode(node, fz_identity());
+ if (fz_isinfiniterect(bbox)) return 0;
+ if (fz_isemptyrect(bbox)) return 1;
+ if (bbox.min.x < clip.min.x) return 0;
+ if (bbox.max.x > clip.max.x) return 0;
+ if (bbox.min.y < clip.min.y) return 0;
+ if (bbox.max.y > clip.max.y) return 0;
+ return 1;
+}
+
+static void cleanmasks(fz_node *node)
+{
+ fz_node *prev;
+ fz_node *current;
+ fz_node *shape;
+ fz_node *color;
+ fz_rect bbox;
+
+ for (current = node->first; current; current = current->next)
+ cleanmasks(current);
+
+ prev = nil;
+ for (current = node->first; current; current = current->next)
+ {
+retry:
+ if (fz_ismasknode(current))
+ {
+ shape = current->first;
+ color = shape->next;
+
+ if (color == nil)
+ {
+ fz_removenode(current);
+ prev = nil;
+ current = node->first;
+ goto retry;
+ }
+
+ if (fz_ispathnode(shape))
+ {
+ if (getrect((fz_pathnode*)shape, &bbox))
+ {
+ if (fitsinside(color, bbox))
+ {
+ fz_removenode(current);
+ if (prev)
+ fz_insertnodeafter(prev, color);
+ else
+ fz_insertnodefirst(node, color);
+ current = color;
+ goto retry;
+ }
+ }
+ }
+ }
+
+ prev = current;
+ }
+}
+
+/*
+ * Turn 1x1 images into rectangle fills
+ */
+
+static fz_error *clean1x1(fz_node *node)
+{
+ fz_error *error;
+ fz_node *current;
+ fz_node *color;
+ fz_pathnode *rect;
+ fz_node *mask;
+ fz_image *image;
+ fz_pixmap *pix;
+ float v[FZ_MAXCOLORS];
+ int i;
+
+ for (current = node->first; current; current = current->next)
+ {
+ if (fz_isimagenode(current))
+ {
+ image = ((fz_imagenode*)current)->image;
+ if (image->w == 1 && image->h == 1)
+ {
+ error = fz_newpathnode(&rect);
+ fz_moveto(rect, 0, 0);
+ fz_lineto(rect, 1, 0);
+ fz_lineto(rect, 1, 1);
+ fz_lineto(rect, 0, 1);
+ fz_closepath(rect);
+ fz_endpath(rect, FZ_FILL, nil, nil);
+
+ if (image->cs)
+ {
+ error = fz_newpixmap(&pix, 0, 0, 1, 1, image->n + 1);
+ if (error)
+ return error;
+
+ error = image->loadtile(image, pix);
+ if (error)
+ return error;
+
+ for (i = 0; i < image->n; i++)
+ v[i] = pix->samples[i + 1] / 255.0;
+
+ fz_droppixmap(pix);
+
+ error = fz_newcolornode(&color, image->cs, image->n, v);
+ if (error)
+ return error;
+ error = fz_newmasknode(&mask);
+ if (error)
+ return error;
+
+ fz_insertnodeafter(current, mask);
+ fz_insertnodelast(mask, (fz_node*)rect);
+ fz_insertnodelast(mask, color);
+ fz_removenode(current);
+ current = mask;
+ }
+
+ else
+ {
+ /* pray that the 1x1 image mask is all opaque */
+ fz_insertnodeafter(current, (fz_node*)rect);
+ fz_removenode(current);
+ current = (fz_node*)rect;
+ }
+ }
+ }
+
+ error = clean1x1(current);
+ if (error)
+ return error;
+ }
+
+ return nil;
+}
+
+/*
+ *
+ */
+
+fz_error *
+fz_optimizetree(fz_tree *tree)
+{
+ if (getenv("DONTOPT"))
+ return nil;
+ cleanwhite(tree->root);
+ cleanovers(tree->root);
+ cleanmasks(tree->root);
+ clean1x1(tree->root);
+ return nil;
+}
+
diff --git a/base/node_path.c b/base/node_path.c
new file mode 100644
index 00000000..24b4dfc8
--- /dev/null
+++ b/base/node_path.c
@@ -0,0 +1,305 @@
+#include <fitz.h>
+
+fz_error *
+fz_newpathnode(fz_pathnode **pathp)
+{
+ fz_pathnode *path;
+
+ path = *pathp = fz_malloc(sizeof(fz_pathnode));
+ if (!path)
+ return fz_outofmem;
+
+ fz_initnode((fz_node*)path, FZ_NPATH);
+
+ path->paint = FZ_FILL;
+ path->linecap = 0;
+ path->linejoin = 0;
+ path->linewidth = 1.0;
+ path->miterlimit = 10.0;
+ path->dash = nil;
+ path->len = 0;
+ path->cap = 0;
+ path->els = nil;
+
+ return nil;
+}
+
+fz_error *
+fz_clonepathnode(fz_pathnode **pathp, fz_pathnode *oldpath)
+{
+ fz_pathnode *path;
+
+ path = *pathp = fz_malloc(sizeof(fz_pathnode));
+ if (!path)
+ return fz_outofmem;
+
+ fz_initnode((fz_node*)path, FZ_NPATH);
+
+ path->paint = FZ_FILL;
+ path->linecap = 0;
+ path->linejoin = 0;
+ path->linewidth = 1.0;
+ path->miterlimit = 10.0;
+ path->dash = nil;
+ path->len = oldpath->len;
+ path->cap = oldpath->len;
+
+ path->els = fz_malloc(sizeof (fz_pathel) * path->len);
+ if (!path->els) {
+ fz_free(path);
+ return fz_outofmem;
+ }
+ memcpy(path->els, oldpath->els, sizeof(fz_pathel) * path->len);
+
+ return nil;
+}
+
+void
+fz_droppathnode(fz_pathnode *node)
+{
+ fz_free(node->dash);
+ fz_free(node->els);
+}
+
+static fz_error *
+growpath(fz_pathnode *path, int n)
+{
+ int newcap;
+ fz_pathel *newels;
+
+ while (path->len + n > path->cap)
+ {
+ newcap = path->cap + 36;
+ newels = fz_realloc(path->els, sizeof (fz_pathel) * newcap);
+ if (!newels)
+ return fz_outofmem;
+ path->cap = newcap;
+ path->els = newels;
+ }
+
+ return nil;
+}
+
+fz_error *
+fz_moveto(fz_pathnode *path, float x, float y)
+{
+ if (growpath(path, 3) != nil)
+ return fz_outofmem;
+ path->els[path->len++].k = FZ_MOVETO;
+ path->els[path->len++].v = x;
+ path->els[path->len++].v = y;
+ return nil;
+}
+
+fz_error *
+fz_lineto(fz_pathnode *path, float x, float y)
+{
+ if (growpath(path, 3) != nil)
+ return fz_outofmem;
+ path->els[path->len++].k = FZ_LINETO;
+ path->els[path->len++].v = x;
+ path->els[path->len++].v = y;
+ return nil;
+}
+
+fz_error *
+fz_curveto(fz_pathnode *path,
+ float x1, float y1,
+ float x2, float y2,
+ float x3, float y3)
+{
+ if (growpath(path, 7) != nil)
+ return fz_outofmem;
+ path->els[path->len++].k = FZ_CURVETO;
+ path->els[path->len++].v = x1;
+ path->els[path->len++].v = y1;
+ path->els[path->len++].v = x2;
+ path->els[path->len++].v = y2;
+ path->els[path->len++].v = x3;
+ path->els[path->len++].v = y3;
+ return nil;
+}
+
+fz_error *
+fz_curvetov(fz_pathnode *path, float x2, float y2, float x3, float y3)
+{
+ float x1 = path->els[path->len-2].v;
+ float y1 = path->els[path->len-1].v;
+ return fz_curveto(path, x1, y1, x2, y2, x3, y3);
+}
+
+fz_error *
+fz_curvetoy(fz_pathnode *path, float x1, float y1, float x3, float y3)
+{
+ return fz_curveto(path, x1, y1, x3, y3, x3, y3);
+}
+
+fz_error *
+fz_closepath(fz_pathnode *path)
+{
+ if (growpath(path, 1) != nil)
+ return fz_outofmem;
+ path->els[path->len++].k = FZ_CLOSEPATH;
+ return nil;
+}
+
+fz_error *
+fz_endpath(fz_pathnode *path, fz_pathkind paint, fz_stroke *stroke, fz_dash *dash)
+{
+ fz_pathel *newels;
+
+ newels = fz_realloc(path->els, path->len * sizeof(fz_pathel));
+ if (!newels)
+ return fz_outofmem;
+ path->els = newels;
+
+ path->paint = paint;
+ path->dash = dash;
+ if (stroke)
+ {
+ path->linecap = stroke->linecap;
+ path->linejoin = stroke->linejoin;
+ path->linewidth = stroke->linewidth;
+ path->miterlimit = stroke->miterlimit;
+ }
+
+ if (path->linewidth < 0.01)
+ path->linewidth = 0.01;
+
+ return nil;
+}
+
+static inline fz_rect boundexpand(fz_rect r, fz_point p)
+{
+ if (p.x < r.min.x) r.min.x = p.x;
+ if (p.y < r.min.y) r.min.y = p.y;
+ if (p.x > r.max.x) r.max.x = p.x;
+ if (p.y > r.max.y) r.max.y = p.y;
+ return r;
+}
+
+fz_rect
+fz_boundpathnode(fz_pathnode *path, fz_matrix ctm)
+{
+ fz_point p;
+ fz_rect r = fz_emptyrect;
+ int i = 0;
+
+ if (path->len)
+ {
+ p.x = path->els[1].v;
+ p.y = path->els[2].v;
+ p = fz_transformpoint(ctm, p);
+ r.min.x = r.max.x = p.x;
+ r.min.y = r.max.y = p.y;
+ }
+
+ while (i < path->len)
+ {
+ switch (path->els[i++].k)
+ {
+ case FZ_CURVETO:
+ p.x = path->els[i++].v;
+ p.y = path->els[i++].v;
+ r = boundexpand(r, fz_transformpoint(ctm, p));
+ p.x = path->els[i++].v;
+ p.y = path->els[i++].v;
+ r = boundexpand(r, fz_transformpoint(ctm, p));
+ case FZ_MOVETO:
+ case FZ_LINETO:
+ p.x = path->els[i++].v;
+ p.y = path->els[i++].v;
+ r = boundexpand(r, fz_transformpoint(ctm, p));
+ break;
+ case FZ_CLOSEPATH:
+ break;
+ }
+ }
+
+ if (path->paint == FZ_STROKE)
+ {
+ float miterlength = sin(path->miterlimit / 2.0);
+ float linewidth = path->linewidth;
+ float expand = MAX(miterlength, linewidth) / 2.0;
+ r.min.x -= expand;
+ r.min.y -= expand;
+ r.max.x += expand;
+ r.max.y += expand;
+ }
+
+ return r;
+}
+
+void
+fz_debugpathnode(fz_pathnode *path)
+{
+ float x, y;
+ int i = 0;
+ while (i < path->len)
+ {
+ switch (path->els[i++].k)
+ {
+ case FZ_MOVETO:
+ x = path->els[i++].v;
+ y = path->els[i++].v;
+ printf("%g %g m\n", x, y);
+ break;
+ case FZ_LINETO:
+ x = path->els[i++].v;
+ y = path->els[i++].v;
+ printf("%g %g l\n", x, y);
+ break;
+ case FZ_CURVETO:
+ x = path->els[i++].v;
+ y = path->els[i++].v;
+ printf("%g %g ", x, y);
+ x = path->els[i++].v;
+ y = path->els[i++].v;
+ printf("%g %g ", x, y);
+ x = path->els[i++].v;
+ y = path->els[i++].v;
+ printf("%g %g c\n", x, y);
+ break;
+ case FZ_CLOSEPATH:
+ printf("h\n");
+ }
+ }
+
+ switch (path->paint)
+ {
+ case FZ_STROKE:
+ printf("S\n");
+ break;
+ case FZ_FILL:
+ printf("f\n");
+ break;
+ case FZ_EOFILL:
+ printf("f*\n");
+ break;
+ }
+}
+
+fz_error *
+fz_newdash(fz_dash **dashp, float phase, int len, float *array)
+{
+ fz_dash *dash;
+ int i;
+
+ dash = *dashp = fz_malloc(sizeof(fz_dash) + sizeof(float) * len);
+ if (!dash)
+ return fz_outofmem;
+
+ dash->len = len;
+ dash->phase = phase;
+ for (i = 0; i < len; i++)
+ dash->array[i] = array[i];
+
+ return nil;
+}
+
+void
+fz_dropdash(fz_dash *dash)
+{
+ fz_free(dash);
+}
+
diff --git a/base/node_text.c b/base/node_text.c
new file mode 100644
index 00000000..d88e04ec
--- /dev/null
+++ b/base/node_text.c
@@ -0,0 +1,141 @@
+#include <fitz.h>
+
+fz_error *
+fz_newtextnode(fz_textnode **textp, fz_font *font)
+{
+ fz_textnode *text;
+
+ text = fz_malloc(sizeof(fz_textnode));
+ if (!text)
+ return fz_outofmem;
+
+ fz_initnode((fz_node*)text, FZ_NTEXT);
+
+ text->font = fz_keepfont(font);
+ text->trm = fz_identity();
+ text->len = 0;
+ text->cap = 0;
+ text->els = nil;
+
+ *textp = text;
+ return nil;
+}
+
+fz_error *
+fz_clonetextnode(fz_textnode **textp, fz_textnode *oldtext)
+{
+ fz_textnode *text;
+
+ text = *textp = fz_malloc(sizeof(fz_textnode));
+ if (!text)
+ return fz_outofmem;
+
+ fz_initnode((fz_node*)text, FZ_NTEXT);
+
+ text->font = fz_keepfont(oldtext->font);
+ text->trm = oldtext->trm;
+ text->len = oldtext->len;
+ text->cap = oldtext->len;
+ text->els = nil;
+
+ text->els = fz_malloc(sizeof(fz_textel) * text->len);
+ if (!text->els)
+ {
+ fz_dropfont(text->font);
+ fz_free(text);
+ return fz_outofmem;
+ }
+
+ memcpy(text->els, oldtext->els, sizeof(fz_textel) * text->len);
+
+ *textp = text;
+ return nil;
+}
+
+void
+fz_droptextnode(fz_textnode *text)
+{
+ fz_dropfont(text->font);
+ fz_free(text->els);
+}
+
+fz_rect
+fz_boundtextnode(fz_textnode *text, fz_matrix ctm)
+{
+ fz_matrix trm;
+ fz_rect bbox;
+ fz_rect fbox;
+ int i;
+
+ if (text->len == 0)
+ return fz_emptyrect;
+
+ /* find bbox of glyph origins in ctm space */
+
+ bbox.min.x = bbox.max.x = text->els[0].x;
+ bbox.min.y = bbox.max.y = text->els[0].y;
+
+ for (i = 1; i < text->len; i++)
+ {
+ bbox.min.x = MIN(bbox.min.x, text->els[i].x);
+ bbox.min.y = MIN(bbox.min.y, text->els[i].y);
+ bbox.max.x = MAX(bbox.max.x, text->els[i].x);
+ bbox.max.y = MAX(bbox.max.y, text->els[i].y);
+ }
+
+ bbox = fz_transformaabb(ctm, bbox);
+
+ /* find bbox of font in trm * ctm space */
+
+ trm = fz_concat(text->trm, ctm);
+ trm.e = 0;
+ trm.f = 0;
+
+ fbox.min.x = text->font->bbox.min.x * 0.001;
+ fbox.min.y = text->font->bbox.min.y * 0.001;
+ fbox.max.x = text->font->bbox.max.x * 0.001;
+ fbox.max.y = text->font->bbox.max.y * 0.001;
+
+ fbox = fz_transformaabb(trm, fbox);
+
+ /* expand glyph origin bbox by font bbox */
+
+ bbox.min.x += fbox.min.x;
+ bbox.min.y += fbox.min.y;
+ bbox.max.x += fbox.max.x;
+ bbox.max.y += fbox.max.y;
+
+ return bbox;
+}
+
+static fz_error *
+growtext(fz_textnode *text, int n)
+{
+ int newcap;
+ fz_textel *newels;
+
+ while (text->len + n > text->cap)
+ {
+ newcap = text->cap + 36;
+ newels = fz_realloc(text->els, sizeof (fz_textel) * newcap);
+ if (!newels)
+ return fz_outofmem;
+ text->cap = newcap;
+ text->els = newels;
+ }
+
+ return nil;
+}
+
+fz_error *
+fz_addtext(fz_textnode *text, int cid, float x, float y)
+{
+ if (growtext(text, 1) != nil)
+ return fz_outofmem;
+ text->els[text->len].cid = cid;
+ text->els[text->len].x = x;
+ text->els[text->len].y = y;
+ text->len++;
+ return nil;
+}
+
diff --git a/base/node_tree.c b/base/node_tree.c
new file mode 100644
index 00000000..f6874711
--- /dev/null
+++ b/base/node_tree.c
@@ -0,0 +1,107 @@
+#include <fitz.h>
+
+fz_error *
+fz_newtree(fz_tree **treep)
+{
+ fz_tree *tree;
+
+ tree = *treep = fz_malloc(sizeof (fz_tree));
+ if (!tree)
+ return fz_outofmem;
+
+ tree->refs = 1;
+ tree->root = nil;
+ tree->head = nil;
+
+ return nil;
+}
+
+fz_tree *
+fz_keeptree(fz_tree *tree)
+{
+ tree->refs ++;
+ return tree;
+}
+
+void
+fz_droptree(fz_tree *tree)
+{
+ if (--tree->refs == 0)
+ {
+ if (tree->root)
+ fz_dropnode(tree->root);
+ fz_free(tree);
+ }
+}
+
+fz_rect
+fz_boundtree(fz_tree *tree, fz_matrix ctm)
+{
+ if (tree->root)
+ return fz_boundnode(tree->root, ctm);
+ return fz_emptyrect;
+}
+
+void
+fz_insertnodefirst(fz_node *parent, fz_node *child)
+{
+ child->parent = parent;
+ child->next = parent->first;
+ parent->first = child;
+ if (!parent->last)
+ parent->last = child;
+}
+
+void
+fz_insertnodelast(fz_node *parent, fz_node *child)
+{
+ child->parent = parent;
+ if (!parent->first)
+ parent->first = child;
+ else
+ parent->last->next = child;
+ parent->last = child;
+}
+
+void
+fz_insertnodeafter(fz_node *prev, fz_node *child)
+{
+ fz_node *parent = prev->parent;
+ child->parent = parent;
+ if (parent->last == prev)
+ parent->last = child;
+ child->next = prev->next;
+ prev->next = child;
+}
+
+void
+fz_removenode(fz_node *child)
+{
+ fz_node *parent = child->parent;
+ fz_node *prev;
+ fz_node *node;
+
+ if (parent->first == child)
+ {
+ parent->first = child->next;
+ if (parent->last == child)
+ parent->last = nil;
+ return;
+ }
+
+ prev = parent->first;
+ node = prev->next;
+
+ while (node)
+ {
+ if (node == child)
+ {
+ prev->next = child->next;
+ }
+ prev = node;
+ node = node->next;
+ }
+
+ parent->last = prev;
+}
+
diff --git a/base/res_cmap.c b/base/res_cmap.c
new file mode 100644
index 00000000..577ba7c0
--- /dev/null
+++ b/base/res_cmap.c
@@ -0,0 +1,466 @@
+#include <fitz.h>
+
+typedef struct fz_range_s fz_range;
+
+enum { MAXCODESPACE = 10 };
+enum { SINGLE, RANGE, LOOKUP };
+
+struct fz_range_s
+{
+ int low;
+ int high;
+ int flag;
+ int offset;
+};
+
+struct fz_cmap_s
+{
+ int refs;
+ char cmapname[32];
+
+ char usecmapname[32];
+ fz_cmap *usecmap;
+
+ int wmode;
+
+ int ncspace;
+ struct {
+ int n;
+ unsigned char lo[4];
+ unsigned char hi[4];
+ } cspace[MAXCODESPACE];
+
+ int rlen, rcap;
+ fz_range *ranges;
+
+ int tlen, tcap;
+ int *lookup;
+};
+
+fz_error *
+fz_newcmap(fz_cmap **cmapp)
+{
+ fz_cmap *cmap;
+
+ cmap = *cmapp = fz_malloc(sizeof(fz_cmap));
+ if (!cmap)
+ return fz_outofmem;
+
+ cmap->refs = 1;
+ strcpy(cmap->cmapname, "");
+
+ strcpy(cmap->usecmapname, "");
+ cmap->usecmap = nil;
+
+ cmap->wmode = 0;
+
+ cmap->ncspace = 0;
+
+ cmap->rlen = 0;
+ cmap->rcap = 0;
+ cmap->ranges = nil;
+
+ cmap->tlen = 0;
+ cmap->tcap = 0;
+ cmap->lookup = nil;
+
+ return nil;
+}
+
+fz_cmap *
+fz_keepcmap(fz_cmap *cmap)
+{
+ cmap->refs ++;
+ return cmap;
+}
+
+void
+fz_dropcmap(fz_cmap *cmap)
+{
+ if (--cmap->refs == 0)
+ {
+ if (cmap->usecmap)
+ fz_dropcmap(cmap->usecmap);
+ fz_free(cmap->ranges);
+ fz_free(cmap->lookup);
+ fz_free(cmap);
+ }
+}
+
+char *
+fz_getcmapname(fz_cmap *cmap)
+{
+ if (cmap->cmapname[0])
+ return cmap->cmapname;
+ return nil;
+}
+
+void
+fz_setcmapname(fz_cmap *cmap, char *cmapname)
+{
+ strlcpy(cmap->cmapname, cmapname, sizeof cmap->cmapname);
+}
+
+char *
+fz_getusecmapname(fz_cmap *cmap)
+{
+ if (cmap->usecmapname[0])
+ return cmap->usecmapname;
+ return nil;
+}
+
+void
+fz_setusecmapname(fz_cmap *cmap, char *usecmap)
+{
+ strlcpy(cmap->usecmapname, usecmap, sizeof cmap->usecmapname);
+}
+
+fz_cmap *
+fz_getusecmap(fz_cmap *cmap)
+{
+ return cmap->usecmap;
+}
+
+void
+fz_setusecmap(fz_cmap *cmap, fz_cmap *usecmap)
+{
+ int i;
+
+ if (cmap->usecmap)
+ fz_dropcmap(cmap->usecmap);
+ cmap->usecmap = fz_keepcmap(usecmap);
+
+ if (cmap->ncspace == 0)
+ {
+ cmap->ncspace = usecmap->ncspace;
+ for (i = 0; i < usecmap->ncspace; i++)
+ cmap->cspace[i] = usecmap->cspace[i];
+ }
+}
+
+void
+fz_setwmode(fz_cmap *cmap, int wmode)
+{
+ cmap->wmode = wmode;
+}
+
+int
+fz_getwmode(fz_cmap *cmap)
+{
+ return cmap->wmode;
+}
+
+fz_error *
+fz_addcodespacerange(fz_cmap *cmap, unsigned lo, unsigned hi, int n)
+{
+ int i;
+
+ if (cmap->ncspace + 1 == MAXCODESPACE)
+ return fz_throw("rangelimit: too many code space ranges");
+
+ cmap->cspace[cmap->ncspace].n = n;
+
+ for (i = 0; i < n; i++)
+ {
+ int o = (n - i - 1) * 8;
+ cmap->cspace[cmap->ncspace].lo[i] = (lo >> o) & 0xFF;
+ cmap->cspace[cmap->ncspace].hi[i] = (hi >> o) & 0xFF;
+ }
+
+ cmap->ncspace ++;
+
+ return nil;
+}
+
+fz_error *
+fz_addcidrange(fz_cmap *cmap, int low, int high, int offset)
+{
+ if (cmap->rlen + 1 > cmap->rcap)
+ {
+ fz_range *newranges;
+ int newcap = cmap->rcap == 0 ? 256 : cmap->rcap * 2;
+ newranges = fz_realloc(cmap->ranges, newcap * sizeof(fz_range));
+ if (!newranges)
+ return fz_outofmem;
+ cmap->rcap = newcap;
+ cmap->ranges = newranges;
+ }
+
+ cmap->ranges[cmap->rlen].low = low;
+ cmap->ranges[cmap->rlen].high = high;
+ cmap->ranges[cmap->rlen].flag = high - low == 0 ? SINGLE : RANGE;
+ cmap->ranges[cmap->rlen].offset = offset;
+ cmap->rlen ++;
+
+ return nil;
+}
+
+static fz_error *
+addlookup(fz_cmap *cmap, int value)
+{
+ if (cmap->tlen + 1 > cmap->tcap)
+ {
+ int newcap = cmap->tcap == 0 ? 256 : cmap->tcap * 2;
+ int *newlookup = fz_realloc(cmap->lookup, newcap * sizeof(int));
+ if (!newlookup)
+ return fz_outofmem;
+ cmap->tcap = newcap;
+ cmap->lookup = newlookup;
+ }
+
+ cmap->lookup[cmap->tlen++] = value;
+
+ return nil;
+}
+
+static int compare(const void *va, const void *vb)
+{
+ return ((const fz_range*)va)->low - ((const fz_range*)vb)->low;
+}
+
+fz_error *
+fz_endcidrange(fz_cmap *cmap)
+{
+ fz_error *error;
+ fz_range *newranges;
+ int *newlookup;
+ fz_range *a; /* last written range on output */
+ fz_range *b; /* current range examined on input */
+
+ qsort(cmap->ranges, cmap->rlen, sizeof(fz_range), compare);
+
+ a = cmap->ranges;
+ b = cmap->ranges + 1;
+
+ while (b < cmap->ranges + cmap->rlen)
+ {
+ /* input contiguous */
+ if (a->high + 1 == b->low)
+ {
+ /* output contiguous */
+ if (a->high - a->low + a->offset + 1 == b->offset)
+ {
+ /* SR -> R and SS -> R and RR -> R and RS -> R */
+ if (a->flag == SINGLE || a->flag == RANGE)
+ {
+ a->flag = RANGE;
+ a->high = b->high;
+ }
+
+ /* LS -> L */
+ else if (a->flag == LOOKUP && b->flag == SINGLE)
+ {
+ a->high = b->high;
+ error = addlookup(cmap, b->offset);
+ if (error)
+ return error;
+ }
+
+ /* LR -> LR */
+ else if (a->flag == LOOKUP && b->flag == RANGE)
+ {
+ *(++a) = *b;
+ }
+ }
+
+ /* output separated */
+ else
+ {
+ /* SS -> L */
+ if (a->flag == SINGLE && b->flag == SINGLE)
+ {
+ a->flag = LOOKUP;
+ a->high = b->high;
+
+ error = addlookup(cmap, a->offset);
+ if (error)
+ return error;
+
+ error = addlookup(cmap, b->offset);
+ if (error)
+ return error;
+
+ a->offset = cmap->tlen - 2;
+ }
+
+ /* LS -> L */
+ else if (a->flag == LOOKUP && b->flag == SINGLE)
+ {
+ a->high = b->high;
+ error = addlookup(cmap, b->offset);
+ if (error)
+ return error;
+ }
+
+ /* XX -> XX */
+ else
+ {
+ *(++a) = *b;
+ }
+ }
+ }
+
+ /* input separated: XX -> XX */
+ else
+ {
+ *(++a) = *b;
+ }
+
+ b ++;
+ }
+
+ cmap->rlen = a - cmap->ranges + 1;
+
+ assert(cmap->rlen > 0);
+
+ newranges = fz_realloc(cmap->ranges, cmap->rlen * sizeof(fz_range));
+ if (!newranges)
+ return fz_outofmem;
+ cmap->rcap = cmap->rlen;
+ cmap->ranges = newranges;
+
+ if (cmap->tlen)
+ {
+ newlookup = fz_realloc(cmap->lookup, cmap->tlen * sizeof(int));
+ if (!newlookup)
+ return fz_outofmem;
+ cmap->tcap = cmap->tlen;
+ cmap->lookup = newlookup;
+ }
+
+ return nil;
+}
+
+fz_error *
+fz_setcidlookup(fz_cmap *cmap, int map[256])
+{
+ int i;
+
+ cmap->rlen = cmap->rcap = 1;
+ cmap->ranges = fz_malloc(sizeof (fz_range));
+ if (!cmap->ranges) {
+ return fz_outofmem;
+ }
+
+ cmap->tlen = cmap->tcap = 256;
+ cmap->lookup = fz_malloc(sizeof (int) * 256);
+ if (!cmap->lookup) {
+ fz_free(cmap->ranges);
+ return fz_outofmem;
+ }
+
+ cmap->ranges[0].low = 0;
+ cmap->ranges[0].high = 255;
+ cmap->ranges[0].flag = LOOKUP;
+ cmap->ranges[0].offset = 0;
+
+ for (i = 0; i < 256; i++)
+ cmap->lookup[i] = map[i];
+
+ return nil;
+}
+
+int
+fz_lookupcid(fz_cmap *cmap, int cpt)
+{
+ int l = 0;
+ int r = cmap->rlen - 1;
+ int m;
+
+ while (l <= r)
+ {
+ m = (l + r) >> 1;
+ if (cpt < cmap->ranges[m].low)
+ r = m - 1;
+ else if (cpt > cmap->ranges[m].high)
+ l = m + 1;
+ else
+ {
+ int i = cpt - cmap->ranges[m].low + cmap->ranges[m].offset;
+ if (cmap->ranges[m].flag == LOOKUP)
+ return cmap->lookup[i];
+ return i;
+ }
+ }
+
+ if (cmap->usecmap)
+ return fz_lookupcid(cmap->usecmap, cpt);
+
+ return -1;
+}
+
+unsigned char *
+fz_decodecpt(fz_cmap *cmap, unsigned char *buf, int *cpt)
+{
+ int i, k;
+
+ for (k = 0; k < cmap->ncspace; k++)
+ {
+ unsigned char *lo = cmap->cspace[k].lo;
+ unsigned char *hi = cmap->cspace[k].hi;
+ int n = cmap->cspace[k].n;
+ int c = 0;
+
+ for (i = 0; i < n; i++)
+ {
+ if (lo[i] <= buf[i] && buf[i] <= hi[i])
+ c = (c << 8) | buf[i];
+ else
+ break;
+ }
+
+ if (i == n) {
+ *cpt = c;
+ return buf + n;
+ }
+ }
+
+ *cpt = 0;
+ return buf + 1;
+}
+
+void
+fz_debugcmap(fz_cmap *cmap)
+{
+ int i, k;
+
+ printf("cmap $%p /%s {\n", cmap, cmap->cmapname);
+
+ if (cmap->usecmapname[0])
+ printf(" usecmap /%s\n", cmap->usecmapname);
+ if (cmap->usecmap)
+ printf(" usecmap $%p\n", cmap->usecmap);
+
+ printf(" wmode %d\n", cmap->wmode);
+
+ printf(" codespaces {\n");
+ for (i = 0; i < cmap->ncspace; i++)
+ {
+ printf(" <");
+ for (k = 0; k < cmap->cspace[i].n; k++)
+ printf("%02x", cmap->cspace[i].lo[k]);
+ printf("> <");
+ for (k = 0; k < cmap->cspace[i].n; k++)
+ printf("%02x", cmap->cspace[i].hi[k]);
+ printf(">\n");
+ }
+ printf(" }\n");
+
+ printf(" ranges (%d,%d) {\n", cmap->rlen, cmap->tlen);
+ for (i = 0; i < cmap->rlen; i++)
+ {
+ fz_range *r = &cmap->ranges[i];
+ printf(" <%04x> <%04x> ", r->low, r->high);
+ if (r->flag == LOOKUP)
+ {
+ printf("[ ");
+ for (k = 0; k < r->high - r->low + 1; k++)
+ printf("%d ", cmap->lookup[r->offset + k]);
+ printf("]\n");
+ }
+ else
+ printf("%d\n", r->offset);
+ }
+ printf(" }\n}\n");
+}
+
diff --git a/base/res_colorspace.c b/base/res_colorspace.c
new file mode 100644
index 00000000..65909bfe
--- /dev/null
+++ b/base/res_colorspace.c
@@ -0,0 +1,89 @@
+#include <fitz.h>
+
+void
+fz_convertpixmap(fz_colorspace *srcs, fz_pixmap *src, fz_colorspace *dsts, fz_pixmap *dst)
+{
+ srcs->convpixmap(srcs, src, dsts, dst);
+}
+
+void
+fz_convertcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv)
+{
+ srcs->convcolor(srcs, srcv, dsts, dstv);
+}
+
+fz_colorspace *
+fz_keepcolorspace(fz_colorspace *cs)
+{
+ if (cs->refs < 0)
+ return cs;
+ cs->refs ++;
+ return cs;
+}
+
+void
+fz_dropcolorspace(fz_colorspace *cs)
+{
+ if (cs->refs < 0)
+ return;
+ if (--cs->refs == 0)
+ {
+ if (cs->drop)
+ cs->drop(cs);
+ fz_free(cs);
+ }
+}
+
+void
+fz_stdconvcolor(fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv)
+{
+ float xyz[3];
+ int i;
+
+ if (srcs != dsts)
+ {
+ srcs->toxyz(srcs, srcv, xyz);
+ dsts->fromxyz(dsts, xyz, dstv);
+ for (i = 0; i < dsts->n; i++)
+ dstv[i] = CLAMP(dstv[i], 0.0, 1.0);
+ }
+ else
+ {
+ for (i = 0; i < srcs->n; i++)
+ dstv[i] = srcv[i];
+ }
+}
+
+void
+fz_stdconvpixmap(fz_colorspace *srcs, fz_pixmap *src, fz_colorspace *dsts, fz_pixmap *dst)
+{
+ float srcv[FZ_MAXCOLORS];
+ float dstv[FZ_MAXCOLORS];
+ int y, x, k;
+
+ unsigned char *s = src->samples;
+ unsigned char *d = dst->samples;
+
+ printf("convert pixmap from %s to %s\n", srcs->name, dsts->name);
+
+ assert(src->w == dst->w && src->h == dst->h);
+ assert(src->n == srcs->n + 1);
+ assert(dst->n == dsts->n + 1);
+
+ for (y = 0; y < src->h; y++)
+ {
+ for (x = 0; x < src->w; x++)
+ {
+ *d++ = *s++;
+
+ for (k = 0; k < src->n - 1; k++)
+ srcv[k] = *s++ / 255.0;
+
+ fz_convertcolor(srcs, srcv, dsts, dstv);
+
+ for (k = 0; k < dst->n - 1; k++)
+ *d++ = dstv[k] * 255;
+ }
+ }
+}
+
diff --git a/base/res_font.c b/base/res_font.c
new file mode 100644
index 00000000..b7367ce1
--- /dev/null
+++ b/base/res_font.c
@@ -0,0 +1,269 @@
+#include <fitz.h>
+
+void
+fz_initfont(fz_font *font, char *name)
+{
+ font->refs = 1;
+ strlcpy(font->name, name, sizeof font->name);
+
+ font->wmode = 0;
+
+ font->bbox.min.x = 0;
+ font->bbox.min.y = 0;
+ font->bbox.max.x = 1000;
+ font->bbox.max.y = 1000;
+
+ font->hmtxcap = 0;
+ font->vmtxcap = 0;
+ font->nhmtx = 0;
+ font->nvmtx = 0;
+ font->hmtx = nil;
+ font->vmtx = nil;
+
+ font->dhmtx.lo = 0x0000;
+ font->dhmtx.hi = 0xFFFF;
+ font->dhmtx.w = 0;
+
+ font->dvmtx.lo = 0x0000;
+ font->dvmtx.hi = 0xFFFF;
+ font->dvmtx.x = 0;
+ font->dvmtx.y = 880;
+ font->dvmtx.w = -1000;
+}
+
+fz_font *
+fz_keepfont(fz_font *font)
+{
+ font->refs ++;
+ return font;
+}
+
+void
+fz_dropfont(fz_font *font)
+{
+ if (--font->refs == 0)
+ {
+ if (font->drop)
+ font->drop(font);
+ fz_free(font->hmtx);
+ fz_free(font->vmtx);
+ fz_free(font);
+ }
+}
+
+void
+fz_setfontwmode(fz_font *font, int wmode)
+{
+ font->wmode = wmode;
+}
+
+void
+fz_setfontbbox(fz_font *font, int xmin, int ymin, int xmax, int ymax)
+{
+ font->bbox.min.x = xmin;
+ font->bbox.min.y = ymin;
+ font->bbox.max.x = xmax;
+ font->bbox.max.y = ymax;
+}
+
+void
+fz_setdefaulthmtx(fz_font *font, int w)
+{
+ font->dhmtx.w = w;
+}
+
+void
+fz_setdefaultvmtx(fz_font *font, int y, int w)
+{
+ font->dvmtx.y = y;
+ font->dvmtx.w = w;
+}
+
+fz_error *
+fz_addhmtx(fz_font *font, int lo, int hi, int w)
+{
+ int newcap;
+ fz_hmtx *newmtx;
+
+ if (font->nhmtx + 1 >= font->hmtxcap)
+ {
+ newcap = font->hmtxcap + 16;
+ newmtx = fz_realloc(font->hmtx, sizeof(fz_hmtx) * newcap);
+ if (!newmtx)
+ return fz_outofmem;
+ font->hmtxcap = newcap;
+ font->hmtx = newmtx;
+ }
+
+ font->hmtx[font->nhmtx].lo = lo;
+ font->hmtx[font->nhmtx].hi = hi;
+ font->hmtx[font->nhmtx].w = w;
+ font->nhmtx++;
+
+ return nil;
+}
+
+fz_error *
+fz_addvmtx(fz_font *font, int lo, int hi, int x, int y, int w)
+{
+ int newcap;
+ fz_vmtx *newmtx;
+
+ if (font->nvmtx + 1 >= font->vmtxcap)
+ {
+ newcap = font->vmtxcap + 16;
+ newmtx = fz_realloc(font->vmtx, sizeof(fz_vmtx) * newcap);
+ if (!newmtx)
+ return fz_outofmem;
+ font->vmtxcap = newcap;
+ font->vmtx = newmtx;
+ }
+
+ font->vmtx[font->nvmtx].lo = lo;
+ font->vmtx[font->nvmtx].hi = hi;
+ font->vmtx[font->nvmtx].x = x;
+ font->vmtx[font->nvmtx].y = y;
+ font->vmtx[font->nvmtx].w = w;
+ font->nvmtx++;
+
+ return nil;
+}
+
+static int cmph(const void *a0, const void *b0)
+{
+ fz_hmtx *a = (fz_hmtx*)a0;
+ fz_hmtx *b = (fz_hmtx*)b0;
+ return a->lo - b->lo;
+}
+
+static int cmpv(const void *a0, const void *b0)
+{
+ fz_vmtx *a = (fz_vmtx*)a0;
+ fz_vmtx *b = (fz_vmtx*)b0;
+ return a->lo - b->lo;
+}
+
+fz_error *
+fz_endhmtx(fz_font *font)
+{
+ fz_hmtx *newmtx;
+
+ if (!font->hmtx)
+ return nil;
+
+ qsort(font->hmtx, font->nhmtx, sizeof(fz_hmtx), cmph);
+
+ newmtx = fz_realloc(font->hmtx, sizeof(fz_hmtx) * font->nhmtx);
+ if (!newmtx)
+ return fz_outofmem;
+ font->hmtxcap = font->nhmtx;
+ font->hmtx = newmtx;
+
+ return nil;
+}
+
+fz_error *
+fz_endvmtx(fz_font *font)
+{
+ fz_vmtx *newmtx;
+
+ if (!font->vmtx)
+ return nil;
+
+ qsort(font->vmtx, font->nvmtx, sizeof(fz_vmtx), cmpv);
+
+ newmtx = fz_realloc(font->vmtx, sizeof(fz_vmtx) * font->nvmtx);
+ if (!newmtx)
+ return fz_outofmem;
+ font->vmtxcap = font->nvmtx;
+ font->vmtx = newmtx;
+
+ return nil;
+}
+
+fz_hmtx
+fz_gethmtx(fz_font *font, int cid)
+{
+ int l = 0;
+ int r = font->nhmtx - 1;
+ int m;
+
+ if (!font->hmtx)
+ goto notfound;
+
+ while (l <= r)
+ {
+ m = (l + r) >> 1;
+ if (cid < font->hmtx[m].lo)
+ r = m - 1;
+ else if (cid > font->hmtx[m].hi)
+ l = m + 1;
+ else
+ return font->hmtx[m];
+ }
+
+notfound:
+ return font->dhmtx;
+}
+
+fz_vmtx
+fz_getvmtx(fz_font *font, int cid)
+{
+ fz_hmtx h;
+ fz_vmtx v;
+ int l = 0;
+ int r = font->nvmtx - 1;
+ int m;
+
+ if (!font->vmtx)
+ goto notfound;
+
+ while (l <= r)
+ {
+ m = (l + r) >> 1;
+ if (cid < font->vmtx[m].lo)
+ r = m - 1;
+ else if (cid > font->vmtx[m].hi)
+ l = m + 1;
+ else
+ return font->vmtx[m];
+ }
+
+notfound:
+ h = fz_gethmtx(font, cid);
+ v = font->dvmtx;
+ v.x = h.w / 2;
+ return v;
+}
+
+void
+fz_debugfont(fz_font *font)
+{
+ int i;
+
+ printf("font '%s' {\n", font->name);
+ printf(" wmode %d\n", font->wmode);
+ printf(" bbox [%d %d %d %d]\n",
+ font->bbox.min.x, font->bbox.min.y,
+ font->bbox.max.x, font->bbox.max.y);
+ printf(" DW %d\n", font->dhmtx.w);
+
+ printf(" W {\n");
+ for (i = 0; i < font->nhmtx; i++)
+ printf(" <%04x> <%04x> %d\n",
+ font->hmtx[i].lo, font->hmtx[i].hi, font->hmtx[i].w);
+ printf(" }\n");
+
+ if (font->wmode)
+ {
+ printf(" DW2 [%d %d]\n", font->dvmtx.y, font->dvmtx.w);
+ printf(" W2 {\n");
+ for (i = 0; i < font->nvmtx; i++)
+ printf(" <%04x> <%04x> %d %d %d\n", font->vmtx[i].lo, font->vmtx[i].hi,
+ font->vmtx[i].x, font->vmtx[i].y, font->vmtx[i].w);
+ printf(" }\n");
+ }
+
+ printf("}\n");
+}
+
diff --git a/base/res_image.c b/base/res_image.c
new file mode 100644
index 00000000..dbeb1fd8
--- /dev/null
+++ b/base/res_image.c
@@ -0,0 +1,22 @@
+#include <fitz.h>
+
+fz_image *
+fz_keepimage(fz_image *image)
+{
+ image->refs ++;
+ return image;
+}
+
+void
+fz_dropimage(fz_image *image)
+{
+ if (--image->refs == 0)
+ {
+ if (image->drop)
+ image->drop(image);
+ if (image->cs)
+ fz_dropcolorspace(image->cs);
+ fz_free(image);
+ }
+}
+
diff --git a/base/res_shade.c b/base/res_shade.c
new file mode 100644
index 00000000..67a64e4e
--- /dev/null
+++ b/base/res_shade.c
@@ -0,0 +1,28 @@
+#include <fitz.h>
+
+fz_shade *
+fz_keepshade(fz_shade *shade)
+{
+ shade->refs ++;
+ return shade;
+}
+
+void
+fz_dropshade(fz_shade *shade)
+{
+ if (--shade->refs == 0)
+ {
+ if (shade->cs)
+ fz_dropcolorspace(shade->cs);
+ fz_free(shade->mesh);
+ fz_free(shade);
+ }
+}
+
+fz_rect
+fz_boundshade(fz_shade *shade, fz_matrix ctm)
+{
+ ctm = fz_concat(shade->matrix, ctm);
+ return fz_transformaabb(ctm, shade->bbox);
+}
+
diff --git a/base/util_getopt.c b/base/util_getopt.c
new file mode 100644
index 00000000..c870e206
--- /dev/null
+++ b/base/util_getopt.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 4.13 (Berkeley) 2/23/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * get option letter from argument vector
+ */
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt; /* character checked for validity */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define EMSG ""
+
+int getopt(int nargc, char * const * nargv, const char *ostr)
+{
+ static char *place = EMSG; /* option letter processing */
+ register char *oli; /* option letter list index */
+ char *p;
+
+ if (!*place) { /* update scanning pointer */
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return(EOF);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ ++optind;
+ place = EMSG;
+ return(EOF);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means EOF.
+ */
+ if (optopt == (int)'-')
+ return(EOF);
+ if (!*place)
+ ++optind;
+ if (opterr) {
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ (void)fprintf(stderr, "%s: illegal option -- %c\n",
+ p, optopt);
+ }
+ return(BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ p, optopt);
+ return(BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return(optopt); /* dump back option letter */
+}
diff --git a/base/util_strlcat.c b/base/util_strlcat.c
new file mode 100644
index 00000000..c659b73a
--- /dev/null
+++ b/base/util_strlcat.c
@@ -0,0 +1,35 @@
+/* Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+
+#include <string.h>
+
+int strlcat(char *dst, const char *src, int siz)
+{
+ register char *d = dst;
+ register const char *s = src;
+ register int n = siz;
+ int dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (*d != '\0' && n-- != 0)
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return dlen + strlen(s);
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return dlen + (s - src); /* count does not include NUL */
+}
+
diff --git a/base/util_strlcpy.c b/base/util_strlcpy.c
new file mode 100644
index 00000000..73416ae1
--- /dev/null
+++ b/base/util_strlcpy.c
@@ -0,0 +1,32 @@
+/* Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+
+#include <string.h>
+
+int strlcpy(char *dst, const char *src, int siz)
+{
+ register char *d = dst;
+ register const char *s = src;
+ register int n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
diff --git a/base/util_strsep.c b/base/util_strsep.c
new file mode 100644
index 00000000..e54903ce
--- /dev/null
+++ b/base/util_strsep.c
@@ -0,0 +1,11 @@
+#include <string.h>
+
+char *strsep(char **stringp, const char *delim)
+{
+ char *ret = *stringp;
+ if (ret == NULL) return NULL;
+ if ((*stringp = strpbrk(*stringp, delim)) != NULL)
+ *((*stringp)++) = '\0';
+ return ret;
+}
+