Commit 032e23aab9cee8329554d30c0747549a4ca1e4ae

David Turner 2003-01-30T14:57:38

improvements to the Postscript hinter

diff --git a/src/pshinter/pshalgo3.c b/src/pshinter/pshalgo3.c
index 12a0f16..39e9ca1 100644
--- a/src/pshinter/pshalgo3.c
+++ b/src/pshinter/pshalgo3.c
@@ -456,7 +456,9 @@
         return;
       }
 
-      /* perform stem snapping when requested */
+     /* perform stem snapping when requested - this is necessary
+      * for monochrome and LCD hinting modes only
+      */
       do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
                     ( dimension == 1 && glyph->do_vert_snapping );
 
@@ -516,14 +518,24 @@
           hint->cur_pos = pos;
           hint->cur_len = fit_len;
 
+#if 0          
+         /* stem adjustment tries to snap stem widths to standard
+          * ones. this is important to prevent unpleasant rounding
+          * artefacts...
+          */
           if ( glyph->do_stem_adjust )
           {
             if ( len <= 64 )
             {
-              /* the stem is less than one pixel, we will center it */
-              /* around the nearest pixel center                    */
-              /*                                                    */
+             /* the stem is less than one pixel, we will center it
+              * around the nearest pixel center
+              */
+#if 1
+              pos = ( pos + (len >> 1) ) & -64;
+#else
+             /* this seems to be a bug !! */
               pos = ( pos + ( (len >> 1) & -64 ) );
+#endif        
               len = 64;
             }
             else
@@ -531,6 +543,7 @@
               len = psh3_dimension_quantize_len( dim, len, 0 );
             }
           }
+#endif /* 0 */
 
           /* now that we have a good hinted stem width, try to position */
           /* the stem along a pixel grid integer coordinate             */
@@ -541,7 +554,7 @@
 
       if ( do_snapping )
       {
-        pos = hint->cur_pos;
+        pos = hint->cur_pos;                   
         len = hint->cur_len;
 
         if ( len < 64 )
@@ -587,6 +600,186 @@
   }
 
 
+ /*
+  *  A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT)
+  *  of stems
+  */
+  static void
+  psh3_hint_align_light( PSH3_Hint    hint,
+                         PSH_Globals  globals,
+                         FT_Int       dimension,
+                         PSH3_Glyph   glyph )
+  {
+    PSH_Dimension  dim   = &globals->dimension[dimension];
+    FT_Fixed       scale = dim->scale_mult;
+    FT_Fixed       delta = dim->scale_delta;
+
+
+    if ( !psh3_hint_is_fitted(hint) )
+    {
+      FT_Pos  pos = FT_MulFix( hint->org_pos, scale ) + delta;
+      FT_Pos  len = FT_MulFix( hint->org_len, scale );
+
+      FT_Pos  fit_center;
+      FT_Pos  fit_len;
+
+      PSH_AlignmentRec  align;
+
+      /* ignore stem alignments when requested through the hint flags */
+      if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
+           ( dimension == 1 && !glyph->do_vert_hints ) )
+      {
+        hint->cur_pos = pos;
+        hint->cur_len = len;
+
+        psh3_hint_set_fitted( hint );
+        return;
+      }
+
+      fit_len = len;
+
+      hint->cur_len = fit_len;
+
+      /* check blue zones for horizontal stems */
+      align.align = PSH_BLUE_ALIGN_NONE;
+      align.align_bot = align.align_top = 0;
+
+      if ( dimension == 1 )
+        psh_blues_snap_stem( &globals->blues,
+                             hint->org_pos + hint->org_len,
+                             hint->org_pos,
+                             &align );
+
+      switch ( align.align )
+      {
+      case PSH_BLUE_ALIGN_TOP:
+        /* the top of the stem is aligned against a blue zone */
+        hint->cur_pos = align.align_top - fit_len;
+        break;
+
+      case PSH_BLUE_ALIGN_BOT:
+        /* the bottom of the stem is aligned against a blue zone */
+        hint->cur_pos = align.align_bot;
+        break;
+
+      case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
+        /* both edges of the stem are aligned against blue zones */
+        hint->cur_pos = align.align_bot;
+        hint->cur_len = align.align_top - align.align_bot;
+        break;
+
+      default:
+        {
+          PSH3_Hint  parent = hint->parent;
+
+
+          if ( parent )
+          {
+            FT_Pos  par_org_center, par_cur_center;
+            FT_Pos  cur_org_center, cur_delta;
+
+
+            /* ensure that parent is already fitted */
+            if ( !psh3_hint_is_fitted( parent ) )
+              psh3_hint_align_light( parent, globals, dimension, glyph );
+
+            par_org_center = parent->org_pos + ( parent->org_len / 2);
+            par_cur_center = parent->cur_pos + ( parent->cur_len / 2);
+            cur_org_center = hint->org_pos   + ( hint->org_len   / 2);
+
+            cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
+            pos       = par_cur_center + cur_delta - ( len >> 1 );
+          }
+
+         /* Stems less than one pixel wide are easy - we want to
+          * make them as dark as possible, so they must fall within
+          * one pixel. If the stem is split between two pixels
+          * then snap the edge that is nearer to the pixel boundary
+          * to the pixel boundary
+          */
+          if (len <= 64)
+          {
+            if ( ( pos + len + 63 ) / 64  != pos / 64 + 1 )
+              pos += psh3_hint_snap_stem_side_delta ( pos, len );
+          }
+         /* Position stems other to minimize the amount of mid-grays.
+          * There are, in general, two positions that do this,
+          * illustrated as A) and B) below.
+          *
+          *   +                   +                   +                   +
+          *
+          * A)             |--------------------------------|
+          * B)   |--------------------------------|
+          * C)       |--------------------------------|
+          *
+          * Position A) (split the excess stem equally) should be better
+          * for stems of width N + f where f < 0.5
+          *
+          * Position B) (split the deficiency equally) should be better
+          * for stems of width N + f where f > 0.5
+          *
+          * It turns out though that minimizing the total number of lit
+          * pixels is also important, so position C), with one edge
+          * aligned with a pixel boundary is actually preferable
+          * to A). There are also more possibile positions for C) than
+          * for A) or B), so it involves less distortion of the overall
+          * character shape.
+          */
+          else /* len > 64 */
+          {
+            FT_Fixed frac_len = len & 63;
+            FT_Fixed center = pos + ( len >> 1 );
+            FT_Fixed delta_a, delta_b;
+
+            if ( ( len / 64 ) & 1 )
+            {
+              delta_a = ( center & -64 ) + 32 - center;
+              delta_b = ( ( center + 32 ) & - 64 ) - center;
+            }
+            else
+            {
+              delta_a = ( ( center + 32 ) & - 64 ) - center;
+              delta_b = ( center & -64 ) + 32 - center;
+            }
+
+           /* We choose between B) and C) above based on the amount
+            * of fractinal stem width; for small amounts, choose
+            * C) always, for large amounts, B) always, and inbetween,
+            * pick whichever one involves less stem movement.
+            */
+            if (frac_len < 32)
+            {
+              pos += psh3_hint_snap_stem_side_delta ( pos, len );
+            }
+            else if (frac_len < 48)
+            {
+              FT_Fixed side_delta = psh3_hint_snap_stem_side_delta ( pos, len );
+
+              if ( ABS( side_delta ) < ABS( delta_b ) )
+                pos += side_delta;
+              else
+                pos += delta_b;
+            }
+            else
+            {
+              pos += delta_b;
+            }
+          }
+
+          hint->cur_pos = pos;
+        }
+      }  /* switch */
+
+      psh3_hint_set_fitted( hint );
+
+#ifdef DEBUG_HINTER
+      if ( ps3_debug_hint_func )
+        ps3_debug_hint_func( hint, dimension );
+#endif
+    }
+  }
+
+
   static void
   psh3_hint_table_align_hints( PSH3_Hint_Table  table,
                                PSH_Globals      globals,