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