SkScan_Path.cpp revision 96fcdcc219d2a0d3579719b84b28bede76efba64
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
64static void insert_new_edges(SkEdge* newEdge, int curr_y) {
65    SkASSERT(newEdge->fFirstY >= curr_y);
66
67    while (newEdge->fFirstY == curr_y) {
68        SkEdge* next = newEdge->fNext;
69        backward_insert_edge_based_on_x(newEdge  SkPARAM(curr_y));
70        newEdge = next;
71    }
72}
73
74#ifdef SK_DEBUG
75static void validate_edges_for_y(const SkEdge* edge, int curr_y) {
76    while (edge->fFirstY <= curr_y) {
77        SkASSERT(edge->fPrev && edge->fNext);
78        SkASSERT(edge->fPrev->fNext == edge);
79        SkASSERT(edge->fNext->fPrev == edge);
80        SkASSERT(edge->fFirstY <= edge->fLastY);
81
82        SkASSERT(edge->fPrev->fX <= edge->fX);
83        edge = edge->fNext;
84    }
85}
86#else
87    #define validate_edges_for_y(edge, curr_y)
88#endif
89
90#if defined _WIN32 && _MSC_VER >= 1300  // disable warning : local variable used without having been initialized
91#pragma warning ( push )
92#pragma warning ( disable : 4701 )
93#endif
94
95typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline);
96#define PREPOST_START   true
97#define PREPOST_END     false
98
99static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
100                       SkBlitter* blitter, int start_y, int stop_y,
101                       PrePostProc proc, int rightClip) {
102    validate_sort(prevHead->fNext);
103
104    int curr_y = start_y;
105    // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
106    int windingMask = (fillType & 1) ? 1 : -1;
107
108    for (;;) {
109        int     w = 0;
110        int     left SK_INIT_TO_AVOID_WARNING;
111        bool    in_interval = false;
112        SkEdge* currE = prevHead->fNext;
113        SkFixed prevX = prevHead->fX;
114
115        validate_edges_for_y(currE, curr_y);
116
117        if (proc) {
118            proc(blitter, curr_y, PREPOST_START);    // pre-proc
119        }
120
121        while (currE->fFirstY <= curr_y) {
122            SkASSERT(currE->fLastY >= curr_y);
123
124            int x = SkFixedRoundToInt(currE->fX);
125            w += currE->fWinding;
126            if ((w & windingMask) == 0) { // we finished an interval
127                SkASSERT(in_interval);
128                int width = x - left;
129                SkASSERT(width >= 0);
130                if (width)
131                    blitter->blitH(left, curr_y, width);
132                in_interval = false;
133            } else if (!in_interval) {
134                left = x;
135                in_interval = true;
136            }
137
138            SkEdge* next = currE->fNext;
139            SkFixed newX;
140
141            if (currE->fLastY == curr_y) {    // are we done with this edge?
142                if (currE->fCurveCount < 0) {
143                    if (((SkCubicEdge*)currE)->updateCubic()) {
144                        SkASSERT(currE->fFirstY == curr_y + 1);
145
146                        newX = currE->fX;
147                        goto NEXT_X;
148                    }
149                } else if (currE->fCurveCount > 0) {
150                    if (((SkQuadraticEdge*)currE)->updateQuadratic()) {
151                        newX = currE->fX;
152                        goto NEXT_X;
153                    }
154                }
155                remove_edge(currE);
156            } else {
157                SkASSERT(currE->fLastY > curr_y);
158                newX = currE->fX + currE->fDX;
159                currE->fX = newX;
160            NEXT_X:
161                if (newX < prevX) { // ripple currE backwards until it is x-sorted
162                    backward_insert_edge_based_on_x(currE  SkPARAM(curr_y));
163                } else {
164                    prevX = newX;
165                }
166            }
167            currE = next;
168            SkASSERT(currE);
169        }
170
171        // was our right-edge culled away?
172        if (in_interval) {
173            int width = rightClip - left;
174            if (width > 0) {
175                blitter->blitH(left, curr_y, width);
176            }
177        }
178
179        if (proc) {
180            proc(blitter, curr_y, PREPOST_END);    // post-proc
181        }
182
183        curr_y += 1;
184        if (curr_y >= stop_y) {
185            break;
186        }
187        // now currE points to the first edge with a Yint larger than curr_y
188        insert_new_edges(currE, curr_y);
189    }
190}
191
192// return true if we're done with this edge
193static bool update_edge(SkEdge* edge, int last_y) {
194    SkASSERT(edge->fLastY >= last_y);
195    if (last_y == edge->fLastY) {
196        if (edge->fCurveCount < 0) {
197            if (((SkCubicEdge*)edge)->updateCubic()) {
198                SkASSERT(edge->fFirstY == last_y + 1);
199                return false;
200            }
201        } else if (edge->fCurveCount > 0) {
202            if (((SkQuadraticEdge*)edge)->updateQuadratic()) {
203                SkASSERT(edge->fFirstY == last_y + 1);
204                return false;
205            }
206        }
207        return true;
208    }
209    return false;
210}
211
212static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType,
213                              SkBlitter* blitter, int start_y, int stop_y,
214                              PrePostProc proc) {
215    validate_sort(prevHead->fNext);
216
217    SkEdge* leftE = prevHead->fNext;
218    SkEdge* riteE = leftE->fNext;
219    SkEdge* currE = riteE->fNext;
220
221#if 0
222    int local_top = leftE->fFirstY;
223    SkASSERT(local_top == riteE->fFirstY);
224#else
225    // our edge choppers for curves can result in the initial edges
226    // not lining up, so we take the max.
227    int local_top = SkMax32(leftE->fFirstY, riteE->fFirstY);
228#endif
229    SkASSERT(local_top >= start_y);
230
231    for (;;) {
232        SkASSERT(leftE->fFirstY <= stop_y);
233        SkASSERT(riteE->fFirstY <= stop_y);
234
235        if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX &&
236                                      leftE->fDX > riteE->fDX)) {
237            SkTSwap(leftE, riteE);
238        }
239
240        int local_bot = SkMin32(leftE->fLastY, riteE->fLastY);
241        local_bot = SkMin32(local_bot, stop_y - 1);
242        SkASSERT(local_top <= local_bot);
243
244        SkFixed left = leftE->fX;
245        SkFixed dLeft = leftE->fDX;
246        SkFixed rite = riteE->fX;
247        SkFixed dRite = riteE->fDX;
248        int count = local_bot - local_top;
249        SkASSERT(count >= 0);
250        if (0 == (dLeft | dRite)) {
251            int L = SkFixedRoundToInt(left);
252            int R = SkFixedRoundToInt(rite);
253            if (L < R) {
254                count += 1;
255                blitter->blitRect(L, local_top, R - L, count);
256            }
257            local_top = local_bot + 1;
258        } else {
259            do {
260                int L = SkFixedRoundToInt(left);
261                int R = SkFixedRoundToInt(rite);
262                if (L < R) {
263                    blitter->blitH(L, local_top, R - L);
264                }
265                left += dLeft;
266                rite += dRite;
267                local_top += 1;
268            } while (--count >= 0);
269        }
270
271        leftE->fX = left;
272        riteE->fX = rite;
273
274        if (update_edge(leftE, local_bot)) {
275            if (currE->fFirstY >= stop_y) {
276                break;
277            }
278            leftE = currE;
279            currE = currE->fNext;
280        }
281        if (update_edge(riteE, local_bot)) {
282            if (currE->fFirstY >= stop_y) {
283                break;
284            }
285            riteE = currE;
286            currE = currE->fNext;
287        }
288
289        SkASSERT(leftE);
290        SkASSERT(riteE);
291
292        // check our bottom clip
293        SkASSERT(local_top == local_bot + 1);
294        if (local_top >= stop_y) {
295            break;
296        }
297    }
298}
299
300///////////////////////////////////////////////////////////////////////////////
301
302// this guy overrides blitH, and will call its proxy blitter with the inverse
303// of the spans it is given (clipped to the left/right of the cliprect)
304//
305// used to implement inverse filltypes on paths
306//
307class InverseBlitter : public SkBlitter {
308public:
309    void setBlitter(SkBlitter* blitter, const SkIRect& clip, int shift) {
310        fBlitter = blitter;
311        fFirstX = clip.fLeft << shift;
312        fLastX = clip.fRight << shift;
313    }
314    void prepost(int y, bool isStart) {
315        if (isStart) {
316            fPrevX = fFirstX;
317        } else {
318            int invWidth = fLastX - fPrevX;
319            if (invWidth > 0) {
320                fBlitter->blitH(fPrevX, y, invWidth);
321            }
322        }
323    }
324
325    // overrides
326    void blitH(int x, int y, int width) override {
327        int invWidth = x - fPrevX;
328        if (invWidth > 0) {
329            fBlitter->blitH(fPrevX, y, invWidth);
330        }
331        fPrevX = x + width;
332    }
333
334    // we do not expect to get called with these entrypoints
335    void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) override {
336        SkDEBUGFAIL("blitAntiH unexpected");
337    }
338    void blitV(int x, int y, int height, SkAlpha alpha) override {
339        SkDEBUGFAIL("blitV unexpected");
340    }
341    void blitRect(int x, int y, int width, int height) override {
342        SkDEBUGFAIL("blitRect unexpected");
343    }
344    void blitMask(const SkMask&, const SkIRect& clip) override {
345        SkDEBUGFAIL("blitMask unexpected");
346    }
347    const SkPixmap* justAnOpaqueColor(uint32_t* value) override {
348        SkDEBUGFAIL("justAnOpaqueColor unexpected");
349        return nullptr;
350    }
351
352private:
353    SkBlitter*  fBlitter;
354    int         fFirstX, fLastX, fPrevX;
355};
356
357static void PrePostInverseBlitterProc(SkBlitter* blitter, int y, bool isStart) {
358    ((InverseBlitter*)blitter)->prepost(y, isStart);
359}
360
361///////////////////////////////////////////////////////////////////////////////
362
363#if defined _WIN32 && _MSC_VER >= 1300
364#pragma warning ( pop )
365#endif
366
367static bool operator<(const SkEdge& a, const SkEdge& b) {
368    int valuea = a.fFirstY;
369    int valueb = b.fFirstY;
370
371    if (valuea == valueb) {
372        valuea = a.fX;
373        valueb = b.fX;
374    }
375
376    return valuea < valueb;
377}
378
379static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) {
380    SkTQSort(list, list + count - 1);
381
382    // now make the edges linked in sorted order
383    for (int i = 1; i < count; i++) {
384        list[i - 1]->fNext = list[i];
385        list[i]->fPrev = list[i - 1];
386    }
387
388    *last = list[count - 1];
389    return list[0];
390}
391
392// clipRect may be null, even though we always have a clip. This indicates that
393// the path is contained in the clip, and so we can ignore it during the blit
394//
395// clipRect (if no null) has already been shifted up
396//
397void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter,
398                  int start_y, int stop_y, int shiftEdgesUp, const SkRegion& clipRgn) {
399    SkASSERT(blitter);
400
401    SkEdgeBuilder   builder;
402
403    // If we're convex, then we need both edges, even the right edge is past the clip
404    const bool canCullToTheRight = !path.isConvex();
405
406    int count = builder.build(path, clipRect, shiftEdgesUp, canCullToTheRight);
407    SkASSERT(count >= 0);
408
409    SkEdge**    list = builder.edgeList();
410
411    if (0 == count) {
412        if (path.isInverseFillType()) {
413            /*
414             *  Since we are in inverse-fill, our caller has already drawn above
415             *  our top (start_y) and will draw below our bottom (stop_y). Thus
416             *  we need to restrict our drawing to the intersection of the clip
417             *  and those two limits.
418             */
419            SkIRect rect = clipRgn.getBounds();
420            if (rect.fTop < start_y) {
421                rect.fTop = start_y;
422            }
423            if (rect.fBottom > stop_y) {
424                rect.fBottom = stop_y;
425            }
426            if (!rect.isEmpty()) {
427                blitter->blitRect(rect.fLeft << shiftEdgesUp,
428                                  rect.fTop << shiftEdgesUp,
429                                  rect.width() << shiftEdgesUp,
430                                  rect.height() << shiftEdgesUp);
431            }
432        }
433        return;
434    }
435
436    SkEdge headEdge, tailEdge, *last;
437    // this returns the first and last edge after they're sorted into a dlink list
438    SkEdge* edge = sort_edges(list, count, &last);
439
440    headEdge.fPrev = nullptr;
441    headEdge.fNext = edge;
442    headEdge.fFirstY = kEDGE_HEAD_Y;
443    headEdge.fX = SK_MinS32;
444    edge->fPrev = &headEdge;
445
446    tailEdge.fPrev = last;
447    tailEdge.fNext = nullptr;
448    tailEdge.fFirstY = kEDGE_TAIL_Y;
449    last->fNext = &tailEdge;
450
451    // now edge is the head of the sorted linklist
452
453    start_y <<= shiftEdgesUp;
454    stop_y <<= shiftEdgesUp;
455    if (clipRect && start_y < clipRect->fTop) {
456        start_y = clipRect->fTop;
457    }
458    if (clipRect && stop_y > clipRect->fBottom) {
459        stop_y = clipRect->fBottom;
460    }
461
462    InverseBlitter  ib;
463    PrePostProc     proc = nullptr;
464
465    if (path.isInverseFillType()) {
466        ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp);
467        blitter = &ib;
468        proc = PrePostInverseBlitterProc;
469    }
470
471    if (path.isConvex() && (nullptr == proc)) {
472        SkASSERT(count >= 2);   // convex walker does not handle missing right edges
473        walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, nullptr);
474    } else {
475        int rightEdge;
476        if (clipRect) {
477            rightEdge = clipRect->right();
478        } else {
479            rightEdge = SkScalarRoundToInt(path.getBounds().right()) << shiftEdgesUp;
480        }
481
482        walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc, rightEdge);
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 */
519SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip,
520                             const SkIRect& ir, bool skipRejectTest) {
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 (fClipRect->contains(ir)) {
532                fClipRect = nullptr;
533            } else {
534                // only need a wrapper blitter if we're horizontally clipped
535                if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) {
536                    fRectBlitter.init(blitter, *fClipRect);
537                    blitter = &fRectBlitter;
538                }
539            }
540        } else {
541            fRgnBlitter.init(blitter, clip);
542            blitter = &fRgnBlitter;
543        }
544    }
545    fBlitter = blitter;
546}
547
548///////////////////////////////////////////////////////////////////////////////
549
550static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) {
551    const int32_t limit = 32767;
552
553    SkIRect limitR;
554    limitR.set(-limit, -limit, limit, limit);
555    if (limitR.contains(orig.getBounds())) {
556        return false;
557    }
558    reduced->op(orig, limitR, SkRegion::kIntersect_Op);
559    return true;
560}
561
562void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
563                      SkBlitter* blitter) {
564    if (origClip.isEmpty()) {
565        return;
566    }
567
568    // Our edges are fixed-point, and don't like the bounds of the clip to
569    // exceed that. Here we trim the clip just so we don't overflow later on
570    const SkRegion* clipPtr = &origClip;
571    SkRegion finiteClip;
572    if (clip_to_limit(origClip, &finiteClip)) {
573        if (finiteClip.isEmpty()) {
574            return;
575        }
576        clipPtr = &finiteClip;
577    }
578        // don't reference "origClip" any more, just use clipPtr
579
580    SkIRect ir;
581    // We deliberately call dround() instead of round(), since we can't afford to generate a
582    // bounds that is tighter than the corresponding SkEdges. The edge code basically converts
583    // the floats to fixed, and then "rounds". If we called round() instead of dround() here,
584    // we could generate the wrong ir for values like 0.4999997.
585    path.getBounds().dround(&ir);
586    if (ir.isEmpty()) {
587        if (path.isInverseFillType()) {
588            blitter->blitRegion(*clipPtr);
589        }
590        return;
591    }
592
593    SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType());
594
595    blitter = clipper.getBlitter();
596    if (blitter) {
597        // we have to keep our calls to blitter in sorted order, so we
598        // must blit the above section first, then the middle, then the bottom.
599        if (path.isInverseFillType()) {
600            sk_blit_above(blitter, ir, *clipPtr);
601        }
602        sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom,
603                     0, *clipPtr);
604        if (path.isInverseFillType()) {
605            sk_blit_below(blitter, ir, *clipPtr);
606        }
607    } else {
608        // what does it mean to not have a blitter if path.isInverseFillType???
609    }
610}
611
612void SkScan::FillPath(const SkPath& path, const SkIRect& ir,
613                      SkBlitter* blitter) {
614    SkRegion rgn(ir);
615    FillPath(path, rgn, blitter);
616}
617
618///////////////////////////////////////////////////////////////////////////////
619
620static int build_tri_edges(SkEdge edge[], const SkPoint pts[],
621                           const SkIRect* clipRect, SkEdge* list[]) {
622    SkEdge** start = list;
623
624    if (edge->setLine(pts[0], pts[1], clipRect, 0)) {
625        *list++ = edge;
626        edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
627    }
628    if (edge->setLine(pts[1], pts[2], clipRect, 0)) {
629        *list++ = edge;
630        edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
631    }
632    if (edge->setLine(pts[2], pts[0], clipRect, 0)) {
633        *list++ = edge;
634    }
635    return (int)(list - start);
636}
637
638
639static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
640                             SkBlitter* blitter, const SkIRect& ir) {
641    SkASSERT(pts && blitter);
642
643    SkEdge edgeStorage[3];
644    SkEdge* list[3];
645
646    int count = build_tri_edges(edgeStorage, pts, clipRect, list);
647    if (count < 2) {
648        return;
649    }
650
651    SkEdge headEdge, tailEdge, *last;
652
653    // this returns the first and last edge after they're sorted into a dlink list
654    SkEdge* edge = sort_edges(list, count, &last);
655
656    headEdge.fPrev = nullptr;
657    headEdge.fNext = edge;
658    headEdge.fFirstY = kEDGE_HEAD_Y;
659    headEdge.fX = SK_MinS32;
660    edge->fPrev = &headEdge;
661
662    tailEdge.fPrev = last;
663    tailEdge.fNext = nullptr;
664    tailEdge.fFirstY = kEDGE_TAIL_Y;
665    last->fNext = &tailEdge;
666
667    // now edge is the head of the sorted linklist
668    int stop_y = ir.fBottom;
669    if (clipRect && stop_y > clipRect->fBottom) {
670        stop_y = clipRect->fBottom;
671    }
672    int start_y = ir.fTop;
673    if (clipRect && start_y < clipRect->fTop) {
674        start_y = clipRect->fTop;
675    }
676    walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, nullptr);
677//    walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, nullptr);
678}
679
680void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
681                          SkBlitter* blitter) {
682    if (clip.isEmpty()) {
683        return;
684    }
685
686    SkRect  r;
687    SkIRect ir;
688    r.set(pts, 3);
689    r.round(&ir);
690    if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) {
691        return;
692    }
693
694    SkAAClipBlitterWrapper wrap;
695    const SkRegion* clipRgn;
696    if (clip.isBW()) {
697        clipRgn = &clip.bwRgn();
698    } else {
699        wrap.init(clip, blitter);
700        clipRgn = &wrap.getRgn();
701        blitter = wrap.getBlitter();
702    }
703
704    SkScanClipper clipper(blitter, clipRgn, ir);
705    blitter = clipper.getBlitter();
706    if (blitter) {
707        sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);
708    }
709}
710