Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkScan_Path.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
11#include "include/core/SkRect.h"
21#include "src/base/SkTSort.h"
22#include "src/core/SkBlitter.h"
23#include "src/core/SkEdge.h"
25#include "src/core/SkFDot6.h"
27#include "src/core/SkRectPriv.h"
28#include "src/core/SkScan.h"
29#include "src/core/SkScanPriv.h"
30
31#include <algorithm>
32#include <cmath>
33#include <cstdint>
34
35struct SkMask;
36
37#define kEDGE_HEAD_Y SK_MinS32
38#define kEDGE_TAIL_Y SK_MaxS32
39
40#ifdef SK_DEBUG
41 static void validate_sort(const SkEdge* edge) {
42 int y = kEDGE_HEAD_Y;
43
44 while (edge->fFirstY != SK_MaxS32) {
45 edge->validate();
46 SkASSERT(y <= edge->fFirstY);
47
48 y = edge->fFirstY;
49 edge = edge->fNext;
50 }
51 }
52#else
53 #define validate_sort(edge)
54#endif
55
56static void insert_new_edges(SkEdge* newEdge, int curr_y) {
57 if (newEdge->fFirstY != curr_y) {
58 return;
59 }
60 SkEdge* prev = newEdge->fPrev;
61 if (prev->fX <= newEdge->fX) {
62 return;
63 }
64 // find first x pos to insert
66 // insert the lot, fixing up the links as we go
67 do {
68 SkEdge* next = newEdge->fNext;
69 do {
70 if (start->fNext == newEdge) {
71 goto nextEdge;
72 }
73 SkEdge* after = start->fNext;
74 if (after->fX >= newEdge->fX) {
75 break;
76 }
77 start = after;
78 } while (true);
79 remove_edge(newEdge);
80 insert_edge_after(newEdge, start);
81nextEdge:
82 start = newEdge;
83 newEdge = next;
84 } while (newEdge->fFirstY == curr_y);
85}
86
87#ifdef SK_DEBUG
88static void validate_edges_for_y(const SkEdge* edge, int curr_y) {
89 while (edge->fFirstY <= curr_y) {
90 SkASSERT(edge->fPrev && edge->fNext);
91 SkASSERT(edge->fPrev->fNext == edge);
92 SkASSERT(edge->fNext->fPrev == edge);
93 SkASSERT(edge->fFirstY <= edge->fLastY);
94
95 SkASSERT(edge->fPrev->fX <= edge->fX);
96 edge = edge->fNext;
97 }
98}
99#else
100 #define validate_edges_for_y(edge, curr_y)
101#endif
102
103#if defined _WIN32 // disable warning : local variable used without having been initialized
104#pragma warning ( push )
105#pragma warning ( disable : 4701 )
106#endif
107
108typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline);
109#define PREPOST_START true
110#define PREPOST_END false
111
112static void walk_edges(SkEdge* prevHead, SkPathFillType fillType,
113 SkBlitter* blitter, int start_y, int stop_y,
114 PrePostProc proc, int rightClip) {
115 validate_sort(prevHead->fNext);
116
117 int curr_y = start_y;
118 int windingMask = SkPathFillType_IsEvenOdd(fillType) ? 1 : -1;
119
120 for (;;) {
121 int w = 0;
123 SkEdge* currE = prevHead->fNext;
124 SkFixed prevX = prevHead->fX;
125
126 validate_edges_for_y(currE, curr_y);
127
128 if (proc) {
129 proc(blitter, curr_y, PREPOST_START); // pre-proc
130 }
131
132 while (currE->fFirstY <= curr_y) {
133 SkASSERT(currE->fLastY >= curr_y);
134
135 int x = SkFixedRoundToInt(currE->fX);
136
137 if ((w & windingMask) == 0) { // we're starting interval
138 left = x;
139 }
140
141 w += currE->fWinding;
142
143 if ((w & windingMask) == 0) { // we finished an interval
144 int width = x - left;
145 SkASSERT(width >= 0);
146 if (width > 0) {
147 blitter->blitH(left, curr_y, width);
148 }
149 }
150
151 SkEdge* next = currE->fNext;
152 SkFixed newX;
153
154 if (currE->fLastY == curr_y) { // are we done with this edge?
155 if (currE->fCurveCount > 0) {
156 if (((SkQuadraticEdge*)currE)->updateQuadratic()) {
157 newX = currE->fX;
158 goto NEXT_X;
159 }
160 } else if (currE->fCurveCount < 0) {
161 if (((SkCubicEdge*)currE)->updateCubic()) {
162 SkASSERT(currE->fFirstY == curr_y + 1);
163
164 newX = currE->fX;
165 goto NEXT_X;
166 }
167 }
168 remove_edge(currE);
169 } else {
170 SkASSERT(currE->fLastY > curr_y);
171 newX = currE->fX + currE->fDX;
172 currE->fX = newX;
173 NEXT_X:
174 if (newX < prevX) { // ripple currE backwards until it is x-sorted
176 } else {
177 prevX = newX;
178 }
179 }
180 currE = next;
181 SkASSERT(currE);
182 }
183
184 if ((w & windingMask) != 0) { // was our right-edge culled away?
185 int width = rightClip - left;
186 if (width > 0) {
187 blitter->blitH(left, curr_y, width);
188 }
189 }
190
191 if (proc) {
192 proc(blitter, curr_y, PREPOST_END); // post-proc
193 }
194
195 curr_y += 1;
196 if (curr_y >= stop_y) {
197 break;
198 }
199 // now currE points to the first edge with a Yint larger than curr_y
200 insert_new_edges(currE, curr_y);
201 }
202}
203
204// return true if we're NOT done with this edge
205static bool update_edge(SkEdge* edge, int last_y) {
206 SkASSERT(edge->fLastY >= last_y);
207 if (last_y == edge->fLastY) {
208 if (edge->fCurveCount < 0) {
209 if (((SkCubicEdge*)edge)->updateCubic()) {
210 SkASSERT(edge->fFirstY == last_y + 1);
211 return true;
212 }
213 } else if (edge->fCurveCount > 0) {
214 if (((SkQuadraticEdge*)edge)->updateQuadratic()) {
215 SkASSERT(edge->fFirstY == last_y + 1);
216 return true;
217 }
218 }
219 return false;
220 }
221 return true;
222}
223
224// Unexpected conditions for which we need to return
225#define ASSERT_RETURN(cond) \
226 do { \
227 if (!(cond)) { \
228 SkDEBUGFAILF("assert(%s)", #cond); \
229 return; \
230 } \
231 } while (0)
232
233// Needs Y to only change once (looser than convex in X)
234static void walk_simple_edges(SkEdge* prevHead, SkBlitter* blitter, int start_y, int stop_y) {
235 validate_sort(prevHead->fNext);
236
237 SkEdge* leftE = prevHead->fNext;
238 SkEdge* riteE = leftE->fNext;
239 SkEdge* currE = riteE->fNext;
240
241 // our edge choppers for curves can result in the initial edges
242 // not lining up, so we take the max.
243 int local_top = std::max(leftE->fFirstY, riteE->fFirstY);
244 ASSERT_RETURN(local_top >= start_y);
245
246 while (local_top < stop_y) {
247 SkASSERT(leftE->fFirstY <= stop_y);
248 SkASSERT(riteE->fFirstY <= stop_y);
249
250 int local_bot = std::min(leftE->fLastY, riteE->fLastY);
251 local_bot = std::min(local_bot, stop_y - 1);
252 ASSERT_RETURN(local_top <= local_bot);
253
254 SkFixed left = leftE->fX;
255 SkFixed dLeft = leftE->fDX;
256 SkFixed rite = riteE->fX;
257 SkFixed dRite = riteE->fDX;
258 int count = local_bot - local_top;
259 ASSERT_RETURN(count >= 0);
260
261 if (0 == (dLeft | dRite)) {
262 int L = SkFixedRoundToInt(left);
263 int R = SkFixedRoundToInt(rite);
264 if (L > R) {
265 std::swap(L, R);
266 }
267 if (L < R) {
268 count += 1;
269 blitter->blitRect(L, local_top, R - L, count);
270 }
271 local_top = local_bot + 1;
272 } else {
273 do {
274 int L = SkFixedRoundToInt(left);
275 int R = SkFixedRoundToInt(rite);
276 if (L > R) {
277 std::swap(L, R);
278 }
279 if (L < R) {
280 blitter->blitH(L, local_top, R - L);
281 }
282 // Either/both of these might overflow, since we perform this step even if
283 // (later) we determine that we are done with the edge, and so the computed
284 // left or rite edge will not be used (see update_edge). Use this helper to
285 // silence UBSAN when we perform the add.
287 rite = Sk32_can_overflow_add(rite, dRite);
288 local_top += 1;
289 } while (--count >= 0);
290 }
291
292 leftE->fX = left;
293 riteE->fX = rite;
294
295 if (!update_edge(leftE, local_bot)) {
296 if (currE->fFirstY >= stop_y) {
297 return; // we're done
298 }
299 leftE = currE;
300 currE = currE->fNext;
301 ASSERT_RETURN(leftE->fFirstY == local_top);
302 }
303 if (!update_edge(riteE, local_bot)) {
304 if (currE->fFirstY >= stop_y) {
305 return; // we're done
306 }
307 riteE = currE;
308 currE = currE->fNext;
309 ASSERT_RETURN(riteE->fFirstY == local_top);
310 }
311 }
312}
313
314///////////////////////////////////////////////////////////////////////////////
315
316// this overrides blitH, and will call its proxy blitter with the inverse
317// of the spans it is given (clipped to the left/right of the cliprect)
318//
319// used to implement inverse filltypes on paths
320//
321class InverseBlitter : public SkBlitter {
322public:
323 void setBlitter(SkBlitter* blitter, const SkIRect& clip, int shift) {
324 fBlitter = blitter;
325 fFirstX = clip.fLeft << shift;
326 fLastX = clip.fRight << shift;
327 }
328 void prepost(int y, bool isStart) {
329 if (isStart) {
330 fPrevX = fFirstX;
331 } else {
332 int invWidth = fLastX - fPrevX;
333 if (invWidth > 0) {
334 fBlitter->blitH(fPrevX, y, invWidth);
335 }
336 }
337 }
338
339 // overrides
340 void blitH(int x, int y, int width) override {
341 int invWidth = x - fPrevX;
342 if (invWidth > 0) {
343 fBlitter->blitH(fPrevX, y, invWidth);
344 }
345 fPrevX = x + width;
346 }
347
348 // we do not expect to get called with these entrypoints
349 void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) override {
350 SkDEBUGFAIL("blitAntiH unexpected");
351 }
352 void blitV(int x, int y, int height, SkAlpha alpha) override {
353 SkDEBUGFAIL("blitV unexpected");
354 }
355 void blitRect(int x, int y, int width, int height) override {
356 SkDEBUGFAIL("blitRect unexpected");
357 }
358 void blitMask(const SkMask&, const SkIRect& clip) override {
359 SkDEBUGFAIL("blitMask unexpected");
360 }
361
362private:
363 SkBlitter* fBlitter;
364 int fFirstX, fLastX, fPrevX;
365};
366
367static void PrePostInverseBlitterProc(SkBlitter* blitter, int y, bool isStart) {
368 ((InverseBlitter*)blitter)->prepost(y, isStart);
369}
370
371///////////////////////////////////////////////////////////////////////////////
372
373#if defined _WIN32
374#pragma warning ( pop )
375#endif
376
377static bool operator<(const SkEdge& a, const SkEdge& b) {
378 int valuea = a.fFirstY;
379 int valueb = b.fFirstY;
380
381 if (valuea == valueb) {
382 valuea = a.fX;
383 valueb = b.fX;
384 }
385
386 return valuea < valueb;
387}
388
389static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) {
390 SkTQSort(list, list + count);
391
392 // now make the edges linked in sorted order
393 for (int i = 1; i < count; i++) {
394 list[i - 1]->fNext = list[i];
395 list[i]->fPrev = list[i - 1];
396 }
397
398 *last = list[count - 1];
399 return list[0];
400}
401
402// clipRect has not been shifted up
403void sk_fill_path(const SkPath& path, const SkIRect& clipRect, SkBlitter* blitter,
404 int start_y, int stop_y, int shiftEdgesUp, bool pathContainedInClip) {
405 SkASSERT(blitter);
406
407 SkIRect shiftedClip = clipRect;
408 shiftedClip.fLeft = SkLeftShift(shiftedClip.fLeft, shiftEdgesUp);
409 shiftedClip.fRight = SkLeftShift(shiftedClip.fRight, shiftEdgesUp);
410 shiftedClip.fTop = SkLeftShift(shiftedClip.fTop, shiftEdgesUp);
411 shiftedClip.fBottom = SkLeftShift(shiftedClip.fBottom, shiftEdgesUp);
412
413 SkBasicEdgeBuilder builder(shiftEdgesUp);
414 int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &shiftedClip);
415 SkEdge** list = builder.edgeList();
416
417 if (0 == count) {
418 if (path.isInverseFillType()) {
419 /*
420 * Since we are in inverse-fill, our caller has already drawn above
421 * our top (start_y) and will draw below our bottom (stop_y). Thus
422 * we need to restrict our drawing to the intersection of the clip
423 * and those two limits.
424 */
425 SkIRect rect = clipRect;
426 if (rect.fTop < start_y) {
427 rect.fTop = start_y;
428 }
429 if (rect.fBottom > stop_y) {
430 rect.fBottom = stop_y;
431 }
432 if (!rect.isEmpty()) {
433 blitter->blitRect(rect.fLeft << shiftEdgesUp,
434 rect.fTop << shiftEdgesUp,
435 rect.width() << shiftEdgesUp,
436 rect.height() << shiftEdgesUp);
437 }
438 }
439 return;
440 }
441
442 SkEdge headEdge, tailEdge, *last;
443 // this returns the first and last edge after they're sorted into a dlink list
444 SkEdge* edge = sort_edges(list, count, &last);
445
446 headEdge.fPrev = nullptr;
447 headEdge.fNext = edge;
448 headEdge.fFirstY = kEDGE_HEAD_Y;
449 headEdge.fX = SK_MinS32;
450 edge->fPrev = &headEdge;
451
452 tailEdge.fPrev = last;
453 tailEdge.fNext = nullptr;
454 tailEdge.fFirstY = kEDGE_TAIL_Y;
455 last->fNext = &tailEdge;
456
457 // now edge is the head of the sorted linklist
458
459 start_y = SkLeftShift(start_y, shiftEdgesUp);
460 stop_y = SkLeftShift(stop_y, shiftEdgesUp);
461 if (!pathContainedInClip && start_y < shiftedClip.fTop) {
462 start_y = shiftedClip.fTop;
463 }
464 if (!pathContainedInClip && stop_y > shiftedClip.fBottom) {
465 stop_y = shiftedClip.fBottom;
466 }
467
469 PrePostProc proc = nullptr;
470
471 if (path.isInverseFillType()) {
472 ib.setBlitter(blitter, clipRect, shiftEdgesUp);
473 blitter = &ib;
475 }
476
477 // count >= 2 is required as the convex walker does not handle missing right edges
478 if (path.isConvex() && (nullptr == proc) && count >= 2) {
479 walk_simple_edges(&headEdge, blitter, start_y, stop_y);
480 } else {
481 walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc,
482 shiftedClip.right());
483 }
484}
485
486void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
487 const SkIRect& cr = clip.getBounds();
488 SkIRect tmp;
489
490 tmp.fLeft = cr.fLeft;
491 tmp.fRight = cr.fRight;
492 tmp.fTop = cr.fTop;
493 tmp.fBottom = ir.fTop;
494 if (!tmp.isEmpty()) {
495 blitter->blitRectRegion(tmp, clip);
496 }
497}
498
499void sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
500 const SkIRect& cr = clip.getBounds();
501 SkIRect tmp;
502
503 tmp.fLeft = cr.fLeft;
504 tmp.fRight = cr.fRight;
505 tmp.fTop = ir.fBottom;
506 tmp.fBottom = cr.fBottom;
507 if (!tmp.isEmpty()) {
508 blitter->blitRectRegion(tmp, clip);
509 }
510}
511
512///////////////////////////////////////////////////////////////////////////////
513
514/**
515 * If the caller is drawing an inverse-fill path, then it pass true for
516 * skipRejectTest, so we don't abort drawing just because the src bounds (ir)
517 * is outside of the clip.
518 */
520 const SkIRect& ir, bool skipRejectTest, bool irPreClipped) {
521 fBlitter = nullptr; // null means blit nothing
522 fClipRect = nullptr;
523
524 if (clip) {
525 fClipRect = &clip->getBounds();
526 if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, ir)) { // completely clipped out
527 return;
528 }
529
530 if (clip->isRect()) {
531 if (!irPreClipped && fClipRect->contains(ir)) {
532#ifdef SK_DEBUG
533 fRectClipCheckBlitter.init(blitter, *fClipRect);
534 blitter = &fRectClipCheckBlitter;
535#endif
536 fClipRect = nullptr;
537 } else {
538 // only need a wrapper blitter if we're horizontally clipped
539 if (irPreClipped ||
540 fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) {
541 fRectBlitter.init(blitter, *fClipRect);
542 blitter = &fRectBlitter;
543 } else {
544#ifdef SK_DEBUG
545 fRectClipCheckBlitter.init(blitter, *fClipRect);
546 blitter = &fRectClipCheckBlitter;
547#endif
548 }
549 }
550 } else {
551 fRgnBlitter.init(blitter, clip);
552 blitter = &fRgnBlitter;
553 }
554 }
555 fBlitter = blitter;
556}
557
558///////////////////////////////////////////////////////////////////////////////
559
560static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) {
561 // need to limit coordinates such that the width/height of our rect can be represented
562 // in SkFixed (16.16). See skbug.com/7998
563 const int32_t limit = 32767 >> 1;
564
565 SkIRect limitR;
566 limitR.setLTRB(-limit, -limit, limit, limit);
567 if (limitR.contains(orig.getBounds())) {
568 return false;
569 }
570 reduced->op(orig, limitR, SkRegion::kIntersect_Op);
571 return true;
572}
573
574// Bias used for conservative rounding of float rects to int rects, to nudge the irects a little
575// larger, so we don't "think" a path's bounds are inside a clip, when (due to numeric drift in
576// the scan-converter) we might walk beyond the predicted limits.
577//
578// This value has been determined trial and error: pick the smallest value (after the 0.5) that
579// fixes any problematic cases (e.g. crbug.com/844457)
580// NOTE: cubics appear to be the main reason for needing this slop. If we could (perhaps) have a
581// more accurate walker for cubics, we may be able to reduce this fudge factor.
582static const double kConservativeRoundBias = 0.5 + 1.5 / SK_FDot6One;
583
584/**
585 * Round the value down. This is used to round the top and left of a rectangle,
586 * and corresponds to the way the scan converter treats the top and left edges.
587 * It has a slight bias to make the "rounded" int smaller than a normal round, to create a more
588 * conservative int-bounds (larger) from a float rect.
589 */
590static inline int round_down_to_int(SkScalar x) {
591 double xx = x;
593 return sk_double_saturate2int(ceil(xx));
594}
595
596/**
597 * Round the value up. This is used to round the right and bottom of a rectangle.
598 * It has a slight bias to make the "rounded" int smaller than a normal round, to create a more
599 * conservative int-bounds (larger) from a float rect.
600 */
601static inline int round_up_to_int(SkScalar x) {
602 double xx = x;
604 return sk_double_saturate2int(floor(xx));
605}
606
607/*
608 * Conservative rounding function, which effectively nudges the int-rect to be slightly larger
609 * than SkRect::round() might have produced. This is a safety-net for the scan-converter, which
610 * inspects the returned int-rect, and may disable clipping (for speed) if it thinks all of the
611 * edges will fit inside the clip's bounds. The scan-converter introduces slight numeric errors
612 * due to accumulated += of the slope, so this function is used to return a conservatively large
613 * int-bounds, and thus we will only disable clipping if we're sure the edges will stay in-bounds.
614 */
616 return {
617 round_down_to_int(src.fLeft),
618 round_down_to_int(src.fTop),
619 round_up_to_int(src.fRight),
620 round_up_to_int(src.fBottom),
621 };
622}
623
624void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
625 SkBlitter* blitter) {
626 if (origClip.isEmpty()) {
627 return;
628 }
629
630 // Our edges are fixed-point, and don't like the bounds of the clip to
631 // exceed that. Here we trim the clip just so we don't overflow later on
632 const SkRegion* clipPtr = &origClip;
633 SkRegion finiteClip;
634 if (clip_to_limit(origClip, &finiteClip)) {
635 if (finiteClip.isEmpty()) {
636 return;
637 }
638 clipPtr = &finiteClip;
639 }
640 // don't reference "origClip" any more, just use clipPtr
641
642
643 SkRect bounds = path.getBounds();
644 bool irPreClipped = false;
645 if (!SkRectPriv::MakeLargeS32().contains(bounds)) {
646 if (!bounds.intersect(SkRectPriv::MakeLargeS32())) {
647 bounds.setEmpty();
648 }
649 irPreClipped = true;
650 }
651
653 if (ir.isEmpty()) {
654 if (path.isInverseFillType()) {
655 blitter->blitRegion(*clipPtr);
656 }
657 return;
658 }
659
660 SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType(), irPreClipped);
661
662 blitter = clipper.getBlitter();
663 if (blitter) {
664 // we have to keep our calls to blitter in sorted order, so we
665 // must blit the above section first, then the middle, then the bottom.
666 if (path.isInverseFillType()) {
667 sk_blit_above(blitter, ir, *clipPtr);
668 }
669 SkASSERT(clipper.getClipRect() == nullptr ||
670 *clipper.getClipRect() == clipPtr->getBounds());
671 sk_fill_path(path, clipPtr->getBounds(), blitter, ir.fTop, ir.fBottom,
672 0, clipper.getClipRect() == nullptr);
673 if (path.isInverseFillType()) {
674 sk_blit_below(blitter, ir, *clipPtr);
675 }
676 } else {
677 // what does it mean to not have a blitter if path.isInverseFillType???
678 }
679}
680
681void SkScan::FillPath(const SkPath& path, const SkIRect& ir,
682 SkBlitter* blitter) {
683 SkRegion rgn(ir);
684 FillPath(path, rgn, blitter);
685}
686
688 SkRegion out; // ignored
689 return clip_to_limit(SkRegion(bounds), &out);
690}
691
692///////////////////////////////////////////////////////////////////////////////
693
694static int build_tri_edges(SkEdge edge[], const SkPoint pts[],
695 const SkIRect* clipRect, SkEdge* list[]) {
696 SkEdge** start = list;
697
698 if (edge->setLine(pts[0], pts[1], clipRect, 0)) {
699 *list++ = edge;
700 edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
701 }
702 if (edge->setLine(pts[1], pts[2], clipRect, 0)) {
703 *list++ = edge;
704 edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
705 }
706 if (edge->setLine(pts[2], pts[0], clipRect, 0)) {
707 *list++ = edge;
708 }
709 return (int)(list - start);
710}
711
712
713static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
714 SkBlitter* blitter, const SkIRect& ir) {
715 SkASSERT(pts && blitter);
716
717 SkEdge edgeStorage[3];
718 SkEdge* list[3];
719
720 int count = build_tri_edges(edgeStorage, pts, clipRect, list);
721 if (count < 2) {
722 return;
723 }
724
725 SkEdge headEdge, tailEdge, *last;
726
727 // this returns the first and last edge after they're sorted into a dlink list
728 SkEdge* edge = sort_edges(list, count, &last);
729
730 headEdge.fPrev = nullptr;
731 headEdge.fNext = edge;
732 headEdge.fFirstY = kEDGE_HEAD_Y;
733 headEdge.fX = SK_MinS32;
734 edge->fPrev = &headEdge;
735
736 tailEdge.fPrev = last;
737 tailEdge.fNext = nullptr;
738 tailEdge.fFirstY = kEDGE_TAIL_Y;
739 last->fNext = &tailEdge;
740
741 // now edge is the head of the sorted linklist
742 int stop_y = ir.fBottom;
743 if (clipRect && stop_y > clipRect->fBottom) {
744 stop_y = clipRect->fBottom;
745 }
746 int start_y = ir.fTop;
747 if (clipRect && start_y < clipRect->fTop) {
748 start_y = clipRect->fTop;
749 }
750 walk_simple_edges(&headEdge, blitter, start_y, stop_y);
751}
752
754 SkBlitter* blitter) {
755 if (clip.isEmpty()) {
756 return;
757 }
758
759 SkRect r;
760 r.setBounds(pts, 3);
761 // If r is too large (larger than can easily fit in SkFixed) then we need perform geometric
762 // clipping. This is a bit of work, so we just call the general FillPath() to handle it.
763 // Use FixedMax/2 as the limit so we can subtract two edges and still store that in Fixed.
764 const SkScalar limit = SK_MaxS16 >> 1;
765 if (!SkRect::MakeLTRB(-limit, -limit, limit, limit).contains(r)) {
766 SkPath path;
767 path.addPoly(pts, 3, false);
768 FillPath(path, clip, blitter);
769 return;
770 }
771
773 if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) {
774 return;
775 }
776
778 const SkRegion* clipRgn;
779 if (clip.isBW()) {
780 clipRgn = &clip.bwRgn();
781 } else {
782 wrap.init(clip, blitter);
783 clipRgn = &wrap.getRgn();
784 blitter = wrap.getBlitter();
785 }
786
787 SkScanClipper clipper(blitter, clipRgn, ir);
788 blitter = clipper.getBlitter();
789 if (blitter) {
790 sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);
791 }
792}
int count
static float next(float f)
static float prev(float f)
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
#define SkASSERT(cond)
Definition SkAssert.h:116
uint8_t SkAlpha
Definition SkColor.h:26
#define SK_FDot6One
Definition SkFDot6.h:40
int32_t SkFixed
Definition SkFixed.h:25
#define SkFixedRoundToInt(x)
Definition SkFixed.h:76
static constexpr int sk_double_saturate2int(double x)
#define SK_INIT_TO_AVOID_WARNING
Definition SkMacros.h:58
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 int16_t SK_MaxS16
Definition SkMath.h:18
static constexpr int32_t SK_MaxS32
Definition SkMath.h:21
static bool contains(const SkRect &r, SkPoint p)
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 constexpr int32_t Sk32_can_overflow_add(int32_t a, int32_t b)
Definition SkSafe32.h:30
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
#define validate_edges_for_y(edge, curr_y)
static SkIRect conservative_round_to_int(const SkRect &src)
void sk_fill_path(const SkPath &path, const SkIRect &clipRect, SkBlitter *blitter, int start_y, int stop_y, int shiftEdgesUp, bool pathContainedInClip)
#define PREPOST_END
static SkEdge * sort_edges(SkEdge *list[], int count, SkEdge **last)
#define kEDGE_HEAD_Y
static const double kConservativeRoundBias
static bool clip_to_limit(const SkRegion &orig, SkRegion *reduced)
static int round_down_to_int(SkScalar x)
static void walk_simple_edges(SkEdge *prevHead, SkBlitter *blitter, int start_y, int stop_y)
static int round_up_to_int(SkScalar x)
static int build_tri_edges(SkEdge edge[], const SkPoint pts[], const SkIRect *clipRect, SkEdge *list[])
static void insert_new_edges(SkEdge *newEdge, int curr_y)
static void walk_edges(SkEdge *prevHead, SkPathFillType fillType, SkBlitter *blitter, int start_y, int stop_y, PrePostProc proc, int rightClip)
#define ASSERT_RETURN(cond)
static bool update_edge(SkEdge *edge, int last_y)
#define PREPOST_START
static void sk_fill_triangle(const SkPoint pts[], const SkIRect *clipRect, SkBlitter *blitter, const SkIRect &ir)
#define validate_sort(edge)
void sk_blit_below(SkBlitter *blitter, const SkIRect &ir, const SkRegion &clip)
void(* PrePostProc)(SkBlitter *blitter, int y, bool isStartOfScanline)
void sk_blit_above(SkBlitter *blitter, const SkIRect &ir, const SkRegion &clip)
#define kEDGE_TAIL_Y
static bool operator<(const SkEdge &a, const SkEdge &b)
static void PrePostInverseBlitterProc(SkBlitter *blitter, int y, bool isStart)
void SkTQSort(T *begin, T *end, const C &lessThan)
Definition SkTSort.h:194
void setBlitter(SkBlitter *blitter, const SkIRect &clip, int shift)
void blitH(int x, int y, int width) override
Blit a horizontal run of one or more pixels.
void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) override
void blitMask(const SkMask &, const SkIRect &clip) override
void blitV(int x, int y, int height, SkAlpha alpha) override
Blit a vertical run of pixels with a constant alpha value.
void prepost(int y, bool isStart)
void blitRect(int x, int y, int width, int height) override
Blit a solid rectangle one or more pixels wide.
void init(const SkRasterClip &, SkBlitter *)
const SkRegion & getRgn() const
SkBlitter * getBlitter()
void blitRectRegion(const SkIRect &rect, const SkRegion &clip)
void blitRegion(const SkRegion &clip)
virtual void blitH(int x, int y, int width)=0
Blit a horizontal run of one or more pixels.
virtual void blitRect(int x, int y, int width, int height)
Blit a solid rectangle one or more pixels wide.
bool isEmpty() const
Definition SkPath.cpp:406
const SkRect & getBounds() const
Definition SkPath.cpp:420
bool isRect(SkRect *rect, bool *isClosed=nullptr, SkPathDirection *direction=nullptr) const
Definition SkPath.cpp:506
void init(SkBlitter *blitter, const SkIRect &clipRect)
Definition SkBlitter.h:183
static SkRect MakeLargeS32()
Definition SkRectPriv.h:33
@ kIntersect_Op
target intersected with operand
Definition SkRegion.h:368
const SkIRect & getBounds() const
Definition SkRegion.h:165
bool op(const SkIRect &rect, Op op)
Definition SkRegion.h:384
bool isEmpty() const
Definition SkRegion.h:146
void init(SkBlitter *blitter, const SkRegion *clipRgn)
Definition SkBlitter.h:216
SkScanClipper(SkBlitter *blitter, const SkRegion *clip, const SkIRect &bounds, bool skipRejectTest=false, bool boundsPreClipped=false)
SkBlitter * getBlitter() const
Definition SkScanPriv.h:23
const SkIRect * getClipRect() const
Definition SkScanPriv.h:24
static bool PathRequiresTiling(const SkIRect &bounds)
friend class SkRegion
Definition SkScan.h:76
static void FillPath(const SkPath &, const SkIRect &, SkBlitter *)
static void FillTriangle(const SkPoint pts[], const SkRasterClip &, SkBlitter *)
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct a[10]
#define R(r)
double y
double x
SkScalar w
int32_t height
int32_t width
SkEdge * fNext
Definition SkEdge.h:33
int8_t fWinding
Definition SkEdge.h:44
SkEdge * fPrev
Definition SkEdge.h:34
int32_t fLastY
Definition SkEdge.h:39
SkFixed fX
Definition SkEdge.h:36
int setLine(const SkPoint &p0, const SkPoint &p1, const SkIRect *clip, int shiftUp)
Definition SkEdge.cpp:57
SkFixed fDX
Definition SkEdge.h:37
int8_t fCurveCount
Definition SkEdge.h:41
int32_t fFirstY
Definition SkEdge.h:38
static bool Intersects(const SkIRect &a, const SkIRect &b)
Definition SkRect.h:535
int32_t fBottom
larger y-axis bounds
Definition SkRect.h:36
constexpr int32_t right() const
Definition SkRect.h:127
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
bool isEmpty() const
Definition SkRect.h:202
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom)
Definition SkRect.h:253
bool contains(int32_t x, int32_t y) const
Definition SkRect.h:463
int32_t fRight
larger x-axis bounds
Definition SkRect.h:35
void setBounds(const SkPoint pts[], int count)
Definition SkRect.h:881
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646