summaryrefslogtreecommitdiff
path: root/source/fitz/list-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/fitz/list-device.c')
-rw-r--r--source/fitz/list-device.c1576
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);
}