summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Turner <david@freetype.org>2006-11-10 16:49:42 +0000
committerDavid Turner <david@freetype.org>2006-11-10 16:49:42 +0000
commit8765c71b41625406fe87598645d842ca8451983c (patch)
tree983bd5c33ab890c7b737257e06c906ec93ff3573
parent49c77a87c37702cf3bbc0a2c1c10f2ff01b181f1 (diff)
downloadfreetype2-8765c71b41625406fe87598645d842ca8451983c.tar.gz
* include/freetype/ftlcdfil.h, include/internal/ftobjs.h,
src/base/ftlcdfilt.c, src/smooth/ftsmooth.c: API change for the LCD filter, the FT_LcdFilter value is a enum describing which filter to apply, new values FT_LCD_FILTER_LIGHT and FT_LCD_FILTER_LEGACY (the latter implements the LibXft original algorithm which produces incredible color fringes for everything except very-well hinted text) * src/autofit/aflatin.c: various tiny improvements that drastically improve the handling of serif fonts and of LCD/LCD_V hinting modes.
-rw-r--r--ChangeLog13
-rw-r--r--README2
-rw-r--r--include/freetype/ftlcdfil.h75
-rw-r--r--include/freetype/internal/ftobjs.h9
-rw-r--r--src/autofit/aflatin.c23
-rw-r--r--src/base/ftlcdfil.c166
-rw-r--r--src/smooth/ftsmooth.c45
7 files changed, 254 insertions, 79 deletions
diff --git a/ChangeLog b/ChangeLog
index b9e0b53f2..d20995580 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2006-11-10 David Turner <david@freetype.org>
+
+ * include/freetype/ftlcdfil.h, include/internal/ftobjs.h,
+ src/base/ftlcdfilt.c, src/smooth/ftsmooth.c: API change for
+ the LCD filter, the FT_LcdFilter value is a enum describing
+ which filter to apply, new values FT_LCD_FILTER_LIGHT and
+ FT_LCD_FILTER_LEGACY (the latter implements the LibXft original
+ algorithm which produces incredible color fringes for everything
+ except very-well hinted text)
+
+ * src/autofit/aflatin.c: various tiny improvements that drastically
+ improve the handling of serif fonts and of LCD/LCD_V hinting modes.
+
2006-11-09 David Turner <david@freetype.org>
* src/pshinter/pshalgo.c (psh_glyph_compute_inflections): Fix
diff --git a/README b/README
index 0116c3da9..99750988c 100644
--- a/README
+++ b/README
@@ -51,7 +51,7 @@
----------------------------------------------------------------------
-Copyright 2001, 2002, 2003, 2004, 2006 by
+Copyright 2001-2006 by
David Turner, Robert Wilhelm, and Werner Lemberg.
This file is part of the FreeType project, and may only be used,
diff --git a/include/freetype/ftlcdfil.h b/include/freetype/ftlcdfil.h
index 5882921e6..132c8d019 100644
--- a/include/freetype/ftlcdfil.h
+++ b/include/freetype/ftlcdfil.h
@@ -27,6 +27,51 @@
FT_BEGIN_HEADER
+ /****************************************************************************
+ *
+ * @func:
+ * FT_LcdFilter
+ *
+ * @description:
+ * a list of values used to identify various types of LCD filters
+ *
+ * @values:
+ * FT_LCD_FILTER_NONE :: value 0 means do not perform filtering. when
+ * used with subpixel rendering, this will result in sometimes severe
+ * color fringes
+ *
+ * FT_LCD_FILTER_DEFAULT ::
+ * the default filter reduces color fringes considerably, at the cost of
+ * a slight bluriness in the output
+ *
+ * FT_LCD_FILTER_LIGHT ::
+ * the light filter is a variant that produces less bluriness
+ * at the cost of slightly more color fringes than the default one. It
+ * might be better than the default one, depending on your monitor and
+ * personal vision.
+ *
+ * FT_LCD_FILTER_LEGACY ::
+ * this filter corresponds to the original libXft color filter, this
+ * provides high contrast output, but can exhibit really bad color fringes
+ * if your glyphs are not extremely well hinted to the pixel grid. In
+ * other words, it only works well when enabling the TrueType bytecode
+ * interpreter *and* using high-quality hinted fonts. It will suck for
+ * all other cases.
+ *
+ * this filter is only provided for comparison purposes, and might be
+ * disabled/unsupported in the future...
+ */
+ typedef enum
+ {
+ FT_LCD_FILTER_NONE = 0,
+ FT_LCD_FILTER_DEFAULT = 1,
+ FT_LCD_FILTER_LIGHT = 2,
+ FT_LCD_FILTER_LEGACY = 16,
+
+ FT_LCD_FILTER_MAX /* do not remove */
+
+ } FT_LcdFilter;
+
/**************************************************************************
*
@@ -85,34 +130,8 @@ FT_BEGIN_HEADER
*
*/
FT_EXPORT( FT_Error )
- FT_Library_SetLcdFilter( FT_Library library,
- const FT_Byte* filter_weights );
-
-
-
- /**************************************************************************
- *
- * @enum:
- * FT_LCD_FILTER_XXX
- *
- * @description:
- * A list of constants which correspond to useful lcd filter settings
- * for the @FT_Library_SetLcdFilter function.
- *
- * @values:
- * FT_LCD_FILTER_NONE ::
- * The value NULL is reserved to indicate that LCD color filtering
- * should be disabled.
- *
- * FT_LCD_FILTER_DEFAULT ::
- * This value is reserved to indicate a default FIR filter that should
- * work well on most LCD screen. It corresponds to the array 0x10,
- * 0x40, 0x70, 0x40, 0x10.
- *
- */
-#define FT_LCD_FILTER_NONE ( (const FT_Byte*)NULL )
-
-#define FT_LCD_FILTER_DEFAULT ( (const FT_Byte*)(void*)(ft_ptrdiff_t)1 )
+ FT_Library_SetLcdFilter( FT_Library library,
+ FT_LcdFilter filter );
/* */
diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h
index f57f0ac25..2f497582c 100644
--- a/include/freetype/internal/ftobjs.h
+++ b/include/freetype/internal/ftobjs.h
@@ -29,6 +29,7 @@
#include <ft2build.h>
#include FT_RENDER_H
#include FT_SIZES_H
+#include FT_LCD_FILTER_H
#include FT_INTERNAL_MEMORY_H
#include FT_INTERNAL_GLYPH_LOADER_H
#include FT_INTERNAL_DRIVER_H
@@ -637,7 +638,7 @@ FT_BEGIN_HEADER
typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap,
FT_Render_Mode render_mode,
- FT_Byte* weights );
+ FT_Library library );
/*************************************************************************/
@@ -714,8 +715,10 @@ FT_BEGIN_HEADER
FT_DebugHook_Func debug_hooks[4];
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
- FT_Byte lcd_filter_weights[5];
- FT_Bitmap_LcdFilterFunc lcd_filter;
+ FT_LcdFilter lcd_filter;
+ FT_Int lcd_extra; /* number of extra pixels */
+ FT_Byte lcd_weights[7]; /* filter weights, if any */
+ FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */
#endif
} FT_LibraryRec;
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index bb333ba03..a8107356a 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -965,7 +965,7 @@
* to avoid many problems with serif fonts. We compute the
* corresponding threshold in font units.
*/
- if ( dim == AF_DIMENSION_VERT )
+ if ( dim == AF_DIMENSION_HORZ )
segment_length_threshold = FT_DivFix( 64, hints->y_scale );
else
segment_length_threshold = 0;
@@ -1536,6 +1536,7 @@
else
{
/* strong hinting process: snap the stem width to integer pixels */
+ FT_Pos org_dist = dist;
dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
@@ -1571,7 +1572,27 @@
dist = ( dist + 64 ) >> 1;
else if ( dist < 128 )
+ {
+ /* ok, we're only going to round to an integer width if
+ * the corresponding distorsion is less than 1/4 pixel
+ * otherwise, this really screws everything, since the
+ * diagonals, which are not hinted, will appear a lot
+ * more bolder or thinner than the vertical stems
+ */
+ FT_Int delta;
+
dist = ( dist + 22 ) & ~63;
+ delta = dist - org_dist;
+ if ( delta < 0 )
+ delta = -delta;
+
+ if (delta >= 16)
+ {
+ dist = org_dist;
+ if ( dist < 48 )
+ dist = (dist + 64) >> 1;
+ }
+ }
else
/* round otherwise to prevent color fringes in LCD mode */
dist = ( dist + 32 ) & ~63;
diff --git a/src/base/ftlcdfil.c b/src/base/ftlcdfil.c
index 1aa7a6c83..4529cf212 100644
--- a/src/base/ftlcdfil.c
+++ b/src/base/ftlcdfil.c
@@ -24,14 +24,17 @@
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
- /* The smooth rasterizer invokes this function. */
+#define USE_LEGACY
+
+ /* FIR filter used by the default and light filters */
static void
- _ft_lcd_filter( FT_Bitmap* bitmap,
- FT_Render_Mode mode,
- FT_Byte* weights )
+ _ft_lcd_filter_fir( FT_Bitmap* bitmap,
+ FT_Render_Mode mode,
+ FT_Library library )
{
- FT_UInt width = (FT_UInt)bitmap->width;
- FT_UInt height = (FT_UInt)bitmap->rows;
+ FT_Byte* weights = library->lcd_weights;
+ FT_UInt width = (FT_UInt)bitmap->width;
+ FT_UInt height = (FT_UInt)bitmap->rows;
/* horizontal in-place FIR filter */
@@ -155,39 +158,160 @@
}
+#ifdef USE_LEGACY
+ /* FIR filter used by the default and light filters */
+ static void
+ _ft_lcd_filter_legacy( FT_Bitmap* bitmap,
+ FT_Render_Mode mode,
+ FT_Library library )
+ {
+ FT_UInt width = (FT_UInt)bitmap->width;
+ FT_UInt height = (FT_UInt)bitmap->rows;
+ FT_Int pitch = bitmap->pitch;
+
+ static const int filters[3][3] =
+ {
+ { 65538*9/13, 65538*1/6, 65538*1/13 },
+ { 65538*3/13, 65538*4/6, 65538*3/13 },
+ { 65538*1/13, 65538*1/6, 65538*9/13 }
+ };
+
+ FT_UNUSED(library);
+
+ /* horizontal in-place FIR filter */
+ if ( mode == FT_RENDER_MODE_LCD && width >= 3 )
+ {
+ FT_Byte* line = bitmap->buffer;
+
+
+ for ( ; height > 0; height--, line += pitch )
+ {
+ FT_UInt xx;
+
+ for ( xx = 0; xx < width; xx += 3 )
+ {
+ FT_UInt r = 0;
+ FT_UInt g = 0;
+ FT_UInt b = 0;
+ FT_UInt p;
+
+ p = line[xx];
+ r += filters[0][0]*p;
+ g += filters[0][1]*p;
+ b += filters[0][2]*p;
+
+ p = line[xx+1];
+ r += filters[1][0]*p;
+ g += filters[1][1]*p;
+ b += filters[1][2]*p;
+
+ p = line[xx+2];
+ r += filters[2][0]*p;
+ g += filters[2][1]*p;
+ b += filters[2][2]*p;
+
+ line[xx] = (FT_Byte)( r / 65536 );
+ line[xx+1] = (FT_Byte)( g / 65536 );
+ line[xx+2] = (FT_Byte)( b / 65536 );
+ }
+ }
+ }
+ else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 )
+ {
+ FT_Byte* column = bitmap->buffer;
+
+ for ( ; width > 0; width--, column++ )
+ {
+ FT_Byte* col = column;
+ FT_Byte* col_end = col + height*pitch;
+
+ for ( ; col < col_end; col += 3*pitch )
+ {
+ FT_UInt r = 0;
+ FT_UInt g = 0;
+ FT_UInt b = 0;
+ FT_UInt p;
+
+ p = col[0];
+ r += filters[0][0]*p;
+ g += filters[0][1]*p;
+ b += filters[0][2]*p;
+
+ p = col[pitch];
+ r += filters[1][0]*p;
+ g += filters[1][1]*p;
+ b += filters[1][2]*p;
+
+ p = col[pitch*2];
+ r += filters[2][0]*p;
+ g += filters[2][1]*p;
+ b += filters[2][2]*p;
+
+ col[0] = (FT_Byte)( r / 65536 );
+ col[pitch] = (FT_Byte)( g / 65536 );
+ col[2*pitch] = (FT_Byte)( b / 65536 );
+ }
+ }
+ }
+ }
+#endif /* USE_LEGACY */
+
FT_EXPORT( FT_Error )
- FT_Library_SetLcdFilter( FT_Library library,
- const FT_Byte* filter_weights )
+ FT_Library_SetLcdFilter( FT_Library library,
+ FT_LcdFilter filter )
{
+ static const FT_Byte light_filter[5] = { 0, 85, 86, 85, 0 };
static const FT_Byte default_filter[5] = { 0x10, 0x40, 0x70, 0x40, 0x10 };
-
if ( library == NULL )
return FT_Err_Invalid_Argument;
- if ( filter_weights == FT_LCD_FILTER_NONE )
+ switch ( filter )
{
- library->lcd_filter = NULL;
- return 0;
+ case FT_LCD_FILTER_NONE:
+ library->lcd_filter_func = NULL;
+ library->lcd_extra = 0;
+ break;
+
+ case FT_LCD_FILTER_DEFAULT:
+#if 0 /* DEBUGGING */
+ library->lcd_filter_func = _ft_lcd_filter_legacy;
+ library->lcd_extra = 0;
+#else
+ memcpy( library->lcd_weights, default_filter, 5 );
+ library->lcd_filter_func = _ft_lcd_filter_fir;
+ library->lcd_extra = 2;
+#endif
+ break;
+
+ case FT_LCD_FILTER_LIGHT:
+ memcpy( library->lcd_weights, light_filter, 5 );
+ library->lcd_filter_func = _ft_lcd_filter_fir;
+ library->lcd_extra = 2;
+ break;
+
+#ifdef USE_LEGACY
+ case FT_LCD_FILTER_LEGACY:
+ library->lcd_filter_func = _ft_lcd_filter_legacy;
+ library->lcd_extra = 0;
+ break;
+#endif
+ default:
+ return FT_Err_Invalid_Argument;
}
- if ( filter_weights == FT_LCD_FILTER_DEFAULT )
- filter_weights = default_filter;
-
- memcpy( library->lcd_filter_weights, filter_weights, 5 );
- library->lcd_filter = _ft_lcd_filter;
-
+ library->lcd_filter = filter;
return 0;
}
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
FT_EXPORT( FT_Error )
- FT_Library_SetLcdFilter( FT_Library library,
- const FT_Byte* filter_weights )
+ FT_Library_SetLcdFilter( FT_Library library,
+ FT_LcdFilter filter )
{
FT_UNUSED( library );
- FT_UNUSED( filter_weights );
+ FT_UNUSED( filter );
return FT_Err_Unimplemented_Feature;
}
diff --git a/src/smooth/ftsmooth.c b/src/smooth/ftsmooth.c
index ad19645a1..c7e4c7a4b 100644
--- a/src/smooth/ftsmooth.c
+++ b/src/smooth/ftsmooth.c
@@ -171,20 +171,22 @@
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
- if ( slot->library->lcd_filter )
+ if ( slot->library->lcd_filter_func )
{
+ FT_Int extra = slot->library->lcd_extra;
+
if ( hmul )
{
- x_shift -= 64;
- width += 6;
+ x_shift -= 64*(extra >> 1);
+ width += 3*extra;
pitch = FT_PAD_CEIL( width, 4 );
- x_left -= 1;
+ x_left -= (extra >> 1);
}
if ( vmul )
{
- y_shift -= 64;
- height += 6;
- y_top += 1;
+ y_shift -= 64*(extra >> 1);
+ height += 3*extra;
+ y_top += (extra >> 1);
}
}
@@ -213,20 +215,17 @@
/* implode outline if needed */
{
- FT_Int n;
+ FT_Vector* points = outline->points;
+ FT_Vector* points_end = points + outline->n_points;
FT_Vector* vec;
if ( hmul )
- for ( vec = outline->points, n = 0;
- n < outline->n_points;
- n++, vec++ )
+ for ( vec = points; vec < points_end; vec++ )
vec->x *= 3;
if ( vmul )
- for ( vec = outline->points, n = 0;
- n < outline->n_points;
- n++, vec++ )
+ for ( vec = points; vec < points_end; vec++ )
vec->y *= 3;
}
@@ -235,26 +234,22 @@
/* deflate outline if needed */
{
- FT_Int n;
+ FT_Vector* points = outline->points;
+ FT_Vector* points_end = points + outline->n_points;
FT_Vector* vec;
if ( hmul )
- for ( vec = outline->points, n = 0;
- n < outline->n_points;
- n++, vec++ )
+ for ( vec = points; vec < points_end; vec++ )
vec->x /= 3;
if ( vmul )
- for ( vec = outline->points, n = 0;
- n < outline->n_points;
- n++, vec++ )
+ for ( vec = points; vec < points_end; vec++ )
vec->y /= 3;
}
- if ( slot->library->lcd_filter )
- slot->library->lcd_filter( bitmap, mode,
- slot->library->lcd_filter_weights );
+ if ( slot->library->lcd_filter_func )
+ slot->library->lcd_filter_func( bitmap, mode, slot->library );
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
@@ -264,7 +259,7 @@
/* expand it horizontally */
if ( hmul )
{
- FT_Byte* line = bitmap->buffer + ( height - height_org ) * pitch;
+ FT_Byte* line = bitmap->buffer;
FT_UInt hh;