shithub: freetype+ttf2subf

Download patch

ref: 8b84c9d19fe646b2aafb5d8a57d4d453cfb8966d
parent: b5a460597a4cc2a0c4f6906279aeb36dc6f94bfc
author: Werner Lemberg <[email protected]>
date: Mon Apr 27 15:40:35 EDT 2009

autohinter: Don't change digit widths if all widths are the same.
This fixes FreeDesktop bug #21197.

* src/autofit/afglobal.c (AF_DIGIT): New macro.
(af_face_globals_compute_script_coverage): Mark ASCII digits in
`glyph_scripts' array.
(af_face_globals_get_metrics): Updated.
(af_face_globals_is_digit): New function.
* src/autofit/afglobal.h: Updated.
(AF_ScriptMetricsRec): Add `digits_have_same_width' flag.

* src/autofit/aflatin.c: Include FT_ADVANCES_H.
(af_latin_metrics_check_digits): New function.
(af_latin_metrics_init): Use it.
* src/autofit/aflatin.h: Updated.
* src/autofit/afcjk.c (af_cjk_metrics_init): Updated.

* src/autofit/aflatin2.c: Similar changes as with aflatin.c.

* src/autofit/afloader.c (af_loader_load_g): Test digit width.

* docs/CHANGES: Document it.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2009-04-27  Werner Lemberg  <[email protected]>
+
+	autohinter: Don't change digit widths if all widths are the same.
+	This fixes FreeDesktop bug #21197.
+
+	* src/autofit/afglobal.c (AF_DIGIT): New macro.
+	(af_face_globals_compute_script_coverage): Mark ASCII digits in
+	`glyph_scripts' array.
+	(af_face_globals_get_metrics): Updated.
+	(af_face_globals_is_digit): New function.
+	* src/autofit/afglobal.h: Updated.
+	(AF_ScriptMetricsRec): Add `digits_have_same_width' flag.
+
+	* src/autofit/aflatin.c: Include FT_ADVANCES_H.
+	(af_latin_metrics_check_digits): New function.
+	(af_latin_metrics_init): Use it.
+	* src/autofit/aflatin.h: Updated.
+	* src/autofit/afcjk.c (af_cjk_metrics_init): Updated.
+
+	* src/autofit/aflatin2.c: Similar changes as with aflatin.c.
+
+	* src/autofit/afloader.c (af_loader_load_g): Test digit width.
+
+	* docs/CHANGES: Document it.
+
 2009-04-26  Werner Lemberg  <[email protected]>
 
 	Make ftgrays compile with _STANDALONE_ and FT_STATIC_RASTER again.
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -1,6 +1,12 @@
 CHANGES BETWEEN 2.3.10 and 2.3.9
 
-  I. IMPORTANT CHANGES
+  I. IMPORTANT BUG FIXES
+
+    - If all ASCII digits in a font have the same (unscaled) width,
+      the autohinter respects this and won't change it.
+
+
+  II. IMPORTANT CHANGES
 
     - Support for the SFNT cmap 13 table format (as defined by the new
       OpenType 1.6 specification) has been added.
--- a/src/autofit/afcjk.c
+++ b/src/autofit/afcjk.c
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Auto-fitter hinting routines for CJK script (body).                  */
 /*                                                                         */
-/*  Copyright 2006, 2007, 2008 by                                          */
+/*  Copyright 2006, 2007, 2008, 2009 by                                    */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -58,9 +58,12 @@
 
     if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
       face->charmap = NULL;
-
-    /* latin's version would suffice */
-    af_latin_metrics_init_widths( metrics, face, 0x7530 );
+    else
+    {
+      /* latin's version would suffice */
+      af_latin_metrics_init_widths( metrics, face, 0x7530 );
+      af_latin_metrics_check_digits( metrics, face );
+    }
 
     FT_Set_Charmap( face, oldmap );
 
--- a/src/autofit/afglobal.c
+++ b/src/autofit/afglobal.c
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Auto-fitter routines to compute global hinting values (body).        */
 /*                                                                         */
-/*  Copyright 2003, 2004, 2005, 2006, 2007, 2008 by                        */
+/*  Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 by                  */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -51,8 +51,10 @@
 
   /* index of default script in `af_script_classes' */
 #define AF_SCRIPT_LIST_DEFAULT  2
-  /* indicates an uncovered glyph                   */
-#define AF_SCRIPT_LIST_NONE   255
+  /* a bit mask indicating an uncovered glyph       */
+#define AF_SCRIPT_LIST_NONE     0x7F
+  /* if this flag is set, we have an ASCII digit    */
+#define AF_DIGIT                0x80
 
 
   /*
@@ -80,7 +82,7 @@
     FT_Face     face        = globals->face;
     FT_CharMap  old_charmap = face->charmap;
     FT_Byte*    gscripts    = globals->glyph_scripts;
-    FT_UInt     ss;
+    FT_UInt     ss, i;
 
 
     /* the value 255 means `uncovered glyph' */
@@ -144,6 +146,16 @@
       }
     }
 
+    /* mark ASCII digits */
+    for ( i = 0x30; i <= 0x39; i++ )
+    {
+      FT_UInt  gindex = FT_Get_Char_Index( face, i );
+
+
+      if ( gindex != 0 && gindex < globals->glyph_count )
+        gscripts[gindex] |= AF_DIGIT;
+    }
+
   Exit:
     /*
      *  By default, all uncovered glyphs are set to the latin script.
@@ -253,7 +265,7 @@
 
     gidx = script;
     if ( gidx == 0 || gidx + 1 >= script_max )
-      gidx = globals->glyph_scripts[gindex];
+      gidx = globals->glyph_scripts[gindex] & AF_SCRIPT_LIST_NONE;
 
     clazz = AF_SCRIPT_CLASSES_GET[gidx];
     if ( script == 0 )
@@ -291,6 +303,17 @@
     *ametrics = metrics;
 
     return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Bool )
+  af_face_globals_is_digit( AF_FaceGlobals  globals,
+                            FT_UInt         gindex )
+  {
+    if ( gindex < globals->glyph_count )
+      return (FT_Bool)( globals->glyph_scripts[gindex] & AF_DIGIT );
+
+    return (FT_Bool)0;
   }
 
 
--- a/src/autofit/afglobal.h
+++ b/src/autofit/afglobal.h
@@ -5,7 +5,7 @@
 /*    Auto-fitter routines to compute global hinting values                */
 /*    (specification).                                                     */
 /*                                                                         */
-/*  Copyright 2003, 2004, 2005, 2007 by                                    */
+/*  Copyright 2003, 2004, 2005, 2007, 2009 by                              */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -56,7 +56,11 @@
   FT_LOCAL( void )
   af_face_globals_free( AF_FaceGlobals  globals );
 
- /* */
+  FT_LOCAL_DEF( FT_Bool )
+  af_face_globals_is_digit( AF_FaceGlobals  globals,
+                            FT_UInt         gindex );
+
+  /* */
 
 
 FT_END_HEADER
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Auto-fitter hinting routines for latin script (body).                */
 /*                                                                         */
-/*  Copyright 2003, 2004, 2005, 2006, 2007, 2008 by                        */
+/*  Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 by                  */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -16,6 +16,8 @@
 /***************************************************************************/
 
 
+#include FT_ADVANCES_H
+
 #include "aflatin.h"
 #include "aferrors.h"
 
@@ -146,7 +148,8 @@
 #define AF_LATIN_MAX_TEST_CHARACTERS  12
 
 
-  static const char af_latin_blue_chars[AF_LATIN_MAX_BLUES][AF_LATIN_MAX_TEST_CHARACTERS+1] =
+  static const char af_latin_blue_chars[AF_LATIN_MAX_BLUES]
+                                       [AF_LATIN_MAX_TEST_CHARACTERS + 1] =
   {
     "THEZOCQS",
     "HEZLOCUS",
@@ -379,7 +382,7 @@
         blue->flags |= AF_LATIN_BLUE_TOP;
 
       /*
-       * The following flags is used later to adjust the y and x scales
+       * The following flag is used later to adjust the y and x scales
        * in order to optimize the pixel grid alignment of the top of small
        * letters.
        */
@@ -393,6 +396,52 @@
   }
 
 
+  FT_LOCAL_DEF( void )
+  af_latin_metrics_check_digits( AF_LatinMetrics  metrics,
+                                 FT_Face          face )
+  {
+    FT_UInt  i;
+    FT_Bool  started = 0, same_width = 1;
+
+
+    /* check whether all ASCII digits have the same advance width; */
+    /* digit `0' is 0x30 in all supported charmaps                 */
+    for ( i = 0x30; i <= 0x39; i++ )
+    {
+      FT_UInt   glyph_index;
+      FT_Fixed  advance, old_advance;
+
+
+      glyph_index = FT_Get_Char_Index( face, i );
+      if ( glyph_index == 0 )
+        continue;
+
+      if ( FT_Get_Advance( face, glyph_index,
+                           FT_LOAD_NO_SCALE         |
+                           FT_LOAD_NO_HINTING       |
+                           FT_LOAD_IGNORE_TRANSFORM,
+                           &advance ) )
+        continue;
+
+      if ( started )
+      {
+        if ( advance != old_advance )
+        {
+          same_width = 0;
+          break;
+        }
+      }
+      else
+      {
+        old_advance = advance;
+        started     = 1;
+      }
+    }
+
+    metrics->root.digits_have_same_width = same_width;
+  }
+
+
   FT_LOCAL_DEF( FT_Error )
   af_latin_metrics_init( AF_LatinMetrics  metrics,
                          FT_Face          face )
@@ -426,6 +475,7 @@
       /* For now, compute the standard width and height from the `o'. */
       af_latin_metrics_init_widths( metrics, face, 'o' );
       af_latin_metrics_init_blues( metrics, face );
+      af_latin_metrics_check_digits( metrics, face );
     }
 
     FT_Set_Charmap( face, oldmap );
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Auto-fitter hinting routines for latin script (specification).       */
 /*                                                                         */
-/*  Copyright 2003, 2004, 2005, 2006, 2007 by                              */
+/*  Copyright 2003, 2004, 2005, 2006, 2007, 2009 by                        */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -136,6 +136,10 @@
   af_latin_metrics_init_widths( AF_LatinMetrics  metrics,
                                 FT_Face          face,
                                 FT_ULong         charcode );
+
+  FT_LOCAL( void )
+  af_latin_metrics_check_digits( AF_LatinMetrics  metrics,
+                                 FT_Face          face );
 
 
   /*************************************************************************/
--- a/src/autofit/aflatin2.c
+++ b/src/autofit/aflatin2.c
@@ -16,6 +16,8 @@
 /***************************************************************************/
 
 
+#include FT_ADVANCES_H
+
 #include "aflatin.h"
 #include "aflatin2.h"
 #include "aferrors.h"
@@ -401,6 +403,52 @@
   }
 
 
+  FT_LOCAL_DEF( void )
+  af_latin2_metrics_check_digits( AF_LatinMetrics  metrics,
+                                  FT_Face          face )
+  {
+    FT_UInt  i;
+    FT_Bool  started = 0, same_width = 1;
+
+
+    /* check whether all ASCII digits have the same advance width; */
+    /* digit `0' is 0x30 in all supported charmaps                 */
+    for ( i = 0x30; i <= 0x39; i++ )
+    {
+      FT_UInt   glyph_index;
+      FT_Fixed  advance, old_advance;
+
+
+      glyph_index = FT_Get_Char_Index( face, i );
+      if ( glyph_index == 0 )
+        continue;
+
+      if ( FT_Get_Advance( face, glyph_index,
+                           FT_LOAD_NO_SCALE         |
+                           FT_LOAD_NO_HINTING       |
+                           FT_LOAD_IGNORE_TRANSFORM,
+                           &advance ) )
+        continue;
+
+      if ( started )
+      {
+        if ( advance != old_advance )
+        {
+          same_width = 0;
+          break;
+        }
+      }
+      else
+      {
+        old_advance = advance;
+        started     = 1;
+      }
+    }
+
+    metrics->root.digits_have_same_width = same_width;
+  }
+
+
   FT_LOCAL_DEF( FT_Error )
   af_latin2_metrics_init( AF_LatinMetrics  metrics,
                          FT_Face          face )
@@ -434,6 +482,7 @@
       /* For now, compute the standard width and height from the `o'. */
       af_latin2_metrics_init_widths( metrics, face, 'o' );
       af_latin2_metrics_init_blues( metrics, face );
+      af_latin2_metrics_check_digits( metrics, face );
     }
 
     FT_Set_Charmap( face, oldmap );
--- a/src/autofit/afloader.c
+++ b/src/autofit/afloader.c
@@ -183,9 +183,9 @@
 
         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;
+          old_rsb = loader->pp2.x - edge2->opos;
+          old_lsb = edge1->opos;
+          new_lsb = edge1->pos;
 
           /* remember unhinted values to later account */
           /* for rounding errors                       */
@@ -216,9 +216,10 @@
         }
         else
         {
-          FT_Pos   pp1x = loader->pp1.x;
-          FT_Pos   pp2x = loader->pp2.x;
+          FT_Pos  pp1x = loader->pp1.x;
+          FT_Pos  pp2x = loader->pp2.x;
 
+
           loader->pp1.x = FT_PIX_ROUND( pp1x );
           loader->pp2.x = FT_PIX_ROUND( pp2x );
 
@@ -228,9 +229,10 @@
       }
       else
       {
-        FT_Pos   pp1x = loader->pp1.x;
-        FT_Pos   pp2x = loader->pp2.x;
+        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 );
 
@@ -412,7 +414,8 @@
       slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );
 
       /* for mono-width fonts (like Andale, Courier, etc.) we need */
-      /* to keep the original rounded advance width                */
+      /* 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;
@@ -420,14 +423,10 @@
         slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                                x_scale );
 #else
-      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
+      if ( FT_IS_FIXED_WIDTH( slot->face )                              ||
+           ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
+             metrics->digits_have_same_width                          ) )
       {
-        /* non-spacing glyphs must stay as-is */
-        if ( slot->metrics.horiAdvance )
-          slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
-      }
-      else
-      {
         slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                                metrics->scaler.x_scale );
 
@@ -435,6 +434,12 @@
         /* going to ruin the fixed advance width.                   */
         slot->lsb_delta = 0;
         slot->rsb_delta = 0;
+      }
+      else
+      {
+        /* non-spacing glyphs must stay as-is */
+        if ( slot->metrics.horiAdvance )
+          slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
       }
 #endif
 
--- a/src/autofit/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -285,6 +285,7 @@
   {
     AF_ScriptClass  clazz;
     AF_ScalerRec    scaler;
+    FT_Bool         digits_have_same_width;
 
   } AF_ScriptMetricsRec, *AF_ScriptMetrics;