1
2/*
3 * 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.
7 */
8
9
10#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 */
16static int chop(int64_t x0, SkFixed edge, int64_t x1, int64_t dx, int count) {
17    SkASSERT(dx > 0);
18    SkASSERT(count >= 0);
19
20    if (x0 >= edge) {
21        return 0;
22    }
23    if (x1 <= edge) {
24        return count;
25    }
26    int64_t n = (edge - x0 + dx - 1) / dx;
27    SkASSERT(n >= 0);
28    SkASSERT(n <= count);
29    return (int)n;
30}
31
32static 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) {
49    SkASSERT(count > 0);
50
51    fV0 = v0;
52    fV1 = v1;
53
54    // 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;
59    }
60
61    int64_t fx = fx0;
62    int64_t dx = dx0;
63    // start with ex equal to the last computed value
64    int64_t ex = fx + (count - 1) * dx;
65
66    if ((uint64_t)(fx | ex) <= 0xFFFF) {
67        fCount0 = fCount2 = 0;
68        fCount1 = count;
69        fFx1 = fx0;
70        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
83    int extraCount = 0;
84
85    // now make ex be 1 past the last computed value
86    ex += dx;
87    // now check for over/under flow
88    if (overflows_fixed(ex)) {
89        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);
102
103        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    }
116
117    bool doSwap = dx < 0;
118
119    if (doSwap) {
120        ex -= dx;
121        fx -= dx;
122        SkTSwap(fx, ex);
123        dx = -dx;
124    }
125
126
127    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);
150        dx = -dx;
151    }
152
153    if (fCount1 > 0) {
154        fFx1 = fx0 + fCount0 * (int)dx;
155    }
156
157    if (dx > 0) {
158        fCount2 += extraCount;
159    } else {
160        fCount0 += extraCount;
161    }
162}
163