blob: efc93959d11bd14ca9c73b343f1b99762e170222 [file] [log] [blame]
mike@reedtribe.org676d69b2011-04-15 03:43:23 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * 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.
mike@reedtribe.org676d69b2011-04-15 03:43:23 +00006 */
7
8#include "SkClampRange.h"
halcanary4dbbd042016-06-07 17:21:10 -07009#include "SkMathPriv.h"
reed9d91eb32015-01-28 11:44:48 -080010
11static 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
Florin Malita72245c52016-12-13 09:42:20 -050021static bool sk_64_smul_check(int64_t count, int64_t dx, int64_t* result) {
reed9d91eb32015-01-28 11:44:48 -080022 // Do it the slow way until we have some assembly.
Florin Malita72245c52016-12-13 09:42:20 -050023 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);
reed9d91eb32015-01-28 11:44:48 -080031 // 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 }
Florin Malita72245c52016-12-13 09:42:20 -050037 *result = count * dx;
reed9d91eb32015-01-28 11:44:48 -080038 return true;
39}
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000040
Florin Malitad9569662017-02-09 16:41:34 -050041static 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
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000057/*
58 * returns [0..count] for the number of steps (<= count) for which x0 <= edge
59 * given each step is followed by x0 += dx
60 */
reedcaf7e932014-12-18 12:43:08 -080061static int chop(int64_t x0, SkGradFixed edge, int64_t x1, int64_t dx, int count) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000062 SkASSERT(dx > 0);
63 SkASSERT(count >= 0);
64
65 if (x0 >= edge) {
66 return 0;
67 }
68 if (x1 <= edge) {
69 return count;
70 }
reed@google.com13659f12011-04-18 19:59:38 +000071 int64_t n = (edge - x0 + dx - 1) / dx;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000072 SkASSERT(n >= 0);
73 SkASSERT(n <= count);
reed@google.com13659f12011-04-18 19:59:38 +000074 return (int)n;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000075}
76
reedcaf7e932014-12-18 12:43:08 -080077void SkClampRange::initFor1(SkGradFixed fx) {
reed@google.com13659f12011-04-18 19:59:38 +000078 fCount0 = fCount1 = fCount2 = 0;
79 if (fx <= 0) {
80 fCount0 = 1;
reedcaf7e932014-12-18 12:43:08 -080081 } else if (fx < kFracMax_SkGradFixed) {
reed@google.com13659f12011-04-18 19:59:38 +000082 fCount1 = 1;
83 fFx1 = fx;
84 } else {
85 fCount2 = 1;
86 }
87}
88
reedcaf7e932014-12-18 12:43:08 -080089void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int v1) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000090 SkASSERT(count > 0);
91
92 fV0 = v0;
93 fV1 = v1;
94
reed@google.com13659f12011-04-18 19:59:38 +000095 // 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;
reed@google.com63c1ad82011-04-18 14:15:36 +0000100 }
101
reed@google.com13659f12011-04-18 19:59:38 +0000102 int64_t fx = fx0;
103 int64_t dx = dx0;
reedcaf7e932014-12-18 12:43:08 -0800104
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000105 // start with ex equal to the last computed value
Florin Malitad9569662017-02-09 16:41:34 -0500106 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)) {
reed9d91eb32015-01-28 11:44:48 -0800109 // 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
reedcaf7e932014-12-18 12:43:08 -0800115 if ((uint64_t)(fx | ex) <= kFracMax_SkGradFixed) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000116 fCount0 = fCount2 = 0;
117 fCount1 = count;
reed@google.com13659f12011-04-18 19:59:38 +0000118 fFx1 = fx0;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000119 return;
120 }
121 if (fx <= 0 && ex <= 0) {
122 fCount1 = fCount2 = 0;
123 fCount0 = count;
124 return;
125 }
reedcaf7e932014-12-18 12:43:08 -0800126 if (fx >= kFracMax_SkGradFixed && ex >= kFracMax_SkGradFixed) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000127 fCount0 = fCount1 = 0;
128 fCount2 = count;
129 return;
130 }
131
132 // now make ex be 1 past the last computed value
133 ex += dx;
reedcaf7e932014-12-18 12:43:08 -0800134
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000135 bool doSwap = dx < 0;
136
137 if (doSwap) {
138 ex -= dx;
139 fx -= dx;
140 SkTSwap(fx, ex);
141 dx = -dx;
142 }
143
reed@google.com13659f12011-04-18 19:59:38 +0000144
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000145 fCount0 = chop(fx, 0, ex, dx, count);
reed9d91eb32015-01-28 11:44:48 -0800146 SkASSERT(fCount0 >= 0);
147 SkASSERT(fCount0 <= count);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000148 count -= fCount0;
149 fx += fCount0 * dx;
150 SkASSERT(fx >= 0);
151 SkASSERT(fCount0 == 0 || (fx - dx) < 0);
reedcaf7e932014-12-18 12:43:08 -0800152 fCount1 = chop(fx, kFracMax_SkGradFixed, ex, dx, count);
reed9d91eb32015-01-28 11:44:48 -0800153 SkASSERT(fCount1 >= 0);
154 SkASSERT(fCount1 <= count);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000155 count -= fCount1;
156 fCount2 = count;
157
158#ifdef SK_DEBUG
159 fx += fCount1 * dx;
160 SkASSERT(fx <= ex);
161 if (fCount2 > 0) {
reedcaf7e932014-12-18 12:43:08 -0800162 SkASSERT(fx >= kFracMax_SkGradFixed);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000163 if (fCount1 > 0) {
reedcaf7e932014-12-18 12:43:08 -0800164 SkASSERT(fx - dx < kFracMax_SkGradFixed);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000165 }
166 }
167#endif
168
169 if (doSwap) {
170 SkTSwap(fCount0, fCount2);
171 SkTSwap(fV0, fV1);
reed@google.com63c1ad82011-04-18 14:15:36 +0000172 dx = -dx;
173 }
174
175 if (fCount1 > 0) {
reed438b0d72014-12-19 07:40:26 -0800176 fFx1 = fx0 + fCount0 * dx;
reed@google.com13659f12011-04-18 19:59:38 +0000177 }
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000178}