1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkClampRange.h" 9 #include "SkMathPriv.h" 10 11 static int SkCLZ64(uint64_t value) { 12 int count = 0; 13 if (value >> 32) { 14 value >>= 32; 15 } else { 16 count += 32; 17 } 18 return count + SkCLZ(SkToU32(value)); 19 } 20 21 static bool sk_64_smul_check(int64_t count, int64_t dx, int64_t* result) { 22 // Do it the slow way until we have some assembly. 23 if (dx == std::numeric_limits<int64_t>::min()) { 24 return false; // SkTAbs overflow 25 } 26 27 SkASSERT(count >= 0); 28 uint64_t ucount = static_cast<uint64_t>(count); 29 uint64_t udx = static_cast<uint64_t>(SkTAbs(dx)); 30 int zeros = SkCLZ64(ucount) + SkCLZ64(udx); 31 // this is a conservative check: it may return false when in fact it would not have overflowed. 32 // Hackers Delight uses 34 as its convervative check, but that is for 32x32 multiplies. 33 // Since we are looking at 64x64 muls, we add 32 to the check. 34 if (zeros < (32 + 34)) { 35 return false; 36 } 37 *result = count * dx; 38 return true; 39 } 40 41 static bool sk_64_sadd_check(int64_t a, int64_t b, int64_t* result) { 42 if (a > 0) { 43 if (b > std::numeric_limits<int64_t>::max() - a) { 44 return false; 45 } 46 } else { 47 if (b < std::numeric_limits<int64_t>::min() - a) { 48 return false; 49 } 50 } 51 52 *result = a + b; 53 return true; 54 } 55 56 57 /* 58 * returns [0..count] for the number of steps (<= count) for which x0 <= edge 59 * given each step is followed by x0 += dx 60 */ 61 static int chop(int64_t x0, SkGradFixed edge, int64_t x1, int64_t dx, int count) { 62 SkASSERT(dx > 0); 63 SkASSERT(count >= 0); 64 65 if (x0 >= edge) { 66 return 0; 67 } 68 if (x1 <= edge) { 69 return count; 70 } 71 int64_t n = (edge - x0 + dx - 1) / dx; 72 SkASSERT(n >= 0); 73 SkASSERT(n <= count); 74 return (int)n; 75 } 76 77 void SkClampRange::initFor1(SkGradFixed fx) { 78 fCount0 = fCount1 = fCount2 = 0; 79 if (fx <= 0) { 80 fCount0 = 1; 81 } else if (fx < kFracMax_SkGradFixed) { 82 fCount1 = 1; 83 fFx1 = fx; 84 } else { 85 fCount2 = 1; 86 } 87 } 88 89 void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int v1) { 90 SkASSERT(count > 0); 91 92 fV0 = v0; 93 fV1 = v1; 94 95 // special case 1 == count, as it is slightly common for skia 96 // and avoids us ever calling divide or 64bit multiply 97 if (1 == count) { 98 this->initFor1(fx0); 99 return; 100 } 101 102 int64_t fx = fx0; 103 int64_t dx = dx0; 104 105 // start with ex equal to the last computed value 106 int64_t count_times_dx, ex; 107 if (!sk_64_smul_check(count - 1, dx, &count_times_dx) || 108 !sk_64_sadd_check(fx, count_times_dx, &ex)) { 109 // we can't represent the computed end in 32.32, so just draw something (first color) 110 fCount1 = fCount2 = 0; 111 fCount0 = count; 112 return; 113 } 114 115 if ((uint64_t)(fx | ex) <= kFracMax_SkGradFixed) { 116 fCount0 = fCount2 = 0; 117 fCount1 = count; 118 fFx1 = fx0; 119 return; 120 } 121 if (fx <= 0 && ex <= 0) { 122 fCount1 = fCount2 = 0; 123 fCount0 = count; 124 return; 125 } 126 if (fx >= kFracMax_SkGradFixed && ex >= kFracMax_SkGradFixed) { 127 fCount0 = fCount1 = 0; 128 fCount2 = count; 129 return; 130 } 131 132 // now make ex be 1 past the last computed value 133 ex += dx; 134 135 bool doSwap = dx < 0; 136 137 if (doSwap) { 138 ex -= dx; 139 fx -= dx; 140 SkTSwap(fx, ex); 141 dx = -dx; 142 } 143 144 145 fCount0 = chop(fx, 0, ex, dx, count); 146 SkASSERT(fCount0 >= 0); 147 SkASSERT(fCount0 <= count); 148 count -= fCount0; 149 fx += fCount0 * dx; 150 SkASSERT(fx >= 0); 151 SkASSERT(fCount0 == 0 || (fx - dx) < 0); 152 fCount1 = chop(fx, kFracMax_SkGradFixed, ex, dx, count); 153 SkASSERT(fCount1 >= 0); 154 SkASSERT(fCount1 <= count); 155 count -= fCount1; 156 fCount2 = count; 157 158 #ifdef SK_DEBUG 159 fx += fCount1 * dx; 160 SkASSERT(fx <= ex); 161 if (fCount2 > 0) { 162 SkASSERT(fx >= kFracMax_SkGradFixed); 163 if (fCount1 > 0) { 164 SkASSERT(fx - dx < kFracMax_SkGradFixed); 165 } 166 } 167 #endif 168 169 if (doSwap) { 170 SkTSwap(fCount0, fCount2); 171 SkTSwap(fV0, fV1); 172 dx = -dx; 173 } 174 175 if (fCount1 > 0) { 176 fFx1 = fx0 + fCount0 * dx; 177 } 178 } 179