From ded124f1cc463bac9e076146a4ffb77b8a370e0c Mon Sep 17 00:00:00 2001
From: Tor Andersson <tor@ghostscript.com>
Date: Thu, 21 Oct 2004 10:51:08 +0200
Subject: rewrote resource dict handling

---
 Jamfile                 |   4 +-
 include/fitz.h          |   4 +-
 include/fitz/image.h    |  10 ++
 include/fitz/scanconv.h |   2 +-
 include/fitz/tree.h     |  11 +-
 mupdf/build.c           |  58 +++++++-
 mupdf/colorspace.c      |   6 +
 mupdf/font.c            |   1 +
 mupdf/image.c           |  54 +++++++
 mupdf/interpret.c       | 131 +++++++++++------
 mupdf/open.c            |   3 +-
 mupdf/page.c            |  22 +--
 mupdf/repair.c          |   3 +-
 mupdf/resources.c       | 376 +++++++++++++++++++++++++++++++++++++-----------
 mupdf/xref.c            |   3 +-
 render/render.c         |  14 +-
 render/renderimage.c    |  59 ++++++++
 render/renderpath.c     |  53 ++++---
 render/rendertext.c     |   8 +-
 render/scanconv.c       |  30 ++--
 test/pdfrip.c           |  15 +-
 tree/debug.c            |   5 +-
 tree/font.c             |   1 +
 tree/node2.c            |  24 ++--
 tree/text.c             |  64 ++++++++-
 25 files changed, 740 insertions(+), 221 deletions(-)
 create mode 100644 include/fitz/image.h
 create mode 100644 mupdf/image.c
 create mode 100644 render/renderimage.c

diff --git a/Jamfile b/Jamfile
index 80219171..3ce33eab 100644
--- a/Jamfile
+++ b/Jamfile
@@ -82,8 +82,9 @@ Library libfitz :
 	render/fill.c
 	render/stroke.c
 	render/render.c
-	render/renderpath.c
 	render/rendertext.c
+	render/renderpath.c
+	render/renderimage.c
 ;
 
 Library libmupdf :
@@ -103,6 +104,7 @@ Library libmupdf :
 	mupdf/font.c
 	mupdf/fontfile.c
 	mupdf/colorspace.c
+	mupdf/image.c
 	mupdf/resources.c
 	mupdf/page.c
 	mupdf/pagetree.c
diff --git a/include/fitz.h b/include/fitz.h
index 85ac8118..48754391 100644
--- a/include/fitz.h
+++ b/include/fitz.h
@@ -18,13 +18,15 @@
 
 #include "fitz/cmap.h"
 #include "fitz/font.h"
+
 #include "fitz/colorspace.h"
+#include "fitz/pixmap.h"
+#include "fitz/image.h"
 
 #include "fitz/tree.h"
 #include "fitz/path.h"
 #include "fitz/text.h"
 
-#include "fitz/pixmap.h"
 #include "fitz/scanconv.h"
 #include "fitz/render.h"
 
diff --git a/include/fitz/image.h b/include/fitz/image.h
new file mode 100644
index 00000000..0ff954c5
--- /dev/null
+++ b/include/fitz/image.h
@@ -0,0 +1,10 @@
+typedef struct fz_image_s fz_image;
+
+struct fz_image_s
+{
+	fz_error* (*loadtile)(fz_image*,fz_pixmap*);
+	void (*free)(fz_image*);
+	fz_colorspace *cs;
+	int w, h, n, a;
+};
+
diff --git a/include/fitz/scanconv.h b/include/fitz/scanconv.h
index 794b9ba2..057153c4 100644
--- a/include/fitz/scanconv.h
+++ b/include/fitz/scanconv.h
@@ -39,7 +39,7 @@ void fz_advanceael(fz_ael *ael);
 void fz_freeael(fz_ael *ael);
 
 fz_error *fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, int y0, int y1,
-	void (*blitfunc)(int,int,int,short*,void*), void *blitdata);
+	void (*blitfunc)(int,int,int,unsigned char*,void*), void *blitdata);
 
 fz_error *fz_fillpath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness);
 fz_error *fz_strokepath(fz_gel *gel, fz_pathnode *path, fz_matrix ctm, float flatness);
diff --git a/include/fitz/tree.h b/include/fitz/tree.h
index 6578ab51..7181ac9b 100644
--- a/include/fitz/tree.h
+++ b/include/fitz/tree.h
@@ -125,15 +125,14 @@ struct fz_linknode_s
 struct fz_metanode_s
 {
 	fz_node super;
-	fz_obj *info;
+	fz_obj *name;
+	fz_obj *dict;
 };
 
 struct fz_imagenode_s
 {
 	fz_node super;
-	fz_colorspace *cs;
-	int w, h, n, a;
-	// XXX fz_image *image;
+	fz_image *image;
 };
 
 /* common to all nodes */
@@ -142,7 +141,7 @@ fz_rect fz_boundnode(fz_node *node, fz_matrix ctm);
 void fz_freenode(fz_node *node);
 
 /* branch nodes */
-fz_error *fz_newmetanode(fz_node **nodep, fz_obj *info);
+fz_error *fz_newmetanode(fz_node **nodep, fz_obj *name, fz_obj *dict);
 fz_error *fz_newovernode(fz_node **nodep);
 fz_error *fz_newmasknode(fz_node **nodep);
 fz_error *fz_newblendnode(fz_node **nodep, fz_colorspace *cs, fz_blendkind b, int k, int i);
@@ -157,7 +156,7 @@ int fz_ismetanode(fz_node *node);
 /* leaf nodes */
 fz_error *fz_newlinknode(fz_node **nodep, fz_tree *subtree);
 fz_error *fz_newcolornode(fz_node **nodep, fz_colorspace *cs, int n, float *v);
-fz_error *fz_newimagenode(fz_node **nodep, fz_colorspace *cs, int w, int h, int n, int a);
+fz_error *fz_newimagenode(fz_node **nodep, fz_image *image);
 
 int fz_islinknode(fz_node *node);
 int fz_iscolornode(fz_node *node);
diff --git a/mupdf/build.c b/mupdf/build.c
index 5747b962..d235c9bc 100644
--- a/mupdf/build.c
+++ b/mupdf/build.c
@@ -1,8 +1,6 @@
 #include <fitz.h>
 #include <mupdf.h>
 
-extern int FT_Get_Char_Index(void*, int);
-
 void
 pdf_initgstate(pdf_gstate *gs)
 {
@@ -137,6 +135,62 @@ pdf_addtransform(pdf_gstate *gs, fz_node *transform)
 	return nil;
 }
 
+#if 0
+
+BMC ... EMC object nesting can be completely fucked up
+and out of sync with graphics object nesting.
+
+fz_error *
+pdf_beginmarkedcontent(pdf_gstate *gs, fz_node *meta)
+{
+	fz_error *error;
+	fz_node *over;
+
+	error = fz_newovernode(&over);
+	if (error) return error;
+
+	fz_insertnode(gs->head, meta);
+	fz_insertnode(meta, over);
+	gs->head = over;
+
+printf("begin mc meta=%p over=%p\n", meta, over);
+{
+fz_node *node = gs->head;
+	while (node)
+	{
+printf("  node=%p ismeta=%d\n", node, fz_ismetanode(node));
+		node = node->parent;
+	}
+printf("okay.\n");
+}
+
+	return nil;
+}
+
+fz_error *
+pdf_endmarkedcontent(pdf_gstate *gs)
+{
+	fz_node *node = gs->head;
+
+printf("end mc\n");
+printf("  node=%p ismeta=%d\n", node, fz_ismetanode(node));
+
+	while (node && !fz_ismetanode(node))
+	{
+printf("  node=%p ismeta=%d\n", node, fz_ismetanode(node));
+		node = node->parent;
+	}
+
+	if (node == nil)
+		return fz_throw("syntaxerror: unbalanced marked content");
+
+	gs->head = node->parent;
+
+	return nil;
+}
+
+#endif
+
 fz_error *
 pdf_showpath(pdf_csi *csi,
 	int doclose, int dofill, int dostroke, int evenodd)
diff --git a/mupdf/colorspace.c b/mupdf/colorspace.c
index 05a4535c..3511dc91 100644
--- a/mupdf/colorspace.c
+++ b/mupdf/colorspace.c
@@ -530,6 +530,12 @@ printf("\n");
 			{
 				return loadiccbased(csp, xref, fz_arrayget(obj, 1));
 			}
+
+			if (!strcmp(fz_toname(name), "Separation"))
+			{
+				*csp = pdf_devicegray;
+				return nil;
+			}
 		}
 	}
 
diff --git a/mupdf/font.c b/mupdf/font.c
index c7ff3eb9..562eb5ba 100644
--- a/mupdf/font.c
+++ b/mupdf/font.c
@@ -94,6 +94,7 @@ ftrender(fz_glyph *glyph, fz_font *fzfont, int cid, fz_matrix trm)
 	FT_Set_Transform(face, &m, &v);
 
 	fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
+	//fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP);
 	if (fterr)
 		return fz_throw("freetype failed to load glyph: 0x%x", fterr);
 
diff --git a/mupdf/image.c b/mupdf/image.c
new file mode 100644
index 00000000..00e6171b
--- /dev/null
+++ b/mupdf/image.c
@@ -0,0 +1,54 @@
+#include <fitz.h>
+#include <mupdf.h>
+
+static fz_error *loadtile(fz_image *fzimg, fz_pixmap *tile)
+{
+	return nil;
+}
+
+fz_error *
+pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *dict)
+{
+	fz_error *error;
+	pdf_image *img;
+	fz_colorspace *cs;
+	int ismask;
+	fz_obj *obj;
+
+	img = fz_malloc(sizeof(pdf_image));
+	if (!img)
+		return fz_outofmem;
+
+	img->super.loadtile = loadtile;
+	img->super.free = nil;
+	img->super.cs = nil;
+
+	img->super.w = fz_toint(fz_dictgets(dict, "Width"));
+	img->super.h = fz_toint(fz_dictgets(dict, "Height"));
+	img->bpc = fz_toint(fz_dictgets(dict, "BitsPerComponent"));
+
+	cs = nil;
+	obj = fz_dictgets(dict, "ColorSpace");
+	if (obj)
+		error = pdf_loadcolorspace(&cs, xref, obj);
+
+	ismask = fz_tobool(fz_dictgets(dict, "ImageMask"));
+
+	if (!ismask)
+	{
+		img->super.cs = cs;
+		img->super.n = cs->n;
+		img->super.a = 0;
+	}
+	else
+	{
+		img->super.cs = nil;
+		img->super.n = 0;
+		img->super.a = 1;
+	}
+
+	*imgp = img;
+
+	return nil;
+}
+
diff --git a/mupdf/interpret.c b/mupdf/interpret.c
index fdf367b5..f9179792 100644
--- a/mupdf/interpret.c
+++ b/mupdf/interpret.c
@@ -1,20 +1,6 @@
 #include <fitz.h>
 #include <mupdf.h>
 
-void pdf_initgstate(pdf_gstate *gs);
-
-fz_error *pdf_buildstrokepath(pdf_gstate *gs, fz_pathnode *path);
-fz_error *pdf_buildfillpath(pdf_gstate *gs, fz_pathnode *path, int evenodd);
-
-fz_error *pdf_addfillshape(pdf_gstate *gs, fz_node *shape);
-fz_error *pdf_addstrokeshape(pdf_gstate *gs, fz_node *shape);
-fz_error *pdf_addclipmask(pdf_gstate *gs, fz_node *shape);
-fz_error *pdf_addtransform(pdf_gstate *gs, fz_node *transform);
-
-fz_error *pdf_showpath(pdf_csi *, int doclose, int dofill, int dostroke, int evenodd);
-fz_error *pdf_showtext(pdf_csi *, fz_obj *text);
-fz_error *pdf_flushtext(pdf_csi *);
-
 fz_error *
 pdf_newcsi(pdf_csi **csip)
 {
@@ -51,8 +37,8 @@ pdf_newcsi(pdf_csi **csip)
 	csi->tree->root = node;
 	csi->gstate[0].head = node;
 
-	error = fz_newcolornode(&node, pdf_devicegray, 1, &white);
-	fz_insertnode(csi->tree->root, node);
+//	error = fz_newcolornode(&node, pdf_devicegray, 1, &white);
+//	fz_insertnode(csi->tree->root, node);
 
 	csi->clip = nil;
 
@@ -83,9 +69,8 @@ pdf_freecsi(pdf_csi *csi)
 }
 
 static fz_error *
-runextgstate(pdf_gstate *gstate, pdf_resources *rdb, fz_obj *extgstate)
+runextgstate(pdf_gstate *gstate, pdf_xref *xref, fz_obj *extgstate)
 {
-	char name[64];
 	int i, k;
 
 	for (i = 0; i < fz_dictlen(extgstate); i++)
@@ -98,13 +83,9 @@ runextgstate(pdf_gstate *gstate, pdf_resources *rdb, fz_obj *extgstate)
 		{
 			if (fz_isarray(val) && fz_arraylen(val) == 2)
 			{
-				fz_obj *ref, *obj;
-				ref = fz_arrayget(val, 0);
-				sprintf(name, "$f.%d.%d", fz_tonum(ref), fz_togen(ref));
-				obj = fz_dictgets(rdb->font, name);
-				if (!obj)
-					return fz_throw("syntaxerror: missing resource");
-				gstate->font = fz_topointer(obj);
+				gstate->font = pdf_findresource(xref->rfont, fz_arrayget(val, 0));
+				if (!gstate->font)
+					return fz_throw("syntaxerror: missing font resource");
 				gstate->size = fz_toreal(fz_arrayget(val, 1));
 			}
 			else
@@ -139,7 +120,7 @@ runextgstate(pdf_gstate *gstate, pdf_resources *rdb, fz_obj *extgstate)
 }
 
 static fz_error *
-runkeyword(pdf_csi *csi, pdf_resources *rdb, char *buf)
+runkeyword(pdf_csi *csi, pdf_xref *xref, fz_obj *rdb, char *buf)
 {
 	pdf_gstate *gstate = csi->gstate + csi->gtop;
 	fz_error *error;
@@ -169,7 +150,7 @@ runkeyword(pdf_csi *csi, pdf_resources *rdb, char *buf)
 			fz_node *meta;
 			if (csi->top != 1)
 				goto syntaxerror;
-			error = fz_newmetanode(&meta, csi->stack[0]);
+			error = fz_newmetanode(&meta, csi->stack[0], nil);
 			if (error) return error;
 			fz_insertnode(gstate->head, meta);
 		}
@@ -177,18 +158,43 @@ runkeyword(pdf_csi *csi, pdf_resources *rdb, char *buf)
 		else if (!strcmp(buf, "DP"))
 		{
 			fz_node *meta;
-			fz_obj *info;
 			if (csi->top != 2)
 				goto syntaxerror;
-			error = fz_packobj(&info, "<< %o %o >>",
-						csi->stack[0], csi->stack[1]);
+			error = fz_newmetanode(&meta, csi->stack[0], csi->stack[1]);
 			if (error) return error;
-			error = fz_newmetanode(&meta, info);
-			fz_dropobj(info);
+			fz_insertnode(gstate->head, meta);
+		}
+
+		else if (!strcmp(buf, "BMC"))
+		{
+			fz_node *meta;
+			if (csi->top != 1)
+				goto syntaxerror;
+			error = fz_newmetanode(&meta, csi->stack[0], nil);
 			if (error) return error;
+			// error = pdf_beginmarkedcontent(gstate, meta);
+			// if (error) { fz_freenode(meta); return error; };
 			fz_insertnode(gstate->head, meta);
 		}
 
+		else if (!strcmp(buf, "BDC"))
+		{
+			fz_node *meta;
+			if (csi->top != 2)
+				goto syntaxerror;
+			error = fz_newmetanode(&meta, csi->stack[0], csi->stack[1]);
+			if (error) return error;
+			// error = pdf_beginmarkedcontent(gstate, meta);
+			// if (error) { fz_freenode(meta); return error; };
+			fz_insertnode(gstate->head, meta);
+		}
+
+		else if (!strcmp(buf, "EMC"))
+		{
+			// error = pdf_endmarkedcontent(gstate);
+			// if (error) return error;
+		}
+
 		else if (!strcmp(buf, "cm"))
 		{
 			fz_matrix m;
@@ -218,16 +224,21 @@ runkeyword(pdf_csi *csi, pdf_resources *rdb, char *buf)
 
 		else if (!strcmp(buf, "gs"))
 		{
+			fz_obj *dict;
 			fz_obj *obj;
 
 			if (csi->top != 1)
 				goto syntaxerror;
 
-			obj = fz_dictget(rdb->extgstate, csi->stack[0]);
+			dict = fz_dictgets(rdb, "ExtGState");
+			if (!dict)
+				return fz_throw("syntaxerror: missing extgstate resource");
+
+			obj = fz_dictget(dict, csi->stack[0]);
 			if (!obj)
-				return fz_throw("syntaxerror: missing resource");
-			
-			runextgstate(gstate, rdb, obj);
+				return fz_throw("syntaxerror: missing extgstate resource");
+
+			runextgstate(gstate, xref, obj);
 		}
 
 		else if (!strcmp(buf, "re"))
@@ -286,6 +297,7 @@ runkeyword(pdf_csi *csi, pdf_resources *rdb, char *buf)
 
 		else if (!strcmp(buf, "cs"))
 		{
+			fz_obj *dict;
 			fz_obj *obj;
 
 			if (csi->top != 1)
@@ -301,15 +313,24 @@ runkeyword(pdf_csi *csi, pdf_resources *rdb, char *buf)
 				gstate->fillcs = pdf_devicecmyk;
 			else
 			{
-				obj = fz_dictget(rdb->colorspace, obj);
+				dict = fz_dictgets(rdb, "ColorSpace");
+				if (!dict)
+					return fz_throw("syntaxerror: missing colorspace resource");
+				obj = fz_dictget(dict, obj);
 				if (!obj)
-					return fz_throw("syntaxerror: missing resource");
-				gstate->fillcs = fz_topointer(obj);
+					return fz_throw("syntaxerror: missing colorspace resource");
+				if (fz_isindirect(obj))
+					gstate->fillcs = pdf_findresource(xref->rcolorspace, obj);
+				else
+					return fz_throw("syntaxerror: inline colorspace in dict");
+				if (!gstate->fillcs)
+					return fz_throw("syntaxerror: missing colorspace resource");
 			}
 		}
 
 		else if (!strcmp(buf, "CS"))
 		{
+			fz_obj *dict;
 			fz_obj *obj;
 
 			if (csi->top != 1)
@@ -325,10 +346,18 @@ runkeyword(pdf_csi *csi, pdf_resources *rdb, char *buf)
 				gstate->strokecs = pdf_devicecmyk;
 			else
 			{
-				obj = fz_dictget(rdb->colorspace, obj);
+				dict = fz_dictgets(rdb, "ColorSpace");
+				if (!dict)
+					return fz_throw("syntaxerror: missing colorspace resource");
+				obj = fz_dictget(dict, obj);
 				if (!obj)
-					return fz_throw("syntaxerror: missing resource");
-				gstate->strokecs = fz_topointer(obj);
+					return fz_throw("syntaxerror: missing colorspace resource");
+				if (fz_isindirect(obj))
+					gstate->strokecs = pdf_findresource(xref->rcolorspace, obj);
+				else
+					return fz_throw("syntaxerror: inline colorspace in dict");
+				if (!gstate->strokecs)
+					return fz_throw("syntaxerror: missing colorspace resource");
 			}
 		}
 
@@ -419,16 +448,24 @@ runkeyword(pdf_csi *csi, pdf_resources *rdb, char *buf)
 
 		else if (!strcmp(buf, "Tf"))
 		{
+			fz_obj *dict;
 			fz_obj *obj;
 
 			if (csi->top != 2)
 				goto syntaxerror;
 
-			obj = fz_dictget(rdb->font, csi->stack[0]);
+			dict = fz_dictgets(rdb, "Font");
+			if (!dict)
+				return fz_throw("syntaxerror: missing font resource");
+
+			obj = fz_dictget(dict, csi->stack[0]);
 			if (!obj)
-				return fz_throw("syntaxerror: missing resource");
+				return fz_throw("syntaxerror: missing font resource");
+
+			gstate->font = pdf_findresource(xref->rfont, obj);
+			if (!gstate->font)
+				return fz_throw("syntaxerror: missing font resource");
 
-			gstate->font = fz_topointer(obj);
 			gstate->size = fz_toreal(csi->stack[1]);
 		}
 
@@ -754,7 +791,7 @@ syntaxerror:
 }
 
 fz_error *
-pdf_runcsi(pdf_csi *csi, pdf_resources *rdb, fz_file *file)
+pdf_runcsi(pdf_csi *csi, pdf_xref *xref, fz_obj *rdb, fz_file *file)
 {
 	fz_error *error;
 	unsigned char buf[65536];
@@ -835,7 +872,7 @@ pdf_runcsi(pdf_csi *csi, pdf_resources *rdb, fz_file *file)
 			break;
 
 		case PDF_TKEYWORD:
-			error = runkeyword(csi, rdb, buf);
+			error = runkeyword(csi, xref, rdb, buf);
 			if (error) return error;
 			clearstack(csi);
 			break;
diff --git a/mupdf/open.c b/mupdf/open.c
index 529872a8..19320d43 100644
--- a/mupdf/open.c
+++ b/mupdf/open.c
@@ -460,9 +460,10 @@ pdf_openpdf(pdf_xref **xrefp, char *filename)
 
 	unsigned char buf[65536];	/* yeowch! */
 
-	xref = fz_malloc(sizeof (pdf_xref));
+	xref = fz_malloc(sizeof(pdf_xref));
 	if (!xref)
 		return fz_outofmem;
+	memset(xref, 0, sizeof(pdf_xref));
 
 	xref->file = nil;
 	xref->version = 1.0;
diff --git a/mupdf/page.c b/mupdf/page.c
index 4450ae8d..48e8af77 100644
--- a/mupdf/page.c
+++ b/mupdf/page.c
@@ -2,7 +2,7 @@
 #include <mupdf.h>
 
 static fz_error *
-runcsi(pdf_xref *xref, pdf_csi *csi, pdf_resources *rdb, fz_obj *stmref)
+runcsi(pdf_csi *csi, pdf_xref *xref, fz_obj *rdb, fz_obj *stmref)
 {
 	fz_error *error;
 
@@ -10,7 +10,7 @@ runcsi(pdf_xref *xref, pdf_csi *csi, pdf_resources *rdb, fz_obj *stmref)
 	if (error)
 		return error;
 
-	error = pdf_runcsi(csi, rdb, xref->stream);
+	error = pdf_runcsi(csi, xref, rdb, xref->stream);
 
 	pdf_closestream(xref);
 
@@ -18,7 +18,7 @@ runcsi(pdf_xref *xref, pdf_csi *csi, pdf_resources *rdb, fz_obj *stmref)
 }
 
 static fz_error *
-loadpagecontents(fz_tree **treep, pdf_xref *xref, pdf_resources *rdb, fz_obj *ref)
+loadpagecontents(fz_tree **treep, pdf_xref *xref, fz_obj *rdb, fz_obj *ref)
 {
 	fz_error *error;
 	fz_obj *obj;
@@ -39,7 +39,7 @@ loadpagecontents(fz_tree **treep, pdf_xref *xref, pdf_resources *rdb, fz_obj *re
 		{
 			for (i = 0; i < fz_arraylen(obj); i++)
 			{
-				error = runcsi(xref, csi, rdb, fz_arrayget(obj, i));
+				error = runcsi(csi, xref, rdb, fz_arrayget(obj, i));
 				if (error) {
 					fz_dropobj(obj);
 					goto cleanup;
@@ -48,7 +48,7 @@ loadpagecontents(fz_tree **treep, pdf_xref *xref, pdf_resources *rdb, fz_obj *re
 		}
 		else
 		{
-			error = runcsi(xref, csi, rdb, ref);
+			error = runcsi(csi, xref, rdb, ref);
 			if (error) {
 				fz_dropobj(obj);
 				goto cleanup;
@@ -62,7 +62,7 @@ loadpagecontents(fz_tree **treep, pdf_xref *xref, pdf_resources *rdb, fz_obj *re
 	{
 		for (i = 0; i < fz_arraylen(ref); i++)
 		{
-			error = runcsi(xref, csi, rdb, fz_arrayget(ref, i));
+			error = runcsi(csi, xref, rdb, fz_arrayget(ref, i));
 			if (error)
 				goto cleanup;
 		}
@@ -83,7 +83,7 @@ pdf_loadpage(pdf_page **pagep, pdf_xref *xref, fz_obj *dict)
 	fz_error *error;
 	fz_obj *obj;
 	pdf_page *page;
-	pdf_resources *rdb;
+	fz_obj *rdb;
 	fz_tree *tree;
 	fz_rect bbox;
 	int rotate;
@@ -123,7 +123,7 @@ pdf_loadpage(pdf_page **pagep, pdf_xref *xref, fz_obj *dict)
 
 	error = loadpagecontents(&tree, xref, rdb, obj);
 	if (error) {
-		pdf_freeresources(rdb);
+		fz_dropobj(rdb);
 		return error;
 	}
 
@@ -134,7 +134,7 @@ pdf_loadpage(pdf_page **pagep, pdf_xref *xref, fz_obj *dict)
 	page = *pagep = fz_malloc(sizeof(pdf_page));
 	if (!page) {
 		fz_droptree(tree);
-		pdf_freeresources(rdb);
+		fz_dropobj(rdb);
 		return fz_outofmem;
 	}
 
@@ -143,7 +143,7 @@ pdf_loadpage(pdf_page **pagep, pdf_xref *xref, fz_obj *dict)
 	page->mediabox.max.x = MAX(bbox.min.x, bbox.max.x);
 	page->mediabox.max.y = MAX(bbox.min.y, bbox.max.y);
 	page->rotate = rotate;
-	page->rdb = rdb;
+	page->resources = rdb;
 	page->tree = tree;
 
 	return nil;
@@ -152,7 +152,7 @@ pdf_loadpage(pdf_page **pagep, pdf_xref *xref, fz_obj *dict)
 void
 pdf_freepage(pdf_page *page)
 {
-	pdf_freeresources(page->rdb);
+	fz_dropobj(page->resources);
 	fz_droptree(page->tree);
 	fz_free(page);
 }
diff --git a/mupdf/repair.c b/mupdf/repair.c
index 8742d15f..5f4a139e 100644
--- a/mupdf/repair.c
+++ b/mupdf/repair.c
@@ -124,9 +124,10 @@ pdf_repairpdf(pdf_xref **xrefp, char *filename)
 	int next;
 	int i;
 
-	xref = fz_malloc(sizeof (pdf_xref));
+	xref = fz_malloc(sizeof(pdf_xref));
 	if (!xref)
 		return fz_outofmem;
+	memset(xref, 0, sizeof(pdf_xref));
 
 	xref->file = nil;
 	xref->version = 0.0;
diff --git a/mupdf/resources.c b/mupdf/resources.c
index ef2515a2..f859566f 100644
--- a/mupdf/resources.c
+++ b/mupdf/resources.c
@@ -1,126 +1,348 @@
 #include <fitz.h>
 #include <mupdf.h>
 
+void *
+pdf_findresource(pdf_rsrc *rsrc, fz_obj *ref)
+{
+	while (rsrc)
+	{
+		if (rsrc->oid == fz_tonum(ref) && rsrc->gen == fz_togen(ref))
+			return rsrc->val;
+		rsrc = rsrc->next;
+	}
+	return nil;
+}
+
+/*
+Load resources:
+
+Go through resource dictionary and resolve some levels of
+indirect references so we end up with a stylized structure:
+
+<<
+	/Font <<
+		/F0 1 0 R
+		/F1 2 0 R
+		/F2 3 0 R
+	>>
+	/ExtGState <<
+		/Gs0 << ... /Font 1 0 R ... >>
+		/Gs1 << ... >>
+	>>
+	/ColorSpace <<
+		/Cs0 5 0 R
+		/Cs1 [ /ICCBased 5 0 R ]		% /Cs1 -1 0 R ???
+		/Cs2 [ /CalRGB << ... >> ]		% /Cs2 -2 0 R ???
+	>>
+	/XObject <<
+		/Im0 10 0 R
+		/Fm0 11 0 R
+	>>
+>>
+
+Then all references to actual resources will get
+parsed and inserted into the pdf_xref resource
+lists, indexed by their object number.
+
+TODO: inline colorspaces -> fake objects || refcount ?
+TODO: inline images -> fake objects || refcount?
+
+*/
+
 static fz_error *
-loadextgstatefonts(pdf_resources *rdb, pdf_xref *xref)
+preloadcolorspace(pdf_xref *xref, fz_obj *ref)
 {
-	fz_error *err;
-	char name[64];
-	pdf_font *font;
-	fz_obj *extgstate;
+	fz_error *error;
+	fz_colorspace *colorspace;
+	pdf_rsrc *rsrc;
 	fz_obj *obj;
-	fz_obj *ptr;
-	fz_obj *ref;
-	int i;
 
-	for (i = 0; i < fz_dictlen(rdb->extgstate); i++)
-	{
-		extgstate = fz_dictgetval(rdb->extgstate, i);
+	if (pdf_findresource(xref->rcolorspace, ref))
+		return nil;
 
-		obj = fz_dictgets(extgstate, "Font");
-		if (obj)
-		{
-			font = nil;
-			ptr = nil;
+	rsrc = fz_malloc(sizeof(pdf_rsrc));
+	if (!rsrc)
+		return fz_outofmem;
+	rsrc->oid = fz_tonum(ref);
+	rsrc->gen = fz_togen(ref);
+
+	error = pdf_loadindirect(&obj, xref, ref);
+	if (error)
+		return error;
+	error = pdf_loadcolorspace(&colorspace, xref, obj);
+	fz_dropobj(obj);
+	if (error) {
+		fz_free(rsrc);
+		return error;
+	}
 
-			if (!fz_isarray(obj) || fz_arraylen(obj) != 2)
-				return fz_throw("syntaxerror in ExtGState/Font");
+	rsrc->val = colorspace;
+	rsrc->next = xref->rcolorspace;
+	xref->rcolorspace = rsrc;
+	return nil;
+}
 
-			ref = fz_arrayget(obj, 0);
-			sprintf(name, "$f.%d.%d", fz_tonum(ref), fz_togen(ref));
+static fz_error *
+preloadxobject(pdf_xref *xref, fz_obj *ref)
+{
+	fz_error *error;
+	pdf_rsrc *rsrc;
+	fz_obj *obj;
+	fz_obj *subtype;
 
-			err = pdf_resolve(&ref, xref);
-			if (err) return err;
+	if (pdf_findresource(xref->rxobject, ref))
+		return nil;
+	if (pdf_findresource(xref->rimage, ref))
+		return nil;
 
-			err = pdf_loadfont(&font, xref, ref);
-			if (err) goto cleanup;
+	rsrc = fz_malloc(sizeof(pdf_rsrc));
+	if (!rsrc)
+		return fz_outofmem;
+	rsrc->oid = fz_tonum(ref);
+	rsrc->gen = fz_togen(ref);
 
-			err = fz_newpointer(&ptr, font);
-			if (err) goto cleanup;
+	error = pdf_loadindirect(&obj, xref, ref);
+	if (error)
+		return error;
 
-			err = fz_dictputs(rdb->font, name, ptr);
-			if (err) goto cleanup;
+	subtype = fz_dictgets(obj, "Subtype");
 
-			fz_dropobj(ptr);
-			fz_dropobj(ref);
+	if (!strcmp(fz_toname(subtype), "Form"))
+	{
+//		error = pdf_loadxobject((pdf_xobject**)&rsrc->val, xref, obj);
+		fz_dropobj(obj);
+		if (error) {
+			fz_free(rsrc);
+			return error;
 		}
+		rsrc->next = xref->rxobject;
+		xref->rxobject = rsrc;
+		return nil;
 	}
 
-	return nil;
+	else if (!strcmp(fz_toname(subtype), "Image"))
+	{
+		error = pdf_loadimage((pdf_image**)&rsrc->val, xref, obj);
+		fz_dropobj(obj);
+		if (error) {
+			fz_free(rsrc);
+			return error;
+		}
+		rsrc->next = xref->rimage;
+		xref->rimage = rsrc;
+		return nil;
+	}
 
-cleanup:
-	if (font) fz_freefont((fz_font*)font);
-	if (ptr) fz_dropobj(ptr);
-	fz_dropobj(ref);
-	return err;
+	else
+	{
+		fz_dropobj(obj);
+		fz_free(rsrc);
+		return fz_throw("syntaxerror: unknown XObject subtype");
+	}
 }
 
 static fz_error *
-loadextgstates(pdf_resources *rdb, pdf_xref *xref, fz_obj *dict)
+preloadfont(pdf_xref *xref, fz_obj *ref)
 {
-	fz_error *err;
-	fz_obj *key, *val;
-	int i;
+	fz_error *error;
+	pdf_font *font;
+	pdf_rsrc *rsrc;
+	fz_obj *obj;
 
-	for (i = 0; i < fz_dictlen(dict); i++)
-	{
-		key = fz_dictgetkey(dict, i);
-		val = fz_dictgetval(dict, i);
+	if (pdf_findresource(xref->rfont, ref))
+		return nil;
 
-		err = pdf_resolve(&val, xref);
-		if (err) return err;
+	rsrc = fz_malloc(sizeof(pdf_rsrc));
+	if (!rsrc)
+		return fz_outofmem;
+	rsrc->oid = fz_tonum(ref);
+	rsrc->gen = fz_togen(ref);
+
+	error = pdf_loadindirect(&obj, xref, ref);
+	if (error)
+		return error;
+	error = pdf_loadfont(&font, xref, obj);
+	fz_dropobj(obj);
+	if (error) {
+		fz_free(rsrc);
+		return error;
+	}
 
-		err = fz_dictput(rdb->extgstate, key, val);
-		if (err) { fz_dropobj(val); return err; }
+	rsrc->val = font;
+	rsrc->next = xref->rfont;
+	xref->rfont = rsrc;
+	return nil;
+}
 
-		fz_dropobj(val);
+static fz_error *
+scanfonts(pdf_xref *xref, fz_obj *rdb)
+{
+	fz_error *error;
+	fz_obj *dict;
+	fz_obj *obj;
+	int i;
+
+	dict = fz_dictgets(rdb, "ExtGState");
+	if (dict)
+	{
+		for (i = 0; i < fz_dictlen(dict); i++)
+		{
+			obj = fz_dictgetval(dict, i);
+			obj = fz_dictgets(obj, "Font");
+			if (obj)
+			{
+				error = preloadfont(xref, fz_arrayget(obj, 0));
+				if (error)
+					return error;
+			}
+		}
+	}
+
+	dict = fz_dictgets(rdb, "Font");
+	if (dict)
+	{
+		for (i = 0; i < fz_dictlen(dict); i++)
+		{
+			obj = fz_dictgetval(dict, i);
+			error = preloadfont(xref, obj);
+			if (error)
+				return error;
+		}
 	}
 
 	return nil;
 }
 
 static fz_error *
-loadfonts(pdf_resources *rdb, pdf_xref *xref, fz_obj *dict)
+copyresolved(fz_obj **outp, pdf_xref *xref, fz_obj *dict)
 {
-	fz_error *err;
-	pdf_font *font;
-	fz_obj *key, *val;
-	fz_obj *ptr;
+	fz_error *error;
+	fz_obj *key, *val, *obj;
+	fz_obj *copy;
 	int i;
 
+	error = fz_newdict(&copy, fz_dictlen(dict));
+	if (error)
+		return error;
+
 	for (i = 0; i < fz_dictlen(dict); i++)
 	{
-		font = nil;
-		ptr = nil;
-
 		key = fz_dictgetkey(dict, i);
 		val = fz_dictgetval(dict, i);
 
-		err = pdf_resolve(&val, xref);
-		if (err) return err;
+		if (fz_isindirect(val))
+		{
+			error = pdf_loadindirect(&obj, xref, val);
+			if (error)
+				goto cleanup;
+			error = fz_dictput(copy, key, obj);
+			fz_dropobj(obj);
+			if (error)
+				goto cleanup;
+		}
+		else
+		{
+			error = fz_dictput(copy, key, val);
+			if (error)
+				goto cleanup;
+		}
+	}
 
-		err = pdf_loadfont(&font, xref, val);
-		if (err) goto cleanup;
+	*outp = copy;
+	return nil;
 
-		err = fz_newpointer(&ptr, font);
-		if (err) goto cleanup;
+cleanup:
+	fz_dropobj(copy);
+	return error;
+}
 
-		err = fz_dictput(rdb->font, key, ptr);
-		if (err) goto cleanup;
+fz_error *
+pdf_loadresources(fz_obj **rdbp, pdf_xref *xref, fz_obj *orig)
+{
+	fz_error *error;
+	fz_obj *copy;
+	fz_obj *old;
+	fz_obj *new;
+	fz_obj *dict;
+	fz_obj *obj;
+	int i;
 
-		fz_dropobj(ptr);
-		fz_dropobj(val);
+	/*
+	 * Resolve indirect objects
+	 */
+
+	error = copyresolved(&copy, xref, orig);
+	if (error)
+		return error;
+
+	old = fz_dictgets(copy, "ExtGState");
+	if (old)
+	{
+		error = copyresolved(&new, xref, old);
+		if (error)
+			goto cleanup;
+		error = fz_dictputs(copy, "ExtGState", new);
+		fz_dropobj(new);
+		if (error)
+			goto cleanup;
 	}
 
+	/*
+	 * Load ColorSpace objects
+	 */
+
+	dict = fz_dictgets(copy, "ColorSpace");
+	if (dict)
+	{
+		for (i = 0; i < fz_dictlen(dict); i++)
+		{
+			obj = fz_dictgetval(dict, i);
+			if (fz_isindirect(obj))
+			{
+				error = preloadcolorspace(xref, obj);
+				if (error)
+					return error;
+			}
+		}
+	}
+
+	/*
+	 * Load XObjects and Images
+	 */
+
+	dict = fz_dictgets(copy, "XObject");
+	if (dict)
+	{
+		for (i = 0; i < fz_dictlen(dict); i++)
+		{
+			obj = fz_dictgetval(dict, i);
+			if (fz_isindirect(obj))
+			{
+				error = preloadxobject(xref, obj);
+				if (error)
+					return error;
+			}
+		}
+	}
+
+	/*
+	 * Load Font objects
+	 */
+
+	error = scanfonts(xref, copy);
+	if (error)
+		goto cleanup;
+
+	*rdbp = copy;
 	return nil;
 
 cleanup:
-	if (font) fz_freefont((fz_font*)font);
-	if (ptr) fz_dropobj(ptr);
-	fz_dropobj(val);
-	return err;
+	fz_dropobj(copy);
+	return error;
 }
 
+#if 0
+
 static fz_error *
 loadcolorspaces(pdf_resources *rdb, pdf_xref *xref, fz_obj *dict)
 {
@@ -228,15 +450,5 @@ pdf_loadresources(pdf_resources **rdbp, pdf_xref *xref, fz_obj *topdict)
 	return nil;
 }
 
-void
-pdf_freeresources(pdf_resources *rdb)
-{
-	/* TODO freefont and freecolorspace */
-	if (rdb->extgstate) fz_dropobj(rdb->extgstate);
-	if (rdb->colorspace) fz_dropobj(rdb->colorspace);
-	if (rdb->font) fz_dropobj(rdb->font);
-	if (rdb->ximage) fz_dropobj(rdb->ximage);
-	if (rdb->xform) fz_dropobj(rdb->xform);
-	fz_free(rdb);
-}
+#endif
 
diff --git a/mupdf/xref.c b/mupdf/xref.c
index ae11ebb7..5dde5f5f 100644
--- a/mupdf/xref.c
+++ b/mupdf/xref.c
@@ -10,9 +10,10 @@ pdf_newpdf(pdf_xref **xrefp)
 {
 	pdf_xref *xref;
 
-	xref = fz_malloc(sizeof (pdf_xref));
+	xref = fz_malloc(sizeof(pdf_xref));
 	if (!xref)
 		return fz_outofmem;
+	memset(xref, 0, sizeof(pdf_xref));
 
 	xref->file = nil;
 	xref->version = 1.3;
diff --git a/render/render.c b/render/render.c
index d46d5b71..29b51480 100644
--- a/render/render.c
+++ b/render/render.c
@@ -5,6 +5,9 @@ fz_error *fz_rendercolorpath(fz_renderer*, fz_pathnode*, fz_colornode*, fz_matri
 fz_error *fz_rendertext(fz_renderer*, fz_textnode*, fz_matrix);
 fz_error *fz_renderpath(fz_renderer*, fz_pathnode*, fz_matrix);
 
+fz_error *fz_renderimageover(fz_renderer*, fz_imagenode*, fz_matrix);
+fz_error *fz_renderimage(fz_renderer*, fz_imagenode*, fz_matrix);
+
 fz_error *
 fz_newrenderer(fz_renderer **gcp, fz_colorspace *processcolormodel)
 {
@@ -131,7 +134,6 @@ fz_renderover(fz_renderer *gc, fz_overnode *over, fz_matrix ctm)
 	fz_error *error;
 	fz_pixmap *oldacc = nil;
 	int oldmode;
-int i;
 
 	/* uh-oh! we have a new over cluster */
 	if (gc->mode != FZ_ROVER)
@@ -209,6 +211,10 @@ fz_rendermask(fz_renderer *gc, fz_masknode *mask, fz_matrix ctm)
 
 	fz_blendmask(gc->tmp, colorpix, shapepix);
 
+//printf("mask color");fz_debugpixmap(colorpix);getchar();
+//printf("mask shape");fz_debugpixmap(shapepix);getchar();
+//printf("mask blend");fz_debugpixmap(gc->tmp);getchar();
+
 	fz_freepixmap(shapepix);
 	fz_freepixmap(colorpix);
 
@@ -246,6 +252,8 @@ fz_rendernode(fz_renderer *gc, fz_node *node, fz_matrix ctm)
 		return fz_renderpath(gc, (fz_pathnode*)node, ctm);
 	case FZ_NTEXT:
 		return fz_rendertext(gc, (fz_textnode*)node, ctm);
+	case FZ_NIMAGE:
+		return fz_renderimage(gc, (fz_imagenode*)node, ctm);
 	default:
 		return nil;
 	}
@@ -261,6 +269,10 @@ fz_rendertree(fz_pixmap **outp, fz_renderer *gc, fz_tree *tree, fz_matrix ctm, f
 	gc->w = ceil(bbox.max.x) - floor(bbox.min.x);
 	gc->h = ceil(bbox.max.y) - floor(bbox.min.y);
 
+	/* compensate for rounding */
+	ctm.e -= bbox.min.x - floor(bbox.min.x);
+	ctm.f -= bbox.min.y - floor(bbox.min.y);
+
 	error = fz_rendernode(gc, tree->root, ctm);
 	if (error)
 		return error;
diff --git a/render/renderimage.c b/render/renderimage.c
new file mode 100644
index 00000000..4c6ef816
--- /dev/null
+++ b/render/renderimage.c
@@ -0,0 +1,59 @@
+#include <fitz.h>
+
+static int cmpy(const void *a, const void *b)
+{
+	const fz_point *ap = a;
+	const fz_point *bp = b;
+	return bp->y - ap->y;
+}
+
+static void
+drawtile(fz_pixmap *out, fz_pixmap *tile, fz_matrix ctm)
+{
+	static const fz_point rect[4] = { {0, 0}, {0, 1}, {1, 1}, {1, 0} };
+	fz_point v[4];
+	int i;
+
+	for (i = 0; i < 4; i++)
+		v[i] = fz_transformpoint(ctm, rect[i]);
+
+	qsort(v, 4, sizeof(fz_point), cmpy);
+
+	for (i = 0; i < 4; i++)
+		printf("%d: %g %g\n", i, v[i].x, v[i].y);
+
+}
+
+fz_error *
+fz_renderimage(fz_renderer *gc, fz_imagenode *node, fz_matrix ctm)
+{
+	fz_error *error;
+	fz_pixmap *tile;
+	fz_image *image = node->image;
+	fz_colorspace *cs = image->cs;
+	int w = image->w;
+	int h = image->h;
+	int n = image->n;
+
+	error = fz_newpixmap(&tile, cs, 0, 0, w, h, n, 1);
+	if (error)
+		return error;
+
+	error = fz_newpixmap(&gc->tmp, cs, gc->x, gc->y, gc->w, gc->h, n, 1);
+	if (error)
+		goto cleanup;
+
+	error = image->loadtile(image, tile);
+	if (error)
+		goto cleanup;
+
+	drawtile(gc->tmp, tile, ctm);
+
+	fz_freepixmap(tile);
+	return nil;
+
+cleanup:
+	fz_freepixmap(tile);
+	return error;
+}
+
diff --git a/render/renderpath.c b/render/renderpath.c
index 9e805a53..8d2f875b 100644
--- a/render/renderpath.c
+++ b/render/renderpath.c
@@ -1,6 +1,8 @@
 #include <fitz.h>
 
-enum { HS = 17, VS = 15 };
+// enum { HS = 1, VS = 1, SF = 255 };
+// enum { HS = 5, VS = 3, SF = 17 };
+enum { HS = 17, VS = 15, SF = 1 };
 
 static fz_error *pathtogel(fz_gel *gel, fz_pathnode *path, fz_matrix ctm)
 {
@@ -17,7 +19,7 @@ static fz_error *pathtogel(fz_gel *gel, fz_pathnode *path, fz_matrix ctm)
 	return fz_fillpath(gel, path, ctm, flatness);
 }
 
-static void blitcolorspan(int y, int x0, int n, short *list, void *userdata)
+static void blitcolorspan(int y, int x, int n, unsigned char *alpha, void *userdata)
 {
 	fz_renderer *gc = userdata;
 	fz_pixmap *pix = gc->acc;
@@ -28,23 +30,24 @@ static void blitcolorspan(int y, int x0, int n, short *list, void *userdata)
 	unsigned char g = gc->g;
 	unsigned char b = gc->b;
 
-	sa = 0;
-
-	while (x0 < pix->x)
+	if (x < pix->x)
 	{
-		sa += *list++;
-		x0 ++;
-		n --;
+		alpha += pix->x - x;
+		n -= pix->x - x;
+		x = pix->x;
 	}
 
-	if (n > pix->w)
-		n = pix->w;
+	if (x + n > pix->x + pix->w)
+		n = pix->x + pix->w - x;
+
+	if (n < 0)
+		return;
 
-	p = &pix->samples[(y - pix->y) * pix->stride + (x0 - pix->x) * 4];
+	p = &pix->samples[(y - pix->y) * pix->stride + (x - pix->x) * 4];
 
 	while (n--)
 	{
-		sa += *list++;
+		sa = *alpha++ * SF;
 		ssa = 255 - sa;
 
 		p[0] = fz_mul255(r, sa) + fz_mul255(p[0], ssa);
@@ -56,31 +59,27 @@ static void blitcolorspan(int y, int x0, int n, short *list, void *userdata)
 	}
 }
 
-static void blitalphaspan(int y, int x0, int n, short *list, void *userdata)
+static void blitalphaspan(int y, int x, int n, unsigned char *alpha, void *userdata)
 {
 	fz_pixmap *pix = userdata;
-	unsigned char a;
 	unsigned char *p;
 
-	a = 0;
-
-	while (x0 < pix->x)
+	if (x < pix->x)
 	{
-		a += *list++;
-		x0 ++;
-		n --;
+		alpha += pix->x - x;
+		n -= pix->x - x;
+		x = pix->x;
 	}
 
-	if (n > pix->w)
-		n = pix->w;
+	if (x + n > pix->x + pix->w)
+		n = pix->x + pix->w - x;
 
-	p = &pix->samples[(y - pix->y) * pix->stride + (x0 - pix->x) * 4];
+	if (n < 0)
+		return;
 
+	p = &pix->samples[(y - pix->y) * pix->stride + (x - pix->x)];
 	while (n--)
-	{
-		a += *list++;
-		*p++ = a;
-	}
+		*p++ = *alpha++ * SF;
 }
 
 fz_error *
diff --git a/render/rendertext.c b/render/rendertext.c
index cc181657..81afeafa 100644
--- a/render/rendertext.c
+++ b/render/rendertext.c
@@ -33,13 +33,13 @@ static void blitcolorglyph(fz_pixmap *out, fz_glyph *gl, int xo, int yo, fz_rend
 	{
 		for (sx = 0; sx < gl->w; sx++)
 		{
-			dx = xo + sx + gl->lsb - out->x;
 			dy = yo - sy + gl->top - out->y;
+			if (dy < 0) continue;
+			if (dy >= out->h) break;
 
+			dx = xo + sx + gl->lsb - out->x;
 			if (dx < 0) continue;
-			if (dy < 0) continue;
-			if (dx >= out->w) continue;
-			if (dy >= out->h) continue;
+			if (dx >= out->w) break;
 
 			sa = gl->bitmap[sx + sy * gl->w];
 			ssa = 255 - sa;
diff --git a/render/scanconv.c b/render/scanconv.c
index b2689ae2..db859d1f 100644
--- a/render/scanconv.c
+++ b/render/scanconv.c
@@ -1,7 +1,7 @@
 #include <fitz.h>
 
 static inline void
-addspan(short *list, int x0, int x1, int xofs, int hs)
+addspan(unsigned char *list, int x0, int x1, int xofs, int hs)
 {
 	int x0pix, x0sub;
 	int x1pix, x1sub;
@@ -34,7 +34,7 @@ addspan(short *list, int x0, int x1, int xofs, int hs)
 }
 
 static inline void
-nonzerowinding(fz_ael *ael, short *list, int xofs, int hs)
+nonzerowinding(fz_ael *ael, unsigned char *list, int xofs, int hs)
 {
 	int winding = 0;
 	int x = 0;
@@ -50,7 +50,7 @@ nonzerowinding(fz_ael *ael, short *list, int xofs, int hs)
 }
 
 static inline void
-evenodd(fz_ael *ael, short *list, int xofs, int hs)
+evenodd(fz_ael *ael, unsigned char *list, int xofs, int hs)
 {
 	int even = 0;
 	int x = 0;
@@ -65,22 +65,22 @@ evenodd(fz_ael *ael, short *list, int xofs, int hs)
 	}
 }
 
-/*
-void
-fz_emitdeltas(short *list, int y, int xofs, int n)
+static void toalpha(unsigned char *list, int n)
 {
 	int d = 0;
 	while (n--)
-		d += *list++;
+	{
+		d += *list;
+		*list++ = d;
+	}
 }
-*/
 
 fz_error *
 fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, int y0, int y1,
-	void (*blitfunc)(int,int,int,short*,void*), void *blitdata)
+	void (*blitfunc)(int,int,int,unsigned char*,void*), void *blitdata)
 {
 	fz_error *error;
-	short *deltas;
+	unsigned char *deltas;
 	int y, e;
 	int yd, yc;
 
@@ -96,11 +96,11 @@ fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, int y0, int y1,
 	if (gel->len == 0)
 		return nil;
 
-	deltas = fz_malloc(sizeof(short) * (xmax - xmin + 1));
+	deltas = fz_malloc(xmax - xmin + 1);
 	if (!deltas)
 		return fz_outofmem;
 
-	memset(deltas, 0, sizeof(short) * (xmax - xmin + 1));
+	memset(deltas, 0, xmax - xmin + 1);
 
 	e = 0;
 	y = gel->edges[0].y;
@@ -113,8 +113,9 @@ fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, int y0, int y1,
 		if (yc != yd) {
 			if (yd >= y0 && yd < y1)
 			{
+				toalpha(deltas, xmax - xmin);
 				blitfunc(yd, xmin, xmax - xmin, deltas, blitdata);
-				memset(deltas, 0, sizeof(short) * (xmax - xmin + 1));
+				memset(deltas, 0, xmax - xmin + 1);
 			}
 		}
 		yd = yc;
@@ -142,7 +143,10 @@ fz_scanconvert(fz_gel *gel, fz_ael *ael, int eofill, int y0, int y1,
 	}
 
 	if (yd >= y0 && yd < y1)
+	{
+		toalpha(deltas, xmax - xmin);
 		blitfunc(yd, xmin, xmax - xmin, deltas, blitdata);
+	}
 
 	fz_free(deltas);
 	return nil;
diff --git a/test/pdfrip.c b/test/pdfrip.c
index f7cbc093..e8cd088f 100644
--- a/test/pdfrip.c
+++ b/test/pdfrip.c
@@ -33,23 +33,20 @@ void showpage(pdf_xref *xref, fz_obj *pageobj)
 			page->mediabox.max.x, page->mediabox.max.y);
 		printf("  rotate %d\n", page->rotate);
 
-		printf("  fonts\n");
-		fz_debugobj(page->rdb->font);
-		printf("\n");
-
-		printf("  colorspaces\n");
-		fz_debugobj(page->rdb->colorspace);
+		printf("  resources\n");
+		fz_debugobj(page->resources);
 		printf("\n");
 
 		printf("tree\n");
 		fz_debugtree(page->tree);
-		printf("endtree");
+		printf("endtree\n");
 	}
 
 	{
 		fz_pixmap *pix;
 		fz_renderer *gc;
 		fz_matrix ctm;
+		fz_rect bbox;
 
 		error = fz_newrenderer(&gc, pdf_devicergb);
 		if (error) fz_abort(error);
@@ -58,8 +55,12 @@ void showpage(pdf_xref *xref, fz_obj *pageobj)
 printf("ctm %g %g %g %g %g %g\n",
 	ctm.a, ctm.b, ctm.c, ctm.d, ctm.e, ctm.f);
 
+printf("bounding!\n");
+		bbox = fz_boundtree(page->tree, ctm);
+printf("  [%g %g %g %g]\n", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y);
 printf("rendering!\n");
 		error = fz_rendertree(&pix, gc, page->tree, ctm, page->mediabox);
+		//error = fz_rendertree(&pix, gc, page->tree, ctm, bbox);
 		if (error) fz_abort(error);
 printf("done!\n");
 
diff --git a/tree/debug.c b/tree/debug.c
index 583608f5..e55d56e7 100644
--- a/tree/debug.c
+++ b/tree/debug.c
@@ -13,7 +13,8 @@ static void lispmeta(fz_metanode *node, int level)
 	fz_node *child;
 	indent(level);
 	printf("(meta ");
-	fz_debugobj(node->info);
+	if (node->name) { fz_debugobj(node->name); }
+	if (node->dict) { printf("\n"); fz_debugobj(node->dict); }
 	printf("\n");
 	for (child = node->super.child; child; child = child->next)
 		lispnode(child, level + 1);
@@ -141,7 +142,7 @@ static void lisptext(fz_textnode *node, int level)
 static void lispimage(fz_imagenode *node, int level)
 {
 	indent(level);
-	printf("(image %d %d %d %d)\n", node->w, node->h, node->n, node->a);
+	printf("(image)\n");
 }
 
 static void lispnode(fz_node *node, int level)
diff --git a/tree/font.c b/tree/font.c
index 5dfaec2e..58c194ae 100644
--- a/tree/font.c
+++ b/tree/font.c
@@ -39,6 +39,7 @@ fz_setfontwmode(fz_font *font, int wmode)
 void
 fz_setfontbbox(fz_font *font, int xmin, int ymin, int xmax, int ymax)
 {
+printf("  bbox [%d %d %d %d]\n", xmin, ymin, xmax, ymax);
     font->bbox.min.x = xmin;
     font->bbox.min.y = ymin;
     font->bbox.max.x = xmax;
diff --git a/tree/node2.c b/tree/node2.c
index d50936ef..6e28aaac 100644
--- a/tree/node2.c
+++ b/tree/node2.c
@@ -164,7 +164,7 @@ fz_boundtransformnode(fz_transformnode *node, fz_matrix ctm)
  */
 
 fz_error *
-fz_newmetanode(fz_node **nodep, fz_obj *info)
+fz_newmetanode(fz_node **nodep, fz_obj *name, fz_obj *dict)
 {
 	fz_metanode *node;
 
@@ -174,7 +174,13 @@ fz_newmetanode(fz_node **nodep, fz_obj *info)
 	*nodep = (fz_node*)node;
 
 	fz_initnode((fz_node*)node, FZ_NMETA);
-	node->info = fz_keepobj(info);
+	node->name = nil;
+	node->dict = nil;
+
+	if (name)
+		node->name = fz_keepobj(name);
+	if (dict)
+		node->dict = fz_keepobj(dict);
 
 	return nil;
 }
@@ -182,8 +188,10 @@ fz_newmetanode(fz_node **nodep, fz_obj *info)
 void
 fz_freemetanode(fz_metanode *node)
 {
-	if (node->info)
-		fz_dropobj(node->info);
+	if (node->name)
+		fz_dropobj(node->name);
+	if (node->dict)
+		fz_dropobj(node->dict);
 }
 
 fz_rect
@@ -261,7 +269,7 @@ fz_boundcolornode(fz_colornode *node, fz_matrix ctm)
  */
 
 fz_error *
-fz_newimagenode(fz_node **nodep, fz_colorspace *cs, int w, int h, int n, int a)
+fz_newimagenode(fz_node **nodep, fz_image *image)
 {
 	fz_imagenode *node;
 
@@ -271,11 +279,7 @@ fz_newimagenode(fz_node **nodep, fz_colorspace *cs, int w, int h, int n, int a)
 	*nodep = (fz_node*)node;
 
 	fz_initnode((fz_node*)node, FZ_NIMAGE);
-	node->cs = cs;
-	node->w = w;
-	node->h = h;
-	node->n = n;
-	node->a = a;
+	node->image = image;
 
 	return nil;
 }
diff --git a/tree/text.c b/tree/text.c
index d822ec34..1832df9f 100644
--- a/tree/text.c
+++ b/tree/text.c
@@ -29,9 +29,67 @@ fz_freetextnode(fz_textnode *text)
 fz_rect
 fz_boundtextnode(fz_textnode *text, fz_matrix ctm)
 {
-	// FIXME convolve font bbox to all glyph x,y pairs
-	/* fz_rect bounds = fz_boundglyph(text->font, text->els[0], ctm); */
-	return fz_infiniterect();
+	fz_matrix trm;
+	fz_point ul, ur, ll, lr;
+	fz_rect bbox;
+	fz_rect fbox;
+	int i;
+
+	if (text->len == 0)
+		return fz_infiniterect();
+
+	/* 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);
+	}
+
+	ll.x = bbox.min.x; ll.y = bbox.min.y; ll = fz_transformpoint(ctm, ll);
+	ul.x = bbox.min.x; ul.y = bbox.max.y; ul = fz_transformpoint(ctm, ul);
+	ur.x = bbox.max.x; ur.y = bbox.max.y; ur = fz_transformpoint(ctm, ur);
+	lr.x = bbox.max.x; lr.y = bbox.min.y; lr = fz_transformpoint(ctm, lr);
+
+	bbox.min.x = MIN4(ll.x, ul.x, ur.x, lr.x);
+	bbox.min.y = MIN4(ll.y, ul.y, ur.y, lr.y);
+	bbox.max.x = MAX4(ll.x, ul.x, ur.x, lr.x);
+	bbox.max.y = MAX4(ll.y, ul.y, ur.y, lr.y);
+
+	/* 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;
+
+	ll.x = fbox.min.x; ll.y = fbox.min.y; ll = fz_transformpoint(trm, ll);
+	ul.x = fbox.min.x; ul.y = fbox.max.y; ul = fz_transformpoint(trm, ul);
+	ur.x = fbox.max.x; ur.y = fbox.max.y; ur = fz_transformpoint(trm, ur);
+	lr.x = fbox.max.x; lr.y = fbox.min.y; lr = fz_transformpoint(trm, lr);
+
+	fbox.min.x = MIN4(ll.x, ul.x, ur.x, lr.x);
+	fbox.min.y = MIN4(ll.y, ul.y, ur.y, lr.y);
+	fbox.max.x = MAX4(ll.x, ul.x, ur.x, lr.x);
+	fbox.max.y = MAX4(ll.y, ul.y, ur.y, lr.y);
+
+	bbox.min.x += MIN4(ll.x, ul.x, ur.x, lr.x);
+	bbox.min.y += MIN4(ll.y, ul.y, ur.y, lr.y);
+	bbox.max.x += MAX4(ll.x, ul.x, ur.x, lr.x);
+	bbox.max.y += MAX4(ll.y, ul.y, ur.y, lr.y);
+
+//	printf("text [ %g %g %g %g ]\n", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y);
+
+	return bbox;
 }
 
 static fz_error *
-- 
cgit v1.2.3