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