summaryrefslogtreecommitdiff
path: root/source/fitz/list-device.c
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2013-06-19 15:29:44 +0200
committerTor Andersson <tor.andersson@artifex.com>2013-06-20 16:45:35 +0200
commit0a927854a10e1e6b9770a81e2e1d9f3093631757 (patch)
tree3d65d820d9fdba2d0d394d99c36290c851b78ca0 /source/fitz/list-device.c
parent1ae8f19179c5f0f8c6352b3c7855465325d5449a (diff)
downloadmupdf-0a927854a10e1e6b9770a81e2e1d9f3093631757.tar.xz
Rearrange source files.
Diffstat (limited to 'source/fitz/list-device.c')
-rw-r--r--source/fitz/list-device.c851
1 files changed, 851 insertions, 0 deletions
diff --git a/source/fitz/list-device.c b/source/fitz/list-device.c
new file mode 100644
index 00000000..6ffe165f
--- /dev/null
+++ b/source/fitz/list-device.c
@@ -0,0 +1,851 @@
+#include "mupdf/fitz.h"
+
+typedef struct fz_display_node_s fz_display_node;
+
+#define STACK_SIZE 96
+
+typedef enum fz_display_command_e
+{
+ FZ_CMD_BEGIN_PAGE,
+ FZ_CMD_END_PAGE,
+ FZ_CMD_FILL_PATH,
+ FZ_CMD_STROKE_PATH,
+ FZ_CMD_CLIP_PATH,
+ FZ_CMD_CLIP_STROKE_PATH,
+ FZ_CMD_FILL_TEXT,
+ FZ_CMD_STROKE_TEXT,
+ FZ_CMD_CLIP_TEXT,
+ FZ_CMD_CLIP_STROKE_TEXT,
+ FZ_CMD_IGNORE_TEXT,
+ FZ_CMD_FILL_SHADE,
+ FZ_CMD_FILL_IMAGE,
+ FZ_CMD_FILL_IMAGE_MASK,
+ FZ_CMD_CLIP_IMAGE_MASK,
+ FZ_CMD_POP_CLIP,
+ FZ_CMD_BEGIN_MASK,
+ FZ_CMD_END_MASK,
+ FZ_CMD_BEGIN_GROUP,
+ FZ_CMD_END_GROUP,
+ FZ_CMD_BEGIN_TILE,
+ FZ_CMD_END_TILE
+} fz_display_command;
+
+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];
+};
+
+struct fz_display_list_s
+{
+ fz_storable storable;
+ fz_display_node *first;
+ fz_display_node *last;
+ int len;
+
+ int top;
+ struct {
+ fz_rect *update;
+ fz_rect rect;
+ } stack[STACK_SIZE];
+ int tiled;
+};
+
+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;
+}
+
+static void
+fz_append_display_node(fz_display_list *list, fz_display_node *node)
+{
+ switch (node->cmd)
+ {
+ case FZ_CMD_CLIP_PATH:
+ case FZ_CMD_CLIP_STROKE_PATH:
+ case FZ_CMD_CLIP_IMAGE_MASK:
+ if (list->top < STACK_SIZE)
+ {
+ list->stack[list->top].update = &node->rect;
+ list->stack[list->top].rect = fz_empty_rect;
+ }
+ list->top++;
+ break;
+ case FZ_CMD_END_MASK:
+ case FZ_CMD_CLIP_TEXT:
+ case FZ_CMD_CLIP_STROKE_TEXT:
+ if (list->top < STACK_SIZE)
+ {
+ list->stack[list->top].update = NULL;
+ list->stack[list->top].rect = fz_empty_rect;
+ }
+ list->top++;
+ break;
+ case FZ_CMD_BEGIN_TILE:
+ list->tiled++;
+ if (list->top > 0 && list->top <= STACK_SIZE)
+ {
+ list->stack[list->top-1].rect = fz_infinite_rect;
+ }
+ break;
+ case FZ_CMD_END_TILE:
+ list->tiled--;
+ break;
+ case FZ_CMD_END_GROUP:
+ break;
+ case FZ_CMD_POP_CLIP:
+ if (list->top > STACK_SIZE)
+ {
+ list->top--;
+ node->rect = fz_infinite_rect;
+ }
+ else if (list->top > 0)
+ {
+ fz_rect *update;
+ list->top--;
+ update = list->stack[list->top].update;
+ if (list->tiled == 0)
+ {
+ if (update)
+ {
+ fz_intersect_rect(update, &list->stack[list->top].rect);
+ node->rect = *update;
+ }
+ else
+ node->rect = list->stack[list->top].rect;
+ }
+ else
+ node->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);
+ break;
+ }
+ if (!list->first)
+ {
+ list->first = node;
+ list->last = node;
+ }
+ else
+ {
+ list->last->next = node;
+ list->last = node;
+ }
+ list->len++;
+}
+
+static void
+fz_free_display_node(fz_context *ctx, fz_display_node *node)
+{
+ switch (node->cmd)
+ {
+ case FZ_CMD_FILL_PATH:
+ case FZ_CMD_STROKE_PATH:
+ case FZ_CMD_CLIP_PATH:
+ case FZ_CMD_CLIP_STROKE_PATH:
+ fz_free_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_free_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 (node->stroke)
+ fz_drop_stroke_state(ctx, node->stroke);
+ if (node->colorspace)
+ fz_drop_colorspace(ctx, node->colorspace);
+ fz_free(ctx, node);
+}
+
+static void
+fz_list_begin_page(fz_device *dev, const fz_rect *mediabox, const fz_matrix *ctm)
+{
+ fz_context *ctx = dev->ctx;
+ 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(dev->user, node);
+}
+
+static void
+fz_list_end_page(fz_device *dev)
+{
+ fz_context *ctx = dev->ctx;
+ fz_display_node *node = fz_new_display_node(ctx, FZ_CMD_END_PAGE, &fz_identity, NULL, NULL, 0);
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_fill_path(fz_device *dev, fz_path *path, int even_odd, const fz_matrix *ctm,
+ fz_colorspace *colorspace, float *color, float alpha)
+{
+ fz_display_node *node;
+ fz_context *ctx = dev->ctx;
+ node = fz_new_display_node(ctx, FZ_CMD_FILL_PATH, ctm, colorspace, color, alpha);
+ fz_try(ctx)
+ {
+ fz_bound_path(dev->ctx, path, NULL, ctm, &node->rect);
+ node->item.path = fz_clone_path(dev->ctx, path);
+ node->flag = even_odd;
+ }
+ fz_catch(ctx)
+ {
+ fz_free_display_node(ctx, node);
+ fz_rethrow(ctx);
+ }
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_stroke_path(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;
+ fz_context *ctx = dev->ctx;
+ node = fz_new_display_node(ctx, FZ_CMD_STROKE_PATH, ctm, colorspace, color, alpha);
+ fz_try(ctx)
+ {
+ fz_bound_path(dev->ctx, path, stroke, ctm, &node->rect);
+ node->item.path = fz_clone_path(dev->ctx, path);
+ node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
+ }
+ fz_catch(ctx)
+ {
+ fz_free_display_node(ctx, node);
+ fz_rethrow(ctx);
+ }
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_clip_path(fz_device *dev, fz_path *path, const fz_rect *rect, int even_odd, const fz_matrix *ctm)
+{
+ fz_display_node *node;
+ fz_context *ctx = dev->ctx;
+ node = fz_new_display_node(ctx, FZ_CMD_CLIP_PATH, ctm, NULL, NULL, 0);
+ fz_try(ctx)
+ {
+ fz_bound_path(dev->ctx, path, NULL, ctm, &node->rect);
+ if (rect)
+ fz_intersect_rect(&node->rect, rect);
+ node->item.path = fz_clone_path(dev->ctx, path);
+ node->flag = even_odd;
+ }
+ fz_catch(ctx)
+ {
+ fz_free_display_node(ctx, node);
+ fz_rethrow(ctx);
+ }
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_clip_stroke_path(fz_device *dev, fz_path *path, const fz_rect *rect, fz_stroke_state *stroke, const fz_matrix *ctm)
+{
+ fz_display_node *node;
+ fz_context *ctx = dev->ctx;
+ node = fz_new_display_node(ctx, FZ_CMD_CLIP_STROKE_PATH, ctm, NULL, NULL, 0);
+ fz_try(ctx)
+ {
+ fz_bound_path(dev->ctx, path, stroke, ctm, &node->rect);
+ if (rect)
+ fz_intersect_rect(&node->rect, rect);
+ node->item.path = fz_clone_path(dev->ctx, path);
+ node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
+ }
+ fz_catch(ctx)
+ {
+ fz_free_display_node(ctx, node);
+ fz_rethrow(ctx);
+ }
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_fill_text(fz_device *dev, fz_text *text, const fz_matrix *ctm,
+ fz_colorspace *colorspace, float *color, float alpha)
+{
+ fz_display_node *node;
+ fz_context *ctx = dev->ctx;
+ node = fz_new_display_node(ctx, FZ_CMD_FILL_TEXT, ctm, colorspace, color, alpha);
+ fz_try(ctx)
+ {
+ fz_bound_text(dev->ctx, text, NULL, ctm, &node->rect);
+ node->item.text = fz_clone_text(dev->ctx, text);
+ }
+ fz_catch(ctx)
+ {
+ fz_free_display_node(ctx, node);
+ fz_rethrow(ctx);
+ }
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_stroke_text(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;
+ fz_context *ctx = dev->ctx;
+ node = fz_new_display_node(ctx, FZ_CMD_STROKE_TEXT, ctm, colorspace, color, alpha);
+ node->item.text = NULL;
+ fz_try(ctx)
+ {
+ fz_bound_text(dev->ctx, text, stroke, ctm, &node->rect);
+ node->item.text = fz_clone_text(dev->ctx, text);
+ node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
+ }
+ fz_catch(ctx)
+ {
+ fz_free_display_node(ctx, node);
+ fz_rethrow(ctx);
+ }
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_clip_text(fz_device *dev, fz_text *text, const fz_matrix *ctm, int accumulate)
+{
+ fz_display_node *node;
+ fz_context *ctx = dev->ctx;
+ node = fz_new_display_node(ctx, FZ_CMD_CLIP_TEXT, ctm, NULL, NULL, 0);
+ fz_try(ctx)
+ {
+ fz_bound_text(dev->ctx, text, NULL, ctm, &node->rect);
+ node->item.text = fz_clone_text(dev->ctx, text);
+ node->flag = accumulate;
+ /* when accumulating, be conservative about culling */
+ if (accumulate)
+ node->rect = fz_infinite_rect;
+ }
+ fz_catch(ctx)
+ {
+ fz_free_display_node(ctx, node);
+ fz_rethrow(ctx);
+ }
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm)
+{
+ fz_display_node *node;
+ fz_context *ctx = dev->ctx;
+ node = fz_new_display_node(ctx, FZ_CMD_CLIP_STROKE_TEXT, ctm, NULL, NULL, 0);
+ fz_try(ctx)
+ {
+ fz_bound_text(dev->ctx, text, stroke, ctm, &node->rect);
+ node->item.text = fz_clone_text(dev->ctx, text);
+ node->stroke = fz_keep_stroke_state(dev->ctx, stroke);
+ }
+ fz_catch(ctx)
+ {
+ fz_free_display_node(ctx, node);
+ fz_rethrow(ctx);
+ }
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_ignore_text(fz_device *dev, fz_text *text, const fz_matrix *ctm)
+{
+ fz_display_node *node;
+ fz_context *ctx = dev->ctx;
+ node = fz_new_display_node(ctx, FZ_CMD_IGNORE_TEXT, ctm, NULL, NULL, 0);
+ fz_try(ctx)
+ {
+ fz_bound_text(dev->ctx, text, NULL, ctm, &node->rect);
+ node->item.text = fz_clone_text(dev->ctx, text);
+ }
+ fz_catch(ctx)
+ {
+ fz_free_display_node(ctx, node);
+ fz_rethrow(ctx);
+ }
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_pop_clip(fz_device *dev)
+{
+ fz_display_node *node;
+ node = fz_new_display_node(dev->ctx, FZ_CMD_POP_CLIP, &fz_identity, NULL, NULL, 0);
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_fill_shade(fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
+{
+ fz_display_node *node;
+ fz_context *ctx = dev->ctx;
+ 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(dev->user, node);
+}
+
+static void
+fz_list_fill_image(fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha)
+{
+ fz_display_node *node;
+ node = fz_new_display_node(dev->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(dev->ctx, image);
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_fill_image_mask(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(dev->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(dev->ctx, image);
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_clip_image_mask(fz_device *dev, fz_image *image, const fz_rect *rect, const fz_matrix *ctm)
+{
+ fz_display_node *node;
+ node = fz_new_display_node(dev->ctx, FZ_CMD_CLIP_IMAGE_MASK, ctm, NULL, NULL, 0);
+ node->rect = fz_unit_rect;
+ fz_transform_rect(&node->rect, ctm);
+ if (rect)
+ fz_intersect_rect(&node->rect, rect);
+ node->item.image = fz_keep_image(dev->ctx, image);
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_begin_mask(fz_device *dev, const fz_rect *rect, int luminosity, fz_colorspace *colorspace, float *color)
+{
+ fz_display_node *node;
+ node = fz_new_display_node(dev->ctx, FZ_CMD_BEGIN_MASK, &fz_identity, colorspace, color, 0);
+ node->rect = *rect;
+ node->flag = luminosity;
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_end_mask(fz_device *dev)
+{
+ fz_display_node *node;
+ node = fz_new_display_node(dev->ctx, FZ_CMD_END_MASK, &fz_identity, NULL, NULL, 0);
+ fz_append_display_node(dev->user, node);
+}
+
+static void
+fz_list_begin_group(fz_device *dev, const fz_rect *rect, int isolated, int knockout, int blendmode, float alpha)
+{
+ fz_display_node *node;
+ node = fz_new_display_node(dev->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(dev->user, node);
+}
+
+static void
+fz_list_end_group(fz_device *dev)
+{
+ fz_display_node *node;
+ node = fz_new_display_node(dev->ctx, FZ_CMD_END_GROUP, &fz_identity, NULL, NULL, 0);
+ fz_append_display_node(dev->user, node);
+}
+
+static int
+fz_list_begin_tile(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(dev->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(dev->user, node);
+ return 0;
+}
+
+static void
+fz_list_end_tile(fz_device *dev)
+{
+ fz_display_node *node;
+ node = fz_new_display_node(dev->ctx, FZ_CMD_END_TILE, &fz_identity, NULL, NULL, 0);
+ fz_append_display_node(dev->user, node);
+}
+
+fz_device *
+fz_new_list_device(fz_context *ctx, fz_display_list *list)
+{
+ fz_device *dev = fz_new_device(ctx, list);
+
+ dev->begin_page = fz_list_begin_page;
+ dev->end_page = fz_list_end_page;
+
+ dev->fill_path = fz_list_fill_path;
+ dev->stroke_path = fz_list_stroke_path;
+ dev->clip_path = fz_list_clip_path;
+ dev->clip_stroke_path = fz_list_clip_stroke_path;
+
+ dev->fill_text = fz_list_fill_text;
+ dev->stroke_text = fz_list_stroke_text;
+ dev->clip_text = fz_list_clip_text;
+ dev->clip_stroke_text = fz_list_clip_stroke_text;
+ dev->ignore_text = fz_list_ignore_text;
+
+ dev->fill_shade = fz_list_fill_shade;
+ dev->fill_image = fz_list_fill_image;
+ dev->fill_image_mask = fz_list_fill_image_mask;
+ dev->clip_image_mask = fz_list_clip_image_mask;
+
+ dev->pop_clip = fz_list_pop_clip;
+
+ dev->begin_mask = fz_list_begin_mask;
+ dev->end_mask = fz_list_end_mask;
+ dev->begin_group = fz_list_begin_group;
+ dev->end_group = fz_list_end_group;
+
+ dev->begin_tile = fz_list_begin_tile;
+ dev->end_tile = fz_list_end_tile;
+
+ return dev;
+}
+
+static void
+fz_free_display_list(fz_context *ctx, fz_storable *list_)
+{
+ fz_display_list *list = (fz_display_list *)list_;
+ fz_display_node *node;
+
+ if (list == NULL)
+ return;
+ node = list->first;
+ while (node)
+ {
+ fz_display_node *next = node->next;
+ fz_free_display_node(ctx, node);
+ node = next;
+ }
+ fz_free(ctx, list);
+}
+
+fz_display_list *
+fz_new_display_list(fz_context *ctx)
+{
+ fz_display_list *list = fz_malloc_struct(ctx, fz_display_list);
+ FZ_INIT_STORABLE(list, 1, fz_free_display_list);
+ list->first = NULL;
+ list->last = NULL;
+ list->len = 0;
+ list->top = 0;
+ list->tiled = 0;
+ return list;
+}
+
+fz_display_list *
+fz_keep_display_list(fz_context *ctx, fz_display_list *list)
+{
+ return (fz_display_list *)fz_keep_storable(ctx, &list->storable);
+}
+
+void
+fz_drop_display_list(fz_context *ctx, fz_display_list *list)
+{
+ fz_drop_storable(ctx, &list->storable);
+}
+
+static fz_display_node *
+skip_to_end_tile(fz_display_node *node, int *progress)
+{
+ fz_display_node *next;
+ int depth = 1;
+
+ /* Skip through until we find the matching end_tile. Note that
+ * (somewhat nastily) we return the PREVIOUS node to this to help
+ * the calling routine. */
+ do
+ {
+ next = node->next;
+ if (next == NULL)
+ break;
+ if (next->cmd == FZ_CMD_BEGIN_TILE)
+ depth++;
+ else if (next->cmd == FZ_CMD_END_TILE)
+ {
+ depth--;
+ if (depth == 0)
+ return node;
+ }
+ (*progress)++;
+ node = next;
+ }
+ while (1);
+
+ return NULL;
+}
+
+void
+fz_run_display_list(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;
+ int clipped = 0;
+ int tiled = 0;
+ int progress = 0;
+ fz_context *ctx = dev->ctx;
+
+ if (!scissor)
+ scissor = &fz_infinite_rect;
+
+ if (cookie)
+ {
+ cookie->progress_max = list->len;
+ cookie->progress = 0;
+ }
+
+ for (node = list->first; node; node = node->next)
+ {
+ int empty;
+
+ fz_rect node_rect = node->rect;
+ fz_transform_rect(&node_rect, top_ctm);
+
+ /* Check the cookie for aborting */
+ if (cookie)
+ {
+ if (cookie->abort)
+ break;
+ cookie->progress = progress++;
+ }
+
+ /* 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)
+ {
+ empty = 0;
+ }
+ else
+ {
+ fz_rect rect = node_rect;
+ fz_intersect_rect(&rect, scissor);
+ empty = fz_is_empty_rect(&rect);
+ }
+
+ if (clipped || empty)
+ {
+ switch (node->cmd)
+ {
+ case FZ_CMD_CLIP_PATH:
+ case FZ_CMD_CLIP_STROKE_PATH:
+ case FZ_CMD_CLIP_STROKE_TEXT:
+ case FZ_CMD_CLIP_IMAGE_MASK:
+ case FZ_CMD_BEGIN_MASK:
+ case FZ_CMD_BEGIN_GROUP:
+ clipped++;
+ continue;
+ case FZ_CMD_CLIP_TEXT:
+ /* Accumulated text has no extra pops */
+ if (node->flag != 2)
+ clipped++;
+ continue;
+ case FZ_CMD_POP_CLIP:
+ case FZ_CMD_END_GROUP:
+ if (!clipped)
+ goto visible;
+ clipped--;
+ continue;
+ case FZ_CMD_END_MASK:
+ if (!clipped)
+ goto visible;
+ continue;
+ default:
+ continue;
+ }
+ }
+
+visible:
+ fz_concat(&ctm, &node->ctm, top_ctm);
+
+
+ fz_try(ctx)
+ {
+ switch (node->cmd)
+ {
+ case FZ_CMD_BEGIN_PAGE:
+ fz_begin_page(dev, &node_rect, &ctm);
+ break;
+ case FZ_CMD_END_PAGE:
+ fz_end_page(dev);
+ break;
+ case FZ_CMD_FILL_PATH:
+ fz_fill_path(dev, node->item.path, node->flag, &ctm,
+ node->colorspace, node->color, node->alpha);
+ break;
+ case FZ_CMD_STROKE_PATH:
+ fz_stroke_path(dev, node->item.path, node->stroke, &ctm,
+ node->colorspace, node->color, node->alpha);
+ break;
+ case FZ_CMD_CLIP_PATH:
+ fz_clip_path(dev, node->item.path, &node_rect, node->flag, &ctm);
+ break;
+ case FZ_CMD_CLIP_STROKE_PATH:
+ fz_clip_stroke_path(dev, node->item.path, &node_rect, node->stroke, &ctm);
+ break;
+ case FZ_CMD_FILL_TEXT:
+ fz_fill_text(dev, node->item.text, &ctm,
+ node->colorspace, node->color, node->alpha);
+ break;
+ case FZ_CMD_STROKE_TEXT:
+ fz_stroke_text(dev, node->item.text, node->stroke, &ctm,
+ node->colorspace, node->color, node->alpha);
+ break;
+ case FZ_CMD_CLIP_TEXT:
+ fz_clip_text(dev, node->item.text, &ctm, node->flag);
+ break;
+ case FZ_CMD_CLIP_STROKE_TEXT:
+ fz_clip_stroke_text(dev, node->item.text, node->stroke, &ctm);
+ break;
+ case FZ_CMD_IGNORE_TEXT:
+ fz_ignore_text(dev, node->item.text, &ctm);
+ break;
+ case FZ_CMD_FILL_SHADE:
+ if ((dev->hints & FZ_IGNORE_SHADE) == 0)
+ fz_fill_shade(dev, node->item.shade, &ctm, node->alpha);
+ break;
+ case FZ_CMD_FILL_IMAGE:
+ if ((dev->hints & FZ_IGNORE_IMAGE) == 0)
+ fz_fill_image(dev, node->item.image, &ctm, node->alpha);
+ break;
+ case FZ_CMD_FILL_IMAGE_MASK:
+ if ((dev->hints & FZ_IGNORE_IMAGE) == 0)
+ fz_fill_image_mask(dev, node->item.image, &ctm,
+ node->colorspace, node->color, node->alpha);
+ break;
+ case FZ_CMD_CLIP_IMAGE_MASK:
+ if ((dev->hints & FZ_IGNORE_IMAGE) == 0)
+ fz_clip_image_mask(dev, node->item.image, &node_rect, &ctm);
+ break;
+ case FZ_CMD_POP_CLIP:
+ fz_pop_clip(dev);
+ break;
+ case FZ_CMD_BEGIN_MASK:
+ fz_begin_mask(dev, &node_rect, node->flag, node->colorspace, node->color);
+ break;
+ case FZ_CMD_END_MASK:
+ fz_end_mask(dev);
+ break;
+ case FZ_CMD_BEGIN_GROUP:
+ fz_begin_group(dev, &node_rect,
+ (node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0,
+ node->item.blendmode, node->alpha);
+ break;
+ case FZ_CMD_END_GROUP:
+ fz_end_group(dev);
+ break;
+ case FZ_CMD_BEGIN_TILE:
+ {
+ int cached;
+ 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(dev, &node->rect, &tile_rect, node->color[0], node->color[1], &ctm, node->flag);
+ if (cached)
+ node = skip_to_end_tile(node, &progress);
+ break;
+ }
+ case FZ_CMD_END_TILE:
+ tiled--;
+ fz_end_tile(dev);
+ break;
+ }
+ }
+ fz_catch(ctx)
+ {
+ /* Swallow the error */
+ if (cookie)
+ cookie->errors++;
+ fz_warn(ctx, "Ignoring error during interpretation");
+ }
+ }
+}