shithub: freetype+ttf2subf

Download patch

ref: 33f5f24957397d37ff44f27098937f6e1aceed32
parent: 2b21a932f18d4887e5753a41a3303153afdbd418
author: David Turner <[email protected]>
date: Wed Aug 16 12:50:55 EDT 2006

* include/freetype/internal/ftgloadr.h,
    include/freetype/internal/tttypes.h, src/base/ftgloadr.c,
    src/base/ftobjs.c, src/truetype/ttgload.c, src/truetype/ttinterp.c,
    src/truetype/ttobjs.c: improvements to native TrueType hinting,
    this is a first try, controlled by the FIX_BYTECODE macro in
    src/truetype/ttinterp.c

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,14 @@
     * src/base/ftobjs.c (ft_validator_run): disabling function, it is
     buggy by design, so it will always return -1
 
+    * include/freetype/internal/ftgloadr.h,
+    include/freetype/internal/tttypes.h, src/base/ftgloadr.c,
+    src/base/ftobjs.c, src/truetype/ttgload.c, src/truetype/ttinterp.c,
+    src/truetype/ttobjs.c: improvements to native TrueType hinting,
+    this is a first try, controlled by the FIX_BYTECODE macro in
+    src/truetype/ttinterp.c
+
+
 2006-08-15  suzuki toshiya  <[email protected]>
 
 	* modules.cfg (BASE_EXTENSIONS): Compile in ftgxval.c by default to
--- a/include/freetype/internal/ftgloadr.h
+++ b/include/freetype/internal/ftgloadr.h
@@ -69,6 +69,7 @@
   {
     FT_Outline   outline;       /* outline             */
     FT_Vector*   extra_points;  /* extra points table  */
+    FT_Vector*   extra_points2; /* second extra points table */
     FT_UInt      num_subglyphs; /* number of subglyphs */
     FT_SubGlyph  subglyphs;     /* subglyphs           */
 
--- a/include/freetype/internal/tttypes.h
+++ b/include/freetype/internal/tttypes.h
@@ -1470,6 +1470,7 @@
 
     FT_Vector*  org;         /* original point coordinates  */
     FT_Vector*  cur;         /* current point coordinates   */
+    FT_Vector*  orus;        /* original (unscaled) point coordinates */
 
     FT_Byte*    tags;        /* current touch flags         */
     FT_UShort*  contours;    /* contour end points          */
--- a/src/base/ftgloadr.c
+++ b/src/base/ftgloadr.c
@@ -112,6 +112,8 @@
     FT_FREE( loader->base.extra_points );
     FT_FREE( loader->base.subglyphs );
 
+    loader->base.extra_points2 = NULL;
+
     loader->max_points    = 0;
     loader->max_contours  = 0;
     loader->max_subglyphs = 0;
@@ -149,8 +151,13 @@
 
     /* handle extra points table - if any */
     if ( loader->use_extra )
-      loader->current.extra_points =
-        loader->base.extra_points + base->n_points;
+    {
+      loader->current.extra_points  = loader->base.extra_points +
+                                      base->n_points;
+
+      loader->current.extra_points2 = loader->base.extra_points2 +
+                                      base->n_points;
+    }
   }
 
 
@@ -161,9 +168,12 @@
     FT_Memory  memory = loader->memory;
 
 
-    if ( !FT_NEW_ARRAY( loader->base.extra_points, loader->max_points ) )
+    if ( !FT_NEW_ARRAY( loader->base.extra_points, 2*loader->max_points ) )
     {
-      loader->use_extra = 1;
+      loader->use_extra          = 1;
+      loader->base.extra_points2 = loader->base.extra_points +
+                                   loader->max_points;
+
       FT_GlyphLoader_Adjust_Points( loader );
     }
     return error;
@@ -212,10 +222,18 @@
            FT_RENEW_ARRAY( base->tags,   old_max, new_max ) )
         goto Exit;
 
-      if ( loader->use_extra &&
-           FT_RENEW_ARRAY( loader->base.extra_points, old_max, new_max ) )
-        goto Exit;
+      if ( loader->use_extra )
+      {
+        if ( FT_RENEW_ARRAY( loader->base.extra_points, old_max*2, new_max*2 ) )
+          goto Exit;
 
+        FT_ARRAY_MOVE( loader->base.extra_points + new_max,
+                       loader->base.extra_points + old_max,
+                       old_max );
+
+        loader->base.extra_points2 = loader->base.extra_points + new_max;
+      }
+
       adjust = 1;
       loader->max_points = new_max;
     }
@@ -355,8 +373,12 @@
 
       /* do we need to copy the extra points? */
       if ( target->use_extra && source->use_extra )
+      {
         FT_ARRAY_COPY( target->base.extra_points, source->base.extra_points,
                        num_points );
+        FT_ARRAY_COPY( target->base.extra_points2, source->base.extra_points2,
+                       num_points );
+      }
 
       out->n_points   = (short)num_points;
       out->n_contours = (short)num_contours;
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -79,6 +79,7 @@
   ft_validator_run( FT_Validator  valid )
   {
     /* this function is so buggy, none should be calling it */
+    FT_UNUSED(valid);
     return -1;
   }
 
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -576,6 +576,7 @@
     zone->n_contours = (FT_Short) ( load->outline.n_contours - start_contour );
     zone->org        = load->extra_points + start_point;
     zone->cur        = load->outline.points + start_point;
+    zone->orus       = load->extra_points2 + start_point;
     zone->tags       = (FT_Byte*)load->outline.tags + start_point;
     zone->contours   = (FT_UShort*)load->outline.contours + start_contour;
     zone->first_point = (FT_UShort)start_point;
@@ -591,9 +592,6 @@
   /*    Hint the glyph using the zone prepared by the caller.  Note that   */
   /*    the zone is supposed to include four phantom points.               */
   /*                                                                       */
-#define cur_to_org( n, zone ) \
-          FT_ARRAY_COPY( (zone)->org, (zone)->cur, (n) )
-
   static FT_Error
   TT_Hint_Glyph( TT_Loader  loader,
                  FT_Bool    is_composite )
@@ -620,7 +618,7 @@
 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
     /* save original point positioin in org */
     if ( n_ins > 0 )
-      cur_to_org( zone->n_points, zone );
+      FT_ARRAY_COPY( zone->org,  zone->cur, zone->n_points );
 #endif
 
     /* round pp2 and pp4 */
@@ -732,6 +730,14 @@
 
 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
 
+    if ( IS_HINTED( loader->load_flags ) )
+    {
+      tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 );
+
+      FT_ARRAY_COPY( loader->zone.orus, loader->zone.cur,
+                     loader->zone.n_points + 4 );
+    }
+
     /* scale the glyph */
     if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
     {
@@ -755,7 +761,6 @@
 
     if ( IS_HINTED( loader->load_flags ) )
     {
-      tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 );
       loader->zone.n_points += 4;
 
       error = TT_Hint_Glyph( loader, 0 );
--- a/src/truetype/ttinterp.c
+++ b/src/truetype/ttinterp.c
@@ -16,6 +16,11 @@
 /***************************************************************************/
 
 
+/* define FIX_BYTECODE to implement the bytecode interpreter fixes needed
+ * to match Windows behaviour more accurately
+ */
+#define  FIX_BYTECODE
+
 #include <ft2build.h>
 #include FT_INTERNAL_DEBUG_H
 #include FT_INTERNAL_CALC_H
@@ -4781,7 +4786,31 @@
       if ( CUR.opcode & 1 )
         D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
       else
+      {
+#ifdef FIX_BYTECODE
+        FT_Vector  vec1, vec2;
+
+        if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
+        {
+          FT_ARRAY_COPY( CUR.twilight.orus,
+                         CUR.twilight.org,
+                         CUR.twilight.n_points );
+        }
+
+        /* get scaled orus coordinates */
+        vec1 = CUR.zp0.orus[L];
+        vec2 = CUR.zp1.orus[K];
+
+        vec1.x = TT_MULFIX( vec1.x, CUR.metrics.x_scale );
+        vec1.y = TT_MULFIX( vec1.y, CUR.metrics.y_scale );
+        vec2.x = TT_MULFIX( vec2.x, CUR.metrics.x_scale );
+        vec2.y = TT_MULFIX( vec2.y, CUR.metrics.y_scale );
+
+        D = CUR_Func_dualproj( &vec1, &vec2 );
+#else
         D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
+#endif
+      }
     }
 
     args[0] = D;
@@ -5695,8 +5724,30 @@
     /* XXX: Is there some undocumented feature while in the */
     /*      twilight zone?                                  */
 
+#ifdef FIX_BYTECODE
+    {
+      FT_Vector  vec1, vec2;
+
+      if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
+        FT_ARRAY_COPY( CUR.twilight.orus,
+                       CUR.twilight.org,
+                       CUR.twilight.n_points );
+
+      vec1 = CUR.zp1.orus[point];
+      vec2 = CUR.zp0.orus[CUR.GS.rp0];
+
+      vec1.x = TT_MULFIX( vec1.x, CUR.metrics.x_scale );
+      vec1.y = TT_MULFIX( vec1.y, CUR.metrics.y_scale );
+
+      vec2.x = TT_MULFIX( vec2.x, CUR.metrics.x_scale );
+      vec2.y = TT_MULFIX( vec2.y, CUR.metrics.y_scale );
+
+      org_dist = CUR_Func_dualproj( &vec1, &vec2 );
+    }
+#else
     org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
                                   CUR.zp0.org + CUR.GS.rp0 );
+#endif
 
     /* single width cutin test */
 
@@ -6053,7 +6104,7 @@
   {
     FT_F26Dot6  org_a, org_b, org_x,
                 cur_a, cur_b, cur_x,
-                distance;
+                distance = 0;
     FT_UShort   point;
 
     FT_UNUSED_ARG;
@@ -6065,6 +6116,22 @@
       return;
     }
 
+#ifdef FIX_BYTECODE
+   /* we need to deal in a special way with the twilight zone
+    * the easiest is simply to copy the coordinates from 'org' to 'orus'
+    * whenever someone tries to perform intersections based on some
+    * of its points.
+    *
+    * otherwise, by definition value of CUR.twilight[n] is (0,0), whatever 'n'
+    */
+    if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0 )
+    {
+      FT_ARRAY_COPY( CUR.twilight.orus,
+                     CUR.twilight.org,
+                     CUR.twilight.n_points );
+    }
+#endif /* FIX_BYTECODE */
+
     /* XXX: There are some glyphs in some braindead but popular  */
     /*      fonts out there (e.g. [aeu]grave in monotype.ttf)    */
     /*      calling IP[] with bad values of rp[12].              */
@@ -6078,8 +6145,22 @@
     }
     else
     {
+#ifdef FIX_BYTECODE
+      FT_Vector  vec1, vec2;
+
+      vec1   = CUR.zp0.orus[CUR.GS.rp1];
+      vec2   = CUR.zp1.orus[CUR.GS.rp2];
+      vec1.x = TT_MULFIX( vec1.x, CUR.metrics.x_scale );
+      vec1.y = TT_MULFIX( vec1.y, CUR.metrics.y_scale );
+      vec2.x = TT_MULFIX( vec2.x, CUR.metrics.x_scale );
+      vec2.y = TT_MULFIX( vec2.y, CUR.metrics.y_scale );
+
+      org_a = CUR_Func_dualproj( &vec1, NULL_Vector );
+      org_b = CUR_Func_dualproj( &vec2, NULL_Vector );
+#else
       org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
       org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
+#endif
 
       cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
       cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
@@ -6100,7 +6181,17 @@
       }
       else
       {
+#ifdef FIX_BYTECODE
+        FT_Vector  vec;
+
+        vec   = CUR.zp2.orus[point];
+        vec.x = TT_MULFIX( vec.x, CUR.metrics.x_scale );
+        vec.y = TT_MULFIX( vec.y, CUR.metrics.y_scale );
+
+        org_x = CUR_Func_dualproj( &vec, NULL_Vector );
+#else
         org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
+#endif
         cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
 
         if ( ( org_a <= org_b && org_x <= org_a ) ||
@@ -6113,7 +6204,7 @@
 
           distance = ( cur_b - org_b ) + ( org_x - cur_x );
 
-        else
+        else if ( org_b != org_a )
            /* note: it seems that rounding this value isn't a good */
            /*       idea (cf. width of capital `S' in Times)       */
 
@@ -6167,110 +6258,113 @@
 
 
   /* Local variables for Ins_IUP: */
-  struct  LOC_Ins_IUP
+  typedef struct
   {
     FT_Vector*  orgs;   /* original and current coordinate */
     FT_Vector*  curs;   /* arrays                          */
-  };
+    FT_Vector*  orus;
 
+  } IUP_WorkerRec, *IUP_Worker;
 
+
   static void
-  Shift( FT_UInt              p1,
-         FT_UInt              p2,
-         FT_UInt              p,
-         struct LOC_Ins_IUP*  LINK )
+  _iup_worker_shift( IUP_Worker  worker,
+                     FT_UInt     p1,
+                     FT_UInt     p2,
+                     FT_UInt     p )
   {
     FT_UInt     i;
-    FT_F26Dot6  x;
+    FT_F26Dot6  dx;
 
 
-    x = LINK->curs[p].x - LINK->orgs[p].x;
+    dx = worker->curs[p].x - worker->orgs[p].x;
+    if ( dx != 0 )
+    {
+      for ( i = p1; i < p; i++ )
+        worker->curs[i].x += dx;
 
-    for ( i = p1; i < p; i++ )
-      LINK->curs[i].x += x;
-
-    for ( i = p + 1; i <= p2; i++ )
-      LINK->curs[i].x += x;
+      for ( i = p + 1; i <= p2; i++ )
+        worker->curs[i].x += dx;
+    }
   }
 
 
   static void
-  Interp( FT_UInt              p1,
-          FT_UInt              p2,
-          FT_UInt              ref1,
-          FT_UInt              ref2,
-          struct LOC_Ins_IUP*  LINK )
+  _iup_worker_interpolate( IUP_Worker  worker,
+                           FT_UInt     p1,
+                           FT_UInt     p2,
+                           FT_UInt     ref1,
+                           FT_UInt     ref2 )
   {
     FT_UInt     i;
-    FT_F26Dot6  x, x1, x2, d1, d2;
+    FT_F26Dot6  orus1, orus2, org1, org2, delta1, delta2;
 
 
     if ( p1 > p2 )
       return;
 
-    x1 = LINK->orgs[ref1].x;
-    d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
-    x2 = LINK->orgs[ref2].x;
-    d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
+    orus1 = worker->orus[ref1].x;
+    orus2 = worker->orus[ref2].x;
 
-    if ( x1 == x2 )
+    if (orus1 > orus2)
     {
+      FT_F26Dot6  tmp_o;
+      FT_UInt     tmp_r;
+
+      tmp_o = orus1; orus1 = orus2; orus2 = tmp_o;
+      tmp_r = ref1;  ref1  = ref2;  ref2  = tmp_r;
+    }
+
+    org1   = worker->orgs[ref1].x;
+    org2   = worker->orgs[ref2].x;
+    delta1 = worker->curs[ref1].x - org1;
+    delta2 = worker->curs[ref2].x - org2;
+
+    if ( orus1 == orus2 )
+    {
+      /* simple shift of untouched points */
       for ( i = p1; i <= p2; i++ )
       {
-        x = LINK->orgs[i].x;
+        FT_F26Dot6  x = worker->orgs[i].x;
 
-        if ( x <= x1 )
-          x += d1;
+        if ( x <= org1 )
+          x += delta1;
         else
-          x += d2;
+          x += delta2;
 
-        LINK->curs[i].x = x;
+        worker->curs[i].x = x;
       }
-      return;
     }
-
-    if ( x1 < x2 )
+    else
     {
+      FT_Fixed  scale       = 0;
+      FT_Bool   scale_valid = 0;
+
+      /* interpolation */
       for ( i = p1; i <= p2; i++ )
       {
-        x = LINK->orgs[i].x;
+        FT_F26Dot6  x = worker->orgs[i].x;
 
-        if ( x <= x1 )
-          x += d1;
+        if ( x <= org1 )
+          x += delta1;
+
+        else if ( x >= org2 )
+          x += delta2;
+
         else
         {
-          if ( x >= x2 )
-            x += d2;
-          else
-            x = LINK->curs[ref1].x +
-                  TT_MULDIV( x - x1,
-                             LINK->curs[ref2].x - LINK->curs[ref1].x,
-                             x2 - x1 );
+          if ( !scale_valid )
+          {
+            scale_valid = 1;
+            scale       = TT_MULDIV( org2+delta2 - (org1+delta1), 0x10000,
+                                     orus2 - orus1 );
+          }
+
+          x = (org1 + delta1) + TT_MULFIX( worker->orus[i].x - orus1, scale );
         }
-        LINK->curs[i].x = x;
+        worker->curs[i].x = x;
       }
-      return;
     }
-
-    /* x2 < x1 */
-
-    for ( i = p1; i <= p2; i++ )
-    {
-      x = LINK->orgs[i].x;
-      if ( x <= x2 )
-        x += d2;
-      else
-      {
-        if ( x >= x1 )
-          x += d1;
-        else
-          x = LINK->curs[ref1].x +
-              TT_MULDIV( x - x1,
-                         LINK->curs[ref2].x - LINK->curs[ref1].x,
-                         x2 - x1 );
-      }
-      LINK->curs[i].x = x;
-    }
   }
 
 
@@ -6283,8 +6377,8 @@
   static void
   Ins_IUP( INS_ARG )
   {
-    struct LOC_Ins_IUP  V;
-    FT_Byte             mask;
+    IUP_WorkerRec  V;
+    FT_Byte        mask;
 
     FT_UInt   first_point;   /* first point of contour        */
     FT_UInt   end_point;     /* end point (last+1) of contour */
@@ -6303,6 +6397,7 @@
       mask   = FT_CURVE_TAG_TOUCH_X;
       V.orgs = CUR.pts.org;
       V.curs = CUR.pts.cur;
+      V.orus = CUR.pts.orus;
     }
     else
     {
@@ -6309,6 +6404,7 @@
       mask   = FT_CURVE_TAG_TOUCH_Y;
       V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
       V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
+      V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
     }
 
     contour = 0;
@@ -6334,11 +6430,11 @@
           if ( ( CUR.pts.tags[point] & mask ) != 0 )
           {
             if ( point > 0 )
-              Interp( cur_touched + 1,
-                      point - 1,
-                      cur_touched,
-                      point,
-                      &V );
+              _iup_worker_interpolate( &V,
+                                       cur_touched + 1,
+                                       point - 1,
+                                       cur_touched,
+                                       point );
             cur_touched = point;
           }
 
@@ -6346,21 +6442,21 @@
         }
 
         if ( cur_touched == first_touched )
-          Shift( first_point, end_point, cur_touched, &V );
+          _iup_worker_shift( &V, first_point, end_point, cur_touched );
         else
         {
-          Interp( (FT_UShort)( cur_touched + 1 ),
-                  end_point,
-                  cur_touched,
-                  first_touched,
-                  &V );
+          _iup_worker_interpolate( &V,
+                                   (FT_UShort)( cur_touched + 1 ),
+                                   end_point,
+                                   cur_touched,
+                                   first_touched );
 
           if ( first_touched > 0 )
-            Interp( first_point,
-                    first_touched - 1,
-                    cur_touched,
-                    first_touched,
-                    &V );
+            _iup_worker_interpolate( &V,
+                                     first_point,
+                                     first_touched - 1,
+                                     cur_touched,
+                                     first_touched );
         }
       }
       contour++;
--- a/src/truetype/ttobjs.c
+++ b/src/truetype/ttobjs.c
@@ -83,6 +83,7 @@
       FT_FREE( zone->tags );
       FT_FREE( zone->cur );
       FT_FREE( zone->org );
+      FT_FREE( zone->orus );
 
       zone->max_points   = zone->n_points   = 0;
       zone->max_contours = zone->n_contours = 0;
@@ -126,6 +127,7 @@
 
     if ( FT_NEW_ARRAY( zone->org,      maxPoints   ) ||
          FT_NEW_ARRAY( zone->cur,      maxPoints   ) ||
+         FT_NEW_ARRAY( zone->orus,     maxPoints   ) ||
          FT_NEW_ARRAY( zone->tags,     maxPoints   ) ||
          FT_NEW_ARRAY( zone->contours, maxContours ) )
     {