summaryrefslogtreecommitdiff
path: root/draw/draw_device.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2011-11-15 16:40:18 +0000
committerRobin Watts <robin.watts@artifex.com>2011-11-15 16:40:18 +0000
commit819aed16c190263a853fabe07870f9da98070f80 (patch)
tree325d6cfa3ff2c8df052c1a812c8775ff62fb3ec8 /draw/draw_device.c
parent54d7093e80e419b8aa18ffe33a4a3ff4fda25140 (diff)
downloadmupdf-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.c124
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;