From ee154f16bd09a43359967f7e7b86c3677c09461d Mon Sep 17 00:00:00 2001
From: Tor Andersson <tor@ghostscript.com>
Date: Wed, 30 Mar 2005 08:30:22 +0200
Subject: rename part 1 -- files

---
 base/node_optimize.c | 310 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 310 insertions(+)
 create mode 100644 base/node_optimize.c

(limited to 'base/node_optimize.c')

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;
+}
+
-- 
cgit v1.2.3