blob: 398b02434fd531ac137d69abd8ab18aa84273c0a [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;
53
reed@google.com13659f12011-04-18 19:59:38 +000054 // special case 1 == count, as it is slightly common for skia
55 // and avoids us ever calling divide or 64bit multiply
56 if (1 == count) {
57 this->initFor1(fx0);
58 return;
reed@google.com63c1ad82011-04-18 14:15:36 +000059 }
60
reed@google.com13659f12011-04-18 19:59:38 +000061 int64_t fx = fx0;
62 int64_t dx = dx0;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000063 // start with ex equal to the last computed value
reed@google.com13659f12011-04-18 19:59:38 +000064 int64_t ex = fx + (count - 1) * dx;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000065
reed@google.com13659f12011-04-18 19:59:38 +000066 if ((uint64_t)(fx | ex) <= 0xFFFF) {
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000067 fCount0 = fCount2 = 0;
68 fCount1 = count;
reed@google.com13659f12011-04-18 19:59:38 +000069 fFx1 = fx0;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000070 return;
71 }
72 if (fx <= 0 && ex <= 0) {
73 fCount1 = fCount2 = 0;
74 fCount0 = count;
75 return;
76 }
77 if (fx >= 0xFFFF && ex >= 0xFFFF) {
78 fCount0 = fCount1 = 0;
79 fCount2 = count;
80 return;
81 }
82
reed@google.com13659f12011-04-18 19:59:38 +000083 int extraCount = 0;
84
mike@reedtribe.org676d69b2011-04-15 03:43:23 +000085 // now make ex be 1 past the last computed value
86 ex += dx;
reed@google.com13659f12011-04-18 19:59:38 +000087 // now check for over/under flow
reed@google.com33a94e22014-04-18 19:36:22 +000088 if (overflows_fixed(ex)) {
reed@google.com13659f12011-04-18 19:59:38 +000089 int originalCount = count;
90 int64_t ccount;
91 bool swap = dx < 0;
92 if (swap) {
93 dx = -dx;
94 fx = -fx;
95 }
96 ccount = (SK_FixedMax - fx + dx - 1) / dx;
97 if (swap) {
98 dx = -dx;
99 fx = -fx;
100 }
101 SkASSERT(ccount > 0 && ccount <= SK_FixedMax);
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000102
reed@google.com13659f12011-04-18 19:59:38 +0000103 count = (int)ccount;
104 if (0 == count) {
105 this->initFor1(fx0);
106 if (dx > 0) {
107 fCount2 += originalCount - 1;
108 } else {
109 fCount0 += originalCount - 1;
110 }
111 return;
112 }
113 extraCount = originalCount - count;
114 ex = fx + dx * count;
115 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000116
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000117 bool doSwap = dx < 0;
118
119 if (doSwap) {
120 ex -= dx;
121 fx -= dx;
122 SkTSwap(fx, ex);
123 dx = -dx;
124 }
125
reed@google.com13659f12011-04-18 19:59:38 +0000126
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000127 fCount0 = chop(fx, 0, ex, dx, count);
128 count -= fCount0;
129 fx += fCount0 * dx;
130 SkASSERT(fx >= 0);
131 SkASSERT(fCount0 == 0 || (fx - dx) < 0);
132 fCount1 = chop(fx, 0xFFFF, ex, dx, count);
133 count -= fCount1;
134 fCount2 = count;
135
136#ifdef SK_DEBUG
137 fx += fCount1 * dx;
138 SkASSERT(fx <= ex);
139 if (fCount2 > 0) {
140 SkASSERT(fx >= 0xFFFF);
141 if (fCount1 > 0) {
142 SkASSERT(fx - dx < 0xFFFF);
143 }
144 }
145#endif
146
147 if (doSwap) {
148 SkTSwap(fCount0, fCount2);
149 SkTSwap(fV0, fV1);
reed@google.com63c1ad82011-04-18 14:15:36 +0000150 dx = -dx;
151 }
152
153 if (fCount1 > 0) {
reed@google.com13659f12011-04-18 19:59:38 +0000154 fFx1 = fx0 + fCount0 * (int)dx;
155 }
156
157 if (dx > 0) {
158 fCount2 += extraCount;
159 } else {
160 fCount0 += extraCount;
mike@reedtribe.org676d69b2011-04-15 03:43:23 +0000161 }
162}