Commit 2e09812c5121413fa29692a46b310983cb3de3e8

Werner Lemberg 2015-12-25T08:05:30

[autofit] Make top-to-bottom hinting work in latin auto-hinter. This improves rendering of scripts like Bengali or Devanagari. * src/autofit/afhints.c (af_axis_hints_new_edge): Add parameter to pass top-to-bottom hinting flag. This makes the function sort edges in descending vertical position. * src/autofit/afhints.c: Updated. * src/autofit/aflatin.c (af_latin_hints_compute_edges, af_latin_hint_edges): Use `top_to_bottom_hinting' flag. * src/autofit/afcjk.c (af_cjk_hints_compute_edges), src/autofit/aflatin2.c (af_latin2_hints_compute_edges): Updated.

diff --git a/ChangeLog b/ChangeLog
index 89d03ef..7b51780 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2015-12-25  Werner Lemberg  <wl@gnu.org>
+
+	[autofit] Make top-to-bottom hinting work in latin auto-hinter.
+
+	This improves rendering of scripts like Bengali or Devanagari.
+
+	* src/autofit/afhints.c (af_axis_hints_new_edge): Add parameter to
+	pass top-to-bottom hinting flag.  This makes the function sort edges
+	in descending vertical position.
+
+	* src/autofit/afhints.c: Updated.
+
+	* src/autofit/aflatin.c (af_latin_hints_compute_edges,
+	af_latin_hint_edges): Use `top_to_bottom_hinting' flag.
+
+	* src/autofit/afcjk.c (af_cjk_hints_compute_edges),
+	src/autofit/aflatin2.c (af_latin2_hints_compute_edges): Updated.
+
 2015-12-24  Werner Lemberg  <wl@gnu.org>
 
 	[autofit] Add hinting direction to `AF_ScriptClassRec'.
diff --git a/src/autofit/afcjk.c b/src/autofit/afcjk.c
index 73d75ae..247d447 100644
--- a/src/autofit/afcjk.c
+++ b/src/autofit/afcjk.c
@@ -1091,7 +1091,7 @@
         /* insert a new edge in the list and */
         /* sort according to the position    */
         error = af_axis_hints_new_edge( axis, seg->pos,
-                                        (AF_Direction)seg->dir,
+                                        (AF_Direction)seg->dir, 0,
                                         memory, &edge );
         if ( error )
           goto Exit;
diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c
index 56c8220..b85f4b3 100644
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -99,6 +99,7 @@
   af_axis_hints_new_edge( AF_AxisHints  axis,
                           FT_Int        fpos,
                           AF_Direction  dir,
+                          FT_Bool       top_to_bottom_hinting,
                           FT_Memory     memory,
                           AF_Edge      *anedge )
   {
@@ -153,7 +154,8 @@
 
     while ( edge > edges )
     {
-      if ( edge[-1].fpos < fpos )
+      if ( top_to_bottom_hinting ? ( edge[-1].fpos > fpos )
+                                 : ( edge[-1].fpos < fpos ) )
         break;
 
       /* we want the edge with same position and minor direction */
diff --git a/src/autofit/afhints.h b/src/autofit/afhints.h
index a64c7a4..eb59332 100644
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -419,6 +419,7 @@ FT_BEGIN_HEADER
   af_axis_hints_new_edge( AF_AxisHints  axis,
                           FT_Int        fpos,
                           AF_Direction  dir,
+                          FT_Bool       top_to_bottom_hinting,
                           FT_Memory     memory,
                           AF_Edge      *edge );
 
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index 9c9f370..f75bf00 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -1773,6 +1773,12 @@
     FT_Memory     memory = hints->memory;
     AF_LatinAxis  laxis  = &((AF_LatinMetrics)hints->metrics)->axis[dim];
 
+    AF_StyleClass   style_class  = hints->metrics->style_class;
+    AF_ScriptClass  script_class = AF_SCRIPT_CLASSES_GET
+                                     [style_class->script];
+
+    FT_Bool  top_to_bottom_hinting = 0;
+
     AF_Segment    segments      = axis->segments;
     AF_Segment    segment_limit = segments + axis->num_segments;
     AF_Segment    seg;
@@ -1795,6 +1801,9 @@
                                           : AF_DIR_RIGHT;
 #endif
 
+    if ( dim == AF_DIMENSION_VERT )
+      top_to_bottom_hinting = script_class->top_to_bottom_hinting;
+
     /*
      *  We ignore all segments that are less than 1 pixel in length
      *  to avoid many problems with serif fonts.  We compute the
@@ -1872,6 +1881,7 @@
         /* sort according to the position    */
         error = af_axis_hints_new_edge( axis, seg->pos,
                                         (AF_Direction)seg->dir,
+                                        top_to_bottom_hinting,
                                         memory, &edge );
         if ( error )
           goto Exit;
@@ -2558,8 +2568,14 @@
     AF_Edge       anchor     = NULL;
     FT_Int        has_serifs = 0;
 
+    AF_StyleClass   style_class  = hints->metrics->style_class;
+    AF_ScriptClass  script_class = AF_SCRIPT_CLASSES_GET
+                                     [style_class->script];
+
+    FT_Bool  top_to_bottom_hinting = 0;
+
 #ifdef FT_DEBUG_LEVEL_TRACE
-    FT_UInt       num_actions = 0;
+    FT_UInt  num_actions = 0;
 #endif
 
 
@@ -2567,6 +2583,9 @@
                 dim == AF_DIMENSION_VERT ? "horizontal" : "vertical",
                 af_style_names[hints->metrics->style_class->style] ));
 
+    if ( dim == AF_DIMENSION_VERT )
+      top_to_bottom_hinting = script_class->top_to_bottom_hinting;
+
     /* we begin by aligning all stems relative to the blue zone */
     /* if needed -- that's only for horizontal edges            */
 
@@ -2862,7 +2881,9 @@
         edge->flags  |= AF_EDGE_DONE;
         edge2->flags |= AF_EDGE_DONE;
 
-        if ( edge > edges && edge->pos < edge[-1].pos )
+        if ( edge > edges                                             &&
+             ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos )
+                                     : ( edge->pos < edge[-1].pos ) ) )
         {
 #ifdef FT_DEBUG_LEVEL_TRACE
           FT_TRACE5(( "  BOUND: edge %d (pos=%.2f) moved to %.2f\n",
@@ -3023,7 +3044,9 @@
 #endif
         edge->flags |= AF_EDGE_DONE;
 
-        if ( edge > edges && edge->pos < edge[-1].pos )
+        if ( edge > edges                                             &&
+             ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos )
+                                     : ( edge->pos < edge[-1].pos ) ) )
         {
 #ifdef FT_DEBUG_LEVEL_TRACE
           FT_TRACE5(( "  BOUND: edge %d (pos=%.2f) moved to %.2f\n",
@@ -3034,9 +3057,10 @@
           edge->pos = edge[-1].pos;
         }
 
-        if ( edge + 1 < edge_limit        &&
-             edge[1].flags & AF_EDGE_DONE &&
-             edge->pos > edge[1].pos      )
+        if ( edge + 1 < edge_limit                                   &&
+             edge[1].flags & AF_EDGE_DONE                            &&
+             ( top_to_bottom_hinting ? ( edge->pos < edge[1].pos )
+                                     : ( edge->pos > edge[1].pos ) ) )
         {
 #ifdef FT_DEBUG_LEVEL_TRACE
           FT_TRACE5(( "  BOUND: edge %d (pos=%.2f) moved to %.2f\n",
diff --git a/src/autofit/aflatin2.c b/src/autofit/aflatin2.c
index 2fb7d1d..216848a 100644
--- a/src/autofit/aflatin2.c
+++ b/src/autofit/aflatin2.c
@@ -1195,7 +1195,7 @@
 
         /* insert a new edge in the list and */
         /* sort according to the position    */
-        error = af_axis_hints_new_edge( axis, seg->pos, seg->dir,
+        error = af_axis_hints_new_edge( axis, seg->pos, seg->dir, 0,
                                         memory, &edge );
         if ( error )
           goto Exit;