Explanation (modified text from an "ubuntuforms" discussion): Earlier this year [2006,] FreeType developer David Turner posted some patches for Cairo and Xft that improved the rendering of fonts on LCD screens (and also CRTs with Trinitron layout). These were put up with the proviso that he was unsure whether they would infringe patented algorithms around Microsoft's ClearType technology. David has taken his site down, but Jinghua Luo has worked on updating the patches so they apply to the Cairo and Xft versions in [Ubuntu] Edgy (or the Cairo that is in the unofficial XGL repos). There are two different flavors of patches: 1. The older set that pat- ches the filtering in Xft and Cairo to have less fringing and more faithful letter outlines, and 2. a newer one by David Turner that moves filtering into FreeType and improves letter contrast. The 2nd set has been commited to FreeType CVS. The patches for set 1 are on Jinghua Luo's server: for Cairo > 1.2: http://www.magiclinux.org/people/sunmoon1997/patches/cairo/git/\ 0001-freetype-Add-fir-filter-for-subpixel-text-rendering-enabled-\ by-default.txt for libXft 2.1.10: http://www.magiclinux.org/people/sunmoon1997/patches/libXft/\ libXft-2.1.10-lcd-cleartype.diff The second set can be found at David Turner's Freetype page: http://david.freetype.org/lcd/ and Freetype CVS. Source for explanation: http://www.ubuntuforums.org/showthread.php?t=235526 This is a copy of the 1st of the "cairo" patches mentioned above, i.e., Jinghua Luo's version. This version is dated June 22, 2006. It appears to be compatible at the source level with "cairo" 1.2.6. Addi- tionally, it's compatible with David Turner's "cairo" performance patch. However, it's _not_ compatible with Mr. Turner's alternate "cairo" LCD patch. You can use one, and only one, of the two LCD pat- ches. This file was obtained originally from: http://www.magiclinux.org/people/sunmoon1997/patches/cairo/git/\ 0001-freetype-Add-fir-filter-for-subpixel-text-rendering-enabled-\ by-default.txt The contents are unchanged except for these comments. ====================================================================== From nobody Mon Sep 17 00:00:00 2001 From: Jinghua Luo Date: Thu Jun 22 20:15:48 2006 +0800 Subject: [PATCH] freetype: Add fir filter for subpixel text rendering(enabled by default). --- src/cairo-ft-font.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 229 insertions(+), 1 deletions(-) 6b0dcf35096721bd1b6f7068c60fa51f8c39c1d8 diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 9db46d2..cd92182 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -52,6 +52,8 @@ #if HAVE_FT_GLYPHSLOT_EMBOLDEN #include FT_SYNTHESIS_H #endif +#define FIR_FILTER 1 + #define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0)) #define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) #define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) @@ -490,6 +492,8 @@ _cairo_ft_unscaled_font_destroy (void *a } } +static const int fir_filter[5] = { 0x1C, 0x38, 0x55, 0x38, 0x1C }; + static cairo_bool_t _has_unlocked_face (void *entry) { @@ -776,7 +780,220 @@ #endif } format = CAIRO_FORMAT_A8; break; - case CAIRO_ANTIALIAS_SUBPIXEL: { + case CAIRO_ANTIALIAS_SUBPIXEL: +#ifdef FIR_FILTER + { + unsigned char* line; + unsigned char* bufBitmap; + int pitch; + unsigned char *data_rgba; + unsigned int width_rgba, stride_rgba; + int vmul = 1; + int hmul = 1; + + switch (font_options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + case CAIRO_SUBPIXEL_ORDER_BGR: + default: + width /= 3; + hmul = 3; + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + case CAIRO_SUBPIXEL_ORDER_VBGR: + vmul = 3; + height /= 3; + break; + } + /* + * Filter the glyph to soften the color fringes + */ + width_rgba = width; + stride = bitmap->pitch; + stride_rgba = (width_rgba * 4 + 3) & ~3; + data_rgba = calloc (1, stride_rgba * height); + + /* perform in-place FIR filtering in either the horizontal or + * vertical direction. We're going to modify the RGB graymap, + * but that's ok, because we either own it, or its part of + * the FreeType glyph slot, which will not be used anymore. + */ + pitch = bitmap->pitch; + line = (unsigned char*)bitmap->buffer; + if ( pitch < 0 ) + line -= pitch*(height-1); + + bufBitmap = line; + + switch (font_options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + case CAIRO_SUBPIXEL_ORDER_BGR: + { + int h; + + for ( h = height; h > 0; h--, line += pitch ) { + int pix[6] = { 0, 0, 0, 0, 0, 0 }; + unsigned char* p = line; + unsigned char* limit = line + width*3; + int nn, val, val2; + + val = p[0]; + for (nn = 0; nn < 3; nn++) + pix[2 + nn] += val * fir_filter[nn]; + + val = p[1]; + for (nn = 0; nn < 4; nn++) + pix[1 + nn] += val * fir_filter[nn]; + + p += 2; + + for ( ; p < limit; p++ ) { + val = p[0]; + for (nn = 0; nn < 5; nn++) + pix[nn] += val * fir_filter[nn]; + + val2 = pix[0] / 256; + val2 |= -(val2 >> 8); + p[-2] = (unsigned char)val2; + + for (nn = 0; nn < 5; nn++) + pix[nn] = pix[nn + 1]; + } + for (nn = 0; nn < 2; nn++ ) { + val2 = pix[nn] / 256; + val2 |= -(val2 >> 8); + p[nn - 2] = (unsigned char)val2; + } + } + } + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + case CAIRO_SUBPIXEL_ORDER_VBGR: + { + int w; + + for (w = 0; w < width; w++ ) { + int pix[6] = { 0, 0, 0, 0, 0, 0 }; + unsigned char* p = bufBitmap + w; + unsigned char* limit = bufBitmap + w + height*3*pitch; + int nn, val, val2; + + val = p[0]; + for (nn = 0; nn < 3; nn++) + pix[2 + nn] += val*fir_filter[nn]; + + val = p[pitch]; + for (nn = 0; nn < 4; nn++ ) + pix[1 + nn] += val * fir_filter[nn]; + + p += 2*pitch; + for ( ; p < limit; p += pitch ) { + val = p[0]; + for (nn = 0; nn < 5; nn++ ) + pix[nn] += val * fir_filter[nn]; + + val2 = pix[0] / 256; + val2 |= -(val2 >> 8); + p[-2 * pitch] = (unsigned char)val2; + + for (nn = 0; nn < 5; nn++) + pix[nn] = pix[nn+1]; + } + + for (nn = 0; nn < 2; nn++) { + val2 = pix[nn] / 256; + val2 |= -(val2 >> 8); + p[(nn - 2) * pitch] = (unsigned char)val2; + } + } + } + break; + default: /* shouldn't happen */ + break; + } + + /* now copy the resulting graymap into an ARGB32 image */ + { + unsigned char* in_line = bufBitmap; + unsigned char* out_line = data_rgba; + int h = height; + + switch (font_options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + for ( ; h > 0; h--, in_line += pitch, out_line += stride_rgba) { + unsigned char* in = in_line; + int* out = (int*)out_line; + int w; + + for (w = width; w > 0; w--, in += 3, out += 1) { + int r = in[0]; + int g = in[1]; + int b = in[2]; + + out[0] = (g << 24) | (r << 16) | (g << 8) | b; + } + } + break; + case CAIRO_SUBPIXEL_ORDER_BGR: + for ( ; h > 0; h--, in_line += pitch, out_line += stride_rgba) { + unsigned char* in = in_line; + int* out = (int*)out_line; + int w; + + for (w = width; w > 0; w--, in += 3, out += 1) { + int r = in[2]; + int g = in[1]; + int b = in[0]; + + out[0] = (g << 24) | (r << 16) | (g << 8) | b; + } + } + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + for ( ; h > 0; h--, in_line += pitch*3, out_line += stride_rgba) { + unsigned char* in = in_line; + int* out = (int*)out_line; + int w; + + for (w = width; w > 0; w--, in += 1, out += 1) { + int r = in[0]; + int g = in[pitch]; + int b = in[pitch*2]; + + out[0] = (g << 24) | (r << 16) | (g << 8) | b; + } + } + break; + case CAIRO_SUBPIXEL_ORDER_VBGR: + for ( ; h > 0; h--, in_line += pitch*3, out_line += stride_rgba) { + unsigned char* in = in_line; + int* out = (int*)out_line; + int w; + + for (w = width; w > 0; w--, in += 1, out += 1) { + int r = in[2*pitch]; + int g = in[pitch]; + int b = in[0]; + + out[0] = (g << 24) | (r << 16) | (g << 8) | b; + } + } + break; + } + } + + if (own_buffer) + free (bitmap->buffer); + data = data_rgba; + stride = stride_rgba; + format = CAIRO_FORMAT_ARGB32; + subpixel = TRUE; + break; + } +#else /* !FIR_FILTER */ + { int x, y; unsigned char *in_line, *out_line, *in; unsigned int *out; @@ -868,6 +1085,7 @@ #endif subpixel = TRUE; break; } +#endif /* !FIR_FILTER */ } break; case FT_PIXEL_MODE_GRAY2: @@ -982,12 +1200,22 @@ _render_glyph_outline (FT_Face matrix.xx *= 3; hmul = 3; subpixel = TRUE; +#ifdef FIR_FILTER + cbox.xMin -= 64; + cbox.xMax += 64; + width += 2; +#endif break; case CAIRO_SUBPIXEL_ORDER_VRGB: case CAIRO_SUBPIXEL_ORDER_VBGR: matrix.yy *= 3; vmul = 3; subpixel = TRUE; +#ifdef FIR_FILTER + cbox.yMin -= 64; + cbox.yMax += 64; + height += 2; +#endif break; } FT_Outline_Transform (outline, &matrix); -- 1.3.1