diff options
author | Robin Watts <Robin.Watts@artifex.com> | 2011-08-01 22:01:46 +0100 |
---|---|---|
committer | Robin Watts <Robin.Watts@artifex.com> | 2011-08-01 22:27:34 +0100 |
commit | 332b2aed1f1f17bdcafdffe2b9f773e00d7e6a0d (patch) | |
tree | 9e62ea9b93625e3a9af3997b29a12ea2df553741 | |
parent | d451b09f75625a1b902c14afdede5242ad66713a (diff) | |
download | mupdf-332b2aed1f1f17bdcafdffe2b9f773e00d7e6a0d.tar.xz |
Fix bug 692377: Incorrect rendering of blending groups.
A combination of constant alpha and non-zero blending modes resulted
in incorrect rendering.
Various fixes seem to have made it work:
* Allow for non-full alpha when blending non-isolated groups back.
* Clamp blended pixels to allow for overflow.
* Allow for alpha in the shape blending.
-rw-r--r-- | draw/draw_blend.c | 21 | ||||
-rw-r--r-- | draw/draw_device.c | 29 |
2 files changed, 35 insertions, 15 deletions
diff --git a/draw/draw_blend.c b/draw/draw_blend.c index 0634f944..20ad8a28 100644 --- a/draw/draw_blend.c +++ b/draw/draw_blend.c @@ -330,14 +330,14 @@ fz_blend_nonseparable(byte * restrict bp, byte * restrict sp, int w, int blendmo } } -void -fz_blend_separable_isolated(byte * restrict bp, byte * restrict sp, int n, int w, int blendmode, byte * restrict hp) +static void +fz_blend_separable_nonisolated(byte * restrict bp, byte * restrict sp, int n, int w, int blendmode, byte * restrict hp, int alpha) { int k; int n1 = n - 1; while (w--) { - int ha = *hp++; /* ha = shape_alpha */ + int ha = fz_mul255(*hp++, alpha); /* ha = shape_alpha */ /* If ha == 0 then leave everything unchanged */ if (ha != 0) { @@ -374,8 +374,9 @@ fz_blend_separable_isolated(byte * restrict bp, byte * restrict sp, int n, int w case FZ_BLEND_DIFFERENCE: rc = fz_difference_byte(bc, sc); break; case FZ_BLEND_EXCLUSION: rc = fz_exclusion_byte(bc, sc); break; } - rc = fz_mul255(255 - ha, bc) + fz_mul255(255 - ba, sc) + fz_mul255(baha, rc); + if (rc < 0) rc = 0; + if (rc > 255) rc = 255; bp[k] = fz_mul255(rc, ra); } } @@ -385,12 +386,12 @@ fz_blend_separable_isolated(byte * restrict bp, byte * restrict sp, int n, int w } } -void -fz_blend_nonseparable_isolated(byte * restrict bp, byte * restrict sp, int w, int blendmode, byte * restrict hp) +static void +fz_blend_nonseparable_nonisolated(byte * restrict bp, byte * restrict sp, int w, int blendmode, byte * restrict hp, int alpha) { while (w--) { - int ha = *hp++; + int ha = fz_mul255(*hp++, alpha); if (ha != 0) { int sa = sp[3]; @@ -455,7 +456,7 @@ fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int is int x, y, w, h, n; /* TODO: fix this hack! */ - if (alpha < 255) + if (isolated && alpha < 255) { sp = src->samples; n = src->w * src->h * src->n; @@ -487,9 +488,9 @@ fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int is while (h--) { if (n == 4 && blendmode >= FZ_BLEND_HUE) - fz_blend_nonseparable_isolated(dp, sp, w, blendmode, hp); + fz_blend_nonseparable_nonisolated(dp, sp, w, blendmode, hp, alpha); else - fz_blend_separable_isolated(dp, sp, n, w, blendmode, hp); + fz_blend_separable_nonisolated(dp, sp, n, w, blendmode, hp, alpha); sp += src->w * n; dp += dst->w * n; hp += shape->w; diff --git a/draw/draw_device.c b/draw/draw_device.c index 22cdc720..8042ce84 100644 --- a/draw/draw_device.c +++ b/draw/draw_device.c @@ -43,6 +43,7 @@ static void fz_knockout_begin(void *user) fz_draw_device *dev = user; fz_bbox bbox; fz_pixmap *dest, *shape; + int isolated = dev->blendmode & FZ_BLEND_ISOLATED; if ((dev->blendmode & FZ_BLEND_KNOCKOUT) == 0) return; @@ -57,10 +58,9 @@ static void fz_knockout_begin(void *user) bbox = fz_intersect_bbox(bbox, dev->scissor); dest = fz_new_pixmap_with_rect(dev->dest->colorspace, bbox); - if (dev->blendmode & FZ_BLEND_ISOLATED) + if (isolated) { fz_clear_pixmap(dest); - shape = dev->shape; } else { @@ -69,9 +69,19 @@ static void fz_knockout_begin(void *user) do { prev = dev->stack[--i].dest; } while (prev == NULL); + fz_copy_pixmap_rect(dest, prev, bbox); + } + + if (dev->blendmode == 0 && isolated) + { + /* We can render direct to any existing shape plane. If there + * isn't one, we don't need to make one. */ + shape = dev->shape; + } + else + { shape = fz_new_pixmap_with_rect(NULL, bbox); fz_clear_pixmap(shape); - fz_copy_pixmap_rect(dest, prev, bbox); } dev->stack[dev->top].blendmode = dev->blendmode; dev->stack[dev->top].scissor = dev->scissor; @@ -1149,13 +1159,22 @@ fz_draw_begin_group(void *user, fz_rect rect, int isolated, int knockout, int bl if (isolated) { fz_clear_pixmap(dest); + } + else + { + fz_copy_pixmap_rect(dest, dev->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 = dev->shape; } else { shape = fz_new_pixmap_with_rect(NULL, bbox); fz_clear_pixmap(shape); - fz_copy_pixmap_rect(dest, dev->dest, bbox); } dev->stack[dev->top].alpha = alpha; @@ -1202,7 +1221,7 @@ fz_draw_end_group(void *user) { if (dev->shape) { - fz_paint_pixmap(dev->shape, shape, 255); + fz_paint_pixmap(dev->shape, shape, alpha * 255); } fz_drop_pixmap(shape); } |