shithub: freetype+ttf2subf

Download patch

ref: 2e9519885b8e7e5fdc9d75b35992ef7bbf15e53a
parent: 64cdee73480587352fb45402b771077be05c1715
author: Nikolaus Waxweiler <[email protected]>
date: Thu Feb 16 15:45:45 EST 2017

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'.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2017-02-16  Nikolaus Waxweiler  <[email protected]>
+	    Werner Lemberg  <[email protected]>
+
+	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  <[email protected]>
 	    Werner Lemberg  <[email protected]>
 
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -3629,6 +3629,12 @@
    *   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.
--- a/include/freetype/ftlcdfil.h
+++ b/include/freetype/ftlcdfil.h
@@ -275,6 +275,37 @@
   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];
+
+
   /* */
 
 
--- a/include/freetype/internal/ftobjs.h
+++ b/include/freetype/internal/ftobjs.h
@@ -348,6 +348,10 @@
   /*      @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_Int              refcount;
 
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    FT_LcdFiveTapFilter  lcd_weights;  /* preset or custom filter weights */
+#endif
+
   } FT_Face_InternalRec;
 
 
@@ -775,14 +783,21 @@
 
   /* 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 );
+
+
   /*************************************************************************/
   /*                                                                       */
   /* <Struct>                                                              */
@@ -876,7 +891,7 @@
 #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
 
--- a/src/base/ftlcdfil.c
+++ b/src/base/ftlcdfil.c
@@ -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;
 
@@ -355,6 +358,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,
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -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;
--- a/src/smooth/ftsmooth.c
+++ b/src/smooth/ftsmooth.c
@@ -122,7 +122,61 @@
     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 */