From fba3b6d1979c1d1ad0d56d46fc2d787f111c07fb Mon Sep 17 00:00:00 2001 From: marha Date: Thu, 26 Jun 2014 09:46:14 +0200 Subject: Updated to freetype 2.5.3 --- freetype/src/base/ftbbox.c | 334 ++++++++++++--------------------------------- 1 file changed, 86 insertions(+), 248 deletions(-) (limited to 'freetype/src/base/ftbbox.c') diff --git a/freetype/src/base/ftbbox.c b/freetype/src/base/ftbbox.c index 6d1c44cb2..8d3f383b4 100644 --- a/freetype/src/base/ftbbox.c +++ b/freetype/src/base/ftbbox.c @@ -85,7 +85,7 @@ /* BBox_Conic_Check */ /* */ /* */ - /* Finds the extrema of a 1-dimensional conic Bezier curve and update */ + /* Find the extrema of a 1-dimensional conic Bezier curve and update */ /* a bounding range. This version uses direct computation, as it */ /* doesn't need square roots. */ /* */ @@ -108,30 +108,19 @@ FT_Pos* min, FT_Pos* max ) { - if ( y1 <= y3 && y2 == y1 ) /* flat arc */ - goto Suite; - - if ( y1 < y3 ) - { - if ( y2 >= y1 && y2 <= y3 ) /* ascending arc */ - goto Suite; - } - else - { - if ( y2 >= y3 && y2 <= y1 ) /* descending arc */ - { - y2 = y1; - y1 = y3; - y3 = y2; - goto Suite; - } - } - - y1 = y3 = y1 - FT_MulDiv( y2 - y1, y2 - y1, y1 - 2*y2 + y3 ); - - Suite: - if ( y1 < *min ) *min = y1; - if ( y3 > *max ) *max = y3; + /* This function is only called when a control off-point is outside */ + /* the bbox that contains all on-points. It finds a local extremum */ + /* within the segment, equal to (y1*y3 - y2*y2)/(y1 - 2*y2 + y3). */ + /* Or, offsetting from y2, we get */ + + y1 -= y2; + y3 -= y2; + y2 += FT_MulDiv( y1, y3, y1 + y3 ); + + if ( y2 < *min ) + *min = y2; + if ( y2 > *max ) + *max = y2; } @@ -195,9 +184,9 @@ /* BBox_Cubic_Check */ /* */ /* */ - /* Finds the extrema of a 1-dimensional cubic Bezier curve and */ - /* updates a bounding range. This version uses splitting because we */ - /* don't want to use square roots and extra accuracy. */ + /* Find the extrema of a 1-dimensional cubic Bezier curve and */ + /* update a bounding range. This version uses iterative splitting */ + /* because it is faster than the exact solution with square roots. */ /* */ /* */ /* p1 :: The start coordinate. */ @@ -213,28 +202,16 @@ /* */ /* max :: The address of the current maximum. */ /* */ - -#if 0 - - static void - BBox_Cubic_Check( FT_Pos p1, - FT_Pos p2, - FT_Pos p3, - FT_Pos p4, - FT_Pos* min, - FT_Pos* max ) + static FT_Pos + update_cubic_max( FT_Pos q1, + FT_Pos q2, + FT_Pos q3, + FT_Pos q4, + FT_Pos max ) { - FT_Pos q1, q2, q3, q4; - - - q1 = p1; - q2 = p2; - q3 = p3; - q4 = p4; - - /* for a conic segment to possibly reach new maximum */ - /* one of its off-points must be above the current value */ - while ( q2 > *max || q3 > *max ) + /* for a cubic segment to possibly reach new maximum, at least */ + /* one of its off-points must stay above the current value */ + while ( q2 > max || q3 > max ) { /* determine which half contains the maximum and split */ if ( q1 + q2 > q3 + q4 ) /* first half */ @@ -260,231 +237,91 @@ q3 = q3 / 2; } - /* check if either end reached the maximum */ + /* check whether either end reached the maximum */ if ( q1 == q2 && q1 >= q3 ) { - *max = q1; + max = q1; break; } if ( q3 == q4 && q2 <= q4 ) { - *max = q4; + max = q4; break; } } - q1 = p1; - q2 = p2; - q3 = p3; - q4 = p4; - - /* for a conic segment to possibly reach new minimum */ - /* one of its off-points must be below the current value */ - while ( q2 < *min || q3 < *min ) - { - /* determine which half contains the minimum and split */ - if ( q1 + q2 < q3 + q4 ) /* first half */ - { - q4 = q4 + q3; - q3 = q3 + q2; - q2 = q2 + q1; - q4 = q4 + q3; - q3 = q3 + q2; - q4 = ( q4 + q3 ) / 8; - q3 = q3 / 4; - q2 = q2 / 2; - } - else /* second half */ - { - q1 = q1 + q2; - q2 = q2 + q3; - q3 = q3 + q4; - q1 = q1 + q2; - q2 = q2 + q3; - q1 = ( q1 + q2 ) / 8; - q2 = q2 / 4; - q3 = q3 / 2; - } - - /* check if either end reached the minimum */ - if ( q1 == q2 && q1 <= q3 ) - { - *min = q1; - break; - } - if ( q3 == q4 && q2 >= q4 ) - { - *min = q4; - break; - } - } - } - -#else - - static void - test_cubic_extrema( FT_Pos y1, - FT_Pos y2, - FT_Pos y3, - FT_Pos y4, - FT_Fixed u, - FT_Pos* min, - FT_Pos* max ) - { - /* FT_Pos a = y4 - 3*y3 + 3*y2 - y1; */ - FT_Pos b = y3 - 2*y2 + y1; - FT_Pos c = y2 - y1; - FT_Pos d = y1; - FT_Pos y; - FT_Fixed uu; - - FT_UNUSED ( y4 ); - - - /* The polynomial is */ - /* */ - /* P(x) = a*x^3 + 3b*x^2 + 3c*x + d , */ - /* */ - /* dP/dx = 3a*x^2 + 6b*x + 3c . */ - /* */ - /* However, we also have */ - /* */ - /* dP/dx(u) = 0 , */ - /* */ - /* which implies by subtraction that */ - /* */ - /* P(u) = b*u^2 + 2c*u + d . */ - - if ( u > 0 && u < 0x10000L ) - { - uu = FT_MulFix( u, u ); - y = d + FT_MulFix( c, 2*u ) + FT_MulFix( b, uu ); - - if ( y < *min ) *min = y; - if ( y > *max ) *max = y; - } + return max; } static void - BBox_Cubic_Check( FT_Pos y1, - FT_Pos y2, - FT_Pos y3, - FT_Pos y4, + BBox_Cubic_Check( FT_Pos p1, + FT_Pos p2, + FT_Pos p3, + FT_Pos p4, FT_Pos* min, FT_Pos* max ) { - /* always compare first and last points */ - if ( y1 < *min ) *min = y1; - else if ( y1 > *max ) *max = y1; + FT_Pos nmin, nmax; + FT_Int shift; - if ( y4 < *min ) *min = y4; - else if ( y4 > *max ) *max = y4; - /* now, try to see if there are split points here */ - if ( y1 <= y4 ) + /* This function is only called when a control off-point is outside */ + /* the bbox that contains all on-points. It finds a local extremum */ + /* within the segment using iterative bisection of the segment. */ + /* The fixed-point arithmetic 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. */ + /* The control off-point outside the bbox is likely to have the top */ + /* absolute value among arguments. */ + + shift = 27 - FT_MSB( FT_ABS( p2 ) | FT_ABS( p3 ) ); + + if ( shift > 0 ) { - /* flat or ascending arc test */ - if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 ) - return; + /* 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 /* y1 > y4 */ + else { - /* descending arc test */ - if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 ) - return; + p1 >>= -shift; + p2 >>= -shift; + p3 >>= -shift; + p4 >>= -shift; + nmin = *min >> -shift; + nmax = *max >> -shift; } - /* There are some split points. Find them. */ - /* We already made sure that a, b, and c below cannot be all zero. */ - { - FT_Pos a = y4 - 3*y3 + 3*y2 - y1; - FT_Pos b = y3 - 2*y2 + y1; - FT_Pos c = y2 - y1; - FT_Pos d; - FT_Fixed t; - FT_Int shift; - - - /* We need to solve `ax^2+2bx+c' here, without floating points! */ - /* The trick is to normalize to a different representation in order */ - /* to use our 16.16 fixed-point routines. */ - /* */ - /* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after normalization. */ - /* These values must fit into a single 16.16 value. */ - /* */ - /* We normalize a, b, and c to `8.16' fixed-point values to ensure */ - /* that their product is held in a `16.16' value including the sign. */ - /* Necessarily, we need to shift `a', `b', and `c' so that the most */ - /* significant bit of their absolute values is at position 22. */ - /* */ - /* This also means that we are using 23 bits of precision to compute */ - /* the zeros, independently of the range of the original polynomial */ - /* coefficients. */ - /* */ - /* This algorithm should ensure reasonably accurate values for the */ - /* zeros. Note that they are only expressed with 16 bits when */ - /* computing the extrema (the zeros need to be in 0..1 exclusive */ - /* to be considered part of the arc). */ - - shift = FT_MSB( FT_ABS( a ) | FT_ABS( b ) | FT_ABS( c ) ); - - if ( shift > 22 ) - { - shift -= 22; + nmax = update_cubic_max( p1, p2, p3, p4, nmax ); - /* this loses some bits of precision, but we use 23 of them */ - /* for the computation anyway */ - a >>= shift; - b >>= shift; - c >>= shift; - } - else - { - shift = 22 - shift; - - a <<= shift; - b <<= shift; - c <<= shift; - } + /* now flip the signs to update the minimum */ + nmin = -update_cubic_max( -p1, -p2, -p3, -p4, -nmin ); - /* handle a == 0 */ - if ( a == 0 ) - { - if ( b != 0 ) - { - t = - FT_DivFix( c, b ) / 2; - test_cubic_extrema( y1, y2, y3, y4, t, min, max ); - } - } - else - { - /* solve the equation now */ - d = FT_MulFix( b, b ) - FT_MulFix( a, c ); - if ( d < 0 ) - return; - - if ( d == 0 ) - { - /* there is a single split point at -b/a */ - t = - FT_DivFix( b, a ); - test_cubic_extrema( y1, y2, y3, y4, t, min, max ); - } - else - { - /* there are two solutions; we need to filter them */ - d = FT_SqrtFixed( (FT_Int32)d ); - t = - FT_DivFix( b - d, a ); - test_cubic_extrema( y1, y2, y3, y4, t, min, max ); - - t = - FT_DivFix( b + d, a ); - test_cubic_extrema( y1, y2, y3, y4, t, min, max ); - } - } + if ( shift > 0 ) + { + nmin >>= shift; + nmax >>= shift; + } + else + { + nmin <<= -shift; + nmax <<= -shift; } - } -#endif + if ( nmin < *min ) + *min = nmin; + if ( nmax > *max ) + *max = nmax; + } /*************************************************************************/ @@ -521,8 +358,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 ) ) -- cgit v1.2.3