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