< prev index next >
src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c
Print this page
*** 43,53 ****
/**************************************************************************
*
* This is a new anti-aliasing scan-converter for FreeType 2. The
* algorithm used here is _very_ different from the one in the standard
* `ftraster' module. Actually, `ftgrays' computes the _exact_
! * coverage of the outline on each pixel cell.
*
* It is based on ideas that I initially found in Raph Levien's
* excellent LibArt graphics library (see https://www.levien.com/libart
* for more information, though the web pages do not tell anything
* about the renderer; you'll have to dive into the source code to
--- 43,53 ----
/**************************************************************************
*
* This is a new anti-aliasing scan-converter for FreeType 2. The
* algorithm used here is _very_ different from the one in the standard
* `ftraster' module. Actually, `ftgrays' computes the _exact_
! * coverage of the outline on each pixel cell by straight segments.
*
* It is based on ideas that I initially found in Raph Levien's
* excellent LibArt graphics library (see https://www.levien.com/libart
* for more information, though the web pages do not tell anything
* about the renderer; you'll have to dive into the source code to
*** 56,83 ****
* Note, however, that this is a _very_ different implementation
* compared to Raph's. Coverage information is stored in a very
* different way, and I don't use sorted vector paths. Also, it doesn't
* use floating point values.
*
* This renderer has the following advantages:
*
* - It doesn't need an intermediate bitmap. Instead, one can supply a
* callback function that will be called by the renderer to draw gray
* spans on any target surface. You can thus do direct composition on
* any kind of bitmap, provided that you give the renderer the right
* callback.
*
* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on
! * each pixel cell.
*
* - It performs a single pass on the outline (the `standard' FT2
* renderer makes two passes).
*
* - It can easily be modified to render to _any_ number of gray levels
* cheaply.
*
! * - For small (< 20) pixel sizes, it is faster than the standard
* renderer.
*
*/
--- 56,91 ----
* Note, however, that this is a _very_ different implementation
* compared to Raph's. Coverage information is stored in a very
* different way, and I don't use sorted vector paths. Also, it doesn't
* use floating point values.
*
+ * Bézier segments are flattened by splitting them until their deviation
+ * from straight line becomes much smaller than a pixel. Therefore, the
+ * pixel coverage by a Bézier curve is calculated approximately. To
+ * estimate the deviation, we use the distance from the control point
+ * to the conic chord centre or the cubic chord trisection. These
+ * distances vanish fast after each split. In the conic case, they vanish
+ * predictably and the number of necessary splits can be calculated.
+ *
* This renderer has the following advantages:
*
* - It doesn't need an intermediate bitmap. Instead, one can supply a
* callback function that will be called by the renderer to draw gray
* spans on any target surface. You can thus do direct composition on
* any kind of bitmap, provided that you give the renderer the right
* callback.
*
* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on
! * each pixel cell by straight segments.
*
* - It performs a single pass on the outline (the `standard' FT2
* renderer makes two passes).
*
* - It can easily be modified to render to _any_ number of gray levels
* cheaply.
*
! * - For small (< 80) pixel sizes, it is faster than the standard
* renderer.
*
*/
*** 325,345 ****
/* must be at least 6 bits! */
#define PIXEL_BITS 8
- #undef FLOOR
- #undef CEILING
- #undef TRUNC
- #undef SCALED
-
#define ONE_PIXEL ( 1 << PIXEL_BITS )
! #define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) )
! #define SUBPIXELS( x ) ( (TPos)(x) * ONE_PIXEL )
! #define FLOOR( x ) ( (x) & -ONE_PIXEL )
! #define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
! #define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
#if PIXEL_BITS >= 6
#define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) )
#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
#else
--- 333,345 ----
/* must be at least 6 bits! */
#define PIXEL_BITS 8
#define ONE_PIXEL ( 1 << PIXEL_BITS )
! #define TRUNC( x ) (TCoord)( (x) >> PIXEL_BITS )
! #define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) )
#if PIXEL_BITS >= 6
#define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) )
#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
#else
*** 387,397 ****
/* with multiplications and right shifts. */
#define FT_UDIVPREP( c, b ) \
long b ## _r = c ? (long)( FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \
: 0
#define FT_UDIV( a, b ) \
! ( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \
( sizeof( long ) * FT_CHAR_BIT - PIXEL_BITS ) )
/**************************************************************************
*
--- 387,397 ----
/* with multiplications and right shifts. */
#define FT_UDIVPREP( c, b ) \
long b ## _r = c ? (long)( FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \
: 0
#define FT_UDIV( a, b ) \
! (TCoord)( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \
( sizeof( long ) * FT_CHAR_BIT - PIXEL_BITS ) )
/**************************************************************************
*
*** 430,439 ****
--- 430,442 ----
#define FT_MAX_GRAY_POOL ( FT_RENDER_POOL_SIZE / sizeof ( TCell ) )
#else
#define FT_MAX_GRAY_POOL ( 2048 / sizeof ( TCell ) )
#endif
+ /* FT_Span buffer size for direct rendering only */
+ #define FT_MAX_GRAY_SPANS 10
+
#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */
/* We disable the warning `structure was padded due to */
/* __declspec(align())' in order to compile cleanly with */
/* the maximum level of warnings. */
*** 463,472 ****
--- 466,477 ----
FT_Outline outline;
TPixmap target;
FT_Raster_Span_Func render_span;
void* render_span_data;
+ FT_Span spans[FT_MAX_GRAY_SPANS];
+ int num_spans;
} gray_TWorker, *gray_PWorker;
#if defined( _MSC_VER )
#pragma warning( pop )
*** 514,537 ****
#endif /* FT_DEBUG_LEVEL_TRACE */
/**************************************************************************
*
! * Record the current cell in the table.
*/
static void
gray_record_cell( RAS_ARG )
{
PCell *pcell, cell;
TCoord x = ras.ex;
pcell = &ras.ycells[ras.ey - ras.min_ey];
! for (;;)
{
! cell = *pcell;
! if ( !cell || cell->x > x )
break;
if ( cell->x == x )
goto Found;
--- 519,541 ----
#endif /* FT_DEBUG_LEVEL_TRACE */
/**************************************************************************
*
! * Record the current cell in the linked list.
*/
static void
gray_record_cell( RAS_ARG )
{
PCell *pcell, cell;
TCoord x = ras.ex;
pcell = &ras.ycells[ras.ey - ras.min_ey];
! while ( ( cell = *pcell ) )
{
! if ( cell->x > x )
break;
if ( cell->x == x )
goto Found;
*** 575,594 ****
/* . the new horizontal position must be strictly less than max_ex */
/* */
/* Note that if a cell is to the left of the clipping region, it is */
/* actually set to the (min_ex-1) horizontal position. */
- if ( ex < ras.min_ex )
- ex = ras.min_ex - 1;
-
/* record the current one if it is valid and substantial */
if ( !ras.invalid && ( ras.area || ras.cover ) )
gray_record_cell( RAS_VAR );
ras.area = 0;
ras.cover = 0;
! ras.ex = ex;
ras.ey = ey;
ras.invalid = ( ey >= ras.max_ey || ey < ras.min_ey ||
ex >= ras.max_ex );
}
--- 579,595 ----
/* . the new horizontal position must be strictly less than max_ex */
/* */
/* Note that if a cell is to the left of the clipping region, it is */
/* actually set to the (min_ex-1) horizontal position. */
/* record the current one if it is valid and substantial */
if ( !ras.invalid && ( ras.area || ras.cover ) )
gray_record_cell( RAS_VAR );
ras.area = 0;
ras.cover = 0;
! ras.ex = FT_MAX( ex, ras.min_ex - 1 );
ras.ey = ey;
ras.invalid = ( ey >= ras.max_ey || ey < ras.min_ey ||
ex >= ras.max_ex );
}
*** 620,631 ****
{
gray_set_cell( RAS_VAR_ ex2, ey );
return;
}
! fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
! fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
/* everything is located in a single cell. That is easy! */
/* */
if ( ex1 == ex2 )
goto End;
--- 621,632 ----
{
gray_set_cell( RAS_VAR_ ex2, ey );
return;
}
! fx1 = FRACT( x1 );
! fx2 = FRACT( x2 );
/* everything is located in a single cell. That is easy! */
/* */
if ( ex1 == ex2 )
goto End;
*** 648,657 ****
--- 649,661 ----
first = 0;
incr = -1;
dx = -dx;
}
+ /* the fractional part of y-delta is mod/dx. It is essential to */
+ /* keep track of its accumulation for accurate rendering. */
+ /* XXX: y-delta and x-delta below should be related. */
FT_DIV_MOD( TCoord, p, dx, delta, mod );
ras.area += (TArea)( ( fx1 + first ) * delta );
ras.cover += delta;
y1 += delta;
*** 713,724 ****
/* perform vertical clipping */
if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
( ey1 < ras.min_ey && ey2 < ras.min_ey ) )
goto End;
! fy1 = (TCoord)( ras.y - SUBPIXELS( ey1 ) );
! fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
/* everything is on a single scanline */
if ( ey1 == ey2 )
{
gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
--- 717,728 ----
/* perform vertical clipping */
if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
( ey1 < ras.min_ey && ey2 < ras.min_ey ) )
goto End;
! fy1 = FRACT( ras.y );
! fy2 = FRACT( to_y );
/* everything is on a single scanline */
if ( ey1 == ey2 )
{
gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
*** 730,740 ****
/* vertical line - avoid calling gray_render_scanline */
if ( dx == 0 )
{
TCoord ex = TRUNC( ras.x );
! TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
TArea area;
if ( dy > 0)
{
--- 734,744 ----
/* vertical line - avoid calling gray_render_scanline */
if ( dx == 0 )
{
TCoord ex = TRUNC( ras.x );
! TCoord two_fx = FRACT( ras.x ) << 1;
TArea area;
if ( dy > 0)
{
*** 785,794 ****
--- 789,800 ----
first = 0;
incr = -1;
dy = -dy;
}
+ /* the fractional part of x-delta is mod/dy. It is essential to */
+ /* keep track of its accumulation for accurate rendering. */
FT_DIV_MOD( TCoord, p, dy, delta, mod );
x = ras.x + delta;
gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first );
*** 841,852 ****
*/
static void
gray_render_line( RAS_ARG_ TPos to_x,
TPos to_y )
{
! TPos dx, dy, fx1, fy1, fx2, fy2;
! TCoord ex1, ex2, ey1, ey2;
ey1 = TRUNC( ras.y );
ey2 = TRUNC( to_y );
--- 847,859 ----
*/
static void
gray_render_line( RAS_ARG_ TPos to_x,
TPos to_y )
{
! TPos dx, dy;
! TCoord fx1, fy1, fx2, fy2;
! TCoord ex1, ey1, ex2, ey2;
ey1 = TRUNC( ras.y );
ey2 = TRUNC( to_y );
*** 856,877 ****
goto End;
ex1 = TRUNC( ras.x );
ex2 = TRUNC( to_x );
! fx1 = ras.x - SUBPIXELS( ex1 );
! fy1 = ras.y - SUBPIXELS( ey1 );
dx = to_x - ras.x;
dy = to_y - ras.y;
if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */
;
else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */
{
! ex1 = ex2;
! gray_set_cell( RAS_VAR_ ex1, ey1 );
}
else if ( dx == 0 )
{
if ( dy > 0 ) /* vertical line up */
do
--- 863,884 ----
goto End;
ex1 = TRUNC( ras.x );
ex2 = TRUNC( to_x );
! fx1 = FRACT( ras.x );
! fy1 = FRACT( ras.y );
dx = to_x - ras.x;
dy = to_y - ras.y;
if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */
;
else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */
{
! gray_set_cell( RAS_VAR_ ex2, ey2 );
! goto End;
}
else if ( dx == 0 )
{
if ( dy > 0 ) /* vertical line up */
do
*** 894,904 ****
gray_set_cell( RAS_VAR_ ex1, ey1 );
} while ( ey1 != ey2 );
}
else /* any other line */
{
! TPos prod = dx * fy1 - dy * fx1;
FT_UDIVPREP( ex1 != ex2, dx );
FT_UDIVPREP( ey1 != ey2, dy );
/* The fundamental value `prod' determines which side and the */
--- 901,911 ----
gray_set_cell( RAS_VAR_ ex1, ey1 );
} while ( ey1 != ey2 );
}
else /* any other line */
{
! TPos prod = dx * (TPos)fy1 - dy * (TPos)fx1;
FT_UDIVPREP( ex1 != ex2, dx );
FT_UDIVPREP( ey1 != ey2, dy );
/* The fundamental value `prod' determines which side and the */
*** 908,918 ****
{
if ( prod <= 0 &&
prod - dx * ONE_PIXEL > 0 ) /* left */
{
fx2 = 0;
! fy2 = (TPos)FT_UDIV( -prod, -dx );
prod -= dy * ONE_PIXEL;
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = ONE_PIXEL;
fy1 = fy2;
--- 915,925 ----
{
if ( prod <= 0 &&
prod - dx * ONE_PIXEL > 0 ) /* left */
{
fx2 = 0;
! fy2 = FT_UDIV( -prod, -dx );
prod -= dy * ONE_PIXEL;
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = ONE_PIXEL;
fy1 = fy2;
*** 920,930 ****
}
else if ( prod - dx * ONE_PIXEL <= 0 &&
prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */
{
prod -= dx * ONE_PIXEL;
! fx2 = (TPos)FT_UDIV( -prod, dy );
fy2 = ONE_PIXEL;
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = fx2;
fy1 = 0;
--- 927,937 ----
}
else if ( prod - dx * ONE_PIXEL <= 0 &&
prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */
{
prod -= dx * ONE_PIXEL;
! fx2 = FT_UDIV( -prod, dy );
fy2 = ONE_PIXEL;
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = fx2;
fy1 = 0;
*** 933,953 ****
else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 &&
prod + dy * ONE_PIXEL >= 0 ) /* right */
{
prod += dy * ONE_PIXEL;
fx2 = ONE_PIXEL;
! fy2 = (TPos)FT_UDIV( prod, dx );
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = 0;
fy1 = fy2;
ex1++;
}
else /* ( prod + dy * ONE_PIXEL < 0 &&
prod > 0 ) down */
{
! fx2 = (TPos)FT_UDIV( prod, -dy );
fy2 = 0;
prod += dx * ONE_PIXEL;
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = fx2;
--- 940,960 ----
else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 &&
prod + dy * ONE_PIXEL >= 0 ) /* right */
{
prod += dy * ONE_PIXEL;
fx2 = ONE_PIXEL;
! fy2 = FT_UDIV( prod, dx );
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = 0;
fy1 = fy2;
ex1++;
}
else /* ( prod + dy * ONE_PIXEL < 0 &&
prod > 0 ) down */
{
! fx2 = FT_UDIV( prod, -dy );
fy2 = 0;
prod += dx * ONE_PIXEL;
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
fx1 = fx2;
*** 957,968 ****
gray_set_cell( RAS_VAR_ ex1, ey1 );
} while ( ex1 != ex2 || ey1 != ey2 );
}
! fx2 = to_x - SUBPIXELS( ex2 );
! fy2 = to_y - SUBPIXELS( ey2 );
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
End:
--- 964,975 ----
gray_set_cell( RAS_VAR_ ex1, ey1 );
} while ( ex1 != ex2 || ey1 != ey2 );
}
! fx2 = FRACT( to_x );
! fy2 = FRACT( to_y );
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
End:
*** 977,996 ****
{
TPos a, b;
base[4].x = base[2].x;
! b = base[1].x;
! a = base[3].x = ( base[2].x + b ) / 2;
! b = base[1].x = ( base[0].x + b ) / 2;
! base[2].x = ( a + b ) / 2;
base[4].y = base[2].y;
! b = base[1].y;
! a = base[3].y = ( base[2].y + b ) / 2;
! b = base[1].y = ( base[0].y + b ) / 2;
! base[2].y = ( a + b ) / 2;
}
static void
gray_render_conic( RAS_ARG_ const FT_Vector* control,
--- 984,1005 ----
{
TPos a, b;
base[4].x = base[2].x;
! a = base[0].x + base[1].x;
! b = base[1].x + base[2].x;
! base[3].x = b >> 1;
! base[2].x = ( a + b ) >> 2;
! base[1].x = a >> 1;
base[4].y = base[2].y;
! a = base[0].y + base[1].y;
! b = base[1].y + base[2].y;
! base[3].y = b >> 1;
! base[2].y = ( a + b ) >> 2;
! base[1].y = a >> 1;
}
static void
gray_render_conic( RAS_ARG_ const FT_Vector* control,
*** 1040,1055 ****
/* We use decrement counter to count the total number of segments */
/* to draw starting from 2^level. Before each draw we split as */
/* many times as there are trailing zeros in the counter. */
do
{
! split = 1;
! while ( ( draw & split ) == 0 )
{
gray_split_conic( arc );
arc += 2;
- split <<= 1;
}
gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
arc -= 2;
--- 1049,1063 ----
/* We use decrement counter to count the total number of segments */
/* to draw starting from 2^level. Before each draw we split as */
/* many times as there are trailing zeros in the counter. */
do
{
! split = draw & ( -draw ); /* isolate the rightmost 1-bit */
! while ( ( split >>= 1 ) )
{
gray_split_conic( arc );
arc += 2;
}
gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
arc -= 2;
*** 1058,1102 ****
static void
gray_split_cubic( FT_Vector* base )
{
! TPos a, b, c, d;
base[6].x = base[3].x;
! c = base[1].x;
! d = base[2].x;
! base[1].x = a = ( base[0].x + c ) / 2;
! base[5].x = b = ( base[3].x + d ) / 2;
! c = ( c + d ) / 2;
! base[2].x = a = ( a + c ) / 2;
! base[4].x = b = ( b + c ) / 2;
! base[3].x = ( a + b ) / 2;
base[6].y = base[3].y;
! c = base[1].y;
! d = base[2].y;
! base[1].y = a = ( base[0].y + c ) / 2;
! base[5].y = b = ( base[3].y + d ) / 2;
! c = ( c + d ) / 2;
! base[2].y = a = ( a + c ) / 2;
! base[4].y = b = ( b + c ) / 2;
! base[3].y = ( a + b ) / 2;
}
static void
gray_render_cubic( RAS_ARG_ const FT_Vector* control1,
const FT_Vector* control2,
const FT_Vector* to )
{
FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */
FT_Vector* arc = bez_stack;
- TPos dx, dy, dx_, dy_;
- TPos dx1, dy1, dx2, dy2;
- TPos L, s, s_limit;
arc[0].x = UPSCALE( to->x );
arc[0].y = UPSCALE( to->y );
arc[1].x = UPSCALE( control2->x );
--- 1066,1111 ----
static void
gray_split_cubic( FT_Vector* base )
{
! TPos a, b, c;
base[6].x = base[3].x;
! a = base[0].x + base[1].x;
! b = base[1].x + base[2].x;
! c = base[2].x + base[3].x;
! base[5].x = c >> 1;
! c += b;
! base[4].x = c >> 2;
! base[1].x = a >> 1;
! a += b;
! base[2].x = a >> 2;
! base[3].x = ( a + c ) >> 3;
base[6].y = base[3].y;
! a = base[0].y + base[1].y;
! b = base[1].y + base[2].y;
! c = base[2].y + base[3].y;
! base[5].y = c >> 1;
! c += b;
! base[4].y = c >> 2;
! base[1].y = a >> 1;
! a += b;
! base[2].y = a >> 2;
! base[3].y = ( a + c ) >> 3;
}
static void
gray_render_cubic( RAS_ARG_ const FT_Vector* control1,
const FT_Vector* control2,
const FT_Vector* to )
{
FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */
FT_Vector* arc = bez_stack;
arc[0].x = UPSCALE( to->x );
arc[0].y = UPSCALE( to->y );
arc[1].x = UPSCALE( control2->x );
*** 1121,1169 ****
return;
}
for (;;)
{
! /* Decide whether to split or draw. See `Rapid Termination */
! /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
! /* F. Hain, at */
! /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
!
! /* dx and dy are x and y components of the P0-P3 chord vector. */
! dx = dx_ = arc[3].x - arc[0].x;
! dy = dy_ = arc[3].y - arc[0].y;
!
! L = FT_HYPOT( dx_, dy_ );
!
! /* Avoid possible arithmetic overflow below by splitting. */
! if ( L > 32767 )
! goto Split;
!
! /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
! s_limit = L * (TPos)( ONE_PIXEL / 6 );
!
! /* s is L * the perpendicular distance from P1 to the line P0-P3. */
! dx1 = arc[1].x - arc[0].x;
! dy1 = arc[1].y - arc[0].y;
! s = FT_ABS( SUB_LONG( MUL_LONG( dy, dx1 ), MUL_LONG( dx, dy1 ) ) );
!
! if ( s > s_limit )
! goto Split;
!
! /* s is L * the perpendicular distance from P2 to the line P0-P3. */
! dx2 = arc[2].x - arc[0].x;
! dy2 = arc[2].y - arc[0].y;
! s = FT_ABS( SUB_LONG( MUL_LONG( dy, dx2 ), MUL_LONG( dx, dy2 ) ) );
!
! if ( s > s_limit )
! goto Split;
!
! /* Split super curvy segments where the off points are so far
! from the chord that the angles P0-P1-P3 or P0-P2-P3 become
! acute as detected by appropriate dot products. */
! if ( dx1 * ( dx1 - dx ) + dy1 * ( dy1 - dy ) > 0 ||
! dx2 * ( dx2 - dx ) + dy2 * ( dy2 - dy ) > 0 )
goto Split;
gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
if ( arc == bez_stack )
--- 1130,1146 ----
return;
}
for (;;)
{
! /* with each split, control points quickly converge towards */
! /* chord trisection points and the vanishing distances below */
! /* indicate when the segment is flat enough to draw */
! if ( FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 ||
! FT_ABS( 2 * arc[0].y - 3 * arc[1].y + arc[3].y ) > ONE_PIXEL / 2 ||
! FT_ABS( arc[0].x - 3 * arc[2].x + 2 * arc[3].x ) > ONE_PIXEL / 2 ||
! FT_ABS( arc[0].y - 3 * arc[2].y + 2 * arc[3].y ) > ONE_PIXEL / 2 )
goto Split;
gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
if ( arc == bez_stack )
*** 1234,1271 ****
TArea coverage,
TCoord acount )
{
/* scale the coverage from 0..(ONE_PIXEL*ONE_PIXEL*2) to 0..256 */
coverage >>= PIXEL_BITS * 2 + 1 - 8;
- if ( coverage < 0 )
- coverage = -coverage - 1;
/* compute the line's coverage depending on the outline fill rule */
if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
{
coverage &= 511;
if ( coverage >= 256 )
coverage = 511 - coverage;
}
! else
{
! /* normal non-zero winding rule */
if ( coverage >= 256 )
coverage = 255;
}
! if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */
{
! FT_Span span;
! span.x = (short)x;
! span.len = (unsigned short)acount;
! span.coverage = (unsigned char)coverage;
! ras.render_span( y, 1, &span, ras.render_span_data );
}
else
{
unsigned char* q = ras.target.origin - ras.target.pitch * y + x;
unsigned char c = (unsigned char)coverage;
--- 1211,1253 ----
TArea coverage,
TCoord acount )
{
/* scale the coverage from 0..(ONE_PIXEL*ONE_PIXEL*2) to 0..256 */
coverage >>= PIXEL_BITS * 2 + 1 - 8;
/* compute the line's coverage depending on the outline fill rule */
if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
{
coverage &= 511;
if ( coverage >= 256 )
coverage = 511 - coverage;
}
! else /* default non-zero winding rule */
{
! if ( coverage < 0 )
! coverage = ~coverage; /* the same as -coverage - 1 */
!
if ( coverage >= 256 )
coverage = 255;
}
! if ( ras.num_spans >= 0 ) /* for FT_RASTER_FLAG_DIRECT only */
{
! FT_Span* span = ras.spans + ras.num_spans++;
! span->x = (short)x;
! span->len = (unsigned short)acount;
! span->coverage = (unsigned char)coverage;
! if ( ras.num_spans == FT_MAX_GRAY_SPANS )
! {
! /* flush the span buffer and reset the count */
! ras.render_span( y, ras.num_spans, ras.spans, ras.render_span_data );
! ras.num_spans = 0;
! }
}
else
{
unsigned char* q = ras.target.origin - ras.target.pitch * y + x;
unsigned char c = (unsigned char)coverage;
*** 1275,1292 ****
* calling `memset'. This is mainly due to the cost of the
* function call.
*/
switch ( acount )
{
! case 7: *q++ = c;
! case 6: *q++ = c;
! case 5: *q++ = c;
! case 4: *q++ = c;
! case 3: *q++ = c;
! case 2: *q++ = c;
! case 1: *q = c;
! case 0: break;
default:
FT_MEM_SET( q, c, acount );
}
}
}
--- 1257,1289 ----
* calling `memset'. This is mainly due to the cost of the
* function call.
*/
switch ( acount )
{
! case 7:
! *q++ = c;
! /* fall through */
! case 6:
! *q++ = c;
! /* fall through */
! case 5:
! *q++ = c;
! /* fall through */
! case 4:
! *q++ = c;
! /* fall through */
! case 3:
! *q++ = c;
! /* fall through */
! case 2:
! *q++ = c;
! /* fall through */
! case 1:
! *q = c;
! /* fall through */
! case 0:
! break;
default:
FT_MEM_SET( q, c, acount );
}
}
}
*** 1320,1329 ****
--- 1317,1333 ----
x = cell->x + 1;
}
if ( cover != 0 )
gray_hline( RAS_VAR_ x, y, cover, ras.max_ex - x );
+
+ if ( ras.num_spans > 0 ) /* for FT_RASTER_FLAG_DIRECT only */
+ {
+ /* flush the span buffer and reset the count */
+ ras.render_span( y, ras.num_spans, ras.spans, ras.render_span_data );
+ ras.num_spans = 0;
+ }
}
}
#ifdef STANDALONE_
*** 1369,1379 ****
FT_Outline_Decompose( const FT_Outline* outline,
const FT_Outline_Funcs* func_interface,
void* user )
{
#undef SCALED
! #define SCALED( x ) ( ( (x) << shift ) - delta )
FT_Vector v_last;
FT_Vector v_control;
FT_Vector v_start;
--- 1373,1383 ----
FT_Outline_Decompose( const FT_Outline* outline,
const FT_Outline_Funcs* func_interface,
void* user )
{
#undef SCALED
! #define SCALED( x ) ( (x) * ( 1L << shift ) - delta )
FT_Vector v_last;
FT_Vector v_control;
FT_Vector v_start;
*** 1629,1639 ****
static int
gray_convert_glyph_inner( RAS_ARG,
int continued )
{
! volatile int error = 0;
if ( ft_setjmp( ras.jump_buffer ) == 0 )
{
if ( continued )
--- 1633,1643 ----
static int
gray_convert_glyph_inner( RAS_ARG,
int continued )
{
! int error;
if ( ft_setjmp( ras.jump_buffer ) == 0 )
{
if ( continued )
*** 1753,1763 ****
gray_raster_render( FT_Raster raster,
const FT_Raster_Params* params )
{
const FT_Outline* outline = (const FT_Outline*)params->source;
const FT_Bitmap* target_map = params->target;
- FT_BBox clip;
#ifndef FT_STATIC_RASTER
gray_TWorker worker[1];
#endif
--- 1757,1766 ----
*** 1790,1799 ****
--- 1793,1808 ----
if ( !params->gray_spans )
return 0;
ras.render_span = (FT_Raster_Span_Func)params->gray_spans;
ras.render_span_data = params->user;
+ ras.num_spans = 0;
+
+ ras.min_ex = params->clip_box.xMin;
+ ras.min_ey = params->clip_box.yMin;
+ ras.max_ex = params->clip_box.xMax;
+ ras.max_ey = params->clip_box.yMax;
}
else
{
/* if direct mode is not set, we must have a target bitmap */
if ( !target_map )
*** 1814,1844 ****
ras.target.pitch = target_map->pitch;
ras.render_span = (FT_Raster_Span_Func)NULL;
ras.render_span_data = NULL;
! }
! /* compute clipping box */
! if ( params->flags & FT_RASTER_FLAG_DIRECT &&
! params->flags & FT_RASTER_FLAG_CLIP )
! clip = params->clip_box;
! else
! {
! /* compute clip box from target pixmap */
! clip.xMin = 0;
! clip.yMin = 0;
! clip.xMax = (FT_Pos)target_map->width;
! clip.yMax = (FT_Pos)target_map->rows;
}
! /* clip to target bitmap, exit if nothing to do */
! ras.min_ex = clip.xMin;
! ras.min_ey = clip.yMin;
! ras.max_ex = clip.xMax;
! ras.max_ey = clip.yMax;
!
if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey )
return 0;
return gray_convert_glyph( RAS_VAR );
}
--- 1823,1841 ----
ras.target.pitch = target_map->pitch;
ras.render_span = (FT_Raster_Span_Func)NULL;
ras.render_span_data = NULL;
! ras.num_spans = -1; /* invalid */
! ras.min_ex = 0;
! ras.min_ey = 0;
! ras.max_ex = (FT_Pos)target_map->width;
! ras.max_ey = (FT_Pos)target_map->rows;
}
! /* exit if nothing to do */
if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey )
return 0;
return gray_convert_glyph( RAS_VAR );
}
< prev index next >