summaryrefslogtreecommitdiff
path: root/source/fitz/list-device.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2015-03-13 17:09:29 +0000
committerRobin Watts <robin.watts@artifex.com>2015-03-24 19:50:01 +0000
commit33c49228d078cc963ac5e59e526c97d2fd50a01f (patch)
tree233e29c78e497ca3b4d90bb3ea03ab846b61fbc6 /source/fitz/list-device.c
parent5f161e45d5daacb696d02b8fad23d0c23f5bc8bc (diff)
downloadmupdf-33c49228d078cc963ac5e59e526c97d2fd50a01f.tar.xz
Path packing for memory efficiency.
Introduce the concept of 'packed' paths. These reduce the header overhead for most common paths (ones with less than 256 commands and 256 coords) to a single 32bit int once stored in the display list. The previous commit reduces the torture-test.pdf from 95 to 87Meg. This commit futher reduces it to 70Meg.
Diffstat (limited to 'source/fitz/list-device.c')
-rw-r--r--source/fitz/list-device.c69
1 files changed, 40 insertions, 29 deletions
diff --git a/source/fitz/list-device.c b/source/fitz/list-device.c
index 738499b1..038517b4 100644
--- a/source/fitz/list-device.c
+++ b/source/fitz/list-device.c
@@ -71,7 +71,7 @@ typedef enum fz_display_command_e
* flags: Flags (node specific meanings)
*
* Nodes are packed in the order:
- * header, rect, path, colorspace, color, alpha, ctm, stroke_state, private data.
+ * header, rect, colorspace, color, alpha, ctm, stroke_state, path, private data.
*/
struct fz_display_node_s
{
@@ -105,7 +105,9 @@ enum {
CTM_UNCHANGED = 0,
CTM_CHANGE_AD = 1,
CTM_CHANGE_BC = 2,
- CTM_CHANGE_EF = 4
+ CTM_CHANGE_EF = 4,
+
+ MAX_NODE_SIZE = (1<<9)-sizeof(fz_display_node)
};
struct fz_display_list_s
@@ -176,6 +178,7 @@ fz_append_display_node(
fz_path *my_path = NULL;
fz_stroke_state *my_stroke = NULL;
fz_rect local_rect;
+ int path_size = 0;
switch (cmd)
{
@@ -242,7 +245,7 @@ fz_append_display_node(
}
/* fallthrough */
default:
- if (writer->top > 0 && writer->tiled == 0 && writer->top <= STACK_SIZE)
+ if (writer->top > 0 && writer->tiled == 0 && writer->top <= STACK_SIZE && rect)
fz_union_rect(&writer->stack[writer->top-1].rect, rect);
break;
}
@@ -258,12 +261,6 @@ fz_append_display_node(
rect_off = size;
size += SIZE_IN_NODES(sizeof(fz_rect));
}
- if (path && (writer->path == NULL || path != writer->path))
- {
- node.path = 1;
- path_off = size;
- size += SIZE_IN_NODES(sizeof(fz_path *));
- }
if (color && !colorspace)
{
/* SoftMasks can omit a colorspace, but we know what they mean */
@@ -456,6 +453,15 @@ fz_append_display_node(
size += SIZE_IN_NODES(sizeof(fz_stroke_state *));
node.stroke = 1;
}
+ if (path && (writer->path == NULL || path != writer->path))
+ {
+ int max = SIZE_IN_NODES(MAX_NODE_SIZE) - size - SIZE_IN_NODES(private_data_len);
+ path_size = SIZE_IN_NODES(fz_pack_path(ctx, NULL, max, path));
+ node.path = 1;
+ path_off = size;
+
+ size += path_size;
+ }
if (private_data != NULL)
{
private_off = size;
@@ -480,12 +486,24 @@ fz_append_display_node(
if (writer->stack[i].update != NULL)
writer->stack[i].update = (fz_rect *)(((char *)writer->stack[i].update) + diff);
}
+ if (writer->path)
+ writer->path = (fz_path *)(((char *)writer->path) + diff);
}
+ /* Write the node to the list */
+ node.size = size;
+ node.flags = flags;
+ assert(size < (1<<9));
+ node_ptr = &list->list[list->len];
+ *node_ptr = node;
+
/* Path is the most frequent one, so try to avoid the try/catch in
* this case */
if (path_off)
- my_path = fz_keep_path(ctx, path);
+ {
+ my_path = (void *)(&node_ptr[path_off]);
+ (void)fz_pack_path(ctx, (void *)my_path, path_size * sizeof(fz_display_node), path);
+ }
if (stroke_off)
{
@@ -500,12 +518,6 @@ fz_append_display_node(
}
}
- /* Write the node to the list */
- node.size = size;
- node.flags = flags;
- assert(size < (1<<9));
- node_ptr = &list->list[list->len];
- *node_ptr = node;
if (rect_off)
{
fz_rect *out_rect = (fz_rect *)(void *)(&node_ptr[rect_off]);
@@ -516,8 +528,6 @@ fz_append_display_node(
}
if (path_off)
{
- fz_path **out_path = (fz_path **)(void *)(&node_ptr[path_off]);
- *out_path = my_path;
fz_drop_path(ctx, writer->path);
writer->path = fz_keep_path(ctx, my_path); /* Can never fail */
}
@@ -1282,11 +1292,6 @@ fz_drop_display_list_imp(fz_context *ctx, fz_storable *list_)
{
node += SIZE_IN_NODES(sizeof(fz_rect));
}
- if (n.path)
- {
- fz_drop_path(ctx, *(fz_path **)node);
- node += SIZE_IN_NODES(sizeof(fz_path *));
- }
switch (n.cs)
{
default:
@@ -1329,6 +1334,12 @@ fz_drop_display_list_imp(fz_context *ctx, fz_storable *list_)
fz_drop_stroke_state(ctx, *(fz_stroke_state **)node);
node += SIZE_IN_NODES(sizeof(fz_stroke_state *));
}
+ if (n.path)
+ {
+ int path_size = fz_packed_path_size((fz_path *)node);
+ fz_drop_path(ctx, (fz_path *)node);
+ node += SIZE_IN_NODES(path_size);
+ }
switch(n.cmd)
{
case FZ_CMD_FILL_TEXT:
@@ -1435,12 +1446,6 @@ fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, cons
rect = *(fz_rect *)node;
node += SIZE_IN_NODES(sizeof(fz_rect));
}
- if (n.path)
- {
- fz_drop_path(ctx, path);
- path = fz_keep_path(ctx, *(fz_path **)node);
- node += SIZE_IN_NODES(sizeof(fz_path *));
- }
if (n.cs)
{
int i;
@@ -1541,6 +1546,12 @@ fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, cons
stroke = fz_keep_stroke_state(ctx, *(fz_stroke_state **)node);
node += SIZE_IN_NODES(sizeof(fz_stroke_state *));
}
+ if (n.path)
+ {
+ fz_drop_path(ctx, path);
+ path = fz_keep_path(ctx, (fz_path *)node);
+ node += SIZE_IN_NODES(fz_packed_path_size(path));
+ }
if (tile_skip_depth > 0)
{