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.
This commit is contained in:
Werner Lemberg 2009-06-18 15:42:52 +02:00
parent 780d7e05e7
commit 7227114043
4 changed files with 118 additions and 27 deletions

View File

@ -1,3 +1,41 @@
2009-06-18 Werner Lemberg <wl@gnu.org>
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 <wl@gnu.org> 2009-06-16 Werner Lemberg <wl@gnu.org>
Improve scan conversion rules 4 and 6. Improve scan conversion rules 4 and 6.

View File

@ -318,14 +318,23 @@ FT_BEGIN_HEADER
/* elements, giving the outline's point coordinates. */ /* elements, giving the outline's point coordinates. */
/* */ /* */
/* tags :: A pointer to an array of `n_points' chars, giving */ /* tags :: A pointer to an array of `n_points' chars, giving */
/* each outline point's type. If bit~0 is unset, the */ /* each outline point's type. */
/* point is `off' the curve, i.e., a Bézier control */ /* */
/* point, while it is `on' when set. */ /* 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, */ /* Bit~1 is meaningful for `off' points only. If set, */
/* it indicates a third-order Bézier arc control point; */ /* it indicates a third-order Bézier arc control point; */
/* and a second-order control point if unset. */ /* 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 */ /* contours :: An array of `n_contours' shorts, giving the end */
/* point of each contour within the outline. For */ /* point of each contour within the outline. For */
/* example, the first contour is defined by the points */ /* example, the first contour is defined by the points */
@ -336,6 +345,12 @@ FT_BEGIN_HEADER
/* and give hints to the scan-converter and hinter on */ /* and give hints to the scan-converter and hinter on */
/* how to convert/grid-fit it. See @FT_OUTLINE_FLAGS. */ /* 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_ typedef struct FT_Outline_
{ {
short n_contours; /* number of contours in glyph */ short n_contours; /* number of contours in glyph */
@ -371,7 +386,7 @@ FT_BEGIN_HEADER
/* FT_OUTLINE_EVEN_ODD_FILL :: */ /* FT_OUTLINE_EVEN_ODD_FILL :: */
/* By default, outlines are filled using the non-zero winding rule. */ /* 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 */ /* 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 :: */ /* FT_OUTLINE_REVERSE_FILL :: */
/* By default, outside contours of an outline are oriented in */ /* By default, outside contours of an outline are oriented in */
@ -384,15 +399,17 @@ FT_BEGIN_HEADER
/* By default, the scan converter will try to detect drop-outs in */ /* By default, the scan converter will try to detect drop-outs in */
/* an outline and correct the glyph bitmap to ensure consistent */ /* an outline and correct the glyph bitmap to ensure consistent */
/* shape continuity. If set, this flag hints the scan-line */ /* 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 :: */ /* FT_OUTLINE_SMART_DROPOUTS :: */
/* Select smart dropout control. If unset, use simple dropout */ /* 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 :: */ /* FT_OUTLINE_INCLUDE_STUBS :: */
/* If set, turn pixels on for `stubs', otherwise exclude them. */ /* 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 :: */ /* FT_OUTLINE_HIGH_PRECISION :: */
/* This flag indicates that the scan-line converter should try to */ /* This flag indicates that the scan-line converter should try to */
@ -409,6 +426,13 @@ FT_BEGIN_HEADER
/* scan-converter. */ /* scan-converter. */
/* */ /* */
/* <Note> */ /* <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 */ /* Please refer to the description of the `SCANTYPE' instruction in */
/* the OpenType specification (in file `ttinst1.doc') how simple */ /* the OpenType specification (in file `ttinst1.doc') how simple */
/* drop-outs, smart drop-outs, and stubs are defined. */ /* drop-outs, smart drop-outs, and stubs are defined. */
@ -455,15 +479,17 @@ FT_BEGIN_HEADER
#define FT_CURVE_TAG( flag ) ( flag & 3 ) #define FT_CURVE_TAG( flag ) ( flag & 3 )
#define FT_CURVE_TAG_ON 1 #define FT_CURVE_TAG_ON 1
#define FT_CURVE_TAG_CONIC 0 #define FT_CURVE_TAG_CONIC 0
#define FT_CURVE_TAG_CUBIC 2 #define FT_CURVE_TAG_CUBIC 2
#define FT_CURVE_TAG_TOUCH_X 8 /* reserved for the TrueType hinter */ #define FT_CURVE_TAG_HAS_SCANMODE 4
#define FT_CURVE_TAG_TOUCH_Y 16 /* reserved for the TrueType hinter */
#define FT_CURVE_TAG_TOUCH_BOTH ( FT_CURVE_TAG_TOUCH_X | \ #define FT_CURVE_TAG_TOUCH_X 8 /* reserved for the TrueType hinter */
FT_CURVE_TAG_TOUCH_Y ) #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_On FT_CURVE_TAG_ON
#define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC #define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC

View File

@ -306,9 +306,9 @@
/* values for the `flags' bit field */ /* values for the `flags' bit field */
#define Flow_Up 0x1 #define Flow_Up 0x8
#define Overshoot_Top 0x2 #define Overshoot_Top 0x10
#define Overshoot_Bottom 0x4 #define Overshoot_Bottom 0x20
/* States of each line, arc, and profile */ /* States of each line, arc, and profile */
@ -330,8 +330,10 @@
FT_F26Dot6 X; /* current coordinate during sweep */ FT_F26Dot6 X; /* current coordinate during sweep */
PProfile link; /* link to next profile (various purposes) */ PProfile link; /* link to next profile (various purposes) */
PLong offset; /* start of profile's data in render pool */ PLong offset; /* start of profile's data in render pool */
unsigned flags; /* Bit 0: profile orientation (up/down) */ unsigned flags; /* Bit 0-2: drop-out mode */
/* Bit 1, 2: profile overshoot (top/bottom) */ /* Bit 3: profile orientation (up/down) */
/* Bit 4: is top profile? */
/* Bit 5: is bottom profile? */
long height; /* profile's height in scanlines */ long height; /* profile's height in scanlines */
long start; /* profile's starting scanline */ long start; /* profile's starting scanline */
@ -656,6 +658,7 @@
ras.cProfile->offset = ras.top; ras.cProfile->offset = ras.top;
ras.cProfile->link = (PProfile)0; ras.cProfile->link = (PProfile)0;
ras.cProfile->next = (PProfile)0; ras.cProfile->next = (PProfile)0;
ras.cProfile->flags = ras.dropOutControl;
switch ( aState ) switch ( aState )
{ {
@ -1739,7 +1742,12 @@
point = points + first; point = points + first;
tags = ras.outline.tags + 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! */ /* A contour cannot start with a cubic control point! */
if ( tag == FT_CURVE_TAG_CUBIC ) if ( tag == FT_CURVE_TAG_CUBIC )
@ -2269,9 +2277,12 @@
if ( e1 > e2 ) if ( e1 > e2 )
{ {
Int dropOutControl = left->flags & 7;
if ( e1 == e2 + ras.precision ) if ( e1 == e2 + ras.precision )
{ {
switch ( ras.dropOutControl ) switch ( dropOutControl )
{ {
case 0: /* simple drop-outs including stubs */ case 0: /* simple drop-outs including stubs */
pxl = e2; pxl = e2;
@ -2324,7 +2335,7 @@
x2 - x1 >= ras.precision_half ) ) x2 - x1 >= ras.precision_half ) )
return; return;
if ( ras.dropOutControl == 1 ) if ( dropOutControl == 1 )
pxl = e2; pxl = e2;
else else
pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
@ -2467,9 +2478,12 @@
if ( e1 > e2 ) if ( e1 > e2 )
{ {
Int dropOutControl = left->flags & 7;
if ( e1 == e2 + ras.precision ) if ( e1 == e2 + ras.precision )
{ {
switch ( ras.dropOutControl ) switch ( dropOutControl )
{ {
case 0: /* simple drop-outs including stubs */ case 0: /* simple drop-outs including stubs */
pxl = e2; pxl = e2;
@ -2497,7 +2511,7 @@
x2 - x1 >= ras.precision_half ) ) x2 - x1 >= ras.precision_half ) )
return; return;
if ( ras.dropOutControl == 1 ) if ( dropOutControl == 1 )
pxl = e2; pxl = e2;
else else
pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
@ -2723,9 +2737,12 @@
if ( e1 > e2 ) if ( e1 > e2 )
{ {
Int dropOutControl = left->flags & 7;
if ( e1 == e2 + ras.precision ) if ( e1 == e2 + ras.precision )
{ {
switch ( ras.dropOutControl ) switch ( dropOutControl )
{ {
case 0: /* simple drop-outs including stubs */ case 0: /* simple drop-outs including stubs */
e1 = e2; e1 = e2;
@ -2747,7 +2764,7 @@
if ( right->next == left && left->start == y ) if ( right->next == left && left->start == y )
return; return;
if ( ras.dropOutControl == 1 ) if ( dropOutControl == 1 )
e1 = e2; e1 = e2;
else else
e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half );
@ -2928,7 +2945,10 @@
{ {
if ( e1 > e2 || e2 == e1 + ras.precision ) 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 drop-out was detected */

View File

@ -680,6 +680,9 @@
FT_Bool debug; FT_Bool debug;
FT_Error error; FT_Error error;
FT_GlyphLoader gloader = loader->gloader;
FT_Outline current_outline = gloader->current.outline;
error = TT_Set_CodeRange( loader->exec, tt_coderange_glyph, error = TT_Set_CodeRange( loader->exec, tt_coderange_glyph,
loader->exec->glyphIns, n_ins ); loader->exec->glyphIns, n_ins );
@ -695,6 +698,10 @@
error = TT_Run_Context( loader->exec, debug ); error = TT_Run_Context( loader->exec, debug );
if ( error && loader->exec->pedantic_hinting ) if ( error && loader->exec->pedantic_hinting )
return error; 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 #endif