Chromium Code Reviews| Index: trunk/src/core/SkPoint.cpp |
| =================================================================== |
| --- trunk/src/core/SkPoint.cpp (revision 8976) |
| +++ trunk/src/core/SkPoint.cpp (working copy) |
| @@ -107,30 +107,74 @@ |
| } |
| SkScalar SkPoint::Normalize(SkPoint* pt) { |
| + float x = pt->fX; |
| + float y = pt->fY; |
| float mag2; |
| - if (!isLengthNearlyZero(pt->fX, pt->fY, &mag2)) { |
| - float mag = sk_float_sqrt(mag2); |
| - float scale = 1.0f / mag; |
| - pt->fX = pt->fX * scale; |
| - pt->fY = pt->fY * scale; |
| - return mag; |
| + if (isLengthNearlyZero(x, y, &mag2)) { |
| + return false; |
|
caryclark
2013/05/03 15:41:51
return 0?
|
| } |
| - return 0; |
| + |
| + float mag, scale; |
| + if (SkScalarIsFinite(mag2)) { |
| + mag = sk_float_sqrt(mag2); |
| + scale = 1 / mag; |
| + } else { |
| + // our mag2 step overflowed to infinity, so use doubles instead. |
| + // much slower, but needed when x or y are very large, other wise we |
| + // divide by inf. and return (0,0) vector. |
| + double xx = x; |
| + double yy = y; |
| + double magmag = sqrt(xx * xx + yy * yy); |
| + mag = (float)magmag; |
| + // we perform the divide with the double magmag, to stay exactly the |
| + // same as setLength. It would be faster to perform the divide with |
| + // mag, but it is possible that mag has overflowed to inf. but still |
| + // have a non-zero value for scale (thanks to denormalized numbers). |
| + scale = (float)(1 / magmag); |
| + } |
| + pt->set(x * scale, y * scale); |
| + return mag; |
| } |
| SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) { |
| - return sk_float_sqrt(getLengthSquared(dx, dy)); |
| + float mag2 = dx * dx + dy * dy; |
| + if (SkScalarIsFinite(mag2)) { |
| + return sk_float_sqrt(mag2); |
| + } else { |
|
caryclark
2013/05/03 15:41:51
don't need else?
|
| + double xx = dx; |
| + double yy = dy; |
| + return (float)sqrt(xx * xx + yy * yy); |
| + } |
| } |
| +/* |
| + * We have to worry about 2 tricky conditions: |
| + * 1. underflow of mag2 (compared against nearlyzero^2) |
| + * 2. overflow of mag2 (compared w/ isfinite) |
| + * |
| + * If we underflow, we return false. If we overflow, we compute again using |
| + * doubles, which is much slower (3x in a desktop test) but will not overflow. |
| + */ |
| bool SkPoint::setLength(float x, float y, float length) { |
| float mag2; |
| - if (!isLengthNearlyZero(x, y, &mag2)) { |
| - float scale = length / sk_float_sqrt(mag2); |
| - fX = x * scale; |
| - fY = y * scale; |
| - return true; |
| + if (isLengthNearlyZero(x, y, &mag2)) { |
| + return false; |
| } |
| - return false; |
| + |
| + float scale; |
| + if (SkScalarIsFinite(mag2)) { |
| + scale = length / sk_float_sqrt(mag2); |
| + } else { |
| + // our mag2 step overflowed to infinity, so use doubles instead. |
| + // much slower, but needed when x or y are very large, other wise we |
| + // divide by inf. and return (0,0) vector. |
| + double xx = x; |
| + double yy = y; |
| + scale = (float)(length / sqrt(xx * xx + yy * yy)); |
| + } |
| + fX = x * scale; |
| + fY = y * scale; |
| + return true; |
| } |
| #else |