Here's something.
>From 0d62556870ccd939782141a2ba7aa3150a1b03b8 Mon Sep 17 00:00:00 2001
From: Nikolaus Waxweiler <[email protected]>
Date: Sun, 23 Oct 2016 22:43:25 +0200
Subject: [PATCH] Minor clean-up of af_loader_load_glyph().

Merge af_loader_load_g into af_loader_load_glyph, move emboldening into own
function, minor documentation improvements.
---
 src/autofit/afloader.c | 600 ++++++++++++++++++++++++-------------------------
 src/autofit/afloader.h |   5 +
 2 files changed, 304 insertions(+), 301 deletions(-)

diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c
index 26bba06..e593db8 100644
--- a/src/autofit/afloader.c
+++ b/src/autofit/afloader.c
@@ -86,161 +86,135 @@
           ( (FT_Fixed)( (f) * 65536.0 + 0.5 ) )
 
 
-  /* Do the main work of `af_loader_load_glyph'.  Note that we never   */
-  /* have to deal with composite glyphs as those get loaded into       */
-  /* FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. */
-  /* In the rare cases where FT_LOAD_NO_RECURSE is set, it implies     */
-  /* FT_LOAD_NO_SCALE and as such the auto-hinter is never called.     */
-
-  static FT_Error
-  af_loader_load_g( AF_Loader  loader,
-                    AF_Scaler  scaler,
-                    FT_UInt    glyph_index,
-                    FT_Int32   load_flags )
+  /* Load the glyph at index into the current slot of a face and hint it. */
+
+  FT_LOCAL_DEF( FT_Error )
+  af_loader_load_glyph( AF_Loader  loader,
+                        AF_Module  module,
+                        FT_Face    face,
+                        FT_UInt    glyph_index,
+                        FT_Int32   load_flags )
   {
-    AF_Module  module = loader->globals->module;
+    FT_Error               error;
+    FT_Size                size     = face->size;
+    FT_GlyphSlot           slot     = face->glyph;
+    FT_Slot_Internal       internal = slot->internal;
+    FT_GlyphLoader         gloader  = internal->loader;
+    AF_GlyphHints          hints    = loader->hints;
+    AF_ScalerRec           scaler;
+    AF_StyleMetrics        style_metrics;
+    FT_UInt                style_options  = AF_STYLE_NONE_DFLT;
+    AF_StyleClass          style_class;
+    AF_WritingSystemClass  writing_system_class;
+#ifdef FT_CONFIG_OPTION_PIC
+    AF_FaceGlobals         globals  = loader->globals;
+#endif
 
-    FT_Error          error;
-    FT_Face           face     = loader->face;
-    AF_StyleMetrics   metrics  = loader->metrics;
-    AF_GlyphHints     hints    = loader->hints;
-    FT_GlyphSlot      slot     = face->glyph;
-    FT_Slot_Internal  internal = slot->internal;
-    FT_GlyphLoader    gloader  = internal->loader;
-    FT_Int32          flags;
 
+    if ( !size )
+      return FT_THROW( Invalid_Size_Handle );
 
-    flags = load_flags | FT_LOAD_LINEAR_DESIGN;
-    error = FT_Load_Glyph( face, glyph_index, flags );
-    if ( error )
-      goto Exit;
+    FT_ZERO( &scaler );
 
     /*
-     * Apply stem darkening (emboldening) here before hints are applied to
-     * the outline.  Glyphs are scaled down proportionally to the
-     * emboldening so that curve points don't fall outside their precomputed
-     * blue zones.
-     *
-     * Any emboldening done by the font driver (e.g., the CFF driver)
-     * doesn't reach here because the autohinter loads the unprocessed
-     * glyphs in font units for analysis (functions `af_*_metrics_init_*')
-     * and then above to prepare it for the rasterizers by itself,
-     * independently of the font driver.  So emboldening must be done here,
-     * within the autohinter.
-     *
-     * All glyphs to be autohinted pass through here one by one.  The
-     * standard widths can therefore change from one glyph to the next,
-     * depending on what script a glyph is assigned to (each script has its
-     * own set of standard widths and other metrics).  The darkening amount
-     * must therefore be recomputed for each size and
-     * `standard_{vertical,horizontal}_width' change.
+     * TODO: This code currently doesn't support fractional advance widths,
+     * i.e. placing hinted glyphs at anything other than integer x-positions.
+     * This is only relevant for the warper code, which scales and shifts
+     * glyphs to optimize blackness of stems (hinting on the x-axis by nature
+     * places things on pixel integers, hinting on the y-axis only, i.e. LIGHT
+     * mode, doesn't touch the x-axis). The delta values of the scaler would
+     * need to be adjusted.
      */
-    if ( !module->no_stem_darkening )
-    {
-      AF_FaceGlobals         globals = loader->globals;
-      AF_WritingSystemClass  writing_system_class;
-
-      FT_Pos  stdVW = 0;
-      FT_Pos  stdHW = 0;
-
-      FT_Bool  size_changed = face->size->metrics.x_ppem
-                                != globals->stem_darkening_for_ppem;
+    scaler.face    = face;
+    scaler.x_scale = size->metrics.x_scale;
+    scaler.x_delta = 0;
+    scaler.y_scale = size->metrics.y_scale;
+    scaler.y_delta = 0;
 
-      FT_Fixed  em_size  = af_intToFixed( face->units_per_EM );
-      FT_Fixed  em_ratio = FT_DivFix( af_intToFixed( 1000 ), em_size );
+    scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
+    scaler.flags       = 0;
 
-      FT_Matrix  scale_down_matrix = { 0x10000L, 0, 0, 0x10000L };
+    error = af_loader_reset( loader, module, face );
 
+    if ( error )
+      goto Exit;
 
-      /* Skip stem darkening for broken fonts. */
-      if ( !face->units_per_EM )
-        goto After_Emboldening;
+#ifdef FT_OPTION_AUTOFIT2
+    /* XXX: undocumented hook to activate the latin2 writing system. */
+    if ( load_flags & ( 1UL << 20 ) )
+      style_options = AF_STYLE_LTN2_DFLT;
+#endif
 
-      /*
-       * We depend on the writing system (script analyzers) to supply
-       * standard widths for the script of the glyph we are looking at.  If
-       * it can't deliver, stem darkening is effectively disabled.
-       */
-      writing_system_class =
-        AF_WRITING_SYSTEM_CLASSES_GET[metrics->style_class->writing_system];
+    /*
+     * Glyphs (really code points) are assigned scripts. Script analysis is
+     * done lazily: For each glyph that passes through here, the corresponding
+     * script analyzer is called, but returns immediately if it has been run
+     * already.
+     */
+    error = af_face_globals_get_metrics( loader->globals, glyph_index,
+                                         style_options, &style_metrics );
+    if ( error )
+      goto Exit;
 
-      if ( writing_system_class->style_metrics_getstdw )
-        writing_system_class->style_metrics_getstdw( metrics,
-                                                     &stdHW,
-                                                     &stdVW );
-      else
-        goto After_Emboldening;
+    style_class = style_metrics->style_class;
+    writing_system_class =
+      AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system];
 
+    loader->metrics = style_metrics;
 
-      if ( size_changed                                               ||
-           ( stdVW > 0 && stdVW != globals->standard_vertical_width ) )
-      {
-        FT_Fixed  darken_by_font_units_x, darken_x;
+    if ( writing_system_class->style_metrics_scale )
+      writing_system_class->style_metrics_scale( style_metrics, &scaler );
+    else
+      style_metrics->scaler = scaler;
 
+    if ( writing_system_class->style_hints_init )
+    {
+      error = writing_system_class->style_hints_init( hints,
+                                                      style_metrics );
+      if ( error )
+        goto Exit;
+    }
 
-        darken_by_font_units_x =
-          af_intToFixed( af_loader_compute_darkening( loader,
-                                                      face,
-                                                      stdVW ) );
-        darken_x = FT_DivFix( FT_MulFix( darken_by_font_units_x,
-                                         face->size->metrics.x_scale ),
-                              em_ratio );
+    /*
+     * Do the main work of `af_loader_load_glyph'.  Note that we never have to
+     * deal with composite glyphs as those get loaded into
+     * FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function.  In
+     * the rare cases where FT_LOAD_NO_RECURSE is set, it implies
+     * FT_LOAD_NO_SCALE and as such the auto-hinter is never called.
+     */
+    load_flags |=  FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM |
+                   FT_LOAD_LINEAR_DESIGN;
+    load_flags &= ~FT_LOAD_RENDER;
 
-        globals->standard_vertical_width = stdVW;
-        globals->stem_darkening_for_ppem = face->size->metrics.x_ppem;
-        globals->darken_x                = af_fixedToInt( darken_x );
-      }
+    error = FT_Load_Glyph( face, glyph_index, load_flags );
 
-      if ( size_changed                                                 ||
-           ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) )
-      {
-        FT_Fixed  darken_by_font_units_y, darken_y;
-
-
-        darken_by_font_units_y =
-          af_intToFixed( af_loader_compute_darkening( loader,
-                                                      face,
-                                                      stdHW ) );
-        darken_y = FT_DivFix( FT_MulFix( darken_by_font_units_y,
-                                         face->size->metrics.y_scale ),
-                              em_ratio );
-
-        globals->standard_horizontal_width = stdHW;
-        globals->stem_darkening_for_ppem   = face->size->metrics.x_ppem;
-        globals->darken_y                  = af_fixedToInt( darken_y );
-
-        /*
-         * Scale outlines down on the Y-axis to keep them inside their blue
-         * zones.  The stronger the emboldening, the stronger the
-         * downscaling (plus heuristical padding to prevent outlines still
-         * falling out their zones due to rounding).
-         *
-         * Reason: `FT_Outline_Embolden' works by shifting the rightmost
-         * points of stems farther to the right, and topmost points farther
-         * up.  This positions points on the Y-axis outside their
-         * pre-computed blue zones and leads to distortion when applying the
-         * hints in the code further below.  Code outside this emboldening
-         * block doesn't know we are presenting it with modified outlines
-         * the analyzer didn't see!
-         *
-         * An unfortunate side effect of downscaling is that the emboldening
-         * effect is slightly decreased.  The loss becomes more pronounced
-         * versus the CFF driver at smaller sizes, e.g., at 9ppem and below.
-         */
-        globals->scale_down_factor =
-          FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ),
-                     em_size );
-      }
+    if ( error )
+      goto Exit;
 
-      FT_Outline_EmboldenXY( &slot->outline,
-                             globals->darken_x,
-                             globals->darken_y );
+    /*
+     * Apply stem darkening (emboldening) here before hints are applied to the
+     * outline.  Glyphs are scaled down proportionally to the emboldening so
+     * that curve points don't fall outside their precomputed blue zones.
+     *
+     * Any emboldening done by the font driver (e.g., the CFF driver) doesn't
+     * reach here because the autohinter loads the unprocessed glyphs in font
+     * units for analysis (functions `af_*_metrics_init_*') and then above to
+     * prepare it for the rasterizers by itself, independently of the font
+     * driver.  So emboldening must be done here, within the autohinter.
+     *
+     * All glyphs to be autohinted pass through here one by one.  The standard
+     * widths can therefore change from one glyph to the next, depending on
+     * what script a glyph is assigned to (each script has its own set of
+     * standard widths and other metrics).  The darkening amount must therefore
+     * be recomputed for each size and `standard_{vertical,horizontal}_width'
+     * change.
+     *
+     * Ignore Errors and carry on without emboldening.
+     */
+    if ( !module->no_stem_darkening )
+      af_loader_embolden_glyph_in_slot( loader, face, style_metrics );
 
-      scale_down_matrix.yy = globals->scale_down_factor;
-      FT_Outline_Transform( &slot->outline, &scale_down_matrix );
-    }
 
-  After_Emboldening:
     loader->transformed = internal->glyph_transformed;
     if ( loader->transformed )
     {
@@ -257,87 +231,100 @@
 
     switch ( slot->format )
     {
-    case FT_GLYPH_FORMAT_OUTLINE:
-      /* translate the loaded glyph when an internal transform is needed */
-      if ( loader->transformed )
-        FT_Outline_Translate( &slot->outline,
-                              loader->trans_delta.x,
-                              loader->trans_delta.y );
-
-      /* compute original horizontal phantom points (and ignore */
-      /* vertical ones)                                         */
-      loader->pp1.x = hints->x_delta;
-      loader->pp1.y = hints->y_delta;
-      loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
-                                 hints->x_scale ) + hints->x_delta;
-      loader->pp2.y = hints->y_delta;
-
-      /* be sure to check for spacing glyphs */
-      if ( slot->outline.n_points == 0 )
-        goto Hint_Metrics;
-
-      /* now load the slot image into the auto-outline and run the */
-      /* automatic hinting process                                 */
-      {
+      case FT_GLYPH_FORMAT_OUTLINE:
+        /* translate the loaded glyph when an internal transform is needed */
+        if ( loader->transformed )
+          FT_Outline_Translate( &slot->outline,
+                                loader->trans_delta.x,
+                                loader->trans_delta.y );
+
+        /* compute original horizontal phantom points (and ignore */
+        /* vertical ones)                                         */
+        loader->pp1.x = hints->x_delta;
+        loader->pp1.y = hints->y_delta;
+        loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
+                                   hints->x_scale ) + hints->x_delta;
+        loader->pp2.y = hints->y_delta;
+
+        /* be sure to check for spacing glyphs */
+        if ( slot->outline.n_points == 0 )
+          goto Hint_Metrics;
+
+        /* now load the slot image into the auto-outline and run the */
+        /* automatic hinting process                                 */
+        {
 #ifdef FT_CONFIG_OPTION_PIC
-        AF_FaceGlobals         globals = loader->globals;
+          AF_FaceGlobals         globals = loader->globals;
 #endif
-        AF_StyleClass          style_class = metrics->style_class;
-        AF_WritingSystemClass  writing_system_class =
-          AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system];
+          AF_StyleClass          style_class = style_metrics->style_class;
+          AF_WritingSystemClass  writing_system_class =
+            AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system];
 
 
-        if ( writing_system_class->style_hints_apply )
-          writing_system_class->style_hints_apply( glyph_index,
-                                                   hints,
-                                                   &gloader->base.outline,
-                                                   metrics );
-      }
+          if ( writing_system_class->style_hints_apply )
+            writing_system_class->style_hints_apply( glyph_index,
+                                                     hints,
+                                                     &gloader->base.outline,
+                                                     style_metrics );
+        }
 
-      /* we now need to adjust the metrics according to the change in */
-      /* width/positioning that occurred during the hinting process   */
-      if ( scaler->render_mode != FT_RENDER_MODE_LIGHT )
-      {
-        FT_Pos        old_rsb, old_lsb, new_lsb;
-        FT_Pos        pp1x_uh, pp2x_uh;
-        AF_AxisHints  axis  = &hints->axis[AF_DIMENSION_HORZ];
-        AF_Edge       edge1 = axis->edges;         /* leftmost edge  */
-        AF_Edge       edge2 = edge1 +
-                              axis->num_edges - 1; /* rightmost edge */
+        /* we now need to adjust the metrics according to the change in */
+        /* width/positioning that occurred during the hinting process   */
+        if ( scaler.render_mode != FT_RENDER_MODE_LIGHT )
+        {
+          FT_Pos        old_rsb, old_lsb, new_lsb;
+          FT_Pos        pp1x_uh, pp2x_uh;
+          AF_AxisHints  axis  = &hints->axis[AF_DIMENSION_HORZ];
+          AF_Edge       edge1 = axis->edges;         /* leftmost edge  */
+          AF_Edge       edge2 = edge1 +
+            axis->num_edges - 1; /* rightmost edge */
 
 
-        if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
-        {
-          old_rsb = loader->pp2.x - edge2->opos;
-          old_lsb = edge1->opos;
-          new_lsb = edge1->pos;
+          if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
+          {
+            old_rsb = loader->pp2.x - edge2->opos;
+            old_lsb = edge1->opos;
+            new_lsb = edge1->pos;
+
+            /* remember unhinted values to later account */
+            /* for rounding errors                       */
 
-          /* remember unhinted values to later account */
-          /* for rounding errors                       */
+            pp1x_uh = new_lsb    - old_lsb;
+            pp2x_uh = edge2->pos + old_rsb;
 
-          pp1x_uh = new_lsb    - old_lsb;
-          pp2x_uh = edge2->pos + old_rsb;
+            /* prefer too much space over too little space */
+            /* for very small sizes                        */
 
-          /* prefer too much space over too little space */
-          /* for very small sizes                        */
+            if ( old_lsb < 24 )
+              pp1x_uh -= 8;
 
-          if ( old_lsb < 24 )
-            pp1x_uh -= 8;
+            if ( old_rsb < 24 )
+              pp2x_uh += 8;
 
-          if ( old_rsb < 24 )
-            pp2x_uh += 8;
+            loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
+            loader->pp2.x = FT_PIX_ROUND( pp2x_uh );
 
-          loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
-          loader->pp2.x = FT_PIX_ROUND( pp2x_uh );
+            if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
+              loader->pp1.x -= 64;
 
-          if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
-            loader->pp1.x -= 64;
+            if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
+              loader->pp2.x += 64;
 
-          if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
-            loader->pp2.x += 64;
+            slot->lsb_delta = loader->pp1.x - pp1x_uh;
+            slot->rsb_delta = loader->pp2.x - pp2x_uh;
+          }
+          else
+          {
+            FT_Pos  pp1x = loader->pp1.x;
+            FT_Pos  pp2x = loader->pp2.x;
 
-          slot->lsb_delta = loader->pp1.x - pp1x_uh;
-          slot->rsb_delta = loader->pp2.x - pp2x_uh;
+
+            loader->pp1.x = FT_PIX_ROUND( pp1x );
+            loader->pp2.x = FT_PIX_ROUND( pp2x );
+
+            slot->lsb_delta = loader->pp1.x - pp1x;
+            slot->rsb_delta = loader->pp2.x - pp2x;
+          }
         }
         else
         {
@@ -345,34 +332,21 @@
           FT_Pos  pp2x = loader->pp2.x;
 
 
-          loader->pp1.x = FT_PIX_ROUND( pp1x );
-          loader->pp2.x = FT_PIX_ROUND( pp2x );
+          loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
+          loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );
 
           slot->lsb_delta = loader->pp1.x - pp1x;
           slot->rsb_delta = loader->pp2.x - pp2x;
         }
-      }
-      else
-      {
-        FT_Pos  pp1x = loader->pp1.x;
-        FT_Pos  pp2x = loader->pp2.x;
-
-
-        loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
-        loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );
-
-        slot->lsb_delta = loader->pp1.x - pp1x;
-        slot->rsb_delta = loader->pp2.x - pp2x;
-      }
 
-      break;
+        break;
 
-    default:
-      /* we don't support other formats (yet?) */
-      error = FT_THROW( Unimplemented_Feature );
+      default:
+        /* we don't support other formats (yet?) */
+        error = FT_THROW( Unimplemented_Feature );
     }
 
-  Hint_Metrics:
+Hint_Metrics:
     {
       FT_BBox    bbox;
       FT_Vector  vvector;
@@ -380,8 +354,8 @@
 
       vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
       vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
-      vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale );
-      vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale );
+      vvector.x = FT_MulFix( vvector.x, style_metrics->scaler.x_scale );
+      vvector.y = FT_MulFix( vvector.y, style_metrics->scaler.y_scale );
 
       /* transform the hinted outline if needed */
       if ( loader->transformed )
@@ -389,12 +363,12 @@
         FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
         FT_Vector_Transform( &vvector, &loader->trans_matrix );
       }
-#if 1
+
       /* we must translate our final outline by -pp1.x and compute */
       /* the new metrics                                           */
       if ( loader->pp1.x )
         FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
-#endif
+
       FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
 
       bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
@@ -413,20 +387,13 @@
       /* for mono-width fonts (like Andale, Courier, etc.) we need */
       /* to keep the original rounded advance width; ditto for     */
       /* digits if all have the same advance width                 */
-#if 0
-      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
-        slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
-      else
-        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
-                                               x_scale );
-#else
-      if ( scaler->render_mode != FT_RENDER_MODE_LIGHT                      &&
+      if ( scaler.render_mode != FT_RENDER_MODE_LIGHT                      &&
            ( FT_IS_FIXED_WIDTH( slot->face )                              ||
              ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
-               metrics->digits_have_same_width                          ) ) )
+               style_metrics->digits_have_same_width                          ) ) )
       {
         slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
-                                               metrics->scaler.x_scale );
+                                               style_metrics->scaler.x_scale );
 
         /* Set delta values to 0.  Otherwise code that uses them is */
         /* going to ruin the fixed advance width.                   */
@@ -439,106 +406,137 @@
         if ( slot->metrics.horiAdvance )
           slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
       }
-#endif
 
       slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
-                                             metrics->scaler.y_scale );
+                                             style_metrics->scaler.y_scale );
 
       slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
       slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );
 
-#if 0
-      /* reassign all outline fields except flags to protect them */
-      slot->outline.n_contours = internal->loader->base.outline.n_contours;
-      slot->outline.n_points   = internal->loader->base.outline.n_points;
-      slot->outline.points     = internal->loader->base.outline.points;
-      slot->outline.tags       = internal->loader->base.outline.tags;
-      slot->outline.contours   = internal->loader->base.outline.contours;
-#endif
-
       slot->format  = FT_GLYPH_FORMAT_OUTLINE;
     }
-
-  Exit:
+Exit:
     return error;
   }
 
 
-  /* Load a glyph. */
-
   FT_LOCAL_DEF( FT_Error )
-  af_loader_load_glyph( AF_Loader  loader,
-                        AF_Module  module,
-                        FT_Face    face,
-                        FT_UInt    gindex,
-                        FT_Int32   load_flags )
+  af_loader_embolden_glyph_in_slot( AF_Loader       loader,
+                                    FT_Face         face,
+                                    AF_StyleMetrics style_metrics )
   {
-    FT_Error      error;
-    FT_Size       size   = face->size;
-    AF_ScalerRec  scaler;
+    FT_Error  error = FT_Err_Ok;
+    FT_GlyphSlot           slot     = face->glyph;
+    AF_FaceGlobals         globals  = loader->globals;
+    AF_WritingSystemClass  writing_system_class;
 
+    FT_Pos  stdVW = 0;
+    FT_Pos  stdHW = 0;
 
-    if ( !size )
-      return FT_THROW( Invalid_Size_Handle );
+    FT_Bool  size_changed = face->size->metrics.x_ppem
+                            != globals->stem_darkening_for_ppem;
 
-    FT_ZERO( &scaler );
+    FT_Fixed  em_size  = af_intToFixed( face->units_per_EM );
+    FT_Fixed  em_ratio = FT_DivFix( af_intToFixed( 1000 ), em_size );
 
-    scaler.face    = face;
-    scaler.x_scale = size->metrics.x_scale;
-    scaler.x_delta = 0;  /* XXX: TODO: add support for sub-pixel hinting */
-    scaler.y_scale = size->metrics.y_scale;
-    scaler.y_delta = 0;  /* XXX: TODO: add support for sub-pixel hinting */
+    FT_Matrix  scale_down_matrix = { 0x10000L, 0, 0, 0x10000L };
 
-    scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
-    scaler.flags       = 0;  /* XXX: fix this */
 
-    error = af_loader_reset( loader, module, face );
-    if ( !error )
+    /* Skip stem darkening for broken fonts. */
+    if ( !face->units_per_EM )
     {
-      AF_StyleMetrics  metrics;
-      FT_UInt          options = AF_STYLE_NONE_DFLT;
+      error = FT_Err_Corrupted_Font_Header;
+      goto Exit;
+    }
 
+    /*
+     * We depend on the writing system (script analyzers) to supply standard
+     * widths for the script of the glyph we are looking at.  If it can't
+     * deliver, stem darkening is disabled.
+     */
+    writing_system_class =
+      AF_WRITING_SYSTEM_CLASSES_GET[style_metrics->style_class->writing_system];
 
-#ifdef FT_OPTION_AUTOFIT2
-      /* XXX: undocumented hook to activate the latin2 writing system */
-      if ( load_flags & ( 1UL << 20 ) )
-        options = AF_STYLE_LTN2_DFLT;
-#endif
+    if ( writing_system_class->style_metrics_getstdw )
+    {
+      writing_system_class->style_metrics_getstdw( style_metrics,
+                                                   &stdHW,
+                                                   &stdVW );
+    }
+    else
+    {
+      error = FT_Err_Unimplemented_Feature;
+      goto Exit;
+    }
 
-      error = af_face_globals_get_metrics( loader->globals, gindex,
-                                           options, &metrics );
-      if ( !error )
-      {
-#ifdef FT_CONFIG_OPTION_PIC
-        AF_FaceGlobals         globals = loader->globals;
-#endif
-        AF_StyleClass          style_class = metrics->style_class;
-        AF_WritingSystemClass  writing_system_class =
-          AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system];
 
+    if ( size_changed                                               ||
+         ( stdVW > 0 && stdVW != globals->standard_vertical_width ) )
+    {
+      FT_Fixed  darken_by_font_units_x, darken_x;
 
-        loader->metrics = metrics;
 
-        if ( writing_system_class->style_metrics_scale )
-          writing_system_class->style_metrics_scale( metrics, &scaler );
-        else
-          metrics->scaler = scaler;
+      darken_by_font_units_x =
+        af_intToFixed( af_loader_compute_darkening( loader,
+                                                    face,
+                                                    stdVW ) );
+      darken_x = FT_DivFix( FT_MulFix( darken_by_font_units_x,
+                                       face->size->metrics.x_scale ),
+                            em_ratio );
 
-        load_flags |=  FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
-        load_flags &= ~FT_LOAD_RENDER;
+      globals->standard_vertical_width = stdVW;
+      globals->stem_darkening_for_ppem = face->size->metrics.x_ppem;
+      globals->darken_x                = af_fixedToInt( darken_x );
+    }
 
-        if ( writing_system_class->style_hints_init )
-        {
-          error = writing_system_class->style_hints_init( loader->hints,
-                                                          metrics );
-          if ( error )
-            goto Exit;
-        }
+    if ( size_changed                                                 ||
+         ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) )
+    {
+      FT_Fixed  darken_by_font_units_y, darken_y;
 
-        error = af_loader_load_g( loader, &scaler, gindex, load_flags );
-      }
+
+      darken_by_font_units_y =
+        af_intToFixed( af_loader_compute_darkening( loader,
+                                                    face,
+                                                    stdHW ) );
+      darken_y = FT_DivFix( FT_MulFix( darken_by_font_units_y,
+                                       face->size->metrics.y_scale ),
+                            em_ratio );
+
+      globals->standard_horizontal_width = stdHW;
+      globals->stem_darkening_for_ppem   = face->size->metrics.x_ppem;
+      globals->darken_y                  = af_fixedToInt( darken_y );
+
+      /*
+       * Scale outlines down on the Y-axis to keep them inside their blue
+       * zones.  The stronger the emboldening, the stronger the downscaling
+       * (plus heuristical padding to prevent outlines still falling out
+       * their zones due to rounding).
+       *
+       * Reason: `FT_Outline_Embolden' works by shifting the rightmost points
+       * of stems farther to the right, and topmost points farther up.  This
+       * positions points on the Y-axis outside their pre-computed blue zones
+       * and leads to distortion when applying the hints in the code further
+       * below.  Code outside this emboldening block doesn't know we are
+       * presenting it with modified outlines the analyzer didn't see!
+       *
+       * An unfortunate side effect of downscaling is that the emboldening
+       * effect is slightly decreased.  The loss becomes more pronounced
+       * versus the CFF driver at smaller sizes, e.g., at 9ppem and below.
+       */
+      globals->scale_down_factor =
+        FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ),
+                   em_size );
     }
-  Exit:
+
+    FT_Outline_EmboldenXY( &slot->outline,
+                           globals->darken_x,
+                           globals->darken_y );
+
+    scale_down_matrix.yy = globals->scale_down_factor;
+    FT_Outline_Transform( &slot->outline, &scale_down_matrix );
+
+Exit:
     return error;
   }
 
diff --git a/src/autofit/afloader.h b/src/autofit/afloader.h
index 0062eb9..2e6f36b 100644
--- a/src/autofit/afloader.h
+++ b/src/autofit/afloader.h
@@ -75,6 +75,11 @@ FT_BEGIN_HEADER
                         FT_UInt    gindex,
                         FT_Int32   load_flags );
 
+  FT_LOCAL_DEF( FT_Error )
+  af_loader_embolden_glyph_in_slot( AF_Loader       loader,
+                                    FT_Face         face,
+                                    AF_StyleMetrics style_metrics );
+
   FT_LOCAL_DEF( FT_Int32 )
   af_loader_compute_darkening( AF_Loader  loader,
                                FT_Face    face,
-- 
2.7.4

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

Reply via email to