summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <Robin.Watts@artifex.com>2011-08-01 22:01:46 +0100
committerRobin Watts <Robin.Watts@artifex.com>2011-08-01 22:27:34 +0100
commit332b2aed1f1f17bdcafdffe2b9f773e00d7e6a0d (patch)
tree9e62ea9b93625e3a9af3997b29a12ea2df553741
parentd451b09f75625a1b902c14afdede5242ad66713a (diff)
downloadmupdf-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.c21
-rw-r--r--draw/draw_device.c29
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);
}