summaryrefslogtreecommitdiff
path: root/draw
diff options
context:
space:
mode:
authorRobin Watts <Robin.Watts@artifex.com>2011-07-13 20:31:56 +0100
committerRobin Watts <robin.watts@artifex.com>2011-07-13 21:03:28 +0100
commit6913145eefde0e5c4cde9573d8d2cb2a35fd605d (patch)
treef79dc7269f4f562bdb168b572a37367e806e0190 /draw
parent2c4bbbfdc7413a68cad395c3c61ff8e62dceb18b (diff)
downloadmupdf-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.c223
-rw-r--r--draw/draw_blend.c174
-rw-r--r--draw/draw_device.c201
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;