SkScan_Path.cpp revision ae658e15477df86d1a864feb48d0274af2784f40
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
8#include "SkScanPriv.h"
9#include "SkBlitter.h"
10#include "SkEdge.h"
11#include "SkEdgeBuilder.h"
12#include "SkGeometry.h"
13#include "SkPath.h"
14#include "SkQuadClipper.h"
15#include "SkRasterClip.h"
16#include "SkRegion.h"
17#include "SkTemplates.h"
18#include "SkTSort.h"
19
20#define kEDGE_HEAD_Y    SK_MinS32
21#define kEDGE_TAIL_Y    SK_MaxS32
22
23#ifdef SK_DEBUG
24    static void validate_sort(const SkEdge* edge) {
25        int y = kEDGE_HEAD_Y;
26
27        while (edge->fFirstY != SK_MaxS32) {
28            edge->validate();
29            SkASSERT(y <= edge->fFirstY);
30
31            y = edge->fFirstY;
32            edge = edge->fNext;
33        }
34    }
35#else
36    #define validate_sort(edge)
37#endif
38
39static inline void remove_edge(SkEdge* edge) {
40    edge->fPrev->fNext = edge->fNext;
41    edge->fNext->fPrev = edge->fPrev;
42}
43
44static inline void insert_edge_after(SkEdge* edge, SkEdge* afterMe) {
45    edge->fPrev = afterMe;
46    edge->fNext = afterMe->fNext;
47    afterMe->fNext->fPrev = edge;
48    afterMe->fNext = edge;
49}
50
51static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, curr_y)) {
52    SkFixed x = edge->fX;
53
54    SkEdge* prev = edge->fPrev;
55    while (prev->fX > x) {
56        prev = prev->fPrev;
57    }
58    if (prev->fNext != edge) {
59        remove_edge(edge);
60        insert_edge_after(edge, prev);
61    }
62}
63
64#ifndef SK_SUPPORT_LEGACY_INSERT_NEW_EDGES
65// Start from the right side, searching backwards for the point to begin the new edge list
66// insertion, marching forwards from here. The implementation could have started from the left
67// of the prior insertion, and search to the right, or with some additional caching, binary
68// search the starting point. More work could be done to determine optimal new edge insertion.
69static SkEdge* backward_insert_start(SkEdge* prev, SkFixed x) {
70    while (prev->fX > x) {
71        prev = prev->fPrev;
72    }
73    return prev;
74}
75#endif
76
77static void insert_new_edges(SkEdge* newEdge, int curr_y) {
78#ifdef SK_SUPPORT_LEGACY_INSERT_NEW_EDGES
79    SkASSERT(newEdge->fFirstY >= curr_y);
80
81    while (newEdge->fFirstY == curr_y) {
82        SkEdge* next = newEdge->fNext;
83        backward_insert_edge_based_on_x(newEdge  SkPARAM(curr_y));
84        newEdge = next;
85    }
86}
87#else
88    if (newEdge->fFirstY != curr_y) {
89        return;
90    }
91    SkEdge* prev = newEdge->fPrev;
92    if (prev->fX <= newEdge->fX) {
93        return;
94    }
95    // find first x pos to insert
96    SkEdge* start = backward_insert_start(prev, newEdge->fX);
97    // insert the lot, fixing up the links as we go
98    do {
99        SkEdge* next = newEdge->fNext;
100        do {
101            if (start->fNext == newEdge) {
102                goto nextEdge;
103            }
104            SkEdge* after = start->fNext;
105            if (after->fX >= newEdge->fX) {
106                break;
107            }
108            start = after;
109        } while (true);
110        remove_edge(newEdge);
111        insert_edge_after(newEdge, start);
112nextEdge:
113        start = newEdge;
114        newEdge = next;
115    } while (newEdge->fFirstY == curr_y);
116#endif
117}
118
119#ifdef SK_DEBUG
120static void validate_edges_for_y(const SkEdge* edge, int curr_y) {
121    while (edge->fFirstY <= curr_y) {
122        SkASSERT(edge->fPrev && edge->fNext);
123        SkASSERT(edge->fPrev->fNext == edge);
124        SkASSERT(edge->fNext->fPrev == edge);
125        SkASSERT(edge->fFirstY <= edge->fLastY);
126
127        SkASSERT(edge->fPrev->fX <= edge->fX);
128        edge = edge->fNext;
129    }
130}
131#else
132    #define validate_edges_for_y(edge, curr_y)
133#endif
134
135#if defined _WIN32 && _MSC_VER >= 1300  // disable warning : local variable used without having been initialized
136#pragma warning ( push )
137#pragma warning ( disable : 4701 )
138#endif
139
140typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline);
141#define PREPOST_START   true
142#define PREPOST_END     false
143
144static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
145                       SkBlitter* blitter, int start_y, int stop_y,
146                       PrePostProc proc, int rightClip) {
147    validate_sort(prevHead->fNext);
148
149    int curr_y = start_y;
150    // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
151    int windingMask = (fillType & 1) ? 1 : -1;
152
153    for (;;) {
154        int     w = 0;
155        int     left SK_INIT_TO_AVOID_WARNING;
156        bool    in_interval = false;
157        SkEdge* currE = prevHead->fNext;
158        SkFixed prevX = prevHead->fX;
159
160        validate_edges_for_y(currE, curr_y);
161
162        if (proc) {
163            proc(blitter, curr_y, PREPOST_START);    // pre-proc
164        }
165
166        while (currE->fFirstY <= curr_y) {
167            SkASSERT(currE->fLastY >= curr_y);
168
169            int x = SkFixedRoundToInt(currE->fX);
170            w += currE->fWinding;
171            if ((w & windingMask) == 0) { // we finished an interval
172                SkASSERT(in_interval);
173                int width = x - left;
174                SkASSERT(width >= 0);
175                if (width)
176                    blitter->blitH(left, curr_y, width);
177                in_interval = false;
178            } else if (!in_interval) {
179                left = x;
180                in_interval = true;
181            }
182
183            SkEdge* next = currE->fNext;
184            SkFixed newX;
185
186            if (currE->fLastY == curr_y) {    // are we done with this edge?
187                if (currE->fCurveCount < 0) {
188                    if (((SkCubicEdge*)currE)->updateCubic()) {
189                        SkASSERT(currE->fFirstY == curr_y + 1);
190
191                        newX = currE->fX;
192                        goto NEXT_X;
193                    }
194                } else if (currE->fCurveCount > 0) {
195                    if (((SkQuadraticEdge*)currE)->updateQuadratic()) {
196                        newX = currE->fX;
197                        goto NEXT_X;
198                    }
199                }
200                remove_edge(currE);
201            } else {
202                SkASSERT(currE->fLastY > curr_y);
203                newX = currE->fX + currE->fDX;
204                currE->fX = newX;
205            NEXT_X:
206                if (newX < prevX) { // ripple currE backwards until it is x-sorted
207                    backward_insert_edge_based_on_x(currE  SkPARAM(curr_y));
208                } else {
209                    prevX = newX;
210                }
211            }
212            currE = next;
213            SkASSERT(currE);
214        }
215
216        // was our right-edge culled away?
217        if (in_interval) {
218            int width = rightClip - left;
219            if (width > 0) {
220                blitter->blitH(left, curr_y, width);
221            }
222        }
223
224        if (proc) {
225            proc(blitter, curr_y, PREPOST_END);    // post-proc
226        }
227
228        curr_y += 1;
229        if (curr_y >= stop_y) {
230            break;
231        }
232        // now currE points to the first edge with a Yint larger than curr_y
233        insert_new_edges(currE, curr_y);
234    }
235}
236
237// return true if we're done with this edge
238static bool update_edge(SkEdge* edge, int last_y) {
239    SkASSERT(edge->fLastY >= last_y);
240    if (last_y == edge->fLastY) {
241        if (edge->fCurveCount < 0) {
242            if (((SkCubicEdge*)edge)->updateCubic()) {
243                SkASSERT(edge->fFirstY == last_y + 1);
244                return false;
245            }
246        } else if (edge->fCurveCount > 0) {
247            if (((SkQuadraticEdge*)edge)->updateQuadratic()) {
248                SkASSERT(edge->fFirstY == last_y + 1);
249                return false;
250            }
251        }
252        return true;
253    }
254    return false;
255}
256
257static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType,
258                              SkBlitter* blitter, int start_y, int stop_y,
259                              PrePostProc proc) {
260    validate_sort(prevHead->fNext);
261
262    SkEdge* leftE = prevHead->fNext;
263    SkEdge* riteE = leftE->fNext;
264    SkEdge* currE = riteE->fNext;
265
266#if 0
267    int local_top = leftE->fFirstY;
268    SkASSERT(local_top == riteE->fFirstY);
269#else
270    // our edge choppers for curves can result in the initial edges
271    // not lining up, so we take the max.
272    int local_top = SkMax32(leftE->fFirstY, riteE->fFirstY);
273#endif
274    SkASSERT(local_top >= start_y);
275
276    for (;;) {
277        SkASSERT(leftE->fFirstY <= stop_y);
278        SkASSERT(riteE->fFirstY <= stop_y);
279
280        if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX &&
281                                      leftE->fDX > riteE->fDX)) {
282            SkTSwap(leftE, riteE);
283        }
284
285        int local_bot = SkMin32(leftE->fLastY, riteE->fLastY);
286        local_bot = SkMin32(local_bot, stop_y - 1);
287        SkASSERT(local_top <= local_bot);
288
289        SkFixed left = leftE->fX;
290        SkFixed dLeft = leftE->fDX;
291        SkFixed rite = riteE->fX;
292        SkFixed dRite = riteE->fDX;
293        int count = local_bot - local_top;
294        SkASSERT(count >= 0);
295        if (0 == (dLeft | dRite)) {
296            int L = SkFixedRoundToInt(left);
297            int R = SkFixedRoundToInt(rite);
298            if (L < R) {
299                count += 1;
300                blitter->blitRect(L, local_top, R - L, count);
301            }
302            local_top = local_bot + 1;
303        } else {
304            do {
305                int L = SkFixedRoundToInt(left);
306                int R = SkFixedRoundToInt(rite);
307                if (L < R) {
308                    blitter->blitH(L, local_top, R - L);
309                }
310                left += dLeft;
311                rite += dRite;
312                local_top += 1;
313            } while (--count >= 0);
314        }
315
316        leftE->fX = left;
317        riteE->fX = rite;
318
319        if (update_edge(leftE, local_bot)) {
320            if (currE->fFirstY >= stop_y) {
321                break;
322            }
323            leftE = currE;
324            currE = currE->fNext;
325        }
326        if (update_edge(riteE, local_bot)) {
327            if (currE->fFirstY >= stop_y) {
328                break;
329            }
330            riteE = currE;
331            currE = currE->fNext;
332        }
333
334        SkASSERT(leftE);
335        SkASSERT(riteE);
336
337        // check our bottom clip
338        SkASSERT(local_top == local_bot + 1);
339        if (local_top >= stop_y) {
340            break;
341        }
342    }
343}
344
345///////////////////////////////////////////////////////////////////////////////
346
347// this guy overrides blitH, and will call its proxy blitter with the inverse
348// of the spans it is given (clipped to the left/right of the cliprect)
349//
350// used to implement inverse filltypes on paths
351//
352class InverseBlitter : public SkBlitter {
353public:
354    void setBlitter(SkBlitter* blitter, const SkIRect& clip, int shift) {
355        fBlitter = blitter;
356        fFirstX = clip.fLeft << shift;
357        fLastX = clip.fRight << shift;
358    }
359    void prepost(int y, bool isStart) {
360        if (isStart) {
361            fPrevX = fFirstX;
362        } else {
363            int invWidth = fLastX - fPrevX;
364            if (invWidth > 0) {
365                fBlitter->blitH(fPrevX, y, invWidth);
366            }
367        }
368    }
369
370    // overrides
371    void blitH(int x, int y, int width) override {
372        int invWidth = x - fPrevX;
373        if (invWidth > 0) {
374            fBlitter->blitH(fPrevX, y, invWidth);
375        }
376        fPrevX = x + width;
377    }
378
379    // we do not expect to get called with these entrypoints
380    void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) override {
381        SkDEBUGFAIL("blitAntiH unexpected");
382    }
383    void blitV(int x, int y, int height, SkAlpha alpha) override {
384        SkDEBUGFAIL("blitV unexpected");
385    }
386    void blitRect(int x, int y, int width, int height) override {
387        SkDEBUGFAIL("blitRect unexpected");
388    }
389    void blitMask(const SkMask&, const SkIRect& clip) override {
390        SkDEBUGFAIL("blitMask unexpected");
391    }
392    const SkPixmap* justAnOpaqueColor(uint32_t* value) override {
393        SkDEBUGFAIL("justAnOpaqueColor unexpected");
394        return nullptr;
395    }
396
397private:
398    SkBlitter*  fBlitter;
399    int         fFirstX, fLastX, fPrevX;
400};
401
402static void PrePostInverseBlitterProc(SkBlitter* blitter, int y, bool isStart) {
403    ((InverseBlitter*)blitter)->prepost(y, isStart);
404}
405
406///////////////////////////////////////////////////////////////////////////////
407
408#if defined _WIN32 && _MSC_VER >= 1300
409#pragma warning ( pop )
410#endif
411
412static bool operator<(const SkEdge& a, const SkEdge& b) {
413    int valuea = a.fFirstY;
414    int valueb = b.fFirstY;
415
416    if (valuea == valueb) {
417        valuea = a.fX;
418        valueb = b.fX;
419    }
420
421    return valuea < valueb;
422}
423
424static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) {
425    SkTQSort(list, list + count - 1);
426
427    // now make the edges linked in sorted order
428    for (int i = 1; i < count; i++) {
429        list[i - 1]->fNext = list[i];
430        list[i]->fPrev = list[i - 1];
431    }
432
433    *last = list[count - 1];
434    return list[0];
435}
436
437// clipRect may be null, even though we always have a clip. This indicates that
438// the path is contained in the clip, and so we can ignore it during the blit
439//
440// clipRect (if no null) has already been shifted up
441//
442void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter,
443                  int start_y, int stop_y, int shiftEdgesUp, const SkRegion& clipRgn) {
444    SkASSERT(blitter);
445
446    SkEdgeBuilder   builder;
447
448    // If we're convex, then we need both edges, even the right edge is past the clip
449    const bool canCullToTheRight = !path.isConvex();
450
451    int count = builder.build(path, clipRect, shiftEdgesUp, canCullToTheRight);
452    SkASSERT(count >= 0);
453
454    SkEdge**    list = builder.edgeList();
455
456    if (0 == count) {
457        if (path.isInverseFillType()) {
458            /*
459             *  Since we are in inverse-fill, our caller has already drawn above
460             *  our top (start_y) and will draw below our bottom (stop_y). Thus
461             *  we need to restrict our drawing to the intersection of the clip
462             *  and those two limits.
463             */
464            SkIRect rect = clipRgn.getBounds();
465            if (rect.fTop < start_y) {
466                rect.fTop = start_y;
467            }
468            if (rect.fBottom > stop_y) {
469                rect.fBottom = stop_y;
470            }
471            if (!rect.isEmpty()) {
472                blitter->blitRect(rect.fLeft << shiftEdgesUp,
473                                  rect.fTop << shiftEdgesUp,
474                                  rect.width() << shiftEdgesUp,
475                                  rect.height() << shiftEdgesUp);
476            }
477        }
478        return;
479    }
480
481    SkEdge headEdge, tailEdge, *last;
482    // this returns the first and last edge after they're sorted into a dlink list
483    SkEdge* edge = sort_edges(list, count, &last);
484
485    headEdge.fPrev = nullptr;
486    headEdge.fNext = edge;
487    headEdge.fFirstY = kEDGE_HEAD_Y;
488    headEdge.fX = SK_MinS32;
489    edge->fPrev = &headEdge;
490
491    tailEdge.fPrev = last;
492    tailEdge.fNext = nullptr;
493    tailEdge.fFirstY = kEDGE_TAIL_Y;
494    last->fNext = &tailEdge;
495
496    // now edge is the head of the sorted linklist
497
498    start_y = SkLeftShift(start_y, shiftEdgesUp);
499    stop_y = SkLeftShift(stop_y, shiftEdgesUp);
500    if (clipRect && start_y < clipRect->fTop) {
501        start_y = clipRect->fTop;
502    }
503    if (clipRect && stop_y > clipRect->fBottom) {
504        stop_y = clipRect->fBottom;
505    }
506
507    InverseBlitter  ib;
508    PrePostProc     proc = nullptr;
509
510    if (path.isInverseFillType()) {
511        ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp);
512        blitter = &ib;
513        proc = PrePostInverseBlitterProc;
514    }
515
516    if (path.isConvex() && (nullptr == proc)) {
517        SkASSERT(count >= 2);   // convex walker does not handle missing right edges
518        walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, nullptr);
519    } else {
520        int rightEdge;
521        if (clipRect) {
522            rightEdge = clipRect->right();
523        } else {
524            rightEdge = SkScalarRoundToInt(path.getBounds().right()) << shiftEdgesUp;
525        }
526
527        walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc, rightEdge);
528    }
529}
530
531void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
532    const SkIRect& cr = clip.getBounds();
533    SkIRect tmp;
534
535    tmp.fLeft = cr.fLeft;
536    tmp.fRight = cr.fRight;
537    tmp.fTop = cr.fTop;
538    tmp.fBottom = ir.fTop;
539    if (!tmp.isEmpty()) {
540        blitter->blitRectRegion(tmp, clip);
541    }
542}
543
544void sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
545    const SkIRect& cr = clip.getBounds();
546    SkIRect tmp;
547
548    tmp.fLeft = cr.fLeft;
549    tmp.fRight = cr.fRight;
550    tmp.fTop = ir.fBottom;
551    tmp.fBottom = cr.fBottom;
552    if (!tmp.isEmpty()) {
553        blitter->blitRectRegion(tmp, clip);
554    }
555}
556
557///////////////////////////////////////////////////////////////////////////////
558
559/**
560 *  If the caller is drawing an inverse-fill path, then it pass true for
561 *  skipRejectTest, so we don't abort drawing just because the src bounds (ir)
562 *  is outside of the clip.
563 */
564SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip,
565                             const SkIRect& ir, bool skipRejectTest) {
566    fBlitter = nullptr;     // null means blit nothing
567    fClipRect = nullptr;
568
569    if (clip) {
570        fClipRect = &clip->getBounds();
571        if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, ir)) { // completely clipped out
572            return;
573        }
574
575        if (clip->isRect()) {
576            if (fClipRect->contains(ir)) {
577                fClipRect = nullptr;
578            } else {
579                // only need a wrapper blitter if we're horizontally clipped
580                if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) {
581                    fRectBlitter.init(blitter, *fClipRect);
582                    blitter = &fRectBlitter;
583                }
584            }
585        } else {
586            fRgnBlitter.init(blitter, clip);
587            blitter = &fRgnBlitter;
588        }
589    }
590    fBlitter = blitter;
591}
592
593///////////////////////////////////////////////////////////////////////////////
594
595static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) {
596    const int32_t limit = 32767;
597
598    SkIRect limitR;
599    limitR.set(-limit, -limit, limit, limit);
600    if (limitR.contains(orig.getBounds())) {
601        return false;
602    }
603    reduced->op(orig, limitR, SkRegion::kIntersect_Op);
604    return true;
605}
606
607/**
608  * Variant of SkScalarRoundToInt, identical to SkDScalarRoundToInt except when the input fraction
609  * is 0.5. In this case only, round the value down. This is used to round the top and left
610  * of a rectangle, and corresponds to the way the scan converter treats the top and left edges.
611  */
612static inline int round_down_to_int(SkScalar x) {
613    double xx = x;
614    xx += 0.5;
615    double floorXX = floor(xx);
616    return (int)floorXX - (xx == floorXX);
617}
618
619/**
620  *  Variant of SkRect::round() that explicitly performs the rounding step (i.e. floor(x + 0.5))
621  *  using double instead of SkScalar (float). It does this by calling SkDScalarRoundToInt(),
622  *  which may be slower than calling SkScalarRountToInt(), but gives slightly more accurate
623  *  results. Also rounds top and left using double, flooring when the fraction is exactly 0.5f.
624  *
625  *  e.g.
626  *      SkScalar left = 0.5f;
627  *      int ileft = SkScalarRoundToInt(left);
628  *      SkASSERT(0 == ileft);  // <--- fails
629  *      int ileft = round_down_to_int(left);
630  *      SkASSERT(0 == ileft);  // <--- succeeds
631  *      SkScalar right = 0.49999997f;
632  *      int iright = SkScalarRoundToInt(right);
633  *      SkASSERT(0 == iright);  // <--- fails
634  *      iright = SkDScalarRoundToInt(right);
635  *      SkASSERT(0 == iright);  // <--- succeeds
636  */
637static void round_asymmetric_to_int(const SkRect& src, SkIRect* dst) {
638    SkASSERT(dst);
639    dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop),
640             SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom));
641}
642
643void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
644                      SkBlitter* blitter) {
645    if (origClip.isEmpty()) {
646        return;
647    }
648
649    // Our edges are fixed-point, and don't like the bounds of the clip to
650    // exceed that. Here we trim the clip just so we don't overflow later on
651    const SkRegion* clipPtr = &origClip;
652    SkRegion finiteClip;
653    if (clip_to_limit(origClip, &finiteClip)) {
654        if (finiteClip.isEmpty()) {
655            return;
656        }
657        clipPtr = &finiteClip;
658    }
659        // don't reference "origClip" any more, just use clipPtr
660
661    SkIRect ir;
662    // We deliberately call round_asymmetric_to_int() instead of round(), since we can't afford
663    // to generate a bounds that is tighter than the corresponding SkEdges. The edge code basically
664    // converts the floats to fixed, and then "rounds". If we called round() instead of
665    // round_asymmetric_to_int() here, we could generate the wrong ir for values like 0.4999997.
666    round_asymmetric_to_int(path.getBounds(), &ir);
667    if (ir.isEmpty()) {
668        if (path.isInverseFillType()) {
669            blitter->blitRegion(*clipPtr);
670        }
671        return;
672    }
673
674    SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType());
675
676    blitter = clipper.getBlitter();
677    if (blitter) {
678        // we have to keep our calls to blitter in sorted order, so we
679        // must blit the above section first, then the middle, then the bottom.
680        if (path.isInverseFillType()) {
681            sk_blit_above(blitter, ir, *clipPtr);
682        }
683        sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom,
684                     0, *clipPtr);
685        if (path.isInverseFillType()) {
686            sk_blit_below(blitter, ir, *clipPtr);
687        }
688    } else {
689        // what does it mean to not have a blitter if path.isInverseFillType???
690    }
691}
692
693void SkScan::FillPath(const SkPath& path, const SkIRect& ir,
694                      SkBlitter* blitter) {
695    SkRegion rgn(ir);
696    FillPath(path, rgn, blitter);
697}
698
699///////////////////////////////////////////////////////////////////////////////
700
701static int build_tri_edges(SkEdge edge[], const SkPoint pts[],
702                           const SkIRect* clipRect, SkEdge* list[]) {
703    SkEdge** start = list;
704
705    if (edge->setLine(pts[0], pts[1], clipRect, 0)) {
706        *list++ = edge;
707        edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
708    }
709    if (edge->setLine(pts[1], pts[2], clipRect, 0)) {
710        *list++ = edge;
711        edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
712    }
713    if (edge->setLine(pts[2], pts[0], clipRect, 0)) {
714        *list++ = edge;
715    }
716    return (int)(list - start);
717}
718
719
720static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
721                             SkBlitter* blitter, const SkIRect& ir) {
722    SkASSERT(pts && blitter);
723
724    SkEdge edgeStorage[3];
725    SkEdge* list[3];
726
727    int count = build_tri_edges(edgeStorage, pts, clipRect, list);
728    if (count < 2) {
729        return;
730    }
731
732    SkEdge headEdge, tailEdge, *last;
733
734    // this returns the first and last edge after they're sorted into a dlink list
735    SkEdge* edge = sort_edges(list, count, &last);
736
737    headEdge.fPrev = nullptr;
738    headEdge.fNext = edge;
739    headEdge.fFirstY = kEDGE_HEAD_Y;
740    headEdge.fX = SK_MinS32;
741    edge->fPrev = &headEdge;
742
743    tailEdge.fPrev = last;
744    tailEdge.fNext = nullptr;
745    tailEdge.fFirstY = kEDGE_TAIL_Y;
746    last->fNext = &tailEdge;
747
748    // now edge is the head of the sorted linklist
749    int stop_y = ir.fBottom;
750    if (clipRect && stop_y > clipRect->fBottom) {
751        stop_y = clipRect->fBottom;
752    }
753    int start_y = ir.fTop;
754    if (clipRect && start_y < clipRect->fTop) {
755        start_y = clipRect->fTop;
756    }
757    walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, nullptr);
758//    walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, nullptr);
759}
760
761void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
762                          SkBlitter* blitter) {
763    if (clip.isEmpty()) {
764        return;
765    }
766
767    SkRect  r;
768    SkIRect ir;
769    r.set(pts, 3);
770    r.round(&ir);
771    if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) {
772        return;
773    }
774
775    SkAAClipBlitterWrapper wrap;
776    const SkRegion* clipRgn;
777    if (clip.isBW()) {
778        clipRgn = &clip.bwRgn();
779    } else {
780        wrap.init(clip, blitter);
781        clipRgn = &wrap.getRgn();
782        blitter = wrap.getBlitter();
783    }
784
785    SkScanClipper clipper(blitter, clipRgn, ir);
786    blitter = clipper.getBlitter();
787    if (blitter) {
788        sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);
789    }
790}
791