diff options
author | Robin Watts <Robin.Watts@artifex.com> | 2011-07-13 20:31:56 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2011-07-13 21:03:28 +0100 |
commit | 6913145eefde0e5c4cde9573d8d2cb2a35fd605d (patch) | |
tree | f79dc7269f4f562bdb168b572a37367e806e0190 /draw | |
parent | 2c4bbbfdc7413a68cad395c3c61ff8e62dceb18b (diff) | |
download | mupdf-6913145eefde0e5c4cde9573d8d2cb2a35fd605d.tar.xz |
Non-isolated group support, and fix Bug 692336.
Firstly, this takes on some of Zenikos patch to correct the clip
stack handling that was broken by the fix to bug 692287 (in commit
2c3bbbf). This bug should now be solved.
We add a new 'shape' field to the draw device structure (and clip
stack). When we are inside non-isolated groups, this is set to be
a pixmap where we accumulate the 'shape' of the objects drawn.
When we come to blend back, if we are blending a non-isolated group
back, we have to use a different blending function that takes account
of the shape.
Various internal groups (the page group, and groups used to force
blending) are set to be isolated to avoid carrying shape planes
around when this is not required.
All our rendering code now has to know how to maintain the shape
plane as well as doing the basic rendering.
Diffstat (limited to 'draw')
-rw-r--r-- | draw/draw_affine.c | 223 | ||||
-rw-r--r-- | draw/draw_blend.c | 174 | ||||
-rw-r--r-- | draw/draw_device.c | 201 |
3 files changed, 462 insertions, 136 deletions
diff --git a/draw/draw_affine.c b/draw/draw_affine.c index 68323876..249e6215 100644 --- a/draw/draw_affine.c +++ b/draw/draw_affine.c @@ -29,9 +29,10 @@ static inline byte *sample_nearest(byte *s, int w, int h, int n, int u, int v) /* Blend premultiplied source image in constant alpha over destination */ static inline void -fz_paint_affine_alpha_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) +fz_paint_affine_alpha_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *hp) { int k; + int n1 = n-1; while (w--) { @@ -45,15 +46,22 @@ fz_paint_affine_alpha_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, i byte *b = sample_nearest(sp, sw, sh, n, ui+1, vi); byte *c = sample_nearest(sp, sw, sh, n, ui, vi+1); byte *d = sample_nearest(sp, sw, sh, n, ui+1, vi+1); - int x = bilerp(a[n-1], b[n-1], c[n-1], d[n-1], uf, vf); - int t = 255 - fz_mul255(x, alpha); - for (k = 0; k < n; k++) + int xa = bilerp(a[n1], b[n1], c[n1], d[n1], uf, vf); + int t; + xa = fz_mul255(xa, alpha); + t = 255 - xa; + for (k = 0; k < n1; k++) { - x = bilerp(a[k], b[k], c[k], d[k], uf, vf); + int x = bilerp(a[k], b[k], c[k], d[k], uf, vf); dp[k] = fz_mul255(x, alpha) + fz_mul255(dp[k], t); } + dp[n1] = xa + fz_mul255(dp[n1], t); + if (hp) + hp[0] = xa + fz_mul255(hp[n1], t); } dp += n; + if (hp) + hp++; u += fa; v += fb; } @@ -61,7 +69,7 @@ fz_paint_affine_alpha_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, i /* Special case code for gray -> rgb */ static inline void -fz_paint_affine_alpha_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int alpha) +fz_paint_affine_alpha_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int alpha, byte *hp) { while (w--) { @@ -76,24 +84,31 @@ fz_paint_affine_alpha_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int byte *c = sample_nearest(sp, sw, sh, 2, ui, vi+1); byte *d = sample_nearest(sp, sw, sh, 2, ui+1, vi+1); int y = bilerp(a[1], b[1], c[1], d[1], uf, vf); - int t = 255 - fz_mul255(y, alpha); int x = bilerp(a[0], b[0], c[0], d[0], uf, vf); + int t; x = fz_mul255(x, alpha); + y = fz_mul255(y, alpha); + t = 255 - y; dp[0] = x + fz_mul255(dp[0], t); dp[1] = x + fz_mul255(dp[1], t); dp[2] = x + fz_mul255(dp[2], t); - dp[3] = fz_mul255(y, alpha) + fz_mul255(dp[3], t); + dp[3] = y + fz_mul255(dp[3], t); + if (hp) + hp[0] = y + fz_mul255(hp[0], t); } dp += 4; + if (hp) + hp++; u += fa; v += fb; } } static inline void -fz_paint_affine_alpha_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) +fz_paint_affine_alpha_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *hp) { int k; + int n1 = n-1; while (w--) { @@ -102,18 +117,24 @@ fz_paint_affine_alpha_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, i if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { byte *sample = sp + ((vi * sw + ui) * n); - int t = 255 - fz_mul255(sample[n-1], alpha); - for (k = 0; k < n; k++) + int a = fz_mul255(sample[n-1], alpha); + int t = 255 - a; + for (k = 0; k < n1; k++) dp[k] = fz_mul255(sample[k], alpha) + fz_mul255(dp[k], t); + dp[n1] = a + fz_mul255(dp[n1], t); + if (hp) + hp[0] = a + fz_mul255(hp[n1], t); } dp += n; + if (hp) + hp++; u += fa; v += fb; } } static inline void -fz_paint_affine_alpha_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int alpha) +fz_paint_affine_alpha_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int alpha, byte *hp) { while (w--) { @@ -122,14 +143,19 @@ fz_paint_affine_alpha_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { byte *sample = sp + ((vi * sw + ui) * 2); - int t = 255 - fz_mul255(sample[1], alpha); int x = fz_mul255(sample[0], alpha); + int a = fz_mul255(sample[1], alpha); + int t = 255 - a; dp[0] = x + fz_mul255(dp[0], t); dp[1] = x + fz_mul255(dp[1], t); dp[2] = x + fz_mul255(dp[2], t); - dp[3] = fz_mul255(sample[1], alpha) + fz_mul255(dp[3], t); + dp[3] = a + fz_mul255(dp[3], t); + if (hp) + hp[0] = a + fz_mul255(hp[0], t); } dp += 4; + if (hp) + hp++; u += fa; v += fb; } @@ -138,9 +164,10 @@ fz_paint_affine_alpha_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int /* Blend premultiplied source image over destination */ static inline void -fz_paint_affine_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n) +fz_paint_affine_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *hp) { int k; + int n1 = n-1; while (w--) { @@ -154,21 +181,27 @@ fz_paint_affine_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, byte *b = sample_nearest(sp, sw, sh, n, ui+1, vi); byte *c = sample_nearest(sp, sw, sh, n, ui, vi+1); byte *d = sample_nearest(sp, sw, sh, n, ui+1, vi+1); - int t = 255 - bilerp(a[n-1], b[n-1], c[n-1], d[n-1], uf, vf); - for (k = 0; k < n; k++) + int y = bilerp(a[n1], b[n1], c[n1], d[n1], uf, vf); + int t = 255 - y; + for (k = 0; k < n1; k++) { int x = bilerp(a[k], b[k], c[k], d[k], uf, vf); dp[k] = x + fz_mul255(dp[k], t); } + dp[n1] = y + fz_mul255(dp[n1], t); + if (hp) + hp[0] = y + fz_mul255(hp[0], t); } dp += n; + if (hp) + hp++; u += fa; v += fb; } } static inline void -fz_paint_affine_solid_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w) +fz_paint_affine_solid_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, byte *hp) { while (w--) { @@ -189,17 +222,22 @@ fz_paint_affine_solid_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int dp[1] = x + fz_mul255(dp[1], t); dp[2] = x + fz_mul255(dp[2], t); dp[3] = y + fz_mul255(dp[3], t); + if (hp) + hp[0] = y + fz_mul255(hp[0], t); } dp += 4; + if (hp) + hp++; u += fa; v += fb; } } static inline void -fz_paint_affine_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n) +fz_paint_affine_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *hp) { int k; + int n1 = n-1; while (w--) { @@ -208,18 +246,24 @@ fz_paint_affine_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { byte *sample = sp + ((vi * sw + ui) * n); - int t = 255 - sample[n-1]; - for (k = 0; k < n; k++) + int a = sample[n1]; + int t = 255 - a; + for (k = 0; k < n1; k++) dp[k] = sample[k] + fz_mul255(dp[k], t); + dp[n1] = a + fz_mul255(dp[n1], t); + if (hp) + hp[0] = a + fz_mul255(hp[0], t); } dp += n; + if (hp) + hp++; u += fa; v += fb; } } static inline void -fz_paint_affine_solid_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w) +fz_paint_affine_solid_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, byte *hp) { while (w--) { @@ -228,13 +272,19 @@ fz_paint_affine_solid_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { byte *sample = sp + ((vi * sw + ui) * 2); - int t = 255 - sample[1]; - dp[0] = sample[0] + fz_mul255(dp[0], t); - dp[1] = sample[0] + fz_mul255(dp[1], t); - dp[2] = sample[0] + fz_mul255(dp[2], t); - dp[3] = sample[1] + fz_mul255(dp[3], t); + int x = sample[0]; + int a = sample[1]; + int t = 255 - a; + dp[0] = x + fz_mul255(dp[0], t); + dp[1] = x + fz_mul255(dp[1], t); + dp[2] = x + fz_mul255(dp[2], t); + dp[3] = a + fz_mul255(dp[3], t); + if (hp) + hp[0] = a + fz_mul255(hp[0], t); } dp += 4; + if (hp) + hp++; u += fa; v += fb; } @@ -243,9 +293,10 @@ fz_paint_affine_solid_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int /* Blend non-premultiplied color in source image mask over destination */ static inline void -fz_paint_affine_color_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color) +fz_paint_affine_color_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color, byte *hp) { - int sa = color[n-1]; + int n1 = n - 1; + int sa = color[n1]; int k; while (w--) @@ -262,20 +313,25 @@ fz_paint_affine_color_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, i byte *d = sample_nearest(sp, sw, sh, 1, ui+1, vi+1); int ma = bilerp(a[0], b[0], c[0], d[0], uf, vf); int masa = FZ_COMBINE(FZ_EXPAND(ma), sa); - for (k = 0; k < n - 1; k++) + for (k = 0; k < n1; k++) dp[k] = FZ_BLEND(color[k], dp[k], masa); - dp[k] = FZ_BLEND(255, dp[k], masa); + dp[n1] = FZ_BLEND(255, dp[n1], masa); + if (hp) + hp[0] = FZ_BLEND(255, hp[0], masa); } dp += n; + if (hp) + hp++; u += fa; v += fb; } } static inline void -fz_paint_affine_color_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color) +fz_paint_affine_color_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color, byte *hp) { - int sa = color[n-1]; + int n1 = n-1; + int sa = color[n1]; int k; while (w--) @@ -286,127 +342,131 @@ fz_paint_affine_color_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, i { int ma = sp[vi * sw + ui]; int masa = FZ_COMBINE(FZ_EXPAND(ma), sa); - for (k = 0; k < n - 1; k++) + for (k = 0; k < n1; k++) dp[k] = FZ_BLEND(color[k], dp[k], masa); - dp[k] = FZ_BLEND(255, dp[k], masa); + dp[n1] = FZ_BLEND(255, dp[n1], masa); + if (hp) + hp[n1] = FZ_BLEND(255, hp[n1], masa); } dp += n; + if (hp) + hp++; u += fa; v += fb; } } static void -fz_paint_affine_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused*/) +fz_paint_affine_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused*/, byte *hp) { if (alpha == 255) { switch (n) { - case 1: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 1); break; - case 2: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 2); break; - case 4: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 4); break; - default: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, n); break; + case 1: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 1, hp); break; + case 2: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 2, hp); break; + case 4: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 4, hp); break; + default: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, n, hp); break; } } else if (alpha > 0) { switch (n) { - case 1: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 1, alpha); break; - case 2: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 2, alpha); break; - case 4: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 4, alpha); break; - default: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); break; + case 1: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 1, alpha, hp); break; + case 2: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 2, alpha, hp); break; + case 4: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 4, alpha, hp); break; + default: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha, hp); break; } } } static void -fz_paint_affine_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused*/) +fz_paint_affine_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused*/, byte *hp) { if (alpha == 255) { - fz_paint_affine_solid_g2rgb_lerp(dp, sp, sw, sh, u, v, fa, fb, w); + fz_paint_affine_solid_g2rgb_lerp(dp, sp, sw, sh, u, v, fa, fb, w, hp); } else if (alpha > 0) { - fz_paint_affine_alpha_g2rgb_lerp(dp, sp, sw, sh, u, v, fa, fb, w, alpha); + fz_paint_affine_alpha_g2rgb_lerp(dp, sp, sw, sh, u, v, fa, fb, w, alpha, hp); } } static void -fz_paint_affine_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused */) +fz_paint_affine_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused */, byte *hp) { if (alpha == 255) { switch (n) { - case 1: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 1); break; - case 2: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 2); break; - case 4: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 4); break; - default: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, n); break; + case 1: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 1, hp); break; + case 2: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 2, hp); break; + case 4: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 4, hp); break; + default: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, n, hp); break; } } else if (alpha > 0) { switch (n) { - case 1: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 1, alpha); break; - case 2: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 2, alpha); break; - case 4: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 4, alpha); break; - default: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); break; + case 1: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 1, alpha, hp); break; + case 2: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 2, alpha, hp); break; + case 4: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 4, alpha, hp); break; + default: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha, hp); break; } } } static void -fz_paint_affine_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused*/) +fz_paint_affine_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused*/, byte *hp) { if (alpha == 255) { - fz_paint_affine_solid_g2rgb_near(dp, sp, sw, sh, u, v, fa, fb, w); + fz_paint_affine_solid_g2rgb_near(dp, sp, sw, sh, u, v, fa, fb, w, hp); } else if (alpha > 0) { - fz_paint_affine_alpha_g2rgb_near(dp, sp, sw, sh, u, v, fa, fb, w, alpha); + fz_paint_affine_alpha_g2rgb_near(dp, sp, sw, sh, u, v, fa, fb, w, alpha, hp); } } static void -fz_paint_affine_color_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha/*unused*/, byte *color) +fz_paint_affine_color_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha/*unused*/, byte *color, byte *hp) { switch (n) { - case 2: fz_paint_affine_color_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 2, color); break; - case 4: fz_paint_affine_color_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 4, color); break; - default: fz_paint_affine_color_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, n, color); break; + case 2: fz_paint_affine_color_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 2, color, hp); break; + case 4: fz_paint_affine_color_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 4, color, hp); break; + default: fz_paint_affine_color_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, n, color, hp); break; } } static void -fz_paint_affine_color_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha/*unused*/, byte *color) +fz_paint_affine_color_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha/*unused*/, byte *color, byte *hp) { switch (n) { - case 2: fz_paint_affine_color_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 2, color); break; - case 4: fz_paint_affine_color_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 4, color); break; - default: fz_paint_affine_color_N_near(dp, sp, sw, sh, u, v, fa, fb, w, n, color); break; + case 2: fz_paint_affine_color_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 2, color, hp); break; + case 4: fz_paint_affine_color_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 4, color, hp); break; + default: fz_paint_affine_color_N_near(dp, sp, sw, sh, u, v, fa, fb, w, n, color, hp); break; } } /* Draw an image with an affine transform on destination */ static void -fz_paint_image_imp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, byte *color, int alpha) +fz_paint_image_imp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, byte *color, int alpha) { - byte *dp, *sp; + byte *dp, *sp, *hp; int u, v, fa, fb, fc, fd; int x, y, w, h; - int sw, sh, n; + int sw, sh, n, hw; fz_matrix inv; fz_bbox bbox; int dolerp; - void (*paintfn)(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color); + void (*paintfn)(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color, byte *hp); /* grid fit the image */ if (fz_is_rectilinear(ctm)) @@ -464,6 +524,16 @@ fz_paint_image_imp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ct sp = img->samples; sw = img->w; sh = img->h; + if (shape) + { + hw = shape->w; + hp = shape->samples + ((y - shape->y) * hw) + x - dst->x; + } + else + { + hw = 0; + hp = NULL; + } /* TODO: if (fb == 0 && fa == 1) call fz_paint_span */ @@ -495,23 +565,24 @@ fz_paint_image_imp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ct while (h--) { - paintfn(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha, color); + paintfn(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha, color, hp); dp += dst->w * n; + hp += hw; u += fc; v += fd; } } void -fz_paint_image_with_color(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, byte *color) +fz_paint_image_with_color(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, byte *color) { assert(img->n == 1); - fz_paint_image_imp(dst, scissor, img, ctm, color, 255); + fz_paint_image_imp(dst, scissor, shape, img, ctm, color, 255); } void -fz_paint_image(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, int alpha) +fz_paint_image(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, int alpha) { assert(dst->n == img->n || (dst->n == 4 && img->n == 2)); - fz_paint_image_imp(dst, scissor, img, ctm, NULL, alpha); + fz_paint_image_imp(dst, scissor, shape, img, ctm, NULL, alpha); } diff --git a/draw/draw_blend.c b/draw/draw_blend.c index ef9d8c7c..0634f944 100644 --- a/draw/draw_blend.c +++ b/draw/draw_blend.c @@ -4,29 +4,6 @@ typedef unsigned char byte; -enum -{ - /* PDF 1.4 -- standard separable */ - FZ_BLEND_NORMAL, - FZ_BLEND_MULTIPLY, - FZ_BLEND_SCREEN, - FZ_BLEND_OVERLAY, - FZ_BLEND_DARKEN, - FZ_BLEND_LIGHTEN, - FZ_BLEND_COLOR_DODGE, - FZ_BLEND_COLOR_BURN, - FZ_BLEND_HARD_LIGHT, - FZ_BLEND_SOFT_LIGHT, - FZ_BLEND_DIFFERENCE, - FZ_BLEND_EXCLUSION, - - /* PDF 1.4 -- standard non-separable */ - FZ_BLEND_HUE, - FZ_BLEND_SATURATION, - FZ_BLEND_COLOR, - FZ_BLEND_LUMINOSITY, -}; - static const char *fz_blendmode_names[] = { "Normal", @@ -354,7 +331,124 @@ fz_blend_nonseparable(byte * restrict bp, byte * restrict sp, int w, int blendmo } void -fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode) +fz_blend_separable_isolated(byte * restrict bp, byte * restrict sp, int n, int w, int blendmode, byte * restrict hp) +{ + int k; + int n1 = n - 1; + while (w--) + { + int ha = *hp++; /* ha = shape_alpha */ + /* If ha == 0 then leave everything unchanged */ + if (ha != 0) + { + int sa = sp[n1]; + int ba = bp[n1]; + int baha = fz_mul255(ba, ha); + + /* ugh, division to get non-premul components */ + int invsa = sa ? 255 * 256 / sa : 0; + int invba = ba ? 255 * 256 / ba : 0; + + /* Calculate result_alpha */ + int ra = bp[n1] = ba - baha + ha; + + if (ra != 0) for (k = 0; k < n1; k++) + { + int sc = (sp[k] * invsa) >> 8; + int bc = (bp[k] * invba) >> 8; + int rc; + + switch (blendmode) + { + default: + case FZ_BLEND_NORMAL: rc = sc; break; + case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break; + case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break; + case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break; + case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break; + case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break; + case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break; + case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break; + case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break; + case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break; + 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); + bp[k] = fz_mul255(rc, ra); + } + } + + sp += n; + bp += n; + } +} + +void +fz_blend_nonseparable_isolated(byte * restrict bp, byte * restrict sp, int w, int blendmode, byte * restrict hp) +{ + while (w--) + { + int ha = *hp++; + if (ha != 0) + { + int sa = sp[3]; + int ba = bp[3]; + int baha = fz_mul255(ba, ha); + + /* Calculate result_alpha */ + int ra = bp[3] = ba - baha + ha; + + if (ra != 0) + { + int rr, rg, rb; + + /* ugh, division to get non-premul components */ + int invsa = sa ? 255 * 256 / sa : 0; + int invba = ba ? 255 * 256 / ba : 0; + + int sr = (sp[0] * invsa) >> 8; + int sg = (sp[1] * invsa) >> 8; + int sb = (sp[2] * invsa) >> 8; + + int br = (bp[0] * invba) >> 8; + int bg = (bp[1] * invba) >> 8; + int bb = (bp[2] * invba) >> 8; + + switch (blendmode) + { + default: + case FZ_BLEND_HUE: + fz_hue_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); + break; + case FZ_BLEND_SATURATION: + fz_saturation_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); + break; + case FZ_BLEND_COLOR: + fz_color_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); + break; + case FZ_BLEND_LUMINOSITY: + fz_luminosity_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); + break; + } + + rr = fz_mul255(255 - ha, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(baha, rr); + rg = fz_mul255(255 - ha, bp[1]) + fz_mul255(255 - ba, sp[1]) + fz_mul255(baha, rg); + rb = fz_mul255(255 - ha, bp[2]) + fz_mul255(255 - ba, sp[2]) + fz_mul255(baha, rb); + bp[0] = fz_mul255(ra, rr); + bp[1] = fz_mul255(ra, rg); + bp[2] = fz_mul255(ra, rb); + } + } + + sp += 4; + bp += 4; + } +} + +void +fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int isolated, fz_pixmap *shape) { unsigned char *sp, *dp; fz_bbox bbox; @@ -386,13 +480,31 @@ fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode) assert(src->n == dst->n); - while (h--) + if (!isolated) { - if (n == 4 && blendmode >= FZ_BLEND_HUE) - fz_blend_nonseparable(dp, sp, w, blendmode); - else - fz_blend_separable(dp, sp, n, w, blendmode); - sp += src->w * n; - dp += dst->w * n; + unsigned char *hp = shape->samples + (y - shape->y) * shape->w + (x - shape->x); + + while (h--) + { + if (n == 4 && blendmode >= FZ_BLEND_HUE) + fz_blend_nonseparable_isolated(dp, sp, w, blendmode, hp); + else + fz_blend_separable_isolated(dp, sp, n, w, blendmode, hp); + sp += src->w * n; + dp += dst->w * n; + hp += shape->w; + } + } + else + { + while (h--) + { + if (n == 4 && blendmode >= FZ_BLEND_HUE) + fz_blend_nonseparable(dp, sp, w, blendmode); + else + fz_blend_separable(dp, sp, n, w, blendmode); + sp += src->w * n; + dp += dst->w * n; + } } } diff --git a/draw/draw_device.c b/draw/draw_device.c index 2a38c099..67b766ca 100644 --- a/draw/draw_device.c +++ b/draw/draw_device.c @@ -14,6 +14,7 @@ struct fz_draw_device_s fz_gel *gel; fz_pixmap *dest; + fz_pixmap *shape; fz_bbox scissor; int top; @@ -21,6 +22,7 @@ struct fz_draw_device_s fz_bbox scissor; fz_pixmap *dest; fz_pixmap *mask; + fz_pixmap *shape; int blendmode; int luminosity; float alpha; @@ -59,6 +61,15 @@ fz_draw_fill_path(void *user, fz_path *path, int even_odd, fz_matrix ctm, colorbv[i] = alpha * 255; fz_scan_convert(dev->gel, even_odd, bbox, dev->dest, colorbv); + if (dev->shape) + { + fz_reset_gel(dev->gel, dev->scissor); + fz_flatten_fill_path(dev->gel, path, ctm, flatness); + fz_sort_gel(dev->gel); + + colorbv[0] = 255; + fz_scan_convert(dev->gel, even_odd, bbox, dev->shape, colorbv); + } } static void @@ -97,6 +108,18 @@ fz_draw_stroke_path(void *user, fz_path *path, fz_stroke_state *stroke, fz_matri colorbv[i] = alpha * 255; fz_scan_convert(dev->gel, 0, bbox, dev->dest, colorbv); + if (dev->shape) + { + fz_reset_gel(dev->gel, dev->scissor); + if (stroke->dash_len > 0) + fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth); + else + fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth); + fz_sort_gel(dev->gel); + + colorbv[0] = 255; + fz_scan_convert(dev->gel, 0, bbox, dev->shape, colorbv); + } } static void @@ -106,7 +129,7 @@ fz_draw_clip_path(void *user, fz_path *path, fz_rect *rect, int even_odd, fz_mat fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; - fz_pixmap *mask, *dest; + fz_pixmap *mask, *dest, *shape; fz_bbox bbox; if (dev->top == STACK_SIZE) @@ -130,24 +153,33 @@ fz_draw_clip_path(void *user, fz_path *path, fz_rect *rect, int even_odd, fz_mat dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = NULL; dev->stack[dev->top].dest = NULL; + dev->stack[dev->top].shape = dev->shape; dev->scissor = bbox; dev->top++; return; } mask = fz_new_pixmap_with_rect(NULL, bbox); - dest = fz_new_pixmap_with_rect(model, bbox); - fz_clear_pixmap(mask); + dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(dest); + if (dev->shape) + { + shape = fz_new_pixmap_with_rect(NULL, bbox); + fz_clear_pixmap(shape); + } + else + shape = NULL; fz_scan_convert(dev->gel, even_odd, bbox, mask, NULL); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; + dev->stack[dev->top].shape = dev->shape; dev->scissor = bbox; dev->dest = dest; + dev->shape = shape; dev->top++; } @@ -159,7 +191,7 @@ fz_draw_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_sta float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; - fz_pixmap *mask, *dest; + fz_pixmap *mask, *dest, *shape; fz_bbox bbox; if (dev->top == STACK_SIZE) @@ -184,10 +216,16 @@ fz_draw_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_sta bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); mask = fz_new_pixmap_with_rect(NULL, bbox); - dest = fz_new_pixmap_with_rect(model, bbox); - fz_clear_pixmap(mask); + dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(dest); + if (dev->shape) + { + shape = fz_new_pixmap_with_rect(NULL, bbox); + fz_clear_pixmap(shape); + } + else + shape = NULL; if (!fz_is_empty_rect(bbox)) fz_scan_convert(dev->gel, 0, bbox, mask, NULL); @@ -195,8 +233,10 @@ fz_draw_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_sta dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; + dev->stack[dev->top].shape = dev->shape; dev->scissor = bbox; dev->dest = dest; + dev->shape = shape; dev->top++; } @@ -243,6 +283,7 @@ fz_draw_fill_text(void *user, fz_text *text, fz_matrix ctm, fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; + unsigned char shapebv; float colorfv[FZ_MAX_COLORS]; fz_matrix tm, trm; fz_pixmap *glyph; @@ -252,6 +293,7 @@ fz_draw_fill_text(void *user, fz_text *text, fz_matrix ctm, for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; + shapebv = 255; tm = text->trm; @@ -273,6 +315,8 @@ fz_draw_fill_text(void *user, fz_text *text, fz_matrix ctm, if (glyph) { draw_glyph(colorbv, dev->dest, glyph, x, y, dev->scissor); + if (dev->shape) + draw_glyph(&shapebv, dev->shape, glyph, x, y, dev->scissor); fz_drop_pixmap(glyph); } } @@ -315,6 +359,8 @@ fz_draw_stroke_text(void *user, fz_text *text, fz_stroke_state *stroke, fz_matri if (glyph) { draw_glyph(colorbv, dev->dest, glyph, x, y, dev->scissor); + if (dev->shape) + draw_glyph(colorbv, dev->shape, glyph, x, y, dev->scissor); fz_drop_pixmap(glyph); } } @@ -326,7 +372,7 @@ fz_draw_clip_text(void *user, fz_text *text, fz_matrix ctm, int accumulate) fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; - fz_pixmap *mask, *dest; + fz_pixmap *mask, *dest, *shape; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; @@ -356,16 +402,24 @@ fz_draw_clip_text(void *user, fz_text *text, fz_matrix ctm, int accumulate) if (accumulate == 0 || accumulate == 1) { mask = fz_new_pixmap_with_rect(NULL, bbox); - dest = fz_new_pixmap_with_rect(model, bbox); - fz_clear_pixmap(mask); + dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(dest); + if (dev->shape) + { + shape = fz_new_pixmap_with_rect(NULL, bbox); + fz_clear_pixmap(shape); + } + else + shape = NULL; dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; + dev->stack[dev->top].shape = dev->shape; dev->scissor = bbox; dev->dest = dest; + dev->shape = shape; dev->top++; } else @@ -395,6 +449,8 @@ fz_draw_clip_text(void *user, fz_text *text, fz_matrix ctm, int accumulate) if (glyph) { draw_glyph(NULL, mask, glyph, x, y, bbox); + if (dev->shape) + draw_glyph(NULL, dev->shape, glyph, x, y, bbox); fz_drop_pixmap(glyph); } } @@ -407,7 +463,7 @@ fz_draw_clip_stroke_text(void *user, fz_text *text, fz_stroke_state *stroke, fz_ fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; - fz_pixmap *mask, *dest; + fz_pixmap *mask, *dest, *shape; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; @@ -423,16 +479,24 @@ fz_draw_clip_stroke_text(void *user, fz_text *text, fz_stroke_state *stroke, fz_ bbox = fz_intersect_bbox(bbox, dev->scissor); mask = fz_new_pixmap_with_rect(NULL, bbox); - dest = fz_new_pixmap_with_rect(model, bbox); - fz_clear_pixmap(mask); + dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(dest); + if (dev->shape) + { + shape = fz_new_pixmap_with_rect(NULL, bbox); + fz_clear_pixmap(shape); + } + else + shape = dev->shape; dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; + dev->stack[dev->top].shape = dev->shape; dev->scissor = bbox; dev->dest = dest; + dev->shape = shape; dev->top++; if (!fz_is_empty_rect(bbox)) @@ -457,6 +521,8 @@ fz_draw_clip_stroke_text(void *user, fz_text *text, fz_stroke_state *stroke, fz_ if (glyph) { draw_glyph(NULL, mask, glyph, x, y, bbox); + if (dev->shape) + draw_glyph(NULL, dev->shape, glyph, x, y, bbox); fz_drop_pixmap(glyph); } } @@ -519,9 +585,22 @@ fz_draw_fill_shade(void *user, fz_shade *shade, fz_matrix ctm, float alpha) *s++ = colorbv[i]; } } + if (dev->shape) + { + for (y = scissor.y0; y < scissor.y1; y++) + { + s = dev->shape->samples + (scissor.x0 - dev->shape->x) + (y - dev->shape->y) * dev->shape->w; + for (x = scissor.x0; x < scissor.x1; x++) + { + *s++ = 255; + } + } + } } fz_paint_shade(shade, ctm, dest, bbox); + if (dev->shape) + fz_clear_pixmap_rect_with_color(dev->shape, 255, bbox); if (alpha < 1) { @@ -634,7 +713,7 @@ fz_draw_fill_image(void *user, fz_pixmap *image, fz_matrix ctm, float alpha) } } - fz_paint_image(dev->dest, dev->scissor, image, ctm, alpha * 255); + fz_paint_image(dev->dest, dev->scissor, dev->shape, image, ctm, alpha * 255); if (scaled) fz_drop_pixmap(scaled); @@ -679,7 +758,7 @@ fz_draw_fill_image_mask(void *user, fz_pixmap *image, fz_matrix ctm, colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; - fz_paint_image_with_color(dev->dest, dev->scissor, image, ctm, colorbv); + fz_paint_image_with_color(dev->dest, dev->scissor, dev->shape, image, ctm, colorbv); if (scaled) fz_drop_pixmap(scaled); @@ -691,7 +770,7 @@ fz_draw_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix c fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; - fz_pixmap *mask, *dest; + fz_pixmap *mask, *dest, *shape; fz_pixmap *scaled = NULL; int dx, dy; @@ -717,10 +796,16 @@ fz_draw_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix c bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); mask = fz_new_pixmap_with_rect(NULL, bbox); - dest = fz_new_pixmap_with_rect(model, bbox); - fz_clear_pixmap(mask); + dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(dest); + if (dev->shape) + { + shape = fz_new_pixmap_with_rect(NULL, bbox); + fz_clear_pixmap(shape); + } + else + shape = NULL; dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); @@ -739,7 +824,7 @@ fz_draw_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix c image = scaled; } - fz_paint_image(mask, bbox, image, ctm, 255); + fz_paint_image(mask, bbox, dev->shape, image, ctm, 255); if (scaled) fz_drop_pixmap(scaled); @@ -747,8 +832,10 @@ fz_draw_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix c dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; + dev->stack[dev->top].shape = dev->shape; dev->scissor = bbox; dev->dest = dest; + dev->shape = shape; dev->top++; } @@ -756,21 +843,40 @@ static void fz_draw_pop_clip(void *user) { fz_draw_device *dev = user; - fz_pixmap *mask, *dest; + fz_pixmap *mask, *dest, *shape; if (dev->top > 0) { dev->top--; dev->scissor = dev->stack[dev->top].scissor; mask = dev->stack[dev->top].mask; dest = dev->stack[dev->top].dest; - if (mask && dest) + shape = dev->stack[dev->top].shape; + + /* We can get here with mask == NULL if the clipping actually + * resolved to a rectangle earlier. In this case, we will + * have a dest, and the shape will be unchanged. + */ + if (mask) { - fz_pixmap *scratch = dev->dest; - fz_paint_pixmap_with_mask(dest, scratch, mask); + assert(dest); + + fz_paint_pixmap_with_mask(dest, dev->dest, mask); + if (shape != NULL) + { + assert(shape != dev->shape); + fz_paint_pixmap_with_mask(shape, dev->shape, mask); + fz_drop_pixmap(dev->shape); + dev->shape = shape; + } fz_drop_pixmap(mask); - fz_drop_pixmap(scratch); + fz_drop_pixmap(dev->dest); dev->dest = dest; } + else + { + assert(dest == NULL); + assert(shape == dev->shape); + } } } @@ -805,6 +911,8 @@ fz_draw_begin_mask(void *user, fz_rect rect, int luminosity, fz_colorspace *colo dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].luminosity = luminosity; + dev->stack[dev->top].shape = dev->shape; + /* FIXME: More shape stuff? */ dev->top++; dev->scissor = bbox; @@ -847,6 +955,14 @@ fz_draw_end_mask(void *user) dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = temp; dev->stack[dev->top].dest = dev->dest; + /* If we have a shape, then it'll need to be masked with the + * clip mask when we pop. So create a new shape now. */ + if (dev->shape) + { + dev->stack[dev->top].shape = dev->shape; + dev->shape = fz_new_pixmap_with_rect(NULL, bbox); + fz_clear_pixmap(dev->shape); + } dev->scissor = bbox; dev->dest = dest; dev->top++; @@ -859,7 +975,7 @@ fz_draw_begin_group(void *user, fz_rect rect, int isolated, int knockout, int bl fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; - fz_pixmap *dest; + fz_pixmap *dest, *shape; if (dev->top == STACK_SIZE) { @@ -871,16 +987,28 @@ fz_draw_begin_group(void *user, fz_rect rect, int isolated, int knockout, int bl bbox = fz_intersect_bbox(bbox, dev->scissor); dest = fz_new_pixmap_with_rect(model, bbox); - fz_clear_pixmap(dest); + if (isolated) + { + fz_clear_pixmap(dest); + 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; - dev->stack[dev->top].blendmode = blendmode; + dev->stack[dev->top].blendmode = blendmode | (isolated ? FZ_BLEND_ISOLATED : 0) | (knockout ? FZ_BLEND_KNOCKOUT : 0); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; + dev->stack[dev->top].shape = dev->shape; dev->top++; dev->scissor = bbox; dev->dest = dest; + dev->shape = shape; } static void @@ -888,23 +1016,36 @@ fz_draw_end_group(void *user) { fz_draw_device *dev = user; fz_pixmap *group = dev->dest; + fz_pixmap *shape = dev->shape; int blendmode; + int isolated, knockout; float alpha; if (dev->top > 0) { dev->top--; alpha = dev->stack[dev->top].alpha; - blendmode = dev->stack[dev->top].blendmode; + blendmode = dev->stack[dev->top].blendmode & FZ_BLEND_MODEMASK; + isolated = dev->stack[dev->top].blendmode & FZ_BLEND_ISOLATED; + knockout = dev->stack[dev->top].blendmode & FZ_BLEND_KNOCKOUT; + dev->shape = dev->stack[dev->top].shape; dev->dest = dev->stack[dev->top].dest; dev->scissor = dev->stack[dev->top].scissor; - if (blendmode == 0) + if ((blendmode == 0) && (shape == NULL)) fz_paint_pixmap(dev->dest, group, alpha * 255); else - fz_blend_pixmap(dev->dest, group, alpha * 255, blendmode); + fz_blend_pixmap(dev->dest, group, alpha * 255, blendmode, isolated, shape); fz_drop_pixmap(group); + if (shape != dev->shape) + { + if (dev->shape) + { + fz_paint_pixmap(dev->shape, shape, 255); + } + fz_drop_pixmap(shape); + } } } @@ -931,6 +1072,7 @@ fz_draw_begin_tile(void *user, fz_rect area, fz_rect view, float xstep, float ys dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; + dev->stack[dev->top].shape = dev->shape; dev->stack[dev->top].xstep = xstep; dev->stack[dev->top].ystep = ystep; dev->stack[dev->top].area = area; @@ -1003,6 +1145,7 @@ fz_new_draw_device(fz_glyph_cache *cache, fz_pixmap *dest) ddev->cache = cache; ddev->gel = fz_new_gel(); ddev->dest = dest; + ddev->shape = NULL; ddev->top = 0; ddev->scissor.x0 = dest->x; |