Line data Source code
1 : /*
2 : * Copyright 2006 The Android Open Source Project
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 :
9 : #ifndef SkAntiRun_DEFINED
10 : #define SkAntiRun_DEFINED
11 :
12 : #include "SkBlitter.h"
13 :
14 : /** Sparse array of run-length-encoded alpha (supersampling coverage) values.
15 : Sparseness allows us to independently compose several paths into the
16 : same SkAlphaRuns buffer.
17 : */
18 :
19 : class SkAlphaRuns {
20 : public:
21 : int16_t* fRuns;
22 : uint8_t* fAlpha;
23 :
24 : // Return 0-255 given 0-256
25 10271 : static inline SkAlpha CatchOverflow(int alpha) {
26 10271 : SkASSERT(alpha >= 0 && alpha <= 256);
27 10271 : return alpha - (alpha >> 8);
28 : }
29 :
30 : /// Returns true if the scanline contains only a single run,
31 : /// of alpha value 0.
32 2232 : bool empty() const {
33 2232 : SkASSERT(fRuns[0] > 0);
34 2232 : return fAlpha[0] == 0 && fRuns[fRuns[0]] == 0;
35 : }
36 :
37 : /// Reinitialize for a new scanline.
38 : void reset(int width);
39 :
40 : /**
41 : * Insert into the buffer a run starting at (x-offsetX):
42 : * if startAlpha > 0
43 : * one pixel with value += startAlpha,
44 : * max 255
45 : * if middleCount > 0
46 : * middleCount pixels with value += maxValue
47 : * if stopAlpha > 0
48 : * one pixel with value += stopAlpha
49 : * Returns the offsetX value that should be passed on the next call,
50 : * assuming we're on the same scanline. If the caller is switching
51 : * scanlines, then offsetX should be 0 when this is called.
52 : */
53 : SK_ALWAYS_INLINE int add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha,
54 : U8CPU maxValue, int offsetX) {
55 8542 : SkASSERT(middleCount >= 0);
56 8542 : SkASSERT(x >= 0 && x + (startAlpha != 0) + middleCount + (stopAlpha != 0) <= fWidth);
57 :
58 8542 : SkASSERT(fRuns[offsetX] >= 0);
59 :
60 8542 : int16_t* runs = fRuns + offsetX;
61 8542 : uint8_t* alpha = fAlpha + offsetX;
62 8542 : uint8_t* lastAlpha = alpha;
63 8542 : x -= offsetX;
64 :
65 8542 : if (startAlpha) {
66 2025 : SkAlphaRuns::Break(runs, alpha, x, 1);
67 : /* I should be able to just add alpha[x] + startAlpha.
68 : However, if the trailing edge of the previous span and the leading
69 : edge of the current span round to the same super-sampled x value,
70 : I might overflow to 256 with this add, hence the funny subtract (crud).
71 : */
72 2025 : unsigned tmp = alpha[x] + startAlpha;
73 2025 : SkASSERT(tmp <= 256);
74 2025 : alpha[x] = SkToU8(tmp - (tmp >> 8)); // was (tmp >> 7), but that seems wrong if we're trying to catch 256
75 :
76 2025 : runs += x + 1;
77 2025 : alpha += x + 1;
78 2025 : x = 0;
79 2025 : SkDEBUGCODE(this->validate();)
80 : }
81 :
82 8542 : if (middleCount) {
83 8523 : SkAlphaRuns::Break(runs, alpha, x, middleCount);
84 8523 : alpha += x;
85 8523 : runs += x;
86 8523 : x = 0;
87 : do {
88 9929 : alpha[0] = SkToU8(CatchOverflow(alpha[0] + maxValue));
89 9929 : int n = runs[0];
90 9929 : SkASSERT(n <= middleCount);
91 9929 : alpha += n;
92 9929 : runs += n;
93 9929 : middleCount -= n;
94 9929 : } while (middleCount > 0);
95 8523 : SkDEBUGCODE(this->validate();)
96 8523 : lastAlpha = alpha;
97 : }
98 :
99 8542 : if (stopAlpha) {
100 2052 : SkAlphaRuns::Break(runs, alpha, x, 1);
101 2052 : alpha += x;
102 2052 : alpha[0] = SkToU8(alpha[0] + stopAlpha);
103 2052 : SkDEBUGCODE(this->validate();)
104 2052 : lastAlpha = alpha;
105 : }
106 :
107 8542 : return SkToS32(lastAlpha - fAlpha); // new offsetX
108 : }
109 :
110 : SkDEBUGCODE(void assertValid(int y, int maxStep) const;)
111 : SkDEBUGCODE(void dump() const;)
112 :
113 : /**
114 : * Break the runs in the buffer at offsets x and x+count, properly
115 : * updating the runs to the right and left.
116 : * i.e. from the state AAAABBBB, run-length encoded as A4B4,
117 : * Break(..., 2, 5) would produce AAAABBBB rle as A2A2B3B1.
118 : * Allows add() to sum another run to some of the new sub-runs.
119 : * i.e. adding ..CCCCC. would produce AADDEEEB, rle as A2D2E3B1.
120 : */
121 12600 : static void Break(int16_t runs[], uint8_t alpha[], int x, int count) {
122 12600 : SkASSERT(count > 0 && x >= 0);
123 :
124 : // SkAlphaRuns::BreakAt(runs, alpha, x);
125 : // SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count);
126 :
127 12600 : int16_t* next_runs = runs + x;
128 12600 : uint8_t* next_alpha = alpha + x;
129 :
130 19482 : while (x > 0) {
131 5597 : int n = runs[0];
132 5597 : SkASSERT(n > 0);
133 :
134 5597 : if (x < n) {
135 2156 : alpha[x] = alpha[0];
136 2156 : runs[0] = SkToS16(x);
137 2156 : runs[x] = SkToS16(n - x);
138 2156 : break;
139 : }
140 3441 : runs += n;
141 3441 : alpha += n;
142 3441 : x -= n;
143 : }
144 :
145 12600 : runs = next_runs;
146 12600 : alpha = next_alpha;
147 12600 : x = count;
148 :
149 : for (;;) {
150 14006 : int n = runs[0];
151 14006 : SkASSERT(n > 0);
152 :
153 14006 : if (x < n) {
154 4888 : alpha[x] = alpha[0];
155 4888 : runs[0] = SkToS16(x);
156 4888 : runs[x] = SkToS16(n - x);
157 4888 : break;
158 : }
159 9118 : x -= n;
160 9118 : if (x <= 0) {
161 7712 : break;
162 : }
163 1406 : runs += n;
164 1406 : alpha += n;
165 1406 : }
166 12600 : }
167 :
168 : /**
169 : * Cut (at offset x in the buffer) a run into two shorter runs with
170 : * matching alpha values.
171 : * Used by the RectClipBlitter to trim a RLE encoding to match the
172 : * clipping rectangle.
173 : */
174 0 : static void BreakAt(int16_t runs[], uint8_t alpha[], int x) {
175 0 : while (x > 0) {
176 0 : int n = runs[0];
177 0 : SkASSERT(n > 0);
178 :
179 0 : if (x < n) {
180 0 : alpha[x] = alpha[0];
181 0 : runs[0] = SkToS16(x);
182 0 : runs[x] = SkToS16(n - x);
183 0 : break;
184 : }
185 0 : runs += n;
186 0 : alpha += n;
187 0 : x -= n;
188 : }
189 0 : }
190 :
191 : private:
192 : SkDEBUGCODE(int fWidth;)
193 : SkDEBUGCODE(void validate() const;)
194 : };
195 :
196 : #endif
|