blob: f820a037107557c5a0143854f0eab89ca90ca31e [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
41/*
42 * returns [0..count] for the number of steps (<= count) for which x0 <= edge
43 * given each step is followed by x0 += dx
44 */
reedcaf7e932014-12-18 12:43:08 -080045static int chop(int64_t x0, SkGradFixed edge, int64_t x1, int64_t dx, int count) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000046 SkASSERT(dx > 0);
47 SkASSERT(count >= 0);
48
49 if (x0 >= edge) {
50 return 0;
51 }
52 if (x1 <= edge) {
53 return count;
54 }
reed@google.com13659f12011-04-18 19:59:38 +000055 int64_t n = (edge - x0 + dx - 1) / dx;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000056 SkASSERT(n >= 0);
57 SkASSERT(n <= count);
reed@google.com13659f12011-04-18 19:59:38 +000058 return (int)n;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000059}
60
reedcaf7e932014-12-18 12:43:08 -080061void SkClampRange::initFor1(SkGradFixed fx) {
reed@google.com13659f12011-04-18 19:59:38 +000062 fCount0 = fCount1 = fCount2 = 0;
63 if (fx <= 0) {
64 fCount0 = 1;
reedcaf7e932014-12-18 12:43:08 -080065 } else if (fx < kFracMax_SkGradFixed) {
reed@google.com13659f12011-04-18 19:59:38 +000066 fCount1 = 1;
67 fFx1 = fx;
68 } else {
69 fCount2 = 1;
70 }
71}
72
reedcaf7e932014-12-18 12:43:08 -080073void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int v1) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000074 SkASSERT(count > 0);
75
76 fV0 = v0;
77 fV1 = v1;
78
reed@google.com13659f12011-04-18 19:59:38 +000079 // special case 1 == count, as it is slightly common for skia
80 // and avoids us ever calling divide or 64bit multiply
81 if (1 == count) {
82 this->initFor1(fx0);
83 return;
reed@google.com63c1ad82011-04-18 14:15:36 +000084 }
85
reed@google.com13659f12011-04-18 19:59:38 +000086 int64_t fx = fx0;
87 int64_t dx = dx0;
reedcaf7e932014-12-18 12:43:08 -080088
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000089 // start with ex equal to the last computed value
reed9d91eb32015-01-28 11:44:48 -080090 int64_t count_times_dx;
91 if (!sk_64_smul_check(count - 1, dx, &count_times_dx)) {
92 // we can't represent the computed end in 32.32, so just draw something (first color)
93 fCount1 = fCount2 = 0;
94 fCount0 = count;
95 return;
96 }
97
reed@google.com13659f12011-04-18 19:59:38 +000098 int64_t ex = fx + (count - 1) * dx;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000099
reedcaf7e932014-12-18 12:43:08 -0800100 if ((uint64_t)(fx | ex) <= kFracMax_SkGradFixed) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000101 fCount0 = fCount2 = 0;
102 fCount1 = count;
reed@google.com13659f12011-04-18 19:59:38 +0000103 fFx1 = fx0;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000104 return;
105 }
106 if (fx <= 0 && ex <= 0) {
107 fCount1 = fCount2 = 0;
108 fCount0 = count;
109 return;
110 }
reedcaf7e932014-12-18 12:43:08 -0800111 if (fx >= kFracMax_SkGradFixed && ex >= kFracMax_SkGradFixed) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000112 fCount0 = fCount1 = 0;
113 fCount2 = count;
114 return;
115 }
116
117 // now make ex be 1 past the last computed value
118 ex += dx;
reedcaf7e932014-12-18 12:43:08 -0800119
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000120 bool doSwap = dx < 0;
121
122 if (doSwap) {
123 ex -= dx;
124 fx -= dx;
125 SkTSwap(fx, ex);
126 dx = -dx;
127 }
128
reed@google.com13659f12011-04-18 19:59:38 +0000129
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000130 fCount0 = chop(fx, 0, ex, dx, count);
reed9d91eb32015-01-28 11:44:48 -0800131 SkASSERT(fCount0 >= 0);
132 SkASSERT(fCount0 <= count);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000133 count -= fCount0;
134 fx += fCount0 * dx;
135 SkASSERT(fx >= 0);
136 SkASSERT(fCount0 == 0 || (fx - dx) < 0);
reedcaf7e932014-12-18 12:43:08 -0800137 fCount1 = chop(fx, kFracMax_SkGradFixed, ex, dx, count);
reed9d91eb32015-01-28 11:44:48 -0800138 SkASSERT(fCount1 >= 0);
139 SkASSERT(fCount1 <= count);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000140 count -= fCount1;
141 fCount2 = count;
142
143#ifdef SK_DEBUG
144 fx += fCount1 * dx;
145 SkASSERT(fx <= ex);
146 if (fCount2 > 0) {
reedcaf7e932014-12-18 12:43:08 -0800147 SkASSERT(fx >= kFracMax_SkGradFixed);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000148 if (fCount1 > 0) {
reedcaf7e932014-12-18 12:43:08 -0800149 SkASSERT(fx - dx < kFracMax_SkGradFixed);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000150 }
151 }
152#endif
153
154 if (doSwap) {
155 SkTSwap(fCount0, fCount2);
156 SkTSwap(fV0, fV1);
reed@google.com63c1ad82011-04-18 14:15:36 +0000157 dx = -dx;
158 }
159
160 if (fCount1 > 0) {
reed438b0d72014-12-19 07:40:26 -0800161 fFx1 = fx0 + fCount0 * dx;
reed@google.com13659f12011-04-18 19:59:38 +0000162 }
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000163}