mirror of
https://github.com/reactos/reactos.git
synced 2024-10-31 03:48:17 +00:00
435a566751
* sumatrapdf - vendor import * everything compiles (libjpeg, poppler, fitz, sumatrapdf) * does NOT link (remove the comment tags in the parent directory.rbuild file (rosapps dir) to build it) svn path=/trunk/; revision=29295
315 lines
5.9 KiB
C
315 lines
5.9 KiB
C
#include "fitz-base.h"
|
|
#include "fitz-world.h"
|
|
|
|
/*
|
|
* Remove (mask ... white) until we get something not white
|
|
*/
|
|
|
|
static int iswhitenode(fz_solidnode *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_issolidnode(current))
|
|
{
|
|
if (!iswhitenode((fz_solidnode*)current))
|
|
return 1;
|
|
}
|
|
|
|
else if (fz_ismasknode(current))
|
|
{
|
|
shape = current->first;
|
|
color = shape->next;
|
|
if (fz_issolidnode(color))
|
|
{
|
|
if (iswhitenode((fz_solidnode*)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->x0 = MIN(x, x + w);
|
|
bboxp->y0 = MIN(y, y + h);
|
|
bboxp->x1 = MAX(x, x + w);
|
|
bboxp->y1 = 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.x0 < clip.x0) return 0;
|
|
if (bbox.x1 > clip.x1) return 0;
|
|
if (bbox.y0 < clip.y0) return 0;
|
|
if (bbox.y1 > clip.y1) 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 (!current)
|
|
break;
|
|
|
|
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_newsolidnode(&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;
|
|
}
|
|
|