diff -rupN cairo-9999.new/src/cairo-ft-font.c cairo-9999/src/cairo-ft-font.c
--- cairo-9999.new/src/cairo-ft-font.c 2010-08-06 21:51:21.603000022 +0300
+++ cairo-9999/src/cairo-ft-font.c 2010-08-06 21:52:00.926000031 +0300
@@ -57,6 +57,8 @@
#include FT_SYNTHESIS_H
#endif
+#define FIR_FILTER 1
+
#if HAVE_FT_LIBRARY_SETLCDFILTER
#include FT_LCD_FILTER_H
#endif
@@ -607,6 +609,8 @@ _cairo_ft_unscaled_font_destroy (void *a
_cairo_ft_unscaled_font_fini (unscaled);
}
+static const int fir_filter[5] = { 0x1C, 0x38, 0x55, 0x38, 0x1C };
+
static cairo_bool_t
_has_unlocked_face (const void *entry)
{
@@ -1114,6 +1118,7 @@ _get_bitmap_surface (FT_Bitmap *bi
unsigned char *data;
int format = CAIRO_FORMAT_A8;
cairo_image_surface_t *image;
+ cairo_bool_t subpixel = FALSE;
width = bitmap->width;
height = bitmap->rows;
@@ -1183,7 +1188,220 @@ _get_bitmap_surface (FT_Bitmap *bi
}
format = CAIRO_FORMAT_A8;
- } else {
+ } else
+#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 */
+ {
/* if we get there, the data from the source bitmap
* really comes from _fill_xrender_bitmap, and is
* made of 32-bit ARGB or ABGR values */
@@ -1194,6 +1412,7 @@ _get_bitmap_surface (FT_Bitmap *bi
stride = bitmap->pitch;
format = CAIRO_FORMAT_ARGB32;
}
+#endif /* !FIR_FILTER */
break;
case FT_PIXEL_MODE_GRAY2:
case FT_PIXEL_MODE_GRAY4:
@@ -1244,59 +1463,16 @@ _render_glyph_outline (FT_Face
cairo_font_options_t *font_options,
cairo_image_surface_t **surface)
{
- int rgba = FC_RGBA_UNKNOWN;
- int lcd_filter = FT_LCD_FILTER_LEGACY;
- FT_GlyphSlot glyphslot = face->glyph;
+ FT_GlyphSlot glyphslot = face->glyph;
FT_Outline *outline = &glyphslot->outline;
FT_Bitmap bitmap;
FT_BBox cbox;
- unsigned int width, height;
+ FT_Matrix matrix;
+ int hmul = 1;
+ int vmul = 1;
+ unsigned int width, height, stride;
+ cairo_bool_t subpixel = FALSE;
cairo_status_t status;
- FT_Error fterror;
- FT_Library library = glyphslot->library;
- FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL;
-
- switch (font_options->antialias) {
- case CAIRO_ANTIALIAS_NONE:
- render_mode = FT_RENDER_MODE_MONO;
- break;
-
- case CAIRO_ANTIALIAS_SUBPIXEL:
- switch (font_options->subpixel_order) {
- case CAIRO_SUBPIXEL_ORDER_DEFAULT:
- case CAIRO_SUBPIXEL_ORDER_RGB:
- case CAIRO_SUBPIXEL_ORDER_BGR:
- render_mode = FT_RENDER_MODE_LCD;
- break;
-
- case CAIRO_SUBPIXEL_ORDER_VRGB:
- case CAIRO_SUBPIXEL_ORDER_VBGR:
- render_mode = FT_RENDER_MODE_LCD_V;
- break;
- }
-
- switch (font_options->lcd_filter) {
- case CAIRO_LCD_FILTER_NONE:
- lcd_filter = FT_LCD_FILTER_NONE;
- break;
- case CAIRO_LCD_FILTER_DEFAULT:
- case CAIRO_LCD_FILTER_INTRA_PIXEL:
- lcd_filter = FT_LCD_FILTER_LEGACY;
- break;
- case CAIRO_LCD_FILTER_FIR3:
- lcd_filter = FT_LCD_FILTER_LIGHT;
- break;
- case CAIRO_LCD_FILTER_FIR5:
- lcd_filter = FT_LCD_FILTER_DEFAULT;
- break;
- }
-
- break;
-
- case CAIRO_ANTIALIAS_DEFAULT:
- case CAIRO_ANTIALIAS_GRAY:
- render_mode = FT_RENDER_MODE_NORMAL;
- }
FT_Outline_Get_CBox (outline, &cbox);
@@ -1307,21 +1483,20 @@ _render_glyph_outline (FT_Face
width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6);
height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6);
+ stride = (width * hmul + 3) & ~3;
if (width * height == 0) {
cairo_format_t format;
/* Looks like fb handles zero-sized images just fine */
- switch (render_mode) {
- case FT_RENDER_MODE_MONO:
+ switch (font_options->antialias) {
+ case CAIRO_ANTIALIAS_NONE:
format = CAIRO_FORMAT_A1;
break;
- case FT_RENDER_MODE_LCD:
- case FT_RENDER_MODE_LCD_V:
+ case CAIRO_ANTIALIAS_SUBPIXEL:
format= CAIRO_FORMAT_ARGB32;
break;
- case FT_RENDER_MODE_LIGHT:
- case FT_RENDER_MODE_NORMAL:
- case FT_RENDER_MODE_MAX:
+ case CAIRO_ANTIALIAS_DEFAULT:
+ case CAIRO_ANTIALIAS_GRAY:
default:
format = CAIRO_FORMAT_A8;
break;
@@ -1331,75 +1506,86 @@ _render_glyph_outline (FT_Face
cairo_image_surface_create_for_data (NULL, format, 0, 0, 0);
if ((*surface)->base.status)
return (*surface)->base.status;
- } else {
+ } else {
- int bitmap_size;
+ matrix.xx = matrix.yy = 0x10000L;
+ matrix.xy = matrix.yx = 0;
- switch (render_mode) {
- case FT_RENDER_MODE_LCD:
- if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_BGR) {
- rgba = FC_RGBA_BGR;
- } else {
- rgba = FC_RGBA_RGB;
- }
- case FT_RENDER_MODE_LCD_V:
- if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_VBGR) {
- rgba = FC_RGBA_VBGR;
- } else {
- rgba = FC_RGBA_VRGB;
- }
- break;
- case FT_RENDER_MODE_MONO:
- case FT_RENDER_MODE_LIGHT:
- case FT_RENDER_MODE_NORMAL:
- case FT_RENDER_MODE_MAX:
- default:
+ switch (font_options->antialias) {
+ case CAIRO_ANTIALIAS_NONE:
+ bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
+ bitmap.num_grays = 1;
+ stride = ((width + 31) & -32) >> 3;
+ break;
+ case CAIRO_ANTIALIAS_DEFAULT:
+ case CAIRO_ANTIALIAS_GRAY:
+ bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
+ bitmap.num_grays = 256;
+ stride = (width + 3) & -4;
break;
- }
-
-#if HAVE_FT_LIBRARY_SETLCDFILTER
- FT_Library_SetLcdFilter (library, lcd_filter);
+ case CAIRO_ANTIALIAS_SUBPIXEL:
+ switch (font_options->subpixel_order) {
+ case CAIRO_SUBPIXEL_ORDER_RGB:
+ case CAIRO_SUBPIXEL_ORDER_BGR:
+ case CAIRO_SUBPIXEL_ORDER_DEFAULT:
+ default:
+ matrix.xx *= 3;
+ hmul = 3;
+ subpixel = TRUE;
+#ifdef FIR_FILTER
+ cbox.xMin -= 64;
+ cbox.xMax += 64;
+ width += 2;
#endif
-
- fterror = FT_Render_Glyph (face->glyph, render_mode);
-
-#if HAVE_FT_LIBRARY_SETLCDFILTER
- FT_Library_SetLcdFilter (library, FT_LCD_FILTER_NONE);
+ 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);
- if (fterror != 0)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
+ bitmap.num_grays = 256;
+ stride = (width * hmul + 3) & -4;
+ }
- bitmap_size = _compute_xrender_bitmap_size (&bitmap,
- face->glyph,
- render_mode);
- if (bitmap_size < 0)
+ bitmap.pitch = stride;
+ bitmap.width = width * hmul;
+ bitmap.rows = height * vmul;
+ bitmap.buffer = calloc (stride, bitmap.rows);
+ if (bitmap.buffer == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- bitmap.buffer = calloc (1, bitmap_size);
- if (bitmap.buffer == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul);
- _fill_xrender_bitmap (&bitmap, face->glyph, render_mode,
- (rgba == FC_RGBA_BGR || rgba == FC_RGBA_VBGR));
+ if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
+ free (bitmap.buffer);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
- /* Note:
- * _get_bitmap_surface will free bitmap.buffer if there is an error
- */
status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface);
- if (unlikely (status))
+ if (status)
return status;
-
- /* Note: the font's coordinate system is upside down from ours, so the
- * Y coordinate of the control box needs to be negated. Moreover, device
- * offsets are position of glyph origin relative to top left while xMin
- * and yMax are offsets of top left relative to origin. Another negation.
- */
- cairo_surface_set_device_offset (&(*surface)->base,
- (double)-glyphslot->bitmap_left,
- (double)+glyphslot->bitmap_top);
}
+ /*
+ * Note: the font's coordinate system is upside down from ours, so the
+ * Y coordinate of the control box needs to be negated. Moreover, device
+ * offsets are position of glyph origin relative to top left while xMin
+ * and yMax are offsets of top left relative to origin. Another negation.
+ */
+ cairo_surface_set_device_offset (&(*surface)->base,
+ floor (-(double) cbox.xMin / 64.0),
+ floor (+(double) cbox.yMax / 64.0));
+
return CAIRO_STATUS_SUCCESS;
}