>From 297b68621c020c8d6e61a04b8e91ac829a6bc13d Mon Sep 17 00:00:00 2001
From: Nikolaus Waxweiler
Date: Sun, 13 Nov 2016 20:47:08 +0100
Subject: [PATCH 1/2] Implement FT_Face_Option() [1/2]
FT_Face_Option() can override certain library or module-wide options on
a face-by-face basis. These options are stored in the 'internal'
structure of a FT_Face. They are "unset" by default.
First up are custom LCD filter weights.
* Implement FT_Face_Option() and declare the option tags.
* Implement the code to honors the face-level LCD filter option.
* Make the default and light filter weights publicly accessible as
FT_LCD_FILTER_DEFAULT_WEIGHTS and FT_LCD_FILTER_LIGHT_WEIGHTS.
* Modify the signature of FT_Bitmap_LcdFilterFunc to take FT_Byte*
instead of FT_Library as the last argument, change _ft_lcd_filter_fir
and _ft_lcd_filter_legacy accordingly.
* Rename _ft_lcd_filter_fir to ft_lcd_filter_fir and make it accessible
from within the FreeType source.
---
include/freetype/freetype.h | 77 ++++++++++++++++++++++++++++++++++++++
include/freetype/ftlcdfil.h | 6 +++
include/freetype/internal/ftobjs.h | 22 ++++++++++-
src/base/ftlcdfil.c | 39 ++++++++++---------
src/base/ftobjs.c | 65 +++++++++++++++++++++++++++++++-
src/smooth/ftsmooth.c | 53 ++++++++++++++++++++------
6 files changed, 230 insertions(+), 32 deletions(-)
diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h
index f3287b7..36f503b 100644
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -3578,6 +3578,83 @@ FT_BEGIN_HEADER
/*************************************************************************/
+ /*
+ *
+ * FT_Face_Option
+ *
+ *
+ * This function can be used to set or override certain (library or
+ * module-wide) options on a face-by-face basis. Useful for finer grained
+ * control and avoiding locks on shared structures (threads can modify
+ * their own faces as they see fit).
+ *
+ *
+ * face :: A handle to the source face object.
+ * num_params :: The number of parameters that follow.
+ * parameters :: A handle to the num_params FT_Parameters.
+ *
+ *
+ * FreeType error code. 0~means success.
+ *
+ *
+ * The accepted parameters are:
+ *
+ * 1) FT_FACE_OPTION_ENABLE_STEM_DARKENING:
+ * Toggles stem darkening. Overrides the module setting.
+ *
+ * Currently implies forcing the native CFF engine for OpenType/CFF
+ * fonts and the (LIGHT) autohinter for all other outline formats, as
+ * only those engines have full control over how an outline is
+ * rendered.
+ *
+ * 2) FT_FACE_OPTION_SET_LCD_FILTER_WEIGHTS:
+ * Sets the weights for the 5-tap in-place FIR filter used by default
+ * (the legacy intra-pixel filter is not supported). Overrides the
+ * library setting. See @lcd_filtering.
+ *
+ * Pass NULL as data for a tag to reset the option and use the library or
+ * module default again.
+ *
+ * Example:
+ * {
+ * FT_Parameter parameter1;
+ * FT_Bool darken_stems = 1;
+ * parameter1.tag = FT_FACE_OPTION_ENABLE_STEM_DARKENING;
+ * parameter1.data = &darken_stems;
+ *
+ * FT_Parameter parameter2;
+ * FT_Byte custom_weight[5] = { 0x10, 0x40, 0x70, 0x40, 0x10 };
+ * parameter2.tag = FT_FACE_OPTION_SET_LCD_FILTER_WEIGHTS;
+ * parameter2.data = custom_weight;
+ *
+ * FT_Parameter parameters[2] = { parameter1, parameter2 };
+ *
+ * FT_Face_Option( face, 2, parameters );
+ *
+ * // Switch options around.
+ * darken_stems = 0;
+ * ft_memcpy(parameters[1].data, FT_LCD_FILTER_LIGHT_WEIGHTS, 5);
+ *
+ * FT_Face_Option( face, 2, parameters );
+ *
+ * // Example for a single option.
+ * FT_Parameter parameter3;
+ * parameter3.tag = FT_FACE_OPTION_SET_LCD_FILTER_WEIGHTS;
+ * parameter3.data = NULL;
+ *
+ * FT_Face_Option( face, 1, ¶meter3 );
+ * }
+ */
+ FT_EXPORT( FT_Error )
+ FT_Face_Option( FT_Face face,
+ FT_UInt num_params,
+ FT_Parameter* parameters);
+
+#define FT_FACE_OPTION_ENABLE_STEM_DARKENING FT_MAKE_TAG( 'd', 'a', 'r', 'k' )
+#define FT_FACE_OPTION_SET_LCD_FILTER_WEIGHTS FT_MAKE_TAG( 'l', 'w', 'g', 't' )
+
+
+ /*************************************************************************/
/* */
/* */
/* FT_Get_Name_Index */
diff --git a/include/freetype/ftlcdfil.h b/include/freetype/ftlcdfil.h
index e06a895..bb85769 100644
--- a/include/freetype/ftlcdfil.h
+++ b/include/freetype/ftlcdfil.h
@@ -197,6 +197,12 @@ FT_BEGIN_HEADER
} FT_LcdFilter;
+ static const FT_Byte FT_LCD_FILTER_DEFAULT_WEIGHTS[5] =
+ { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
+ static const FT_Byte FT_LCD_FILTER_LIGHT_WEIGHTS[5] =
+ { 0x00, 0x55, 0x56, 0x55, 0x00 };
+
+
/**************************************************************************
*
diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h
index 15936f2..69a56e9 100644
--- a/include/freetype/internal/ftobjs.h
+++ b/include/freetype/internal/ftobjs.h
@@ -347,6 +347,15 @@ FT_BEGIN_HEADER
/* created. @FT_Reference_Face increments this counter, and */
/* @FT_Done_Face only destroys a face if the counter is~1, */
/* otherwise it simply decrements it. */
+ /*
+ * stem_darkening ::
+ * Overrides the module-level default, see e.g. @stem-darkening[cff]. 1
+ * and 0 toggle on and off, -1 means to use the library default.
+ *
+ * lcd_weights ::
+ * Overrides the library default with custom weights for the 5-tap FIR
+ * filter. {0, 0, 0, 0, 0} means to use the module default.
+ */
/* */
typedef struct FT_Face_InternalRec_
{
@@ -362,6 +371,11 @@ FT_BEGIN_HEADER
FT_Int refcount;
+ FT_Char stem_darkening;
+
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+ FT_Byte lcd_weights[5]; /* Preset or custom filter weights. */
+#endif
} FT_Face_InternalRec;
@@ -779,7 +793,13 @@ FT_BEGIN_HEADER
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_Byte* weights );
/*************************************************************************/
diff --git a/src/base/ftlcdfil.c b/src/base/ftlcdfil.c
index 8bcbed7..c3d341c 100644
--- a/src/base/ftlcdfil.c
+++ b/src/base/ftlcdfil.c
@@ -30,12 +30,11 @@
#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_Byte* weights )
{
- FT_Byte* weights = library->lcd_weights;
FT_UInt width = (FT_UInt)bitmap->width;
FT_UInt height = (FT_UInt)bitmap->rows;
@@ -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 */
@@ -296,7 +295,7 @@
return FT_THROW( Invalid_Argument );
ft_memcpy( library->lcd_weights, weights, 5 );
- library->lcd_filter_func = _ft_lcd_filter_fir;
+ library->lcd_filter_func = ft_lcd_filter_fir;
library->lcd_extra = 2;
return FT_Err_Ok;
@@ -307,12 +306,6 @@
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 };
-
-
if ( !library )
return FT_THROW( Invalid_Library_Handle );
@@ -324,14 +317,14 @@
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, FT_LCD_FILTER_DEFAULT_WEIGHTS, 5 );
+ 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, FT_LCD_FILTER_LIGHT_WEIGHTS, 5 );
+ library->lcd_filter_func = ft_lcd_filter_fir;
library->lcd_extra = 2;
break;
@@ -356,6 +349,16 @@
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+ FT_BASE( void )
+ ft_lcd_filter_fir( FT_Bitmap* bitmap,
+ FT_Render_Mode mode,
+ FT_Byte* weights )
+ {
+ FT_UNUSED( bitmap );
+ FT_UNUSED( mode );
+ FT_UNUSED( weights );
+ }
+
FT_EXPORT_DEF( FT_Error )
FT_Library_SetLcdFilterWeights( FT_Library library,
unsigned char *weights )
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index c701ebc..3d52f45 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -2340,7 +2340,8 @@
/* initialize internal face data */
{
- FT_Face_Internal internal = face->internal;
+ FT_Face_Internal internal = face->internal;
+ static const FT_Byte lcd_weights[5] = { 0 };
internal->transform_matrix.xx = 0x10000L;
@@ -2352,8 +2353,12 @@
internal->transform_delta.y = 0;
internal->refcount = 1;
+
+ internal->stem_darkening = -1;
+ ft_memcpy( internal->lcd_weights, lcd_weights, 5 );
}
+
if ( aface )
*aface = face;
else
@@ -3506,6 +3511,64 @@
/* documentation is in freetype.h */
+ FT_EXPORT_DEF( FT_Error )
+ FT_Face_Option( FT_Face face,
+ FT_UInt num_params,
+ FT_Parameter* parameters)
+ {
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( num_params > 0 && !parameters )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+ }
+
+ for ( ; num_params > 0; num_params-- )
+ {
+ if ( parameters->tag == FT_FACE_OPTION_ENABLE_STEM_DARKENING )
+ {
+ if ( parameters->data )
+ {
+ if ( *((FT_Bool*)parameters->data) == 1 )
+ face->internal->stem_darkening = 1;
+ else
+ face->internal->stem_darkening = 0;
+ }
+ else /* Use module default. */
+ face->internal->stem_darkening = -1;
+ }
+ else if ( parameters->tag == FT_FACE_OPTION_SET_LCD_FILTER_WEIGHTS )
+ {
+ if ( parameters->data )
+ ft_memcpy( face->internal->lcd_weights, parameters->data, 5 );
+ else /* NULL == no custom weights, use library default. Signaled by
+ filling the weight field with zeros. */
+ {
+ FT_Byte no_weight[5] = { 0 };
+ ft_memcpy( face->internal->lcd_weights, no_weight, 5 );
+ }
+ }
+ else
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+ }
+
+ if ( error )
+ break;
+
+ parameters++;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
FT_EXPORT_DEF( FT_UInt )
FT_Face_GetCharVariantIndex( FT_Face face,
FT_ULong charcode,
diff --git a/src/smooth/ftsmooth.c b/src/smooth/ftsmooth.c
index 1371792..03ee3ef 100644
--- a/src/smooth/ftsmooth.c
+++ b/src/smooth/ftsmooth.c
@@ -122,6 +122,38 @@
FT_Bool have_outline_shifted = FALSE;
FT_Bool have_buffer = FALSE;
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+ FT_Int lcd_extra = 0;
+ FT_Byte lcd_weights[5] = { 0 };
+ const static FT_Byte lcd_weights_empty[5] = { 0 };
+ FT_Bitmap_LcdFilterFunc lcd_filter_func = NULL;
+
+ /* 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 ( slot->face &&
+ ft_memcmp( slot->face->internal->lcd_weights,
+ lcd_weights_empty,
+ 5 * sizeof(FT_Byte) ) )
+ {
+ /* A per-font filter is set. It will always use the default 5-tap
+ * in-place FIR filter that needs 2 extra pixels. */
+ lcd_filter_func = ft_lcd_filter_fir;
+ lcd_extra = 2;
+ ft_memcpy( lcd_weights, slot->face->internal->lcd_weights, 5 );
+ }
+ else
+ {
+ /* The face's lcd_weights is {0, 0, 0, 0, 0}, use library default. If the
+ * library is set to use no LCD filtering (lcd_filter_func == NULL),
+ * lcd_filter_func here will also be set to NULL and the tests further
+ * below will pass over the filtering process. */
+ lcd_filter_func = slot->library->lcd_filter_func;
+ lcd_extra = slot->library->lcd_extra;
+ ft_memcpy( lcd_weights, slot->library->lcd_weights, 5 );
+ }
+#endif
+
/* check glyph image format */
if ( slot->format != render->glyph_format )
@@ -178,24 +210,21 @@
#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;
}
}
@@ -299,8 +328,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 */
--
2.9.3