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