diff options
-rw-r--r-- | draw/blendmodes.c | 14 | ||||
-rw-r--r-- | draw/imagedraw.c | 364 | ||||
-rw-r--r-- | draw/meshdraw.c | 2 | ||||
-rw-r--r-- | draw/pathscan.c | 4 | ||||
-rw-r--r-- | draw/porterduff.c | 328 | ||||
-rw-r--r-- | fitz/dev_draw.c | 138 | ||||
-rw-r--r-- | fitz/fitz.h | 66 | ||||
-rw-r--r-- | fitz/res_font.c | 8 |
8 files changed, 451 insertions, 473 deletions
diff --git a/draw/blendmodes.c b/draw/blendmodes.c index 0c8c7eec..184e1a28 100644 --- a/draw/blendmodes.c +++ b/draw/blendmodes.c @@ -326,12 +326,24 @@ fz_blendnonseparable(byte * restrict bp, byte * restrict sp, int w, fz_blendmode } void -fz_blendpixmapswithmode(fz_pixmap *dst, fz_pixmap *src, fz_blendmode blendmode) +fz_blendpixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_blendmode blendmode) { unsigned char *sp, *dp; fz_bbox bbox; int x, y, w, h, n; + /* TODO: fix this hack! */ + if (alpha < 255) + { + sp = src->samples; + n = src->w * src->h * src->n; + while (n--) + { + *sp = fz_mul255(*sp, alpha); + sp++; + } + } + bbox = fz_boundpixmap(dst); bbox = fz_intersectbbox(bbox, fz_boundpixmap(src)); diff --git a/draw/imagedraw.c b/draw/imagedraw.c index a626deb7..b9bb2702 100644 --- a/draw/imagedraw.c +++ b/draw/imagedraw.c @@ -1,301 +1,194 @@ #include "fitz.h" -#define noNEAREST +#define LINEAR typedef unsigned char byte; -/* Sample image and clamp to edge */ - -static inline byte -getmask(byte *s, int w, int h, int u, int v) +static inline float roundup(float x) { - if (u < 0) u = 0; - if (v < 0) v = 0; - if (u >= w) u = w - 1; - if (v >= h) v = h - 1; - return s[w * v + u]; + return (x < 0) ? floorf(x) : ceilf(x); } -static inline byte * -getga(byte *s, int w, int h, int u, int v) +#ifdef LINEAR + +static inline int lerp(int a, int b, int t) { - if (u < 0) u = 0; - if (v < 0) v = 0; - if (u >= w) u = w - 1; - if (v >= h) v = h - 1; - return s + ((w * v + u) << 1); + return a + (((b - a) * t) >> 16); } -static inline byte * -getrgba(byte *s, int w, int h, int u, int v) +static inline int bilerp(int a, int b, int c, int d, int u, int v) { - if (u < 0) u = 0; - if (v < 0) v = 0; - if (u >= w) u = w - 1; - if (v >= h) v = h - 1; - return s + ((w * v + u) << 2); + return lerp(lerp(a, b, u), lerp(c, d, u), v); } -static inline int -getcolor(byte *s, int w, int h, int n, int u, int v, int k) +static inline byte *samplenearest(byte *s, int w, int h, int n, int u, int v) { if (u < 0) u = 0; if (v < 0) v = 0; if (u >= w) u = w - 1; if (v >= h) v = h - 1; - return s[w * v * n + u + k]; -} - -/* Bi-linear interpolation of sample */ - -static inline int -lerp(int a, int b, int t) -{ - return a + (((b - a) * t) >> 16); -} - -static inline void -lerpga(byte *dst, byte *a, byte *b, int t) -{ - dst[0] = lerp(a[0], b[0], t); - dst[1] = lerp(a[1], b[1], t); -} - -static inline void -lerprgba(byte *dst, byte *a, byte *b, int t) -{ - dst[0] = lerp(a[0], b[0], t); - dst[1] = lerp(a[1], b[1], t); - dst[2] = lerp(a[2], b[2], t); - dst[3] = lerp(a[3], b[3], t); -} - -static inline int -samplemask(byte *s, int w, int h, int u, int v) -{ -#ifdef NEAREST - return getmask(s, w, h, u >> 16, v >> 16); -#else - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; - int a = getmask(s, w, h, ui, vi); - int b = getmask(s, w, h, ui+1, vi); - int c = getmask(s, w, h, ui, vi+1); - int d = getmask(s, w, h, ui+1, vi+1); - int ab = lerp(a, b, ud); - int cd = lerp(c, d, ud); - return lerp(ab, cd, vd); -#endif + return s + (v * w + u) * n; } -static inline void -samplega(byte *s, int w, int h, int u, int v, int *gout, int *aout) -{ -#ifdef NEAREST - byte *ga = getga(s, w, h, u >> 16, v >> 16); - *gout = ga[0]; - *aout = ga[1]; -#else - byte ab[2]; - byte cd[2]; - byte abcd[2]; - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; - byte *a = getga(s, w, h, ui, vi); - byte *b = getga(s, w, h, ui+1, vi); - byte *c = getga(s, w, h, ui, vi+1); - byte *d = getga(s, w, h, ui+1, vi+1); - lerpga(ab, a, b, ud); - lerpga(cd, c, d, ud); - lerpga(abcd, ab, cd, vd); - *gout = abcd[0]; - *aout = abcd[1]; #endif -} -static inline void -samplergba(byte *s, int w, int h, int u, int v, int *rout, int *gout, int *bout, int *aout) -{ -#ifdef NEAREST - byte *rgba = getrgba(s, w, h, u >> 16, v >> 16); - *rout = rgba[0]; - *gout = rgba[1]; - *bout = rgba[2]; - *aout = rgba[3]; -#else - byte ab[4]; - byte cd[4]; - byte abcd[4]; - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; - byte *a = getrgba(s, w, h, ui, vi); - byte *b = getrgba(s, w, h, ui+1, vi); - byte *c = getrgba(s, w, h, ui, vi+1); - byte *d = getrgba(s, w, h, ui+1, vi+1); - lerprgba(ab, a, b, ud); - lerprgba(cd, c, d, ud); - lerprgba(abcd, ab, cd, vd); - *rout = abcd[0]; - *gout = abcd[1]; - *bout = abcd[2]; - *aout = abcd[3]; -#endif -} +/* Blend premultiplied source image in constant alpha over destination */ static inline void -samplecolor(byte *s, int w, int h, int n, int u, int v, byte *out) +fz_paintaffinealphaN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) { -#ifdef NEAREST - int k; - for (k = 0; k < n; k++) - out[k] = getcolor(s, w, h, n, u >> 16, v >> 16, k); -#else - int ui = u >> 16; - int vi = v >> 16; - int ud = u & 0xFFFF; - int vd = v & 0xFFFF; int k; - for (k = 0; k < n; k++) - { - int a = getcolor(s, w, h, n, ui, vi, k); - int b = getcolor(s, w, h, n, ui+1, vi, k); - int c = getcolor(s, w, h, n, ui, vi+1, k); - int d = getcolor(s, w, h, n, ui+1, vi+1, k); - int ab = lerp(a, b, ud); - int cd = lerp(c, d, ud); - out[k] = lerp(ab, cd, vd); - } -#endif -} - -/* Blend source image scanline over destination */ -#define INSIDEU u >= 0 && u <= (sw << 16) -#define INSIDEV v >= 0 && v <= (sh << 16) -#define INSIDE INSIDEU && INSIDEV - -static inline void -fz_blendscan1(unsigned char *dp, unsigned char *sp, int sw, int sh, - int u, int v, int fa, int fb, int w) -{ while (w--) { - if (INSIDE) + int ui = u >> 16; + int vi = v >> 16; + if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { - int a = samplemask(sp, sw, sh, u, v); - dp[0] = a + fz_mul255(dp[0], 255 - a); +#ifdef LINEAR + int uf = u & 0xffff; + int vf = v & 0xffff; + byte *a = samplenearest(sp, sw, sh, n, ui, vi); + byte *b = samplenearest(sp, sw, sh, n, ui+1, vi); + byte *c = samplenearest(sp, sw, sh, n, ui, vi+1); + byte *d = samplenearest(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++) + { + x = bilerp(a[k], b[k], c[k], d[k], uf, vf); + dp[k] = x + fz_mul255(dp[k], t); + } +#else + byte *sample = sp + ((vi * sw + ui) * n); + int t = 255 - fz_mul255(sample[n-1], alpha); + for (k = 0; k < n; k++) + dp[k] = sample[k] + fz_mul255(dp[k], t); +#endif } - dp ++; + dp += n; u += fa; v += fb; } } +/* Blend premultiplied source image over destination */ + static inline void -fz_blendscan2(unsigned char *dp, unsigned char *sp, int sw, int sh, - int u, int v, int fa, int fb, int w) +fz_paintaffineN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n) { + int k; + while (w--) { - if (INSIDE) + int ui = u >> 16; + int vi = v >> 16; + if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { - int g, a, t; - samplega(sp, sw, sh, u, v, &g, &a); - t = 255 - a; - dp[0] = g + fz_mul255(dp[0], t); - dp[1] = a + fz_mul255(dp[1], t); +#ifdef LINEAR + int uf = u & 0xffff; + int vf = v & 0xffff; + byte *a = samplenearest(sp, sw, sh, n, ui, vi); + byte *b = samplenearest(sp, sw, sh, n, ui+1, vi); + byte *c = samplenearest(sp, sw, sh, n, ui, vi+1); + byte *d = samplenearest(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 x = bilerp(a[k], b[k], c[k], d[k], uf, vf); + dp[k] = x + fz_mul255(dp[k], t); + } +#else + byte *sample = sp + ((vi * sw + ui) * n); + int t = 255 - sample[n-1]; + for (k = 0; k < n; k++) + dp[k] = sample[k] + fz_mul255(dp[k], t); +#endif } - dp += 2; + dp += n; u += fa; v += fb; } } +/* Blend non-premultiplied color in source image mask over destination */ + static inline void -fz_blendscan4(unsigned char *dp, unsigned char *sp, int sw, int sh, - int u, int v, int fa, int fb, int w) +fz_paintaffinecolorN(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color) { + int sa = color[n-1]; + int k; + while (w--) { - if (INSIDE) + int ui = u >> 16; + int vi = v >> 16; + if (ui >= 0 && ui < sw && vi >= 0 && vi < sh) { - int r, g, b, a, t; - samplergba(sp, sw, sh, u, v, &r, &g, &b, &a); - t = 255 - a; - dp[0] = r + fz_mul255(dp[0], t); - dp[1] = g + fz_mul255(dp[1], t); - dp[2] = b + fz_mul255(dp[2], t); - dp[3] = a + fz_mul255(dp[3], t); +#ifdef LINEAR + int uf = u & 0xffff; + int vf = v & 0xffff; + byte *a = samplenearest(sp, sw, sh, 1, ui, vi); + byte *b = samplenearest(sp, sw, sh, 1, ui+1, vi); + byte *c = samplenearest(sp, sw, sh, 1, ui, vi+1); + byte *d = samplenearest(sp, sw, sh, 1, ui+1, vi+1); + int ma = bilerp(a[0], b[0], c[0], d[0], uf, vf); +#else + int ma = sp[vi * sw + ui]; +#endif + int masa = FZ_COMBINE(FZ_EXPAND(ma), sa); + for (k = 0; k < n - 1; k++) + dp[k] = FZ_BLEND(color[k], dp[k], masa); + dp[k] = FZ_BLEND(255, dp[k], masa); } - dp += 4; + dp += n; u += fa; v += fb; } } -static inline void -fz_blendscan(unsigned char *dp, unsigned char *sp, int sw, int sh, - int u, int v, int fa, int fb, int w, int n) +void +fz_paintaffine(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha) { - while (w--) + if (alpha == 255) { - if (INSIDE) + switch (n) { - unsigned char color[FZ_MAXCOLORS+1]; - int k, t; - samplecolor(sp, sw, sh, n, u, v, color); - t = 255 - color[n-1]; - for (k = 0; k < n; k++) - dp[k] = color[k] + fz_mul255(dp[k], t); + case 1: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 1); break; + case 2: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 2); break; + case 4: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, 4); break; + default: fz_paintaffineN(dp, sp, sw, sh, u, v, fa, fb, w, n); break; } - dp += n; - u += fa; - v += fb; } -} - -/* Blend non-premultiplied color in image mask over destination */ - -static inline void -fz_blendscanwithcolor(unsigned char *dp, unsigned char *sp, int sw, int sh, - int u, int v, int fa, int fb, int w, int n, unsigned char *color) -{ - int sa = color[n-1]; - while (w--) + else if (alpha > 0) { - if (INSIDE) + switch (n) { - int ma = samplemask(sp, sw, sh, u, v); - int masa = fz_mul255(sa, ma); - int t = 255 - masa; - int k; - for (k = 0; k < n; k++) - dp[k] = fz_mul255(color[k], ma) + fz_mul255(dp[k], t); + case 1: fz_paintaffinealphaN(dp, sp, sw, sh, u, v, fa, fb, w, 1, alpha); break; + case 2: fz_paintaffinealphaN(dp, sp, sw, sh, u, v, fa, fb, w, 2, alpha); break; + case 4: fz_paintaffinealphaN(dp, sp, sw, sh, u, v, fa, fb, w, 4, alpha); break; + default: fz_paintaffinealphaN(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); break; } - dp += n; - u += fa; - v += fb; } } -/* Draw an image with an affine transform on destination */ - -static inline float roundup(float x) +void +fz_paintaffinecolor(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color) { - return (x < 0) ? floorf(x) : ceilf(x); + switch (n) + { + case 2: fz_paintaffinecolorN(dp, sp, sw, sh, u, v, fa, fb, w, 2, color); break; + case 4: fz_paintaffinecolorN(dp, sp, sw, sh, u, v, fa, fb, w, 4, color); break; + default: fz_paintaffinecolorN(dp, sp, sw, sh, u, v, fa, fb, w, n, color); break; + } } +/* Draw an image with an affine transform on destination */ + static void -fz_blendimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, - unsigned char *color) +fz_paintimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, byte *color, int alpha) { - unsigned char *dp, *sp; + byte *dp, *sp; int u, v, fa, fb, fc, fd; int x, y, w, h; int sw, sh, n; @@ -339,22 +232,14 @@ fz_blendimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, sw = img->w; sh = img->h; + /* TODO: if (fb == 0 && fa == 1) call fz_paintspan */ + while (h--) { if (color) - { - fz_blendscanwithcolor(dp, sp, sw, sh, u, v, fa, fb, w, n, color); - } + fz_paintaffinecolor(dp, sp, sw, sh, u, v, fa, fb, w, n, color); else - { - switch (n) - { - case 1: fz_blendscan1(dp, sp, sw, sh, u, v, fa, fb, w); break; - case 2: fz_blendscan2(dp, sp, sw, sh, u, v, fa, fb, w); break; - case 4: fz_blendscan4(dp, sp, sw, sh, u, v, fa, fb, w); break; - default: fz_blendscan(dp, sp, sw, sh, u, v, fa, fb, w, n); break; - } - } + fz_paintaffine(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha); dp += dst->w * n; u += fc; v += fd; @@ -362,16 +247,15 @@ fz_blendimageimp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, } void -fz_blendimagewithcolor(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, - unsigned char *color) +fz_paintimagecolor(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, byte *color) { assert(img->n == 1); - fz_blendimageimp(dst, scissor, img, ctm, color); + fz_paintimageimp(dst, scissor, img, ctm, color, 255); } void -fz_blendimage(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm) +fz_paintimage(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, int alpha) { assert(dst->n == img->n); - fz_blendimageimp(dst, scissor, img, ctm, nil); + fz_paintimageimp(dst, scissor, img, ctm, nil, alpha); } diff --git a/draw/meshdraw.c b/draw/meshdraw.c index 4fbdab70..61b678ab 100644 --- a/draw/meshdraw.c +++ b/draw/meshdraw.c @@ -378,7 +378,7 @@ fz_rendershade(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox) *d++ = clut[v][k]; *d++ = *s++; } - fz_blendpixmaps(dest, conv); + fz_paintpixmap(dest, conv, 255); fz_droppixmap(conv); fz_droppixmap(temp); } diff --git a/draw/pathscan.c b/draw/pathscan.c index dc6c6ff8..459dd306 100644 --- a/draw/pathscan.c +++ b/draw/pathscan.c @@ -476,9 +476,9 @@ blit(fz_pixmap *dest, int x, int y, unsigned char *mp, int w, unsigned char *col dp = dest->samples + ( (y - dest->y) * dest->w + (x - dest->x) ) * dest->n; if (color) - fz_blendwithcolormask(dp, color, mp, dest->n, w); + fz_paintspancolor(dp, mp, dest->n, w, color); else - fz_blendmasks(dp, mp, w); + fz_paintspan(dp, mp, 1, w, 255); } fz_error diff --git a/draw/porterduff.c b/draw/porterduff.c index e5070a5d..59a4f4d4 100644 --- a/draw/porterduff.c +++ b/draw/porterduff.c @@ -72,131 +72,172 @@ and stick to using the premultiplied form. typedef unsigned char byte; -/* Blend source alpha over destination alpha */ +/* Blend a non-premultiplied color in mask over destination */ -void -fz_blendmasks(byte * restrict dp, byte * restrict sp, int w) +static inline void +fz_paintspancolor2(byte * restrict dp, byte * restrict mp, int w, byte *color) { + int sa = FZ_EXPAND(color[1]); + int g = color[0]; while (w--) { - dp[0] = sp[0] + fz_mul255(dp[0], 255 - sp[0]); - sp++; - dp++; + int ma = *mp++; + int masa = FZ_COMBINE(FZ_EXPAND(ma), sa); + dp[0] = FZ_BLEND(g, dp[0], masa); + dp[1] = FZ_BLEND(255, dp[1], masa); + dp += 2; } } -/* Blend a non-premultiplied color in mask over destination */ +static inline void +fz_paintspancolor4(byte * restrict dp, byte * restrict mp, int w, byte *color) +{ + int sa = FZ_EXPAND(color[3]); + int r = color[0]; + int g = color[1]; + int b = color[2]; + while (w--) + { + int ma = *mp++; + int masa = FZ_COMBINE(FZ_EXPAND(ma), sa); + dp[0] = FZ_BLEND(r, dp[0], masa); + dp[1] = FZ_BLEND(g, dp[1], masa); + dp[2] = FZ_BLEND(b, dp[2], masa); + dp[3] = FZ_BLEND(255, dp[3], masa); + dp += 4; + } +} -void -fz_blendwithcolormask(byte * restrict dp, byte * restrict sp, byte * restrict mp, int n, int w) +static inline void +fz_paintspancolorN(byte * restrict dp, byte * restrict mp, int n, int w, byte *color) { - int sa, r, g, b, k; + int sa = FZ_EXPAND(color[n-1]); + int k; + while (w--) + { + int ma = *mp++; + int masa = FZ_COMBINE(FZ_EXPAND(ma), sa); + for (k = 0; k < n - 1; k++) + dp[k] = FZ_BLEND(color[k], dp[k], masa); + dp[k] = FZ_BLEND(255, dp[k], masa); + dp += n; + } +} +void +fz_paintspancolor(byte * restrict dp, byte * restrict mp, int n, int w, byte *color) +{ switch (n) { - case 2: - sa = FZ_EXPAND(sp[1]); - g = sp[0]; - while (w--) - { - int ma = *mp++; - int masa = FZ_COMBINE(FZ_EXPAND(ma), sa); - dp[0] = FZ_BLEND(g, dp[0], masa); - dp[1] = FZ_BLEND(255, dp[1], masa); - dp += 2; - } - break; - case 4: - sa = FZ_EXPAND(sp[3]); - r = sp[0]; - g = sp[1]; - b = sp[2]; - while (w--) - { - int ma = *mp++; - int masa = FZ_COMBINE(FZ_EXPAND(ma), sa); - dp[0] = FZ_BLEND(r, dp[0], masa); - dp[1] = FZ_BLEND(g, dp[1], masa); - dp[2] = FZ_BLEND(b, dp[2], masa); - dp[3] = FZ_BLEND(255, dp[3], masa); - dp += 4; - } - break; - default: - sa = FZ_EXPAND(sp[n-1]); - while (w--) - { - int ma = *mp++; - int masa = FZ_COMBINE(FZ_EXPAND(ma), sa); - for (k = 0; k < n - 1; k++) - dp[k] = FZ_BLEND(sp[k], dp[k], masa); - dp[k] = FZ_BLEND(255, dp[k], masa); - dp += n; - } + case 2: fz_paintspancolor2(dp, mp, w, color); break; + case 4: fz_paintspancolor4(dp, mp, w, color); break; + default: fz_paintspancolorN(dp, mp, n, w, color); break; } } /* Blend source in mask over destination */ -void -fz_blendwithmask(byte * restrict dp, byte * restrict sp, byte * restrict mp, int n, int w) +static inline void +fz_paintspanmask2(byte * restrict dp, byte * restrict sp, byte * restrict mp, int w) +{ + while (w--) + { + int ma = *mp++; + int masa = fz_mul255(sp[1], ma); + int t = 255 - masa; + dp[0] = fz_mul255(sp[0], ma) + fz_mul255(dp[0], t); + dp[1] = fz_mul255(sp[1], ma) + fz_mul255(dp[1], t); + sp += 2; + dp += 2; + } +} + +static inline void +fz_paintspanmask4(byte * restrict dp, byte * restrict sp, byte * restrict mp, int w) +{ + while (w--) + { + int ma = *mp++; + int masa = fz_mul255(sp[3], ma); + int t = 255 - masa; + dp[0] = fz_mul255(sp[0], ma) + fz_mul255(dp[0], t); + dp[1] = fz_mul255(sp[1], ma) + fz_mul255(dp[1], t); + dp[2] = fz_mul255(sp[2], ma) + fz_mul255(dp[2], t); + dp[3] = fz_mul255(sp[3], ma) + fz_mul255(dp[3], t); + sp += 4; + dp += 4; + } +} + +static inline void +fz_paintspanmaskN(byte * restrict dp, byte * restrict sp, byte * restrict mp, int n, int w) { int k; + while (w--) + { + int ma = *mp++; + int masa = fz_mul255(sp[n-1], ma); + int t = 255 - masa; + for (k = 0; k < n; k++) + dp[k] = fz_mul255(sp[k], ma) + fz_mul255(dp[k], t); + sp += n; + dp += n; + } +} +void +fz_paintspanmask(byte * restrict dp, byte * restrict sp, byte * restrict mp, int n, int w) +{ switch (n) { - case 2: - while (w--) - { - int ma = *mp++; - int masa = fz_mul255(sp[1], ma); - int t = 255 - masa; - dp[0] = fz_mul255(sp[0], ma) + fz_mul255(dp[0], t); - sp += 2; - dp += 2; - } - break; - case 4: - while (w--) - { - int ma = *mp++; - int masa = fz_mul255(sp[3], ma); - int t = 255 - masa; - dp[0] = fz_mul255(sp[0], ma) + fz_mul255(dp[0], t); - dp[1] = fz_mul255(sp[1], ma) + fz_mul255(dp[1], t); - dp[2] = fz_mul255(sp[2], ma) + fz_mul255(dp[2], t); - dp[3] = fz_mul255(sp[3], ma) + fz_mul255(dp[3], t); - sp += 4; - dp += 4; - } - break; - default: - while (w--) - { - int ma = *mp++; - int masa = fz_mul255(sp[n-1], ma); - int t = 255 - masa; - for (k = 0; k < n; k++) - dp[k] = fz_mul255(sp[k], ma) + fz_mul255(dp[k], t); - sp += n; - dp += n; - } + case 2: fz_paintspanmask2(dp, sp, mp, w); break; + case 4: fz_paintspanmask4(dp, sp, mp, w); break; + default: fz_paintspanmaskN(dp, sp, mp, n, w); break; } } -/* Blend source in (constant) alpha over destination */ +/* Blend source in constant alpha over destination */ -void -fz_blendwithalpha(byte * restrict dp, byte * restrict sp, int ma, int n, int w) +static inline void +fz_paintspan2alpha(byte * restrict dp, byte * restrict sp, int w, int alpha) { - int k; + while (w--) + { + int masa = fz_mul255(sp[1], alpha); + int t = 255 - masa; + dp[0] = fz_mul255(sp[0], masa) + fz_mul255(dp[0], t); + dp[1] = fz_mul255(sp[1], masa) + fz_mul255(dp[1], t); + sp += 2; + dp += 2; + } +} +static inline void +fz_paintspan4alpha(byte * restrict dp, byte * restrict sp, int w, int alpha) +{ while (w--) { - int masa = fz_mul255(sp[n-1], ma); + int masa = fz_mul255(sp[3], alpha); + int t = 255 - masa; + dp[0] = fz_mul255(sp[0], masa) + fz_mul255(dp[0], t); + dp[1] = fz_mul255(sp[1], masa) + fz_mul255(dp[1], t); + dp[2] = fz_mul255(sp[2], masa) + fz_mul255(dp[2], t); + dp[3] = fz_mul255(sp[3], masa) + fz_mul255(dp[3], t); + sp += 4; + dp += 4; + } +} + +static inline void +fz_paintspanNalpha(byte * restrict dp, byte * restrict sp, int n, int w, int alpha) +{ + int k; + while (w--) + { + int masa = fz_mul255(sp[n-1], alpha); int t = 255 - masa; for (k = 0; k < n; k++) - dp[k] = fz_mul255(sp[k], ma) + fz_mul255(dp[k], t); + dp[k] = fz_mul255(sp[k], masa) + fz_mul255(dp[k], t); sp += n; dp += n; } @@ -204,11 +245,50 @@ fz_blendwithalpha(byte * restrict dp, byte * restrict sp, int ma, int n, int w) /* Blend source over destination */ -void -fz_blendnormal(byte * restrict dp, byte * restrict sp, int n, int w) +static inline void +fz_paintspan1(byte * restrict dp, byte * restrict sp, int w) { - int k; + while (w--) + { + int t = 255 - sp[0]; + dp[0] = sp[0] + fz_mul255(dp[0], t); + sp ++; + dp ++; + } +} +static inline void +fz_paintspan2(byte * restrict dp, byte * restrict sp, int w) +{ + while (w--) + { + int t = 255 - sp[1]; + dp[0] = sp[0] + fz_mul255(dp[0], t); + dp[1] = sp[1] + fz_mul255(dp[1], t); + sp += 2; + dp += 2; + } +} + +static inline void +fz_paintspan4(byte * restrict dp, byte * restrict sp, int w) +{ + while (w--) + { + int t = 255 - sp[3]; + dp[0] = sp[0] + fz_mul255(dp[0], t); + dp[1] = sp[1] + fz_mul255(dp[1], t); + dp[2] = sp[2] + fz_mul255(dp[2], t); + dp[3] = sp[3] + fz_mul255(dp[3], t); + sp += 4; + dp += 4; + } +} + +static inline void +fz_paintspanN(byte * restrict dp, byte * restrict sp, int n, int w) +{ + int k; while (w--) { int t = 255 - sp[n-1]; @@ -219,23 +299,45 @@ fz_blendnormal(byte * restrict dp, byte * restrict sp, int n, int w) } } +void +fz_paintspan(byte * restrict dp, byte * restrict sp, int n, int w, int alpha) +{ + if (alpha == 255) + { + switch (n) + { + case 1: fz_paintspan1(dp, sp, w); break; + case 2: fz_paintspan2(dp, sp, w); break; + case 4: fz_paintspan4(dp, sp, w); break; + default: fz_paintspanN(dp, sp, n, w); break; + } + } + else if (alpha > 0) + { + switch (n) + { + case 2: fz_paintspan2alpha(dp, sp, w, alpha); break; + case 4: fz_paintspan4alpha(dp, sp, w, alpha); break; + default: fz_paintspanNalpha(dp, sp, n, w, alpha); break; + } + } +} + /* * Pixmap blending functions */ void -fz_blendpixmapswithmask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk) +fz_paintpixmap(fz_pixmap *dst, fz_pixmap *src, int alpha) { - unsigned char *sp, *dp, *mp; + unsigned char *sp, *dp; fz_bbox bbox; int x, y, w, h, n; assert(dst->n == src->n); - assert(msk->n == 1); bbox = fz_boundpixmap(dst); bbox = fz_intersectbbox(bbox, fz_boundpixmap(src)); - bbox = fz_intersectbbox(bbox, fz_boundpixmap(msk)); x = bbox.x0; y = bbox.y0; @@ -244,53 +346,45 @@ fz_blendpixmapswithmask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk) n = src->n; sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n; - mp = msk->samples + ((y - msk->y) * msk->w + (x - msk->x)) * msk->n; dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n; while (h--) { - fz_blendwithmask(dp, sp, mp, n, w); + fz_paintspan(dp, sp, n, w, alpha); sp += src->w * n; dp += dst->w * n; - mp += msk->w; } } void -fz_blendpixmapswithalpha(fz_pixmap *dst, fz_pixmap *src, float alpha) +fz_paintpixmapmask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk) { - unsigned char *sp, *dp; + unsigned char *sp, *dp, *mp; fz_bbox bbox; - int x, y, w, h, n, a; + int x, y, w, h, n; assert(dst->n == src->n); + assert(msk->n == 1); bbox = fz_boundpixmap(dst); bbox = fz_intersectbbox(bbox, fz_boundpixmap(src)); + bbox = fz_intersectbbox(bbox, fz_boundpixmap(msk)); x = bbox.x0; y = bbox.y0; w = bbox.x1 - bbox.x0; h = bbox.y1 - bbox.y0; - a = alpha * 255; n = src->n; sp = src->samples + ((y - src->y) * src->w + (x - src->x)) * src->n; + mp = msk->samples + ((y - msk->y) * msk->w + (x - msk->x)) * msk->n; dp = dst->samples + ((y - dst->y) * dst->w + (x - dst->x)) * dst->n; while (h--) { - if (a == 255) - fz_blendnormal(dp, sp, n, w); - else - fz_blendwithalpha(dp, sp, a, n, w); + fz_paintspanmask(dp, sp, mp, n, w); sp += src->w * n; dp += dst->w * n; + mp += msk->w; } } - -void -fz_blendpixmaps(fz_pixmap *dst, fz_pixmap *src) -{ - fz_blendpixmapswithalpha(dst, src, 1); -} diff --git a/fitz/dev_draw.c b/fitz/dev_draw.c index 964ab4f6..4f7e41a0 100644 --- a/fitz/dev_draw.c +++ b/fitz/dev_draw.c @@ -53,18 +53,12 @@ fz_drawfillpath(void *user, fz_path *path, int evenodd, fz_matrix ctm, if (fz_isemptyrect(bbox)) return; - if (model) - { - fz_convertcolor(colorspace, color, model, colorfv); - for (i = 0; i < model->n; i++) - colorbv[i] = colorfv[i] * 255; - colorbv[i] = alpha * 255; - fz_scanconvert(dev->gel, dev->ael, evenodd, bbox, dev->dest, colorbv); - } - else - { - fz_scanconvert(dev->gel, dev->ael, evenodd, bbox, dev->dest, nil); - } + fz_convertcolor(colorspace, color, model, colorfv); + for (i = 0; i < model->n; i++) + colorbv[i] = colorfv[i] * 255; + colorbv[i] = alpha * 255; + + fz_scanconvert(dev->gel, dev->ael, evenodd, bbox, dev->dest, colorbv); } static void @@ -97,18 +91,12 @@ fz_drawstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matrix c if (fz_isemptyrect(bbox)) return; - if (model) - { - fz_convertcolor(colorspace, color, model, colorfv); - for (i = 0; i < model->n; i++) - colorbv[i] = colorfv[i] * 255; - colorbv[i] = alpha * 255; - fz_scanconvert(dev->gel, dev->ael, 0, bbox, dev->dest, colorbv); - } - else - { - fz_scanconvert(dev->gel, dev->ael, 0, bbox, dev->dest, nil); - } + fz_convertcolor(colorspace, color, model, colorfv); + for (i = 0; i < model->n; i++) + colorbv[i] = colorfv[i] * 255; + colorbv[i] = alpha * 255; + + fz_scanconvert(dev->gel, dev->ael, 0, bbox, dev->dest, colorbv); } static void @@ -235,9 +223,9 @@ drawglyph(unsigned char *colorbv, fz_pixmap *dst, fz_pixmap *msk, while (h--) { if (dst->colorspace) - fz_blendwithcolormask(dp, colorbv, mp, dst->n, w); + fz_paintspancolor(dp, mp, dst->n, w, colorbv); else - fz_blendmasks(dp, mp, w); + fz_paintspan(dp, mp, 1, w, 255); dp += dst->w * dst->n; mp += msk->w; } @@ -255,13 +243,10 @@ fz_drawfilltext(void *user, fz_text *text, fz_matrix ctm, fz_pixmap *glyph; int i, x, y, gid; - if (model) - { - fz_convertcolor(colorspace, color, model, colorfv); - for (i = 0; i < model->n; i++) - colorbv[i] = colorfv[i] * 255; - colorbv[i] = alpha * 255; - } + fz_convertcolor(colorspace, color, model, colorfv); + for (i = 0; i < model->n; i++) + colorbv[i] = colorfv[i] * 255; + colorbv[i] = alpha * 255; tm = text->trm; @@ -282,10 +267,7 @@ fz_drawfilltext(void *user, fz_text *text, fz_matrix ctm, glyph = fz_renderglyph(dev->cache, text->font, gid, trm); if (glyph) { - if (model) - drawglyph(colorbv, dev->dest, glyph, x, y, dev->scissor); - else - drawglyph(nil, dev->dest, glyph, x, y, dev->scissor); + drawglyph(colorbv, dev->dest, glyph, x, y, dev->scissor); fz_droppixmap(glyph); } } @@ -303,13 +285,10 @@ fz_drawstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix c fz_pixmap *glyph; int i, x, y, gid; - if (model) - { - fz_convertcolor(colorspace, color, model, colorfv); - for (i = 0; i < model->n; i++) - colorbv[i] = colorfv[i] * 255; - colorbv[i] = alpha * 255; - } + fz_convertcolor(colorspace, color, model, colorfv); + for (i = 0; i < model->n; i++) + colorbv[i] = colorfv[i] * 255; + colorbv[i] = alpha * 255; tm = text->trm; @@ -330,10 +309,7 @@ fz_drawstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix c glyph = fz_renderstrokedglyph(dev->cache, text->font, gid, trm, ctm, stroke); if (glyph) { - if (model) - drawglyph(colorbv, dev->dest, glyph, x, y, dev->scissor); - else - drawglyph(nil, dev->dest, glyph, x, y, dev->scissor); + drawglyph(colorbv, dev->dest, glyph, x, y, dev->scissor); fz_droppixmap(glyph); } } @@ -413,7 +389,7 @@ fz_drawcliptext(void *user, fz_text *text, fz_matrix ctm, int accumulate) glyph = fz_renderglyph(dev->cache, text->font, gid, trm); if (glyph) { - drawglyph(NULL, mask, glyph, x, y, bbox); + drawglyph(nil, mask, glyph, x, y, bbox); fz_droppixmap(glyph); } } @@ -475,7 +451,7 @@ fz_drawclipstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matr glyph = fz_renderstrokedglyph(dev->cache, text->font, gid, trm, ctm, stroke); if (glyph) { - drawglyph(NULL, mask, glyph, x, y, bbox); + drawglyph(nil, mask, glyph, x, y, bbox); fz_droppixmap(glyph); } } @@ -548,7 +524,7 @@ fz_drawfillshade(void *user, fz_shade *shade, fz_matrix ctm, float alpha) if (alpha < 1) { - fz_blendpixmapswithalpha(dev->dest, dest, alpha); + fz_paintpixmap(dev->dest, dest, alpha * 255); fz_droppixmap(dest); } } @@ -604,21 +580,7 @@ fz_drawfillimage(void *user, fz_pixmap *image, fz_matrix ctm, float alpha) } #endif - if (alpha < 1) - { - fz_pixmap *temp; - fz_bbox bbox; - bbox = fz_roundrect(fz_transformrect(ctm, fz_unitrect)); - bbox = fz_intersectbbox(bbox, dev->scissor); - temp = fz_newpixmapwithrect(dev->dest->colorspace, bbox); - fz_blendimage(temp, bbox, image, ctm); - fz_blendpixmapswithalpha(dev->dest, temp, alpha); - fz_droppixmap(temp); - } - else - { - fz_blendimage(dev->dest, dev->scissor, image, ctm); - } + fz_paintimage(dev->dest, dev->scissor, image, ctm, alpha * 255); if (scaled) fz_droppixmap(scaled); @@ -657,18 +619,12 @@ fz_drawfillimagemask(void *user, fz_pixmap *image, fz_matrix ctm, } #endif - if (dev->dest->colorspace) - { - fz_convertcolor(colorspace, color, model, colorfv); - for (i = 0; i < model->n; i++) - colorbv[i] = colorfv[i] * 255; - colorbv[i] = alpha * 255; - fz_blendimagewithcolor(dev->dest, dev->scissor, image, ctm, colorbv); - } - else - { - fz_blendimage(dev->dest, dev->scissor, image, ctm); - } + fz_convertcolor(colorspace, color, model, colorfv); + for (i = 0; i < model->n; i++) + colorbv[i] = colorfv[i] * 255; + colorbv[i] = alpha * 255; + + fz_paintimagecolor(dev->dest, dev->scissor, image, ctm, colorbv); if (scaled) fz_droppixmap(scaled); @@ -725,7 +681,7 @@ fz_drawclipimagemask(void *user, fz_pixmap *image, fz_matrix ctm) } #endif - fz_blendimage(mask, bbox, image, ctm); + fz_paintimage(mask, bbox, image, ctm, 255); if (scaled) fz_droppixmap(scaled); @@ -752,7 +708,7 @@ fz_drawpopclip(void *user) if (mask && dest) { fz_pixmap *scratch = dev->dest; - fz_blendpixmapswithmask(dest, scratch, mask); + fz_paintpixmapmask(dest, scratch, mask); fz_droppixmap(mask); fz_droppixmap(scratch); dev->dest = dest; @@ -884,27 +840,9 @@ fz_drawendgroup(void *user) dev->scissor = dev->stack[dev->top].scissor; if (blendmode == FZ_BNORMAL) - { - if (alpha < 1) - fz_blendpixmapswithalpha(dev->dest, group, alpha); - else - fz_blendpixmaps(dev->dest, group); - } + fz_paintpixmap(dev->dest, group, alpha * 255); else - { - if (alpha < 1) - { - unsigned char *p = group->samples; - int n = group->w * group->h * group->n; - int a = alpha * 255; - while (n--) - { - *p = fz_mul255(*p, a); - p++; - } - } - fz_blendpixmapswithmode(dev->dest, group, blendmode); - } + fz_blendpixmap(dev->dest, group, alpha * 255, blendmode); fz_droppixmap(group); } diff --git a/fitz/fitz.h b/fitz/fitz.h index 44f1c070..8cd351ae 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -1030,6 +1030,50 @@ void fz_executedisplaylist(fz_displaylist *list, fz_device *dev, fz_matrix ctm); * They can be replaced by cpu-optimized versions. */ +/* +These are the blending primitives: + +span over span (text and path drawing to clip mask) +span in alpha over span +span in span over span +color in span over span (text and path drawing) + + fz_paintspan(dp, sp); + fz_paintspanalpha(dp, sp, alpha) + fz_paintspanmask(dp, sp, mask); + fz_paintspancolor(dp, color, mask); + +pixmap over pixmap (shading with function lookup) +pixmap in alpha over pixmap (xobject/shading with ca) +pixmap in pixmap over pixmap (xobject with softmask / clip) + + fz_paintpixmap() + fz_paintpixmapalpha() + fz_paintpixmapmask() + +affine over span +affine in alpha over span +color in affine over span + + fz_paintaffine() + fz_paintaffinealpha() + fz_paintaffinecolor() + +image over pixmap (image fill) +image in alpha over pixmap (image fill with ca) +color in image over pixmap (image mask fill) + + fz_paintimage() + fz_paintimagealpha() + fz_paintimagecolor() + +pixmap BLEND pixmap +pixmap in alpha BLEND pixmap + + fz_blendpixmap() + fz_blendpixmapalpha() +*/ + void fz_accelerate(void); void fz_acceleratearch(void); @@ -1037,18 +1081,20 @@ void fz_decodetile(fz_pixmap *pix, float *decode); void fz_decodeindexedtile(fz_pixmap *pix, float *decode, int maxval); void fz_unpacktile(fz_pixmap *dst, unsigned char * restrict src, int n, int depth, int stride, int scale); -void fz_blendpixmapswithmode(fz_pixmap *dst, fz_pixmap *src, fz_blendmode blendmode); -void fz_blendpixmapswithmask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk); -void fz_blendpixmapswithalpha(fz_pixmap *dst, fz_pixmap *src, float alpha); -void fz_blendpixmaps(fz_pixmap *dst, fz_pixmap *src); +void fz_paintspan(unsigned char * restrict dp, unsigned char * restrict sp, int n, int w, int alpha); +void fz_paintspancolor(unsigned char * restrict dp, unsigned char * restrict mp, int n, int w, unsigned char *color); +void fz_paintspanmask(unsigned char * restrict dp, unsigned char * restrict sp, unsigned char * restrict mp, int n, int w); + +void fz_paintaffine(unsigned char *dp, unsigned char *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha); +void fz_paintaffinecolor(unsigned char *dp, unsigned char *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, unsigned char *color); + +void fz_paintimage(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, int alpha); +void fz_paintimagecolor(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, unsigned char *colorbv); -void fz_blendmasks(unsigned char * restrict dp, unsigned char * restrict sp, int w); -void fz_blendwithcolormask(unsigned char * restrict dp, unsigned char * restrict sp, unsigned char * restrict mp, int n, int w); -void fz_blendnormal(unsigned char * restrict dp, unsigned char * restrict sp, int n, int w); -void fz_blendwithmask(unsigned char * restrict dp, unsigned char * restrict sp, unsigned char * restrict mp, int n, int w); +void fz_paintpixmap(fz_pixmap *dst, fz_pixmap *src, int alpha); +void fz_paintpixmapmask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk); -void fz_blendimage(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm); -void fz_blendimagewithcolor(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *img, fz_matrix ctm, unsigned char *colorbv); +void fz_blendpixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_blendmode blendmode); extern void (*fz_srown)(unsigned char *restrict, unsigned char *restrict, int w, int denom, int n); extern void (*fz_srow1)(unsigned char *restrict, unsigned char *restrict, int w, int denom); diff --git a/fitz/res_font.c b/fitz/res_font.c index 68b761b2..fd3bbe3f 100644 --- a/fitz/res_font.c +++ b/fitz/res_font.c @@ -458,6 +458,7 @@ fz_rendert3glyph(fz_font *font, int gid, fz_matrix trm) fz_device *dev; fz_glyphcache *cache; fz_pixmap *glyph; + fz_pixmap *result; if (gid < 0 || gid > 255) return NULL; @@ -473,7 +474,7 @@ fz_rendert3glyph(fz_font *font, int gid, fz_matrix trm) fz_catch(error, "cannot draw type3 glyph"); fz_freedevice(dev); - glyph = fz_newpixmap(nil, bbox.x0-1, bbox.y0-1, bbox.x1 - bbox.x0 + 1, bbox.y1 - bbox.y0 + 1); + glyph = fz_newpixmap(fz_devicegray, bbox.x0-1, bbox.y0-1, bbox.x1 - bbox.x0 + 1, bbox.y1 - bbox.y0 + 1); fz_clearpixmap(glyph, 0); cache = fz_newglyphcache(); @@ -484,7 +485,10 @@ fz_rendert3glyph(fz_font *font, int gid, fz_matrix trm) fz_freedevice(dev); fz_freeglyphcache(cache); - return glyph; + result = fz_alphafromgray(glyph, 0); + fz_droppixmap(glyph); + + return result; } void |