Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: src/core/SkScan_AAAPath.cpp

Issue 2221103002: Analytic AntiAlias for Convex Shapes (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Make alpha computation cleaner and faster Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 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 #include "SkAntiRun.h"
9 #include "SkBlitter.h"
10 #include "SkEdge.h"
11 #include "SkEdgeBuilder.h"
12 #include "SkGeometry.h"
13 #include "SkPath.h"
14 #include "SkQuadClipper.h"
15 #include "SkRasterClip.h"
16 #include "SkRegion.h"
17 #include "SkScan.h"
18 #include "SkScanPriv.h"
19 #include "SkTemplates.h"
20 #include "SkTSort.h"
21 #include "SkUtils.h"
22
23 ///////////////////////////////////////////////////////////////////////////////
24
25 /*
26
27 The following is a high-level overview of our analytic anti-aliasing
28 algorithm. We consider a path as a collection of line segments, as
29 quadratic/cubic curves are converted to small line segments. Without loss of
30 generality, let's assume that the draw region is [0, W] x [0, H].
31
32 Our algorithm is based on horizontal scan lines (y = c_i) as the previous
33 sampling-based algorithm did. However, our algorithm uses non-equal-spaced
34 scan lines, while the previous method always uses equal-spaced scan lines,
35 such as (y = 1/2 + 0, 1/2 + 1, 1/2 + 2, ...) in the previous non-AA algorithm,
36 and (y = 1/8 + 1/4, 1/8 + 2/4, 1/8 + 3/4, ...) in the previous
37 16-supersampling AA algorithm.
38
39 Our algorithm contains scan lines y = c_i for c_i that is either:
40
41 1. an integer between [0, H]
42
43 2. the y value of a line segment endpoint
44
45 3. the y value of an intersection of two line segments
46
47 For two consecutive scan lines y = c_i, y = c_{i+1}, we analytically computes
48 the coverage of this horizontal strip of our path on each pixel. This can be
49 done very efficiently because the strip of our path now only consists of
50 trapezoids whose top and bottom edges are y = c_i, y = c_{i+1} (this includes
51 rectangles and triangles as special cases).
52
53 We now describe how the coverage of single pixel is computed against such a
54 trapezoid. That coverage is essentially the intersection area of a rectangle
55 (e.g., [0, 1] x [c_i, c_{i+1}]) and our trapezoid. However, that intersection
56 could be complicated, as shown in the example region A below:
57
58 +-----------\----+
59 | \ C|
60 | \ |
61 \ \ |
62 |\ A \|
63 | \ \
64 | \ |
65 | B \ |
66 +----\-----------+
67
68 However, we don't have to compute the area of A directly. Instead, we can
69 compute the excluded area, which are B and C, quite easily, because they're
70 just triangles. In fact, we can prove that an excluded region (take B as an
71 example) is either itself a simple trapezoid (including rectangles, triangles,
72 and empty regions), or its opposite (the opposite of B is A + C) is a simple
73 trapezoid. In any case, we can compute its area efficiently.
74
75 In summary, our algorithm has a higher quality because it generates ground-
76 truth coverages analytically. It is also faster because it has much fewer
77 unnessasary horizontal scan lines. For example, given a triangle path, the
78 number of scan lines in our algorithm is only about 3 + H while the
79 16-supersampling algorithm has about 4H scan lines.
80
81 */
82
83 ///////////////////////////////////////////////////////////////////////////////
84
85 class AdditiveBlitter : public SkBlitter {
86 public:
87 AdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& c lip,
88 bool isInverse);
89 ~AdditiveBlitter();
90
91 SkBlitter* getRealBlitter();
92
93 void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[] ) override;
94 void blitAntiH(int x, int y, const SkAlpha alpha);
95 void blitAntiH(int x, int y, int width, const SkAlpha alpha);
96
97 void blitV(int x, int y, int height, SkAlpha alpha) override {
98 SkDEBUGFAIL("Please call real blitter's blitV instead.");
99 }
100
101 void blitH(int x, int y, int width) override {
102 SkDEBUGFAIL("Please call real blitter's blitH instead.");
103 }
104
105 void blitRect(int x, int y, int width, int height) override {
106 SkDEBUGFAIL("Please call real blitter's blitRect instead.");
107 }
108
109 void blitAntiRect(int x, int y, int width, int height,
110 SkAlpha leftAlpha, SkAlpha rightAlpha) override {
111 SkDEBUGFAIL("Please call real blitter's blitAntiRect instead.");
112 }
113
114 int getWidth();
115
116 private:
117 SkBlitter* fRealBlitter;
118
119 /// Current y coordinate
120 int fCurrY;
121 /// Widest row of region to be blitted
122 int fWidth;
123 /// Leftmost x coordinate in any row
124 int fLeft;
125 /// Initial y coordinate (top of bounds).
126 int fTop;
127
128 // The next three variables are used to track a circular buffer that
129 // contains the values used in SkAlphaRuns. These variables should only
130 // ever be updated in advanceRuns(), and fRuns should always point to
131 // a valid SkAlphaRuns...
132 int fRunsToBuffer;
133 void* fRunsBuffer;
134 int fCurrentRun;
135 SkAlphaRuns fRuns;
136
137 int fOffsetX;
138
139 inline bool check(int x, int width) {
140 #ifdef SK_DEBUG
141 if (x < 0 || x + width > fWidth) {
142 SkDebugf("Ignore x = %d, width = %d\n", x, width);
143 }
144 #endif
145 return (x >= 0 && x + width <= fWidth);
146 }
147
148 // extra one to store the zero at the end
149 inline int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof (int16_t); }
150
151 // This function updates the fRuns variable to point to the next buffer spac e
152 // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrent Run
153 // and resets fRuns to point to an empty scanline.
154 inline void advanceRuns() {
155 const size_t kRunsSz = this->getRunsSz();
156 fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer;
157 fRuns.fRuns = reinterpret_cast<int16_t*>(
158 reinterpret_cast<uint8_t*>(fRunsBuffer) + fCurrentRun * kRunsSz);
159 fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1);
160 fRuns.reset(fWidth);
161 }
162
163 inline SkAlpha snapAlpha(SkAlpha alpha) {
164 return alpha > 247 ? 0xFF : alpha < 8 ? 0 : alpha;
165 }
166
167 inline void flush() {
168 if (fCurrY >= fTop) {
169 SkASSERT(fCurrentRun < fRunsToBuffer);
170 for (int x = 0; fRuns.fRuns[x]; x += fRuns.fRuns[x]) {
171 // It seems that blitting 255 or 0 is much faster than blitting 254 or 1
172 fRuns.fAlpha[x] = snapAlpha(fRuns.fAlpha[x]);
173 }
174 if (!fRuns.empty()) {
175 // SkDEBUGCODE(fRuns.dump();)
176 fRealBlitter->blitAntiH(fLeft, fCurrY, fRuns.fAlpha, fRuns.fRuns );
177 this->advanceRuns();
178 fOffsetX = 0;
179 }
180 fCurrY = fTop - 1;
181 }
182 }
183
184 inline void checkY(int y) {
185 if (y != fCurrY) {
186 this->flush();
187 fCurrY = y;
188 }
189 }
190 };
191
192 AdditiveBlitter::AdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, cons t SkRegion& clip,
193 bool isInverse) {
194 fRealBlitter = realBlitter;
195
196 SkIRect sectBounds;
197 if (isInverse) {
198 // We use the clip bounds instead of the ir, since we may be asked to
199 //draw outside of the rect when we're a inverse filltype
200 sectBounds = clip.getBounds();
201 } else {
202 if (!sectBounds.intersect(ir, clip.getBounds())) {
203 sectBounds.setEmpty();
204 }
205 }
206
207 const int left = sectBounds.left();
208 const int right = sectBounds.right();
209
210 fLeft = left;
211 fWidth = right - left;
212 fTop = sectBounds.top();
213 fCurrY = fTop - 1;
214
215 fRunsToBuffer = realBlitter->requestRowsPreserved();
216 fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz() );
217 fCurrentRun = -1;
218
219 this->advanceRuns();
220
221 fOffsetX = 0;
222 }
223
224 AdditiveBlitter::~AdditiveBlitter() {
225 this->flush();
226 }
227
228 SkBlitter* AdditiveBlitter::getRealBlitter() {
229 return fRealBlitter;
230 }
231
232 void AdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const i nt16_t runs[]) {
233 checkY(y);
234 x -= fLeft;
235
236 if (x < fOffsetX) {
237 fOffsetX = 0;
238 }
239
240 for (int i=0; runs[i]; i += runs[i]) {
241 if (check(x, runs[i])) {
242 fOffsetX = fRuns.add(x, 0, runs[i], 0, antialias[i], fOffsetX);
243 }
244 x += runs[i];
245 }
246 }
247
248 void AdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) {
249 checkY(y);
250 x -= fLeft;
251
252 if (x < fOffsetX) {
253 fOffsetX = 0;
254 }
255
256 if (check(x, 1)) {
257 fOffsetX = fRuns.add(x, 0, 1, 0, alpha, fOffsetX);
258 }
259 }
260
261 void AdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) {
262 checkY(y);
263 x -= fLeft;
264
265 if (x < fOffsetX) {
266 fOffsetX = 0;
267 }
268
269 if (check(x, width)) {
270 fOffsetX = fRuns.add(x, 0, width, 0, alpha, fOffsetX);
271 }
272 }
273
274 int AdditiveBlitter::getWidth() { return fWidth; }
275
276 ///////////////////////////////////////////////////////////////////////////////
277
278 // Return the alpha of a trapezoid whose height is 1
279 inline SkAlpha trapezoidToAlpha(SkFixed l1, SkFixed l2) {
280 SkASSERT(l1 >= 0 && l2 >= 0);
281 return ((l1 + l2) >> 9);
282 }
283
284 // Return the alpha of a right-angle triangle whose two right-angle edges are l1 , l2
285 inline SkAlpha triangleToAlpha(SkFixed l1, SkFixed l2) {
286 SkASSERT(l1 >= 0 && l2 >= 0);
287 // Since l1, l2 <= SK_Fixed1, we should be able to become more accurate in m ultiplication
288 return SkFixedMul_lowprec(l1, l2) >> 9;
289 }
290
291 inline SkAlpha getPartialAlpha(SkAlpha alpha, SkFixed partialHeight) {
292 return (alpha * partialHeight) >> 16;
293 }
294
295 // Suppose that line (l1, y)-(r1, y+1) intersects with (l2, y)-(r2, y+1),
296 // approximate (very coarsely) the x coordinate of the intersection.
297 inline SkFixed approximateIntersection(SkFixed l1, SkFixed r1, SkFixed l2, SkFix ed r2) {
298 if (l1 > r1) { SkTSwap(l1, r1); }
299 if (l2 > r2) { SkTSwap(l2, r2); }
300 return (SkTMax(l1, l2) + SkTMin(r1, r2)) >> 1;
301 }
302
303 inline void computeAlphaAboveLine(SkAlpha* alphas, SkFixed l, SkFixed r, SkFixed dY, SkFixed rowHeight) {
304 SkASSERT(l <= r);
305 SkASSERT(l >> 16 == 0);
306 int R = SkFixedCeilToInt(r);
307 if (R == 0) {
308 return;
309 } else if (R == 1) {
310 alphas[0] = getPartialAlpha(((R << 17) - l - r) >> 9, rowHeight);
311 } else {
312 SkFixed first = SK_Fixed1 - l;
313 SkFixed last = r - ((R - 1) << 16);
314 SkFixed alpha16 = SkFixedMul_lowprec(first, SkFixedMul_lowprec(first, dY )) >> 1;
315 for (int i = 0; i < R - 1; i++) {
316 alphas[i] = alpha16 >> 8;
317 alpha16 += dY;
318 }
319 alphas[R - 1] = getPartialAlpha(0xFF, rowHeight) - triangleToAlpha(last, SkFixedMul_lowprec(last, dY));
320 }
321 }
322
323 inline void computeAlphaBelowLine(SkAlpha* alphas, SkFixed l, SkFixed r, SkFixed dY, SkFixed rowHeight) {
324 SkASSERT(l <= r);
325 SkASSERT(l >> 16 == 0);
326 int R = SkFixedCeilToInt(r);
327 if (R == 0) {
328 return;
329 } else if (R == 1) {
330 alphas[0] = getPartialAlpha(trapezoidToAlpha(l, r), rowHeight);
331 } else {
332 SkFixed first = SK_Fixed1 - l;
333 SkFixed last = r - ((R - 1) << 16);
334 SkFixed alpha16 = SkFixedMul_lowprec(last, SkFixedMul_lowprec(last, dY)) >> 1;
335 for (int i = R - 1; i > 0; i--) {
336 alphas[i] = alpha16 >> 8;
337 alpha16 += dY;
338 }
339 alphas[0] = getPartialAlpha(0xFF, rowHeight) - triangleToAlpha(first, Sk FixedMul_lowprec(first, dY));
340 }
341 }
342
343 // Blit antialiasing trapzoid (ul, y), (ur, y), (ll, y + rowHeight), (lr, y + ro wHeight)
344 // ul = upper left, ur = upper rite, ll = lower left, lr = lower rite
345 // When rowHeight < SK_Fixed1, blit the partial row with that partial height.
346 // lDY is the dY for the left edge (ul, y) - (ll, y + rowHeight),
347 // and rDY is the dY for the right edge.
348 //
349 // NOTE! To increase performance, we use real blitter (without additive alphas)
350 // if rowHeight = SK_Fixed1. Therefore, we'll lose information if there are
351 // many thin vertical strips within the same pixel.
352 void blit_aaa_trapzoid_row(AdditiveBlitter* blitter, int y,
353 SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr,
354 SkFixed lDY, SkFixed rDY,
355 SkFixed rowHeight) {
356 SkASSERT(lDY >= 0 && rDY >= 0); // We should only send in the absolte value
357
358 if (ul > ur) {
359 #ifdef SK_DEBUG
360 SkDebugf("ul = %f > ur = %f!\n", SkFixedToFloat(ul), SkFixedToFloat(ur)) ;
361 #endif
362 return;
363 }
364
365 // Edge crosses. Approximate it. This should only happend due to precision l imit,
366 // so the approximation could be very coarse.
367 if (ll > lr) {
368 #ifdef SK_DEBUG
369 SkDebugf("approximate intersection: %d %f %f\n", y,
370 SkFixedToFloat(ll), SkFixedToFloat(lr));
371 #endif
372 ll = lr = approximateIntersection(ul, ll, ur, lr);
373 }
374
375 if (ul == ur && ll == lr) {
376 return; // empty trapzoid
377 }
378
379 bool isFullRow = rowHeight == SK_Fixed1;
380 SkAlpha fullAlpha = getPartialAlpha(0xFF, rowHeight);
381
382 SkFixed joinLeft = SkFixedCeilToFixed(SkTMax(ul, ll));
383 SkFixed joinRite = SkFixedFloorToFixed(SkTMin(ur, lr));
384 if (joinLeft < joinRite) {
385 // There's a strip from joinLeft to joinRite that we can blit at once
386 blit_aaa_trapzoid_row(blitter, y, ul, joinLeft, ll, joinLeft, lDY, SK_Ma xS32, rowHeight);
387 if (isFullRow) {
388 blitter->getRealBlitter()->blitH(joinLeft >> 16, y, (joinRite - join Left) >> 16);
389 } else {
390 blitter->blitAntiH(joinLeft >> 16, y, (joinRite - joinLeft) >> 16, f ullAlpha);
391 }
392 blit_aaa_trapzoid_row(blitter, y, joinRite, ur, joinRite, lr, SK_MaxS32, rDY, rowHeight);
393 return;
394 }
395
396 SkFixed left = SkTMin(ul, ll), rite = SkTMax(ur, lr);
397 int L = SkFixedFloorToInt(left), R = SkFixedCeilToInt(rite);
398 int len = R - L;
399
400 #ifdef SK_DEBUG
401 // SkDebugf("y = %d, len = %d\n", y, len);
402 #endif
403
404 if (len == 1) { // Most of the time, len is 1 so we accelerate it
405 SkAlpha alpha = trapezoidToAlpha(ur - ul, lr - ll);
406 if (isFullRow) {
407 blitter->getRealBlitter()->blitV(L, y, 1, alpha);
408 } else {
409 blitter->blitAntiH(L, y, getPartialAlpha(alpha, rowHeight));
410 }
411 return;
412 }
413
414 SkAutoSMalloc<1024> storage((len + 1) * (sizeof(SkAlpha) * 2 + sizeof(int16_ t)));
415 SkAlpha* alphas = (SkAlpha*)storage.get();
416 SkAlpha* tempAlphas = alphas + len + 1;
417 int16_t* runs = (int16_t*)(alphas + (len + 1) * 2);
418
419 // We're going to use the left line ul-ll and the rite line ur-lr
420 // to exclude the area that's not covered by the path.
421 // Swapping (ul, ll) or (ur, lr) won't affect that exclusion
422 // so we'll do that for simplicity.
423 if (ul > ll) { SkTSwap(ul, ll); }
424 if (ur > lr) { SkTSwap(ur, lr); }
425
426 for (int i = 0; i < len; i++) {
427 runs[i] = 1;
428 alphas[i] = fullAlpha;
429 }
430 runs[len] = 0;
431
432 if (ul == ll && ll == L << 16) { // the left edge is vertical integer
433 computeAlphaBelowLine(alphas, ur - (L << 16), lr - (L << 16), rDY, rowHe ight);
434 } else if (ur == lr && lr == R << 16) { // the right edge is vertical intege r
435 computeAlphaAboveLine(alphas, ul - (L << 16), ll - (L << 16), lDY, rowHe ight);
436 } else {
437 int uL = SkFixedFloorToInt(ul);
438 int lL = SkFixedCeilToInt(ll);
439 computeAlphaBelowLine(tempAlphas + uL - L, ul - (uL << 16), ll - (uL << 16),
440 lDY, rowHeight);
441 for (int i = uL; i < lL; i++) {
442 if (alphas[i - L] > tempAlphas[i - L]) {
443 alphas[i - L] -= tempAlphas[i - L];
444 } else {
445 alphas[i - L] = 0;
446 }
447 }
448
449 int uR = SkFixedFloorToInt(ur);
450 int lR = SkFixedCeilToInt(lr);
451 computeAlphaAboveLine(tempAlphas + uR - L, ur - (uR << 16), lr - (uR << 16),
452 rDY, rowHeight);
453 for (int i = uR; i < lR; i++) {
454 if (alphas[i - L] > tempAlphas[i - L]) {
455 alphas[i - L] -= tempAlphas[i - L];
456 } else {
457 alphas[i - L] = 0;
458 }
459 }
460 }
461
462 if (isFullRow) {
463 blitter->getRealBlitter()->blitAntiH(L, y, alphas, runs);
464 } else {
465 blitter->blitAntiH(L, y, alphas, runs);
466 }
467 }
468
469 ///////////////////////////////////////////////////////////////////////////////
470
471 static bool operator<(const SkAnalyticEdge& a, const SkAnalyticEdge& b) {
472 int valuea = a.fUpperY;
473 int valueb = b.fUpperY;
474
475 if (valuea == valueb) {
476 valuea = a.fX;
477 valueb = b.fX;
478 }
479
480 if (valuea == valueb) {
481 valuea = a.fDX;
482 valueb = b.fDX;
483 }
484
485 return valuea < valueb;
486 }
487
488 static SkAnalyticEdge* sort_edges(SkAnalyticEdge* list[], int count, SkAnalyticE dge** last) {
489 SkTQSort(list, list + count - 1);
490
491 // now make the edges linked in sorted order
492 for (int i = 1; i < count; i++) {
493 list[i - 1]->fNext = list[i];
494 list[i]->fPrev = list[i - 1];
495 }
496
497 *last = list[count - 1];
498 return list[0];
499 }
500
501 #ifdef SK_DEBUG
502 static void validate_sort(const SkAnalyticEdge* edge) {
503 SkFixed y = SkIntToFixed(-32768);
504
505 while (edge->fUpperY != SK_MaxS32) {
506 edge->validate();
507 SkASSERT(y <= edge->fUpperY);
508
509 y = edge->fUpperY;
510 edge = (SkAnalyticEdge*)edge->fNext;
511 }
512 }
513 #else
514 #define validate_sort(edge)
515 #endif
516
517 // return true if we're done with this edge
518 static bool update_edge(SkAnalyticEdge* edge, SkFixed last_y) {
519 if (last_y >= edge->fLowerY) {
520 if (edge->fCurveCount < 0) {
521 if (static_cast<SkAnalyticCubicEdge*>(edge)->updateCubic()) {
522 return false;
523 }
524 } else if (edge->fCurveCount > 0) {
525 if (static_cast<SkAnalyticQuadraticEdge*>(edge)->updateQuadratic()) {
526 return false;
527 }
528 }
529 return true;
530 }
531 SkASSERT(false);
532 return false;
533 }
534
535 void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, AdditiveBlitter* blitter,
536 int start_y, int stop_y) {
537 validate_sort((SkAnalyticEdge*)prevHead->fNext);
538
539 SkAnalyticEdge* leftE = (SkAnalyticEdge*) prevHead->fNext;
540 SkAnalyticEdge* riteE = (SkAnalyticEdge*) leftE->fNext;
541 SkAnalyticEdge* currE = (SkAnalyticEdge*) riteE->fNext;
542
543 SkFixed y = SkTMax(leftE->fUpperY, riteE->fUpperY);
544 int local_top = SkFixedFloorToInt(y);
545 SkASSERT(local_top >= start_y);
546
547 #ifdef SK_DEBUG
548 int frac_y_cnt = 0;
549 int total_y_cnt = 0;
550 #endif
551
552 for (;;) {
553 SkASSERT(SkFixedFloorToInt(leftE->fUpperY) <= stop_y);
554 SkASSERT(SkFixedFloorToInt(riteE->fUpperY) <= stop_y);
555
556 if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX &&
557 leftE->fDX > riteE->fDX)) {
558 SkTSwap(leftE, riteE);
559 }
560
561 SkFixed local_bot_fixed = SkMin32(leftE->fLowerY, riteE->fLowerY);
562 local_bot_fixed = SkMin32(local_bot_fixed, SkIntToFixed(stop_y + 1));
563
564 SkFixed left = leftE->fX;
565 SkFixed dLeft = leftE->fDX;
566 SkFixed rite = riteE->fX;
567 SkFixed dRite = riteE->fDX;
568 // x may be out of range without snapping due to precision limit
569 SkFixed snappedLeft = SkAnalyticEdge::snapX(left);
570 SkFixed snappedRite = SkAnalyticEdge::snapX(rite);
571 if (0 == (dLeft | dRite)) {
572 int fullLeft = SkFixedCeilToInt(snappedLeft);
573 int fullRite = SkFixedFloorToInt(snappedRite);
574 SkFixed partialLeft = SkIntToFixed(fullLeft) - snappedLeft;
575 SkFixed partialRite = snappedRite - SkIntToFixed(fullRite);
576 int fullTop = SkFixedCeilToInt(y);
577 int fullBot = SkFixedFloorToInt(local_bot_fixed);
578 SkFixed partialTop = SkIntToFixed(fullTop) - y;
579 SkFixed partialBot = local_bot_fixed - SkIntToFixed(fullBot);
580
581 if (fullRite >= fullLeft) {
582 // Blit all full-height rows from fullTop to fullBot
583 blitter->getRealBlitter()->blitAntiRect(fullLeft - 1, fullTop, f ullRite - fullLeft,
584 fullBot - fullTop,
585 partialLeft >> 8, partia lRite >> 8);
586
587 if (partialTop > 0) { // blit first partial row
588 if (partialLeft > 0) {
589 blitter->blitAntiH(fullLeft - 1, fullTop - 1,
590 SkFixedMul_lowprec(partialTop, partia lLeft) >> 8);
591 }
592 if (partialRite > 0) {
593 blitter->blitAntiH(fullRite, fullTop - 1,
594 SkFixedMul_lowprec(partialTop, partia lRite) >> 8);
595 }
596 blitter->blitAntiH(fullLeft, fullTop - 1, fullRite - fullLef t, partialTop >> 8);
597 }
598
599 if (partialBot > 0) { // blit last partial row
600 if (partialLeft > 0) {
601 blitter->blitAntiH(fullLeft - 1, fullBot,
602 SkFixedMul_lowprec(partialBot, partia lLeft) >> 8);
603 }
604 if (partialRite > 0) {
605 blitter->blitAntiH(fullRite, fullBot,
606 SkFixedMul_lowprec(partialBot, partia lRite) >> 8);
607 }
608 blitter->blitAntiH(fullLeft, fullBot, fullRite - fullLeft, p artialBot >> 8);
609 }
610 } else {
611 if (partialTop > 0) {
612 blitter->getRealBlitter()->blitV(fullLeft - 1, fullTop - 1, 1,
613 SkFixedMul_lowprec(partialTop, rite - left) >> 8);
614 }
615 if (partialBot > 0) {
616 blitter->getRealBlitter()->blitV(fullLeft - 1, fullBot, 1,
617 SkFixedMul_lowprec(partialBot, snappedRite - snapped Left) >> 8);
618 }
619 if (fullBot >= fullTop) {
620 blitter->getRealBlitter()->blitV(fullLeft - 1, fullTop, full Bot - fullTop,
621 (snappedRite - snappedLeft) >> 8);
622 }
623 }
624
625 y = local_bot_fixed;
626 } else {
627 do {
628 #ifdef SK_DEBUG
629 if ((y >> 16 << 16) != y) {
630 frac_y_cnt++;
631 SkDebugf("frac_y = %f\n", SkFixedToFloat(y));
632 }
633 total_y_cnt++;
634 #endif
635
636 local_top = SkFixedFloorToInt(y);
637 SkFixed nextY = SkIntToFixed(local_top + 1);
638 nextY = SkTMin(nextY, local_bot_fixed);
639 SkFixed dY = nextY - y;
640
641 SkFixed nextLeft = left + dLeft;
642 SkFixed nextRite = rite + dRite;
643
644 if (dY != SK_Fixed1) {
645 nextLeft = left + SkFixedMul_lowprec(dLeft, dY);
646 nextRite = rite + SkFixedMul_lowprec(dRite, dY);
647 }
648
649 SkFixed snappedNextLeft = SkAnalyticEdge::snapX(nextLeft);
650 SkFixed snappedNextRite = SkAnalyticEdge::snapX(nextRite);
651
652 blit_aaa_trapzoid_row(blitter, local_top, snappedLeft, snappedRi te,
653 snappedNextLeft, snappedNextRite,
654 leftE->fDY, riteE->fDY, nextY - y);
655
656 left = nextLeft;
657 rite = nextRite;
658 snappedLeft = snappedNextLeft;
659 snappedRite = snappedNextRite;
660 y = nextY;
661 } while (y < local_bot_fixed);
662 }
663
664 leftE->fX = left;
665 riteE->fX = rite;
666
667 while (leftE->fLowerY <= y) {
668 if (update_edge(leftE, y)) {
669 if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) {
670 goto END_WALK;
671 }
672 leftE = currE;
673 leftE->goY(y);
674 currE = (SkAnalyticEdge*)currE->fNext;
675 }
676 }
677 while (riteE->fLowerY <= y) {
678 if (update_edge(riteE, y)) {
679 if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) {
680 goto END_WALK;
681 }
682 riteE = currE;
683 riteE->goY(y);
684 currE = (SkAnalyticEdge*)currE->fNext;
685 }
686 }
687
688 SkASSERT(leftE);
689 SkASSERT(riteE);
690
691 // check our bottom clip
692 SkASSERT(y == local_bot_fixed);
693 if (SkFixedFloorToInt(y) >= stop_y) {
694 break;
695 }
696 }
697
698 END_WALK:
699 ;
700 #ifdef SK_DEBUG
701 SkDebugf("frac_y_cnt = %d, total_y_cnt = %d\n", frac_y_cnt, total_y_cnt);
702 #endif
703 }
704
705 void SkScan::aaa_fill_path(const SkPath& path, const SkIRect* clipRect, Additive Blitter* blitter,
706 int start_y, int stop_y, const SkRegion& clipRgn) {
707 SkASSERT(blitter);
708
709 if (path.isInverseFillType() || !path.isConvex()) {
710 // fall back to supersampling AA
711 GlobalAAConfig::getInstance().fUseAnalyticAA = false;
712 SkScan::AntiFillPath(path, clipRgn, blitter->getRealBlitter(), false);
713 GlobalAAConfig::getInstance().fUseAnalyticAA = true; // turne analytic A A back on
714 return;
715 }
716
717 SkEdgeBuilder builder;
718
719 // If we're convex, then we need both edges, even the right edge is past the clip
720 const bool canCullToTheRight = !path.isConvex();
721
722 SkASSERT(GlobalAAConfig::getInstance().fUseAnalyticAA);
723 int count = builder.build(path, clipRect, 0, canCullToTheRight, true);
724 SkASSERT(count >= 0);
725
726 SkAnalyticEdge** list = (SkAnalyticEdge**)builder.analyticEdgeList();
727
728 if (0 == count) {
729 if (path.isInverseFillType()) {
730 /*
731 * Since we are in inverse-fill, our caller has already drawn above
732 * our top (start_y) and will draw below our bottom (stop_y). Thus
733 * we need to restrict our drawing to the intersection of the clip
734 * and those two limits.
735 */
736 SkIRect rect = clipRgn.getBounds();
737 if (rect.fTop < start_y) {
738 rect.fTop = start_y;
739 }
740 if (rect.fBottom > stop_y) {
741 rect.fBottom = stop_y;
742 }
743 if (!rect.isEmpty()) {
744 blitter->blitRect(rect.fLeft, rect.fTop, rect.width(), rect.heig ht());
745 }
746 }
747 return;
748 }
749
750 SkAnalyticEdge headEdge, tailEdge, *last;
751 // this returns the first and last edge after they're sorted into a dlink li st
752 SkAnalyticEdge* edge = sort_edges(list, count, &last);
753
754 headEdge.fPrev = nullptr;
755 headEdge.fNext = edge;
756 headEdge.fUpperY = headEdge.fLowerY = SK_MinS32;
757 headEdge.fX = SK_MinS32;
758 headEdge.fDX = 0;
759 headEdge.fDY = SK_MaxS32;
760 headEdge.fUpperX = SK_MinS32;
761 edge->fPrev = &headEdge;
762
763 tailEdge.fPrev = last;
764 tailEdge.fNext = nullptr;
765 tailEdge.fUpperY = tailEdge.fLowerY = SK_MaxS32;
766 headEdge.fX = SK_MaxS32;
767 headEdge.fDX = 0;
768 headEdge.fDY = SK_MaxS32;
769 headEdge.fUpperX = SK_MaxS32;
770 last->fNext = &tailEdge;
771
772 // now edge is the head of the sorted linklist
773
774 if (clipRect && start_y < clipRect->fTop) {
775 start_y = clipRect->fTop;
776 }
777 if (clipRect && stop_y > clipRect->fBottom) {
778 stop_y = clipRect->fBottom;
779 }
780
781 if (!path.isInverseFillType() && path.isConvex()) {
782 SkASSERT(count >= 2); // convex walker does not handle missing right e dges
783 aaa_walk_convex_edges(&headEdge, blitter, start_y, stop_y);
784 } else {
785 SkFAIL("Concave AAA is not yet implemented!");
786 }
787 }
788
789 ///////////////////////////////////////////////////////////////////////////////
790
791 void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter * blitter) {
792 if (origClip.isEmpty()) {
793 return;
794 }
795
796 const bool isInverse = path.isInverseFillType();
797 SkIRect ir;
798 path.getBounds().roundOut(&ir);
799 if (ir.isEmpty()) {
800 if (isInverse) {
801 blitter->blitRegion(origClip);
802 }
803 return;
804 }
805
806 SkIRect clippedIR;
807 if (isInverse) {
808 // If the path is an inverse fill, it's going to fill the entire
809 // clip, and we care whether the entire clip exceeds our limits.
810 clippedIR = origClip.getBounds();
811 } else {
812 if (!clippedIR.intersect(ir, origClip.getBounds())) {
813 return;
814 }
815 }
816
817 // Our antialiasing can't handle a clip larger than 32767, so we restrict
818 // the clip to that limit here. (the runs[] uses int16_t for its index).
819 //
820 // A more general solution (one that could also eliminate the need to
821 // disable aa based on ir bounds (see overflows_short_shift) would be
822 // to tile the clip/target...
823 SkRegion tmpClipStorage;
824 const SkRegion* clipRgn = &origClip;
825 {
826 static const int32_t kMaxClipCoord = 32767;
827 const SkIRect& bounds = origClip.getBounds();
828 if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) {
829 SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord };
830 tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op);
831 clipRgn = &tmpClipStorage;
832 }
833 }
834 // for here down, use clipRgn, not origClip
835
836 SkScanClipper clipper(blitter, clipRgn, ir);
837 const SkIRect* clipRect = clipper.getClipRect();
838
839 if (clipper.getBlitter() == nullptr) { // clipped out
840 if (isInverse) {
841 blitter->blitRegion(*clipRgn);
842 }
843 return;
844 }
845
846 // now use the (possibly wrapped) blitter
847 blitter = clipper.getBlitter();
848
849 if (isInverse) {
850 sk_blit_above(blitter, ir, *clipRgn);
851 }
852
853 SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
854
855 AdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse);
856 aaa_fill_path(path, clipRect, &additiveBlitter, ir.fTop, ir.fBottom, *clipRg n);
857
858 if (isInverse) {
859 sk_blit_below(blitter, ir, *clipRgn);
860 }
861 }
862
863 // This almost copies SkScan::AntiFillPath
864 void SkScan::AAAFillPath(const SkPath& path, const SkRasterClip& clip, SkBlitter * blitter) {
865 if (clip.isEmpty()) {
866 return;
867 }
868
869 if (clip.isBW()) {
870 AAAFillPath(path, clip.bwRgn(), blitter);
871 } else {
872 SkRegion tmp;
873 SkAAClipBlitter aaBlitter;
874
875 tmp.setRect(clip.getBounds());
876 aaBlitter.init(blitter, &clip.aaRgn());
877 AAAFillPath(path, tmp, &aaBlitter);
878 }
879 }
OLDNEW
« src/core/SkEdge.cpp ('K') | « src/core/SkScan.h ('k') | src/core/SkScan_AntiPath.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698