New revision. Reverts the no_stem_darkening rename, typedefs FT_Byte
lcd_weight[5] and uses memset in a few places to avoid creating an emtpy
LCD filter.

So far, I have not received comments from Behdad or Qt people on the API
as such, however one person on the Qt development list said that he
wouldn't like the automatic toggling of the autohinter for font drivers
that can't darken stems by themselves.

I think that even without the new API, toolkits can already make an
informed decision about whether to enable stem darkening or not: by
querying the no-stem-darkening property of a driver or the autohinter.
If FT_Property_Get returns an error indicating the property doesn't
exist, the driver/autohinter probably doesn't darken stems.

So now I'm also thinking about how to implement stem darkening in the
TrueType driver. The first problem would be to determine the stem
widths, but a first version could use the heuristic Dave Arnold
described a while back: using fixed values according to what weight a
font advertises itself. Problems begin with hinting, as the concept of
stem darkening is somewhat incompatible with the explicit programming of
TrueType hints. On v40 in backwards compatibility mode, where hinting on
the x-axis is ignored, this is less of a problem, because you can just
darken vertical stems only. In v40 native mode, (tricky) fonts can
modify points on the x-axis. Dave Arnold mentioned that Adobe's software
lessens the darkening in that case because many fonts snap vertical
stems to pixel boundaries, thereby darkening them already. Some don't,
however, so you'd have to darken them normally. Ideally, you measure
stems after the hinting process... Not sure if an acceptable solution
can be found here so that stem darkening can just be toggled for the
TrueType driver and then forgotten about.
From 9d77a2faac41dd39caeadaa13889d286a3023649 Mon Sep 17 00:00:00 2001
From: Nikolaus Waxweiler <[email protected]>
Date: Sun, 20 Nov 2016 18:00:01 +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        | 80 ++++++++++++++++++++++++++++++++++++++
 include/freetype/ftlcdfil.h        | 10 +++++
 include/freetype/internal/ftobjs.h | 25 +++++++++++-
 src/base/ftlcdfil.c                | 41 ++++++++++---------
 src/base/ftobjs.c                  | 65 +++++++++++++++++++++++++++++++
 src/smooth/ftsmooth.c              | 62 +++++++++++++++++++++++------
 6 files changed, 250 insertions(+), 33 deletions(-)

diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h
index f3287b7..0ae2598 100644
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -3578,6 +3578,86 @@ FT_BEGIN_HEADER
 
 
   /*************************************************************************/
+  /*
+   * <Function>
+   *    FT_Face_Option
+   *
+   * <Description>
+   *    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).
+   *
+   * <Input>
+   *    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.
+   *
+   * <Return>
+   *    FreeType error code.  0~means success.
+   *
+   * <Note>
+   *    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:
+   *    {
+   *        // Define FT_CONFIG_OPTION_SUBPIXEL_RENDERING for the LCD filter
+   *        // examples to work.
+   *
+   *        FT_Parameter parameter1;
+   *        FT_Bool darken_stems = 1;
+   *        parameter1.tag  = FT_FACE_OPTION_ENABLE_STEM_DARKENING;
+   *        parameter1.data = &darken_stems;
+   *
+   *        FT_Parameter parameter2;
+   *        FT_LcdFiveTapFilter custom_weight = { 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, FT_LCD_FILTER_FIVE_TAPS);
+   *
+   *        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; // Reset option to driver/module default
+   *
+   *        FT_Face_Option( face, 1, &parameter3 );
+   *    }
+   */
+  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', 'c', 'd', 'f' )
+
+
+  /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
   /*    FT_Get_Name_Index                                                  */
diff --git a/include/freetype/ftlcdfil.h b/include/freetype/ftlcdfil.h
index e06a895..cc3338f 100644
--- a/include/freetype/ftlcdfil.h
+++ b/include/freetype/ftlcdfil.h
@@ -197,6 +197,16 @@ FT_BEGIN_HEADER
 
   } FT_LcdFilter;
 
+  #define FT_LCD_FILTER_FIVE_TAPS 5
+
+  typedef FT_Byte FT_LcdFiveTapFilter[FT_LCD_FILTER_FIVE_TAPS];
+
+  static const FT_LcdFiveTapFilter FT_LCD_FILTER_DEFAULT_WEIGHTS =
+                            { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
+  static const FT_LcdFiveTapFilter FT_LCD_FILTER_LIGHT_WEIGHTS =
+                            { 0x00, 0x55, 0x56, 0x55, 0x00 };
+
+
 
   /**************************************************************************
    *
diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h
index 15936f2..d54e4ec 100644
--- a/include/freetype/internal/ftobjs.h
+++ b/include/freetype/internal/ftobjs.h
@@ -347,6 +347,16 @@ 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.                               */
+  /*
+   *    no_stem_darkening ::
+   *      Overrides the module-level default, see e.g. @stem-darkening[cff].
+   *      FALSE and TRUE toggle stem darkening on and off, respectively, -1
+   *      means to use the module/driver 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 library default.
+   */
   /*                                                                       */
   typedef struct  FT_Face_InternalRec_
   {
@@ -362,6 +372,11 @@ FT_BEGIN_HEADER
 
     FT_Int              refcount;
 
+    FT_Char             no_stem_darkening;
+
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+    FT_LcdFiveTapFilter lcd_weights;   /* Preset or custom filter weights. */
+#endif
   } FT_Face_InternalRec;
 
 
@@ -779,7 +794,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_LcdFiveTapFilter weights );
 
 
   /*************************************************************************/
@@ -875,7 +896,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
 
diff --git a/src/base/ftlcdfil.c b/src/base/ftlcdfil.c
index 8bcbed7..2c1a72e 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_LcdFiveTapFilter 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 */
@@ -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,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, 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, FT_LCD_FILTER_LIGHT_WEIGHTS, FT_LCD_FILTER_FIVE_TAPS );
+      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_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 )
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index c701ebc..cd78424 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -2352,6 +2352,11 @@
       internal->transform_delta.y = 0;
 
       internal->refcount = 1;
+
+      internal->no_stem_darkening = -1;
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+      ft_memset( internal->lcd_weights, 0, FT_LCD_FILTER_FIVE_TAPS );
+#endif
     }
 
     if ( aface )
@@ -3506,6 +3511,66 @@
 
   /* 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) == TRUE )
+            face->internal->no_stem_darkening = FALSE;
+          else
+            face->internal->no_stem_darkening = TRUE;
+        }
+        else /* Use module default. */
+          face->internal->no_stem_darkening = -1;
+      }
+      else if ( parameters->tag == FT_FACE_OPTION_SET_LCD_FILTER_WEIGHTS )
+      {
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+        if ( parameters->data )
+          ft_memcpy( face->internal->lcd_weights, parameters->data, FT_LCD_FILTER_FIVE_TAPS );
+        else /* NULL == no custom weights, use library default. 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;
+
+      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..f9a50d5 100644
--- a/src/smooth/ftsmooth.c
+++ b/src/smooth/ftsmooth.c
@@ -122,6 +122,47 @@
     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 weight_i = 0;
+
+      for ( ; weight_i < FT_LCD_FILTER_FIVE_TAPS; weight_i++ )
+        if ( slot->face->internal->lcd_weights[weight_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 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, FT_LCD_FILTER_FIVE_TAPS );
+    }
+    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, FT_LCD_FILTER_FIVE_TAPS );
+    }
+#endif
+
 
     /* check glyph image format */
     if ( slot->format != render->glyph_format )
@@ -178,24 +219,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 +337,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

From 055afba8dc8427d90b65cf374e06ab720ba31823 Mon Sep 17 00:00:00 2001
From: Nikolaus Waxweiler <[email protected]>
Date: Sun, 20 Nov 2016 18:08:08 +0100
Subject: [PATCH 2/2] Implement FT_Face_Option() [2/2]

Next up is the stem darkening option.

* Honor the face-level option in the CFF driver and autohinter.

* Change FT_Load_Glyph() to trigger the autohinter for font drivers that
  can't darken stems by themselves. This currently means all of them
  except for the CFF driver. Within the autohinter, enforce LIGHT mode
  because stem darkening currently only really works there.
---
 src/autofit/afloader.c | 10 +++++++++-
 src/autofit/afmodule.c |  8 ++++----
 src/base/ftobjs.c      | 18 ++++++++++++++++--
 src/cff/cf2ft.c        |  7 ++++++-
 src/cff/cffdrivr.c     |  8 ++++----
 5 files changed, 39 insertions(+), 12 deletions(-)

diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c
index 26bba06..b214514 100644
--- a/src/autofit/afloader.c
+++ b/src/autofit/afloader.c
@@ -135,7 +135,9 @@
      * must therefore be recomputed for each size and
      * `standard_{vertical,horizontal}_width' change.
      */
-    if ( !module->no_stem_darkening )
+    if ( face->internal->no_stem_darkening == FALSE ||
+         ( face->internal->no_stem_darkening < 0 &&
+           !module->no_stem_darkening ) )
     {
       AF_FaceGlobals         globals = loader->globals;
       AF_WritingSystemClass  writing_system_class;
@@ -492,6 +494,12 @@
     scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
     scaler.flags       = 0;  /* XXX: fix this */
 
+    /* Stem darkening only works well in LIGHT mode. */
+    if ( face->internal->no_stem_darkening == FALSE ||
+         ( face->internal->no_stem_darkening < 0 &&
+           !module->no_stem_darkening ) )
+      scaler.render_mode = FT_RENDER_MODE_LIGHT;
+
     error = af_loader_reset( loader, module, face );
     if ( !error )
     {
diff --git a/src/autofit/afmodule.c b/src/autofit/afmodule.c
index f325ebf..caaf594 100644
--- a/src/autofit/afmodule.c
+++ b/src/autofit/afmodule.c
@@ -291,10 +291,10 @@
         long         nsd = ft_strtol( s, NULL, 10 );
 
 
-        if ( nsd == 0 )
-          module->no_stem_darkening = 0;
-        else if ( nsd == 1 )
-          module->no_stem_darkening = 1;
+        if ( nsd == FALSE )
+          module->no_stem_darkening = FALSE;
+        else if ( nsd == TRUE )
+          module->no_stem_darkening = TRUE;
         else
           return FT_THROW( Invalid_Argument );
       }
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index cd78424..1ec1b0f 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -612,7 +612,9 @@
     FT_Bool       autohint = FALSE;
     FT_Module     hinter;
     TT_Face       ttface = (TT_Face)face;
-
+    FT_Bool       driver_can_darken_stems = FALSE;
+    FT_Bool       stem_darkening = FALSE;
+    FT_Bool       no_stem_darkening_driver = TRUE;
 
     if ( !face || !face->size || !face->glyph )
       return FT_THROW( Invalid_Face_Handle );
@@ -627,8 +629,19 @@
     library = driver->root.library;
     hinter  = library->auto_hinter;
 
-    /* resolve load flags dependencies */
+    /* Determine if stem darkening is to be applied. */
+    error = FT_Property_Get( library, driver->clazz->root.module_name,
+                             "no-stem-darkening", &no_stem_darkening_driver );
+    if ( !error )
+      driver_can_darken_stems = TRUE;
 
+    error = FT_Err_Ok; /* Reset error variable. */
+
+    stem_darkening = ( face->internal->no_stem_darkening == FALSE ||
+                       ( face->internal->no_stem_darkening < 0 &&
+                         !no_stem_darkening_driver ) );
+
+    /* resolve load flags dependencies */
     if ( load_flags & FT_LOAD_NO_RECURSE )
       load_flags |= FT_LOAD_NO_SCALE         |
                     FT_LOAD_IGNORE_TRANSFORM;
@@ -691,6 +704,7 @@
         /* both `fpgm' and `prep' tables are missing                 */
         if ( ( mode == FT_RENDER_MODE_LIGHT                   &&
                !FT_DRIVER_HINTS_LIGHTLY( driver ) )             ||
+             ( stem_darkening && !driver_can_darken_stems )     ||
              ( FT_IS_SFNT( face )                             &&
                ttface->num_locations                          &&
                ttface->max_profile.maxSizeOfInstructions == 0 &&
diff --git a/src/cff/cf2ft.c b/src/cff/cf2ft.c
index edbe6a7..1b349d3 100644
--- a/src/cff/cf2ft.c
+++ b/src/cff/cf2ft.c
@@ -339,6 +339,9 @@
       CFF_Builder*  builder = &decoder->builder;
       CFF_Driver    driver  = (CFF_Driver)FT_FACE_DRIVER( builder->face );
 
+      FT_Bool no_stem_darkening_driver = driver->no_stem_darkening;
+      FT_Char no_stem_darkening_font   = builder->face->root.internal->no_stem_darkening;
+
       /* local error */
       FT_Error       error2 = FT_Err_Ok;
       CF2_BufferRec  buf;
@@ -369,7 +372,9 @@
       font->renderingFlags = 0;
       if ( hinted )
         font->renderingFlags |= CF2_FlagsHinted;
-      if ( scaled && !driver->no_stem_darkening )
+      if ( scaled && ( no_stem_darkening_font == FALSE ||
+                       ( no_stem_darkening_font < 0 &&
+                         !no_stem_darkening_driver ) ) )
         font->renderingFlags |= CF2_FlagsDarkened;
 
       font->darkenParams[0] = driver->darken_params[0];
diff --git a/src/cff/cffdrivr.c b/src/cff/cffdrivr.c
index cf02477..d1b35cf 100644
--- a/src/cff/cffdrivr.c
+++ b/src/cff/cffdrivr.c
@@ -779,10 +779,10 @@
         long         nsd = ft_strtol( s, NULL, 10 );
 
 
-        if ( nsd == 0 )
-          driver->no_stem_darkening = 0;
-        else if ( nsd == 1 )
-          driver->no_stem_darkening = 1;
+        if ( nsd == FALSE )
+          driver->no_stem_darkening = FALSE;
+        else if ( nsd == TRUE )
+          driver->no_stem_darkening = TRUE;
         else
           return FT_THROW( Invalid_Argument );
       }
-- 
2.9.3

_______________________________________________
Freetype-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/freetype-devel

Reply via email to