shithub: freetype+ttf2subf

Download patch

ref: 72271140434028186a49a5dc5925f0727559e46f
parent: 780d7e05e71635812efd3b3a19d70e2411803136
author: Werner Lemberg <[email protected]>
date: Thu Jun 18 11:42:52 EDT 2009

Fix B/W rasterization of subglyphs with different drop-out modes.

Normally, the SCANMODE instruction (if present) to set the drop-out
mode in a TrueType font is located in the `prep' table only and thus
valid for all glyphs.  However, there are fonts like `pala.ttf'
which additionally contain this instruction in the hinting code of
some glyphs (but not all).  As a result it can happen that a
composite glyph needs multiple drop-out modes for its subglyphs
since the rendering state gets reset for each subglyph.

FreeType collects the hinted outlines from all subglyphs, then it
sends the data to the rasterizer.  It also sends the drop-out mode
-- after hinting has been applied -- and here is the error: It sends
the drop-out mode of the last subglyph only; drop-out modes of all
other subglyphs are lost.

This patch fixes the problem; it adds a second, alternative
mechanism to pass the drop-out mode: For each contour, the
rasterizer now checks the first `tags' array element.  If bit 2 is
set, bits 5-7 contain the contour's drop-out mode, overriding the
global drop-out mode.

* include/freetype/ftimage.h (FT_CURVE_TAG_HAS_SCANMODE): New macro.

* src/truetype/ttgload.c (TT_Hint_Glyph): Store drop-out mode in
`tags[0]'.

* src/raster/ftraster.c (Flow_Up, Overshoot_Top, Overshoot_Bottom):
Use bits 3-5 instead of 0-2.
(New_Profile): Set the drop-out mode in the profile's `flags' field.
(Decompose_Curve): Check `tags[0]' and set `dropOutControl' if
necessary.
(Vertical_Sweep_Drop, Horizontal_Sweep_Drop,
Horizontal_Gray_Sweep_Drop, Draw_Sweep): Use the profile's drop-out
mode.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,41 @@
+2009-06-18  Werner Lemberg  <[email protected]>
+
+	Fix B/W rasterization of subglyphs with different drop-out modes.
+
+	Normally, the SCANMODE instruction (if present) to set the drop-out
+	mode in a TrueType font is located in the `prep' table only and thus
+	valid for all glyphs.  However, there are fonts like `pala.ttf'
+	which additionally contain this instruction in the hinting code of
+	some glyphs (but not all).  As a result it can happen that a
+	composite glyph needs multiple drop-out modes for its subglyphs
+	since the rendering state gets reset for each subglyph.
+
+	FreeType collects the hinted outlines from all subglyphs, then it
+	sends the data to the rasterizer.  It also sends the drop-out mode
+	-- after hinting has been applied -- and here is the error: It sends
+	the drop-out mode of the last subglyph only; drop-out modes of all
+	other subglyphs are lost.
+
+	This patch fixes the problem; it adds a second, alternative
+	mechanism to pass the drop-out mode: For each contour, the
+	rasterizer now checks the first `tags' array element.  If bit 2 is
+	set, bits 5-7 contain the contour's drop-out mode, overriding the
+	global drop-out mode.
+
+	* include/freetype/ftimage.h (FT_CURVE_TAG_HAS_SCANMODE): New macro.
+
+	* src/truetype/ttgload.c (TT_Hint_Glyph): Store drop-out mode in
+	`tags[0]'.
+
+	* src/raster/ftraster.c (Flow_Up, Overshoot_Top, Overshoot_Bottom):
+	Use bits 3-5 instead of 0-2.
+	(New_Profile): Set the drop-out mode in the profile's `flags' field.
+	(Decompose_Curve): Check `tags[0]' and set `dropOutControl' if
+	necessary.
+	(Vertical_Sweep_Drop, Horizontal_Sweep_Drop,
+	Horizontal_Gray_Sweep_Drop, Draw_Sweep): Use the profile's drop-out
+	mode.
+
 2009-06-16  Werner Lemberg  <[email protected]>
 
 	Improve scan conversion rules 4 and 6.
--- a/include/freetype/ftimage.h
+++ b/include/freetype/ftimage.h
@@ -318,14 +318,23 @@
   /*                  elements, giving the outline's point coordinates.    */
   /*                                                                       */
   /*    tags       :: A pointer to an array of `n_points' chars, giving    */
-  /*                  each outline point's type.  If bit~0 is unset, the   */
-  /*                  point is `off' the curve, i.e., a Bézier control     */
-  /*                  point, while it is `on' when set.                    */
+  /*                  each outline point's type.                           */
   /*                                                                       */
+  /*                  If bit~0 is unset, the point is `off' the curve,     */
+  /*                  i.e., a Bézier control point, while it is `on' if    */
+  /*                  set.                                                 */
+  /*                                                                       */
   /*                  Bit~1 is meaningful for `off' points only.  If set,  */
   /*                  it indicates a third-order Bézier arc control point; */
   /*                  and a second-order control point if unset.           */
   /*                                                                       */
+  /*                  If bit~2 is set, bits 5-7 contain the drop-out mode  */
+  /*                  (as defined in the OpenType specification; the value */
+  /*                  is the same as the argument to the SCANMODE          */
+  /*                  instruction).                                        */
+  /*                                                                       */
+  /*                  Bits 3 and~4 are reserved for internal purposes.     */
+  /*                                                                       */
   /*    contours   :: An array of `n_contours' shorts, giving the end      */
   /*                  point of each contour within the outline.  For       */
   /*                  example, the first contour is defined by the points  */
@@ -336,6 +345,12 @@
   /*                  and give hints to the scan-converter and hinter on   */
   /*                  how to convert/grid-fit it.  See @FT_OUTLINE_FLAGS.  */
   /*                                                                       */
+  /* <Note>                                                                */
+  /*    The B/W rasterizer only checks bit~2 in the `tags' array for the   */
+  /*    first point of each contour.  The drop-out mode as given with      */
+  /*    @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, and       */
+  /*    @FT_OUTLINE_INCLUDE_STUBS in `flags' is then overridden.           */
+  /*                                                                       */
   typedef struct  FT_Outline_
   {
     short       n_contours;      /* number of contours in glyph        */
@@ -371,7 +386,7 @@
   /*    FT_OUTLINE_EVEN_ODD_FILL ::                                        */
   /*      By default, outlines are filled using the non-zero winding rule. */
   /*      If set to 1, the outline will be filled using the even-odd fill  */
-  /*      rule (only works with the smooth raster).                        */
+  /*      rule (only works with the smooth rasterizer).                    */
   /*                                                                       */
   /*    FT_OUTLINE_REVERSE_FILL ::                                         */
   /*      By default, outside contours of an outline are oriented in       */
@@ -384,15 +399,17 @@
   /*      By default, the scan converter will try to detect drop-outs in   */
   /*      an outline and correct the glyph bitmap to ensure consistent     */
   /*      shape continuity.  If set, this flag hints the scan-line         */
-  /*      converter to ignore such cases.                                  */
+  /*      converter to ignore such cases.  See below for more information. */
   /*                                                                       */
   /*    FT_OUTLINE_SMART_DROPOUTS ::                                       */
   /*      Select smart dropout control.  If unset, use simple dropout      */
-  /*      control.  Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set.         */
+  /*      control.  Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set.  See    */
+  /*      below for more information.                                      */
   /*                                                                       */
   /*    FT_OUTLINE_INCLUDE_STUBS ::                                        */
   /*      If set, turn pixels on for `stubs', otherwise exclude them.      */
-  /*      Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set.                   */
+  /*      Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set.  See below for    */
+  /*      more information.                                                */
   /*                                                                       */
   /*    FT_OUTLINE_HIGH_PRECISION ::                                       */
   /*      This flag indicates that the scan-line converter should try to   */
@@ -409,6 +426,13 @@
   /*      scan-converter.                                                  */
   /*                                                                       */
   /* <Note>                                                                */
+  /*    The flags @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, */
+  /*    and @FT_OUTLINE_INCLUDE_STUBS are ignored by the smooth            */
+  /*    rasterizer.                                                        */
+  /*                                                                       */
+  /*    There exists a second mechanism to pass the drop-out mode to the   */
+  /*    B/W rasterizer; see the `tags' field in @FT_Outline.               */
+  /*                                                                       */
   /*    Please refer to the description of the `SCANTYPE' instruction in   */
   /*    the OpenType specification (in file `ttinst1.doc') how simple      */
   /*    drop-outs, smart drop-outs, and stubs are defined.                 */
@@ -455,15 +479,17 @@
 
 #define FT_CURVE_TAG( flag )  ( flag & 3 )
 
-#define FT_CURVE_TAG_ON           1
-#define FT_CURVE_TAG_CONIC        0
-#define FT_CURVE_TAG_CUBIC        2
+#define FT_CURVE_TAG_ON            1
+#define FT_CURVE_TAG_CONIC         0
+#define FT_CURVE_TAG_CUBIC         2
 
-#define FT_CURVE_TAG_TOUCH_X      8  /* reserved for the TrueType hinter */
-#define FT_CURVE_TAG_TOUCH_Y     16  /* reserved for the TrueType hinter */
+#define FT_CURVE_TAG_HAS_SCANMODE  4
 
-#define FT_CURVE_TAG_TOUCH_BOTH  ( FT_CURVE_TAG_TOUCH_X | \
-                                   FT_CURVE_TAG_TOUCH_Y )
+#define FT_CURVE_TAG_TOUCH_X       8  /* reserved for the TrueType hinter */
+#define FT_CURVE_TAG_TOUCH_Y      16  /* reserved for the TrueType hinter */
+
+#define FT_CURVE_TAG_TOUCH_BOTH    ( FT_CURVE_TAG_TOUCH_X | \
+                                     FT_CURVE_TAG_TOUCH_Y )
 
 #define FT_Curve_Tag_On       FT_CURVE_TAG_ON
 #define FT_Curve_Tag_Conic    FT_CURVE_TAG_CONIC
--- a/src/raster/ftraster.c
+++ b/src/raster/ftraster.c
@@ -306,9 +306,9 @@
 
 
   /* values for the `flags' bit field */
-#define Flow_Up           0x1
-#define Overshoot_Top     0x2
-#define Overshoot_Bottom  0x4
+#define Flow_Up           0x8
+#define Overshoot_Top     0x10
+#define Overshoot_Bottom  0x20
 
 
   /* States of each line, arc, and profile */
@@ -330,8 +330,10 @@
     FT_F26Dot6  X;           /* current coordinate during sweep          */
     PProfile    link;        /* link to next profile (various purposes)  */
     PLong       offset;      /* start of profile's data in render pool   */
-    unsigned    flags;       /* Bit 0: profile orientation (up/down)     */
-                             /* Bit 1, 2: profile overshoot (top/bottom) */
+    unsigned    flags;       /* Bit 0-2: drop-out mode                   */
+                             /* Bit 3: profile orientation (up/down)     */
+                             /* Bit 4: is top profile?                   */
+                             /* Bit 5: is bottom profile?                */
     long        height;      /* profile's height in scanlines            */
     long        start;       /* profile's starting scanline              */
 
@@ -656,6 +658,7 @@
     ras.cProfile->offset = ras.top;
     ras.cProfile->link   = (PProfile)0;
     ras.cProfile->next   = (PProfile)0;
+    ras.cProfile->flags  = ras.dropOutControl;
 
     switch ( aState )
     {
@@ -1739,8 +1742,13 @@
 
     point = points + first;
     tags  = ras.outline.tags + first;
-    tag   = FT_CURVE_TAG( tags[0] );
 
+    /* set scan mode if necessary */
+    if ( tags[0] & FT_CURVE_TAG_HAS_SCANMODE )
+      ras.dropOutControl = (Byte)tags[0] >> 5;
+
+    tag = FT_CURVE_TAG( tags[0] );
+
     /* A contour cannot start with a cubic control point! */
     if ( tag == FT_CURVE_TAG_CUBIC )
       goto Invalid_Outline;
@@ -2269,9 +2277,12 @@
 
     if ( e1 > e2 )
     {
+      Int  dropOutControl = left->flags & 7;
+
+
       if ( e1 == e2 + ras.precision )
       {
-        switch ( ras.dropOutControl )
+        switch ( dropOutControl )
         {
         case 0: /* simple drop-outs including stubs */
           pxl = e2;
@@ -2324,7 +2335,7 @@
                   x2 - x1 >= ras.precision_half  ) )
             return;
 
-          if ( ras.dropOutControl == 1 )
+          if ( dropOutControl == 1 )
             pxl = e2;
           else
             pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
@@ -2467,9 +2478,12 @@
 
     if ( e1 > e2 )
     {
+      Int  dropOutControl = left->flags & 7;
+
+
       if ( e1 == e2 + ras.precision )
       {
-        switch ( ras.dropOutControl )
+        switch ( dropOutControl )
         {
         case 0: /* simple drop-outs including stubs */
           pxl = e2;
@@ -2497,7 +2511,7 @@
                   x2 - x1 >= ras.precision_half  ) )
             return;
 
-          if ( ras.dropOutControl == 1 )
+          if ( dropOutControl == 1 )
             pxl = e2;
           else
             pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
@@ -2723,9 +2737,12 @@
 
     if ( e1 > e2 )
     {
+      Int  dropOutControl = left->flags & 7;
+
+
       if ( e1 == e2 + ras.precision )
       {
-        switch ( ras.dropOutControl )
+        switch ( dropOutControl )
         {
         case 0: /* simple drop-outs including stubs */
           e1 = e2;
@@ -2747,7 +2764,7 @@
           if ( right->next == left && left->start == y )
             return;
 
-          if ( ras.dropOutControl == 1 )
+          if ( dropOutControl == 1 )
             e1 = e2;
           else
             e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
@@ -2928,7 +2945,10 @@
           {
             if ( e1 > e2 || e2 == e1 + ras.precision )
             {
-              if ( ras.dropOutControl != 2 )
+              Int  dropOutControl = P_Left->flags & 7;
+
+
+              if ( dropOutControl != 2 )
               {
                 /* a drop-out was detected */
 
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -680,7 +680,10 @@
       FT_Bool   debug;
       FT_Error  error;
 
+      FT_GlyphLoader  gloader         = loader->gloader;
+      FT_Outline      current_outline = gloader->current.outline;
 
+
       error = TT_Set_CodeRange( loader->exec, tt_coderange_glyph,
                                 loader->exec->glyphIns, n_ins );
       if ( error )
@@ -695,6 +698,10 @@
       error = TT_Run_Context( loader->exec, debug );
       if ( error && loader->exec->pedantic_hinting )
         return error;
+
+      /* store drop-out mode in bits 5-7; set bit 2 also as a marker */
+      current_outline.tags[0] |=
+        ( loader->exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE;
     }
 
 #endif