diff options
author | Robin Watts <robin.watts@artifex.com> | 2011-11-15 16:40:18 +0000 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2011-11-15 16:40:18 +0000 |
commit | 819aed16c190263a853fabe07870f9da98070f80 (patch) | |
tree | 325d6cfa3ff2c8df052c1a812c8775ff62fb3ec8 /draw/draw_device.c | |
parent | 54d7093e80e419b8aa18ffe33a4a3ff4fda25140 (diff) | |
download | mupdf-819aed16c190263a853fabe07870f9da98070f80.tar.xz |
Allow draw device to use a dynamic stack.
Previously, we had a hardwired 96 element stack for clipping/group
nesting etc. If this was exceeeded during rendering we would give
an error.
Now we allow for that stack to be extended dynamically at runtime.
If the stack extension fails, we will give an error and die.
Diffstat (limited to 'draw/draw_device.c')
-rw-r--r-- | draw/draw_device.c | 124 |
1 files changed, 61 insertions, 63 deletions
diff --git a/draw/draw_device.c b/draw/draw_device.c index 0efe701a..165cb1a9 100644 --- a/draw/draw_device.c +++ b/draw/draw_device.c @@ -34,6 +34,21 @@ enum { FZ_DRAWDEV_FLAGS_TYPE3 = 1, }; +typedef struct fz_draw_stack_s fz_draw_stack; + +struct fz_draw_stack_s { + fz_bbox scissor; + fz_pixmap *dest; + fz_pixmap *mask; + fz_pixmap *shape; + int blendmode; + int luminosity; + float alpha; + fz_matrix ctm; + float xstep, ystep; + fz_rect area; +}; + struct fz_draw_device_s { fz_glyph_cache *cache; @@ -46,18 +61,9 @@ struct fz_draw_device_s int flags; int top; int blendmode; - struct { - fz_bbox scissor; - fz_pixmap *dest; - fz_pixmap *mask; - fz_pixmap *shape; - int blendmode; - int luminosity; - float alpha; - fz_matrix ctm; - float xstep, ystep; - fz_rect area; - } stack[STACK_SIZE]; + fz_draw_stack *stack; + int stack_max; + fz_draw_stack init_stack[STACK_SIZE]; }; #ifdef DUMP_GROUP_BLENDS @@ -88,6 +94,24 @@ static void dump_spaces(int x, const char *s) #endif +static void fz_grow_stack(fz_draw_device *dev) +{ + int max = dev->stack_max * 2; + fz_draw_stack *stack; + + if (dev->stack == &dev->init_stack[0]) + { + stack = fz_malloc(sizeof(*stack) * max); + memcpy(stack, dev->stack, sizeof(*stack) * dev->stack_max); + } + else + { + stack = fz_realloc(dev->stack, max, sizeof(*stack)); + } + dev->stack = stack; + dev->stack_max = max; +} + static void fz_knockout_begin(void *user) { fz_draw_device *dev = user; @@ -98,11 +122,8 @@ static void fz_knockout_begin(void *user) if ((dev->blendmode & FZ_BLEND_KNOCKOUT) == 0) return; - if (dev->top == STACK_SIZE) - { - fz_warn("assert: too many buffers on stack"); - return; - } + if (dev->top == dev->stack_max) + fz_grow_stack(dev); bbox = fz_bound_pixmap(dev->dest); bbox = fz_intersect_bbox(bbox, dev->scissor); @@ -159,11 +180,8 @@ static void fz_knockout_end(void *user) if ((dev->blendmode & FZ_BLEND_KNOCKOUT) == 0) return; - if (dev->top == STACK_SIZE) - { - fz_warn("assert: too many buffers on stack"); - return; - } + if (dev->top == dev->stack_max) + fz_grow_stack(dev); if (dev->top > 0) { @@ -324,11 +342,8 @@ fz_draw_clip_path(void *user, fz_path *path, fz_rect *rect, int even_odd, fz_mat fz_pixmap *mask, *dest, *shape; fz_bbox bbox; - if (dev->top == STACK_SIZE) - { - fz_warn("assert: too many buffers on stack"); - return; - } + if (dev->top == dev->stack_max) + fz_grow_stack(dev); fz_reset_gel(dev->gel, dev->scissor); fz_flatten_fill_path(dev->gel, path, ctm, flatness); @@ -395,11 +410,8 @@ fz_draw_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_sta fz_pixmap *mask, *dest, *shape; fz_bbox bbox; - if (dev->top == STACK_SIZE) - { - fz_warn("assert: too many buffers on stack"); - return; - } + if (dev->top == dev->stack_max) + fz_grow_stack(dev); if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; @@ -608,11 +620,8 @@ fz_draw_clip_text(void *user, fz_text *text, fz_matrix ctm, int accumulate) /* If accumulate == 1 then this text object is the first (or only) in a sequence */ /* If accumulate == 2 then this text object is a continuation */ - if (dev->top == STACK_SIZE) - { - fz_warn("assert: too many buffers on stack"); - return; - } + if (dev->top == dev->stack_max) + fz_grow_stack(dev); if (accumulate == 0) { @@ -701,11 +710,8 @@ fz_draw_clip_stroke_text(void *user, fz_text *text, fz_stroke_state *stroke, fz_ fz_pixmap *glyph; int i, x, y, gid; - if (dev->top == STACK_SIZE) - { - fz_warn("assert: too many buffers on stack"); - return; - } + if (dev->top == dev->stack_max) + fz_grow_stack(dev); /* make the mask the exact size needed */ bbox = fz_round_rect(fz_bound_text(text, ctm)); @@ -1042,11 +1048,8 @@ fz_draw_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix c fz_pixmap *scaled = NULL; int dx, dy; - if (dev->top == STACK_SIZE) - { - fz_warn("assert: too many buffers on stack"); - return; - } + if (dev->top == dev->stack_max) + fz_grow_stack(dev); #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Clip (image mask) begin\n"); @@ -1185,11 +1188,8 @@ fz_draw_begin_mask(void *user, fz_rect rect, int luminosity, fz_colorspace *colo fz_pixmap *shape = dev->shape; fz_bbox bbox; - if (dev->top == STACK_SIZE) - { - fz_warn("assert: too many buffers on stack"); - return; - } + if (dev->top == dev->stack_max) + fz_grow_stack(dev); bbox = fz_round_rect(rect); bbox = fz_intersect_bbox(bbox, dev->scissor); @@ -1247,11 +1247,8 @@ fz_draw_end_mask(void *user) fz_bbox bbox; int luminosity; - if (dev->top == STACK_SIZE) - { - fz_warn("assert: too many buffers on stack"); - return; - } + if (dev->top == dev->stack_max) + fz_grow_stack(dev); if (dev->top > 0) { @@ -1304,7 +1301,7 @@ fz_draw_begin_group(void *user, fz_rect rect, int isolated, int knockout, int bl fz_bbox bbox; fz_pixmap *dest, *shape; - if (dev->top == STACK_SIZE) + if (dev->top == dev->stack_max) { fz_warn("assert: too many buffers on stack"); return; @@ -1434,11 +1431,8 @@ fz_draw_begin_tile(void *user, fz_rect area, fz_rect view, float xstep, float ys /* area, view, xstep, ystep are in pattern space */ /* ctm maps from pattern space to device space */ - if (dev->top == STACK_SIZE) - { - fz_warn("assert: too many buffers on stack"); - return; - } + if (dev->top == dev->stack_max) + fz_grow_stack(dev); if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(dev); @@ -1524,6 +1518,8 @@ fz_draw_free_user(void *user) /* TODO: pop and free the stacks */ if (dev->top > 0) fz_warn("items left on stack in draw device: %d", dev->top); + if (dev->stack != &dev->init_stack[0]) + fz_free(dev->stack); fz_free_gel(dev->gel); fz_free(dev); } @@ -1540,6 +1536,8 @@ fz_new_draw_device(fz_glyph_cache *cache, fz_pixmap *dest) ddev->top = 0; ddev->blendmode = 0; ddev->flags = 0; + ddev->stack = &ddev->init_stack[0]; + ddev->stack_max = STACK_SIZE; ddev->scissor.x0 = dest->x; ddev->scissor.y0 = dest->y; |