blob: c4bf8b19065b54befdce592dfa33af0b87e33435 [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 */
reed@google.com13659f12011-04-18 19:59:38 +000016static int chop(int64_t x0, SkFixed 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
reed@google.com13659f12011-04-18 19:59:38 +000032static bool overflows_fixed(int64_t x) {
33 return x < -SK_FixedMax || x > SK_FixedMax;
34}
35
36void SkClampRange::initFor1(SkFixed fx) {
37 fCount0 = fCount1 = fCount2 = 0;
38 if (fx <= 0) {
39 fCount0 = 1;
40 } else if (fx < 0xFFFF) {
41 fCount1 = 1;
42 fFx1 = fx;
43 } else {
44 fCount2 = 1;
45 }
46}
47
48void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000049 SkASSERT(count > 0);
50
51 fV0 = v0;
52 fV1 = v1;
reed@google.com13659f12011-04-18 19:59:38 +000053 fOverflowed = false;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000054
reed@google.com13659f12011-04-18 19:59:38 +000055 // special case 1 == count, as it is slightly common for skia
56 // and avoids us ever calling divide or 64bit multiply
57 if (1 == count) {
58 this->initFor1(fx0);
59 return;
reed@google.com63c1ad82011-04-18 14:15:36 +000060 }
61
reed@google.com13659f12011-04-18 19:59:38 +000062 int64_t fx = fx0;
63 int64_t dx = dx0;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000064 // start with ex equal to the last computed value
reed@google.com13659f12011-04-18 19:59:38 +000065 int64_t ex = fx + (count - 1) * dx;
66 fOverflowed = overflows_fixed(ex);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000067
reed@google.com13659f12011-04-18 19:59:38 +000068 if ((uint64_t)(fx | ex) <= 0xFFFF) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000069 fCount0 = fCount2 = 0;
70 fCount1 = count;
reed@google.com13659f12011-04-18 19:59:38 +000071 fFx1 = fx0;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000072 return;
73 }
74 if (fx <= 0 && ex <= 0) {
75 fCount1 = fCount2 = 0;
76 fCount0 = count;
77 return;
78 }
79 if (fx >= 0xFFFF && ex >= 0xFFFF) {
80 fCount0 = fCount1 = 0;
81 fCount2 = count;
82 return;
83 }
84
reed@google.com13659f12011-04-18 19:59:38 +000085 int extraCount = 0;
86
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000087 // now make ex be 1 past the last computed value
88 ex += dx;
reed@google.com13659f12011-04-18 19:59:38 +000089 fOverflowed = overflows_fixed(ex);
90 // now check for over/under flow
91 if (fOverflowed) {
92 int originalCount = count;
93 int64_t ccount;
94 bool swap = dx < 0;
95 if (swap) {
96 dx = -dx;
97 fx = -fx;
98 }
99 ccount = (SK_FixedMax - fx + dx - 1) / dx;
100 if (swap) {
101 dx = -dx;
102 fx = -fx;
103 }
104 SkASSERT(ccount > 0 && ccount <= SK_FixedMax);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000105
reed@google.com13659f12011-04-18 19:59:38 +0000106 count = (int)ccount;
107 if (0 == count) {
108 this->initFor1(fx0);
109 if (dx > 0) {
110 fCount2 += originalCount - 1;
111 } else {
112 fCount0 += originalCount - 1;
113 }
114 return;
115 }
116 extraCount = originalCount - count;
117 ex = fx + dx * count;
118 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000119
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);
131 count -= fCount0;
132 fx += fCount0 * dx;
133 SkASSERT(fx >= 0);
134 SkASSERT(fCount0 == 0 || (fx - dx) < 0);
135 fCount1 = chop(fx, 0xFFFF, ex, dx, count);
136 count -= fCount1;
137 fCount2 = count;
138
139#ifdef SK_DEBUG
140 fx += fCount1 * dx;
141 SkASSERT(fx <= ex);
142 if (fCount2 > 0) {
143 SkASSERT(fx >= 0xFFFF);
144 if (fCount1 > 0) {
145 SkASSERT(fx - dx < 0xFFFF);
146 }
147 }
148#endif
149
150 if (doSwap) {
151 SkTSwap(fCount0, fCount2);
152 SkTSwap(fV0, fV1);
reed@google.com63c1ad82011-04-18 14:15:36 +0000153 dx = -dx;
154 }
155
156 if (fCount1 > 0) {
reed@google.com13659f12011-04-18 19:59:38 +0000157 fFx1 = fx0 + fCount0 * (int)dx;
158 }
159
160 if (dx > 0) {
161 fCount2 += extraCount;
162 } else {
163 fCount0 += extraCount;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000164 }
165}
166