Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkScan_AAAPath.cpp
Go to the documentation of this file.
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
11#include "include/core/SkRect.h"
18#include "src/base/SkTSort.h"
21#include "src/core/SkBlitter.h"
22#include "src/core/SkEdge.h"
24#include "src/core/SkMask.h"
25#include "src/core/SkScan.h"
26#include "src/core/SkScanPriv.h"
27
28#include <algorithm>
29#include <cstdint>
30#include <cstring>
31
32/*
33
34The following is a high-level overview of our analytic anti-aliasing
35algorithm. We consider a path as a collection of line segments, as
36quadratic/cubic curves are converted to small line segments. Without loss of
37generality, let's assume that the draw region is [0, W] x [0, H].
38
39Our algorithm is based on horizontal scan lines (y = c_i) as the previous
40sampling-based algorithm did. However, our algorithm uses non-equal-spaced
41scan lines, while the previous method always uses equal-spaced scan lines,
42such as (y = 1/2 + 0, 1/2 + 1, 1/2 + 2, ...) in the previous non-AA algorithm,
43and (y = 1/8 + 1/4, 1/8 + 2/4, 1/8 + 3/4, ...) in the previous
4416-supersampling AA algorithm.
45
46Our algorithm contains scan lines y = c_i for c_i that is either:
47
481. an integer between [0, H]
49
502. the y value of a line segment endpoint
51
523. the y value of an intersection of two line segments
53
54For two consecutive scan lines y = c_i, y = c_{i+1}, we analytically computes
55the coverage of this horizontal strip of our path on each pixel. This can be
56done very efficiently because the strip of our path now only consists of
57trapezoids whose top and bottom edges are y = c_i, y = c_{i+1} (this includes
58rectangles and triangles as special cases).
59
60We now describe how the coverage of single pixel is computed against such a
61trapezoid. That coverage is essentially the intersection area of a rectangle
62(e.g., [0, 1] x [c_i, c_{i+1}]) and our trapezoid. However, that intersection
63could be complicated, as shown in the example region A below:
64
65+-----------\----+
66| \ C|
67| \ |
68\ \ |
69|\ A \|
70| \ \
71| \ |
72| B \ |
73+----\-----------+
74
75However, we don't have to compute the area of A directly. Instead, we can
76compute the excluded area, which are B and C, quite easily, because they're
77just triangles. In fact, we can prove that an excluded region (take B as an
78example) is either itself a simple trapezoid (including rectangles, triangles,
79and empty regions), or its opposite (the opposite of B is A + C) is a simple
80trapezoid. In any case, we can compute its area efficiently.
81
82In summary, our algorithm has a higher quality because it generates ground-
83truth coverages analytically. It is also faster because it has much fewer
84unnessasary horizontal scan lines. For example, given a triangle path, the
85number of scan lines in our algorithm is only about 3 + H while the
8616-supersampling algorithm has about 4H scan lines.
87
88*/
89
90static void add_alpha(SkAlpha* alpha, SkAlpha delta) {
91 SkASSERT(*alpha + delta <= 256);
92 *alpha = SkAlphaRuns::CatchOverflow(*alpha + delta);
93}
94
95static void safely_add_alpha(SkAlpha* alpha, SkAlpha delta) {
96 *alpha = std::min(0xFF, *alpha + delta);
97}
98
99class AdditiveBlitter : public SkBlitter {
100public:
101 ~AdditiveBlitter() override {}
102
103 virtual SkBlitter* getRealBlitter(bool forceRealBlitter = false) = 0;
104
105 virtual void blitAntiH(int x, int y, const SkAlpha antialias[], int len) = 0;
106 virtual void blitAntiH(int x, int y, const SkAlpha alpha) = 0;
107 virtual void blitAntiH(int x, int y, int width, const SkAlpha alpha) = 0;
108
109 void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override {
110 SkDEBUGFAIL("Please call real blitter's blitAntiH instead.");
111 }
112
113 void blitV(int x, int y, int height, SkAlpha alpha) override {
114 SkDEBUGFAIL("Please call real blitter's blitV instead.");
115 }
116
117 void blitH(int x, int y, int width) override {
118 SkDEBUGFAIL("Please call real blitter's blitH instead.");
119 }
120
121 void blitRect(int x, int y, int width, int height) override {
122 SkDEBUGFAIL("Please call real blitter's blitRect instead.");
123 }
124
125 void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha)
126 override {
127 SkDEBUGFAIL("Please call real blitter's blitAntiRect instead.");
128 }
129
130 virtual int getWidth() = 0;
131
132 // Flush the additive alpha cache if floor(y) and floor(nextY) is different
133 // (i.e., we'll start working on a new pixel row).
134 virtual void flush_if_y_changed(SkFixed y, SkFixed nextY) = 0;
135};
136
137// We need this mask blitter because it significantly accelerates small path filling.
139public:
140 MaskAdditiveBlitter(SkBlitter* realBlitter,
141 const SkIRect& ir,
142 const SkIRect& clipBounds,
143 bool isInverse);
144 ~MaskAdditiveBlitter() override { fRealBlitter->blitMask(fMask, fClipRect); }
145
146 // Most of the time, we still consider this mask blitter as the real blitter
147 // so we can accelerate blitRect and others. But sometimes we want to return
148 // the absolute real blitter (e.g., when we fall back to the old code path).
149 SkBlitter* getRealBlitter(bool forceRealBlitter) override {
150 return forceRealBlitter ? fRealBlitter : this;
151 }
152
153 // Virtual function is slow. So don't use this. Directly add alpha to the mask instead.
154 void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override;
155
156 // Allowing following methods are used to blit rectangles during aaa_walk_convex_edges
157 // Since there aren't many rectangles, we can still bear the slow speed of virtual functions.
158 void blitAntiH(int x, int y, const SkAlpha alpha) override;
159 void blitAntiH(int x, int y, int width, const SkAlpha alpha) override;
160 void blitV(int x, int y, int height, SkAlpha alpha) override;
161 void blitRect(int x, int y, int width, int height) override;
162 void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha)
163 override;
164
165 // The flush is only needed for RLE (RunBasedAdditiveBlitter)
166 void flush_if_y_changed(SkFixed y, SkFixed nextY) override {}
167
168 int getWidth() override { return fClipRect.width(); }
169
170 static bool CanHandleRect(const SkIRect& bounds) {
171 int width = bounds.width();
172 if (width > MaskAdditiveBlitter::kMAX_WIDTH) {
173 return false;
174 }
175 int64_t rb = SkAlign4(width);
176 // use 64bits to detect overflow
177 int64_t storage = rb * bounds.height();
178
179 return (width <= MaskAdditiveBlitter::kMAX_WIDTH) &&
180 (storage <= MaskAdditiveBlitter::kMAX_STORAGE);
181 }
182
183 // Return a pointer where pointer[x] corresonds to the alpha of (x, y)
184 uint8_t* getRow(int y) {
185 if (y != fY) {
186 fY = y;
187 fRow = fMask.image() + (y - fMask.fBounds.fTop) * fMask.fRowBytes - fMask.fBounds.fLeft;
188 }
189 return fRow;
190 }
191
192private:
193 // so we don't try to do very wide things, where the RLE blitter would be faster
194 static const int kMAX_WIDTH = 32;
195 static const int kMAX_STORAGE = 1024;
196
197 SkBlitter* fRealBlitter;
198 SkMaskBuilder fMask;
199 SkIRect fClipRect;
200 // we add 2 because we can write 1 extra byte at either end due to precision error
201 uint32_t fStorage[(kMAX_STORAGE >> 2) + 2];
202
203 uint8_t* fRow;
204 int fY;
205};
206
208 const SkIRect& ir,
209 const SkIRect& clipBounds,
210 bool isInverse)
211 : fRealBlitter(realBlitter)
212 , fMask((uint8_t*)fStorage + 1, ir, ir.width(), SkMask::kA8_Format)
213 , fRow(nullptr)
214 , fY(ir.fTop - 1)
215 {
217 SkASSERT(!isInverse);
218
219 fClipRect = ir;
220 if (!fClipRect.intersect(clipBounds)) {
221 SkASSERT(0);
222 fClipRect.setEmpty();
223 }
224
225 memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 2);
226}
227
228void MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) {
229 SK_ABORT("Don't use this; directly add alphas to the mask.");
230}
231
232void MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) {
233 SkASSERT(x >= fMask.fBounds.fLeft - 1);
234 add_alpha(&this->getRow(y)[x], alpha);
235}
236
237void MaskAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) {
238 SkASSERT(x >= fMask.fBounds.fLeft - 1);
239 uint8_t* row = this->getRow(y);
240 for (int i = 0; i < width; ++i) {
241 add_alpha(&row[x + i], alpha);
242 }
243}
244
245void MaskAdditiveBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
246 if (alpha == 0) {
247 return;
248 }
249 SkASSERT(x >= fMask.fBounds.fLeft - 1);
250 // This must be called as if this is a real blitter.
251 // So we directly set alpha rather than adding it.
252 uint8_t* row = this->getRow(y);
253 for (int i = 0; i < height; ++i) {
254 row[x] = alpha;
255 row += fMask.fRowBytes;
256 }
257}
258
259void MaskAdditiveBlitter::blitRect(int x, int y, int width, int height) {
260 SkASSERT(x >= fMask.fBounds.fLeft - 1);
261 // This must be called as if this is a real blitter.
262 // So we directly set alpha rather than adding it.
263 uint8_t* row = this->getRow(y);
264 for (int i = 0; i < height; ++i) {
265 memset(row + x, 0xFF, width);
266 row += fMask.fRowBytes;
267 }
268}
269
271 int y,
272 int width,
273 int height,
274 SkAlpha leftAlpha,
275 SkAlpha rightAlpha) {
276 blitV(x, y, height, leftAlpha);
277 blitV(x + 1 + width, y, height, rightAlpha);
278 blitRect(x + 1, y, width, height);
279}
280
282public:
284 const SkIRect& ir,
285 const SkIRect& clipBounds,
286 bool isInverse);
287
288 ~RunBasedAdditiveBlitter() override { this->flush(); }
289
290 SkBlitter* getRealBlitter(bool forceRealBlitter) override { return fRealBlitter; }
291
292 void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override;
293 void blitAntiH(int x, int y, const SkAlpha alpha) override;
294 void blitAntiH(int x, int y, int width, const SkAlpha alpha) override;
295
296 int getWidth() override { return fWidth; }
297
298 void flush_if_y_changed(SkFixed y, SkFixed nextY) override {
299 if (SkFixedFloorToInt(y) != SkFixedFloorToInt(nextY)) {
300 this->flush();
301 }
302 }
303
304protected:
306
307 int fCurrY; // Current y coordinate.
308 int fWidth; // Widest row of region to be blitted
309 int fLeft; // Leftmost x coordinate in any row
310 int fTop; // Initial y coordinate (top of bounds)
311
312 // The next three variables are used to track a circular buffer that
313 // contains the values used in SkAlphaRuns. These variables should only
314 // ever be updated in advanceRuns(), and fRuns should always point to
315 // a valid SkAlphaRuns...
320
322
323 bool check(int x, int width) const { return x >= 0 && x + width <= fWidth; }
324
325 // extra one to store the zero at the end
326 int getRunsSz() const { return (fWidth + 1 + (fWidth + 2) / 2) * sizeof(int16_t); }
327
328 // This function updates the fRuns variable to point to the next buffer space
329 // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun
330 // and resets fRuns to point to an empty scanline.
331 void advanceRuns() {
332 const size_t kRunsSz = this->getRunsSz();
333 fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer;
334 fRuns.fRuns = reinterpret_cast<int16_t*>(reinterpret_cast<uint8_t*>(fRunsBuffer) +
335 fCurrentRun * kRunsSz);
336 fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1);
338 }
339
340 // Blitting 0xFF and 0 is much faster so we snap alphas close to them
341 SkAlpha snapAlpha(SkAlpha alpha) { return alpha > 247 ? 0xFF : alpha < 8 ? 0x00 : alpha; }
342
343 void flush() {
344 if (fCurrY >= fTop) {
346 for (int x = 0; fRuns.fRuns[x]; x += fRuns.fRuns[x]) {
347 // It seems that blitting 255 or 0 is much faster than blitting 254 or 1
349 }
350 if (!fRuns.empty()) {
351 // SkDEBUGCODE(fRuns.dump();)
353 this->advanceRuns();
354 fOffsetX = 0;
355 }
356 fCurrY = fTop - 1;
357 }
358 }
359
360 void checkY(int y) {
361 if (y != fCurrY) {
362 this->flush();
363 fCurrY = y;
364 }
365 }
366};
367
369 const SkIRect& ir,
370 const SkIRect& clipBounds,
371 bool isInverse) {
372 fRealBlitter = realBlitter;
373
374 SkIRect sectBounds;
375 if (isInverse) {
376 // We use the clip bounds instead of the ir, since we may be asked to
377 // draw outside of the rect when we're a inverse filltype
378 sectBounds = clipBounds;
379 } else {
380 if (!sectBounds.intersect(ir, clipBounds)) {
381 sectBounds.setEmpty();
382 }
383 }
384
385 const int left = sectBounds.left();
386 const int right = sectBounds.right();
387
388 fLeft = left;
389 fWidth = right - left;
390 fTop = sectBounds.top();
391 fCurrY = fTop - 1;
392
393 fRunsToBuffer = realBlitter->requestRowsPreserved();
394 fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz());
395 fCurrentRun = -1;
396
397 this->advanceRuns();
398
399 fOffsetX = 0;
400}
401
402void RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) {
403 checkY(y);
404 x -= fLeft;
405
406 if (x < 0) {
407 len += x;
408 antialias -= x;
409 x = 0;
410 }
411 len = std::min(len, fWidth - x);
412 SkASSERT(check(x, len));
413
414 if (x < fOffsetX) {
415 fOffsetX = 0;
416 }
417
418 fOffsetX = fRuns.add(x, 0, len, 0, 0, fOffsetX); // Break the run
419 for (int i = 0; i < len; i += fRuns.fRuns[x + i]) {
420 for (int j = 1; j < fRuns.fRuns[x + i]; j++) {
421 fRuns.fRuns[x + i + j] = 1;
422 fRuns.fAlpha[x + i + j] = fRuns.fAlpha[x + i];
423 }
424 fRuns.fRuns[x + i] = 1;
425 }
426 for (int i = 0; i < len; ++i) {
427 add_alpha(&fRuns.fAlpha[x + i], antialias[i]);
428 }
429}
430
431void RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) {
432 checkY(y);
433 x -= fLeft;
434
435 if (x < fOffsetX) {
436 fOffsetX = 0;
437 }
438
439 if (this->check(x, 1)) {
440 fOffsetX = fRuns.add(x, 0, 1, 0, alpha, fOffsetX);
441 }
442}
443
444void RunBasedAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) {
445 checkY(y);
446 x -= fLeft;
447
448 if (x < fOffsetX) {
449 fOffsetX = 0;
450 }
451
452 if (this->check(x, width)) {
453 fOffsetX = fRuns.add(x, 0, width, 0, alpha, fOffsetX);
454 }
455}
456
457// This exists specifically for concave path filling.
458// In those cases, we can easily accumulate alpha greater than 0xFF.
460public:
462 const SkIRect& ir,
463 const SkIRect& clipBounds,
464 bool isInverse)
465 : RunBasedAdditiveBlitter(realBlitter, ir, clipBounds, isInverse) {}
466
467 void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override;
468 void blitAntiH(int x, int y, const SkAlpha alpha) override;
469 void blitAntiH(int x, int y, int width, const SkAlpha alpha) override;
470};
471
472void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) {
473 checkY(y);
474 x -= fLeft;
475
476 if (x < 0) {
477 len += x;
478 antialias -= x;
479 x = 0;
480 }
481 len = std::min(len, fWidth - x);
482 SkASSERT(check(x, len));
483
484 if (x < fOffsetX) {
485 fOffsetX = 0;
486 }
487
488 fOffsetX = fRuns.add(x, 0, len, 0, 0, fOffsetX); // Break the run
489 for (int i = 0; i < len; i += fRuns.fRuns[x + i]) {
490 for (int j = 1; j < fRuns.fRuns[x + i]; j++) {
491 fRuns.fRuns[x + i + j] = 1;
492 fRuns.fAlpha[x + i + j] = fRuns.fAlpha[x + i];
493 }
494 fRuns.fRuns[x + i] = 1;
495 }
496 for (int i = 0; i < len; ++i) {
497 safely_add_alpha(&fRuns.fAlpha[x + i], antialias[i]);
498 }
499}
500
501void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) {
502 checkY(y);
503 x -= fLeft;
504
505 if (x < fOffsetX) {
506 fOffsetX = 0;
507 }
508
509 if (check(x, 1)) {
510 // Break the run
511 fOffsetX = fRuns.add(x, 0, 1, 0, 0, fOffsetX);
512 safely_add_alpha(&fRuns.fAlpha[x], alpha);
513 }
514}
515
516void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) {
517 checkY(y);
518 x -= fLeft;
519
520 if (x < fOffsetX) {
521 fOffsetX = 0;
522 }
523
524 if (check(x, width)) {
525 // Break the run
526 fOffsetX = fRuns.add(x, 0, width, 0, 0, fOffsetX);
527 for (int i = x; i < x + width; i += fRuns.fRuns[i]) {
528 safely_add_alpha(&fRuns.fAlpha[i], alpha);
529 }
530 }
531}
532
533// Return the alpha of a trapezoid whose height is 1
535 SkASSERT(l1 >= 0 && l2 >= 0);
536 SkFixed area = (l1 + l2) / 2;
537 return SkTo<SkAlpha>(area >> 8);
538}
539
540// The alpha of right-triangle (a, a*b)
542 SkASSERT(a <= SK_Fixed1);
543#if 0
544 // TODO(mtklein): skia:8877
545 SkASSERT(b <= SK_Fixed1);
546#endif
547
548 // Approximating...
549 // SkFixed area = SkFixedMul(a, SkFixedMul(a,b)) / 2;
550 SkFixed area = (a >> 11) * (a >> 11) * (b >> 11);
551
552#if 0
553 // TODO(mtklein): skia:8877
554 return SkTo<SkAlpha>(area >> 8);
555#else
556 return SkTo<SkAlpha>((area >> 8) & 0xFF);
557#endif
558}
559
560static SkAlpha get_partial_alpha(SkAlpha alpha, SkFixed partialHeight) {
561 return SkToU8(SkFixedRoundToInt(alpha * partialHeight));
562}
563
564static SkAlpha get_partial_alpha(SkAlpha alpha, SkAlpha fullAlpha) {
565 return (alpha * fullAlpha) >> 8;
566}
567
568// For SkFixed that's close to SK_Fixed1, we can't convert it to alpha by just shifting right.
569// For example, when f = SK_Fixed1, right shifting 8 will get 256, but we need 255.
570// This is rarely the problem so we'll only use this for blitting rectangles.
572 SkASSERT(f <= SK_Fixed1);
573 return get_partial_alpha(0xFF, f);
574}
575
576// Suppose that line (l1, y)-(r1, y+1) intersects with (l2, y)-(r2, y+1),
577// approximate (very coarsely) the x coordinate of the intersection.
579 if (l1 > r1) {
580 std::swap(l1, r1);
581 }
582 if (l2 > r2) {
583 std::swap(l2, r2);
584 }
585 return (std::max(l1, l2) + std::min(r1, r2)) / 2;
586}
587
588// Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0]
590 SkFixed l,
591 SkFixed r,
592 SkFixed dY,
593 SkAlpha fullAlpha) {
594 SkASSERT(l <= r);
595 SkASSERT(l >> 16 == 0);
596 int R = SkFixedCeilToInt(r);
597 if (R == 0) {
598 return;
599 } else if (R == 1) {
600 alphas[0] = get_partial_alpha(((R << 17) - l - r) >> 9, fullAlpha);
601 } else {
602 SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle
603 SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle
604 SkFixed firstH = SkFixedMul(first, dY); // vertical edge of the left-most triangle
605 alphas[0] = SkFixedMul(first, firstH) >> 9; // triangle alpha
606 SkFixed alpha16 = firstH + (dY >> 1); // rectangle plus triangle
607 for (int i = 1; i < R - 1; ++i) {
608 alphas[i] = alpha16 >> 8;
609 alpha16 += dY;
610 }
611 alphas[R - 1] = fullAlpha - partial_triangle_to_alpha(last, dY);
612 }
613}
614
615// Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0]
617 SkFixed l,
618 SkFixed r,
619 SkFixed dY,
620 SkAlpha fullAlpha) {
621 SkASSERT(l <= r);
622 SkASSERT(l >> 16 == 0);
623 int R = SkFixedCeilToInt(r);
624 if (R == 0) {
625 return;
626 } else if (R == 1) {
627 alphas[0] = get_partial_alpha(trapezoid_to_alpha(l, r), fullAlpha);
628 } else {
629 SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle
630 SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle
631 SkFixed lastH = SkFixedMul(last, dY); // vertical edge of the right-most triangle
632 alphas[R - 1] = SkFixedMul(last, lastH) >> 9; // triangle alpha
633 SkFixed alpha16 = lastH + (dY >> 1); // rectangle plus triangle
634 for (int i = R - 2; i > 0; i--) {
635 alphas[i] = (alpha16 >> 8) & 0xFF;
636 alpha16 += dY;
637 }
638 alphas[0] = fullAlpha - partial_triangle_to_alpha(first, dY);
639 }
640}
641
642// Note that if fullAlpha != 0xFF, we'll multiply alpha by fullAlpha
644 int y,
645 int x,
646 SkAlpha alpha,
647 SkAlpha fullAlpha,
648 SkAlpha* maskRow,
649 bool isUsingMask,
650 bool noRealBlitter,
651 bool needSafeCheck) {
652 if (isUsingMask) {
653 if (fullAlpha == 0xFF && !noRealBlitter) { // noRealBlitter is needed for concave paths
654 maskRow[x] = alpha;
655 } else if (needSafeCheck) {
656 safely_add_alpha(&maskRow[x], get_partial_alpha(alpha, fullAlpha));
657 } else {
658 add_alpha(&maskRow[x], get_partial_alpha(alpha, fullAlpha));
659 }
660 } else {
661 if (fullAlpha == 0xFF && !noRealBlitter) {
662 blitter->getRealBlitter()->blitV(x, y, 1, alpha);
663 } else {
664 blitter->blitAntiH(x, y, get_partial_alpha(alpha, fullAlpha));
665 }
666 }
667}
668
669static void blit_two_alphas(AdditiveBlitter* blitter,
670 int y,
671 int x,
672 SkAlpha a1,
673 SkAlpha a2,
674 SkAlpha fullAlpha,
675 SkAlpha* maskRow,
676 bool isUsingMask,
677 bool noRealBlitter,
678 bool needSafeCheck) {
679 if (isUsingMask) {
680 if (needSafeCheck) {
681 safely_add_alpha(&maskRow[x], a1);
682 safely_add_alpha(&maskRow[x + 1], a2);
683 } else {
684 add_alpha(&maskRow[x], a1);
685 add_alpha(&maskRow[x + 1], a2);
686 }
687 } else {
688 if (fullAlpha == 0xFF && !noRealBlitter) {
689 blitter->getRealBlitter()->blitAntiH2(x, y, a1, a2);
690 } else {
691 blitter->blitAntiH(x, y, a1);
692 blitter->blitAntiH(x + 1, y, a2);
693 }
694 }
695}
696
697static void blit_full_alpha(AdditiveBlitter* blitter,
698 int y,
699 int x,
700 int len,
701 SkAlpha fullAlpha,
702 SkAlpha* maskRow,
703 bool isUsingMask,
704 bool noRealBlitter,
705 bool needSafeCheck) {
706 if (isUsingMask) {
707 for (int i = 0; i < len; ++i) {
708 if (needSafeCheck) {
709 safely_add_alpha(&maskRow[x + i], fullAlpha);
710 } else {
711 add_alpha(&maskRow[x + i], fullAlpha);
712 }
713 }
714 } else {
715 if (fullAlpha == 0xFF && !noRealBlitter) {
716 blitter->getRealBlitter()->blitH(x, y, len);
717 } else {
718 blitter->blitAntiH(x, y, len, fullAlpha);
719 }
720 }
721}
722
724 int y,
725 SkFixed ul,
726 SkFixed ur,
727 SkFixed ll,
728 SkFixed lr,
729 SkFixed lDY,
730 SkFixed rDY,
731 SkAlpha fullAlpha,
732 SkAlpha* maskRow,
733 bool isUsingMask,
734 bool noRealBlitter,
735 bool needSafeCheck) {
736 int L = SkFixedFloorToInt(ul), R = SkFixedCeilToInt(lr);
737 int len = R - L;
738
739 if (len == 1) {
740 SkAlpha alpha = trapezoid_to_alpha(ur - ul, lr - ll);
741 blit_single_alpha(blitter,
742 y,
743 L,
744 alpha,
745 fullAlpha,
746 maskRow,
747 isUsingMask,
748 noRealBlitter,
749 needSafeCheck);
750 return;
751 }
752
753 const int kQuickLen = 31;
754 alignas(2) char quickMemory[(sizeof(SkAlpha) * 2 + sizeof(int16_t)) * (kQuickLen + 1)];
755 SkAlpha* alphas;
756
757 if (len <= kQuickLen) {
758 alphas = (SkAlpha*)quickMemory;
759 } else {
760 alphas = new SkAlpha[(len + 1) * (sizeof(SkAlpha) * 2 + sizeof(int16_t))];
761 }
762
763 SkAlpha* tempAlphas = alphas + len + 1;
764 int16_t* runs = (int16_t*)(alphas + (len + 1) * 2);
765
766 for (int i = 0; i < len; ++i) {
767 runs[i] = 1;
768 alphas[i] = fullAlpha;
769 }
770 runs[len] = 0;
771
772 int uL = SkFixedFloorToInt(ul);
773 int lL = SkFixedCeilToInt(ll);
774 if (uL + 2 == lL) { // We only need to compute two triangles, accelerate this special case
775 SkFixed first = SkIntToFixed(uL) + SK_Fixed1 - ul;
776 SkFixed second = ll - ul - first;
777 SkAlpha a1 = fullAlpha - partial_triangle_to_alpha(first, lDY);
778 SkAlpha a2 = partial_triangle_to_alpha(second, lDY);
779 alphas[0] = alphas[0] > a1 ? alphas[0] - a1 : 0;
780 alphas[1] = alphas[1] > a2 ? alphas[1] - a2 : 0;
781 } else {
783 tempAlphas + uL - L, ul - SkIntToFixed(uL), ll - SkIntToFixed(uL), lDY, fullAlpha);
784 for (int i = uL; i < lL; ++i) {
785 if (alphas[i - L] > tempAlphas[i - L]) {
786 alphas[i - L] -= tempAlphas[i - L];
787 } else {
788 alphas[i - L] = 0;
789 }
790 }
791 }
792
793 int uR = SkFixedFloorToInt(ur);
794 int lR = SkFixedCeilToInt(lr);
795 if (uR + 2 == lR) { // We only need to compute two triangles, accelerate this special case
796 SkFixed first = SkIntToFixed(uR) + SK_Fixed1 - ur;
797 SkFixed second = lr - ur - first;
798 SkAlpha a1 = partial_triangle_to_alpha(first, rDY);
799 SkAlpha a2 = fullAlpha - partial_triangle_to_alpha(second, rDY);
800 alphas[len - 2] = alphas[len - 2] > a1 ? alphas[len - 2] - a1 : 0;
801 alphas[len - 1] = alphas[len - 1] > a2 ? alphas[len - 1] - a2 : 0;
802 } else {
804 tempAlphas + uR - L, ur - SkIntToFixed(uR), lr - SkIntToFixed(uR), rDY, fullAlpha);
805 for (int i = uR; i < lR; ++i) {
806 if (alphas[i - L] > tempAlphas[i - L]) {
807 alphas[i - L] -= tempAlphas[i - L];
808 } else {
809 alphas[i - L] = 0;
810 }
811 }
812 }
813
814 if (isUsingMask) {
815 for (int i = 0; i < len; ++i) {
816 if (needSafeCheck) {
817 safely_add_alpha(&maskRow[L + i], alphas[i]);
818 } else {
819 add_alpha(&maskRow[L + i], alphas[i]);
820 }
821 }
822 } else {
823 if (fullAlpha == 0xFF && !noRealBlitter) {
824 // Real blitter is faster than RunBasedAdditiveBlitter
825 blitter->getRealBlitter()->blitAntiH(L, y, alphas, runs);
826 } else {
827 blitter->blitAntiH(L, y, alphas, len);
828 }
829 }
830
831 if (len > kQuickLen) {
832 delete[] alphas;
833 }
834}
835
837 int y,
838 SkFixed ul,
839 SkFixed ur,
840 SkFixed ll,
841 SkFixed lr,
842 SkFixed lDY,
843 SkFixed rDY,
844 SkAlpha fullAlpha,
845 SkAlpha* maskRow,
846 bool isUsingMask,
847 bool noRealBlitter = false,
848 bool needSafeCheck = false) {
849 SkASSERT(lDY >= 0 && rDY >= 0); // We should only send in the absolte value
850
851 if (ul > ur) {
852 return;
853 }
854
855 // Edge crosses. Approximate it. This should only happend due to precision limit,
856 // so the approximation could be very coarse.
857 if (ll > lr) {
858 ll = lr = approximate_intersection(ul, ll, ur, lr);
859 }
860
861 if (ul == ur && ll == lr) {
862 return; // empty trapzoid
863 }
864
865 // We're going to use the left line ul-ll and the rite line ur-lr
866 // to exclude the area that's not covered by the path.
867 // Swapping (ul, ll) or (ur, lr) won't affect that exclusion
868 // so we'll do that for simplicity.
869 if (ul > ll) {
870 std::swap(ul, ll);
871 }
872 if (ur > lr) {
873 std::swap(ur, lr);
874 }
875
876 SkFixed joinLeft = SkFixedCeilToFixed(ll);
877 SkFixed joinRite = SkFixedFloorToFixed(ur);
878 if (joinLeft <= joinRite) { // There's a rect from joinLeft to joinRite that we can blit
879 if (ul < joinLeft) {
880 int len = SkFixedCeilToInt(joinLeft - ul);
881 if (len == 1) {
882 SkAlpha alpha = trapezoid_to_alpha(joinLeft - ul, joinLeft - ll);
883 blit_single_alpha(blitter,
884 y,
885 ul >> 16,
886 alpha,
887 fullAlpha,
888 maskRow,
889 isUsingMask,
890 noRealBlitter,
891 needSafeCheck);
892 } else if (len == 2) {
893 SkFixed first = joinLeft - SK_Fixed1 - ul;
894 SkFixed second = ll - ul - first;
895 SkAlpha a1 = partial_triangle_to_alpha(first, lDY);
896 SkAlpha a2 = fullAlpha - partial_triangle_to_alpha(second, lDY);
897 blit_two_alphas(blitter,
898 y,
899 ul >> 16,
900 a1,
901 a2,
902 fullAlpha,
903 maskRow,
904 isUsingMask,
905 noRealBlitter,
906 needSafeCheck);
907 } else {
909 y,
910 ul,
911 joinLeft,
912 ll,
913 joinLeft,
914 lDY,
915 SK_MaxS32,
916 fullAlpha,
917 maskRow,
918 isUsingMask,
919 noRealBlitter,
920 needSafeCheck);
921 }
922 }
923 // SkAAClip requires that we blit from left to right.
924 // Hence we must blit [ul, joinLeft] before blitting [joinLeft, joinRite]
925 if (joinLeft < joinRite) {
926 blit_full_alpha(blitter,
927 y,
928 SkFixedFloorToInt(joinLeft),
929 SkFixedFloorToInt(joinRite - joinLeft),
930 fullAlpha,
931 maskRow,
932 isUsingMask,
933 noRealBlitter,
934 needSafeCheck);
935 }
936 if (lr > joinRite) {
937 int len = SkFixedCeilToInt(lr - joinRite);
938 if (len == 1) {
939 SkAlpha alpha = trapezoid_to_alpha(ur - joinRite, lr - joinRite);
940 blit_single_alpha(blitter,
941 y,
942 joinRite >> 16,
943 alpha,
944 fullAlpha,
945 maskRow,
946 isUsingMask,
947 noRealBlitter,
948 needSafeCheck);
949 } else if (len == 2) {
950 SkFixed first = joinRite + SK_Fixed1 - ur;
951 SkFixed second = lr - ur - first;
952 SkAlpha a1 = fullAlpha - partial_triangle_to_alpha(first, rDY);
953 SkAlpha a2 = partial_triangle_to_alpha(second, rDY);
954 blit_two_alphas(blitter,
955 y,
956 joinRite >> 16,
957 a1,
958 a2,
959 fullAlpha,
960 maskRow,
961 isUsingMask,
962 noRealBlitter,
963 needSafeCheck);
964 } else {
966 y,
967 joinRite,
968 ur,
969 joinRite,
970 lr,
971 SK_MaxS32,
972 rDY,
973 fullAlpha,
974 maskRow,
975 isUsingMask,
976 noRealBlitter,
977 needSafeCheck);
978 }
979 }
980 } else {
982 y,
983 ul,
984 ur,
985 ll,
986 lr,
987 lDY,
988 rDY,
989 fullAlpha,
990 maskRow,
991 isUsingMask,
992 noRealBlitter,
993 needSafeCheck);
994 }
995}
996
997static bool operator<(const SkAnalyticEdge& a, const SkAnalyticEdge& b) {
998 int valuea = a.fUpperY;
999 int valueb = b.fUpperY;
1000
1001 if (valuea == valueb) {
1002 valuea = a.fX;
1003 valueb = b.fX;
1004 }
1005
1006 if (valuea == valueb) {
1007 valuea = a.fDX;
1008 valueb = b.fDX;
1009 }
1010
1011 return valuea < valueb;
1012}
1013
1015 SkTQSort(list, list + count);
1016
1017 // now make the edges linked in sorted order
1018 for (int i = 1; i < count; ++i) {
1019 list[i - 1]->fNext = list[i];
1020 list[i]->fPrev = list[i - 1];
1021 }
1022
1023 *last = list[count - 1];
1024 return list[0];
1025}
1026
1027static void validate_sort(const SkAnalyticEdge* edge) {
1028#ifdef SK_DEBUG
1029 SkFixed y = SkIntToFixed(-32768);
1030
1031 while (edge->fUpperY != SK_MaxS32) {
1032 edge->validate();
1033 SkASSERT(y <= edge->fUpperY);
1034
1035 y = edge->fUpperY;
1036 edge = (SkAnalyticEdge*)edge->fNext;
1037 }
1038#endif
1039}
1040
1041// For an edge, we consider it smooth if the Dx doesn't change much, and Dy is large enough
1042// For curves that are updating, the Dx is not changing much if fQDx/fCDx and fQDy/fCDy are
1043// relatively large compared to fQDDx/QCDDx and fQDDy/fCDDy
1044static bool is_smooth_enough(SkAnalyticEdge* thisEdge, SkAnalyticEdge* nextEdge, int stop_y) {
1045 if (thisEdge->fCurveCount < 0) {
1046 const SkCubicEdge& cEdge = static_cast<SkAnalyticCubicEdge*>(thisEdge)->fCEdge;
1047 int ddshift = cEdge.fCurveShift;
1048 return SkAbs32(cEdge.fCDx) >> 1 >= SkAbs32(cEdge.fCDDx) >> ddshift &&
1049 SkAbs32(cEdge.fCDy) >> 1 >= SkAbs32(cEdge.fCDDy) >> ddshift &&
1050 // current Dy is (fCDy - (fCDDy >> ddshift)) >> dshift
1051 (cEdge.fCDy - (cEdge.fCDDy >> ddshift)) >> cEdge.fCubicDShift >= SK_Fixed1;
1052 } else if (thisEdge->fCurveCount > 0) {
1053 const SkQuadraticEdge& qEdge = static_cast<SkAnalyticQuadraticEdge*>(thisEdge)->fQEdge;
1054 return SkAbs32(qEdge.fQDx) >> 1 >= SkAbs32(qEdge.fQDDx) &&
1055 SkAbs32(qEdge.fQDy) >> 1 >= SkAbs32(qEdge.fQDDy) &&
1056 // current Dy is (fQDy - fQDDy) >> shift
1057 (qEdge.fQDy - qEdge.fQDDy) >> qEdge.fCurveShift >= SK_Fixed1;
1058 }
1059 return SkAbs32(nextEdge->fDX - thisEdge->fDX) <= SK_Fixed1 && // DDx should be small
1060 nextEdge->fLowerY - nextEdge->fUpperY >= SK_Fixed1; // Dy should be large
1061}
1062
1063// Check if the leftE and riteE are changing smoothly in terms of fDX.
1064// If yes, we can later skip the fractional y and directly jump to integer y.
1066 SkAnalyticEdge* riteE,
1067 SkAnalyticEdge* currE,
1068 int stop_y) {
1069 if (currE->fUpperY >= SkLeftShift(stop_y, 16)) {
1070 return false; // We're at the end so we won't skip anything
1071 }
1072 if (leftE->fLowerY + SK_Fixed1 < riteE->fLowerY) {
1073 return is_smooth_enough(leftE, currE, stop_y); // Only leftE is changing
1074 } else if (leftE->fLowerY > riteE->fLowerY + SK_Fixed1) {
1075 return is_smooth_enough(riteE, currE, stop_y); // Only riteE is changing
1076 }
1077
1078 // Now both edges are changing, find the second next edge
1079 SkAnalyticEdge* nextCurrE = currE->fNext;
1080 if (nextCurrE->fUpperY >= stop_y << 16) { // Check if we're at the end
1081 return false;
1082 }
1083 // Ensure that currE is the next left edge and nextCurrE is the next right edge. Swap if not.
1084 if (nextCurrE->fUpperX < currE->fUpperX) {
1085 std::swap(currE, nextCurrE);
1086 }
1087 return is_smooth_enough(leftE, currE, stop_y) && is_smooth_enough(riteE, nextCurrE, stop_y);
1088}
1089
1091 AdditiveBlitter* blitter,
1092 int start_y,
1093 int stop_y,
1094 SkFixed leftBound,
1095 SkFixed riteBound,
1096 bool isUsingMask) {
1097 validate_sort((SkAnalyticEdge*)prevHead->fNext);
1098
1099 SkAnalyticEdge* leftE = (SkAnalyticEdge*)prevHead->fNext;
1100 SkAnalyticEdge* riteE = (SkAnalyticEdge*)leftE->fNext;
1101 SkAnalyticEdge* currE = (SkAnalyticEdge*)riteE->fNext;
1102
1103 SkFixed y = std::max(leftE->fUpperY, riteE->fUpperY);
1104
1105 for (;;) {
1106 // We have to check fLowerY first because some edges might be alone (e.g., there's only
1107 // a left edge but no right edge in a given y scan line) due to precision limit.
1108 while (leftE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges
1109 if (!leftE->update(y)) {
1110 if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) {
1111 goto END_WALK;
1112 }
1113 leftE = currE;
1114 currE = (SkAnalyticEdge*)currE->fNext;
1115 }
1116 }
1117 while (riteE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges
1118 if (!riteE->update(y)) {
1119 if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) {
1120 goto END_WALK;
1121 }
1122 riteE = currE;
1123 currE = (SkAnalyticEdge*)currE->fNext;
1124 }
1125 }
1126
1127 SkASSERT(leftE);
1128 SkASSERT(riteE);
1129
1130 // check our bottom clip
1131 if (SkFixedFloorToInt(y) >= stop_y) {
1132 break;
1133 }
1134
1135 SkASSERT(SkFixedFloorToInt(leftE->fUpperY) <= stop_y);
1136 SkASSERT(SkFixedFloorToInt(riteE->fUpperY) <= stop_y);
1137
1138 leftE->goY(y);
1139 riteE->goY(y);
1140
1141 if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX && leftE->fDX > riteE->fDX)) {
1142 std::swap(leftE, riteE);
1143 }
1144
1145 SkFixed local_bot_fixed = std::min(leftE->fLowerY, riteE->fLowerY);
1146 if (is_smooth_enough(leftE, riteE, currE, stop_y)) {
1147 local_bot_fixed = SkFixedCeilToFixed(local_bot_fixed);
1148 }
1149 local_bot_fixed = std::min(local_bot_fixed, SkIntToFixed(stop_y));
1150
1151 SkFixed left = std::max(leftBound, leftE->fX);
1152 SkFixed dLeft = leftE->fDX;
1153 SkFixed rite = std::min(riteBound, riteE->fX);
1154 SkFixed dRite = riteE->fDX;
1155 if (0 == (dLeft | dRite)) {
1156 int fullLeft = SkFixedCeilToInt(left);
1157 int fullRite = SkFixedFloorToInt(rite);
1158 SkFixed partialLeft = SkIntToFixed(fullLeft) - left;
1159 SkFixed partialRite = rite - SkIntToFixed(fullRite);
1160 int fullTop = SkFixedCeilToInt(y);
1161 int fullBot = SkFixedFloorToInt(local_bot_fixed);
1162 SkFixed partialTop = SkIntToFixed(fullTop) - y;
1163 SkFixed partialBot = local_bot_fixed - SkIntToFixed(fullBot);
1164 if (fullTop > fullBot) { // The rectangle is within one pixel height...
1165 partialTop -= (SK_Fixed1 - partialBot);
1166 partialBot = 0;
1167 }
1168
1169 if (fullRite >= fullLeft) {
1170 if (partialTop > 0) { // blit first partial row
1171 if (partialLeft > 0) {
1172 blitter->blitAntiH(fullLeft - 1,
1173 fullTop - 1,
1174 fixed_to_alpha(SkFixedMul(partialTop, partialLeft)));
1175 }
1176 blitter->blitAntiH(
1177 fullLeft, fullTop - 1, fullRite - fullLeft, fixed_to_alpha(partialTop));
1178 if (partialRite > 0) {
1179 blitter->blitAntiH(fullRite,
1180 fullTop - 1,
1181 fixed_to_alpha(SkFixedMul(partialTop, partialRite)));
1182 }
1183 blitter->flush_if_y_changed(y, y + partialTop);
1184 }
1185
1186 // Blit all full-height rows from fullTop to fullBot
1187 if (fullBot > fullTop &&
1188 // SkAAClip cannot handle the empty rect so check the non-emptiness here
1189 // (bug chromium:662800)
1190 (fullRite > fullLeft || fixed_to_alpha(partialLeft) > 0 ||
1191 fixed_to_alpha(partialRite) > 0)) {
1192 blitter->getRealBlitter()->blitAntiRect(fullLeft - 1,
1193 fullTop,
1194 fullRite - fullLeft,
1195 fullBot - fullTop,
1196 fixed_to_alpha(partialLeft),
1197 fixed_to_alpha(partialRite));
1198 }
1199
1200 if (partialBot > 0) { // blit last partial row
1201 if (partialLeft > 0) {
1202 blitter->blitAntiH(fullLeft - 1,
1203 fullBot,
1204 fixed_to_alpha(SkFixedMul(partialBot, partialLeft)));
1205 }
1206 blitter->blitAntiH(
1207 fullLeft, fullBot, fullRite - fullLeft, fixed_to_alpha(partialBot));
1208 if (partialRite > 0) {
1209 blitter->blitAntiH(fullRite,
1210 fullBot,
1211 fixed_to_alpha(SkFixedMul(partialBot, partialRite)));
1212 }
1213 }
1214 } else {
1215 // Normal conditions, this means left and rite are within the same pixel, but if
1216 // both left and rite were < leftBounds or > rightBounds, both edges are clipped and
1217 // we should not do any blitting (particularly since the negative width saturates to
1218 // full alpha).
1219 SkFixed width = rite - left;
1220 if (width > 0) {
1221 if (partialTop > 0) {
1222 blitter->blitAntiH(fullLeft - 1,
1223 fullTop - 1,
1224 1,
1225 fixed_to_alpha(SkFixedMul(partialTop, width)));
1226 blitter->flush_if_y_changed(y, y + partialTop);
1227 }
1228 if (fullBot > fullTop) {
1229 blitter->getRealBlitter()->blitV(
1230 fullLeft - 1, fullTop, fullBot - fullTop, fixed_to_alpha(width));
1231 }
1232 if (partialBot > 0) {
1233 blitter->blitAntiH(fullLeft - 1,
1234 fullBot,
1235 1,
1236 fixed_to_alpha(SkFixedMul(partialBot, width)));
1237 }
1238 }
1239 }
1240
1241 y = local_bot_fixed;
1242 } else {
1243 // The following constant are used to snap X
1244 // We snap X mainly for speedup (no tiny triangle) and
1245 // avoiding edge cases caused by precision errors
1246 const SkFixed kSnapDigit = SK_Fixed1 >> 4;
1247 const SkFixed kSnapHalf = kSnapDigit >> 1;
1248 const SkFixed kSnapMask = (-1 ^ (kSnapDigit - 1));
1249 left += kSnapHalf;
1250 rite += kSnapHalf; // For fast rounding
1251
1252 // Number of blit_trapezoid_row calls we'll have
1253 int count = SkFixedCeilToInt(local_bot_fixed) - SkFixedFloorToInt(y);
1254
1255 // If we're using mask blitter, we advance the mask row in this function
1256 // to save some "if" condition checks.
1257 SkAlpha* maskRow = nullptr;
1258 if (isUsingMask) {
1259 maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16);
1260 }
1261
1262 // Instead of writing one loop that handles both partial-row blit_trapezoid_row
1263 // and full-row trapezoid_row together, we use the following 3-stage flow to
1264 // handle partial-row blit and full-row blit separately. It will save us much time
1265 // on changing y, left, and rite.
1266 if (count > 1) {
1267 if ((int)(y & 0xFFFF0000) != y) { // There's a partial-row on the top
1268 count--;
1269 SkFixed nextY = SkFixedCeilToFixed(y + 1);
1270 SkFixed dY = nextY - y;
1271 SkFixed nextLeft = left + SkFixedMul(dLeft, dY);
1272 SkFixed nextRite = rite + SkFixedMul(dRite, dY);
1273 SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
1274 (nextLeft & kSnapMask) >= leftBound &&
1275 (nextRite & kSnapMask) <= riteBound);
1276 blit_trapezoid_row(blitter,
1277 y >> 16,
1278 left & kSnapMask,
1279 rite & kSnapMask,
1280 nextLeft & kSnapMask,
1281 nextRite & kSnapMask,
1282 leftE->fDY,
1283 riteE->fDY,
1284 get_partial_alpha(0xFF, dY),
1285 maskRow,
1286 isUsingMask);
1287 blitter->flush_if_y_changed(y, nextY);
1288 left = nextLeft;
1289 rite = nextRite;
1290 y = nextY;
1291 }
1292
1293 while (count > 1) { // Full rows in the middle
1294 count--;
1295 if (isUsingMask) {
1296 maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16);
1297 }
1298 SkFixed nextY = y + SK_Fixed1, nextLeft = left + dLeft, nextRite = rite + dRite;
1299 SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
1300 (nextLeft & kSnapMask) >= leftBound &&
1301 (nextRite & kSnapMask) <= riteBound);
1302 blit_trapezoid_row(blitter,
1303 y >> 16,
1304 left & kSnapMask,
1305 rite & kSnapMask,
1306 nextLeft & kSnapMask,
1307 nextRite & kSnapMask,
1308 leftE->fDY,
1309 riteE->fDY,
1310 0xFF,
1311 maskRow,
1312 isUsingMask);
1313 blitter->flush_if_y_changed(y, nextY);
1314 left = nextLeft;
1315 rite = nextRite;
1316 y = nextY;
1317 }
1318 }
1319
1320 if (isUsingMask) {
1321 maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16);
1322 }
1323
1324 SkFixed dY = local_bot_fixed - y; // partial-row on the bottom
1325 SkASSERT(dY <= SK_Fixed1);
1326 // Smooth jumping to integer y may make the last nextLeft/nextRite out of bound.
1327 // Take them back into the bound here.
1328 // Note that we substract kSnapHalf later so we have to add them to leftBound/riteBound
1329 SkFixed nextLeft = std::max(left + SkFixedMul(dLeft, dY), leftBound + kSnapHalf);
1330 SkFixed nextRite = std::min(rite + SkFixedMul(dRite, dY), riteBound + kSnapHalf);
1331 SkASSERT((left & kSnapMask) >= leftBound && (rite & kSnapMask) <= riteBound &&
1332 (nextLeft & kSnapMask) >= leftBound && (nextRite & kSnapMask) <= riteBound);
1333 blit_trapezoid_row(blitter,
1334 y >> 16,
1335 left & kSnapMask,
1336 rite & kSnapMask,
1337 nextLeft & kSnapMask,
1338 nextRite & kSnapMask,
1339 leftE->fDY,
1340 riteE->fDY,
1341 get_partial_alpha(0xFF, dY),
1342 maskRow,
1343 isUsingMask);
1344 blitter->flush_if_y_changed(y, local_bot_fixed);
1345 left = nextLeft;
1346 rite = nextRite;
1347 y = local_bot_fixed;
1348 left -= kSnapHalf;
1349 rite -= kSnapHalf;
1350 }
1351
1352 leftE->fX = left;
1353 riteE->fX = rite;
1354 leftE->fY = riteE->fY = y;
1355 }
1356
1357END_WALK:;
1358}
1359
1360static void update_next_next_y(SkFixed y, SkFixed nextY, SkFixed* nextNextY) {
1361 *nextNextY = y > nextY && y < *nextNextY ? y : *nextNextY;
1362}
1363
1364static void check_intersection(const SkAnalyticEdge* edge, SkFixed nextY, SkFixed* nextNextY) {
1365 if (edge->fPrev->fPrev && edge->fPrev->fX + edge->fPrev->fDX > edge->fX + edge->fDX) {
1366 *nextNextY = nextY + (SK_Fixed1 >> SkAnalyticEdge::kDefaultAccuracy);
1367 }
1368}
1369
1370static void insert_new_edges(SkAnalyticEdge* newEdge, SkFixed y, SkFixed* nextNextY) {
1371 if (newEdge->fUpperY > y) {
1372 update_next_next_y(newEdge->fUpperY, y, nextNextY);
1373 return;
1374 }
1375 SkAnalyticEdge* prev = newEdge->fPrev;
1376 if (prev->fX <= newEdge->fX) {
1377 while (newEdge->fUpperY <= y) {
1378 check_intersection(newEdge, y, nextNextY);
1379 update_next_next_y(newEdge->fLowerY, y, nextNextY);
1380 newEdge = newEdge->fNext;
1381 }
1382 update_next_next_y(newEdge->fUpperY, y, nextNextY);
1383 return;
1384 }
1385 // find first x pos to insert
1387 // insert the lot, fixing up the links as we go
1388 do {
1389 SkAnalyticEdge* next = newEdge->fNext;
1390 do {
1391 if (start->fNext == newEdge) {
1392 goto nextEdge;
1393 }
1394 SkAnalyticEdge* after = start->fNext;
1395 if (after->fX >= newEdge->fX) {
1396 break;
1397 }
1398 SkASSERT(start != after);
1399 start = after;
1400 } while (true);
1401 remove_edge(newEdge);
1402 insert_edge_after(newEdge, start);
1403 nextEdge:
1404 check_intersection(newEdge, y, nextNextY);
1405 update_next_next_y(newEdge->fLowerY, y, nextNextY);
1406 start = newEdge;
1407 newEdge = next;
1408 } while (newEdge->fUpperY <= y);
1409 update_next_next_y(newEdge->fUpperY, y, nextNextY);
1410}
1411
1413#ifdef SK_DEBUG
1414 while (edge->fUpperY <= y) {
1415 SkASSERT(edge->fPrev && edge->fNext);
1416 SkASSERT(edge->fPrev->fNext == edge);
1417 SkASSERT(edge->fNext->fPrev == edge);
1418 SkASSERT(edge->fUpperY <= edge->fLowerY);
1419 SkASSERT(edge->fPrev->fPrev == nullptr || edge->fPrev->fX <= edge->fX);
1420 edge = edge->fNext;
1421 }
1422#endif
1423}
1424
1425// Return true if prev->fX, next->fX are too close in the current pixel row.
1427 // When next->fDX == 0, prev->fX >= next->fX - SkAbs32(next->fDX) would be false
1428 // even if prev->fX and next->fX are close and within one pixel (e.g., prev->fX == 0.1,
1429 // next->fX == 0.9). Adding SLACK = 1 to the formula would guarantee it to be true if two
1430 // edges prev and next are within one pixel.
1431 constexpr SkFixed SLACK = SK_Fixed1;
1432
1433 // Note that even if the following test failed, the edges might still be very close to each
1434 // other at some point within the current pixel row because of prev->fDX and next->fDX.
1435 // However, to handle that case, we have to sacrafice more performance.
1436 // I think the current quality is good enough (mainly by looking at Nebraska-StateSeal.svg)
1437 // so I'll ignore fDX for performance tradeoff.
1438 return next && prev && next->fUpperY < lowerY &&
1439 prev->fX + SLACK >= next->fX - SkAbs32(next->fDX);
1440 // The following is more accurate but also slower.
1441 // return (prev && prev->fPrev && next && next->fNext != nullptr && next->fUpperY < lowerY &&
1442 // prev->fX + SkAbs32(prev->fDX) + SLACK >= next->fX - SkAbs32(next->fDX));
1443}
1444
1445// This function exists for the case where the previous rite edge is removed because
1446// its fLowerY <= nextY
1447static bool edges_too_close(int prevRite, SkFixed ul, SkFixed ll) {
1448 return prevRite > SkFixedFloorToInt(ul) || prevRite > SkFixedFloorToInt(ll);
1449}
1450
1452 SkFixed lowerY,
1453 SkFixed lowerLeft,
1454 SkFixed lowerRite,
1455 AdditiveBlitter* blitter,
1456 SkAlpha* maskRow,
1457 bool isUsingMask,
1458 bool noRealBlitter,
1459 SkFixed leftClip,
1460 SkFixed rightClip) {
1461 SkAnalyticEdge* riteE = leftE->fRiteE;
1462 SkASSERT(riteE);
1463 SkASSERT(riteE->fNext == nullptr || leftE->fSavedY == riteE->fSavedY);
1464 SkASSERT(SkFixedFloorToInt(lowerY - 1) == SkFixedFloorToInt(leftE->fSavedY));
1465 int y = SkFixedFloorToInt(leftE->fSavedY);
1466 // Instead of using fixed_to_alpha(lowerY - leftE->fSavedY), we use the following fullAlpha
1467 // to elimiate cumulative error: if there are many fractional y scan lines within the
1468 // same row, the former may accumulate the rounding error while the later won't.
1469 SkAlpha fullAlpha = fixed_to_alpha(lowerY - SkIntToFixed(y)) -
1471 // We need fSavedDY because the (quad or cubic) edge might be updated
1473 blitter,
1474 y,
1475 std::max(leftE->fSavedX, leftClip),
1476 std::min(riteE->fSavedX, rightClip),
1477 std::max(lowerLeft, leftClip),
1478 std::min(lowerRite, rightClip),
1479 leftE->fSavedDY,
1480 riteE->fSavedDY,
1481 fullAlpha,
1482 maskRow,
1483 isUsingMask,
1484 noRealBlitter || (fullAlpha == 0xFF && (edges_too_close(leftE->fPrev, leftE, lowerY) ||
1485 edges_too_close(riteE, riteE->fNext, lowerY))),
1486 true);
1487 leftE->fRiteE = nullptr;
1488}
1489
1491 SkAnalyticEdge* riteE,
1492 SkFixed left,
1493 SkFixed leftDY, // don't save leftE->fX/fDY as they may have been updated
1494 SkFixed y,
1495 SkFixed nextY,
1496 bool isIntegralNextY,
1497 bool leftEnds,
1498 bool riteEnds,
1499 AdditiveBlitter* blitter,
1500 SkAlpha* maskRow,
1501 bool isUsingMask,
1502 bool noRealBlitter,
1503 SkFixed leftClip,
1504 SkFixed rightClip,
1505 int yShift) {
1506 if (leftE->fRiteE && leftE->fRiteE != riteE) {
1507 // leftE's right edge changed. Blit the saved trapezoid.
1508 SkASSERT(leftE->fRiteE->fNext == nullptr || leftE->fRiteE->fY == y);
1510 y,
1511 left,
1512 leftE->fRiteE->fX,
1513 blitter,
1514 maskRow,
1515 isUsingMask,
1516 noRealBlitter,
1517 leftClip,
1518 rightClip);
1519 }
1520 if (!leftE->fRiteE) {
1521 // Save and defer blitting the trapezoid
1522 SkASSERT(riteE->fRiteE == nullptr);
1523 SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY);
1524 SkASSERT(riteE->fNext == nullptr || riteE->fY == y);
1525 leftE->saveXY(left, y, leftDY);
1526 riteE->saveXY(riteE->fX, y, riteE->fDY);
1527 leftE->fRiteE = riteE;
1528 }
1529 SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY);
1530 riteE->goY(nextY, yShift);
1531 // Always blit when edges end or nextY is integral
1532 if (isIntegralNextY || leftEnds || riteEnds) {
1534 nextY,
1535 leftE->fX,
1536 riteE->fX,
1537 blitter,
1538 maskRow,
1539 isUsingMask,
1540 noRealBlitter,
1541 leftClip,
1542 rightClip);
1543 }
1544}
1545
1546static void aaa_walk_edges(SkAnalyticEdge* prevHead,
1547 SkAnalyticEdge* nextTail,
1548 SkPathFillType fillType,
1549 AdditiveBlitter* blitter,
1550 int start_y,
1551 int stop_y,
1552 SkFixed leftClip,
1553 SkFixed rightClip,
1554 bool isUsingMask,
1555 bool forceRLE,
1556 bool useDeferred,
1557 bool skipIntersect) {
1558 prevHead->fX = prevHead->fUpperX = leftClip;
1559 nextTail->fX = nextTail->fUpperX = rightClip;
1560 SkFixed y = std::max(prevHead->fNext->fUpperY, SkIntToFixed(start_y));
1561 SkFixed nextNextY = SK_MaxS32;
1562
1563 {
1564 SkAnalyticEdge* edge;
1565 for (edge = prevHead->fNext; edge->fUpperY <= y; edge = edge->fNext) {
1566 edge->goY(y);
1567 update_next_next_y(edge->fLowerY, y, &nextNextY);
1568 }
1569 update_next_next_y(edge->fUpperY, y, &nextNextY);
1570 }
1571
1572 int windingMask = SkPathFillType_IsEvenOdd(fillType) ? 1 : -1;
1573 bool isInverse = SkPathFillType_IsInverse(fillType);
1574
1575 if (isInverse && SkIntToFixed(start_y) != y) {
1576 int width = SkFixedFloorToInt(rightClip - leftClip);
1577 if (SkFixedFloorToInt(y) != start_y) {
1578 blitter->getRealBlitter()->blitRect(
1579 SkFixedFloorToInt(leftClip), start_y, width, SkFixedFloorToInt(y) - start_y);
1580 start_y = SkFixedFloorToInt(y);
1581 }
1582 SkAlpha* maskRow =
1583 isUsingMask ? static_cast<MaskAdditiveBlitter*>(blitter)->getRow(start_y) : nullptr;
1584 blit_full_alpha(blitter,
1585 start_y,
1586 SkFixedFloorToInt(leftClip),
1587 width,
1588 fixed_to_alpha(y - SkIntToFixed(start_y)),
1589 maskRow,
1590 isUsingMask,
1591 false,
1592 false);
1593 }
1594
1595 while (true) {
1596 int w = 0;
1597 bool in_interval = isInverse;
1598 SkFixed prevX = prevHead->fX;
1599 SkFixed nextY = std::min(nextNextY, SkFixedCeilToFixed(y + 1));
1600 bool isIntegralNextY = (nextY & (SK_Fixed1 - 1)) == 0;
1601 SkAnalyticEdge* currE = prevHead->fNext;
1602 SkAnalyticEdge* leftE = prevHead;
1603 SkFixed left = leftClip;
1604 SkFixed leftDY = 0;
1605 bool leftEnds = false;
1606 int prevRite = SkFixedFloorToInt(leftClip);
1607
1608 nextNextY = SK_MaxS32;
1609
1610 SkASSERT((nextY & ((SK_Fixed1 >> 2) - 1)) == 0);
1611 int yShift = 0;
1612 if ((nextY - y) & (SK_Fixed1 >> 2)) {
1613 yShift = 2;
1614 nextY = y + (SK_Fixed1 >> 2);
1615 } else if ((nextY - y) & (SK_Fixed1 >> 1)) {
1616 yShift = 1;
1617 SkASSERT(nextY == y + (SK_Fixed1 >> 1));
1618 }
1619
1620 SkAlpha fullAlpha = fixed_to_alpha(nextY - y);
1621
1622 // If we're using mask blitter, we advance the mask row in this function
1623 // to save some "if" condition checks.
1624 SkAlpha* maskRow = nullptr;
1625 if (isUsingMask) {
1626 maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(SkFixedFloorToInt(y));
1627 }
1628
1629 SkASSERT(currE->fPrev == prevHead);
1630 validate_edges_for_y(currE, y);
1631
1632 // Even if next - y == SK_Fixed1, we can still break the left-to-right order requirement
1633 // of the SKAAClip: |\| (two trapezoids with overlapping middle wedges)
1634 bool noRealBlitter = forceRLE; // forceRLE && (nextY - y != SK_Fixed1);
1635
1636 while (currE->fUpperY <= y) {
1637 SkASSERT(currE->fLowerY >= nextY);
1638 SkASSERT(currE->fY == y);
1639
1640 w += currE->fWinding;
1641 bool prev_in_interval = in_interval;
1642 in_interval = !(w & windingMask) == isInverse;
1643
1644 bool isLeft = in_interval && !prev_in_interval;
1645 bool isRite = !in_interval && prev_in_interval;
1646 bool currEnds = currE->fLowerY == nextY;
1647
1648 if (useDeferred) {
1649 if (currE->fRiteE && !isLeft) {
1650 // currE is a left edge previously, but now it's not.
1651 // Blit the trapezoid between fSavedY and y.
1652 SkASSERT(currE->fRiteE->fY == y);
1654 y,
1655 currE->fX,
1656 currE->fRiteE->fX,
1657 blitter,
1658 maskRow,
1659 isUsingMask,
1660 noRealBlitter,
1661 leftClip,
1662 rightClip);
1663 }
1664 if (leftE->fRiteE == currE && !isRite) {
1665 // currE is a right edge previously, but now it's not.
1666 // Moreover, its corresponding leftE doesn't change (otherwise we'll handle it
1667 // in the previous if clause). Hence we blit the trapezoid.
1669 y,
1670 left,
1671 currE->fX,
1672 blitter,
1673 maskRow,
1674 isUsingMask,
1675 noRealBlitter,
1676 leftClip,
1677 rightClip);
1678 }
1679 }
1680
1681 if (isRite) {
1682 if (useDeferred) {
1683 deferred_blit(leftE,
1684 currE,
1685 left,
1686 leftDY,
1687 y,
1688 nextY,
1689 isIntegralNextY,
1690 leftEnds,
1691 currEnds,
1692 blitter,
1693 maskRow,
1694 isUsingMask,
1695 noRealBlitter,
1696 leftClip,
1697 rightClip,
1698 yShift);
1699 } else {
1700 SkFixed rite = currE->fX;
1701 currE->goY(nextY, yShift);
1702 SkFixed nextLeft = std::max(leftClip, leftE->fX);
1703 rite = std::min(rightClip, rite);
1704 SkFixed nextRite = std::min(rightClip, currE->fX);
1706 blitter,
1707 y >> 16,
1708 left,
1709 rite,
1710 nextLeft,
1711 nextRite,
1712 leftDY,
1713 currE->fDY,
1714 fullAlpha,
1715 maskRow,
1716 isUsingMask,
1717 noRealBlitter || (fullAlpha == 0xFF &&
1718 (edges_too_close(prevRite, left, leftE->fX) ||
1719 edges_too_close(currE, currE->fNext, nextY))),
1720 true);
1721 prevRite = SkFixedCeilToInt(std::max(rite, currE->fX));
1722 }
1723 } else {
1724 if (isLeft) {
1725 left = std::max(currE->fX, leftClip);
1726 leftDY = currE->fDY;
1727 leftE = currE;
1728 leftEnds = leftE->fLowerY == nextY;
1729 }
1730 currE->goY(nextY, yShift);
1731 }
1732
1733 SkAnalyticEdge* next = currE->fNext;
1734 SkFixed newX;
1735
1736 while (currE->fLowerY <= nextY) {
1737 if (currE->fCurveCount < 0) {
1738 SkAnalyticCubicEdge* cubicEdge = (SkAnalyticCubicEdge*)currE;
1739 cubicEdge->keepContinuous();
1740 if (!cubicEdge->updateCubic()) {
1741 break;
1742 }
1743 } else if (currE->fCurveCount > 0) {
1745 quadEdge->keepContinuous();
1746 if (!quadEdge->updateQuadratic()) {
1747 break;
1748 }
1749 } else {
1750 break;
1751 }
1752 }
1753 SkASSERT(currE->fY == nextY);
1754
1755 if (currE->fLowerY <= nextY) {
1756 remove_edge(currE);
1757 } else {
1758 update_next_next_y(currE->fLowerY, nextY, &nextNextY);
1759 newX = currE->fX;
1760 SkASSERT(currE->fLowerY > nextY);
1761 if (newX < prevX) { // ripple currE backwards until it is x-sorted
1762 // If the crossing edge is a right edge, blit the saved trapezoid.
1763 if (leftE->fRiteE == currE && useDeferred) {
1764 SkASSERT(leftE->fY == nextY && currE->fY == nextY);
1766 nextY,
1767 leftE->fX,
1768 currE->fX,
1769 blitter,
1770 maskRow,
1771 isUsingMask,
1772 noRealBlitter,
1773 leftClip,
1774 rightClip);
1775 }
1777 } else {
1778 prevX = newX;
1779 }
1780 if (!skipIntersect) {
1781 check_intersection(currE, nextY, &nextNextY);
1782 }
1783 }
1784
1785 currE = next;
1786 SkASSERT(currE);
1787 }
1788
1789 // was our right-edge culled away?
1790 if (in_interval) {
1791 if (useDeferred) {
1792 deferred_blit(leftE,
1793 nextTail,
1794 left,
1795 leftDY,
1796 y,
1797 nextY,
1798 isIntegralNextY,
1799 leftEnds,
1800 false,
1801 blitter,
1802 maskRow,
1803 isUsingMask,
1804 noRealBlitter,
1805 leftClip,
1806 rightClip,
1807 yShift);
1808 } else {
1809 blit_trapezoid_row(blitter,
1810 y >> 16,
1811 left,
1812 rightClip,
1813 std::max(leftClip, leftE->fX),
1814 rightClip,
1815 leftDY,
1816 0,
1817 fullAlpha,
1818 maskRow,
1819 isUsingMask,
1820 noRealBlitter || (fullAlpha == 0xFF &&
1821 edges_too_close(leftE->fPrev, leftE, nextY)),
1822 true);
1823 }
1824 }
1825
1826 if (forceRLE) {
1827 ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, nextY);
1828 }
1829
1830 y = nextY;
1831 if (y >= SkIntToFixed(stop_y)) {
1832 break;
1833 }
1834
1835 // now currE points to the first edge with a fUpperY larger than the previous y
1836 insert_new_edges(currE, y, &nextNextY);
1837 }
1838}
1839
1840static void aaa_fill_path(const SkPath& path,
1841 const SkIRect& clipRect,
1842 AdditiveBlitter* blitter,
1843 int start_y,
1844 int stop_y,
1845 bool pathContainedInClip,
1846 bool isUsingMask,
1847 bool forceRLE) { // forceRLE implies that SkAAClip is calling us
1848 SkASSERT(blitter);
1849
1850 SkAnalyticEdgeBuilder builder;
1851 int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &clipRect);
1852 SkAnalyticEdge** list = builder.analyticEdgeList();
1853
1854 SkIRect rect = clipRect;
1855 if (0 == count) {
1856 if (path.isInverseFillType()) {
1857 /*
1858 * Since we are in inverse-fill, our caller has already drawn above
1859 * our top (start_y) and will draw below our bottom (stop_y). Thus
1860 * we need to restrict our drawing to the intersection of the clip
1861 * and those two limits.
1862 */
1863 if (rect.fTop < start_y) {
1864 rect.fTop = start_y;
1865 }
1866 if (rect.fBottom > stop_y) {
1867 rect.fBottom = stop_y;
1868 }
1869 if (!rect.isEmpty()) {
1870 blitter->getRealBlitter()->blitRect(
1871 rect.fLeft, rect.fTop, rect.width(), rect.height());
1872 }
1873 }
1874 return;
1875 }
1876
1877 SkAnalyticEdge headEdge, tailEdge, *last;
1878 // this returns the first and last edge after they're sorted into a dlink list
1879 SkAnalyticEdge* edge = sort_edges(list, count, &last);
1880
1881 headEdge.fRiteE = nullptr;
1882 headEdge.fPrev = nullptr;
1883 headEdge.fNext = edge;
1884 headEdge.fUpperY = headEdge.fLowerY = SK_MinS32;
1885 headEdge.fX = SK_MinS32;
1886 headEdge.fDX = 0;
1887 headEdge.fDY = SK_MaxS32;
1888 headEdge.fUpperX = SK_MinS32;
1889 edge->fPrev = &headEdge;
1890
1891 tailEdge.fRiteE = nullptr;
1892 tailEdge.fPrev = last;
1893 tailEdge.fNext = nullptr;
1894 tailEdge.fUpperY = tailEdge.fLowerY = SK_MaxS32;
1895 tailEdge.fX = SK_MaxS32;
1896 tailEdge.fDX = 0;
1897 tailEdge.fDY = SK_MaxS32;
1898 tailEdge.fUpperX = SK_MaxS32;
1899 last->fNext = &tailEdge;
1900
1901 // now edge is the head of the sorted linklist
1902
1903 if (!pathContainedInClip && start_y < clipRect.fTop) {
1904 start_y = clipRect.fTop;
1905 }
1906 if (!pathContainedInClip && stop_y > clipRect.fBottom) {
1907 stop_y = clipRect.fBottom;
1908 }
1909
1910 SkFixed leftBound = SkIntToFixed(rect.fLeft);
1911 SkFixed rightBound = SkIntToFixed(rect.fRight);
1912 if (isUsingMask) {
1913 // If we're using mask, then we have to limit the bound within the path bounds.
1914 // Otherwise, the edge drift may access an invalid address inside the mask.
1915 SkIRect ir;
1916 path.getBounds().roundOut(&ir);
1917 leftBound = std::max(leftBound, SkIntToFixed(ir.fLeft));
1918 rightBound = std::min(rightBound, SkIntToFixed(ir.fRight));
1919 }
1920
1921 if (!path.isInverseFillType() && path.isConvex() && count >= 2) {
1923 &headEdge, blitter, start_y, stop_y, leftBound, rightBound, isUsingMask);
1924 } else {
1925 // Only use deferred blitting if there are many edges.
1926 bool useDeferred =
1927 count >
1928 (SkFixedFloorToInt(tailEdge.fPrev->fLowerY - headEdge.fNext->fUpperY) + 1) * 4;
1929
1930 // We skip intersection computation if there are many points which probably already
1931 // give us enough fractional scan lines.
1932 bool skipIntersect = path.countPoints() > (stop_y - start_y) * 2;
1933
1934 aaa_walk_edges(&headEdge,
1935 &tailEdge,
1936 path.getFillType(),
1937 blitter,
1938 start_y,
1939 stop_y,
1940 leftBound,
1941 rightBound,
1942 isUsingMask,
1943 forceRLE,
1944 useDeferred,
1945 skipIntersect);
1946 }
1947}
1948
1949// Check if the path is a rect and fat enough after clipping; if so, blit it.
1950static inline bool try_blit_fat_anti_rect(SkBlitter* blitter,
1951 const SkPath& path,
1952 const SkIRect& clip) {
1953 SkRect rect;
1954 if (!path.isRect(&rect)) {
1955 return false; // not rect
1956 }
1957 if (!rect.intersect(SkRect::Make(clip))) {
1958 return true; // The intersection is empty. Hence consider it done.
1959 }
1960 SkIRect bounds = rect.roundOut();
1961 if (bounds.width() < 3) {
1962 return false; // not fat
1963 }
1964 blitter->blitFatAntiRect(rect);
1965 return true;
1966}
1967
1968void SkScan::AAAFillPath(const SkPath& path,
1969 SkBlitter* blitter,
1970 const SkIRect& ir,
1971 const SkIRect& clipBounds,
1972 bool forceRLE) {
1973 bool containedInClip = clipBounds.contains(ir);
1974 bool isInverse = path.isInverseFillType();
1975
1976 // The mask blitter (where we store intermediate alpha values directly in a mask, and then call
1977 // the real blitter once in the end to blit the whole mask) is faster than the RLE blitter when
1978 // the blit region is small enough (i.e., CanHandleRect(ir)). When isInverse is true, the blit
1979 // region is no longer the rectangle ir so we won't use the mask blitter. The caller may also
1980 // use the forceRLE flag to force not using the mask blitter. Also, when the path is a simple
1981 // rect, preparing a mask and blitting it might have too much overhead. Hence we'll use
1982 // blitFatAntiRect to avoid the mask and its overhead.
1983 if (MaskAdditiveBlitter::CanHandleRect(ir) && !isInverse && !forceRLE) {
1984 // blitFatAntiRect is slower than the normal AAA flow without MaskAdditiveBlitter.
1985 // Hence only tryBlitFatAntiRect when MaskAdditiveBlitter would have been used.
1986 if (!try_blit_fat_anti_rect(blitter, path, clipBounds)) {
1987 MaskAdditiveBlitter additiveBlitter(blitter, ir, clipBounds, isInverse);
1988 aaa_fill_path(path,
1989 clipBounds,
1990 &additiveBlitter,
1991 ir.fTop,
1992 ir.fBottom,
1993 containedInClip,
1994 true,
1995 forceRLE);
1996 }
1997 } else if (!isInverse && path.isConvex()) {
1998 // If the filling area is convex (i.e., path.isConvex && !isInverse), our simpler
1999 // aaa_walk_convex_edges won't generate alphas above 255. Hence we don't need
2000 // SafeRLEAdditiveBlitter (which is slow due to clamping). The basic RLE blitter
2001 // RunBasedAdditiveBlitter would suffice.
2002 RunBasedAdditiveBlitter additiveBlitter(blitter, ir, clipBounds, isInverse);
2003 aaa_fill_path(path,
2004 clipBounds,
2005 &additiveBlitter,
2006 ir.fTop,
2007 ir.fBottom,
2008 containedInClip,
2009 false,
2010 forceRLE);
2011 } else {
2012 // If the filling area might not be convex, the more involved aaa_walk_edges would
2013 // be called and we have to clamp the alpha downto 255. The SafeRLEAdditiveBlitter
2014 // does that at a cost of performance.
2015 SafeRLEAdditiveBlitter additiveBlitter(blitter, ir, clipBounds, isInverse);
2016 aaa_fill_path(path,
2017 clipBounds,
2018 &additiveBlitter,
2019 ir.fTop,
2020 ir.fBottom,
2021 containedInClip,
2022 false,
2023 forceRLE);
2024 }
2025}
int count
static float next(float f)
static float prev(float f)
#define check(reporter, ref, unref, make, kill)
static constexpr T SkAlign4(T x)
Definition SkAlign.h:16
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
uint8_t SkAlpha
Definition SkColor.h:26
#define SkFixedCeilToInt(x)
Definition SkFixed.h:77
int32_t SkFixed
Definition SkFixed.h:25
#define SK_Fixed1
Definition SkFixed.h:26
static SkFixed SkFixedCeilToFixed(SkFixed x)
Definition SkFixed.h:83
#define SkIntToFixed(n)
Definition SkFixed.h:73
#define SkFixedFloorToInt(x)
Definition SkFixed.h:78
#define SkFixedRoundToInt(x)
Definition SkFixed.h:76
static SkFixed SkFixedFloorToFixed(SkFixed x)
Definition SkFixed.h:86
static SkFixed SkFixedMul(SkFixed a, SkFixed b)
Definition SkFixed.h:96
static constexpr int32_t SkLeftShift(int32_t value, int32_t shift)
Definition SkMath.h:37
static constexpr int32_t SK_MinS32
Definition SkMath.h:22
static constexpr int32_t SK_MaxS32
Definition SkMath.h:21
static bool SkPathFillType_IsInverse(SkPathFillType ft)
Definition SkPathTypes.h:26
static bool SkPathFillType_IsEvenOdd(SkPathFillType ft)
Definition SkPathTypes.h:22
SkPathFillType
Definition SkPathTypes.h:11
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
static int32_t SkAbs32(int32_t value)
Definition SkSafe32.h:41
static void remove_edge(EdgeType *edge)
Definition SkScanPriv.h:45
void backward_insert_edge_based_on_x(EdgeType *edge)
Definition SkScanPriv.h:59
static void insert_edge_after(EdgeType *edge, EdgeType *afterMe)
Definition SkScanPriv.h:51
EdgeType * backward_insert_start(EdgeType *prev, SkFixed x)
Definition SkScanPriv.h:76
static void update_next_next_y(SkFixed y, SkFixed nextY, SkFixed *nextNextY)
static void check_intersection(const SkAnalyticEdge *edge, SkFixed nextY, SkFixed *nextNextY)
static SkFixed approximate_intersection(SkFixed l1, SkFixed r1, SkFixed l2, SkFixed r2)
static void deferred_blit(SkAnalyticEdge *leftE, SkAnalyticEdge *riteE, SkFixed left, SkFixed leftDY, SkFixed y, SkFixed nextY, bool isIntegralNextY, bool leftEnds, bool riteEnds, AdditiveBlitter *blitter, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, SkFixed leftClip, SkFixed rightClip, int yShift)
static SkAlpha trapezoid_to_alpha(SkFixed l1, SkFixed l2)
static SkAlpha partial_triangle_to_alpha(SkFixed a, SkFixed b)
static void blit_single_alpha(AdditiveBlitter *blitter, int y, int x, SkAlpha alpha, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, bool needSafeCheck)
static void blit_two_alphas(AdditiveBlitter *blitter, int y, int x, SkAlpha a1, SkAlpha a2, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, bool needSafeCheck)
static void blit_aaa_trapezoid_row(AdditiveBlitter *blitter, int y, SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, SkFixed lDY, SkFixed rDY, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, bool needSafeCheck)
static bool operator<(const SkAnalyticEdge &a, const SkAnalyticEdge &b)
static void blit_trapezoid_row(AdditiveBlitter *blitter, int y, SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, SkFixed lDY, SkFixed rDY, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter=false, bool needSafeCheck=false)
static void add_alpha(SkAlpha *alpha, SkAlpha delta)
static SkAlpha fixed_to_alpha(SkFixed f)
static void blit_saved_trapezoid(SkAnalyticEdge *leftE, SkFixed lowerY, SkFixed lowerLeft, SkFixed lowerRite, AdditiveBlitter *blitter, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, SkFixed leftClip, SkFixed rightClip)
static bool is_smooth_enough(SkAnalyticEdge *thisEdge, SkAnalyticEdge *nextEdge, int stop_y)
static bool try_blit_fat_anti_rect(SkBlitter *blitter, const SkPath &path, const SkIRect &clip)
static void aaa_walk_convex_edges(SkAnalyticEdge *prevHead, AdditiveBlitter *blitter, int start_y, int stop_y, SkFixed leftBound, SkFixed riteBound, bool isUsingMask)
static void safely_add_alpha(SkAlpha *alpha, SkAlpha delta)
static void aaa_fill_path(const SkPath &path, const SkIRect &clipRect, AdditiveBlitter *blitter, int start_y, int stop_y, bool pathContainedInClip, bool isUsingMask, bool forceRLE)
static void compute_alpha_below_line(SkAlpha *alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha)
static void insert_new_edges(SkAnalyticEdge *newEdge, SkFixed y, SkFixed *nextNextY)
static void aaa_walk_edges(SkAnalyticEdge *prevHead, SkAnalyticEdge *nextTail, SkPathFillType fillType, AdditiveBlitter *blitter, int start_y, int stop_y, SkFixed leftClip, SkFixed rightClip, bool isUsingMask, bool forceRLE, bool useDeferred, bool skipIntersect)
static bool edges_too_close(SkAnalyticEdge *prev, SkAnalyticEdge *next, SkFixed lowerY)
static void compute_alpha_above_line(SkAlpha *alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha)
static void blit_full_alpha(AdditiveBlitter *blitter, int y, int x, int len, SkAlpha fullAlpha, SkAlpha *maskRow, bool isUsingMask, bool noRealBlitter, bool needSafeCheck)
static SkAlpha get_partial_alpha(SkAlpha alpha, SkFixed partialHeight)
static SkAnalyticEdge * sort_edges(SkAnalyticEdge *list[], int count, SkAnalyticEdge **last)
#define validate_edges_for_y(edge, curr_y)
#define validate_sort(edge)
void SkTQSort(T *begin, T *end, const C &lessThan)
Definition SkTSort.h:194
constexpr uint8_t SkToU8(S x)
Definition SkTo.h:22
void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override
virtual void blitAntiH(int x, int y, const SkAlpha alpha)=0
virtual void flush_if_y_changed(SkFixed y, SkFixed nextY)=0
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], int len)=0
void blitH(int x, int y, int width) override
Blit a horizontal run of one or more pixels.
virtual int getWidth()=0
~AdditiveBlitter() override
void blitRect(int x, int y, int width, int height) override
Blit a solid rectangle one or more pixels wide.
virtual SkBlitter * getRealBlitter(bool forceRealBlitter=false)=0
virtual void blitAntiH(int x, int y, int width, const SkAlpha alpha)=0
void blitV(int x, int y, int height, SkAlpha alpha) override
Blit a vertical run of pixels with a constant alpha value.
void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) override
static bool CanHandleRect(const SkIRect &bounds)
void blitRect(int x, int y, int width, int height) override
Blit a solid rectangle one or more pixels wide.
int getWidth() override
void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) override
~MaskAdditiveBlitter() override
uint8_t * getRow(int y)
void flush_if_y_changed(SkFixed y, SkFixed nextY) override
void blitV(int x, int y, int height, SkAlpha alpha) override
Blit a vertical run of pixels with a constant alpha value.
void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override
SkBlitter * getRealBlitter(bool forceRealBlitter) override
MaskAdditiveBlitter(SkBlitter *realBlitter, const SkIRect &ir, const SkIRect &clipBounds, bool isInverse)
SkAlpha snapAlpha(SkAlpha alpha)
void flush_if_y_changed(SkFixed y, SkFixed nextY) override
RunBasedAdditiveBlitter(SkBlitter *realBlitter, const SkIRect &ir, const SkIRect &clipBounds, bool isInverse)
SkBlitter * getRealBlitter(bool forceRealBlitter) override
bool check(int x, int width) const
void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override
SafeRLEAdditiveBlitter(SkBlitter *realBlitter, const SkIRect &ir, const SkIRect &clipBounds, bool isInverse)
void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override
bool empty() const
Definition SkAlphaRuns.h:37
uint8_t * fAlpha
Definition SkAlphaRuns.h:27
void reset(int width)
Reinitialize for a new scanline.
SK_ALWAYS_INLINE int add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha, U8CPU maxValue, int offsetX)
Definition SkAlphaRuns.h:58
int16_t * fRuns
Definition SkAlphaRuns.h:26
static SkAlpha CatchOverflow(int alpha)
Definition SkAlphaRuns.h:30
void blitFatAntiRect(const SkRect &rect)
Definition SkBlitter.cpp:67
virtual void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1)
Definition SkBlitter.h:80
virtual int requestRowsPreserved() const
Definition SkBlitter.h:121
virtual void blitMask(const SkMask &, const SkIRect &clip)
virtual void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha)
virtual void * allocBlitMemory(size_t sz)
Definition SkBlitter.h:129
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])=0
virtual void blitH(int x, int y, int width)=0
Blit a horizontal run of one or more pixels.
virtual void blitV(int x, int y, int height, SkAlpha alpha)
Blit a vertical run of pixels with a constant alpha value.
virtual void blitRect(int x, int y, int width, int height)
Blit a solid rectangle one or more pixels wide.
static bool b
struct MyStruct a[10]
#define R(r)
double y
double x
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57
SkScalar w
int32_t height
int32_t width
bool updateCubic(bool sortY=true)
static const int kDefaultAccuracy
void goY(SkFixed y)
SkAnalyticEdge * fRiteE
SkAnalyticEdge * fNext
SkAnalyticEdge * fPrev
bool update(SkFixed last_y, bool sortY=true)
void saveXY(SkFixed x, SkFixed y, SkFixed dY)
SkFixed fCDDy
Definition SkEdge.h:84
SkFixed fCDx
Definition SkEdge.h:83
SkFixed fCDy
Definition SkEdge.h:83
SkFixed fCDDx
Definition SkEdge.h:84
uint8_t fCurveShift
Definition SkEdge.h:42
uint8_t fCubicDShift
Definition SkEdge.h:43
bool intersect(const SkIRect &r)
Definition SkRect.h:513
int32_t fBottom
larger y-axis bounds
Definition SkRect.h:36
constexpr int32_t top() const
Definition SkRect.h:120
constexpr int32_t height() const
Definition SkRect.h:165
constexpr int32_t right() const
Definition SkRect.h:127
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
constexpr int32_t width() const
Definition SkRect.h:158
void setEmpty()
Definition SkRect.h:242
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
constexpr int32_t left() const
Definition SkRect.h:113
bool contains(int32_t x, int32_t y) const
Definition SkRect.h:463
int32_t fRight
larger x-axis bounds
Definition SkRect.h:35
uint8_t *& image()
Definition SkMask.h:236
const uint32_t fRowBytes
Definition SkMask.h:43
const SkIRect fBounds
Definition SkMask.h:42
SkFixed fQDx
Definition SkEdge.h:72
SkFixed fQDDx
Definition SkEdge.h:73
SkFixed fQDy
Definition SkEdge.h:72
SkFixed fQDDy
Definition SkEdge.h:73
static SkRect Make(const SkISize &size)
Definition SkRect.h:669