blob: 0bf30f14eafda9b480f13a8a5a23b8cd2210851f [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"
reed9d91eb32015-01-28 11:44:48 -08009#include "SkMath.h"
10
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
21static bool sk_64_smul_check(int64_t a, int64_t b, int64_t* result) {
22 // Do it the slow way until we have some assembly.
23 int64_t ua = SkTAbs(a);
24 int64_t ub = SkTAbs(b);
25 int zeros = SkCLZ64(ua) + SkCLZ64(ub);
26 // this is a conservative check: it may return false when in fact it would not have overflowed.
27 // Hackers Delight uses 34 as its convervative check, but that is for 32x32 multiplies.
28 // Since we are looking at 64x64 muls, we add 32 to the check.
29 if (zeros < (32 + 34)) {
30 return false;
31 }
32 *result = a * b;
33 return true;
34}
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000035
36/*
37 * returns [0..count] for the number of steps (<= count) for which x0 <= edge
38 * given each step is followed by x0 += dx
39 */
reedcaf7e932014-12-18 12:43:08 -080040static int chop(int64_t x0, SkGradFixed edge, int64_t x1, int64_t dx, int count) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000041 SkASSERT(dx > 0);
42 SkASSERT(count >= 0);
43
44 if (x0 >= edge) {
45 return 0;
46 }
47 if (x1 <= edge) {
48 return count;
49 }
reed@google.com13659f12011-04-18 19:59:38 +000050 int64_t n = (edge - x0 + dx - 1) / dx;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000051 SkASSERT(n >= 0);
52 SkASSERT(n <= count);
reed@google.com13659f12011-04-18 19:59:38 +000053 return (int)n;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000054}
55
reedcaf7e932014-12-18 12:43:08 -080056void SkClampRange::initFor1(SkGradFixed fx) {
reed@google.com13659f12011-04-18 19:59:38 +000057 fCount0 = fCount1 = fCount2 = 0;
58 if (fx <= 0) {
59 fCount0 = 1;
reedcaf7e932014-12-18 12:43:08 -080060 } else if (fx < kFracMax_SkGradFixed) {
reed@google.com13659f12011-04-18 19:59:38 +000061 fCount1 = 1;
62 fFx1 = fx;
63 } else {
64 fCount2 = 1;
65 }
66}
67
reedcaf7e932014-12-18 12:43:08 -080068void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int v1) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000069 SkASSERT(count > 0);
70
71 fV0 = v0;
72 fV1 = v1;
73
reed@google.com13659f12011-04-18 19:59:38 +000074 // special case 1 == count, as it is slightly common for skia
75 // and avoids us ever calling divide or 64bit multiply
76 if (1 == count) {
77 this->initFor1(fx0);
78 return;
reed@google.com63c1ad82011-04-18 14:15:36 +000079 }
80
reed@google.com13659f12011-04-18 19:59:38 +000081 int64_t fx = fx0;
82 int64_t dx = dx0;
reedcaf7e932014-12-18 12:43:08 -080083
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000084 // start with ex equal to the last computed value
reed9d91eb32015-01-28 11:44:48 -080085 int64_t count_times_dx;
86 if (!sk_64_smul_check(count - 1, dx, &count_times_dx)) {
87 // we can't represent the computed end in 32.32, so just draw something (first color)
88 fCount1 = fCount2 = 0;
89 fCount0 = count;
90 return;
91 }
92
reed@google.com13659f12011-04-18 19:59:38 +000093 int64_t ex = fx + (count - 1) * dx;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000094
reedcaf7e932014-12-18 12:43:08 -080095 if ((uint64_t)(fx | ex) <= kFracMax_SkGradFixed) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000096 fCount0 = fCount2 = 0;
97 fCount1 = count;
reed@google.com13659f12011-04-18 19:59:38 +000098 fFx1 = fx0;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000099 return;
100 }
101 if (fx <= 0 && ex <= 0) {
102 fCount1 = fCount2 = 0;
103 fCount0 = count;
104 return;
105 }
reedcaf7e932014-12-18 12:43:08 -0800106 if (fx >= kFracMax_SkGradFixed && ex >= kFracMax_SkGradFixed) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000107 fCount0 = fCount1 = 0;
108 fCount2 = count;
109 return;
110 }
111
112 // now make ex be 1 past the last computed value
113 ex += dx;
reedcaf7e932014-12-18 12:43:08 -0800114
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000115 bool doSwap = dx < 0;
116
117 if (doSwap) {
118 ex -= dx;
119 fx -= dx;
120 SkTSwap(fx, ex);
121 dx = -dx;
122 }
123
reed@google.com13659f12011-04-18 19:59:38 +0000124
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000125 fCount0 = chop(fx, 0, ex, dx, count);
reed9d91eb32015-01-28 11:44:48 -0800126 SkASSERT(fCount0 >= 0);
127 SkASSERT(fCount0 <= count);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000128 count -= fCount0;
129 fx += fCount0 * dx;
130 SkASSERT(fx >= 0);
131 SkASSERT(fCount0 == 0 || (fx - dx) < 0);
reedcaf7e932014-12-18 12:43:08 -0800132 fCount1 = chop(fx, kFracMax_SkGradFixed, ex, dx, count);
reed9d91eb32015-01-28 11:44:48 -0800133 SkASSERT(fCount1 >= 0);
134 SkASSERT(fCount1 <= count);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000135 count -= fCount1;
136 fCount2 = count;
137
138#ifdef SK_DEBUG
139 fx += fCount1 * dx;
140 SkASSERT(fx <= ex);
141 if (fCount2 > 0) {
reedcaf7e932014-12-18 12:43:08 -0800142 SkASSERT(fx >= kFracMax_SkGradFixed);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000143 if (fCount1 > 0) {
reedcaf7e932014-12-18 12:43:08 -0800144 SkASSERT(fx - dx < kFracMax_SkGradFixed);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000145 }
146 }
147#endif
148
149 if (doSwap) {
150 SkTSwap(fCount0, fCount2);
151 SkTSwap(fV0, fV1);
reed@google.com63c1ad82011-04-18 14:15:36 +0000152 dx = -dx;
153 }
154
155 if (fCount1 > 0) {
reed438b0d72014-12-19 07:40:26 -0800156 fFx1 = fx0 + fCount0 * dx;
reed@google.com13659f12011-04-18 19:59:38 +0000157 }
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000158}