Index: src/effects/gradients/SkClampRange.cpp |
diff --git a/src/effects/gradients/SkClampRange.cpp b/src/effects/gradients/SkClampRange.cpp |
index 4f8611281a30607376eb63b227f2809120d2e553..0bf30f14eafda9b480f13a8a5a23b8cd2210851f 100644 |
--- a/src/effects/gradients/SkClampRange.cpp |
+++ b/src/effects/gradients/SkClampRange.cpp |
@@ -1,4 +1,3 @@ |
- |
/* |
* Copyright 2011 Google Inc. |
* |
@@ -6,8 +5,33 @@ |
* found in the LICENSE file. |
*/ |
- |
#include "SkClampRange.h" |
+#include "SkMath.h" |
+ |
+static int SkCLZ64(uint64_t value) { |
+ int count = 0; |
+ if (value >> 32) { |
+ value >>= 32; |
+ } else { |
+ count += 32; |
+ } |
+ return count + SkCLZ(SkToU32(value)); |
+} |
+ |
+static bool sk_64_smul_check(int64_t a, int64_t b, int64_t* result) { |
+ // Do it the slow way until we have some assembly. |
+ int64_t ua = SkTAbs(a); |
+ int64_t ub = SkTAbs(b); |
+ int zeros = SkCLZ64(ua) + SkCLZ64(ub); |
+ // this is a conservative check: it may return false when in fact it would not have overflowed. |
+ // Hackers Delight uses 34 as its convervative check, but that is for 32x32 multiplies. |
+ // Since we are looking at 64x64 muls, we add 32 to the check. |
+ if (zeros < (32 + 34)) { |
+ return false; |
+ } |
+ *result = a * b; |
+ return true; |
+} |
/* |
* returns [0..count] for the number of steps (<= count) for which x0 <= edge |
@@ -58,6 +82,14 @@ void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int |
int64_t dx = dx0; |
// start with ex equal to the last computed value |
+ int64_t count_times_dx; |
+ if (!sk_64_smul_check(count - 1, dx, &count_times_dx)) { |
+ // we can't represent the computed end in 32.32, so just draw something (first color) |
+ fCount1 = fCount2 = 0; |
+ fCount0 = count; |
+ return; |
+ } |
+ |
int64_t ex = fx + (count - 1) * dx; |
if ((uint64_t)(fx | ex) <= kFracMax_SkGradFixed) { |
@@ -77,8 +109,6 @@ void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int |
return; |
} |
- int extraCount = 0; |
- |
// now make ex be 1 past the last computed value |
ex += dx; |
@@ -93,11 +123,15 @@ void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int |
fCount0 = chop(fx, 0, ex, dx, count); |
+ SkASSERT(fCount0 >= 0); |
+ SkASSERT(fCount0 <= count); |
count -= fCount0; |
fx += fCount0 * dx; |
SkASSERT(fx >= 0); |
SkASSERT(fCount0 == 0 || (fx - dx) < 0); |
fCount1 = chop(fx, kFracMax_SkGradFixed, ex, dx, count); |
+ SkASSERT(fCount1 >= 0); |
+ SkASSERT(fCount1 <= count); |
count -= fCount1; |
fCount2 = count; |
@@ -121,10 +155,4 @@ void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int |
if (fCount1 > 0) { |
fFx1 = fx0 + fCount0 * dx; |
} |
- |
- if (dx > 0) { |
- fCount2 += extraCount; |
- } else { |
- fCount0 += extraCount; |
- } |
} |