diff --git a/demos/src/ftrast2.c b/demos/src/ftrast2.c index 7f8715cfc..67393f072 100644 --- a/demos/src/ftrast2.c +++ b/demos/src/ftrast2.c @@ -191,6 +191,7 @@ /* used to access the current raster object, with a '.' instead of a '->' */ #define ras (*raster) +#define UNUSED_RASTER (void)raster; /* For anti-aliasing modes, we use a 2 or 4 lines intermediate bitmap which */ /* is filtered repeatedly to render each pixmap row. The following macro */ @@ -1023,54 +1024,55 @@ b = base[1].y = ( base[0].y + b )/2; base[2].y = (a+b)/2; } +#endif +#ifdef FT_RASTER_CUBIC_BEZIERS /****************************************************************************/ /* */ -/* Push_Conic */ +/* Split_Cubic */ /* */ -/* Clears the Bezier stack and pushes a new arc on top of it */ -/* */ -/* */ -/* p2 :: pointer to second (control) point */ -/* p3 :: pointer to third (end) point */ +/* */ +/* Subdivides a third-order Bezier arc into two joint sub-arcs in the */ +/* Bezier stack. */ /* */ /* */ -/* The first point is taken as "raster->last", so it doesn't appear */ -/* in the signature.. */ +/* This routine is the "beef" of the component. It is one of _the_ */ +/* inner loops that should be optimized like hell to get the best */ +/* performance.. */ /* */ /****************************************************************************/ static - void Push_Conic( RAS_ARGS FT_Vector* p2, - FT_Vector* p3 ) + void Split_Cubic( TPoint* base ) { -#undef STORE -#define STORE( _arc, point ) \ - { \ - TPos x = SCALED(point->x); \ - TPos y = SCALED(point->y); \ - if (ras.flipped) \ - { \ - _arc.x = y; \ - _arc.y = x; \ - } \ - else \ - { \ - _arc.x = x; \ - _arc.y = y; \ - } \ - } + TPos a, b, c, d; - TPoint* arc; - ras.arc = arc = ras.arcs; - - arc[2] = ras.last; - STORE( arc[1], p2 ); - STORE( arc[0], p3 ); -#undef STORE + 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; } +#endif + + +#ifdef FT_RASTER_CONIC_BEZIERS /****************************************************************************/ /* */ /* Conic_Up */ @@ -1251,100 +1253,6 @@ #ifdef FT_RASTER_CUBIC_BEZIERS -/****************************************************************************/ -/* */ -/* Split_Cubic */ -/* */ -/* */ -/* Subdivides a third-order Bezier arc into two joint sub-arcs in the */ -/* Bezier stack. */ -/* */ -/* */ -/* This routine is the "beef" of the component. It is one of _the_ */ -/* inner loops that should be optimized like hell to get the best */ -/* performance.. */ -/* */ -/****************************************************************************/ - - static - void Split_Cubic( TPoint* 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; - } - -/****************************************************************************/ -/* */ -/* Push_Cubic */ -/* */ -/* */ -/* Clears the bezier stack and pushes a new third-order bezier arc */ -/* on top of it */ -/* */ -/* */ -/* p2 :: pointer to second point (control) */ -/* p3 :: pointer to third point (control) */ -/* p4 :: pointer to last point (end) */ -/* */ -/* */ -/* The first point is taken as "raster->last", so it doesn't appear */ -/* in the signature.. */ -/* */ -/****************************************************************************/ - - static - void Push_Cubic( RAS_ARGS FT_Vector* p2, - FT_Vector* p3, - FT_Vector* p4 ) - { -#undef STORE -#define STORE( _arc, point ) \ - { \ - TPos x = SCALED(point->x); \ - TPos y = SCALED(point->y); \ - if (ras.flipped) \ - { \ - _arc.x = y; \ - _arc.y = x; \ - } \ - else \ - { \ - _arc.x = x; \ - _arc.y = y; \ - } \ - } - - TPoint* arc; - ras.arc = arc = ras.arcs; - - arc[3] = ras.last; - STORE( arc[2], p2 ); - STORE( arc[1], p3 ); - STORE( arc[0], p4 ); - -#undef STORE - } - - /****************************************************************************/ /* */ /* Cubic_Up */ @@ -1519,6 +1427,285 @@ #endif /* FT_RASTER_CUBIC_BEZIERS */ + + + + + /* A function type describing the functions used to split bezier arcs */ + typedef void (*TSplitter)( TPoint* base ); + +#ifdef FT_DYNAMIC_BEZIER_STEPS + static + TPos Dynamic_Bezier_Threshold( RAS_ARGS int degree, TPoint* arc ) + { + TPos min_x, max_x, min_y, max_y, A, B; + TPos wide_x, wide_y, threshold; + TPoint* cur = arc; + TPoint* limit = cur + degree; + + /* first of all, set the threshold to the maximum x or y extent */ + min_x = max_x = arc[0].x; + min_y = max_y = arc[0].y; + cur++; + for ( ; cur < limit; cur++ ) + { + TPos x = cur->x; + TPos y = cur->y; + + if ( x < min_x ) min_x = x; + if ( x > max_x ) max_x = x; + + if ( y < min_y ) min_y = y; + if ( y > max_y ) max_y = y; + } + wide_x = (max_x - min_x) << 4; + wide_y = (max_y - min_y) << 4; + + threshold = wide_x; + if (threshold < wide_y) threshold = wide_y; + + /* now compute the second and third order error values */ + + wide_x = arc[0].x + arc[1].x - arc[2].x*2; + wide_y = arc[0].y + arc[1].y - arc[2].y*2; + + if (wide_x < 0) wide_x = -wide_x; + if (wide_y < 0) wide_y = -wide_y; + + A = wide_x; if ( A < wide_y ) A = wide_y; + + if (degree >= 3) + { + wide_x = arc[3].x - arc[0].x + 3*(arc[2].x - arc[3].x); + wide_y = arc[3].y - arc[0].y + 3*(arc[2].y - arc[3].y); + + if (wide_x < 0) wide_x = -wide_x; + if (wide_y < 0) wide_y = -wide_y; + + B = wide_x; if ( B < wide_y ) B = wide_y; + } + else + B = 0; + + while ( A > 0 || B > 0 ) + { + threshold >>= 1; + A >>= 2; + B >>= 3; + } + + if (threshold < PRECISION_STEP) + threshold = PRECISION_STEP; + + return threshold; + } +#endif + + /*************************************************************************/ + /* */ + /* */ + /* Bezier_Up */ + /* */ + /* */ + /* Computes the scan-line intersections of an ascending second-order */ + /* Bezier arc and stores them in the render pool. The arc is taken */ + /* from the top of the stack. */ + /* */ + /* */ + /* miny :: The minimum vertical grid coordinate. */ + /* maxy :: The maximum vertical grid coordinate. */ + /* */ + /* */ + /* SUCCESS or FAILURE. */ + /* */ + static + TBool Bezier_Up( RAS_ARGS int degree, + TSplitter splitter, + TPos miny, + TPos maxy ) + { + TPos y1, y2, e, e2, e0, threshold; + int f1; + + TPoint* arc; + TPoint* start_arc; + + PPos top; + + + arc = ras.arc; + y1 = arc[degree].y; + y2 = arc[0].y; + top = ras.cursor; + + if ( y2 < miny || y1 > maxy ) + goto Fin; + + e2 = FLOOR( y2 ); /* integer end y */ + + if ( e2 > maxy ) + e2 = maxy; + + e0 = miny; + + if ( y1 < miny ) + { + e = e0; /* integer start y == current scanline */ + } + else + { + e = CEILING( y1 ); /* integer start y == current scanline */ + f1 = FRAC( y1 ); /* fractional shift of start y */ + e0 = e; /* first integer scanline to be pushed */ + + if ( f1 == 0 ) /* do we start on an integer scanline? */ + { + if ( ras.joint ) + { + top--; + ras.joint = FALSE; + } + + *top++ = arc[degree].x; /* write directly start position */ + + DEBUG_PSET; + + e += ras.precision; /* go to next scanline */ + } + } + + /* record start position if necessary */ + if ( ras.fresh ) + { + ras.cur_prof->start = TRUNC( e0 ); + ras.fresh = FALSE; + } + + /* exit if the current scanline is already above the max scanline */ + if ( e2 < e ) + goto Fin; + + /* check for overflow */ + if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.pool_limit ) + { + ras.cursor = top; + ras.error = ErrRaster_Overflow; + return FAILURE; + } + + +#ifdef FT_DYNAMIC_BEZIER_STEPS + /* compute dynamic bezier step threshold */ + threshold = Dynamic_Bezier_Threshold( RAS_VAR_ degree, arc ); +#else + threshold = ras.precision_step; +#endif + + start_arc = arc; + + /* loop while there is still an arc on the bezier stack */ + /* and the current scan line is below y max == e2 */ + while ( arc >= start_arc && e <= e2 ) + { + ras.joint = FALSE; + + y2 = arc[0].y; /* final y of the top-most arc */ + + if ( y2 > e ) /* the arc intercepts the current scanline */ + { + y1 = arc[degree].y; /* start y of top-most arc */ + +#ifdef OLD + if ( y2-y1 >= ras.precision_step ) +#else + if ( y2 >= e + ras.precision || y2 - y1 >= threshold ) +#endif + { + /* if the arc's height is too great, split it */ + splitter( arc ); + arc += degree; + } + else + { + /* otherwise, approximate it as a segment and compute */ + /* its intersection with the current scanline */ + *top++ = arc[degree].x + + FMulDiv( arc[0].x-arc[degree].x, + e - y1, + y2 - y1 ); + + DEBUG_PSET; + + arc -= degree; /* pop the arc */ + e += ras.precision; /* go to next scanline */ + } + } + else + { + if ( y2 == e ) /* if the arc falls on the scanline */ + { /* record its _joint_ intersection */ + ras.joint = TRUE; + *top++ = arc[0].x; + + DEBUG_PSET; + + e += ras.precision; /* go to next scanline */ + } + arc -= degree; /* pop the arc */ + } + } + + Fin: + ras.cursor = top; + ras.arc -= degree; + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* */ + /* Bezier_Down */ + /* */ + /* */ + /* Computes the scan-line intersections of a descending second-order */ + /* Bezier arc and stores them in the render pool. The arc is taken */ + /* from the top of the stack. */ + /* */ + /* */ + /* miny :: The minimum vertical grid coordinate. */ + /* maxy :: The maximum vertical grid coordinate. */ + /* */ + /* */ + /* SUCCESS or FAILURE. */ + /* */ + static + TBool Bezier_Down( RAS_ARGS int degree, + TSplitter splitter, + TPos miny, + TPos maxy ) + { + TPoint* arc = ras.arc; + TBool result, fresh; + + arc[0].y = -arc[0].y; + arc[1].y = -arc[1].y; + arc[2].y = -arc[2].y; + if (degree > 2) + arc[3].y = -arc[3].y; + + fresh = ras.fresh; + + result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny ); + + if ( fresh && !ras.fresh ) + ras.cur_prof->start = -ras.cur_prof->start; + + arc[0].y = -arc[0].y; + return result; + } + + /****************************************************************************/ /* */ /* Check_Contour */ @@ -1586,13 +1773,13 @@ /* set the "current last point" */ if (ras.flipped) { - ras.last.x = SCALED( to->y ); - ras.last.y = SCALED( to->x ); + ras.last.x = to->y; + ras.last.y = to->x; } else { - ras.last.x = SCALED( to->x ); - ras.last.y = SCALED( to->y ); + ras.last.x = to->x; + ras.last.y = to->y; } ras.state = Unknown; @@ -1626,83 +1813,50 @@ int Line_To( FT_Vector* to, FT_Raster raster ) { - TPos x; - TPos y; + TPos x; + TPos y; + TDirection new_state; if ( ras.flipped ) { - x = SCALED(to->y); - y = SCALED(to->x); + x = to->y; + y = to->x; } else { - x = SCALED(to->x); - y = SCALED(to->y); + x = to->x; + y = to->y; } /* First, detect a change of direction */ - - switch ( ras.state ) + if ( y != ras.last.y ) { - case Unknown: - if ( y > ras.last.y ) + new_state = ( y > ras.last.y ? Ascending : Descending ); + if (new_state != ras.state) { - if ( New_Profile( RAS_VARS Ascending ) ) return FAILURE; + if (ras.state != Unknown && End_Profile( RAS_VAR )) + goto Fail; + + if ( New_Profile( RAS_VARS new_state) ) + goto Fail; } - else - { - if ( y < ras.last.y ) - if ( New_Profile( RAS_VARS Descending ) ) return FAILURE; - } - break; - - case Ascending: - if ( y < ras.last.y ) - { - if ( End_Profile( RAS_VAR ) || - New_Profile( RAS_VARS Descending ) ) return FAILURE; - } - break; - - case Descending: - if ( y > ras.last.y ) - { - if ( End_Profile( RAS_VAR ) || - New_Profile( RAS_VARS Ascending ) ) return FAILURE; - } - break; - - default: - ; } /* Then compute the lines */ - - switch ( ras.state ) - { - case Ascending: - if ( Line_Up ( RAS_VARS ras.last.x, ras.last.y, - x, y, ras.minY, ras.maxY ) ) - return FAILURE; - break; - - case Descending: - if ( Line_Down( RAS_VARS ras.last.x, ras.last.y, - x, y, ras.minY, ras.maxY ) ) - return FAILURE; - break; - - default: - ; - } - + if ( (ras.state == Ascending ? Line_Up : Line_Down) + ( RAS_VARS ras.last.x, ras.last.y, x, y, ras.minY, ras.maxY ) ) + goto Fail; + ras.last.x = x; ras.last.y = y; return SUCCESS; + Fail: + return FAILURE; } #ifdef FT_RASTER_CONIC_BEZIERS + /****************************************************************************/ /* */ /* Conic_To */ @@ -1725,6 +1879,37 @@ /* */ /****************************************************************************/ + static + void Push_Conic( RAS_ARGS FT_Vector* p2, + FT_Vector* p3 ) + { + #undef STORE + #define STORE( _arc, point ) \ + { \ + TPos x = point->x; \ + TPos y = point->y; \ + if (ras.flipped) \ + { \ + _arc.x = y; \ + _arc.y = x; \ + } \ + else \ + { \ + _arc.x = x; \ + _arc.y = y; \ + } \ + } + + TPoint* arc; + ras.arc = arc = ras.arcs; + + arc[2] = ras.last; + STORE( arc[1], p2 ); + STORE( arc[0], p3 ); + #undef STORE + } + + static int Conic_To( FT_Vector* control, FT_Vector* to, @@ -1786,28 +1971,17 @@ if ( ras.state != state_bez ) { - if ( ras.state != Unknown ) - if ( End_Profile( RAS_VAR ) ) return FAILURE; + if ( ras.state != Unknown && End_Profile( RAS_VAR ) ) + goto Fail; - if ( New_Profile( RAS_VARS state_bez ) ) return FAILURE; + if ( New_Profile( RAS_VARS state_bez ) ) + goto Fail; } /* compute intersections */ - switch ( ras.state ) - { - case Ascending: - if ( Conic_Up ( RAS_VARS ras.minY, ras.maxY ) ) - return FAILURE; - break; - - case Descending: - if ( Conic_Down( RAS_VARS ras.minY, ras.maxY ) ) - return FAILURE; - break; - - default: - ; - } + if ( (ras.state == Ascending ? Bezier_Up : Bezier_Down) + ( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) + goto Fail; } } while ( ras.arc >= ras.arcs ); @@ -1815,6 +1989,8 @@ ras.last.y = y3; return 0; + Fail: + return FAILURE; } #else @@ -1856,6 +2032,40 @@ /* */ /****************************************************************************/ + static + void Push_Cubic( RAS_ARGS FT_Vector* p2, + FT_Vector* p3, + FT_Vector* p4 ) + { + #undef STORE + #define STORE( _arc, point ) \ + { \ + TPos x = point->x; \ + TPos y = point->y; \ + if (ras.flipped) \ + { \ + _arc.x = y; \ + _arc.y = x; \ + } \ + else \ + { \ + _arc.x = x; \ + _arc.y = y; \ + } \ + } + + TPoint* arc; + ras.arc = arc = ras.arcs; + + arc[3] = ras.last; + STORE( arc[2], p2 ); + STORE( arc[1], p3 ); + STORE( arc[0], p4 ); + + #undef STORE + } + + static int Cubic_To( FT_Vector* control1, FT_Vector* control2, @@ -1918,29 +2128,17 @@ if ( ras.state != state_bez ) { - if ( ras.state != Unknown ) - if ( End_Profile( RAS_VAR ) ) return FAILURE; + if ( ras.state != Unknown && End_Profile( RAS_VAR ) ) + goto Fail; - if ( New_Profile( RAS_VARS state_bez ) ) return FAILURE; + if ( New_Profile( RAS_VARS state_bez ) ) + goto Fail; } - /* compute */ - - switch ( ras.state ) - { - case Ascending: - if ( Cubic_Up ( RAS_VARS ras.minY, ras.maxY ) ) - return FAILURE; - break; - - case Descending: - if ( Cubic_Down( RAS_VARS ras.minY, ras.maxY ) ) - return FAILURE; - break; - - default: - ; - } + /* compute intersections */ + if ( (ras.state == Ascending ? Bezier_Up : Bezier_Down) + ( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) + goto Fail; } } while ( ras.arc >= ras.arcs ); @@ -1948,6 +2146,8 @@ ras.last.y = y4; return 0; + Fail: + return FAILURE; } #else @@ -1991,7 +2191,9 @@ (FT_Outline_MoveTo_Func)Move_To, (FT_Outline_LineTo_Func)Line_To, (FT_Outline_ConicTo_Func)Conic_To, - (FT_Outline_CubicTo_Func)Cubic_To + (FT_Outline_CubicTo_Func)Cubic_To, + 0, + 0 }; /* Set up state in the raster object */ @@ -2007,6 +2209,9 @@ ras.cur_prof->offset = ras.cursor; ras.num_profs = 0; + interface.shift = ras.scale_shift; + interface.delta = ras.precision_half; + /* Now decompose curve */ if ( FT_Outline_Decompose( outline, &interface, &ras ) ) return FAILURE; /* XXX : the error condition is in ras.error */ @@ -2202,6 +2407,8 @@ { long pitch = ras.target.pitch; + (void)max; + ras.trace_incr = -pitch; ras.trace_bit = -*min*pitch; if (pitch > 0) @@ -2236,6 +2443,7 @@ TByte* target; /* Drop-out control */ + (void)y; e1 = TRUNC( CEILING( x1 ) ); if ( x2-x1-ras.precision <= ras.precision_jitter ) @@ -2296,7 +2504,7 @@ int x ) { int c1 = x >> 3; - + (void)y; return ( x >= 0 && x < ras.bit_width && ras.bit_buffer[ras.trace_bit + c1] & (0x80 >> (x & 7)) ); } @@ -2322,7 +2530,8 @@ int color ) { (void)color; /* unused here */ - + (void)y; + if ( x >= 0 && x < ras.bit_width ) { int c1 = x >> 3; @@ -2378,6 +2587,9 @@ static void Horizontal_Sweep_Init( RAS_ARGS int* min, int* max ) { /* nothing, really */ + UNUSED_RASTER + (void)min; + (void)max; } @@ -2405,6 +2617,7 @@ PByte bits; TByte f1; + (void)y; /* During the horizontal sweep, we only take care of drop-outs */ if ( x2-x1 < ras.precision ) @@ -2509,6 +2722,7 @@ static void Horizontal_Sweep_Step( RAS_ARG ) { /* Nothing, really */ + UNUSED_RASTER; } @@ -2650,6 +2864,8 @@ int f1 = x & 3; int mask = (0x80 >> f1) >> ((y & 1)*4); + (void)y; + return ( x >= 0 && x < ras.bit_width && ras.bit_buffer[c1] & mask ); @@ -2662,6 +2878,7 @@ int color ) { (void)color; /* unused here */ + (void)y; if ( x >= 0 && x < ras.bit_width ) { @@ -2769,6 +2986,7 @@ TPos x2 ) { /* nothing, really */ + UNUSED_RASTER (void)y; (void)x1; (void)x2; @@ -2780,6 +2998,7 @@ int x ) { /* don't do anything here */ + UNUSED_RASTER (void)x; (void)y; @@ -3046,6 +3265,7 @@ TPos x2 ) { /* nothing, really */ + UNUSED_RASTER (void)y; (void)x1; (void)x2; @@ -3057,6 +3277,7 @@ int x ) { /* don't do anything here */ + UNUSED_RASTER (void)x; (void)y; @@ -3417,12 +3638,16 @@ Scan_DropOuts : while ( ras.band_top >= 0 ) { +#if 1 + ras.maxY = (long)ras.band_stack[ras.band_top].y_max * ras.precision; + ras.minY = (long)ras.band_stack[ras.band_top].y_min * ras.precision; +#else ras.maxY = ((long)ras.band_stack[ras.band_top].y_max << (ras.scale_shift+6))-1; ras.minY = (long)ras.band_stack[ras.band_top].y_min << (ras.scale_shift+6); - +#endif ras.cursor = ras.pool; ras.error = 0; @@ -3516,7 +3741,7 @@ Scan_DropOuts : /* Vertical Sweep */ ras.band_top = 0; ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.rows; + ras.band_stack[0].y_max = ras.target.rows - 1; ras.Proc_Sweep_Init = Vertical_Sweep_Init; ras.Proc_Sweep_Span = Vertical_Sweep_Span;