diff options
author | Robin Watts <robin.watts@artifex.com> | 2015-03-13 17:09:29 +0000 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2015-03-24 19:50:01 +0000 |
commit | 33c49228d078cc963ac5e59e526c97d2fd50a01f (patch) | |
tree | 233e29c78e497ca3b4d90bb3ea03ab846b61fbc6 /source/fitz/list-device.c | |
parent | 5f161e45d5daacb696d02b8fad23d0c23f5bc8bc (diff) | |
download | mupdf-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.c | 69 |
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) { |