diff --git a/ChangeLog b/ChangeLog index dc12dd1e0..009835492 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,17 @@ +2013-08-15 Alexei Podtelezhnikov + + [base] Finish experimental (disabled) BBox_Cubic_Check implementation. + + * src/base/ftbbox.c (BBox_Cubic_Check): Scale arguments to improve + accuracy and avoid overflows. + 2013-08-13 Alexei Podtelezhnikov [base] Refactor experimental (disabled) BBox_Cubic_Check. * src/base/ftbbox.c (BBox_Cubic_Check): Implement the minimum search - as the mirror image of the maximum search. + as the mirror image of the maximum search implemented here... + (update_max): New function. 2013-08-06 John Tytgat diff --git a/src/base/ftbbox.c b/src/base/ftbbox.c index ca53dd894..3fe0a7d5c 100644 --- a/src/base/ftbbox.c +++ b/src/base/ftbbox.c @@ -275,10 +275,62 @@ FT_Pos* min, FT_Pos* max ) { - *max = update_max( p1, p2, p3, p4, *max ); + FT_Pos nmin, nmax; + FT_Int shift; + + /* This implementation relies on iterative bisection of the segment. */ + /* The fixed-point arithmentic of bisection is inherently stable but */ + /* may loose accuracy in the two lowest bits. To compensate, we */ + /* upscale the segment if there is room. Large values may need to be */ + /* downscaled to avoid overflows during bisection bisection. This */ + /* function is only called when a control off-point is outside the */ + /* the bbox and, thus, has the top absolute value among arguments. */ + + shift = 27 - FT_MSB( FT_ABS( p2 ) | FT_ABS( p3 ) ); + + if ( shift > 0 ) + { + /* upscaling too much just wastes time */ + if ( shift > 2 ) + shift = 2; + + p1 <<= shift; + p2 <<= shift; + p3 <<= shift; + p4 <<= shift; + nmin = *min << shift; + nmax = *max << shift; + } + else + { + p1 >>= -shift; + p2 >>= -shift; + p3 >>= -shift; + p4 >>= -shift; + nmin = *min >> -shift; + nmax = *max >> -shift; + } + + nmax = update_max( p1, p2, p3, p4, nmax ); /* now flip the signs to update the minimum */ - *min = -update_max( -p1, -p2, -p3, -p4, -*min ); + nmin = -update_max( -p1, -p2, -p3, -p4, -nmin ); + + if ( shift > 0 ) + { + nmin >>= shift; + nmax >>= shift; + } + else + { + nmin <<= -shift; + nmax <<= -shift; + } + + if ( nmin < *min ) + *min = nmin; + if ( nmax > *max ) + *max = nmax; } #else @@ -482,8 +534,9 @@ FT_Vector* to, TBBox_Rec* user ) { - /* we don't need to check `to' since it is always an `on' point, thus */ - /* within the bbox */ + /* We don't need to check `to' since it is always an on-point, */ + /* thus within the bbox. Only segments with an off-point outside */ + /* the bbox can possibly reach new extreme values. */ if ( CHECK_X( control1, user->bbox ) || CHECK_X( control2, user->bbox ) )