diff options
author | Robin Watts <robin.watts@artifex.com> | 2015-02-17 18:18:34 +0000 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2015-02-20 15:04:47 +0000 |
commit | e9411aba2b71b67b8521f55917ab26585c464b88 (patch) | |
tree | 37fbd99f2f6cc2e93d66a761deeb245b61207621 /source/fitz | |
parent | 4fcc4fecd19b793591dd17d77217881db2f75cf6 (diff) | |
download | mupdf-e9411aba2b71b67b8521f55917ab26585c464b88.tar.xz |
Rejig display device to have a more compact memory representation.
Rather than a linked list of display nodes, we use solid block of
serialised data. We send a 32bit word, which contains various bitfields.
These bitfields indicate the command type, and the presence or absence
of various fields (such as paths, colorspaces, colors etc).
If these fields are not present, they are held to be the same as the
previous values.
Diffstat (limited to 'source/fitz')
-rw-r--r-- | source/fitz/list-device.c | 1576 |
1 files changed, 1223 insertions, 353 deletions
diff --git a/source/fitz/list-device.c b/source/fitz/list-device.c index 72a63ef4..3dbfb9e2 100644 --- a/source/fitz/list-device.c +++ b/source/fitz/list-device.c @@ -1,12 +1,7 @@ #include "mupdf/fitz.h" typedef struct fz_display_node_s fz_display_node; - -typedef struct fz_list_device_s -{ - fz_device super; - fz_display_list *list; -} fz_list_device; +typedef struct fz_list_device_s fz_list_device; #define STACK_SIZE 96 @@ -36,32 +31,104 @@ typedef enum fz_display_command_e FZ_CMD_END_TILE } fz_display_command; +/* The display list is a list of nodes. + * Each node is a structure consisting of a bitfield (that packs into a + * 32 bit word). + * The different fields in the bitfield identify what information is + * present in the node. + * + * cmd: What type of node this is. + * + * size: The number of sizeof(fz_display_node) bytes that this nodes + * data occupies. (i.e. &node[node->size] = the next node in the + * chain; 0 for end of list). + * + * rect: 0 for unchanged, 1 for present. + * + * path: 0 for unchanged, 1 for present. + * + * cs: 0 for unchanged + * 1 for devicegray (color defaults to 0) + * 2 for devicegray (color defaults to 1) + * 3 for devicergb (color defaults to 0,0,0) + * 4 for devicergb (color defaults to 1,1,1) + * 5 for devicecmyk (color defaults to 0,0,0,0) + * 6 for devicecmyk (color defaults to 0,0,0,1) + * 7 for present (color defaults to 0) + * + * color: 0 for unchanged color, 1 for present. + * + * alpha: 0 for unchanged, 1 for solid, 2 for transparent, 3 + * for alpha value present. + * + * ctm: 0 for unchanged, + * 1 for change ad + * 2 for change bc + * 4 for change ef. + * + * stroke: 0 for unchanged, 1 for present. + * + * flags: Flags (node specific meanings) + * + * Nodes are packed in the order: + * header, rect, path, colorspace, color, alpha, ctm, stroke_state, private data. + */ struct fz_display_node_s { - fz_display_command cmd; - fz_display_node *next; - fz_rect rect; - union { - fz_path *path; - fz_text *text; - fz_shade *shade; - fz_image *image; - int blendmode; - } item; - fz_stroke_state *stroke; - int flag; /* even_odd, accumulate, isolated/knockout... */ - fz_matrix ctm; - fz_colorspace *colorspace; - float alpha; - float color[FZ_MAX_COLORS]; + unsigned int cmd : 5; + unsigned int size : 9; + unsigned int rect : 1; + unsigned int path : 1; + unsigned int cs : 3; + unsigned int color : 1; + unsigned int alpha : 2; + unsigned int ctm : 3; + unsigned int stroke : 1; + unsigned int flags : 6; +}; + +enum { + CS_UNCHANGED = 0, + CS_GRAY_0 = 1, + CS_GRAY_1 = 2, + CS_RGB_0 = 3, + CS_RGB_1 = 4, + CS_CMYK_0 = 5, + CS_CMYK_1 = 6, + CS_OTHER_0 = 7, + + ALPHA_UNCHANGED = 0, + ALPHA_1 = 1, + ALPHA_0 = 2, + ALPHA_PRESENT = 3, + + CTM_UNCHANGED = 0, + CTM_CHANGE_AD = 1, + CTM_CHANGE_BC = 2, + CTM_CHANGE_EF = 4 }; struct fz_display_list_s { fz_storable storable; - fz_display_node *first; - fz_display_node *last; + fz_display_node *list; + int max; int len; +}; + +struct fz_list_device_s +{ + fz_device super; + + fz_display_list *list; + + fz_path *path; + float alpha; + fz_matrix ctm; + fz_stroke_state *stroke; + fz_colorspace *colorspace; + float color[FZ_MAX_COLORS]; + fz_rect rect; int top; struct { @@ -73,488 +140,1081 @@ struct fz_display_list_s enum { ISOLATED = 1, KNOCKOUT = 2 }; -static fz_display_node * -fz_new_display_node(fz_context *ctx, fz_display_command cmd, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) -{ - fz_display_node *node; - int i; - - node = fz_malloc_struct(ctx, fz_display_node); - node->cmd = cmd; - node->next = NULL; - node->rect = fz_empty_rect; - node->item.path = NULL; - node->stroke = NULL; - node->flag = (cmd == FZ_CMD_BEGIN_TILE ? fz_gen_id(ctx) : 0); - node->ctm = *ctm; - if (colorspace) - { - node->colorspace = fz_keep_colorspace(ctx, colorspace); - if (color) - { - for (i = 0; i < node->colorspace->n; i++) - node->color[i] = color[i]; - } - } - else - { - node->colorspace = NULL; - } - node->alpha = alpha; - - return node; -} +#define SIZE_IN_NODES(t) \ + ((t + sizeof(fz_display_node) - 1) / sizeof(fz_display_node)) static void -fz_append_display_node(fz_context *ctx, fz_device *dev_, fz_display_node *node) +fz_append_display_node( + fz_context *ctx, + fz_device *dev, + fz_display_command cmd, + int flags, + const fz_rect *rect, + fz_path *path, + float *color, + fz_colorspace *colorspace, + float *alpha, + const fz_matrix *ctm, + fz_stroke_state *stroke, + void *private_data, + int private_data_len) { - fz_list_device *dev = (fz_list_device*)dev_; - fz_display_list *list = dev->list; - - switch (node->cmd) + fz_display_node node = { 0 }; + fz_display_node *node_ptr; + fz_list_device *writer = (fz_list_device *)dev; + fz_display_list *list = writer->list; + int size; + int rect_off = 0; + int path_off = 0; + int color_off = 0; + int colorspace_off = 0; + int alpha_off = 0; + int ctm_off = 0; + int stroke_off = 0; + int rect_for_updates = 0; + int private_off = 0; + fz_path *my_path = NULL; + fz_stroke_state *my_stroke = NULL; + fz_rect local_rect; + + switch (cmd) { case FZ_CMD_CLIP_PATH: case FZ_CMD_CLIP_STROKE_PATH: case FZ_CMD_CLIP_IMAGE_MASK: - if (list->top < STACK_SIZE) + if (writer->top < STACK_SIZE) { - list->stack[list->top].update = &node->rect; - list->stack[list->top].rect = fz_empty_rect; + rect_for_updates = 1; + writer->stack[writer->top].rect = fz_empty_rect; } - list->top++; + writer->top++; break; case FZ_CMD_CLIP_TEXT: /* don't reset the clip rect for accumulated text */ - if (node->flag == 2) + if (flags == 2) break; /* fallthrough */ case FZ_CMD_END_MASK: case FZ_CMD_CLIP_STROKE_TEXT: - if (list->top < STACK_SIZE) + if (writer->top < STACK_SIZE) { - list->stack[list->top].update = NULL; - list->stack[list->top].rect = fz_empty_rect; + writer->stack[writer->top].update = NULL; + writer->stack[writer->top].rect = fz_empty_rect; } - list->top++; + writer->top++; break; case FZ_CMD_BEGIN_TILE: - list->tiled++; - if (list->top > 0 && list->top <= STACK_SIZE) + writer->tiled++; + if (writer->top > 0 && writer->top <= STACK_SIZE) { - list->stack[list->top-1].rect = fz_infinite_rect; + writer->stack[writer->top-1].rect = fz_infinite_rect; } break; case FZ_CMD_END_TILE: - list->tiled--; + writer->tiled--; break; case FZ_CMD_END_GROUP: break; case FZ_CMD_POP_CLIP: - if (list->top > STACK_SIZE) + if (writer->top > STACK_SIZE) { - list->top--; - node->rect = fz_infinite_rect; + writer->top--; + rect = &fz_infinite_rect; } - else if (list->top > 0) + else if (writer->top > 0) { fz_rect *update; - list->top--; - update = list->stack[list->top].update; - if (list->tiled == 0) + writer->top--; + update = writer->stack[writer->top].update; + if (writer->tiled == 0) { if (update) { - fz_intersect_rect(update, &list->stack[list->top].rect); - node->rect = *update; + fz_intersect_rect(update, &writer->stack[writer->top].rect); + local_rect = *update; + rect = &local_rect; } else - node->rect = list->stack[list->top].rect; + rect = &writer->stack[writer->top].rect; } else - node->rect = fz_infinite_rect; + rect = &fz_infinite_rect; } /* fallthrough */ default: - if (list->top > 0 && list->tiled == 0 && list->top <= STACK_SIZE) - fz_union_rect(&list->stack[list->top-1].rect, &node->rect); + if (writer->top > 0 && writer->tiled == 0 && writer->top <= STACK_SIZE) + fz_union_rect(&writer->stack[writer->top-1].rect, rect); break; } - if (!list->first) + + size = 1; /* 1 for the fz_display_node */ + node.cmd = cmd; + + /* Figure out what we need to write, and the offsets at which we will + * write it. */ + if (rect_for_updates || (rect != NULL && (writer->rect.x0 != rect->x0 || writer->rect.y0 != rect->y0 || writer->rect.x1 != rect->x1 || writer->rect.y1 != rect->y1))) { - list->first = node; - list->last = node; + node.rect = 1; + rect_off = size; + size += SIZE_IN_NODES(sizeof(fz_rect)); } - else + if (path && (writer->path == NULL || path != writer->path)) { - list->last->next = node; - list->last = node; + node.path = 1; + path_off = size; + size += SIZE_IN_NODES(sizeof(fz_path *)); } - list->len++; -} + if (color && !colorspace) + { + /* SoftMasks can omit a colorspace, but we know what they mean */ + colorspace = fz_device_gray(ctx); + } + if (colorspace) + { + if (colorspace != writer->colorspace) + { + assert(color); + if (colorspace == fz_device_gray(ctx)) + { + if (color[0] == 0.0f) + node.cs = CS_GRAY_0, color = NULL; + else + { + node.cs = CS_GRAY_1; + if (color[0] == 1.0f) + color = NULL; + } + } + else if (colorspace == fz_device_rgb(ctx)) + { + if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f) + node.cs = CS_RGB_0, color = NULL; + else + { + node.cs = CS_RGB_1; + if (color[0] == 1.0f && color[1] == 1.0f && color[2] == 1.0f) + color = NULL; + } + } + else if (colorspace == fz_device_cmyk(ctx)) + { + node.cs = CS_CMYK_0; + if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f) + { + if (color[3] == 0.0f) + color = NULL; + else + { + node.cs = CS_CMYK_1; + if (color[3] == 1.0f) + color = NULL; + } + } + } + else + { + int i; + int n = colorspace->n; + + colorspace_off = size; + size += SIZE_IN_NODES(sizeof(fz_colorspace *)); + node.cs = CS_OTHER_0; + for (i = 0; i < n; i++) + if (color[i] != 0.0f) + break; + if (i == n) + color = NULL; + memset(writer->color, 0, sizeof(float)*n); + } + } + else + { + /* Colorspace is unchanged, but color may have changed + * to something best coded as a colorspace change */ + if (colorspace == fz_device_gray(ctx)) + { + if (writer->color[0] != color[0]) + { + if (color[0] == 0.0f) + { + node.cs = CS_GRAY_0; + color = NULL; + } + else if (color[0] == 1.0f) + { + node.cs = CS_GRAY_1; + color = NULL; + } + } + } + else if (colorspace == fz_device_rgb(ctx)) + { + if (writer->color[0] != color[0] || writer->color[1] != color[1] || writer->color[2] != color[2]) + { + if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f) + { + node.cs = CS_RGB_0; + color = NULL; + } + else if (color[0] == 1.0f && color[1] == 1.0f && color[2] == 1.0f) + { + node.cs = CS_RGB_1; + color = NULL; + } + } + } + else if (colorspace == fz_device_cmyk(ctx)) + { + if (writer->color[0] != color[0] || writer->color[1] != color[1] || writer->color[2] != color[2] || writer->color[3] != color[3]) + { + if (color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f) + { + if (color[3] == 0.0f) + { + node.cs = CS_CMYK_0; + color = NULL; + } + else if (color[3] == 1.0f) + { + node.cs = CS_CMYK_1; + color = NULL; + } + } + } + } + else + { + int i; + int n = colorspace->n; + for (i=0; i < n; i++) + if (color[i] != 0.0f) + break; + if (i == n) + { + node.cs = CS_OTHER_0; + colorspace_off = size; + size += SIZE_IN_NODES(sizeof(fz_colorspace *)); + color = NULL; + } + } + } + } + if (color) + { -static void -fz_free_display_node(fz_context *ctx, fz_display_node *node) -{ - switch (node->cmd) + int i, n = colorspace->n; + const float *wc = &writer->color[0]; + + i = 0; + /* Only check colors if the colorspace is unchanged. If the + * colorspace *has* changed and the colors are implicit then + * this will have been caught above. */ + if (colorspace == writer->colorspace) + for (; i < n; i++) + if (color[i] != wc[i]) + break; + + if (i != n) + { + node.color = 1; + color_off = size; + size += n * SIZE_IN_NODES(sizeof(float)); + } + } + if (alpha && (*alpha != writer->alpha)) { - case FZ_CMD_FILL_PATH: - case FZ_CMD_STROKE_PATH: - case FZ_CMD_CLIP_PATH: - case FZ_CMD_CLIP_STROKE_PATH: - fz_drop_path(ctx, node->item.path); - break; - case FZ_CMD_FILL_TEXT: - case FZ_CMD_STROKE_TEXT: - case FZ_CMD_CLIP_TEXT: - case FZ_CMD_CLIP_STROKE_TEXT: - case FZ_CMD_IGNORE_TEXT: - fz_drop_text(ctx, node->item.text); - break; - case FZ_CMD_FILL_SHADE: - fz_drop_shade(ctx, node->item.shade); - break; - case FZ_CMD_FILL_IMAGE: - case FZ_CMD_FILL_IMAGE_MASK: - case FZ_CMD_CLIP_IMAGE_MASK: - fz_drop_image(ctx, node->item.image); - break; - case FZ_CMD_POP_CLIP: - case FZ_CMD_BEGIN_MASK: - case FZ_CMD_END_MASK: - case FZ_CMD_BEGIN_GROUP: - case FZ_CMD_END_GROUP: - case FZ_CMD_BEGIN_TILE: - case FZ_CMD_END_TILE: - case FZ_CMD_BEGIN_PAGE: - case FZ_CMD_END_PAGE: - break; + if (*alpha >= 1.0) + node.alpha = ALPHA_1; + else if (*alpha <= 0.0) + node.alpha = ALPHA_0; + else + { + alpha_off = size; + size += SIZE_IN_NODES(sizeof(float)); + node.alpha = ALPHA_PRESENT; + } + } + if (ctm && (ctm->a != writer->ctm.a || ctm->b != writer->ctm.b || ctm->c != writer->ctm.c || ctm->d != writer->ctm.d || ctm->e != writer->ctm.e || ctm->f != writer->ctm.f)) + { + int flags; + + ctm_off = size; + flags = CTM_UNCHANGED; + if (ctm->a != writer->ctm.a || ctm->d != writer->ctm.d) + flags = CTM_CHANGE_AD, size += SIZE_IN_NODES(2*sizeof(float)); + if (ctm->b != writer->ctm.b || ctm->c != writer->ctm.c) + flags |= CTM_CHANGE_BC, size += SIZE_IN_NODES(2*sizeof(float)); + if (ctm->e != writer->ctm.e || ctm->f != writer->ctm.f) + flags |= CTM_CHANGE_EF, size += SIZE_IN_NODES(2*sizeof(float)); + node.ctm = flags; + } + if (stroke && (writer->stroke == NULL || stroke != writer->stroke)) + { + stroke_off = size; + size += SIZE_IN_NODES(sizeof(fz_stroke_state *)); + node.stroke = 1; + } + if (private_data != NULL) + { + private_off = size; + size += SIZE_IN_NODES(private_data_len); + } + + if (list->len + size > list->max) + { + int newsize = list->max * 2; + fz_display_node *old = list->list; + ptrdiff_t diff; + int i, n; + + if (newsize < 256) + newsize = 256; + list->list = fz_resize_array(ctx, list->list, newsize, sizeof(fz_display_node)); + list->max = newsize; + diff = (char *)(list->list) - (char *)old; + n = (writer->top < STACK_SIZE ? writer->top : STACK_SIZE); + for (i = 0; i < n; i++) + { + if (writer->stack[i].update != NULL) + writer->stack[i].update = (fz_rect *)(((char *)writer->stack[i].update) + diff); + } + } + + /* 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); + + if (stroke_off) + { + fz_try(ctx) + { + my_stroke = fz_keep_stroke_state(ctx, stroke); + } + fz_catch(ctx) + { + fz_drop_path(ctx, my_path); + fz_rethrow(ctx); + } + } + + /* 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]); + writer->rect = *rect; + *out_rect = *rect; + if (rect_for_updates) + writer->stack[writer->top-1].update = out_rect; + } + 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 */ + } + if (node.cs) + { + fz_drop_colorspace(ctx, writer->colorspace); + switch(node.cs) + { + case CS_GRAY_0: + writer->colorspace = fz_device_gray(ctx); + writer->color[0] = 0; + break; + case CS_GRAY_1: + writer->colorspace = fz_device_gray(ctx); + writer->color[0] = 1; + break; + case CS_RGB_0: + writer->color[0] = 0; + writer->color[1] = 0; + writer->color[2] = 0; + writer->colorspace = fz_device_rgb(ctx); + break; + case CS_RGB_1: + writer->color[0] = 1; + writer->color[1] = 1; + writer->color[2] = 1; + writer->colorspace = fz_device_rgb(ctx); + break; + case CS_CMYK_0: + writer->color[0] = 0; + writer->color[1] = 0; + writer->color[2] = 0; + writer->color[3] = 0; + writer->colorspace = fz_device_cmyk(ctx); + break; + case CS_CMYK_1: + writer->color[0] = 0; + writer->color[1] = 0; + writer->color[2] = 0; + writer->color[3] = 1; + writer->colorspace = fz_device_cmyk(ctx); + break; + default: + { + fz_colorspace **out_colorspace = (fz_colorspace **)(void *)(&node_ptr[colorspace_off]); + int i, n = colorspace->n; + *out_colorspace = fz_keep_colorspace(ctx, colorspace); + + writer->colorspace = fz_keep_colorspace(ctx, colorspace); + for (i = 0; i < n; i++) + writer->color[i] = 0; + break; + } + } + } + if (color_off) + { + float *out_color = (float *)(void *)(&node_ptr[color_off]); + memcpy(writer->color, color, colorspace->n * sizeof(float)); + memcpy(out_color, color, colorspace->n * sizeof(float)); + } + if (node.alpha) + { + writer->alpha = *alpha; + if (alpha_off) + { + float *out_alpha = (float *)(void *)(&node_ptr[alpha_off]); + *out_alpha = *alpha; + } + } + if (ctm_off) + { + float *out_ctm = (float *)(void *)(&node_ptr[ctm_off]); + if (node.ctm & CTM_CHANGE_AD) + { + writer->ctm.a = *out_ctm++ = ctm->a; + writer->ctm.d = *out_ctm++ = ctm->d; + } + if (node.ctm & CTM_CHANGE_BC) + { + writer->ctm.b = *out_ctm++ = ctm->b; + writer->ctm.c = *out_ctm++ = ctm->c; + } + if (node.ctm & CTM_CHANGE_EF) + { + writer->ctm.e = *out_ctm++ = ctm->e; + writer->ctm.f = *out_ctm++ = ctm->f; + } + } + if (stroke_off) + { + fz_stroke_state **out_stroke = (fz_stroke_state **)(void *)(&node_ptr[stroke_off]); + *out_stroke = my_stroke; + fz_drop_stroke_state(ctx, writer->stroke); + /* Can never fail as my_stroke was kept above */ + writer->stroke = fz_keep_stroke_state(ctx, my_stroke); + } + if (private_off) + { + char *out_private = (char *)(void *)(&node_ptr[private_off]); + memcpy(out_private, private_data, private_data_len); } - if (node->stroke) - fz_drop_stroke_state(ctx, node->stroke); - if (node->colorspace) - fz_drop_colorspace(ctx, node->colorspace); - fz_free(ctx, node); + list->len += size; } static void fz_list_begin_page(fz_context *ctx, fz_device *dev, const fz_rect *mediabox, const fz_matrix *ctm) { - fz_display_node *node = fz_new_display_node(ctx, FZ_CMD_BEGIN_PAGE, ctm, NULL, NULL, 0); - node->rect = *mediabox; - fz_transform_rect(&node->rect, ctm); - fz_append_display_node(ctx, dev, node); + fz_rect rect = *mediabox; + + fz_transform_rect(&rect, ctm); + fz_append_display_node( + ctx, + dev, + FZ_CMD_BEGIN_PAGE, + 0, /* flags */ + &rect, + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + ctm, + NULL, /* stroke_state */ + NULL, /* private_data */ + 0); /* private_data_len */ } static void fz_list_end_page(fz_context *ctx, fz_device *dev) { - fz_display_node *node = fz_new_display_node(ctx, FZ_CMD_END_PAGE, &fz_identity, NULL, NULL, 0); - fz_append_display_node(ctx, dev, node); + fz_append_display_node( + ctx, + dev, + FZ_CMD_END_PAGE, + 0, /* flags */ + NULL, /* rect */ + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + NULL, /* ctm */ + NULL, /* stroke_state */ + NULL, /* private_data */ + 0); /* private_data_len */ } static void fz_list_fill_path(fz_context *ctx, fz_device *dev, fz_path *path, int even_odd, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_FILL_PATH, ctm, colorspace, color, alpha); - fz_try(ctx) - { - fz_bound_path(ctx, path, NULL, ctm, &node->rect); - node->item.path = fz_keep_path(ctx, path); - node->flag = even_odd; - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(ctx, dev, node); + fz_rect rect; + + fz_bound_path(ctx, path, NULL, ctm, &rect); + fz_append_display_node( + ctx, + dev, + FZ_CMD_FILL_PATH, + even_odd, /* flags */ + &rect, + path, /* path */ + color, + colorspace, + &alpha, /* alpha */ + ctm, + NULL, /* stroke_state */ + NULL, /* private_data */ + 0); /* private_data_len */ } static void fz_list_stroke_path(fz_context *ctx, fz_device *dev, fz_path *path, fz_stroke_state *stroke, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_STROKE_PATH, ctm, colorspace, color, alpha); - fz_try(ctx) - { - fz_bound_path(ctx, path, stroke, ctm, &node->rect); - node->item.path = fz_keep_path(ctx, path); - node->stroke = fz_keep_stroke_state(ctx, stroke); - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(ctx, dev, node); + fz_rect rect; + + fz_bound_path(ctx, path, stroke, ctm, &rect); + fz_append_display_node( + ctx, + dev, + FZ_CMD_STROKE_PATH, + 0, /* flags */ + &rect, + path, /* path */ + color, + colorspace, + &alpha, /* alpha */ + ctm, /* ctm */ + stroke, + NULL, /* private_data */ + 0); /* private_data_len */ } static void fz_list_clip_path(fz_context *ctx, fz_device *dev, fz_path *path, const fz_rect *rect, int even_odd, const fz_matrix *ctm) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_CLIP_PATH, ctm, NULL, NULL, 0); - fz_try(ctx) - { - fz_bound_path(ctx, path, NULL, ctm, &node->rect); - if (rect) - fz_intersect_rect(&node->rect, rect); - node->item.path = fz_keep_path(ctx, path); - node->flag = even_odd; - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(ctx, dev, node); + fz_rect rect2; + + fz_bound_path(ctx, path, NULL, ctm, &rect2); + if (rect) + fz_intersect_rect(&rect2, rect); + fz_append_display_node( + ctx, + dev, + FZ_CMD_CLIP_PATH, + even_odd, /* flags */ + &rect2, + path, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + ctm, /* ctm */ + NULL, /* stroke */ + NULL, /* private_data */ + 0); /* private_data_len */ } static void fz_list_clip_stroke_path(fz_context *ctx, fz_device *dev, fz_path *path, const fz_rect *rect, fz_stroke_state *stroke, const fz_matrix *ctm) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_CLIP_STROKE_PATH, ctm, NULL, NULL, 0); - fz_try(ctx) - { - fz_bound_path(ctx, path, stroke, ctm, &node->rect); - if (rect) - fz_intersect_rect(&node->rect, rect); - node->item.path = fz_keep_path(ctx, path); - node->stroke = fz_keep_stroke_state(ctx, stroke); - } - fz_catch(ctx) - { - fz_free_display_node(ctx, node); - fz_rethrow(ctx); - } - fz_append_display_node(ctx, dev, node); + fz_rect rect2; + + fz_bound_path(ctx, path, stroke, ctm, &rect2); + if (rect) + fz_intersect_rect(&rect2, rect); + fz_append_display_node( + ctx, + dev, + FZ_CMD_CLIP_STROKE_PATH, + 0, /* flags */ + &rect2, + path, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + ctm, /* ctm */ + stroke, /* stroke */ + NULL, /* private_data */ + 0); /* private_data_len */ } static void fz_list_fill_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_FILL_TEXT, ctm, colorspace, color, alpha); + fz_rect rect; + fz_text *cloned_text = fz_keep_text(ctx, text); + fz_try(ctx) { - fz_bound_text(ctx, text, NULL, ctm, &node->rect); - node->item.text = fz_keep_text(ctx, text); + fz_bound_text(ctx, text, NULL, ctm, &rect); + fz_append_display_node( + ctx, + dev, + FZ_CMD_FILL_TEXT, + 0, /* flags */ + &rect, + NULL, /* path */ + color, /* color */ + colorspace, /* colorspace */ + &alpha, /* alpha */ + ctm, /* ctm */ + NULL, /* stroke */ + &cloned_text, /* private_data */ + sizeof(cloned_text)); /* private_data_len */ } fz_catch(ctx) { - fz_free_display_node(ctx, node); + fz_drop_text(ctx, cloned_text); fz_rethrow(ctx); } - fz_append_display_node(ctx, dev, node); } static void fz_list_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_STROKE_TEXT, ctm, colorspace, color, alpha); - node->item.text = NULL; + fz_rect rect; + fz_text *cloned_text = fz_keep_text(ctx, text); + fz_try(ctx) { - fz_bound_text(ctx, text, stroke, ctm, &node->rect); - node->item.text = fz_keep_text(ctx, text); - node->stroke = fz_keep_stroke_state(ctx, stroke); + fz_bound_text(ctx, text, stroke, ctm, &rect); + fz_append_display_node( + ctx, + dev, + FZ_CMD_STROKE_TEXT, + 0, /* flags */ + &rect, + NULL, /* path */ + color, /* color */ + colorspace, /* colorspace */ + &alpha, /* alpha */ + ctm, /* ctm */ + stroke, + &cloned_text, /* private_data */ + sizeof(cloned_text)); /* private_data_len */ } fz_catch(ctx) { - fz_free_display_node(ctx, node); + fz_drop_text(ctx, cloned_text); fz_rethrow(ctx); } - fz_append_display_node(ctx, dev, node); } static void fz_list_clip_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm, int accumulate) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_CLIP_TEXT, ctm, NULL, NULL, 0); + fz_rect rect; + fz_text *cloned_text = fz_keep_text(ctx, text); + fz_try(ctx) { - fz_bound_text(ctx, text, NULL, ctm, &node->rect); - node->item.text = fz_keep_text(ctx, text); - node->flag = accumulate; - /* when accumulating, be conservative about culling */ if (accumulate) - node->rect = fz_infinite_rect; + rect = fz_infinite_rect; + else + fz_bound_text(ctx, text, NULL, ctm, &rect); + fz_append_display_node( + ctx, + dev, + FZ_CMD_CLIP_TEXT, + accumulate, /* flags */ + &rect, + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + ctm, /* ctm */ + NULL, /* stroke */ + &cloned_text, /* private_data */ + sizeof(cloned_text)); /* private_data_len */ } fz_catch(ctx) { - fz_free_display_node(ctx, node); + fz_drop_text(ctx, cloned_text); fz_rethrow(ctx); } - fz_append_display_node(ctx, dev, node); } static void fz_list_clip_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_CLIP_STROKE_TEXT, ctm, NULL, NULL, 0); + fz_rect rect; + fz_text *cloned_text = fz_keep_text(ctx, text); + fz_try(ctx) { - fz_bound_text(ctx, text, stroke, ctm, &node->rect); - node->item.text = fz_keep_text(ctx, text); - node->stroke = fz_keep_stroke_state(ctx, stroke); + fz_bound_text(ctx, text, stroke, ctm, &rect); + fz_append_display_node( + ctx, + dev, + FZ_CMD_CLIP_STROKE_TEXT, + 0, /* flags */ + &rect, + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + ctm, /* ctm */ + stroke, /* stroke */ + &cloned_text, /* private_data */ + sizeof(cloned_text)); /* private_data_len */ } fz_catch(ctx) { - fz_free_display_node(ctx, node); + fz_drop_text(ctx, cloned_text); fz_rethrow(ctx); } - fz_append_display_node(ctx, dev, node); } static void fz_list_ignore_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_IGNORE_TEXT, ctm, NULL, NULL, 0); + fz_rect rect; + fz_text *cloned_text = fz_keep_text(ctx, text); + fz_try(ctx) { - fz_bound_text(ctx, text, NULL, ctm, &node->rect); - node->item.text = fz_keep_text(ctx, text); + fz_bound_text(ctx, text, NULL, ctm, &rect); + fz_append_display_node( + ctx, + dev, + FZ_CMD_IGNORE_TEXT, + 0, /* flags */ + &rect, + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + ctm, /* ctm */ + NULL, /* stroke */ + &cloned_text, /* private_data */ + sizeof(cloned_text)); /* private_data_len */ } fz_catch(ctx) { - fz_free_display_node(ctx, node); + fz_drop_text(ctx, cloned_text); fz_rethrow(ctx); } - fz_append_display_node(ctx, dev, node); } static void fz_list_pop_clip(fz_context *ctx, fz_device *dev) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_POP_CLIP, &fz_identity, NULL, NULL, 0); - fz_append_display_node(ctx, dev, node); + fz_append_display_node( + ctx, + dev, + FZ_CMD_POP_CLIP, + 0, /* flags */ + NULL, /* rect */ + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + NULL, /* ctm */ + NULL, /* stroke */ + NULL, /* private_data */ + 0); /* private_data_len */ } static void fz_list_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_FILL_SHADE, ctm, NULL, NULL, alpha); - fz_bound_shade(ctx, shade, ctm, &node->rect); - node->item.shade = fz_keep_shade(ctx, shade); - fz_append_display_node(ctx, dev, node); + fz_shade *shade2 = fz_keep_shade(ctx, shade); + fz_rect rect; + + fz_try(ctx) + { + fz_bound_shade(ctx, shade, ctm, &rect); + fz_append_display_node( + ctx, + dev, + FZ_CMD_FILL_SHADE, + 0, /* flags */ + &rect, + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + &alpha, /* alpha */ + ctm, + NULL, /* stroke */ + &shade2, /* private_data */ + sizeof(shade2)); /* private_data_len */ + } + fz_catch(ctx) + { + fz_drop_shade(ctx, shade2); + fz_rethrow(ctx); + } } static void fz_list_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_FILL_IMAGE, ctm, NULL, NULL, alpha); - node->rect = fz_unit_rect; - fz_transform_rect(&node->rect, ctm); - node->item.image = fz_keep_image(ctx, image); - fz_append_display_node(ctx, dev, node); + fz_image *image2 = fz_keep_image(ctx, image); + fz_rect rect = fz_unit_rect; + + fz_try(ctx) + { + fz_transform_rect(&rect, ctm); + fz_append_display_node( + ctx, + dev, + FZ_CMD_FILL_IMAGE, + 0, /* flags */ + &rect, + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + &alpha, /* alpha */ + ctm, + NULL, /* stroke */ + &image2, /* private_data */ + sizeof(image2)); /* private_data_len */ + } + fz_catch(ctx) + { + fz_drop_image(ctx, image2); + fz_rethrow(ctx); + } } static void fz_list_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_FILL_IMAGE_MASK, ctm, colorspace, color, alpha); - node->rect = fz_unit_rect; - fz_transform_rect(&node->rect, ctm); - node->item.image = fz_keep_image(ctx, image); - fz_append_display_node(ctx, dev, node); + fz_image *image2 = fz_keep_image(ctx, image); + fz_rect rect = fz_unit_rect; + + fz_try(ctx) + { + fz_transform_rect(&rect, ctm); + fz_append_display_node( + ctx, + dev, + FZ_CMD_FILL_IMAGE_MASK, + 0, /* flags */ + &rect, + NULL, /* path */ + color, + colorspace, + &alpha, /* alpha */ + ctm, + NULL, /* stroke */ + &image2, /* private_data */ + sizeof(image2)); /* private_data_len */ + } + fz_catch(ctx) + { + fz_drop_image(ctx, image2); + fz_rethrow(ctx); + } } static void fz_list_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_rect *rect, const fz_matrix *ctm) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_CLIP_IMAGE_MASK, ctm, NULL, NULL, 0); - node->rect = fz_unit_rect; - fz_transform_rect(&node->rect, ctm); + fz_image *image2 = fz_keep_image(ctx, image); + fz_rect rect2 = fz_unit_rect; + + fz_transform_rect(&rect2, ctm); if (rect) - fz_intersect_rect(&node->rect, rect); - node->item.image = fz_keep_image(ctx, image); - fz_append_display_node(ctx, dev, node); + fz_intersect_rect(&rect2, rect); + fz_try(ctx) + { + fz_append_display_node( + ctx, + dev, + FZ_CMD_CLIP_IMAGE_MASK, + 0, /* flags */ + &rect2, + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + ctm, + NULL, /* stroke */ + &image2, /* private_data */ + sizeof(image2)); /* private_data_len */ + } + fz_catch(ctx) + { + fz_drop_image(ctx, image2); + fz_rethrow(ctx); + } } static void fz_list_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *rect, int luminosity, fz_colorspace *colorspace, float *color) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_BEGIN_MASK, &fz_identity, colorspace, color, 0); - node->rect = *rect; - node->flag = luminosity; - fz_append_display_node(ctx, dev, node); + fz_append_display_node( + ctx, + dev, + FZ_CMD_BEGIN_MASK, + luminosity, /* flags */ + rect, + NULL, /* path */ + color, + colorspace, + NULL, /* alpha */ + NULL, /* ctm */ + NULL, /* stroke */ + NULL, /* private_data */ + 0); /* private_data_len */ } static void fz_list_end_mask(fz_context *ctx, fz_device *dev) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_END_MASK, &fz_identity, NULL, NULL, 0); - fz_append_display_node(ctx, dev, node); + fz_append_display_node( + ctx, + dev, + FZ_CMD_END_MASK, + 0, /* flags */ + NULL, /* rect */ + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + NULL, /* ctm */ + NULL, /* stroke */ + NULL, /* private_data */ + 0); /* private_data_len */ } static void fz_list_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *rect, int isolated, int knockout, int blendmode, float alpha) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_BEGIN_GROUP, &fz_identity, NULL, NULL, alpha); - node->rect = *rect; - node->item.blendmode = blendmode; - node->flag |= isolated ? ISOLATED : 0; - node->flag |= knockout ? KNOCKOUT : 0; - fz_append_display_node(ctx, dev, node); + int flags; + + flags = (blendmode<<2); + if (isolated) + flags |= ISOLATED; + if (knockout) + flags |= KNOCKOUT; + fz_append_display_node( + ctx, + dev, + FZ_CMD_BEGIN_GROUP, + flags, + rect, + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + &alpha, /* alpha */ + NULL, /* ctm */ + NULL, /* stroke */ + NULL, /* private_data */ + 0); /* private_data_len */ } static void fz_list_end_group(fz_context *ctx, fz_device *dev) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_END_GROUP, &fz_identity, NULL, NULL, 0); - fz_append_display_node(ctx, dev, node); + fz_append_display_node( + ctx, + dev, + FZ_CMD_END_GROUP, + 0, /* flags */ + NULL, /* rect */ + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + NULL, /* ctm */ + NULL, /* stroke */ + NULL, /* private_data */ + 0); /* private_data_len */ } +typedef struct fz_list_tile_data_s fz_list_tile_data; + +struct fz_list_tile_data_s +{ + float xstep; + float ystep; + fz_rect view; +}; + static int fz_list_begin_tile(fz_context *ctx, fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id) { - /* We ignore id here, as we will pass on our own id */ - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_BEGIN_TILE, ctm, NULL, NULL, 0); - node->rect = *area; - node->color[0] = xstep; - node->color[1] = ystep; - node->color[2] = view->x0; - node->color[3] = view->y0; - node->color[4] = view->x1; - node->color[5] = view->y1; - fz_append_display_node(ctx, dev, node); + fz_list_tile_data tile; + + tile.xstep = xstep; + tile.ystep = ystep; + tile.view = *view; + fz_append_display_node( + ctx, + dev, + FZ_CMD_BEGIN_TILE, + 0, /* flags */ + area, + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + ctm, + NULL, /* stroke */ + &tile, /* private_data */ + sizeof(tile)); /* private_data_len */ + return 0; } static void fz_list_end_tile(fz_context *ctx, fz_device *dev) { - fz_display_node *node; - node = fz_new_display_node(ctx, FZ_CMD_END_TILE, &fz_identity, NULL, NULL, 0); - fz_append_display_node(ctx, dev, node); + fz_append_display_node( + ctx, + dev, + FZ_CMD_END_TILE, + 0, /* flags */ + NULL, + NULL, /* path */ + NULL, /* color */ + NULL, /* colorspace */ + NULL, /* alpha */ + NULL, /* ctm */ + NULL, /* stroke */ + NULL, /* private_data */ + 0); /* private_data_len */ +} + +static void +drop_writer(fz_context *ctx, fz_device *dev) +{ + fz_list_device *writer = (fz_list_device *)dev; + + fz_drop_colorspace(ctx, writer->colorspace); + fz_drop_stroke_state(ctx, writer->stroke); + fz_drop_path(ctx, writer->path); } fz_device * fz_new_list_device(fz_context *ctx, fz_display_list *list) { - fz_list_device *dev = fz_new_device(ctx, sizeof *dev); + fz_list_device *dev; + + dev = fz_new_device(ctx, sizeof(fz_list_device)); dev->super.begin_page = fz_list_begin_page; dev->super.end_page = fz_list_end_page; @@ -585,26 +1245,110 @@ fz_new_list_device(fz_context *ctx, fz_display_list *list) dev->super.begin_tile = fz_list_begin_tile; dev->super.end_tile = fz_list_end_tile; - dev->list = list; + dev->super.drop_imp = drop_writer; - return (fz_device*)dev; + dev->list = list; + dev->path = NULL; + dev->alpha = 1.0f; + dev->ctm = fz_identity; + dev->stroke = NULL; + dev->colorspace = fz_device_gray(ctx); + memset(dev->color, 0, sizeof(float)*FZ_MAX_COLORS); + dev->top = 0; + dev->tiled = 0; + + return &dev->super; } static void fz_drop_display_list_imp(fz_context *ctx, fz_storable *list_) { fz_display_list *list = (fz_display_list *)list_; - fz_display_node *node; + fz_display_node *node = list->list; + fz_display_node *node_end = list->list + list->len; + int cs_n = 1; if (list == NULL) return; - node = list->first; - while (node) + while (node != node_end) { - fz_display_node *next = node->next; - fz_free_display_node(ctx, node); + fz_display_node n = *node; + fz_display_node *next = node + n.size; + + node++; + if (n.rect) + { + 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: + case CS_UNCHANGED: + break; + case CS_GRAY_0: + case CS_GRAY_1: + cs_n = 1; + break; + case CS_RGB_0: + case CS_RGB_1: + cs_n = 3; + break; + case CS_CMYK_0: + case CS_CMYK_1: + cs_n = 4; + break; + case CS_OTHER_0: + cs_n = (*(fz_colorspace **)node)->n; + fz_drop_colorspace(ctx, *(fz_colorspace **)node); + node += SIZE_IN_NODES(sizeof(fz_colorspace *)); + break; + } + if (n.color) + { + node += SIZE_IN_NODES(cs_n * sizeof(float)); + } + if (n.alpha == ALPHA_PRESENT) + { + node += SIZE_IN_NODES(sizeof(float)); + } + if (n.ctm & CTM_CHANGE_AD) + node += SIZE_IN_NODES(2*sizeof(float)); + if (n.ctm & CTM_CHANGE_BC) + node += SIZE_IN_NODES(2*sizeof(float)); + if (n.ctm & CTM_CHANGE_EF) + node += SIZE_IN_NODES(2*sizeof(float)); + if (n.stroke) + { + fz_drop_stroke_state(ctx, *(fz_stroke_state **)node); + node += SIZE_IN_NODES(sizeof(fz_stroke_state *)); + } + switch(n.cmd) + { + case FZ_CMD_FILL_TEXT: + case FZ_CMD_STROKE_TEXT: + case FZ_CMD_CLIP_TEXT: + case FZ_CMD_CLIP_STROKE_TEXT: + case FZ_CMD_IGNORE_TEXT: + fz_drop_text(ctx, *(fz_text **)node); + break; + case FZ_CMD_FILL_SHADE: + fz_drop_shade(ctx, *(fz_shade **)node); + break; + case FZ_CMD_FILL_IMAGE: + case FZ_CMD_FILL_IMAGE_MASK: + case FZ_CMD_CLIP_IMAGE_MASK: + fz_drop_image(ctx, *(fz_image **)node); + break; + } + node = next; } + fz_free(ctx, list->list); fz_free(ctx, list); } @@ -613,11 +1357,9 @@ fz_new_display_list(fz_context *ctx) { fz_display_list *list = fz_malloc_struct(ctx, fz_display_list); FZ_INIT_STORABLE(list, 1, fz_drop_display_list_imp); - list->first = NULL; - list->last = NULL; + list->list = NULL; + list->max = 0; list->len = 0; - list->top = 0; - list->tiled = 0; return list; } @@ -634,7 +1376,7 @@ fz_drop_display_list(fz_context *ctx, fz_display_list *list) } static fz_display_node * -skip_to_end_tile(fz_display_node *node, int *progress) +skip_to_end_tile(fz_display_node *node, fz_display_node *node_end, int *progress) { fz_display_node *next; int depth = 1; @@ -644,8 +1386,8 @@ skip_to_end_tile(fz_display_node *node, int *progress) * the calling routine. */ do { - next = node->next; - if (next == NULL) + next = node + node->size; + if (next == node_end) break; if (next->cmd == FZ_CMD_BEGIN_TILE) depth++; @@ -667,11 +1409,27 @@ void fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, const fz_matrix *top_ctm, const fz_rect *scissor, fz_cookie *cookie) { fz_display_node *node; - fz_matrix ctm; + fz_display_node *node_end; + fz_display_node *next_node; int clipped = 0; int tiled = 0; int progress = 0; + /* Current graphics state as unpacked from list */ + fz_path *path = NULL; + float alpha = 1.0f; + fz_matrix ctm = fz_identity; + fz_stroke_state *stroke = NULL; + float color[FZ_MAX_COLORS] = { 0 }; + fz_colorspace *colorspace = fz_device_gray(ctx); + fz_rect rect = { 0 }; + + /* Transformed versions of graphic state entries */ + fz_rect trans_rect; + fz_matrix trans_ctm; + + fz_var(colorspace); + if (!scissor) scissor = &fz_infinite_rect; @@ -681,12 +1439,14 @@ fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, cons cookie->progress = 0; } - for (node = list->first; node; node = node->next) + node = list->list; + node_end = &list->list[list->len]; + for (; node != node_end ; node = next_node) { int empty; + fz_display_node n = *node; - fz_rect node_rect = node->rect; - fz_transform_rect(&node_rect, top_ctm); + next_node = node + n.size; /* Check the cookie for aborting */ if (cookie) @@ -696,24 +1456,140 @@ fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, cons cookie->progress = progress++; } + node++; + if (n.rect) + { + 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; + + fz_drop_colorspace(ctx, colorspace); + switch (n.cs) + { + default: + case CS_GRAY_0: + colorspace = fz_device_gray(ctx); + color[0] = 0.0f; + break; + case CS_GRAY_1: + colorspace = fz_device_gray(ctx); + color[0] = 1.0f; + break; + case CS_RGB_0: + colorspace = fz_device_rgb(ctx); + color[0] = 0.0f; + color[1] = 0.0f; + color[2] = 0.0f; + break; + case CS_RGB_1: + colorspace = fz_device_rgb(ctx); + color[0] = 1.0f; + color[1] = 1.0f; + color[2] = 1.0f; + break; + case CS_CMYK_0: + colorspace = fz_device_cmyk(ctx); + color[0] = 0.0f; + color[1] = 0.0f; + color[2] = 0.0f; + color[3] = 0.0f; + break; + case CS_CMYK_1: + colorspace = fz_device_cmyk(ctx); + color[0] = 0.0f; + color[1] = 0.0f; + color[2] = 0.0f; + color[3] = 1.0f; + break; + case CS_OTHER_0: + colorspace = fz_keep_colorspace(ctx, *(fz_colorspace **)(node)); + node += SIZE_IN_NODES(sizeof(fz_colorspace *)); + for (i = 0; i < colorspace->n; i++) + color[i] = 0.0f; + break; + } + } + if (n.color) + { + memcpy(color, (float *)node, colorspace->n * sizeof(float)); + node += SIZE_IN_NODES(colorspace->n * sizeof(float)); + } + if (n.alpha) + { + switch(n.alpha) + { + default: + case ALPHA_0: + alpha = 0.0f; + break; + case ALPHA_1: + alpha = 1.0f; + break; + case ALPHA_PRESENT: + alpha = *(float *)node; + node += SIZE_IN_NODES(sizeof(float)); + break; + } + } + if (n.ctm != 0) + { + float *packed_ctm = (float *)node; + if (n.ctm & CTM_CHANGE_AD) + { + ctm.a = *packed_ctm++; + ctm.d = *packed_ctm++; + node += SIZE_IN_NODES(2*sizeof(float)); + } + if (n.ctm & CTM_CHANGE_BC) + { + ctm.b = *packed_ctm++; + ctm.c = *packed_ctm++; + node += SIZE_IN_NODES(2*sizeof(float)); + } + if (n.ctm & CTM_CHANGE_EF) + { + ctm.e = *packed_ctm++; + ctm.f = *packed_ctm++; + node += SIZE_IN_NODES(2*sizeof(float)); + } + } + if (n.stroke) + { + fz_drop_stroke_state(ctx, stroke); + stroke = fz_keep_stroke_state(ctx, *(fz_stroke_state **)node); + node += SIZE_IN_NODES(sizeof(fz_stroke_state *)); + } + + trans_rect = rect; + fz_transform_rect(&trans_rect, top_ctm); + /* cull objects to draw using a quick visibility test */ if (tiled || - node->cmd == FZ_CMD_BEGIN_TILE || node->cmd == FZ_CMD_END_TILE || - node->cmd == FZ_CMD_BEGIN_PAGE || node->cmd == FZ_CMD_END_PAGE) + n.cmd == FZ_CMD_BEGIN_TILE || n.cmd == FZ_CMD_END_TILE || + n.cmd == FZ_CMD_BEGIN_PAGE || n.cmd == FZ_CMD_END_PAGE) { empty = 0; } else { - fz_rect rect = node_rect; - fz_intersect_rect(&rect, scissor); - empty = fz_is_empty_rect(&rect); + fz_rect irect = rect; + fz_intersect_rect(&irect, scissor); + empty = fz_is_empty_rect(&irect); } if (clipped || empty) { - switch (node->cmd) + switch (n.cmd) { case FZ_CMD_CLIP_PATH: case FZ_CMD_CLIP_STROKE_PATH: @@ -725,7 +1601,7 @@ fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, cons continue; case FZ_CMD_CLIP_TEXT: /* Accumulated text has no extra pops */ - if (node->flag != 2) + if (n.flags != 2) clipped++; continue; case FZ_CMD_POP_CLIP: @@ -744,79 +1620,72 @@ fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, cons } visible: - fz_concat(&ctm, &node->ctm, top_ctm); + fz_concat(&trans_ctm, &ctm, top_ctm); fz_try(ctx) { - switch (node->cmd) + switch (n.cmd) { case FZ_CMD_BEGIN_PAGE: - fz_begin_page(ctx, dev, &node_rect, &ctm); + fz_begin_page(ctx, dev, &trans_rect, &trans_ctm); break; case FZ_CMD_END_PAGE: fz_end_page(ctx, dev); break; case FZ_CMD_FILL_PATH: - fz_fill_path(ctx, dev, node->item.path, node->flag, &ctm, - node->colorspace, node->color, node->alpha); + fz_fill_path(ctx, dev, path, n.flags, &trans_ctm, colorspace, color, alpha); break; case FZ_CMD_STROKE_PATH: - fz_stroke_path(ctx, dev, node->item.path, node->stroke, &ctm, - node->colorspace, node->color, node->alpha); + fz_stroke_path(ctx, dev, path, stroke, &trans_ctm, colorspace, color, alpha); break; case FZ_CMD_CLIP_PATH: - fz_clip_path(ctx, dev, node->item.path, &node_rect, node->flag, &ctm); + fz_clip_path(ctx, dev, path, &trans_rect, n.flags, &trans_ctm); break; case FZ_CMD_CLIP_STROKE_PATH: - fz_clip_stroke_path(ctx, dev, node->item.path, &node_rect, node->stroke, &ctm); + fz_clip_stroke_path(ctx, dev, path, &trans_rect, stroke, &trans_ctm); break; case FZ_CMD_FILL_TEXT: - fz_fill_text(ctx, dev, node->item.text, &ctm, - node->colorspace, node->color, node->alpha); + fz_fill_text(ctx, dev, *(fz_text **)node, &trans_ctm, colorspace, color, alpha); break; case FZ_CMD_STROKE_TEXT: - fz_stroke_text(ctx, dev, node->item.text, node->stroke, &ctm, - node->colorspace, node->color, node->alpha); + fz_stroke_text(ctx, dev, *(fz_text **)node, stroke, &trans_ctm, colorspace, color, alpha); break; case FZ_CMD_CLIP_TEXT: - fz_clip_text(ctx, dev, node->item.text, &ctm, node->flag); + fz_clip_text(ctx, dev, *(fz_text **)node, &trans_ctm, n.flags); break; case FZ_CMD_CLIP_STROKE_TEXT: - fz_clip_stroke_text(ctx, dev, node->item.text, node->stroke, &ctm); + fz_clip_stroke_text(ctx, dev, *(fz_text **)node, stroke, &trans_ctm); break; case FZ_CMD_IGNORE_TEXT: - fz_ignore_text(ctx, dev, node->item.text, &ctm); + fz_ignore_text(ctx, dev, *(fz_text **)node, &trans_ctm); break; case FZ_CMD_FILL_SHADE: if ((dev->hints & FZ_IGNORE_SHADE) == 0) - fz_fill_shade(ctx, dev, node->item.shade, &ctm, node->alpha); + fz_fill_shade(ctx, dev, *(fz_shade **)node, &trans_ctm, alpha); break; case FZ_CMD_FILL_IMAGE: if ((dev->hints & FZ_IGNORE_IMAGE) == 0) - fz_fill_image(ctx, dev, node->item.image, &ctm, node->alpha); + fz_fill_image(ctx, dev, *(fz_image **)node, &trans_ctm, alpha); break; case FZ_CMD_FILL_IMAGE_MASK: if ((dev->hints & FZ_IGNORE_IMAGE) == 0) - fz_fill_image_mask(ctx, dev, node->item.image, &ctm, - node->colorspace, node->color, node->alpha); + fz_fill_image_mask(ctx, dev, *(fz_image **)node, &trans_ctm, colorspace, color, alpha); break; case FZ_CMD_CLIP_IMAGE_MASK: if ((dev->hints & FZ_IGNORE_IMAGE) == 0) - fz_clip_image_mask(ctx, dev, node->item.image, &node_rect, &ctm); + fz_clip_image_mask(ctx, dev, *(fz_image **)node, &trans_rect, &trans_ctm); break; case FZ_CMD_POP_CLIP: fz_pop_clip(ctx, dev); break; case FZ_CMD_BEGIN_MASK: - fz_begin_mask(ctx, dev, &node_rect, node->flag, node->colorspace, node->color); + fz_begin_mask(ctx, dev, &trans_rect, n.flags, colorspace, color); break; case FZ_CMD_END_MASK: fz_end_mask(ctx, dev); break; case FZ_CMD_BEGIN_GROUP: - fz_begin_group(ctx, dev, &node_rect, - (node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0, - node->item.blendmode, node->alpha); + fz_begin_group(ctx, dev, &trans_rect, (n.flags & ISOLATED) != 0, (n.flags & KNOCKOUT) != 0, (n.flags>>2), alpha); break; case FZ_CMD_END_GROUP: fz_end_group(ctx, dev); @@ -824,15 +1693,13 @@ visible: case FZ_CMD_BEGIN_TILE: { int cached; + fz_list_tile_data *data = (fz_list_tile_data *)node; fz_rect tile_rect; tiled++; - tile_rect.x0 = node->color[2]; - tile_rect.y0 = node->color[3]; - tile_rect.x1 = node->color[4]; - tile_rect.y1 = node->color[5]; - cached = fz_begin_tile_id(ctx, dev, &node->rect, &tile_rect, node->color[0], node->color[1], &ctm, node->flag); + tile_rect = data->view; + cached = fz_begin_tile_id(ctx, dev, &rect, &tile_rect, data->xstep, data->ystep, &trans_ctm, n.flags); if (cached) - node = skip_to_end_tile(node, &progress); + node = skip_to_end_tile(node, node_end, &progress); break; } case FZ_CMD_END_TILE: @@ -851,4 +1718,7 @@ visible: fz_warn(ctx, "Ignoring error during interpretation"); } } + fz_drop_colorspace(ctx, colorspace); + fz_drop_stroke_state(ctx, stroke); + fz_drop_path(ctx, path); } |