summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-12-14 17:53:57 +0000
committerRobin Watts <robin.watts@artifex.com>2012-12-18 20:30:36 +0000
commit5e969e35932106ccea0163159f0652627115081a (patch)
tree82b785e2f24da50ec72f1d0d4138c4f176441325
parentbc570f7e6d8740d6c7cef91efc464c2bd36bacb8 (diff)
downloadmupdf-5e969e35932106ccea0163159f0652627115081a.tar.xz
Protect against draw device stack confusion due to errors while pushing.
Whenever we have an error while pushing a gstate, we run the risk of getting confused over how many pops we need etc. With this commit we introduce some checking at the dev_null level that attempts to make this behaviour consistent. Any caller may now assume that calling an operation that pushes a clip will always succeed. This means the only error cleanup they need to do is to ensure that if they have pushed a clip (or begun a group, or a mask etc) is to pop it too. Any callee may now assume that if it throws an error during the call to a device entrypoint that would create a group/clip/mask then no more calls will be forthcoming until after the caller has completely finished with that group. This is achieved by the dev_null layer (the layer that indirects from device calls through the device structure to the function pointers) swallowing errors and regurgitating them later as required. A count is kept of the number of pushes that have happened since an error occurred during a push (including that initial one). When this count reaches zero, the original error is regurgitated. This allows the caller to keep the cookie correctly updated.
-rw-r--r--draw/draw_device.c593
-rw-r--r--fitz/base_error.c6
-rw-r--r--fitz/dev_null.c211
-rw-r--r--fitz/fitz-internal.h3
-rw-r--r--fitz/fitz.h6
5 files changed, 525 insertions, 294 deletions
diff --git a/draw/draw_device.c b/draw/draw_device.c
index a52c77ca..96c4dd53 100644
--- a/draw/draw_device.c
+++ b/draw/draw_device.c
@@ -109,6 +109,20 @@ push_stack(fz_draw_device *dev)
return state;
}
+static void emergency_pop_stack(fz_draw_device *dev, fz_draw_state *state)
+{
+ fz_context *ctx = dev->ctx;
+
+ if (state[1].mask != state[0].mask)
+ fz_drop_pixmap(ctx, state[1].mask);
+ if (state[1].dest != state[0].dest)
+ fz_drop_pixmap(ctx, state[1].dest);
+ if (state[1].shape != state[0].shape)
+ fz_drop_pixmap(ctx, state[1].shape);
+ dev->top--;
+ fz_rethrow(ctx);
+}
+
static fz_draw_state *
fz_knockout_begin(fz_draw_device *dev)
{
@@ -340,13 +354,17 @@ fz_draw_clip_path(fz_device *devp, fz_path *path, fz_rect *rect, int even_odd, f
float expansion = fz_matrix_expansion(ctm);
float flatness = 0.3f / expansion;
fz_bbox bbox;
- fz_draw_state *state = push_stack(dev);
- fz_colorspace *model = state->dest->colorspace;
+ fz_draw_state *state = &dev->stack[dev->top];
+ fz_colorspace *model;
+ fz_context *ctx = dev->ctx;
fz_reset_gel(dev->gel, state->scissor);
fz_flatten_fill_path(dev->gel, path, ctm, flatness);
fz_sort_gel(dev->gel);
+ state = push_stack(dev);
+ model = state->dest->colorspace;
+
bbox = fz_bound_gel(dev->gel);
bbox = fz_intersect_bbox(bbox, state->scissor);
if (rect)
@@ -362,23 +380,30 @@ fz_draw_clip_path(fz_device *devp, fz_path *path, fz_rect *rect, int even_odd, f
return;
}
- state[1].mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
- fz_clear_pixmap(dev->ctx, state[1].mask);
- state[1].dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
- fz_clear_pixmap(dev->ctx, state[1].dest);
- if (state[1].shape)
+ fz_try(ctx)
{
- state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
- fz_clear_pixmap(dev->ctx, state[1].shape);
- }
+ state[1].mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ fz_clear_pixmap(dev->ctx, state[1].mask);
+ state[1].dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
+ fz_clear_pixmap(dev->ctx, state[1].dest);
+ if (state[1].shape)
+ {
+ state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ fz_clear_pixmap(dev->ctx, state[1].shape);
+ }
- fz_scan_convert(dev->gel, even_odd, bbox, state[1].mask, NULL);
+ fz_scan_convert(dev->gel, even_odd, bbox, state[1].mask, NULL);
- state[1].blendmode |= FZ_BLEND_ISOLATED;
- state[1].scissor = bbox;
+ state[1].blendmode |= FZ_BLEND_ISOLATED;
+ state[1].scissor = bbox;
#ifdef DUMP_GROUP_BLENDS
- dump_spaces(dev->top-1, "Clip (non-rectangular) begin\n");
+ dump_spaces(dev->top-1, "Clip (non-rectangular) begin\n");
#endif
+ }
+ fz_catch(ctx)
+ {
+ emergency_pop_stack(dev, state);
+ }
}
static void
@@ -389,8 +414,9 @@ fz_draw_clip_stroke_path(fz_device *devp, fz_path *path, fz_rect *rect, fz_strok
float flatness = 0.3f / expansion;
float linewidth = stroke->linewidth;
fz_bbox bbox;
- fz_draw_state *state = push_stack(dev);
- fz_colorspace *model = state->dest->colorspace;
+ fz_draw_state *state = &dev->stack[dev->top];
+ fz_colorspace *model;
+ fz_context *ctx = dev->ctx;
if (linewidth * expansion < 0.1f)
linewidth = 1 / expansion;
@@ -402,29 +428,39 @@ fz_draw_clip_stroke_path(fz_device *devp, fz_path *path, fz_rect *rect, fz_strok
fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth);
fz_sort_gel(dev->gel);
+ state = push_stack(dev);
+ model = state->dest->colorspace;
+
bbox = fz_bound_gel(dev->gel);
bbox = fz_intersect_bbox(bbox, state->scissor);
if (rect)
bbox = fz_intersect_bbox(bbox, fz_bbox_covering_rect(*rect));
- state[1].mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
- fz_clear_pixmap(dev->ctx, state[1].mask);
- state[1].dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
- fz_clear_pixmap(dev->ctx, state[1].dest);
- if (state->shape)
+ fz_try(ctx)
{
- state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
- fz_clear_pixmap(dev->ctx, state[1].shape);
- }
+ state[1].mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ fz_clear_pixmap(dev->ctx, state[1].mask);
+ state[1].dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
+ fz_clear_pixmap(dev->ctx, state[1].dest);
+ if (state->shape)
+ {
+ state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ fz_clear_pixmap(dev->ctx, state[1].shape);
+ }
- if (!fz_is_empty_rect(bbox))
- fz_scan_convert(dev->gel, 0, bbox, state[1].mask, NULL);
+ if (!fz_is_empty_rect(bbox))
+ fz_scan_convert(dev->gel, 0, bbox, state[1].mask, NULL);
- state[1].blendmode |= FZ_BLEND_ISOLATED;
- state[1].scissor = bbox;
+ state[1].blendmode |= FZ_BLEND_ISOLATED;
+ state[1].scissor = bbox;
#ifdef DUMP_GROUP_BLENDS
- dump_spaces(dev->top-1, "Clip (stroke) begin\n");
+ dump_spaces(dev->top-1, "Clip (stroke) begin\n");
#endif
+ }
+ fz_catch(ctx)
+ {
+ emergency_pop_stack(dev, state);
+ }
}
static void
@@ -645,97 +681,106 @@ fz_draw_clip_text(fz_device *devp, fz_text *text, fz_matrix ctm, int accumulate)
bbox = state->scissor;
}
- if (accumulate == 0 || accumulate == 1)
+ fz_try(ctx)
{
- mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
- fz_clear_pixmap(dev->ctx, mask);
- dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
- fz_clear_pixmap(dev->ctx, dest);
- if (state->shape)
+ if (accumulate == 0 || accumulate == 1)
{
- shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
- fz_clear_pixmap(dev->ctx, shape);
- }
- else
- shape = NULL;
+ mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ fz_clear_pixmap(dev->ctx, mask);
+ dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
+ fz_clear_pixmap(dev->ctx, dest);
+ if (state->shape)
+ {
+ shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ fz_clear_pixmap(dev->ctx, shape);
+ }
+ else
+ shape = NULL;
- state[1].blendmode |= FZ_BLEND_ISOLATED;
- state[1].scissor = bbox;
- state[1].dest = dest;
- state[1].mask = mask;
- state[1].shape = shape;
+ state[1].blendmode |= FZ_BLEND_ISOLATED;
+ state[1].scissor = bbox;
+ state[1].dest = dest;
+ state[1].mask = mask;
+ state[1].shape = shape;
#ifdef DUMP_GROUP_BLENDS
- dump_spaces(dev->top-1, "Clip (text) begin\n");
+ dump_spaces(dev->top-1, "Clip (text) begin\n");
#endif
- }
- else
- {
- mask = state->mask;
- dev->top--;
- }
-
- if (!fz_is_empty_rect(bbox) && mask)
- {
- tm = text->trm;
+ }
+ else
+ {
+ mask = state->mask;
+ dev->top--;
+ }
- for (i = 0; i < text->len; i++)
+ if (!fz_is_empty_rect(bbox) && mask)
{
- gid = text->items[i].gid;
- if (gid < 0)
- continue;
-
- tm.e = text->items[i].x;
- tm.f = text->items[i].y;
- trm = fz_concat(tm, ctm);
- x = floorf(trm.e);
- y = floorf(trm.f);
-
- trunc_trm = trm;
- trunc_trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX);
- trunc_trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX);
-
- glyph = fz_render_glyph(dev->ctx, text->font, gid, trunc_trm, model, bbox);
- if (glyph)
- {
- draw_glyph(NULL, mask, glyph, x, y, bbox);
- if (state[1].shape)
- draw_glyph(NULL, state[1].shape, glyph, x, y, bbox);
- fz_drop_pixmap(dev->ctx, glyph);
- }
- else
+ tm = text->trm;
+
+ for (i = 0; i < text->len; i++)
{
- fz_path *path = fz_outline_glyph(dev->ctx, text->font, gid, trm);
- if (path)
+ gid = text->items[i].gid;
+ if (gid < 0)
+ continue;
+
+ tm.e = text->items[i].x;
+ tm.f = text->items[i].y;
+ trm = fz_concat(tm, ctm);
+ x = floorf(trm.e);
+ y = floorf(trm.f);
+
+ trunc_trm = trm;
+ trunc_trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX);
+ trunc_trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX);
+
+ glyph = fz_render_glyph(dev->ctx, text->font, gid, trunc_trm, model, bbox);
+ if (glyph)
{
- fz_pixmap *old_dest;
- float white = 1;
-
- state = &dev->stack[dev->top];
- old_dest = state[0].dest;
- state[0].dest = state[0].mask;
- state[0].mask = NULL;
- fz_try(ctx)
- {
- fz_draw_fill_path(devp, path, 0, fz_identity, fz_device_gray, &white, 1);
- }
- fz_always(ctx)
+ draw_glyph(NULL, mask, glyph, x, y, bbox);
+ if (state[1].shape)
+ draw_glyph(NULL, state[1].shape, glyph, x, y, bbox);
+ fz_drop_pixmap(dev->ctx, glyph);
+ }
+ else
+ {
+ fz_path *path = fz_outline_glyph(dev->ctx, text->font, gid, trm);
+ if (path)
{
- state[0].mask = state[0].dest;
- state[0].dest = old_dest;
- fz_free_path(dev->ctx, path);
+ fz_pixmap *old_dest;
+ float white = 1;
+
+ state = &dev->stack[dev->top];
+ old_dest = state[0].dest;
+ state[0].dest = state[0].mask;
+ state[0].mask = NULL;
+ fz_try(ctx)
+ {
+ fz_draw_fill_path(devp, path, 0, fz_identity, fz_device_gray, &white, 1);
+ }
+ fz_always(ctx)
+ {
+ state[0].mask = state[0].dest;
+ state[0].dest = old_dest;
+ fz_free_path(dev->ctx, path);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
}
- fz_catch(ctx)
+ else
{
- fz_rethrow(ctx);
+ fz_warn(dev->ctx, "cannot render glyph for clipping");
}
}
- else
- {
- fz_warn(dev->ctx, "cannot render glyph for clipping");
- }
}
}
}
+ fz_catch(ctx)
+ {
+ if (accumulate == 0 || accumulate == 1)
+ emergency_pop_stack(dev, state);
+ fz_rethrow(ctx);
+ }
}
static void
@@ -755,89 +800,93 @@ fz_draw_clip_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke
bbox = fz_bbox_covering_rect(fz_bound_text(dev->ctx, text, ctm));
bbox = fz_intersect_bbox(bbox, state->scissor);
- mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
- fz_clear_pixmap(dev->ctx, mask);
- dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
- fz_clear_pixmap(dev->ctx, dest);
- if (state->shape)
+ fz_try(ctx)
{
- shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
- fz_clear_pixmap(dev->ctx, shape);
- }
- else
- shape = state->shape;
+ state[1].mask = mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ fz_clear_pixmap(dev->ctx, mask);
+ state[1].dest = dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
+ fz_clear_pixmap(dev->ctx, dest);
+ if (state->shape)
+ {
+ state[1].shape = shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ fz_clear_pixmap(dev->ctx, shape);
+ }
+ else
+ shape = state->shape;
- state[1].blendmode |= FZ_BLEND_ISOLATED;
- state[1].scissor = bbox;
- state[1].dest = dest;
- state[1].shape = shape;
- state[1].mask = mask;
+ state[1].blendmode |= FZ_BLEND_ISOLATED;
+ state[1].scissor = bbox;
#ifdef DUMP_GROUP_BLENDS
- dump_spaces(dev->top-1, "Clip (stroke text) begin\n");
+ dump_spaces(dev->top-1, "Clip (stroke text) begin\n");
#endif
- if (!fz_is_empty_rect(bbox))
- {
- tm = text->trm;
-
- for (i = 0; i < text->len; i++)
+ if (!fz_is_empty_rect(bbox))
{
- gid = text->items[i].gid;
- if (gid < 0)
- continue;
-
- tm.e = text->items[i].x;
- tm.f = text->items[i].y;
- trm = fz_concat(tm, ctm);
- x = floorf(trm.e);
- y = floorf(trm.f);
-
- trunc_trm = trm;
- trunc_trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX);
- trunc_trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX);
-
- glyph = fz_render_stroked_glyph(dev->ctx, text->font, gid, trunc_trm, ctm, stroke, bbox);
- if (glyph)
- {
- draw_glyph(NULL, mask, glyph, x, y, bbox);
- if (shape)
- draw_glyph(NULL, shape, glyph, x, y, bbox);
- fz_drop_pixmap(dev->ctx, glyph);
- }
- else
+ tm = text->trm;
+
+ for (i = 0; i < text->len; i++)
{
- fz_path *path = fz_outline_glyph(dev->ctx, text->font, gid, trm);
- if (path)
+ gid = text->items[i].gid;
+ if (gid < 0)
+ continue;
+
+ tm.e = text->items[i].x;
+ tm.f = text->items[i].y;
+ trm = fz_concat(tm, ctm);
+ x = floorf(trm.e);
+ y = floorf(trm.f);
+
+ trunc_trm = trm;
+ trunc_trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX);
+ trunc_trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX);
+
+ glyph = fz_render_stroked_glyph(dev->ctx, text->font, gid, trunc_trm, ctm, stroke, bbox);
+ if (glyph)
{
- fz_pixmap *old_dest;
- float white = 1;
-
- state = &dev->stack[dev->top];
- old_dest = state[0].dest;
- state[0].dest = state[0].mask;
- state[0].mask = NULL;
- fz_try(ctx)
- {
- fz_draw_stroke_path(devp, path, stroke, fz_identity, fz_device_gray, &white, 1);
- }
- fz_always(ctx)
+ draw_glyph(NULL, mask, glyph, x, y, bbox);
+ if (shape)
+ draw_glyph(NULL, shape, glyph, x, y, bbox);
+ fz_drop_pixmap(dev->ctx, glyph);
+ }
+ else
+ {
+ fz_path *path = fz_outline_glyph(dev->ctx, text->font, gid, trm);
+ if (path)
{
- state[0].mask = state[0].dest;
- state[0].dest = old_dest;
- fz_free_path(dev->ctx, path);
+ fz_pixmap *old_dest;
+ float white = 1;
+
+ state = &dev->stack[dev->top];
+ old_dest = state[0].dest;
+ state[0].dest = state[0].mask;
+ state[0].mask = NULL;
+ fz_try(ctx)
+ {
+ fz_draw_stroke_path(devp, path, stroke, fz_identity, fz_device_gray, &white, 1);
+ }
+ fz_always(ctx)
+ {
+ state[0].mask = state[0].dest;
+ state[0].dest = old_dest;
+ fz_free_path(dev->ctx, path);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
}
- fz_catch(ctx)
+ else
{
- fz_rethrow(ctx);
+ fz_warn(dev->ctx, "cannot render glyph for stroked clipping");
}
}
- else
- {
- fz_warn(dev->ctx, "cannot render glyph for stroked clipping");
- }
}
}
}
+ fz_catch(ctx)
+ {
+ emergency_pop_stack(dev, state);
+ }
}
static void
@@ -1177,8 +1226,8 @@ fz_draw_clip_image_mask(fz_device *devp, fz_image *image, fz_rect *rect, fz_matr
fz_pixmap *dest = NULL;
fz_pixmap *shape = NULL;
fz_pixmap *scaled = NULL;
- fz_pixmap *pixmap;
- fz_pixmap *orig_pixmap;
+ fz_pixmap *pixmap = NULL;
+ fz_pixmap *orig_pixmap = NULL;
int dx, dy;
fz_draw_state *state = push_stack(dev);
fz_colorspace *model = state->dest->colorspace;
@@ -1189,6 +1238,8 @@ fz_draw_clip_image_mask(fz_device *devp, fz_image *image, fz_rect *rect, fz_matr
fz_var(mask);
fz_var(dest);
fz_var(shape);
+ fz_var(pixmap);
+ fz_var(orig_pixmap);
if (image->w == 0 || image->h == 0)
{
@@ -1211,22 +1262,26 @@ fz_draw_clip_image_mask(fz_device *devp, fz_image *image, fz_rect *rect, fz_matr
dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
- pixmap = fz_image_to_pixmap(ctx, image, dx, dy);
- orig_pixmap = pixmap;
fz_try(ctx)
{
- mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ pixmap = fz_image_to_pixmap(ctx, image, dx, dy);
+ orig_pixmap = pixmap;
+
+ state[1].mask = mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
fz_clear_pixmap(dev->ctx, mask);
- dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
+ state[1].dest = dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
fz_clear_pixmap(dev->ctx, dest);
if (state->shape)
{
- shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ state[1].shape = shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
fz_clear_pixmap(dev->ctx, shape);
}
+ state[1].blendmode |= FZ_BLEND_ISOLATED;
+ state[1].scissor = bbox;
+
if (dx < pixmap->w && dy < pixmap->h)
{
int gridfit = !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
@@ -1243,7 +1298,6 @@ fz_draw_clip_image_mask(fz_device *devp, fz_image *image, fz_rect *rect, fz_matr
pixmap = scaled;
}
fz_paint_image(mask, bbox, state->shape, pixmap, ctm, 255);
-
}
fz_always(ctx)
{
@@ -1252,17 +1306,8 @@ fz_draw_clip_image_mask(fz_device *devp, fz_image *image, fz_rect *rect, fz_matr
}
fz_catch(ctx)
{
- fz_drop_pixmap(ctx, shape);
- fz_drop_pixmap(ctx, dest);
- fz_drop_pixmap(ctx, mask);
- fz_rethrow(ctx);
+ emergency_pop_stack(dev, state);
}
-
- state[1].blendmode |= FZ_BLEND_ISOLATED;
- state[1].scissor = bbox;
- state[1].dest = dest;
- state[1].shape = shape;
- state[1].mask = mask;
}
static void
@@ -1325,45 +1370,52 @@ fz_draw_begin_mask(fz_device *devp, fz_rect rect, int luminosity, fz_colorspace
fz_bbox bbox;
fz_draw_state *state = push_stack(dev);
fz_pixmap *shape = state->shape;
+ fz_context *ctx = dev->ctx;
bbox = fz_bbox_covering_rect(rect);
bbox = fz_intersect_bbox(bbox, state->scissor);
- dest = fz_new_pixmap_with_bbox(dev->ctx, fz_device_gray, bbox);
- if (state->shape)
- {
- /* FIXME: If we ever want to support AIS true, then we
- * probably want to create a shape pixmap here, using:
- * shape = fz_new_pixmap_with_bbox(NULL, bbox);
- * then, in the end_mask code, we create the mask from this
- * rather than dest.
- */
- shape = NULL;
- }
- if (luminosity)
- {
- float bc;
- if (!colorspace)
- colorspace = fz_device_gray;
- fz_convert_color(dev->ctx, fz_device_gray, &bc, colorspace, colorfv);
- fz_clear_pixmap_with_value(dev->ctx, dest, bc * 255);
- if (shape)
- fz_clear_pixmap_with_value(dev->ctx, shape, 255);
- }
- else
+ fz_try(ctx)
{
- fz_clear_pixmap(dev->ctx, dest);
- if (shape)
- fz_clear_pixmap(dev->ctx, shape);
- }
+ state[1].dest = dest = fz_new_pixmap_with_bbox(dev->ctx, fz_device_gray, bbox);
+ if (state->shape)
+ {
+ /* FIXME: If we ever want to support AIS true, then
+ * we probably want to create a shape pixmap here,
+ * using: shape = fz_new_pixmap_with_bbox(NULL, bbox);
+ * then, in the end_mask code, we create the mask
+ * from this rather than dest.
+ */
+ state[1].shape = shape = NULL;
+ }
+
+ if (luminosity)
+ {
+ float bc;
+ if (!colorspace)
+ colorspace = fz_device_gray;
+ fz_convert_color(dev->ctx, fz_device_gray, &bc, colorspace, colorfv);
+ fz_clear_pixmap_with_value(dev->ctx, dest, bc * 255);
+ if (shape)
+ fz_clear_pixmap_with_value(dev->ctx, shape, 255);
+ }
+ else
+ {
+ fz_clear_pixmap(dev->ctx, dest);
+ if (shape)
+ fz_clear_pixmap(dev->ctx, shape);
+ }
#ifdef DUMP_GROUP_BLENDS
- dump_spaces(dev->top-1, "Mask begin\n");
+ dump_spaces(dev->top-1, "Mask begin\n");
#endif
- state[1].scissor = bbox;
- state[1].dest = dest;
- state[1].shape = shape;
- state[1].luminosity = luminosity;
+ state[1].scissor = bbox;
+ state[1].luminosity = luminosity;
+ }
+ fz_catch(ctx)
+ {
+ emergency_pop_stack(dev, state);
+ }
}
static void
@@ -1435,51 +1487,49 @@ fz_draw_begin_group(fz_device *devp, fz_rect rect, int isolated, int knockout, i
state = push_stack(dev);
bbox = fz_bbox_covering_rect(rect);
bbox = fz_intersect_bbox(bbox, state->scissor);
- dest = fz_new_pixmap_with_bbox(ctx, model, bbox);
+
+ fz_try(ctx)
+ {
+ state[1].dest = dest = fz_new_pixmap_with_bbox(ctx, model, bbox);
#ifndef ATTEMPT_KNOCKOUT_AND_ISOLATED
- knockout = 0;
- isolated = 1;
+ knockout = 0;
+ isolated = 1;
#endif
- if (isolated)
- {
- fz_clear_pixmap(dev->ctx, dest);
- }
- else
- {
- fz_copy_pixmap_rect(dev->ctx, dest, state[0].dest, bbox);
- }
+ if (isolated)
+ {
+ fz_clear_pixmap(dev->ctx, dest);
+ }
+ else
+ {
+ fz_copy_pixmap_rect(dev->ctx, dest, state[0].dest, bbox);
+ }
- if (blendmode == 0 && alpha == 1.0 && isolated)
- {
- /* We can render direct to any existing shape plane. If there
- * isn't one, we don't need to make one. */
- shape = state[0].shape;
- }
- else
- {
- fz_try(ctx)
+ if (blendmode == 0 && alpha == 1.0 && isolated)
{
- shape = fz_new_pixmap_with_bbox(ctx, NULL, bbox);
- fz_clear_pixmap(dev->ctx, shape);
+ /* We can render direct to any existing shape plane.
+ * If there isn't one, we don't need to make one. */
+ state[1].shape =shape = state[0].shape;
}
- fz_catch(ctx)
+ else
{
- fz_drop_pixmap(ctx, dest);
- fz_rethrow(ctx);
+ state[1].shape = shape = fz_new_pixmap_with_bbox(ctx, NULL, bbox);
+ fz_clear_pixmap(dev->ctx, shape);
}
- }
- state[1].alpha = alpha;
+ state[1].alpha = alpha;
#ifdef DUMP_GROUP_BLENDS
- dump_spaces(dev->top-1, "Group begin\n");
+ dump_spaces(dev->top-1, "Group begin\n");
#endif
- state[1].scissor = bbox;
- state[1].dest = dest;
- state[1].shape = shape;
- state[1].blendmode = blendmode | (isolated ? FZ_BLEND_ISOLATED : 0) | (knockout ? FZ_BLEND_KNOCKOUT : 0);
+ state[1].scissor = bbox;
+ state[1].blendmode = blendmode | (isolated ? FZ_BLEND_ISOLATED : 0) | (knockout ? FZ_BLEND_KNOCKOUT : 0);
+ }
+ fz_catch(ctx)
+ {
+ emergency_pop_stack(dev, state);
+ }
}
static void
@@ -1568,35 +1618,32 @@ fz_draw_begin_tile(fz_device *devp, fz_rect area, fz_rect view, float xstep, flo
* assert(bbox.x0 > state->dest->x || bbox.x1 < state->dest->x + state->dest->w ||
* bbox.y0 > state->dest->y || bbox.y1 < state->dest->y + state->dest->h);
*/
- dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
- fz_clear_pixmap(ctx, dest);
- shape = state[0].shape;
- if (shape)
+ fz_try(ctx)
{
- fz_var(shape);
- fz_try(ctx)
+ state[1].dest = dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox);
+ fz_clear_pixmap(ctx, dest);
+ shape = state[0].shape;
+ if (shape)
{
- shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
+ state[1].shape = shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox);
fz_clear_pixmap(ctx, shape);
}
- fz_catch(ctx)
- {
- fz_drop_pixmap(ctx, dest);
- fz_rethrow(ctx);
- }
- }
- state[1].blendmode |= FZ_BLEND_ISOLATED;
- state[1].xstep = xstep;
- state[1].ystep = ystep;
- state[1].area = area;
- state[1].ctm = ctm;
+ state[1].blendmode |= FZ_BLEND_ISOLATED;
+ state[1].xstep = xstep;
+ state[1].ystep = ystep;
+ state[1].area = area;
+ state[1].ctm = ctm;
#ifdef DUMP_GROUP_BLENDS
- dump_spaces(dev->top-1, "Tile begin\n");
+ dump_spaces(dev->top-1, "Tile begin\n");
#endif
- state[1].scissor = bbox;
- state[1].dest = dest;
- state[1].shape = shape;
+ state[1].scissor = bbox;
+ }
+ fz_catch(ctx)
+ {
+ emergency_pop_stack(dev, state);
+ }
+
}
static void
diff --git a/fitz/base_error.c b/fitz/base_error.c
index 0167611a..5ec97a0a 100644
--- a/fitz/base_error.c
+++ b/fitz/base_error.c
@@ -18,7 +18,7 @@ void fz_flush_warnings(fz_context *ctx)
ctx->warn->count = 0;
}
-void fz_warn(fz_context *ctx, char *fmt, ...)
+void fz_warn(fz_context *ctx, const char *fmt, ...)
{
va_list ap;
char buf[sizeof ctx->warn->message];
@@ -100,14 +100,14 @@ int fz_push_try(fz_error_context *ex)
return 0;
}
-char *fz_caught(fz_context *ctx)
+const char *fz_caught(fz_context *ctx)
{
assert(ctx);
assert(ctx->error);
return ctx->error->message;
}
-void fz_throw(fz_context *ctx, char *fmt, ...)
+void fz_throw(fz_context *ctx, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
diff --git a/fitz/dev_null.c b/fitz/dev_null.c
index 886cebe1..ac495cef 100644
--- a/fitz/dev_null.c
+++ b/fitz/dev_null.c
@@ -8,6 +8,7 @@ fz_new_device(fz_context *ctx, void *user)
dev->flags = 0;
dev->user = user;
dev->ctx = ctx;
+ dev->error_depth = 0;
return dev;
}
@@ -25,6 +26,8 @@ void
fz_fill_path(fz_device *dev, fz_path *path, int even_odd, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
+ if (dev->error_depth)
+ return;
if (dev->fill_path)
dev->fill_path(dev, path, even_odd, ctm, colorspace, color, alpha);
}
@@ -33,6 +36,8 @@ void
fz_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
+ if (dev->error_depth)
+ return;
if (dev->stroke_path)
dev->stroke_path(dev, path, stroke, ctm, colorspace, color, alpha);
}
@@ -40,21 +45,57 @@ fz_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_matrix
void
fz_clip_path(fz_device *dev, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm)
{
- if (dev->clip_path)
- dev->clip_path(dev, path, rect, even_odd, ctm);
+ fz_context *ctx = dev->ctx;
+
+ if (dev->error_depth)
+ {
+ dev->error_depth++;
+ return;
+ }
+
+ fz_try(ctx)
+ {
+ if (dev->clip_path)
+ dev->clip_path(dev, path, rect, even_odd, ctm);
+ }
+ fz_catch(ctx)
+ {
+ dev->error_depth = 1;
+ strcpy(dev->errmess, fz_caught(ctx));
+ /* Error swallowed */
+ }
}
void
fz_clip_stroke_path(fz_device *dev, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm)
{
- if (dev->clip_stroke_path)
- dev->clip_stroke_path(dev, path, rect, stroke, ctm);
+ fz_context *ctx = dev->ctx;
+
+ if (dev->error_depth)
+ {
+ dev->error_depth++;
+ return;
+ }
+
+ fz_try(ctx)
+ {
+ if (dev->clip_stroke_path)
+ dev->clip_stroke_path(dev, path, rect, stroke, ctm);
+ }
+ fz_catch(ctx)
+ {
+ dev->error_depth = 1;
+ strcpy(dev->errmess, fz_caught(ctx));
+ /* Error swallowed */
+ }
}
void
fz_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
+ if (dev->error_depth)
+ return;
if (dev->fill_text)
dev->fill_text(dev, text, ctm, colorspace, color, alpha);
}
@@ -63,6 +104,8 @@ void
fz_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
+ if (dev->error_depth)
+ return;
if (dev->stroke_text)
dev->stroke_text(dev, text, stroke, ctm, colorspace, color, alpha);
}
@@ -70,20 +113,59 @@ fz_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix
void
fz_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate)
{
- if (dev->clip_text)
- dev->clip_text(dev, text, ctm, accumulate);
+ fz_context *ctx = dev->ctx;
+
+ if (dev->error_depth)
+ {
+ if (accumulate == 0 || accumulate == 1)
+ dev->error_depth++;
+ return;
+ }
+
+ fz_try(ctx)
+ {
+ if (dev->clip_text)
+ dev->clip_text(dev, text, ctm, accumulate);
+ }
+ fz_catch(ctx)
+ {
+ if (accumulate == 2)
+ fz_rethrow(ctx);
+ dev->error_depth = 1;
+ strcpy(dev->errmess, fz_caught(ctx));
+ /* Error swallowed */
+ }
}
void
fz_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm)
{
- if (dev->clip_stroke_text)
- dev->clip_stroke_text(dev, text, stroke, ctm);
+ fz_context *ctx = dev->ctx;
+
+ if (dev->error_depth)
+ {
+ dev->error_depth++;
+ return;
+ }
+
+ fz_try(ctx)
+ {
+ if (dev->clip_stroke_text)
+ dev->clip_stroke_text(dev, text, stroke, ctm);
+ }
+ fz_catch(ctx)
+ {
+ dev->error_depth = 1;
+ strcpy(dev->errmess, fz_caught(ctx));
+ /* Error swallowed */
+ }
}
void
fz_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm)
{
+ if (dev->error_depth)
+ return;
if (dev->ignore_text)
dev->ignore_text(dev, text, ctm);
}
@@ -91,6 +173,12 @@ fz_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm)
void
fz_pop_clip(fz_device *dev)
{
+ if (dev->error_depth)
+ {
+ dev->error_depth--;
+ if (dev->error_depth == 0)
+ fz_throw(dev->ctx, "%s", dev->errmess);
+ }
if (dev->pop_clip)
dev->pop_clip(dev);
}
@@ -98,6 +186,8 @@ fz_pop_clip(fz_device *dev)
void
fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha)
{
+ if (dev->error_depth)
+ return;
if (dev->fill_shade)
dev->fill_shade(dev, shade, ctm, alpha);
}
@@ -105,6 +195,8 @@ fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha)
void
fz_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha)
{
+ if (dev->error_depth)
+ return;
if (dev->fill_image)
dev->fill_image(dev, image, ctm, alpha);
}
@@ -113,6 +205,8 @@ void
fz_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
+ if (dev->error_depth)
+ return;
if (dev->fill_image_mask)
dev->fill_image_mask(dev, image, ctm, colorspace, color, alpha);
}
@@ -120,20 +214,59 @@ fz_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm,
void
fz_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm)
{
- if (dev->clip_image_mask)
- dev->clip_image_mask(dev, image, rect, ctm);
+ fz_context *ctx = dev->ctx;
+
+ if (dev->error_depth)
+ {
+ dev->error_depth++;
+ return;
+ }
+
+ fz_try(ctx)
+ {
+ if (dev->clip_image_mask)
+ dev->clip_image_mask(dev, image, rect, ctm);
+ }
+ fz_catch(ctx)
+ {
+ dev->error_depth = 1;
+ strcpy(dev->errmess, fz_caught(ctx));
+ /* Error swallowed */
+ }
}
void
fz_begin_mask(fz_device *dev, fz_rect area, int luminosity, fz_colorspace *colorspace, float *bc)
{
- if (dev->begin_mask)
- dev->begin_mask(dev, area, luminosity, colorspace, bc);
+ fz_context *ctx = dev->ctx;
+
+ if (dev->error_depth)
+ {
+ dev->error_depth++;
+ return;
+ }
+
+ fz_try(ctx)
+ {
+ if (dev->begin_mask)
+ dev->begin_mask(dev, area, luminosity, colorspace, bc);
+ }
+ fz_catch(ctx)
+ {
+ dev->error_depth = 1;
+ strcpy(dev->errmess, fz_caught(ctx));
+ /* Error swallowed */
+ }
}
void
fz_end_mask(fz_device *dev)
{
+ if (dev->error_depth)
+ {
+ /* Converts from mask to clip, so no change in stack depth */
+ return;
+ }
if (dev->end_mask)
dev->end_mask(dev);
}
@@ -141,13 +274,36 @@ fz_end_mask(fz_device *dev)
void
fz_begin_group(fz_device *dev, fz_rect area, int isolated, int knockout, int blendmode, float alpha)
{
- if (dev->begin_group)
- dev->begin_group(dev, area, isolated, knockout, blendmode, alpha);
+ fz_context *ctx = dev->ctx;
+
+ if (dev->error_depth)
+ {
+ dev->error_depth++;
+ return;
+ }
+
+ fz_try(ctx)
+ {
+ if (dev->begin_group)
+ dev->begin_group(dev, area, isolated, knockout, blendmode, alpha);
+ }
+ fz_catch(ctx)
+ {
+ dev->error_depth = 1;
+ strcpy(dev->errmess, fz_caught(ctx));
+ /* Error swallowed */
+ }
}
void
fz_end_group(fz_device *dev)
{
+ if (dev->error_depth)
+ {
+ dev->error_depth--;
+ if (dev->error_depth == 0)
+ fz_throw(dev->ctx, "%s", dev->errmess);
+ }
if (dev->end_group)
dev->end_group(dev);
}
@@ -155,13 +311,36 @@ fz_end_group(fz_device *dev)
void
fz_begin_tile(fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm)
{
- if (dev->begin_tile)
- dev->begin_tile(dev, area, view, xstep, ystep, ctm);
+ fz_context *ctx = dev->ctx;
+
+ if (dev->error_depth)
+ {
+ dev->error_depth++;
+ return;
+ }
+
+ fz_try(ctx)
+ {
+ if (dev->begin_tile)
+ dev->begin_tile(dev, area, view, xstep, ystep, ctm);
+ }
+ fz_catch(ctx)
+ {
+ dev->error_depth = 1;
+ strcpy(dev->errmess, fz_caught(ctx));
+ /* Error swallowed */
+ }
}
void
fz_end_tile(fz_device *dev)
{
+ if (dev->error_depth)
+ {
+ dev->error_depth--;
+ if (dev->error_depth == 0)
+ fz_throw(dev->ctx, "%s", dev->errmess);
+ }
if (dev->end_tile)
dev->end_tile(dev);
}
diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h
index 0de2e4c2..35b20d71 100644
--- a/fitz/fitz-internal.h
+++ b/fitz/fitz-internal.h
@@ -1396,6 +1396,9 @@ struct fz_device_s
void (*begin_tile)(fz_device *, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm);
void (*end_tile)(fz_device *);
+
+ int error_depth;
+ char errmess[256];
};
void fz_fill_path(fz_device *dev, fz_path *path, int even_odd, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
diff --git a/fitz/fitz.h b/fitz/fitz.h
index 8f2a6edc..ed515642 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -261,9 +261,11 @@ void fz_var_imp(void *);
if (ctx->error->stack[ctx->error->top--].code > 1)
int fz_push_try(fz_error_context *ex);
-void fz_throw(fz_context *, char *, ...) __printflike(2, 3);
+void fz_throw(fz_context *, const char *, ...) __printflike(2, 3);
void fz_rethrow(fz_context *);
-void fz_warn(fz_context *ctx, char *fmt, ...) __printflike(2, 3);
+void fz_warn(fz_context *ctx, const char *fmt, ...) __printflike(2, 3);
+const char *fz_caught(fz_context *ctx);
+
/*
fz_flush_warnings: Flush any repeated warnings.