diff --git a/ChangeLog b/ChangeLog index 22b2a34c1..568f4d308 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,41 @@ +2009-06-18 Werner Lemberg + + 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 Improve scan conversion rules 4 and 6. diff --git a/include/freetype/ftimage.h b/include/freetype/ftimage.h index 61882e098..171f1b3a2 100644 --- a/include/freetype/ftimage.h +++ b/include/freetype/ftimage.h @@ -318,14 +318,23 @@ FT_BEGIN_HEADER /* 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 @@ FT_BEGIN_HEADER /* and give hints to the scan-converter and hinter on */ /* how to convert/grid-fit it. See @FT_OUTLINE_FLAGS. */ /* */ + /* */ + /* 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_BEGIN_HEADER /* 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 @@ FT_BEGIN_HEADER /* 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 @@ FT_BEGIN_HEADER /* scan-converter. */ /* */ /* */ + /* 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 @@ FT_BEGIN_HEADER #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 diff --git a/src/raster/ftraster.c b/src/raster/ftraster.c index c8c13f22e..4547dc9bf 100644 --- 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,7 +1742,12 @@ 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 ) @@ -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 */ diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index ad2b62e74..38023b82c 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -680,6 +680,9 @@ 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 ); @@ -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