blob: cf302cd2a98068cec493c46f052173ad640fd09d [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
mike@reedtribe.org676d69b2011-04-15 03:43:23 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
mike@reedtribe.org676d69b2011-04-15 03:43:23 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000010#include "SkClampRange.h"
11
12/*
13 * returns [0..count] for the number of steps (<= count) for which x0 <= edge
14 * given each step is followed by x0 += dx
15 */
reedcaf7e932014-12-18 12:43:08 -080016static int chop(int64_t x0, SkGradFixed edge, int64_t x1, int64_t dx, int count) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000017 SkASSERT(dx > 0);
18 SkASSERT(count >= 0);
19
20 if (x0 >= edge) {
21 return 0;
22 }
23 if (x1 <= edge) {
24 return count;
25 }
reed@google.com13659f12011-04-18 19:59:38 +000026 int64_t n = (edge - x0 + dx - 1) / dx;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000027 SkASSERT(n >= 0);
28 SkASSERT(n <= count);
reed@google.com13659f12011-04-18 19:59:38 +000029 return (int)n;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000030}
31
reedcaf7e932014-12-18 12:43:08 -080032#ifdef SK_SUPPORT_LEGACY_GRADIENT_PRECISION
33static bool overflows_gradfixed(int64_t x) {
reed@google.com13659f12011-04-18 19:59:38 +000034 return x < -SK_FixedMax || x > SK_FixedMax;
35}
reedcaf7e932014-12-18 12:43:08 -080036#endif
reed@google.com13659f12011-04-18 19:59:38 +000037
reedcaf7e932014-12-18 12:43:08 -080038void SkClampRange::initFor1(SkGradFixed fx) {
reed@google.com13659f12011-04-18 19:59:38 +000039 fCount0 = fCount1 = fCount2 = 0;
40 if (fx <= 0) {
41 fCount0 = 1;
reedcaf7e932014-12-18 12:43:08 -080042 } else if (fx < kFracMax_SkGradFixed) {
reed@google.com13659f12011-04-18 19:59:38 +000043 fCount1 = 1;
44 fFx1 = fx;
45 } else {
46 fCount2 = 1;
47 }
48}
49
reedcaf7e932014-12-18 12:43:08 -080050void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int v1) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000051 SkASSERT(count > 0);
52
53 fV0 = v0;
54 fV1 = v1;
55
reed@google.com13659f12011-04-18 19:59:38 +000056 // special case 1 == count, as it is slightly common for skia
57 // and avoids us ever calling divide or 64bit multiply
58 if (1 == count) {
59 this->initFor1(fx0);
60 return;
reed@google.com63c1ad82011-04-18 14:15:36 +000061 }
62
reed@google.com13659f12011-04-18 19:59:38 +000063 int64_t fx = fx0;
64 int64_t dx = dx0;
reedcaf7e932014-12-18 12:43:08 -080065
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000066 // start with ex equal to the last computed value
reed@google.com13659f12011-04-18 19:59:38 +000067 int64_t ex = fx + (count - 1) * dx;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000068
reedcaf7e932014-12-18 12:43:08 -080069 if ((uint64_t)(fx | ex) <= kFracMax_SkGradFixed) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000070 fCount0 = fCount2 = 0;
71 fCount1 = count;
reed@google.com13659f12011-04-18 19:59:38 +000072 fFx1 = fx0;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000073 return;
74 }
75 if (fx <= 0 && ex <= 0) {
76 fCount1 = fCount2 = 0;
77 fCount0 = count;
78 return;
79 }
reedcaf7e932014-12-18 12:43:08 -080080 if (fx >= kFracMax_SkGradFixed && ex >= kFracMax_SkGradFixed) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000081 fCount0 = fCount1 = 0;
82 fCount2 = count;
83 return;
84 }
85
reed@google.com13659f12011-04-18 19:59:38 +000086 int extraCount = 0;
87
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000088 // now make ex be 1 past the last computed value
89 ex += dx;
reedcaf7e932014-12-18 12:43:08 -080090
91#ifdef SK_SUPPORT_LEGACY_GRADIENT_PRECISION
reed@google.com13659f12011-04-18 19:59:38 +000092 // now check for over/under flow
reedcaf7e932014-12-18 12:43:08 -080093 if (overflows_gradfixed(ex)) {
reed@google.com13659f12011-04-18 19:59:38 +000094 int originalCount = count;
95 int64_t ccount;
96 bool swap = dx < 0;
97 if (swap) {
98 dx = -dx;
99 fx = -fx;
100 }
reedcaf7e932014-12-18 12:43:08 -0800101
102 int shift = 0;
103 if (sizeof(SkGradFixed) == 8) {
104 shift = 16;
105 }
106
107 ccount = ((SK_FixedMax << shift) - fx + dx - 1) / dx;
reed@google.com13659f12011-04-18 19:59:38 +0000108 if (swap) {
109 dx = -dx;
110 fx = -fx;
111 }
112 SkASSERT(ccount > 0 && ccount <= SK_FixedMax);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000113
reed@google.com13659f12011-04-18 19:59:38 +0000114 count = (int)ccount;
115 if (0 == count) {
116 this->initFor1(fx0);
117 if (dx > 0) {
118 fCount2 += originalCount - 1;
119 } else {
120 fCount0 += originalCount - 1;
121 }
122 return;
123 }
124 extraCount = originalCount - count;
125 ex = fx + dx * count;
126 }
reedcaf7e932014-12-18 12:43:08 -0800127#endif
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000128
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000129 bool doSwap = dx < 0;
130
131 if (doSwap) {
132 ex -= dx;
133 fx -= dx;
134 SkTSwap(fx, ex);
135 dx = -dx;
136 }
137
reed@google.com13659f12011-04-18 19:59:38 +0000138
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000139 fCount0 = chop(fx, 0, ex, dx, count);
140 count -= fCount0;
141 fx += fCount0 * dx;
142 SkASSERT(fx >= 0);
143 SkASSERT(fCount0 == 0 || (fx - dx) < 0);
reedcaf7e932014-12-18 12:43:08 -0800144 fCount1 = chop(fx, kFracMax_SkGradFixed, ex, dx, count);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000145 count -= fCount1;
146 fCount2 = count;
147
148#ifdef SK_DEBUG
149 fx += fCount1 * dx;
150 SkASSERT(fx <= ex);
151 if (fCount2 > 0) {
reedcaf7e932014-12-18 12:43:08 -0800152 SkASSERT(fx >= kFracMax_SkGradFixed);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000153 if (fCount1 > 0) {
reedcaf7e932014-12-18 12:43:08 -0800154 SkASSERT(fx - dx < kFracMax_SkGradFixed);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000155 }
156 }
157#endif
158
159 if (doSwap) {
160 SkTSwap(fCount0, fCount2);
161 SkTSwap(fV0, fV1);
reed@google.com63c1ad82011-04-18 14:15:36 +0000162 dx = -dx;
163 }
164
165 if (fCount1 > 0) {
reed@google.com13659f12011-04-18 19:59:38 +0000166 fFx1 = fx0 + fCount0 * (int)dx;
167 }
168
169 if (dx > 0) {
170 fCount2 += extraCount;
171 } else {
172 fCount0 += extraCount;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000173 }
174}