I was doing some detailed analysis of defects when rendering
URW Nimbus Sans and found the most obvious defects came either
from:
- A few incorrect hints (tweaking the BlueValues makes a
big difference)
- Lack of gamma correction; because a color component
of 0x80 is a lot darker than a 50% intensity level,
diagonal stems appear too dark.
To explore the second issue, I made up the following patch
which adds gamma-corrected compositing to the
anti-aliasing-without-render code in Xft. I chose to
modify this code rather than the Xrender compositing code
because:
- The scope is more limited. (Premultiplication turns
from a blessing to a curse when you throw gamma
correction into the picture, so it's a lot easier
only have to worry about the color + mask case.)
- It's a lot easier to hack a library than the server.
- It provided an easy way to compare and contrast
by turning on or of FC_RENDER.
I used the sRGB color curve rather than a plain power-law
because the linear ramp for low intensities reduces
the needed intermediate precision and thus the size
of the lookup tables.
(This is why sRGB has a linear ramp for low intensities,
I believe.)
My guess is (without any timing at all) that this patch shouldn't
have a big effect on the speed of the aa-without-render code;
my experience is that the heavy bitops that the old code
was doing to manipulate RGBA values as 32 bit quantities
tends to hurt a bit, so I don't think going to separate
12-bit primaries for intermediate results will make a big
difference.
Positive:
- It looks a whole lot better
Negative:
- Getting the best looking results depends fairly strongly
on the actual display gamma. My laptop display's gamma is
somewhat under the ideal 2.2, so the gamma correction
overcompensates a bit. Diagonal stems now appear a bit
light.
- It tends to make it very obvious if the different colors
on your display have different gammas. The gamma for
blue is higher than for the other primaries on my laptop
so diagonal stems look somewhat blue.
- I think the TT Interpreter + AA was producing somewhat
light stems to begin with, which was being compensated
for by the lack of gamma correction.
- The uncorrected results now look awful to me, but
getting this into the Xrender path is going to be
a lot harder. ;-(.
I'll post some screenshots in a little bit.
Regards,
Owen
--- fcpackage.02-06-21.10-39/Xft/xftcore.c.gamma Sun Jun 23 10:35:12 2002
+++ fcpackage.02-06-21.10-39/Xft/xftcore.c Sun Jun 23 16:17:43 2002
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include "xftint.h"
#include <X11/Xmd.h>
+#include <math.h>
void
XftRectCore (XftDraw *draw,
@@ -367,6 +368,64 @@
}
/*
+ * These functions define the sRGB curve that we use for gamma correction;
+ * because of the linear ramp at the beginning, the sRGB curve allows
+ * a much more manageable lookup table than a straight x**2.2 gamma curve
+ *
+ * Apparently, the values of ADJGAMA and OFFSET were chosen to minimize
+ * the difference between the sRGB function and X**2.2; the free parameters
+ * here really are GAMMA (=2.2) and THRESHOLD.
+ */
+#define THRESHOLD 0.03928 /* Very close to 10./255 */
+#define OFFSET 0.055
+#define ADJGAMMA 2.4
+#define SLOPE 12.92 /* gammaCurve (THRESHOLD) / THRESHOLD */
+
+static double
+gammaCurve(double x)
+{
+ if (x <= THRESHOLD)
+ return x / SLOPE;
+ else
+ return pow(((OFFSET + x) / (1 + OFFSET)), ADJGAMMA);
+}
+
+static double
+gammaCurveInv(double y)
+{
+ if (y <= THRESHOLD / SLOPE)
+ return y * SLOPE;
+ else
+ return pow(y, 1/ADJGAMMA) * (1 + OFFSET) - OFFSET;
+}
+
+static CARD16 gammaTable5[32];
+static CARD16 gammaTable6[64];
+static CARD16 gammaTable8[256];
+static CARD8 gammaTableInv[4096];
+
+static void
+gammaTablePrepare(void)
+{
+ static int prepared = 0;
+ int i;
+
+ if (!prepared)
+ {
+ for (i = 0; i < 32; i++)
+ gammaTable5[i] = 4095 * gammaCurve(i/31.) + 0.5;
+ for (i = 0; i < 64; i++)
+ gammaTable6[i] = 4095 * gammaCurve(i/63.) + 0.5;
+ for (i = 0; i < 256; i++)
+ gammaTable8[i] = 4095 * gammaCurve(i/255.) + 0.5;
+ for (i = 0; i < 4096; i++)
+ gammaTableInv[i] = 255 * gammaCurveInv(i/4095.) + 0.5;
+
+ prepared = 1;
+ }
+}
+
+/*
* As simple anti-aliasing is likely to be common, there are three
* optimized versions for the usual true color pixel formats (888, 565, 555).
* Other formats are handled by the general case
@@ -387,13 +446,35 @@
#define cvt0555to8888(s) (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \
((((s) << 6) & 0xf800) | (((s) >> 0) & 0x300)) | \
((((s) << 9) & 0xf80000) | (((s) << 4) & 0x70000)))
+#define cvt0555to8888(s) (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \
+ ((((s) << 6) & 0xf800) | (((s) >> 0) & 0x300)) | \
+ ((((s) << 9) & 0xf80000) | (((s) << 4) & 0x70000)))
+
+#define XftGet8(v,i) ((CARD16) (CARD8) ((v) >> i))
+#define cvt0888toGamma12(d,s) (d##_r = gammaTable8[XftGet8(s,16)], \
+ d##_g = gammaTable8[XftGet8(s,8)], \
+ d##_b = gammaTable8[XftGet8(s,0)])
+#define cvt0565toGamma12(d,s) (d##_r = gammaTable5[((s) & 0xf800) >> 11], \
+ d##_g = gammaTable6[((s) & 0x07e0) >> 5], \
+ d##_b = gammaTable5[((s) & 0x1f)])
+#define cvt0555toGamma12(d,s) (d##_r = gammaTable5[((s) & 0x7c00) >> 10], \
+ d##_g = gammaTable5[((s) & 0x03e0) >> 5], \
+ d##_b = gammaTable5[((s) & 0x001f)])
+
+#define cvtGamma12to0888(s) (gammaTableInv[s##_r] << 16 | \
+ gammaTableInv[s##_g] << 8| \
+ gammaTableInv[s##_b]);
+#define cvtGamma12to0565(s) (((gammaTableInv[s##_r] << 8) & 0xf800) | \
+ ((gammaTableInv[s##_g] << 3) & 0x07e0) | \
+ ((gammaTableInv[s##_b] >> 3)))
+#define cvtGamma12to0555(s) (((gammaTableInv[s##_r] << 7) & 0x7c00) | \
+ ((gammaTableInv[s##_g] << 3) & 0x03e0) | \
+ ((gammaTableInv[s##_b] >> 3)))
#define XftIntMult(a,b,t) ( (t) = (a) * (b) + 0x80, ( ( ( (t)>>8 ) + (t) )>>8 ) )
#define XftIntDiv(a,b) (((CARD16) (a) * 255) / (b))
-#define XftGet8(v,i) ((CARD16) (CARD8) ((v) >> i))
-
/*
* There are two ways of handling alpha -- either as a single unified value or
* a separate value for each component, hence each macro must have two
@@ -402,16 +483,48 @@
* this difference will have two versions using the same convention.
*/
+#define XftDeclare3(var) CARD32 var##_r, var##_g, var##_b
+#define XftDeclare4(var) CARD32 var##_a, var##_r, var##_g, var##_b
+#define XftAssign3(dst,src) (dst##_r = src##_r, \
+ dst##_b = src##_b, \
+ dst##_g = src##_g)
+#define XftAssignRGB(dst,r,g,b) (dst##_r = r, \
+ dst##_b = b, \
+ dst##_g = g)
+
#define XftOverU(x,y,i,a,t) ((t) = XftIntMult(XftGet8(y,i),(a),(t)) + XftGet8(x,i),\
(CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i))
#define XftOverC(x,y,i,a,t) ((t) = XftIntMult(XftGet8(y,i),XftGet8(a,i),(t)) + XftGet8(x,i),\
(CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i))
+#define XftOverO(x,y,a,t) ((t) = XftIntMult(y,255-(a),(t)) + x,\
+ (0xfff & ((t) | (0 - ((t) >> 12)))))
+
+#define XftOver3U(d,x,y,a,t) (d##_r = XftOverO(x##_r,y##_r,a,t##_r), \
+ d##_g = XftOverO(x##_g,y##_g,a,t##_g), \
+ d##_b = XftOverO(x##_b,y##_r,a,t##_b))
+#define XftOver3C(d,x,y,a,t) (d##_r = XftOverO(x##_r,y##_r,a##_r,t##_r), \
+ d##_g = XftOverO(x##_g,y##_g,a##_g,t##_g), \
+ d##_b = XftOverO(x##_b,y##_r,a##_b,t##_b))
+
#define XftInU(x,i,a,t) ((CARD32) XftIntMult(XftGet8(x,i),(a),(t)) << (i))
#define XftInC(x,i,a,t) ((CARD32) XftIntMult(XftGet8(x,i),XftGet8(a,i),(t)) << (i))
+#define XftInO(x,a,t) (XftIntMult(x,a,t))
+
+#define XftIn4U(d,x,a,t) (d##_a = XftInO(x##_a,a,t##_a), \
+ d##_r = XftInO(x##_r,a,t##_r), \
+ d##_g = XftInO(x##_g,a,t##_g), \
+ d##_b = XftInO(x##_b,a,t##_b))
+#define XftIn3C(dc,da,x,a,m,t1,t2) (dc##_r = XftInO(x##_r,XftGet8(m,16),t1##_r), \
+ da##_r = XftInO(a,XftGet8(m,16),t2##_r), \
+ dc##_g = XftInO(x##_g,XftGet8(m,8),t1##_g), \
+ da##_g = XftInO(a,XftGet8(m,8),t2##_g), \
+ dc##_b = XftInO(x##_b,XftGet8(m,0),t1##_b), \
+ da##_b = XftInO(a,XftGet8(m,0),t2##_b))
+
#define XftGen(x,y,i,ax,ay,t,u,v) ((t) = (XftIntMult(XftGet8(y,i),ay,(u)) + \
XftIntMult(XftGet8(x,i),ax,(v))),\
(CARD32) ((CARD8) ((t) | \
@@ -449,36 +562,69 @@
}
static void
+colorToGamma12 (XftColor *color,
+ CARD32 *dst_r,
+ CARD32 *dst_g,
+ CARD32 *dst_b)
+{
+ CARD32 src_a = color->color.alpha >> 8;
+ CARD32 t;
+
+#define fromDouble(a,d,t) XftIntMult(a,(gammaCurve(d) + (0.5 / 4095.)) / 4095, t)
+
+ if (src_a)
+ {
+ *dst_r = fromDouble(src_a, (double)color->color.red / color->color.alpha, t);
+ *dst_g = fromDouble(src_a, (double)color->color.red / color->color.alpha, t);
+ *dst_b = fromDouble(src_a, (double)color->color.red / color->color.alpha, t);
+ }
+ else
+ *dst_r = *dst_g = *dst_b = 0;
+}
+
+#define cvtColorToGamma12(dst,color) colorToGamma12(color, &dst##_r, &dst##_g, &dst##_b)
+#define cvtColorToGamma12r(dst,color) colorToGamma12(color, &dst##_b, &dst##_g, &dst##_r)
+
+static void
_XftSmoothGlyphGray8888 (XImage *image,
XftGlyph *xftg,
int x,
int y,
XftColor *color)
{
- CARD32 src, srca;
- CARD32 r, g, b;
- CARD32 *dstLine, *dst, d;
+ XftDeclare4(src);
+ XftDeclare3(dst);
+ CARD32 src;
+ CARD32 r, g, b;
+ CARD32 *dstLine, *dst;
CARD8 *maskLine, *mask, m;
int dstStride, maskStride;
int width, height;
int w;
- srca = color->color.alpha >> 8;
+ gammaTablePrepare();
+
+ src_a = color->color.alpha >> 8;
/* This handles only RGB and BGR */
- g = (color->color.green & 0xff00);
+ src_g = gammaTable8[color->color.green >> 8];
+ g = color->color.green & 0xff00;
if (image->red_mask == 0xff0000)
{
r = (color->color.red & 0xff00) << 8;
b = color->color.blue >> 8;
+
+ cvtColorToGamma12(src, color);
}
else
{
- r = color->color.red >> 8;
b = (color->color.blue & 0xff00) << 8;
+ r = color->color.red >> 8;
+
+ cvtColorToGamma12r(src, color);
}
- src = (srca << 24) | r | g | b;
-
+ src = r | g | b;
+
width = xftg->metrics.width;
height = xftg->metrics.height;
@@ -503,15 +649,29 @@
m = *mask++;
if (m == 0xff)
{
- if (srca == 0xff)
+ if (src_a == 0xff)
*dst = src;
else
- *dst = fbOver24 (src, *dst);
+ {
+ XftDeclare3(tmpdst);
+ XftDeclare3(scratch1);
+
+ cvt0888toGamma12(tmpdst, *dst);
+ XftOver3U(dst, src, tmpdst, src_a, scratch1);
+ *dst = cvtGamma12to0888(dst);
+ }
}
else if (m)
{
- d = fbIn (src, m);
- *dst = fbOver24 (d, *dst);
+ XftDeclare3(tmpdst);
+ XftDeclare4(tmpsrc);
+ XftDeclare4(scratch1);
+ XftDeclare3(scratch2);
+
+ cvt0888toGamma12(tmpdst, *dst);
+ XftIn4U(tmpsrc, src, m, scratch1);
+ XftOver3U(dst, tmpsrc, tmpdst, tmpsrc_a, scratch2);
+ *dst = cvtGamma12to0888(dst);
}
dst++;
}
@@ -525,16 +685,19 @@
int y,
XftColor *color)
{
- CARD32 src, srca;
+ XftDeclare4(src);
+ XftDeclare3(dst);
+ CARD16 src;
CARD32 r, g, b;
- CARD32 d;
CARD16 *dstLine, *dst;
CARD8 *maskLine, *mask, m;
int dstStride, maskStride;
int width, height;
int w;
- srca = color->color.alpha >> 8;
+ gammaTablePrepare();
+
+ src_a = color->color.alpha >> 8;
/* This handles only RGB and BGR */
g = (color->color.green & 0xff00);
@@ -542,13 +705,17 @@
{
r = (color->color.red & 0xff00) << 8;
b = color->color.blue >> 8;
+
+ cvtColorToGamma12(src, color);
}
else
{
r = color->color.red >> 8;
b = (color->color.blue & 0xff00) << 8;
+
+ cvtColorToGamma12r(src, color);
}
- src = (srca << 24) | r | g | b;
+ src = cvt8888to0565(r | g | b);
width = xftg->metrics.width;
height = xftg->metrics.height;
@@ -574,20 +741,29 @@
m = *mask++;
if (m == 0xff)
{
- if (srca == 0xff)
- d = src;
+ if (src_a == 0xff)
+ *dst = src;
else
{
- d = *dst;
- d = fbOver24 (src, cvt0565to8888(d));
+ XftDeclare3(tmpdst);
+ XftDeclare3(scratch1);
+
+ cvt0565toGamma12(tmpdst, *dst);
+ XftOver3U(dst, src, tmpdst, src_a, scratch1);
+ *dst = cvtGamma12to0565(dst);
}
- *dst = cvt8888to0565(d);
}
else if (m)
{
- d = *dst;
- d = fbOver24 (fbIn(src,m), cvt0565to8888(d));
- *dst = cvt8888to0565(d);
+ XftDeclare3(tmpdst);
+ XftDeclare4(tmpsrc);
+ XftDeclare4(scratch1);
+ XftDeclare3(scratch2);
+
+ cvt0565toGamma12(tmpdst, *dst);
+ XftIn4U(tmpsrc, src, m, scratch1);
+ XftOver3U(dst, tmpsrc, tmpdst, tmpsrc_a, scratch2);
+ *dst = cvtGamma12to0565(dst);
}
dst++;
}
@@ -601,16 +777,19 @@
int y,
XftColor *color)
{
- CARD32 src, srca;
+ XftDeclare4(src);
+ XftDeclare3(dst);
+ CARD16 src;
CARD32 r, g, b;
- CARD32 d;
CARD16 *dstLine, *dst;
CARD8 *maskLine, *mask, m;
int dstStride, maskStride;
int width, height;
int w;
- srca = color->color.alpha >> 8;
+ gammaTablePrepare();
+
+ src_a = color->color.alpha >> 8;
/* This handles only RGB and BGR */
g = (color->color.green & 0xff00);
@@ -618,13 +797,17 @@
{
r = (color->color.red & 0xff00) << 8;
b = color->color.blue >> 8;
+
+ cvtColorToGamma12(src, color);
}
else
{
r = color->color.red >> 8;
b = (color->color.blue & 0xff00) << 8;
+
+ cvtColorToGamma12r(src, color);
}
- src = (srca << 24) | r | g | b;
+ src = cvt8888to0555(r | g | b);
width = xftg->metrics.width;
height = xftg->metrics.height;
@@ -650,20 +833,29 @@
m = *mask++;
if (m == 0xff)
{
- if (srca == 0xff)
- d = src;
+ if (src_a == 0xff)
+ *dst = src;
else
{
- d = *dst;
- d = fbOver24 (src, cvt0555to8888(d));
+ XftDeclare3(tmpdst);
+ XftDeclare3(scratch1);
+
+ cvt0555toGamma12(tmpdst, *dst);
+ XftOver3U(dst, src, tmpdst, src_a, scratch1);
+ *dst = cvtGamma12to0555(dst);
}
- *dst = cvt8888to0555(d);
}
else if (m)
{
- d = *dst;
- d = fbOver24 (fbIn(src,m), cvt0555to8888(d));
- *dst = cvt8888to0555(d);
+ XftDeclare3(tmpdst);
+ XftDeclare4(tmpsrc);
+ XftDeclare4(scratch1);
+ XftDeclare3(scratch2);
+
+ cvt0555toGamma12(tmpdst, *dst);
+ XftIn4U(tmpsrc, src, m, scratch1);
+ XftOver3U(dst, tmpsrc, tmpdst, tmpsrc_a, scratch2);
+ *dst = cvtGamma12to0555(dst);
}
dst++;
}
@@ -677,22 +869,22 @@
int y,
XftColor *color)
{
- CARD32 src, srca;
+ XftDeclare4(src);
+ XftDeclare3(dst);
int r_shift, r_len;
int g_shift, g_len;
int b_shift, b_len;
CARD8 *maskLine, *mask, m;
int maskStride;
- CARD32 d;
unsigned long pixel;
int width, height;
int w, tx;
- srca = color->color.alpha >> 8;
- src = (srca << 24 |
- (color->color.red & 0xff00) << 8 |
- (color->color.green & 0xff00) |
- (color->color.blue) >> 8);
+ gammaTablePrepare();
+
+ src_a = color->color.alpha >> 8;
+ cvtColorToGamma12 (src, color);
+
x -= xftg->metrics.x;
y -= xftg->metrics.y;
width = xftg->metrics.width;
@@ -716,31 +908,42 @@
m = *mask++;
if (m == 0xff)
{
- if (srca == 0xff)
- d = src;
+ if (src_a == 0xff)
+ XftAssign3(dst,src);
else
{
+ XftDeclare3(tmpdst);
+ XftDeclare3(scratch1);
+
pixel = XGetPixel (image, tx, y);
- d = (_XftGetField (pixel, r_shift, r_len) << 16 |
- _XftGetField (pixel, g_shift, g_len) << 8 |
- _XftGetField (pixel, b_shift, b_len));
- d = fbOver24 (src, d);
+ XftAssignRGB(tmpdst,
+ gammaTable8[_XftGetField (pixel, r_shift, r_len)],
+ gammaTable8[_XftGetField (pixel, g_shift, g_len)],
+ gammaTable8[_XftGetField (pixel, b_shift, b_len)]);
+ XftOver3U(dst, src, tmpdst, src_a, scratch1);
}
- pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
- _XftPutField ((d >> 8) & 0xff, g_shift, g_len) |
- _XftPutField ((d ) & 0xff, b_shift, b_len));
+ pixel = (_XftPutField (gammaTableInv[dst_r], r_shift, r_len) |
+ _XftPutField (gammaTableInv[dst_g], g_shift, g_len) |
+ _XftPutField (gammaTableInv[dst_b], b_shift, b_len));
XPutPixel (image, tx, y, pixel);
}
else if (m)
{
+ XftDeclare3(tmpdst);
+ XftDeclare4(tmpsrc);
+ XftDeclare4(scratch1);
+ XftDeclare3(scratch2);
+
pixel = XGetPixel (image, tx, y);
- d = (_XftGetField (pixel, r_shift, r_len) << 16 |
- _XftGetField (pixel, g_shift, g_len) << 8 |
- _XftGetField (pixel, b_shift, b_len));
- d = fbOver24 (fbIn(src,m), d);
- pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
- _XftPutField ((d >> 8) & 0xff, g_shift, g_len) |
- _XftPutField ((d ) & 0xff, b_shift, b_len));
+ XftAssignRGB(tmpdst,
+ gammaTable8[_XftGetField (pixel, r_shift, r_len)],
+ gammaTable8[_XftGetField (pixel, g_shift, g_len)],
+ gammaTable8[_XftGetField (pixel, b_shift, b_len)]);
+ XftIn4U(tmpsrc, src, m, scratch1);
+ XftOver3U(dst, tmpsrc, tmpdst, tmpsrc_a, scratch2);
+ pixel = (_XftPutField (gammaTableInv[dst_r], r_shift, r_len) |
+ _XftPutField (gammaTableInv[dst_g], g_shift, g_len) |
+ _XftPutField (gammaTableInv[dst_b], b_shift, b_len));
XPutPixel (image, tx, y, pixel);
}
tx++;
@@ -756,21 +959,22 @@
int y,
XftColor *color)
{
- CARD32 src, srca;
+ XftDeclare3(src);
+ XftDeclare3(dst);
+ CARD32 src_a;
int r_shift, r_len;
int g_shift, g_len;
int b_shift, b_len;
CARD32 *mask, ma;
- CARD32 d;
unsigned long pixel;
int width, height;
int w, tx;
- srca = color->color.alpha >> 8;
- src = (srca << 24 |
- (color->color.red & 0xff00) << 8 |
- (color->color.green & 0xff00) |
- (color->color.blue) >> 8);
+ gammaTablePrepare();
+
+ src_a = color->color.alpha >> 8;
+ cvtColorToGamma12(src, color);
+
x -= xftg->metrics.x;
y -= xftg->metrics.y;
width = xftg->metrics.width;
@@ -791,45 +995,45 @@
ma = *mask++;
if (ma == 0xffffffff)
{
- if (srca == 0xff)
- d = src;
+ if (src_a == 0xff)
+ XftAssign3(dst,src);
else
{
+ XftDeclare3(tmpdst);
+ XftDeclare3(scratch1);
+
pixel = XGetPixel (image, tx, y);
- d = (_XftGetField (pixel, r_shift, r_len) << 16 |
- _XftGetField (pixel, g_shift, g_len) << 8 |
- _XftGetField (pixel, b_shift, b_len));
- d = fbOver24 (src, d);
+ XftAssignRGB(tmpdst,
+ gammaTable8[_XftGetField (pixel, r_shift, r_len)],
+ gammaTable8[_XftGetField (pixel, g_shift, g_len)],
+ gammaTable8[_XftGetField (pixel, b_shift, b_len)]);
+ XftOver3U(dst, src, tmpdst, src_a, scratch1);
}
- pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
- _XftPutField ((d >> 8) & 0xff, g_shift, g_len) |
- _XftPutField ((d ) & 0xff, b_shift, b_len));
+ pixel = (_XftPutField (gammaTableInv[dst_r], r_shift, r_len) |
+ _XftPutField (gammaTableInv[dst_g], g_shift, g_len) |
+ _XftPutField (gammaTableInv[dst_b], b_shift, b_len));
XPutPixel (image, tx, y, pixel);
}
else if (ma)
{
- CARD32 m,n,o;
+ XftDeclare3(tmpdst);
+ XftDeclare3(tmpsrc);
+ XftDeclare3(tmpa);
+ XftDeclare3(scratch1);
+ XftDeclare3(scratch2);
+ XftDeclare3(scratch3);
+
pixel = XGetPixel (image, tx, y);
- d = (_XftGetField (pixel, r_shift, r_len) << 16 |
- _XftGetField (pixel, g_shift, g_len) << 8 |
- _XftGetField (pixel, b_shift, b_len));
-#define XftInOverC(src,srca,msk,dst,i,result) { \
- CARD16 __a = XftGet8(msk,i); \
- CARD32 __t, __ta; \
- CARD32 __i; \
- __t = XftIntMult (XftGet8(src,i), __a,__i); \
- __ta = (CARD8) ~XftIntMult (srca, __a,__i); \
- __t = __t + XftIntMult(XftGet8(dst,i),__ta,__i); \
- __t = (CARD32) (CARD8) (__t | (-(__t >> 8))); \
- result = __t << (i); \
-}
- XftInOverC(src,srca,ma,d,0,m);
- XftInOverC(src,srca,ma,d,8,n);
- XftInOverC(src,srca,ma,d,16,o);
- d = m | n | o;
- pixel = (_XftPutField ((d >> 16) & 0xff, r_shift, r_len) |
- _XftPutField ((d >> 8) & 0xff, g_shift, g_len) |
- _XftPutField ((d ) & 0xff, b_shift, b_len));
+ XftAssignRGB(tmpdst,
+ gammaTable8[_XftGetField (pixel, r_shift, r_len)],
+ gammaTable8[_XftGetField (pixel, g_shift, g_len)],
+ gammaTable8[_XftGetField (pixel, b_shift, b_len)]);
+ XftIn3C(tmpsrc, tmpa, src, src_a, ma, scratch1, scratch2);
+ XftOver3C(dst, tmpsrc, tmpdst, tmpa, scratch3);
+
+ pixel = (_XftPutField (gammaTableInv[dst_r], r_shift, r_len) |
+ _XftPutField (gammaTableInv[dst_g], g_shift, g_len) |
+ _XftPutField (gammaTableInv[dst_b], b_shift, b_len));
XPutPixel (image, tx, y, pixel);
}
tx++;