diff options
author | Robin Watts <robin.watts@artifex.com> | 2017-09-01 16:54:57 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2017-10-24 15:16:36 +0100 |
commit | c7c407b57a6e1aa5b1a11034ec7cb308cf4ad3c4 (patch) | |
tree | 5e3d13a07dcc007de2474027433644ecae3e68e7 /source/fitz/draw-device.c | |
parent | b940c2fda5de510ea814ce63c903bcffb99b92db (diff) | |
download | mupdf-c7c407b57a6e1aa5b1a11034ec7cb308cf4ad3c4.tar.xz |
Add group_alpha plane to draw device and painters.
Diffstat (limited to 'source/fitz/draw-device.c')
-rw-r--r-- | source/fitz/draw-device.c | 311 |
1 files changed, 253 insertions, 58 deletions
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c index 27229108..ff6097fb 100644 --- a/source/fitz/draw-device.c +++ b/source/fitz/draw-device.c @@ -31,6 +31,7 @@ struct fz_draw_state_s { fz_pixmap *dest; fz_pixmap *mask; fz_pixmap *shape; + fz_pixmap *group_alpha; int blendmode; int id, encache; float alpha; @@ -198,6 +199,8 @@ static void emergency_pop_stack(fz_context *ctx, fz_draw_device *dev, fz_draw_st fz_drop_pixmap(ctx, state[1].dest); if (state[1].shape != state[0].shape) fz_drop_pixmap(ctx, state[1].shape); + if (state[1].group_alpha != state[0].group_alpha) + fz_drop_pixmap(ctx, state[1].group_alpha); dev->top--; STACK_POPPED("emergency"); fz_rethrow(ctx); @@ -242,13 +245,14 @@ fz_knockout_begin(fz_context *ctx, fz_draw_device *dev) fz_clear_pixmap(ctx, dest); } + /* Knockout groups (and only knockout groups) rely on shape */ shape = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); fz_clear_pixmap(ctx, shape); #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top-1, ""); fz_dump_blend(ctx, "Knockout begin: background is ", dest); if (shape) - fz_dump_blend(ctx, "/", shape); + fz_dump_blend(ctx, "/S=", shape); printf("\n"); #endif state[1].scissor = bbox; @@ -282,20 +286,22 @@ static void fz_knockout_end(fz_context *ctx, fz_draw_device *dev) dump_spaces(dev->top, ""); fz_dump_blend(ctx, "Knockout end: blending ", state[1].dest); if (state[1].shape) - fz_dump_blend(ctx, "/", state[1].shape); + fz_dump_blend(ctx, "/S=", state[1].shape); + if (state[1].group_alpha) + fz_dump_blend(ctx, "/GA=", state[1].group_alpha); fz_dump_blend(ctx, " onto ", state[0].dest); if (state[0].shape) - fz_dump_blend(ctx, "/", state[0].shape); + fz_dump_blend(ctx, "/S=", state[0].shape); + if (state[0].group_alpha) + fz_dump_blend(ctx, "/GA=", state[0].group_alpha); if (blendmode != 0) printf(" (blend %d)", blendmode); if (isolated != 0) printf(" (isolated)"); printf(" (knockout)"); #endif - if ((blendmode == 0) && (state[0].shape == state[1].shape)) - fz_paint_pixmap(state[0].dest, state[1].dest, 255); - else - fz_blend_pixmap(ctx, state[0].dest, state[1].dest, 255, blendmode, isolated, state[1].shape); + assert(state[1].shape); + fz_blend_pixmap(ctx, state[0].dest, state[1].dest, 255, blendmode, 0, state[1].shape); /* The following test should not be required, but just occasionally * errors can cause the stack to get out of sync, and this saves our @@ -308,10 +314,18 @@ static void fz_knockout_end(fz_context *ctx, fz_draw_device *dev) fz_paint_pixmap(state[0].shape, state[1].shape, 255); fz_drop_pixmap(ctx, state[1].shape); } + if (state[0].group_alpha != state[1].group_alpha) + { + if (state[0].group_alpha) + fz_paint_pixmap(state[0].group_alpha, state[1].group_alpha, 255); + fz_drop_pixmap(ctx, state[1].group_alpha); + } #ifdef DUMP_GROUP_BLENDS fz_dump_blend(ctx, " to get ", state[0].dest); if (state[0].shape) - fz_dump_blend(ctx, "/", state[0].shape); + fz_dump_blend(ctx, "/S=", state[0].shape); + if (state[0].group_alpha) + fz_dump_blend(ctx, "/GA=", state[0].group_alpha); printf("\n"); #endif } @@ -557,9 +571,17 @@ fz_draw_fill_path(fz_context *ctx, fz_device *devp, const fz_path *path, int eve if (!rast->fns.reusable) fz_flatten_fill_path(ctx, rast, path, &ctm, flatness, &bbox, NULL); - colorbv[0] = alpha * 255; + colorbv[0] = 255; fz_convert_rasterizer(ctx, rast, even_odd, state->shape, colorbv, 0); } + if (state->group_alpha) + { + if (!rast->fns.reusable) + fz_flatten_fill_path(ctx, rast, path, &ctm, flatness, &bbox, NULL); + + colorbv[0] = alpha * 255; + fz_convert_rasterizer(ctx, rast, even_odd, state->group_alpha, colorbv, 0); + } if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); @@ -607,7 +629,9 @@ fz_draw_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path, const dump_spaces(dev->top, ""); fz_dump_blend(ctx, "Before stroke ", state->dest); if (state->shape) - fz_dump_blend(ctx, "/", state->shape); + fz_dump_blend(ctx, "/S=", state->shape); + if (state->group_alpha) + fz_dump_blend(ctx, "/GA=", state->group_alpha); printf("\n"); #endif fz_convert_rasterizer(ctx, rast, 0, state->dest, colorbv, eop); @@ -619,11 +643,21 @@ fz_draw_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path, const colorbv[0] = 255; fz_convert_rasterizer(ctx, rast, 0, state->shape, colorbv, 0); } + if (state->group_alpha) + { + if (!rast->fns.reusable) + (void)fz_flatten_stroke_path(ctx, rast, path, stroke, &ctm, flatness, linewidth, &bbox, NULL); + + colorbv[0] = 255 * alpha; + fz_convert_rasterizer(ctx, rast, 0, state->group_alpha, colorbv, 0); + } #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, ""); fz_dump_blend(ctx, "After stroke ", state->dest); if (state->shape) - fz_dump_blend(ctx, "/", state->shape); + fz_dump_blend(ctx, "/S=", state->shape); + if (state->group_alpha) + fz_dump_blend(ctx, "/GA=", state->group_alpha); printf("\n"); #endif @@ -685,6 +719,11 @@ fz_draw_clip_path(fz_context *ctx, fz_device *devp, const fz_path *path, int eve state[1].shape = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); fz_clear_pixmap(ctx, state[1].shape); } + if (state[1].group_alpha) + { + state[1].group_alpha = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); + fz_clear_pixmap(ctx, state[1].group_alpha); + } fz_convert_rasterizer(ctx, rast, even_odd, state[1].mask, NULL, 0); @@ -767,6 +806,11 @@ fz_draw_clip_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path, state[1].shape = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); fz_clear_pixmap(ctx, state[1].shape); } + if (state->group_alpha) + { + state[1].group_alpha = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); + fz_clear_pixmap(ctx, state[1].group_alpha); + } fz_convert_rasterizer(ctx, rast, 0, state[1].mask, NULL, 0); @@ -860,7 +904,7 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; - unsigned char shapebv; + unsigned char shapebv, shapebva; fz_text_span *span; int i; fz_colorspace *colorspace = NULL; @@ -885,6 +929,7 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f eop = resolve_color(ctx, &op, color, colorspace, alpha, color_params, colorbv, state->dest); shapebv = 255; + shapebva = 255 * alpha; for (span = text->head; span; span = span->next) { @@ -915,13 +960,15 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f draw_glyph(colorbv, state->dest, glyph, x, y, &state->scissor, eop); if (state->shape) draw_glyph(&shapebv, state->shape, glyph, x, y, &state->scissor, 0); + if (state->group_alpha) + draw_glyph(&shapebva, state->group_alpha, glyph, x, y, &state->scissor, 0); } else { fz_matrix mat; mat.a = pixmap->w; mat.b = mat.c = 0; mat.d = pixmap->h; mat.e = x + pixmap->x; mat.f = y + pixmap->y; - fz_paint_image(state->dest, &state->scissor, state->shape, pixmap, &mat, alpha * 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED, eop); + fz_paint_image(state->dest, &state->scissor, state->shape, state->group_alpha, pixmap, &mat, alpha * 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED, eop); } fz_drop_glyph(ctx, glyph); } @@ -953,6 +1000,8 @@ fz_draw_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, const fz_matrix ctm = concat(in_ctm, &dev->transform); fz_draw_state *state = &dev->stack[dev->top]; unsigned char colorbv[FZ_MAX_COLORS + 1]; + unsigned char solid = 255; + unsigned char alpha_byte = alpha * 255; fz_text_span *span; int i; fz_colorspace *colorspace = NULL; @@ -996,7 +1045,9 @@ fz_draw_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, const int y = (int)trm.f; draw_glyph(colorbv, state->dest, glyph, x, y, &state->scissor, eop); if (state->shape) - draw_glyph(colorbv, state->shape, glyph, x, y, &state->scissor, 0); + draw_glyph(&solid, state->shape, glyph, x, y, &state->scissor, 0); + if (state->group_alpha) + draw_glyph(&alpha_byte, state->group_alpha, glyph, x, y, &state->scissor, 0); fz_drop_glyph(ctx, glyph); } else @@ -1025,7 +1076,7 @@ fz_draw_clip_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f fz_draw_device *dev = (fz_draw_device*)devp; fz_matrix ctm = concat(in_ctm, &dev->transform); fz_irect bbox; - fz_pixmap *mask, *dest, *shape; + fz_pixmap *mask, *dest, *shape, *group_alpha; fz_matrix tm, trm; fz_glyph *glyph; int i, gid; @@ -1073,12 +1124,20 @@ fz_draw_clip_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f } else shape = NULL; + if (state->group_alpha) + { + group_alpha = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); + fz_clear_pixmap(ctx, group_alpha); + } + else + group_alpha = 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].group_alpha = group_alpha; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top-1, "Clip (text) begin\n"); #endif @@ -1107,6 +1166,8 @@ fz_draw_clip_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f draw_glyph(NULL, mask, glyph, x, y, &bbox, 0); if (state[1].shape) draw_glyph(NULL, state[1].shape, glyph, x, y, &bbox, 0); + if (state[1].group_alpha) + draw_glyph(NULL, state[1].group_alpha, glyph, x, y, &bbox, 0); fz_drop_glyph(ctx, glyph); } else @@ -1157,7 +1218,7 @@ fz_draw_clip_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, fz_draw_device *dev = (fz_draw_device*)devp; fz_matrix ctm = concat(in_ctm, &dev->transform); fz_irect bbox; - fz_pixmap *mask, *dest, *shape; + fz_pixmap *mask, *dest, *shape, *group_alpha; fz_matrix tm, trm; fz_glyph *glyph; int i, gid; @@ -1202,6 +1263,13 @@ fz_draw_clip_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, } else shape = state->shape; + if (state->group_alpha) + { + state[1].group_alpha = group_alpha = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); + fz_clear_pixmap(ctx, group_alpha); + } + else + group_alpha = NULL; state[1].blendmode |= FZ_BLEND_ISOLATED; state[1].scissor = bbox; @@ -1233,6 +1301,8 @@ fz_draw_clip_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, draw_glyph(NULL, mask, glyph, x, y, &bbox, 0); if (shape) draw_glyph(NULL, shape, glyph, x, y, &bbox, 0); + if (group_alpha) + draw_glyph(NULL, group_alpha, glyph, x, y, &bbox, 0); fz_drop_glyph(ctx, glyph); } else @@ -1289,8 +1359,9 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m fz_matrix ctm = concat(in_ctm, &dev->transform); fz_rect bounds; fz_irect bbox, scissor; - fz_pixmap *dest, *shape; + fz_pixmap *dest, *shape, *group_alpha; unsigned char colorbv[FZ_MAX_COLORS + 1]; + unsigned char alpha_byte = 255 * alpha; fz_draw_state *state = &dev->stack[dev->top]; fz_overprint op = { { 0 } }; fz_overprint *eop; @@ -1314,6 +1385,7 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m dest = state->dest; shape = state->shape; + group_alpha = state->group_alpha; if (alpha < 1) { @@ -1327,6 +1399,11 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m shape = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); fz_clear_pixmap(ctx, shape); } + if (group_alpha) + { + group_alpha = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); + fz_clear_pixmap(ctx, group_alpha); + } } if (shade->use_background) @@ -1383,6 +1460,17 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m } } } + if (group_alpha) + { + for (y = scissor.y0; y < scissor.y1; y++) + { + s = group_alpha->samples + (unsigned int)((y - group_alpha->y) * group_alpha->stride + (scissor.x0 - group_alpha->x)); + for (x = scissor.x0; x < scissor.x1; x++) + { + *s++ = alpha_byte; + } + } + } } if (color_params->op) @@ -1395,12 +1483,16 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m fz_paint_shade(ctx, shade, colorspace, &ctm, dest, color_params, &bbox, eop); if (shape) fz_clear_pixmap_rect_with_value(ctx, shape, 255, &bbox); + if (group_alpha) + fz_clear_pixmap_rect_with_value(ctx, group_alpha, 255, &bbox); #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, ""); fz_dump_blend(ctx, "Shade ", dest); if (shape) - fz_dump_blend(ctx, "/", shape); + fz_dump_blend(ctx, "/S=", shape); + if (group_alpha) + fz_dump_blend(ctx, "/GA=", group_alpha); printf("\n"); #endif @@ -1411,9 +1503,14 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m fz_drop_pixmap(ctx, dest); if (shape) { - fz_paint_pixmap(state->shape, shape, alpha * 255); + fz_paint_pixmap(state->shape, shape, 255); fz_drop_pixmap(ctx, shape); } + if (group_alpha) + { + fz_paint_pixmap(state->group_alpha, group_alpha, alpha * 255); + fz_drop_pixmap(ctx, group_alpha); + } } if (state->blendmode & FZ_BLEND_KNOCKOUT) @@ -1650,7 +1747,7 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m pixmap = convert_pixmap_for_painting(ctx, pixmap, model, src_cs, state->dest, color_params, dev, &eop); } - fz_paint_image(state->dest, &state->scissor, state->shape, pixmap, &local_ctm, alpha * 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED, eop); + fz_paint_image(state->dest, &state->scissor, state->shape, state->group_alpha, pixmap, &local_ctm, alpha * 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED, eop); if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); @@ -1759,7 +1856,7 @@ fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const eop = resolve_color(ctx, &op, color, colorspace, alpha, color_params, colorbv, state->dest); - fz_paint_image_with_color(state->dest, &state->scissor, state->shape, pixmap, &local_ctm, colorbv, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED, eop); + fz_paint_image_with_color(state->dest, &state->scissor, state->shape, state->group_alpha, pixmap, &local_ctm, colorbv, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED, eop); if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); @@ -1837,6 +1934,11 @@ fz_draw_clip_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const state[1].shape = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); fz_clear_pixmap(ctx, state[1].shape); } + if (state[0].group_alpha) + { + state[1].group_alpha = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); + fz_clear_pixmap(ctx, state[1].group_alpha); + } state[1].blendmode |= FZ_BLEND_ISOLATED; state[1].scissor = bbox; @@ -1864,13 +1966,17 @@ fz_draw_clip_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const fz_dump_blend(ctx, "Creating imagemask: plotting ", pixmap); fz_dump_blend(ctx, " onto ", state[1].mask); if (state[1].shape) - fz_dump_blend(ctx, "/", state[1].shape); + fz_dump_blend(ctx, "/S=", state[1].shape); + if (state[1].group_alpha) + fz_dump_blend(ctx, "/GA=", state[1].group_alpha); #endif - fz_paint_image(state[1].mask, &bbox, state[1].shape, pixmap, &local_ctm, 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED, 0); + fz_paint_image(state[1].mask, &bbox, state[1].shape, state[1].group_alpha, pixmap, &local_ctm, 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED, 0); #ifdef DUMP_GROUP_BLENDS fz_dump_blend(ctx, " to get ", state[1].mask); if (state[1].shape) - fz_dump_blend(ctx, "/", state[1].shape); + fz_dump_blend(ctx, "/S=", state[1].shape); + if (state[1].group_alpha) + fz_dump_blend(ctx, "/GA=", state[1].group_alpha); printf("\n"); #endif } @@ -1903,10 +2009,14 @@ fz_draw_pop_clip(fz_context *ctx, fz_device *devp) dump_spaces(dev->top, ""); fz_dump_blend(ctx, "Clipping ", state[1].dest); if (state[1].shape) - fz_dump_blend(ctx, "/", state[1].shape); + fz_dump_blend(ctx, "/S=", state[1].shape); + if (state[1].group_alpha) + fz_dump_blend(ctx, "/GA=", state[1].group_alpha); fz_dump_blend(ctx, " onto ", state[0].dest); if (state[0].shape) - fz_dump_blend(ctx, "/", state[0].shape); + fz_dump_blend(ctx, "/S=", state[0].shape); + if (state[0].group_alpha) + fz_dump_blend(ctx, "/GA=", state[0].group_alpha); fz_dump_blend(ctx, " with ", state[1].mask); #endif fz_paint_pixmap_with_mask(state[0].dest, state[1].dest, state[1].mask); @@ -1915,6 +2025,11 @@ fz_draw_pop_clip(fz_context *ctx, fz_device *devp) fz_paint_pixmap_with_mask(state[0].shape, state[1].shape, state[1].mask); fz_drop_pixmap(ctx, state[1].shape); } + if (state[0].group_alpha != state[1].group_alpha) + { + fz_paint_pixmap_with_mask(state[0].group_alpha, state[1].group_alpha, state[1].mask); + fz_drop_pixmap(ctx, state[1].group_alpha); + } /* The following tests should not be required, but just occasionally * errors can cause the stack to get out of sync, and this might save * our bacon. */ @@ -1925,7 +2040,9 @@ fz_draw_pop_clip(fz_context *ctx, fz_device *devp) #ifdef DUMP_GROUP_BLENDS fz_dump_blend(ctx, " to get ", state[0].dest); if (state[0].shape) - fz_dump_blend(ctx, "/", state[0].shape); + fz_dump_blend(ctx, "/S=", state[0].shape); + if (state[0].group_alpha) + fz_dump_blend(ctx, "/GA=", state[0].group_alpha); printf("\n"); #endif } @@ -1945,6 +2062,7 @@ fz_draw_begin_mask(fz_context *ctx, fz_device *devp, const fz_rect *rect, int lu fz_irect bbox; fz_draw_state *state = push_stack(ctx, dev); fz_pixmap *shape = state->shape; + fz_pixmap *group_alpha = state->group_alpha; fz_rect trect = *rect; fz_colorspace *colorspace = NULL; @@ -1984,6 +2102,10 @@ fz_draw_begin_mask(fz_context *ctx, fz_device *devp, const fz_rect *rect, int lu */ state[1].shape = shape = NULL; } + if (state->group_alpha) + { + state[1].group_alpha = group_alpha = NULL; + } if (luminosity) { @@ -1994,12 +2116,16 @@ fz_draw_begin_mask(fz_context *ctx, fz_device *devp, const fz_rect *rect, int lu fz_clear_pixmap_with_value(ctx, dest, bc * 255); if (shape) fz_clear_pixmap_with_value(ctx, shape, 255); + if (group_alpha) + fz_clear_pixmap_with_value(ctx, group_alpha, 255); } else { fz_clear_pixmap(ctx, dest); if (shape) fz_clear_pixmap(ctx, shape); + if (group_alpha) + fz_clear_pixmap(ctx, group_alpha); } #ifdef DUMP_GROUP_BLENDS @@ -2033,7 +2159,9 @@ fz_draw_end_mask(fz_context *ctx, fz_device *devp) dump_spaces(dev->top-1, "Mask -> Clip: "); fz_dump_blend(ctx, "Mask ", state[1].dest); if (state[1].shape) - fz_dump_blend(ctx, "/", state[1].shape); + fz_dump_blend(ctx, "/S=", state[1].shape); + if (state[1].group_alpha) + fz_dump_blend(ctx, "/GA=", state[1].group_alpha); #endif fz_try(ctx) { @@ -2048,6 +2176,9 @@ fz_draw_end_mask(fz_context *ctx, fz_device *devp) if (state[1].shape != state[0].shape) fz_drop_pixmap(ctx, state[1].shape); state[1].shape = NULL; + if (state[1].group_alpha != state[0].group_alpha) + fz_drop_pixmap(ctx, state[1].group_alpha); + state[1].group_alpha = NULL; #ifdef DUMP_GROUP_BLENDS fz_dump_blend(ctx, "-> Clip ", temp); @@ -2069,6 +2200,11 @@ fz_draw_end_mask(fz_context *ctx, fz_device *devp) state[1].shape = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); fz_clear_pixmap(ctx, state[1].shape); } + if (state[0].group_alpha) + { + state[1].group_alpha = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); + fz_clear_pixmap(ctx, state[1].group_alpha); + } state[1].scissor = bbox; } fz_catch(ctx) @@ -2113,18 +2249,13 @@ fz_draw_begin_group(fz_context *ctx, fz_device *devp, const fz_rect *rect, fz_co if (isolated) { fz_clear_pixmap(ctx, dest); + state[1].group_alpha = NULL; } else { fz_copy_pixmap_rect(ctx, dest, state[0].dest, &bbox, dev->default_cs); - } - - if (isolated) - state[1].shape = NULL; - else - { - state[1].shape = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); - fz_clear_pixmap(ctx, state[1].shape); + state[1].group_alpha = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); + fz_clear_pixmap(ctx, state[1].group_alpha); } state[1].alpha = alpha; @@ -2135,18 +2266,20 @@ fz_draw_begin_group(fz_context *ctx, fz_device *devp, const fz_rect *rect, fz_co char atext[80]; char btext[80]; if (alpha != 1) - sprintf(atext, " (alpha=%g)", alpha); + sprintf(atext, " (alpha %g)", alpha); else atext[0] = 0; if (blendmode != 0) - sprintf(btext, " (blendmode=%d)", blendmode); + sprintf(btext, " (blend %d)", blendmode); else btext[0] = 0; sprintf(text, "Group begin%s%s%s%s: background is ", isolated ? " (isolated)" : "", knockout ? " (knockout)" : "", atext, btext); fz_dump_blend(ctx, text, state[1].dest); } if (state[1].shape) - fz_dump_blend(ctx, "/", state[1].shape); + fz_dump_blend(ctx, "/S=", state[1].shape); + if (state[1].group_alpha) + fz_dump_blend(ctx, "/GA=", state[1].group_alpha); printf("\n"); #endif @@ -2183,10 +2316,14 @@ fz_draw_end_group(fz_context *ctx, fz_device *devp) dump_spaces(dev->top, ""); fz_dump_blend(ctx, "Group end: blending ", state[1].dest); if (state[1].shape) - fz_dump_blend(ctx, "/", state[1].shape); + fz_dump_blend(ctx, "/S=", state[1].shape); + if (state[1].group_alpha) + fz_dump_blend(ctx, "/GA=", state[1].group_alpha); fz_dump_blend(ctx, " onto ", state[0].dest); if (state[0].shape) - fz_dump_blend(ctx, "/", state[0].shape); + fz_dump_blend(ctx, "/S=", state[0].shape); + if (state[0].group_alpha) + fz_dump_blend(ctx, "/GA=", state[0].group_alpha); if (alpha != 1.0f) printf(" (alpha %g)", alpha); if (blendmode != 0) @@ -2203,20 +2340,33 @@ fz_draw_end_group(fz_context *ctx, fz_device *devp) state[1].dest = converted; } - if ((blendmode == 0) && (state[0].shape == state[1].shape)) + if ((blendmode == 0) && (state[0].shape == state[1].shape) && (state[0].group_alpha == state[1].group_alpha)) fz_paint_pixmap(state[0].dest, state[1].dest, alpha * 255); else - fz_blend_pixmap(ctx, state[0].dest, state[1].dest, alpha * 255, blendmode, isolated, state[1].shape); + fz_blend_pixmap(ctx, state[0].dest, state[1].dest, alpha * 255, blendmode, isolated, state[1].group_alpha); - assert(state[0].shape == NULL || state[0].shape != state[1].shape); - if (state[0].shape && state[0].shape != state[1].shape) + if (state[0].shape != state[1].shape) { - if (state[1].shape) - fz_paint_pixmap(state[0].shape, state[1].shape, alpha * 255); + if (state[0].shape) + { + if (state[1].shape) + fz_paint_pixmap(state[0].shape, state[1].shape, 255); + else + fz_paint_pixmap_alpha(state[0].shape, state[1].dest, 255); + } + fz_drop_pixmap(ctx, state[1].shape); + } + assert(state[0].group_alpha == NULL || state[0].group_alpha != state[1].group_alpha); + if (state[0].group_alpha && state[0].group_alpha != state[1].group_alpha) + { + /* The 'D' on page 7 of Altona_Technical_v20_x4.pdf goes wrong if this + * is 255 * alpha, as an alpha effectively gets applied twice. */ + if (state[1].group_alpha) + fz_paint_pixmap(state[0].group_alpha, state[1].group_alpha, 255); else - fz_paint_pixmap_alpha(state[0].shape, state[1].dest, alpha * 255); + fz_paint_pixmap_alpha(state[0].group_alpha, state[1].dest, 255); } - fz_drop_pixmap(ctx, state[1].shape); + fz_drop_pixmap(ctx, state[1].group_alpha); /* The following test should not be required, but just occasionally * errors can cause the stack to get out of sync, and this might save * our bacon. */ @@ -2226,7 +2376,9 @@ fz_draw_end_group(fz_context *ctx, fz_device *devp) #ifdef DUMP_GROUP_BLENDS fz_dump_blend(ctx, " to get ", state[0].dest); if (state[0].shape) - fz_dump_blend(ctx, "/", state[0].shape); + fz_dump_blend(ctx, "/S=", state[0].shape); + if (state[0].group_alpha) + fz_dump_blend(ctx, "/GA=", state[0].group_alpha); printf("\n"); #endif @@ -2247,6 +2399,7 @@ typedef struct fz_storable storable; fz_pixmap *dest; fz_pixmap *shape; + fz_pixmap *group_alpha; } tile_record; static int @@ -2318,6 +2471,7 @@ fz_drop_tile_record_imp(fz_context *ctx, fz_storable *storable) tile_record *tr = (tile_record *)storable; fz_drop_pixmap(ctx, tr->dest); fz_drop_pixmap(ctx, tr->shape); + fz_drop_pixmap(ctx, tr->group_alpha); fz_free(ctx, tr); } @@ -2328,12 +2482,13 @@ fz_drop_tile_record(fz_context *ctx, tile_record *tile) } static tile_record * -fz_new_tile_record(fz_context *ctx, fz_pixmap *dest, fz_pixmap *shape) +fz_new_tile_record(fz_context *ctx, fz_pixmap *dest, fz_pixmap *shape, fz_pixmap *group_alpha) { tile_record *tile = fz_malloc_struct(ctx, tile_record); FZ_INIT_STORABLE(tile, 1, fz_drop_tile_record_imp); tile->dest = fz_keep_pixmap(ctx, dest); tile->shape = fz_keep_pixmap(ctx, shape); + tile->group_alpha = fz_keep_pixmap(ctx, group_alpha); return tile; } @@ -2342,7 +2497,7 @@ fz_tile_size(fz_context *ctx, tile_record *tile) { if (!tile) return 0; - return sizeof(*tile) + fz_pixmap_size(ctx, tile->dest) + fz_pixmap_size(ctx, tile->shape); + return sizeof(*tile) + fz_pixmap_size(ctx, tile->dest) + fz_pixmap_size(ctx, tile->shape) + fz_pixmap_size(ctx, tile->group_alpha); } static int @@ -2351,7 +2506,7 @@ fz_draw_begin_tile(fz_context *ctx, fz_device *devp, const fz_rect *area, const fz_draw_device *dev = (fz_draw_device*)devp; fz_matrix ctm = concat(in_ctm, &dev->transform); fz_pixmap *dest = NULL; - fz_pixmap *shape; + fz_pixmap *shape, *group_alpha; fz_irect bbox; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; @@ -2394,6 +2549,7 @@ fz_draw_begin_tile(fz_context *ctx, fz_device *devp, const fz_rect *area, const { state[1].dest = fz_keep_pixmap(ctx, tile->dest); state[1].shape = fz_keep_pixmap(ctx, tile->shape); + state[1].group_alpha = fz_keep_pixmap(ctx, tile->group_alpha); state[1].blendmode |= FZ_BLEND_ISOLATED; state[1].xstep = xstep; state[1].ystep = ystep; @@ -2422,6 +2578,12 @@ fz_draw_begin_tile(fz_context *ctx, fz_device *devp, const fz_rect *area, const state[1].shape = shape = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); fz_clear_pixmap(ctx, shape); } + group_alpha = state[0].group_alpha; + if (group_alpha) + { + state[1].group_alpha = group_alpha = fz_new_pixmap_with_bbox(ctx, NULL, &bbox, NULL, 1); + fz_clear_pixmap(ctx, group_alpha); + } state[1].blendmode |= FZ_BLEND_ISOLATED; state[1].xstep = xstep; state[1].ystep = ystep; @@ -2448,7 +2610,7 @@ fz_draw_end_tile(fz_context *ctx, fz_device *devp) { fz_draw_device *dev = (fz_draw_device*)devp; float xstep, ystep; - fz_matrix ttm, ctm, shapectm; + fz_matrix ttm, ctm, shapectm, gactm; fz_irect area, scissor, tile_bbox; fz_rect scissor_tmp, tile_tmp; int x0, y0, x1, y1, x, y, extra_x, extra_y; @@ -2505,15 +2667,25 @@ fz_draw_end_tile(fz_context *ctx, fz_device *devp) shapectm.e = state[1].shape->x; shapectm.f = state[1].shape->y; } + if (state[1].group_alpha) + { + gactm = ctm; + gactm.e = state[1].group_alpha->x; + gactm.f = state[1].group_alpha->y; + } #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, ""); fz_dump_blend(ctx, "Tiling ", state[1].dest); if (state[1].shape) - fz_dump_blend(ctx, "/", state[1].shape); + fz_dump_blend(ctx, "/S=", state[1].shape); + if (state[1].group_alpha) + fz_dump_blend(ctx, "/GA=", state[1].group_alpha); fz_dump_blend(ctx, " onto ", state[0].dest); if (state[0].shape) - fz_dump_blend(ctx, "/", state[0].shape); + fz_dump_blend(ctx, "/S=", state[0].shape); + if (state[0].group_alpha) + fz_dump_blend(ctx, "/GA=", state[0].group_alpha); #endif for (y = y0; y < y1; y++) @@ -2538,6 +2710,14 @@ fz_draw_end_tile(fz_context *ctx, fz_device *devp) state[1].shape->y = ttm.f; fz_paint_pixmap_with_bbox(state[0].shape, state[1].shape, 255, state[0].scissor); } + if (state[1].group_alpha) + { + ttm = gactm; + fz_pre_translate(&ttm, x * xstep, y * ystep); + state[1].group_alpha->x = ttm.e; + state[1].group_alpha->y = ttm.f; + fz_paint_pixmap_with_bbox(state[0].group_alpha, state[1].group_alpha, 255, state[0].scissor); + } } } @@ -2548,6 +2728,11 @@ fz_draw_end_tile(fz_context *ctx, fz_device *devp) state[1].shape->x = shapectm.e; state[1].shape->y = shapectm.f; } + if (state[1].group_alpha) + { + state[1].group_alpha->x = gactm.e; + state[1].group_alpha->y = gactm.f; + } /* Now we try to cache the tiles. Any failure here will just result in us not caching. */ if (state[1].encache && state[1].id != 0) @@ -2560,7 +2745,7 @@ fz_draw_end_tile(fz_context *ctx, fz_device *devp) { tile_record *existing_tile; - tile = fz_new_tile_record(ctx, state[1].dest, state[1].shape); + tile = fz_new_tile_record(ctx, state[1].dest, state[1].shape, state[1].group_alpha); key = fz_malloc_struct(ctx, tile_key); key->refs = 1; @@ -2598,10 +2783,14 @@ fz_draw_end_tile(fz_context *ctx, fz_device *devp) fz_drop_pixmap(ctx, state[1].dest); if (state[0].shape != state[1].shape) fz_drop_pixmap(ctx, state[1].shape); + if (state[0].group_alpha != state[1].group_alpha) + fz_drop_pixmap(ctx, state[1].group_alpha); #ifdef DUMP_GROUP_BLENDS fz_dump_blend(ctx, " to get ", state[0].dest); if (state[0].shape) - fz_dump_blend(ctx, "/", state[0].shape); + fz_dump_blend(ctx, "/S=", state[0].shape); + if (state[0].group_alpha) + fz_dump_blend(ctx, "/GA=", state[0].group_alpha); printf("\n"); #endif @@ -2643,6 +2832,8 @@ fz_draw_close_device(fz_context *ctx, fz_device *devp) fz_drop_pixmap(ctx, state[1].dest); if (state[1].shape != state[0].shape) fz_drop_pixmap(ctx, state[1].shape); + if (state[1].group_alpha != state[0].group_alpha) + fz_drop_pixmap(ctx, state[1].group_alpha); } if (dev->resolve_spots && dev->top) @@ -2652,6 +2843,7 @@ fz_draw_close_device(fz_context *ctx, fz_device *devp) fz_drop_pixmap(ctx, state[1].dest); assert(state[1].mask == NULL); assert(state[1].shape == NULL); + assert(state[1].group_alpha == NULL); } } @@ -2676,6 +2868,8 @@ fz_draw_drop_device(fz_context *ctx, fz_device *devp) fz_drop_pixmap(ctx, state[1].dest); if (state[1].shape != state[0].shape) fz_drop_pixmap(ctx, state[1].shape); + if (state[1].group_alpha != state[0].group_alpha) + fz_drop_pixmap(ctx, state[1].group_alpha); } /* We never free the dest/mask/shape at level 0, as: @@ -2734,6 +2928,7 @@ new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest, co dev->stack_cap = STACK_SIZE; dev->stack[0].dest = dest; dev->stack[0].shape = NULL; + dev->stack[0].group_alpha = NULL; dev->stack[0].mask = NULL; dev->stack[0].blendmode = 0; dev->stack[0].scissor.x0 = dest->x; |