The correct patch file.

On Fri, 5 Oct 2018 03:50:14 +0900, Byeongsik Jeon <[email protected]> wrote:
Hi.

Sorry. missed the attachments.

[PATCH 1/2] Improve FT_Outline_Embolden for the unintended arfifacts problem (#45597):

- The mathematical background is clearly added to the patch.
- Some error situation processing is done naturally during the formula 
processing.
- At the bauhaus_256px_win7_ie9.png file, you can see that Microsoft's embolden did not properly inhibits the unintended artifacts. This patch will handled properly. - Because the strength value also affects the unintended artifacts creation, the strength formula of [PATCH 2/2] should also be used.


[PATCH 2/2] Improve FT_GlyphSlot_Embolden to match more with Microsoft Windows looks:

- The DirectWrite font rendering appears to have deleted the strange transformation from the existing GDI. For reference, the GDI matching code has not been deleted.
- "Advance" values are important to match text layouts.
- The strength value must be an integer pixel value to inhibits blurring the hinted outline.

More details are commented on the patch.

Thanks.

---
  src/base/ftoutln.c | 172 +++++++++++++++++++++++++++++++++++++++++++++
  src/base/ftsynth.c |  92 ++++++++++++++++++------
  2 files changed, 242 insertions(+), 22 deletions(-)


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

>From d66801cc5cdac37faa92d18ba7214f2828b14ee2 Mon Sep 17 00:00:00 2001
From: Byeongsik Jeon <[email protected]>
Date: Fri, 5 Oct 2018 02:14:42 +0900
Subject: [PATCH 1/2] Improve FT_Outline_Embolden for the unintended arfifacts
 problem (#45597).
To: freetype-devel <[email protected]>

FreeType-Bugs: https://savannah.nongnu.org/bugs/?45596
---
 src/base/ftoutln.c | 172 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 172 insertions(+)

diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c
index 85a469737..97d6f2c08 100644
--- a/src/base/ftoutln.c
+++ b/src/base/ftoutln.c
@@ -892,6 +892,7 @@
 
   /* documentation is in ftoutln.h */
 
+#if 0
   FT_EXPORT_DEF( FT_Error )
   FT_Outline_EmboldenXY( FT_Outline*  outline,
                          FT_Pos       xstrength,
@@ -1023,7 +1024,178 @@
 
     return FT_Err_Ok;
   }
+#endif
+
+
+  /*
+    --->----------------->------------>-----------> shift
+                A            /|\                  /
+                          di  |                  /
+                              |                 /
+                              |                /
+   ->------------>-----------> ----   do      /
+                     in      /     -----     /
+                            /           --->/
+                           /               /
+                      out /               /
+                         /               /
+                        /             B /
+                       /               /
+                      /               /
+                    |/_             |/_
+
+  assume one strength:
+    ( strength.x, strength.y ) = ( strength, strength )
+
+  normalized vector i, o :
+    i =  in /  |in| = ( i.x, i.y ) , i.x ^2 + i.y ^2 = 1
+    o = out / |out| = ( o.x, o.y ) , o.x ^2 + o.y ^2 = 1
+
+  vector di, do :
+    -90 degree rotate(truetype outline) from in, out vector.
+    and scale to strength.  |di| = |do| = strength.
+
+    di = ( -i.y * strength, i.x * strength )
+    do = ( -o.y * strength, o.x * strength )
+
+  line equation of A, B:
+    i.y * ( x - di.x ) = i.x * ( y - di.y )
+    o.y * ( x - do.x ) = o.x * ( y - do.y )
+
+  intersection of A, B == shift.
+
+  two coalition equation solution:
+    det = i.y * o.x - i.x * o.y , det != 0
+    shift.x = strength * ( i.x - o.x ) / det
+    shift.y = strength * ( i.y - o.y ) / det
+
+  two strength case:
+    introduced equation with a reasonable radical attempt.
+
+    det = i.y * o.x - i.x * o.y  , det != 0
+    shift.x = strength.x * ( i.x - o.x ) / det
+    shift.y = strength.y * ( i.y - o.y ) / det
+
+    This simple expression produces good results.
+    There is a more rigorous expression, but it is more complicated.
+
+  For postscript outline: ( -shift.x, -shift.y )
+
+  det == 0 case:
+     i.x == i.y == 0, or
+     o.x == o.y == 0, or
+     abs( gradient i ) == abs( gradient o )
+
+   */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_EmboldenXY( FT_Outline* outline,
+                         FT_Pos      xstrength,
+                         FT_Pos      ystrength )
+  {
+    FT_Vector*      points;
+    FT_Orientation  orientation;
+    FT_Vector       strength, shift, in, out, anchor;
+    FT_Int          c, n_first, n_last, n_head, n_prev, n_tail, n_anchor;
+    FT_Fixed        det;
+
+    if ( !outline ) return FT_THROW( Invalid_Outline );
+
+    strength.x = xstrength / 2;
+    strength.y = ystrength / 2;
+    if ( strength.x == 0 && strength.y == 0 ) return FT_Err_Ok;
+
+    orientation = FT_Outline_Get_Orientation( outline );
+    if ( orientation == FT_ORIENTATION_NONE )
+    {
+      if ( outline->n_contours ) return FT_THROW( Invalid_Argument );
+      else return FT_Err_Ok;
+    }
+
+    points = outline->points;
 
+    for ( c = n_first = 0; c < outline->n_contours; c++, n_first = n_last + 1 )
+    {
+      n_prev = n_last = outline->contours[c];
+      n_anchor = n_tail = -1;
+      in.x = in.y = anchor.x = anchor.y = 0;
+
+      /* Find the first corner type segment */
+      for ( n_head = n_first; n_head <= n_last; n_head++)
+      {
+        out.x = points[n_head].x - points[n_prev].x;
+        out.y = points[n_head].y - points[n_prev].y;
+        FT_Vector_NormLen( &out ); /* normalize */
+
+        det = FT_MulFix( in.y, out.x ) - FT_MulFix( in.x, out.y );
+        if ( det != 0 )
+        {
+          anchor = in = out;
+          n_anchor = n_tail = n_head;
+          break;
+        }
+
+        in = out;
+        n_prev = n_head;
+      }
+      if ( n_anchor == -1 ) continue;
+
+      do
+      {
+        n_prev = n_head;
+        n_head = ( n_head < n_last )? n_head + 1 : n_first;
+        if ( n_head != n_anchor )
+        {
+          out.x = points[n_head].x - points[n_prev].x;
+          out.y = points[n_head].y - points[n_prev].y;
+          FT_Vector_NormLen( &out ); /* normalize */
+        }
+        else
+          out = anchor;
+
+        /* The shift vector is only calculated from the corner type segment.
+           Other points -- zero length segment, forward straight segment,
+           wrong forward and backward mixed straight segment -- use this
+           shift vector as it is. Note the "in.x * out.y - in.y * out.x".
+
+           wrong forward and backward mixed straight segment:
+             one of the causes of unintended artifact generation.
+         */
+        det = FT_MulFix( in.y, out.x ) - FT_MulFix( in.x, out.y );
+        if ( det == 0 ) continue;
+
+        shift.x = FT_MulDiv( strength.x, in.x - out.x, det );
+        shift.y = FT_MulDiv( strength.y, in.y - out.y, det );
+
+        /* The large shift value creates a cross point, which appears
+           as one of the artifacts. The shift value limitation inhibits
+           the occurrence of artifacts. */
+        shift.x = FT_MAX( FT_MIN( shift.x, strength.x ), -strength.x );
+        shift.y = FT_MAX( FT_MIN( shift.y, strength.y ), -strength.y );
+
+        if ( orientation != FT_ORIENTATION_TRUETYPE )
+        {
+          shift.x = -shift.x;
+          shift.y = -shift.y;
+        }
+
+        while ( n_tail != n_head )
+        {
+          /* left and bottom side are unchanged.
+             grid aligned when using integer pixel {x,y}strength. */
+          points[n_tail].x += strength.x + shift.x;
+          points[n_tail].y += strength.y + shift.y;
+
+          n_tail = ( n_tail < n_last )? n_tail + 1 : n_first;
+        }
+
+        in = out;
+
+      } while ( n_head != n_anchor );
+    }
+
+    return FT_Err_Ok;
+  }
 
   /* documentation is in ftoutln.h */
 
-- 
2.19.0

>From 4b27437b7f455cd0da0892b33357bf52e2eaa42d Mon Sep 17 00:00:00 2001
From: Byeongsik Jeon <[email protected]>
Date: Fri, 5 Oct 2018 02:19:02 +0900
Subject: [PATCH 2/2] Improve FT_GlyphSlot_Embolden to match more with
 Microsoft Windows looks.
To: freetype-devel <[email protected]>

---
 src/base/ftsynth.c | 92 +++++++++++++++++++++++++++++++++++-----------
 1 file changed, 70 insertions(+), 22 deletions(-)

diff --git a/src/base/ftsynth.c b/src/base/ftsynth.c
index ec7b93510..7d599c118 100644
--- a/src/base/ftsynth.c
+++ b/src/base/ftsynth.c
@@ -22,6 +22,7 @@
 #include FT_INTERNAL_OBJECTS_H
 #include FT_OUTLINE_H
 #include FT_BITMAP_H
+#include FT_TRUETYPE_TABLES_H
 
 
   /**************************************************************************
@@ -92,7 +93,7 @@
     FT_Library  library;
     FT_Face     face;
     FT_Error    error;
-    FT_Pos      xstr, ystr;
+    FT_Pos      xstr, ystr, ppem;
 
 
     if ( !slot )
@@ -105,22 +106,68 @@
          slot->format != FT_GLYPH_FORMAT_BITMAP  )
       return;
 
-    /* some reasonable strength */
-    xstr = FT_MulFix( face->units_per_EM,
-                      face->size->metrics.y_scale ) / 24;
-    ystr = xstr;
+    /* the value that matches the MS Windows embolden looks.
+       the larger strength value, the more unintended artifacts increase.
+       using the integer pixel strength inhibits the blurred outlines.
+     */
+    ppem = face->size->metrics.y_ppem;
+    ystr = (( ppem - 1 ) / 50 ) << 6;
+    xstr = ystr + 64;
+
+    /* match to the MS.
+       the important factor that reduces the text layout difference. */
+    slot->metrics.horiAdvance += 1 << 6;
+    slot->linearHoriAdvance   += 1 << 16;
 
     if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
-      FT_Outline_EmboldenXY( &slot->outline, xstr, ystr );
+    {
+      error = FT_Outline_EmboldenXY( &slot->outline, xstr, ystr);
+      if ( error )
+        return;
+#if 1
+      /* MS Windows DirectWrite looks. */
+
+      slot->metrics.width        += xstr;
+      slot->metrics.height       += ystr;
+      slot->metrics.horiBearingY += ystr;
+#else
+      /* MS Windows GDI looks. */
 
+      if ( ystr != 0 ) /* ppem > 50px */
+      {
+        TT_Header *head_table;
+        FT_Matrix scale = { 1 << 16, 0, 0, 1 << 16 };
+
+        /* Elboldened EM square box only increase the width of one pixel.
+           ( ppem, ppem ) -> embolden -> scale -> ( ppem + 1px, ppem )
+
+           ( ppem + xstr ) * scale.xx = ppem + 1px
+           ( ppem + ystr ) * scale.yy = ppem
+         */
+        ppem = ppem << 6;
+        scale.xx = FT_MulDiv( 1 << 16, ppem + 64, ppem + xstr );
+        scale.yy = FT_MulDiv( 1 << 16, ppem     , ppem + ystr );
+        FT_Outline_Transform( &slot->outline, &scale );
+
+        /* Undocumented behavior in truetype spec. */
+        head_table = FT_Get_Sfnt_Table( face, FT_SFNT_HEAD );
+        if ( head_table && head_table->Flags & ( 1 << 4 | 1 << 2 ) )
+          slot->metrics.horiAdvance =
+            FT_MulFix( slot->metrics.horiAdvance, scale.xx );
+      }
+
+      {
+        FT_BBox bbox;
+        FT_Outline_Get_CBox( &slot->outline, &bbox );
+        slot->metrics.width        = bbox.xMax - bbox.xMin;
+        slot->metrics.height       = bbox.yMax - bbox.yMin;
+        slot->metrics.horiBearingX = bbox.xMin;
+        slot->metrics.horiBearingY = bbox.yMax;
+      }
+#endif
+    }
     else /* slot->format == FT_GLYPH_FORMAT_BITMAP */
     {
-      /* round to full pixels */
-      xstr &= ~63;
-      if ( xstr == 0 )
-        xstr = 1 << 6;
-      ystr &= ~63;
-
       /*
        * XXX: overflow check for 16-bit system, for compatibility
        *      with FT_GlyphSlot_Embolden() since FreeType 2.1.10.
@@ -140,23 +187,24 @@
       error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr );
       if ( error )
         return;
+
+      slot->metrics.width        += xstr;
+      slot->metrics.height       += ystr;
+      slot->metrics.horiBearingY += ystr;
+
+      /* XXX: 16-bit overflow case must be excluded before here */
+      slot->bitmap_top += (FT_Int)( ystr >> 6 );
     }
 
+    /* XXX: FT_Set_Transform, FT_GlyphSlot_Embolden combination can
+            produce different results from intention. Recommend the
+            FT_Outline_Transform and a manual metrics modification.
+     */
     if ( slot->advance.x )
       slot->advance.x += xstr;
 
     if ( slot->advance.y )
       slot->advance.y += ystr;
-
-    slot->metrics.width        += xstr;
-    slot->metrics.height       += ystr;
-    slot->metrics.horiAdvance  += xstr;
-    slot->metrics.vertAdvance  += ystr;
-    slot->metrics.horiBearingY += ystr;
-
-    /* XXX: 16-bit overflow case must be excluded before here */
-    if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
-      slot->bitmap_top += (FT_Int)( ystr >> 6 );
   }
 
 
-- 
2.19.0

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

Reply via email to