Add face property for LCD filter weights.

* include/freetype/ftlcdfil.h (FT_PARAM_TAG_LCD_FILTER_WEIGHTS,
FT_LCD_FILTER_FIVE_TAPS): New macros.
(FT_LcdFiveTapFilter): New typedef.

* include/freetype/ftobjs.h (FT_Face_InternalRec)
[FT_CONFIG_OPTION_SUBPIXEL_RENDERING]: Add `lcd_weights' field.
(FT_Bitmap_LcdFilterFunc): Change third argument to weights array.
(ft_lcd_filter_fir): New prototype.
(FT_LibraryRec): Updated.

* src/base/ftlcdfil.c (_ft_lcd_filter_fir): Renamed to...
(ft_lcd_filter_dir): ... this base function.
Updated.
(_ft_lcd_filter_legacy): Updated.
(FT_Library_SetLcdFilterWeights, FT_Library_SetLcdFilter): Updated.

* src/base/ftobjs.c (ft_open_face_internal): Updated.
(FT_Face_Properties): Handle FT_PARAM_TAG_LCD_FILTER_WEIGHTS.

* src/smooth/ftsmooth.c (ft_smooth_render_generic)
[FT_CONFIG_OPTION_SUBPIXEL_RENDERING: Handle LCD weights from
`FT_Face_Internal'.
This commit is contained in:
Nikolaus Waxweiler 2017-02-16 20:45:45 +01:00 committed by Werner Lemberg
parent 64cdee7348
commit 2e9519885b
7 changed files with 208 additions and 38 deletions

View File

@ -1,3 +1,31 @@
2017-02-16 Nikolaus Waxweiler <madigens@gmail.com>
Werner Lemberg <wl@gnu.org>
Add face property for LCD filter weights.
* include/freetype/ftlcdfil.h (FT_PARAM_TAG_LCD_FILTER_WEIGHTS,
FT_LCD_FILTER_FIVE_TAPS): New macros.
(FT_LcdFiveTapFilter): New typedef.
* include/freetype/ftobjs.h (FT_Face_InternalRec)
[FT_CONFIG_OPTION_SUBPIXEL_RENDERING]: Add `lcd_weights' field.
(FT_Bitmap_LcdFilterFunc): Change third argument to weights array.
(ft_lcd_filter_fir): New prototype.
(FT_LibraryRec): Updated.
* src/base/ftlcdfil.c (_ft_lcd_filter_fir): Renamed to...
(ft_lcd_filter_dir): ... this base function.
Updated.
(_ft_lcd_filter_legacy): Updated.
(FT_Library_SetLcdFilterWeights, FT_Library_SetLcdFilter): Updated.
* src/base/ftobjs.c (ft_open_face_internal): Updated.
(FT_Face_Properties): Handle FT_PARAM_TAG_LCD_FILTER_WEIGHTS.
* src/smooth/ftsmooth.c (ft_smooth_render_generic)
[FT_CONFIG_OPTION_SUBPIXEL_RENDERING: Handle LCD weights from
`FT_Face_Internal'.
2017-02-14 Nikolaus Waxweiler <madigens@gmail.com>
Werner Lemberg <wl@gnu.org>

View File

@ -3629,6 +3629,12 @@ FT_BEGIN_HEADER
* Note that only a subset of the available properties can be
* controlled.
*
* * LCD filter weights (@FT_PARAM_TAG_LCD_FILTER_WEIGHTS, corresponding
* to function @FT_Library_SetLcdFilterWeights).
*
* Pass NULL as `data' in @FT_Parameter for a given tag to reset the
* option and use the library or module default again.
*
* @input:
* face ::
* A handle to the source face object.

View File

@ -275,6 +275,37 @@ FT_BEGIN_HEADER
FT_Library_SetLcdFilterWeights( FT_Library library,
unsigned char *weights );
/*
* @constant:
* FT_PARAM_TAG_LCD_FILTER_WEIGHTS
*
* @description:
* An @FT_Parameter tag to be used with @FT_Face_Properties. The
* corresponding argument specifies the five LCD filter weights for a
* given face (if using @FT_LOAD_TARGET_LCD, for example), overriding
* the global default values or the values set up with
* @FT_Library_Set_LcdFilterWeights.
*
*/
#define FT_PARAM_TAG_LCD_FILTER_WEIGHTS \
FT_MAKE_TAG( 'l', 'c', 'd', 'f' )
/*
* @type:
* FT_LcdFiveTapFilter
*
* @description:
* A typedef for passing the five LCD filter weights to
* @FT_Face_Properties within an @FT_Parameter structure.
*
*/
#define FT_LCD_FILTER_FIVE_TAPS 5
typedef FT_Byte FT_LcdFiveTapFilter[FT_LCD_FILTER_FIVE_TAPS];
/* */

View File

@ -348,6 +348,10 @@ FT_BEGIN_HEADER
/* @FT_Done_Face only destroys a face if the counter is~1, */
/* otherwise it simply decrements it. */
/* */
/* lcd_weights :: */
/* Overrides the library default with custom weights for the 5-tap */
/* FIR filter. `{0, 0, 0, 0, 0}' means to use the library default. */
/* */
typedef struct FT_Face_InternalRec_
{
FT_Matrix transform_matrix;
@ -362,6 +366,10 @@ FT_BEGIN_HEADER
FT_Int refcount;
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
FT_LcdFiveTapFilter lcd_weights; /* preset or custom filter weights */
#endif
} FT_Face_InternalRec;
@ -775,12 +783,19 @@ FT_BEGIN_HEADER
/* This hook is used by the TrueType debugger. It must be set to an */
/* alternate truetype bytecode interpreter function. */
#define FT_DEBUG_HOOK_TRUETYPE 0
#define FT_DEBUG_HOOK_TRUETYPE 0
typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap,
FT_Render_Mode render_mode,
FT_Library library );
FT_Byte* weights );
/* This is the default LCD filter, an in-place, 5-tap FIR filter. */
FT_BASE( void )
ft_lcd_filter_fir( FT_Bitmap* bitmap,
FT_Render_Mode mode,
FT_LcdFiveTapFilter weights );
/*************************************************************************/
@ -876,7 +891,7 @@ FT_BEGIN_HEADER
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
FT_LcdFilter lcd_filter;
FT_Int lcd_extra; /* number of extra pixels */
FT_Byte lcd_weights[5]; /* filter weights, if any */
FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */
FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */
#endif

View File

@ -30,14 +30,13 @@
#define USE_LEGACY
/* FIR filter used by the default and light filters */
static void
_ft_lcd_filter_fir( FT_Bitmap* bitmap,
FT_Render_Mode mode,
FT_Library library )
FT_BASE( void )
ft_lcd_filter_fir( FT_Bitmap* bitmap,
FT_Render_Mode mode,
FT_LcdFiveTapFilter weights )
{
FT_Byte* weights = library->lcd_weights;
FT_UInt width = (FT_UInt)bitmap->width;
FT_UInt height = (FT_UInt)bitmap->rows;
FT_UInt width = (FT_UInt)bitmap->width;
FT_UInt height = (FT_UInt)bitmap->rows;
/* horizontal in-place FIR filter */
@ -176,7 +175,7 @@
static void
_ft_lcd_filter_legacy( FT_Bitmap* bitmap,
FT_Render_Mode mode,
FT_Library library )
FT_Byte* weights )
{
FT_UInt width = (FT_UInt)bitmap->width;
FT_UInt height = (FT_UInt)bitmap->rows;
@ -189,7 +188,7 @@
{ 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
};
FT_UNUSED( library );
FT_UNUSED( weights );
/* horizontal in-place intra-pixel filter */
@ -295,8 +294,8 @@
if ( !weights )
return FT_THROW( Invalid_Argument );
ft_memcpy( library->lcd_weights, weights, 5 );
library->lcd_filter_func = _ft_lcd_filter_fir;
ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS );
library->lcd_filter_func = ft_lcd_filter_fir;
library->lcd_extra = 2;
return FT_Err_Ok;
@ -307,10 +306,10 @@
FT_Library_SetLcdFilter( FT_Library library,
FT_LcdFilter filter )
{
static const FT_Byte default_filter[5] =
{ 0x08, 0x4d, 0x56, 0x4d, 0x08 };
static const FT_Byte light_filter[5] =
{ 0x00, 0x55, 0x56, 0x55, 0x00 };
static const FT_LcdFiveTapFilter default_weights =
{ 0x08, 0x4d, 0x56, 0x4d, 0x08 };
static const FT_LcdFiveTapFilter light_weights =
{ 0x00, 0x55, 0x56, 0x55, 0x00 };
if ( !library )
@ -324,14 +323,18 @@
break;
case FT_LCD_FILTER_DEFAULT:
ft_memcpy( library->lcd_weights, default_filter, 5 );
library->lcd_filter_func = _ft_lcd_filter_fir;
ft_memcpy( library->lcd_weights,
default_weights,
FT_LCD_FILTER_FIVE_TAPS );
library->lcd_filter_func = ft_lcd_filter_fir;
library->lcd_extra = 2;
break;
case FT_LCD_FILTER_LIGHT:
ft_memcpy( library->lcd_weights, light_filter, 5 );
library->lcd_filter_func = _ft_lcd_filter_fir;
ft_memcpy( library->lcd_weights,
light_weights,
FT_LCD_FILTER_FIVE_TAPS );
library->lcd_filter_func = ft_lcd_filter_fir;
library->lcd_extra = 2;
break;
@ -356,6 +359,17 @@
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
FT_BASE( void )
ft_lcd_filter_fir( FT_Bitmap* bitmap,
FT_Render_Mode mode,
FT_LcdFiveTapFilter weights )
{
FT_UNUSED( bitmap );
FT_UNUSED( mode );
FT_UNUSED( weights );
}
FT_EXPORT_DEF( FT_Error )
FT_Library_SetLcdFilterWeights( FT_Library library,
unsigned char *weights )

View File

@ -2424,6 +2424,10 @@
internal->transform_delta.y = 0;
internal->refcount = 1;
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
ft_memset( internal->lcd_weights, 0, FT_LCD_FILTER_FIVE_TAPS );
#endif
}
if ( aface )
@ -3607,8 +3611,31 @@
for ( ; num_properties > 0; num_properties-- )
{
error = FT_THROW( Invalid_Argument );
goto Exit;
if ( properties->tag == FT_PARAM_TAG_LCD_FILTER_WEIGHTS )
{
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
if ( properties->data )
ft_memcpy( face->internal->lcd_weights,
properties->data,
FT_LCD_FILTER_FIVE_TAPS );
else
{
/* Value NULL indicates `no custom weights, use library */
/* defaults', signaled by filling the weight field with zeros. */
ft_memset( face->internal->lcd_weights,
0,
FT_LCD_FILTER_FIVE_TAPS );
}
#else
error = FT_THROW( Unimplemented_Feature );
goto Exit;
#endif
}
else
{
error = FT_THROW( Invalid_Argument );
goto Exit;
}
if ( error )
break;

View File

@ -122,6 +122,60 @@
FT_Bool have_outline_shifted = FALSE;
FT_Bool have_buffer = FALSE;
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
FT_Int lcd_extra = 0;
FT_LcdFiveTapFilter lcd_weights = { 0 };
FT_Bool have_custom_weight = FALSE;
FT_Bitmap_LcdFilterFunc lcd_filter_func = NULL;
if ( slot->face )
{
FT_Char i;
for ( i = 0; i < FT_LCD_FILTER_FIVE_TAPS; i++ )
if ( slot->face->internal->lcd_weights[i] != 0 )
{
have_custom_weight = TRUE;
break;
}
}
/*
* The LCD filter can be set library-wide and per-face. Face overrides
* library. If the face filter weights are all zero (the default), it
* means that the library default should be used.
*/
if ( have_custom_weight )
{
/*
* A per-font filter is set. It always uses the default 5-tap
* in-place FIR filter that needs 2 extra pixels.
*/
ft_memcpy( lcd_weights,
slot->face->internal->lcd_weights,
FT_LCD_FILTER_FIVE_TAPS );
lcd_filter_func = ft_lcd_filter_fir;
lcd_extra = 2;
}
else
{
/*
* The face's lcd_weights is {0, 0, 0, 0, 0}, meaning `use library
* default'. If the library is set to use no LCD filtering
* (lcd_filter_func == NULL), `lcd_filter_func' here is also set to
* NULL and the tests further below pass over the filtering process.
*/
ft_memcpy( lcd_weights,
slot->library->lcd_weights,
FT_LCD_FILTER_FIVE_TAPS );
lcd_filter_func = slot->library->lcd_filter_func;
lcd_extra = slot->library->lcd_extra;
}
#endif /*FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
/* check glyph image format */
if ( slot->format != render->glyph_format )
@ -177,28 +231,23 @@
height *= 3;
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
if ( slot->library->lcd_filter_func )
if ( lcd_filter_func )
{
FT_Int extra = slot->library->lcd_extra;
if ( hmul )
{
x_shift += 64 * ( extra >> 1 );
x_left -= extra >> 1;
width += 3 * extra;
x_shift += 64 * ( lcd_extra >> 1 );
x_left -= lcd_extra >> 1;
width += 3 * lcd_extra;
pitch = FT_PAD_CEIL( width, 4 );
}
if ( vmul )
{
y_shift += 64 * ( extra >> 1 );
y_top += extra >> 1;
height += 3 * extra;
y_shift += 64 * ( lcd_extra >> 1 );
y_top += lcd_extra >> 1;
height += 3 * lcd_extra;
}
}
#endif
/*
@ -299,8 +348,8 @@
if ( error )
goto Exit;
if ( slot->library->lcd_filter_func )
slot->library->lcd_filter_func( bitmap, mode, slot->library );
if ( lcd_filter_func )
lcd_filter_func( bitmap, mode, lcd_weights );
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */