< 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 >