From 9c659d040a3890dc6a33aed485eba15364631bec Mon Sep 17 00:00:00 2001
From: Tor Andersson <tor@ghostscript.com>
Date: Thu, 25 Nov 2004 04:46:31 +0100
Subject: optimize away useless clipmasks. undo ctm for shades.

---
 tree/debug.c    |  14 +-----
 tree/optimize.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 tree/tree.c     |   3 ++
 3 files changed, 118 insertions(+), 31 deletions(-)

(limited to 'tree')

diff --git a/tree/debug.c b/tree/debug.c
index a61872c4..e468ef27 100644
--- a/tree/debug.c
+++ b/tree/debug.c
@@ -6,16 +6,6 @@ static void indent(int level)
 		putchar(' ');
 }
 
-static void showbbox(void *node0)
-{
-	fz_node *node = node0;
-	fz_irect bbox;
-	bbox = fz_roundrect(fz_boundnode(node, fz_identity()));
-	printf("[%d %d %d %d]",
-		bbox.min.x, bbox.min.y,
-		bbox.max.x, bbox.max.y);
-}
-
 static void lispnode(fz_node *node, int level);
 
 static void lispmeta(fz_metanode *node, int level)
@@ -36,7 +26,7 @@ static void lispover(fz_overnode *node, int level)
 {
 	fz_node *child;
 	indent(level);
-	printf("(over "); showbbox(node); printf("\n");
+	printf("(over\n");
 	for (child = node->super.first; child; child = child->next)
 		lispnode(child, level + 1);
 	indent(level);
@@ -47,7 +37,7 @@ static void lispmask(fz_masknode *node, int level)
 {
 	fz_node *child;
 	indent(level);
-	printf("(mask "); showbbox(node); printf("\n");
+	printf("(mask\n");
 	for (child = node->super.first; child; child = child->next)
 		lispnode(child, level + 1);
 	indent(level);
diff --git a/tree/optimize.c b/tree/optimize.c
index 14d98232..6371ddec 100644
--- a/tree/optimize.c
+++ b/tree/optimize.c
@@ -7,21 +7,23 @@
 static void cleanovers(fz_node *node)
 {
 	fz_node *prev;
-	fz_node *over;
+	fz_node *next;
+	fz_node *current;
 	fz_node *child;
 
 	prev = nil;
-	for (over = node->first; over; over = prev->next)
+	for (current = node->first; current; current = next)
 	{
-		cleanovers(over);
+		next = current->next;
 
-		if (fz_isovernode(over))
+		cleanovers(current);
+
+		if (fz_isovernode(current))
 		{
-			if (over->first == over->last)
+			if (current->first == current->last)
 			{
-				printf("  remove unused over node\n");
-				child = over->first;
-				fz_removenode(over);
+				child = current->first;
+				fz_removenode(current);
 				if (child)
 				{
 					if (prev)
@@ -29,28 +31,120 @@ static void cleanovers(fz_node *node)
 					else
 						fz_insertnodefirst(node, child);
 				}
-				over = nil;
+				current = nil;
 			}
 		}
 
-		if (over)
-			prev = over;
+		if (current)
+			prev = current;
 	}
 }
 
-fz_error *
-fz_optimizetree(fz_tree *tree)
+/*
+ * Remove rectangular clip-masks whose contents fit...
+ */
+
+static int getrect(fz_pathnode *path, fz_rect *bboxp)
 {
-	printf("optimizing tree\n");
+	float x, y, w, h;
 
-//printf("before:\n");
-//fz_debugtree(tree);
+	/* move x y, line x+w y, line x+w y+h, line x y+h, close */
 
-	cleanovers(tree->root);
+	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 *next;
+	fz_node *current;
+	fz_node *shape;
+	fz_node *color;
+	fz_rect bbox;
 
-//printf("after:\n");
-//fz_debugtree(tree);
+	prev = nil;
+	for (current = node->first; current; current = next)
+	{
+		next = current->next;
+
+		cleanmasks(current);
+
+		if (fz_ismasknode(current))
+		{
+			shape = current->first;
+			color = shape->next;
+
+			if (fz_ispathnode(shape))
+			{
+				if (getrect((fz_pathnode*)shape, &bbox))
+				{
+					if (fitsinside(color, bbox))
+					{
+						printf("removed useless mask\n");
+						fz_removenode(current);
+						if (prev)
+							fz_insertnodeafter(prev, color);
+						else
+							fz_insertnodefirst(node, color);
+						current = nil;
+					}
+				}
+			}
+		}
 
+		if (current)
+			prev = current;
+	}
+}
+
+/*
+ *
+ */
+
+fz_error *
+fz_optimizetree(fz_tree *tree)
+{
+	cleanovers(tree->root);
+	cleanmasks(tree->root);
 	return nil;
 }
 
diff --git a/tree/tree.c b/tree/tree.c
index e59d0413..f667e39a 100644
--- a/tree/tree.c
+++ b/tree/tree.c
@@ -105,6 +105,9 @@ fz_removenode(fz_node *child)
 	if (parent->first == child)
 	{
 		parent->first = child->next;
+		if (parent->last == child)
+			parent->last = nil;
+		return;
 	}
 
 	prev = parent->first;
-- 
cgit v1.2.3