Enable access to the various dropout rules of the B&W rasterizer.

Pass dropout rules from the TT bytecode interpreter to the
rasterizer; temporarily this is enabled only if
`USE_SCAN_CONVERSION_RULES' is defined.

* include/freetype/ftimage.h (FT_OUTLINE_SMART_DROPOUTS,
FT_OUTLINE_EXCLUDE_STUBS): New flags for for FT_Outline.

* src/raster/ftraster.c (Vertical_Sweep_Drop, Horizontal_Sweep_Drop,
Horizontal_Gray_Sweep_Drop): Use same mode numbers as given in the
OpenType specification.
Fix mode 4 computation.
(Render_Glyph, Render_Gray_Glyph): Handle new outline flags.

* src/truetype/ttgload.c (TT_Load_Glyph)
[USE_SCAN_CONVERSION_RULES]: Convert scan conversion mode to
FT_OUTLINE_XXX flags.

* src/truetype/ttinterp.c (Ins_SCANCTRL): Enable ppem check.
This commit is contained in:
Werner Lemberg 2008-06-22 13:40:08 +00:00
parent c91dfa39e8
commit 5df5dbb722
6 changed files with 293 additions and 171 deletions

View File

@ -1,3 +1,25 @@
2008-06-21 Werner Lemberg <wl@gnu.org>
Enable access to the various dropout rules of the B&W rasterizer.
Pass dropout rules from the TT bytecode interpreter to the
rasterizer; temporarily this is enabled only if
`USE_SCAN_CONVERSION_RULES' is defined.
* include/freetype/ftimage.h (FT_OUTLINE_SMART_DROPOUTS,
FT_OUTLINE_EXCLUDE_STUBS): New flags for for FT_Outline.
* src/raster/ftraster.c (Vertical_Sweep_Drop, Horizontal_Sweep_Drop,
Horizontal_Gray_Sweep_Drop): Use same mode numbers as given in the
OpenType specification.
Fix mode 4 computation.
(Render_Glyph, Render_Gray_Glyph): Handle new outline flags.
* src/truetype/ttgload.c (TT_Load_Glyph)
[USE_SCAN_CONVERSION_RULES]: Convert scan conversion mode to
FT_OUTLINE_XXX flags.
* src/truetype/ttinterp.c (Ins_SCANCTRL): Enable ppem check.
2008-06-19 Werner Lemberg <wl@gnu.org>
* src/cff/cffobjs.c (cff_face_init): Compute final

View File

@ -352,67 +352,73 @@ FT_BEGIN_HEADER
/*************************************************************************/
/* */
/* <Enum> */
/* FT_OUTLINE_FLAGS */
/* FT_OUTLINE_FLAGS */
/* */
/* <Description> */
/* A list of bit-field constants use for the flags in an outline's */
/* `flags' field. */
/* */
/* <Values> */
/* FT_OUTLINE_NONE :: Value 0 is reserved. */
/* FT_OUTLINE_NONE :: */
/* Value 0 is reserved. */
/* */
/* FT_OUTLINE_OWNER :: If set, this flag indicates that the */
/* outline's field arrays (i.e., */
/* `points', `flags' & `contours') are */
/* `owned' by the outline object, and */
/* should thus be freed when it is */
/* destroyed. */
/* FT_OUTLINE_OWNER :: */
/* If set, this flag indicates that the outline's field arrays */
/* (i.e., `points', `flags', and `contours') are `owned' by the */
/* outline object, and should thus be freed when it is destroyed. */
/* */
/* 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). */
/* 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). */
/* */
/* FT_OUTLINE_REVERSE_FILL :: By default, outside contours of an */
/* outline are oriented in clock-wise */
/* direction, as defined in the TrueType */
/* specification. This flag is set if */
/* the outline uses the opposite */
/* direction (typically for Type 1 */
/* fonts). This flag is ignored by the */
/* scan-converter. */
/* FT_OUTLINE_REVERSE_FILL :: */
/* By default, outside contours of an outline are oriented in */
/* clock-wise direction, as defined in the TrueType specification. */
/* This flag is set if the outline uses the opposite direction */
/* (typically for Type 1 fonts). This flag is ignored by the scan */
/* converter. */
/* */
/* FT_OUTLINE_IGNORE_DROPOUTS :: 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. */
/* FT_OUTLINE_IGNORE_DROPOUTS :: */
/* 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. */
/* */
/* FT_OUTLINE_HIGH_PRECISION :: This flag indicates that the */
/* scan-line converter should try to */
/* convert this outline to bitmaps with */
/* the highest possible quality. It is */
/* typically set for small character */
/* sizes. Note that this is only a */
/* hint, that might be completely */
/* ignored by a given scan-converter. */
/* FT_OUTLINE_SMART_DROPOUTS :: */
/* Select smart dropout control. If unset, use simple dropout */
/* control. Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set. */
/* */
/* FT_OUTLINE_SINGLE_PASS :: This flag is set to force a given */
/* scan-converter to only use a single */
/* pass over the outline to render a */
/* bitmap glyph image. Normally, it is */
/* set for very large character sizes. */
/* It is only a hint, that might be */
/* completely ignored by a given */
/* scan-converter. */
/* FT_OUTLINE_INCLUDE_STUBS :: */
/* If set, turn pixels on for `stubs', otherwise exclude them. */
/* Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set. */
/* */
/* FT_OUTLINE_HIGH_PRECISION :: */
/* This flag indicates that the scan-line converter should try to */
/* convert this outline to bitmaps with the highest possible */
/* quality. It is typically set for small character sizes. Note */
/* that this is only a hint that might be completely ignored by a */
/* given scan-converter. */
/* */
/* FT_OUTLINE_SINGLE_PASS :: */
/* This flag is set to force a given scan-converter to only use a */
/* single pass over the outline to render a bitmap glyph image. */
/* Normally, it is set for very large character sizes. It is only */
/* a hint that might be completely ignored by a given */
/* scan-converter. */
/* */
/* <Note> */
/* 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. */
/* */
#define FT_OUTLINE_NONE 0x0
#define FT_OUTLINE_OWNER 0x1
#define FT_OUTLINE_EVEN_ODD_FILL 0x2
#define FT_OUTLINE_REVERSE_FILL 0x4
#define FT_OUTLINE_IGNORE_DROPOUTS 0x8
#define FT_OUTLINE_SMART_DROPOUTS 0x10
#define FT_OUTLINE_INCLUDE_STUBS 0x20
#define FT_OUTLINE_HIGH_PRECISION 0x100
#define FT_OUTLINE_SINGLE_PASS 0x200

View File

@ -67,11 +67,11 @@ FT_BEGIN_HEADER
typedef struct FT_GlyphLoadRec_
{
FT_Outline outline; /* outline */
FT_Vector* extra_points; /* extra points table */
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 */
FT_UInt num_subglyphs; /* number of subglyphs */
FT_SubGlyph subglyphs; /* subglyphs */
} FT_GlyphLoadRec, *FT_GlyphLoad;

View File

@ -2150,8 +2150,10 @@ static const char count_table[256] =
f1 = (Byte) ( 0xFF >> ( e1 & 7 ) );
f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) );
if ( ras.gray_min_x > c1 ) ras.gray_min_x = (short)c1;
if ( ras.gray_max_x < c2 ) ras.gray_max_x = (short)c2;
if ( ras.gray_min_x > c1 )
ras.gray_min_x = (short)c1;
if ( ras.gray_max_x < c2 )
ras.gray_max_x = (short)c2;
target = ras.bTarget + ras.traceOfs + c1;
c2 -= c1;
@ -2184,14 +2186,43 @@ static const char count_table[256] =
PProfile left,
PProfile right )
{
Long e1, e2;
Long e1, e2, pxl;
Short c1, f1;
/* Drop-out control */
e1 = CEILING( x1 );
e2 = FLOOR ( x2 );
/* e2 x2 x1 e1 */
/* */
/* ^ | */
/* | | */
/* +-------------+---------------------+------------+ */
/* | | */
/* | v */
/* */
/* pixel contour contour pixel */
/* center center */
/* drop-out mode scan conversion rules (as defined in OpenType) */
/* --------------------------------------------------------------- */
/* 0 1, 2, 3 */
/* 1 1, 2, 4 */
/* 2 1, 2 */
/* 3 same as mode 2 */
/* 4 1, 2, 5 */
/* 5 1, 2, 6 */
/* 6, 7 same as mode 2 */
/* FIXXXME: The specification doesn't discuss the case where the */
/* intersections degenerate to a single point. */
#if 0
if ( x1 == x2 )
return;
#endif
e1 = CEILING( x1 );
e2 = FLOOR ( x2 );
pxl = e1;
if ( e1 > e2 )
{
@ -2199,19 +2230,20 @@ static const char count_table[256] =
{
switch ( ras.dropOutControl )
{
case 1:
e1 = e2;
case 0: /* simple drop-outs including stubs */
pxl = e2;
break;
case 4:
e1 = CEILING( (x1 + x2 + 1) / 2 );
case 4: /* smart drop-outs including stubs */
pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
break;
case 2:
case 5:
/* Drop-out Control Rule #4 */
case 1: /* simple drop-outs excluding stubs */
case 5: /* smart drop-outs excluding stubs */
/* The spec is not very clear regarding rule #4. It */
/* Drop-out Control Rules #4 and #6 */
/* The spec is not very clear regarding those rules. It */
/* presents a method that is way too costly to implement */
/* while the general idea seems to get rid of `stubs'. */
/* */
@ -2233,7 +2265,6 @@ static const char count_table[256] =
/* FIXXXME: uncommenting this line solves the disappearing */
/* bit problem in the `7' of verdana 10pts, but */
/* makes a new one in the `C' of arial 14pts */
#if 0
if ( x2 - x1 < ras.precision_half )
#endif
@ -2247,41 +2278,43 @@ static const char count_table[256] =
return;
}
/* check that the rightmost pixel isn't set */
e1 = TRUNC( e1 );
c1 = (Short)( e1 >> 3 );
f1 = (Short)( e1 & 7 );
if ( e1 >= 0 && e1 < ras.bWidth &&
ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
return;
if ( ras.dropOutControl == 2 )
e1 = e2;
if ( ras.dropOutControl == 1 )
pxl = e2;
else
e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
break;
default:
return; /* unsupported mode */
default: /* modes 2, 3, 6, 7 */
return; /* no drop-out control */
}
/* check that the other pixel isn't set */
e1 = pxl == e1 ? e2 : e1;
e1 = TRUNC( e1 );
c1 = (Short)( e1 >> 3 );
f1 = (Short)( e1 & 7 );
if ( e1 >= 0 && e1 < ras.bWidth &&
ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
return;
}
else
return;
}
e1 = TRUNC( e1 );
e1 = TRUNC( pxl );
if ( e1 >= 0 && e1 < ras.bWidth )
{
c1 = (Short)( e1 >> 3 );
f1 = (Short)( e1 & 7 );
if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
if ( ras.gray_min_x > c1 )
ras.gray_min_x = c1;
if ( ras.gray_max_x < c1 )
ras.gray_max_x = c1;
ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
}
@ -2365,15 +2398,33 @@ static const char count_table[256] =
PProfile left,
PProfile right )
{
Long e1, e2;
Long e1, e2, pxl;
PByte bits;
Byte f1;
/* During the horizontal sweep, we only take care of drop-outs */
e1 = CEILING( x1 );
e2 = FLOOR ( x2 );
/* e1 + <-- pixel center */
/* | */
/* x1 ---+--> <-- contour */
/* | */
/* | */
/* x2 <--+--- <-- contour */
/* | */
/* | */
/* e2 + <-- pixel center */
/* FIXXXME: The specification doesn't discuss the case where the */
/* intersections degenerate to a single point. */
#if 0
if ( x1 == x2 )
return;
#endif
e1 = CEILING( x1 );
e2 = FLOOR ( x2 );
pxl = e1;
if ( e1 > e2 )
{
@ -2381,23 +2432,17 @@ static const char count_table[256] =
{
switch ( ras.dropOutControl )
{
case 1:
e1 = e2;
case 0: /* simple drop-outs including stubs */
pxl = e2;
break;
case 4:
e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
case 4: /* smart drop-outs including stubs */
pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
break;
case 2:
case 5:
/* Drop-out Control Rule #4 */
/* The spec is not very clear regarding rule #4. It */
/* presents a method that is way too costly to implement */
/* while the general idea seems to get rid of `stubs'. */
/* */
case 1: /* simple drop-outs excluding stubs */
case 5: /* smart drop-outs excluding stubs */
/* see Vertical_Sweep_Drop for details */
/* rightmost stub test */
if ( left->next == right && left->height <= 0 )
@ -2407,32 +2452,32 @@ static const char count_table[256] =
if ( right->next == left && left->start == y )
return;
/* check that the rightmost pixel isn't set */
e1 = TRUNC( e1 );
bits = ras.bTarget + ( y >> 3 );
f1 = (Byte)( 0x80 >> ( y & 7 ) );
bits -= e1 * ras.target.pitch;
if ( ras.target.pitch > 0 )
bits += ( ras.target.rows - 1 ) * ras.target.pitch;
if ( e1 >= 0 &&
e1 < ras.target.rows &&
*bits & f1 )
return;
if ( ras.dropOutControl == 2 )
e1 = e2;
if ( ras.dropOutControl == 1 )
pxl = e2;
else
e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
break;
default:
return; /* unsupported mode */
default: /* modes 2, 3, 6, 7 */
return; /* no drop-out control */
}
/* check that the other pixel isn't set */
e1 = pxl == e1 ? e2 : e1;
e1 = TRUNC( e1 );
bits = ras.bTarget + ( y >> 3 );
f1 = (Byte)( 0x80 >> ( y & 7 ) );
bits -= e1 * ras.target.pitch;
if ( ras.target.pitch > 0 )
bits += ( ras.target.rows - 1 ) * ras.target.pitch;
if ( e1 >= 0 &&
e1 < ras.target.rows &&
*bits & f1 )
return;
}
else
return;
@ -2441,7 +2486,7 @@ static const char count_table[256] =
bits = ras.bTarget + ( y >> 3 );
f1 = (Byte)( 0x80 >> ( y & 7 ) );
e1 = TRUNC( e1 );
e1 = TRUNC( pxl );
if ( e1 >= 0 && e1 < ras.target.rows )
{
@ -2627,6 +2672,14 @@ static const char count_table[256] =
/* During the horizontal sweep, we only take care of drop-outs */
/* FIXXXME: The specification doesn't discuss the case where the */
/* intersections degenerate to a single point. */
#if 0
if ( x1 == x2 )
return;
#endif
e1 = CEILING( x1 );
e2 = FLOOR ( x2 );
@ -2636,23 +2689,17 @@ static const char count_table[256] =
{
switch ( ras.dropOutControl )
{
case 1:
case 0: /* simple drop-outs including stubs */
e1 = e2;
break;
case 4:
e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
case 4: /* smart drop-outs including stubs */
e1 = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
break;
case 2:
case 5:
/* Drop-out Control Rule #4 */
/* The spec is not very clear regarding rule #4. It */
/* presents a method that is way too costly to implement */
/* while the general idea seems to get rid of `stubs'. */
/* */
case 1: /* simple drop-outs excluding stubs */
case 5: /* smart drop-outs excluding stubs */
/* see Vertical_Sweep_Drop for details */
/* rightmost stub test */
if ( left->next == right && left->height <= 0 )
@ -2662,15 +2709,15 @@ static const char count_table[256] =
if ( right->next == left && left->start == y )
return;
if ( ras.dropOutControl == 2 )
if ( ras.dropOutControl == 1 )
e1 = e2;
else
e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
e1 = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
break;
default:
return; /* unsupported mode */
default: /* modes 2, 3, 6, 7 */
return; /* no drop-out control */
}
}
else
@ -2742,8 +2789,10 @@ static const char count_table[256] =
bottom = (Short)P->start;
top = (Short)( P->start + P->height - 1 );
if ( min_Y > bottom ) min_Y = bottom;
if ( max_Y < top ) max_Y = top;
if ( min_Y > bottom )
min_Y = bottom;
if ( max_Y < top )
max_Y = top;
P->X = 0;
InsNew( &waiting, P );
@ -3039,13 +3088,23 @@ static const char count_table[256] =
Set_High_Precision( RAS_VARS ras.outline.flags &
FT_OUTLINE_HIGH_PRECISION );
ras.scale_shift = ras.precision_shift;
/* Drop-out mode 2 is hard-coded since this is the only mode used */
/* on Windows platforms. Using other modes, as specified by the */
/* font, results in misplaced pixels. */
ras.dropOutControl = 2;
ras.second_pass = (FT_Byte)( !( ras.outline.flags &
FT_OUTLINE_SINGLE_PASS ) );
ras.scale_shift = ras.precision_shift;
if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS )
ras.dropOutControl = 2;
else
{
if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS )
ras.dropOutControl = 4;
else
ras.dropOutControl = 0;
if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) )
ras.dropOutControl += 1;
}
ras.second_pass = (FT_Byte)( !( ras.outline.flags &
FT_OUTLINE_SINGLE_PASS ) );
/* Vertical Sweep */
ras.Proc_Sweep_Init = Vertical_Sweep_Init;
@ -3106,12 +3165,22 @@ static const char count_table[256] =
Set_High_Precision( RAS_VARS ras.outline.flags &
FT_OUTLINE_HIGH_PRECISION );
ras.scale_shift = ras.precision_shift + 1;
/* Drop-out mode 2 is hard-coded since this is the only mode used */
/* on Windows platforms. Using other modes, as specified by the */
/* font, results in misplaced pixels. */
ras.dropOutControl = 2;
ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS );
ras.scale_shift = ras.precision_shift + 1;
if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS )
ras.dropOutControl = 2;
else
{
if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS )
ras.dropOutControl = 4;
else
ras.dropOutControl = 0;
if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) )
ras.dropOutControl += 1;
}
ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS );
/* Vertical Sweep */
@ -3351,15 +3420,15 @@ static const char count_table[256] =
if ( !target_map->buffer )
return Raster_Err_Invalid;
ras.outline = *outline;
ras.target = *target_map;
ras.outline = *outline;
ras.target = *target_map;
worker->buff = (PLong) raster->buffer;
worker->sizeBuff = worker->buff +
raster->buffer_size / sizeof ( Long );
worker->buff = (PLong) raster->buffer;
worker->sizeBuff = worker->buff +
raster->buffer_size / sizeof ( Long );
#ifdef FT_RASTER_OPTION_ANTI_ALIASING
worker->grays = raster->grays;
worker->gray_width = raster->gray_width;
worker->grays = raster->grays;
worker->gray_width = raster->gray_width;
#endif
return ( ( params->flags & FT_RASTER_FLAG_AA )

View File

@ -557,10 +557,10 @@
FT_Stream stream = loader->stream;
/* we must undo the FT_FRAME_ENTER in order to point to the */
/* composite instructions, if we find some. */
/* we will process them later... */
/* */
/* we must undo the FT_FRAME_ENTER in order to point */
/* to the composite instructions, if we find some. */
/* We will process them later. */
/* */
loader->ins_pos = (FT_ULong)( FT_STREAM_POS() +
p - limit );
}
@ -1958,6 +1958,37 @@
FT_Outline_Translate( &glyph->outline, -loader.pp1.x, 0 );
}
#ifdef TT_USE_BYTECODE_INTERPRETER
if ( loader.exec->GS.scan_control )
{
/* convert scan conversion mode to FT_OUTLINE_XXX flags */
switch ( loader.exec->GS.scan_type )
{
case 0: /* simple drop-outs including stubs */
glyph->outline.flags |= FT_OUTLINE_INCLUDE_STUBS;
break;
case 1: /* simple drop-outs excluding stubs */
/* nothing; it's the default rendering mode */
break;
case 4: /* smart drop-outs including stubs */
glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS |
FT_OUTLINE_INCLUDE_STUBS;
break;
case 5: /* smart drop-outs excluding stubs */
glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS;
break;
default: /* no drop-out control */
glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS;
break;
}
}
else
glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS;
#endif /* TT_USE_BYTECODE_INTERPRETER */
compute_glyph_metrics( &loader, glyph_index );
}

View File

@ -693,7 +693,7 @@
/* exec :: A handle to the target execution context. */
/* */
/* <Return> */
/* TrueTyoe error code. 0 means success. */
/* TrueType error code. 0 means success. */
/* */
/* <Note> */
/* Only the glyph loader and debugger should call this function. */
@ -5092,12 +5092,8 @@
return;
}
A *= 64;
#if 0
if ( ( args[0] & 0x100 ) != 0 && CUR.metrics.pointSize <= A )
if ( ( args[0] & 0x100 ) != 0 && CUR.tt_metrics.ppem < A )
CUR.GS.scan_control = TRUE;
#endif
if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated )
CUR.GS.scan_control = TRUE;
@ -5105,10 +5101,8 @@
if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched )
CUR.GS.scan_control = TRUE;
#if 0
if ( ( args[0] & 0x800 ) != 0 && CUR.metrics.pointSize > A )
if ( ( args[0] & 0x800 ) != 0 && CUR.tt_metrics.ppem >= A )
CUR.GS.scan_control = FALSE;
#endif
if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated )
CUR.GS.scan_control = FALSE;