SkEdgeClipper.cpp revision 7d173403f47bb85cfd5c42b69c734668e25e47f9
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2009 The Android Open Source Project
4909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com */
8909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
10909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com#include "SkEdgeClipper.h"
11909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com#include "SkGeometry.h"
12909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
13909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool quick_reject(const SkRect& bounds, const SkRect& clip) {
14909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return bounds.fTop >= clip.fBottom || bounds.fBottom <= clip.fTop;
15909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
16909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
17909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic inline void clamp_le(SkScalar& value, SkScalar max) {
18909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (value > max) {
19909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        value = max;
20909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
21909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
22909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
23909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic inline void clamp_ge(SkScalar& value, SkScalar min) {
24909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (value < min) {
25909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        value = min;
26909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
27909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
28909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
29909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com/*  src[] must be monotonic in Y. This routine copies src into dst, and sorts
30909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com it to be increasing in Y. If it had to reverse the order of the points,
31909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com it returns true, otherwise it returns false
32909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com */
33909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool sort_increasing_Y(SkPoint dst[], const SkPoint src[], int count) {
34909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // we need the data to be monotonically increasing in Y
35909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (src[0].fY > src[count - 1].fY) {
36909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int i = 0; i < count; i++) {
37909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            dst[i] = src[count - i - 1];
38909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
39909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return true;
40909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {
41909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        memcpy(dst, src, count * sizeof(SkPoint));
42909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return false;
43909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
44909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
45909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
46909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com///////////////////////////////////////////////////////////////////////////////
47909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
48909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2,
49909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                           SkScalar target, SkScalar* t) {
50909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    /* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2
51909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com     *  We solve for t, using quadratic equation, hence we have to rearrange
52909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com     * our cooefficents to look like At^2 + Bt + C
53909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com     */
54909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar A = c0 - c1 - c1 + c2;
55909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar B = 2*(c1 - c0);
56909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar C = c0 - target;
57fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
58909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar roots[2];  // we only expect one, but make room for 2 for safety
59909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    int count = SkFindUnitQuadRoots(A, B, C, roots);
60909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (count) {
61909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        *t = roots[0];
62909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return true;
63909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
64909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return false;
65909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
66909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
67909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
68909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
69909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
70909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
71909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool chopMonoQuadAtX(SkPoint pts[3], SkScalar x, SkScalar* t) {
72909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return chopMonoQuadAt(pts[0].fX, pts[1].fX, pts[2].fX, x, t);
73909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
74909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
75909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com// Modify pts[] in place so that it is clipped in Y to the clip rect
76909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
77909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar t;
78909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPoint tmp[5]; // for SkChopQuadAt
79909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
80909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially above
81909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fY < clip.fTop) {
82909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoQuadAtY(pts, clip.fTop, &t)) {
83909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // take the 2nd chopped quad
84909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopQuadAt(pts, tmp, t);
85e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com            // clamp to clean up imprecise numerics in the chop
86e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com            tmp[2].fY = clip.fTop;
87909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[3].fY, clip.fTop);
88e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com
89909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[0] = tmp[2];
90909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[3];
91909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
92909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
93909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the top
94909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int i = 0; i < 3; i++) {
95909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                if (pts[i].fY < clip.fTop) {
96909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                    pts[i].fY = clip.fTop;
97909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                }
98909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
99909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
100909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
101fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
102909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially below
103909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[2].fY > clip.fBottom) {
104909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoQuadAtY(pts, clip.fBottom, &t)) {
105909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopQuadAt(pts, tmp, t);
106e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com            // clamp to clean up imprecise numerics in the chop
107909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[1].fY, clip.fBottom);
108e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com            tmp[2].fY = clip.fBottom;
109e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com
110909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[1];
111909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[2] = tmp[2];
112909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
113909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
114909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the bottom
115909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int i = 0; i < 3; i++) {
116909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                if (pts[i].fY > clip.fBottom) {
117909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                    pts[i].fY = clip.fBottom;
118909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                }
119909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
120909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
121909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
122909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
123909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
124909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com// srcPts[] must be monotonic in X and Y
125909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid SkEdgeClipper::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
126909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPoint pts[3];
127909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    bool reverse = sort_increasing_Y(pts, srcPts, 3);
128909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
129909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we completely above or below
130909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[2].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
131909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
132909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
133fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
134909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // Now chop so that pts is contained within clip in Y
135909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    chop_quad_in_Y(pts, clip);
136909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
137909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX > pts[2].fX) {
138909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkTSwap<SkPoint>(pts[0], pts[2]);
139909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        reverse = !reverse;
140909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
141909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkASSERT(pts[0].fX <= pts[1].fX);
142909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkASSERT(pts[1].fX <= pts[2].fX);
143909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
144909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // Now chop in X has needed, and record the segments
145909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
146909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[2].fX <= clip.fLeft) {  // wholly to the left
147909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
148909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
149909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
150909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX >= clip.fRight) {  // wholly to the right
15131223e0cb74f47f63b094520a9830c525b72fe87reed        if (!this->canCullToTheRight()) {
15231223e0cb74f47f63b094520a9830c525b72fe87reed            this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
15331223e0cb74f47f63b094520a9830c525b72fe87reed        }
154909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
155909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
156909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
157909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar t;
158909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPoint tmp[5]; // for SkChopQuadAt
159909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
160909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially to the left
161909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX < clip.fLeft) {
162909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoQuadAtX(pts, clip.fLeft, &t)) {
163909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopQuadAt(pts, tmp, t);
164909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse);
165e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com            // clamp to clean up imprecise numerics in the chop
166e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com            tmp[2].fX = clip.fLeft;
167909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[3].fX, clip.fLeft);
168e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com
169909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[0] = tmp[2];
170909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[3];
171909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
172909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
173909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the left
174909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
175181172d5642fce4a4c1d339a6e3c5e4a8079b11areed@android.com            return;
176909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
177909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
178fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
179909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially to the right
180909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[2].fX > clip.fRight) {
181909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoQuadAtX(pts, clip.fRight, &t)) {
182909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopQuadAt(pts, tmp, t);
183e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com            // clamp to clean up imprecise numerics in the chop
184909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[1].fX, clip.fRight);
185e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com            tmp[2].fX = clip.fRight;
186e01403096cc8fc15217d7de08c476c2056d8b9d0reed@google.com
187909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendQuad(tmp, reverse);
188909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse);
189909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
190909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
191909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the right
1923f0785e0c675c906c0bd704702e122149c5ee951reed@android.com            this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
193909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
194909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {    // wholly inside the clip
195909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        this->appendQuad(pts, reverse);
196909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
197909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
198909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
199909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.combool SkEdgeClipper::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
200909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint = fPoints;
201909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrVerb = fVerbs;
202909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
203909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkRect  bounds;
204909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    bounds.set(srcPts, 3);
205fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
206909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (!quick_reject(bounds, clip)) {
207909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkPoint monoY[5];
208909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        int countY = SkChopQuadAtYExtrema(srcPts, monoY);
209909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int y = 0; y <= countY; y++) {
210909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkPoint monoX[5];
211909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX);
212909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int x = 0; x <= countX; x++) {
213909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                this->clipMonoQuad(&monoX[x * 2], clip);
214909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
215909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
216909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
217909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
218909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
219909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
220909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *fCurrVerb = SkPath::kDone_Verb;
221909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint = fPoints;
222909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrVerb = fVerbs;
223909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return SkPath::kDone_Verb != fVerbs[0];
224909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
225909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
226909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com///////////////////////////////////////////////////////////////////////////////
227909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
228909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com// Modify pts[] in place so that it is clipped in Y to the clip rect
229909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
230fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
231909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially above
232909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fY < clip.fTop) {
233dc3088570f945ed0ede84f0af0016eedc267dda3reed        SkPoint tmp[7];
234dc3088570f945ed0ede84f0af0016eedc267dda3reed        if (SkChopMonoCubicAtY(pts, clip.fTop, tmp)) {
235dc3088570f945ed0ede84f0af0016eedc267dda3reed            // tmp[3, 4].fY should all be to the below clip.fTop.
23603ca64b832819564d958b70ee27a2134ff88c9c6reed@google.com            // Since we can't trust the numerics of
2376da3d1757cfee75c25a86b580834dc49d8b53f05reed@google.com            // the chopper, we force those conditions now
23815161620bee33efcb706685486c9ce0fb51a72bbreed@android.com            tmp[3].fY = clip.fTop;
239a90aa534986ffa2019b6a99260bbba086a5c608ereed@google.com            clamp_ge(tmp[4].fY, clip.fTop);
2406da3d1757cfee75c25a86b580834dc49d8b53f05reed@google.com
241909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[0] = tmp[3];
242909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[4];
243909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[2] = tmp[5];
244909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
245909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoCubicAtY failed, then we may have hit inexact numerics
246909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the top
247909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int i = 0; i < 4; i++) {
248909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                clamp_ge(pts[i].fY, clip.fTop);
249909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
250909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
251909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
252fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
253909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially below
254909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[3].fY > clip.fBottom) {
255dc3088570f945ed0ede84f0af0016eedc267dda3reed        SkPoint tmp[7];
256dc3088570f945ed0ede84f0af0016eedc267dda3reed        if (SkChopMonoCubicAtY(pts, clip.fBottom, tmp)) {
257a90aa534986ffa2019b6a99260bbba086a5c608ereed@google.com            tmp[3].fY = clip.fBottom;
258909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[2].fY, clip.fBottom);
259a90aa534986ffa2019b6a99260bbba086a5c608ereed@google.com
260909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[1];
261909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[2] = tmp[2];
262909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[3] = tmp[3];
263909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
264909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoCubicAtY failed, then we may have hit inexact numerics
265909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the bottom
266909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int i = 0; i < 4; i++) {
267909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                clamp_le(pts[i].fY, clip.fBottom);
268909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
269909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
270909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
271909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
272909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
2737d173403f47bb85cfd5c42b69c734668e25e47f9caryclarkstatic void chop_mono_cubic_at_x(SkPoint pts[4], SkScalar x, SkPoint tmp[7]) {
2747d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    if (SkChopMonoCubicAtX(pts, x, tmp)) {
2757d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        return;
2767d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    }
2777d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    SkScalar t = 0.5f;
2787d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    SkScalar lastT;
2797d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    SkScalar bestT  SK_INIT_TO_AVOID_WARNING;
2807d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    SkScalar step = 0.25f;
2817d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    SkScalar D = pts[0].fX;
2827d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    SkScalar A = pts[3].fX + 3*(pts[1].fX - pts[2].fX) - D;
2837d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    SkScalar B = 3*(pts[2].fX - pts[1].fX - pts[1].fX + D);
2847d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    SkScalar C = 3*(pts[1].fX - D);
2857d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    x -= D;
2867d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    SkScalar closest = SK_ScalarMax;
2877d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    do {
2887d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        SkScalar loc = ((A * t + B) * t + C) * t;
2897d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        SkScalar dist = SkScalarAbs(loc - x);
2907d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        if (closest > dist) {
2917d173403f47bb85cfd5c42b69c734668e25e47f9caryclark            closest = dist;
2927d173403f47bb85cfd5c42b69c734668e25e47f9caryclark            bestT = t;
2937d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        }
2947d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        lastT = t;
2957d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        t += loc < x ? step : -step;
2967d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        step *= 0.5f;
2977d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    } while (closest > 0.25f && lastT != t);
2987d173403f47bb85cfd5c42b69c734668e25e47f9caryclark    SkChopCubicAt(pts, tmp, bestT);
2997d173403f47bb85cfd5c42b69c734668e25e47f9caryclark}
3007d173403f47bb85cfd5c42b69c734668e25e47f9caryclark
301909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com// srcPts[] must be monotonic in X and Y
302909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
303909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPoint pts[4];
304909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    bool reverse = sort_increasing_Y(pts, src, 4);
305fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
306909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we completely above or below
307909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[3].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
308909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
309909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
31015161620bee33efcb706685486c9ce0fb51a72bbreed@android.com
311909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // Now chop so that pts is contained within clip in Y
312909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    chop_cubic_in_Y(pts, clip);
31315161620bee33efcb706685486c9ce0fb51a72bbreed@android.com
314909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX > pts[3].fX) {
315909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkTSwap<SkPoint>(pts[0], pts[3]);
316909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkTSwap<SkPoint>(pts[1], pts[2]);
317909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        reverse = !reverse;
318909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
319fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
320909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // Now chop in X has needed, and record the segments
321fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
322909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[3].fX <= clip.fLeft) {  // wholly to the left
323909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
324909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
325909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
326909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX >= clip.fRight) {  // wholly to the right
32731223e0cb74f47f63b094520a9830c525b72fe87reed        if (!this->canCullToTheRight()) {
32831223e0cb74f47f63b094520a9830c525b72fe87reed            this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
32931223e0cb74f47f63b094520a9830c525b72fe87reed        }
330909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
331909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
3326da3d1757cfee75c25a86b580834dc49d8b53f05reed@google.com
333909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially to the left
334909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX < clip.fLeft) {
335dc3088570f945ed0ede84f0af0016eedc267dda3reed        SkPoint tmp[7];
3367d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        chop_mono_cubic_at_x(pts, clip.fLeft, tmp);
3377d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
3387d173403f47bb85cfd5c42b69c734668e25e47f9caryclark
3397d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        // tmp[3, 4].fX should all be to the right of clip.fLeft.
3407d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        // Since we can't trust the numerics of
3417d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        // the chopper, we force those conditions now
3427d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        tmp[3].fX = clip.fLeft;
3437d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        clamp_ge(tmp[4].fX, clip.fLeft);
3447d173403f47bb85cfd5c42b69c734668e25e47f9caryclark
3457d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        pts[0] = tmp[3];
3467d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        pts[1] = tmp[4];
3477d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        pts[2] = tmp[5];
348909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
349fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
350909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially to the right
351909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[3].fX > clip.fRight) {
352dc3088570f945ed0ede84f0af0016eedc267dda3reed        SkPoint tmp[7];
3537d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        chop_mono_cubic_at_x(pts, clip.fRight, tmp);
3547d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        tmp[3].fX = clip.fRight;
3557d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        clamp_le(tmp[2].fX, clip.fRight);
356a90aa534986ffa2019b6a99260bbba086a5c608ereed@google.com
3577d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        this->appendCubic(tmp, reverse);
3587d173403f47bb85cfd5c42b69c734668e25e47f9caryclark        this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
359909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {    // wholly inside the clip
360909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        this->appendCubic(pts, reverse);
361909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
362909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
363909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
364909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.combool SkEdgeClipper::clipCubic(const SkPoint srcPts[4], const SkRect& clip) {
365909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint = fPoints;
366909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrVerb = fVerbs;
367fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
368909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkRect  bounds;
369909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    bounds.set(srcPts, 4);
370fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
371909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (!quick_reject(bounds, clip)) {
372909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkPoint monoY[10];
373909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        int countY = SkChopCubicAtYExtrema(srcPts, monoY);
374909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int y = 0; y <= countY; y++) {
375909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkPoint monoX[10];
376909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX);
377909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int x = 0; x <= countX; x++) {
378909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                this->clipMonoCubic(&monoX[x * 3], clip);
379909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
380909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
381909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
382909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
383909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
384fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
385909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *fCurrVerb = SkPath::kDone_Verb;
386909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint = fPoints;
387909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrVerb = fVerbs;
388909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return SkPath::kDone_Verb != fVerbs[0];
389909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
390909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
391909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com///////////////////////////////////////////////////////////////////////////////
392909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
393909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid SkEdgeClipper::appendVLine(SkScalar x, SkScalar y0, SkScalar y1,
394909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                                bool reverse) {
395909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *fCurrVerb++ = SkPath::kLine_Verb;
396fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
397909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (reverse) {
398909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkTSwap<SkScalar>(y0, y1);
399909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
400909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint[0].set(x, y0);
401909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint[1].set(x, y1);
402909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint += 2;
403909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
404909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
405909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid SkEdgeClipper::appendQuad(const SkPoint pts[3], bool reverse) {
406909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *fCurrVerb++ = SkPath::kQuad_Verb;
407fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
408909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (reverse) {
409909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        fCurrPoint[0] = pts[2];
410909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        fCurrPoint[2] = pts[0];
411909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {
412909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        fCurrPoint[0] = pts[0];
413909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        fCurrPoint[2] = pts[2];
414909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
415909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint[1] = pts[1];
416909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint += 3;
417909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
418909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
419909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid SkEdgeClipper::appendCubic(const SkPoint pts[4], bool reverse) {
420909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *fCurrVerb++ = SkPath::kCubic_Verb;
421fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
422909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (reverse) {
423909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int i = 0; i < 4; i++) {
424909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrPoint[i] = pts[3 - i];
425909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
426909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {
427909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        memcpy(fCurrPoint, pts, 4 * sizeof(SkPoint));
428909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
429909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint += 4;
430909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
431909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
432909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comSkPath::Verb SkEdgeClipper::next(SkPoint pts[]) {
433909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPath::Verb verb = *fCurrVerb;
434909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
435909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    switch (verb) {
436909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        case SkPath::kLine_Verb:
437909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            memcpy(pts, fCurrPoint, 2 * sizeof(SkPoint));
438909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrPoint += 2;
439909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrVerb += 1;
440909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            break;
441909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        case SkPath::kQuad_Verb:
442909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            memcpy(pts, fCurrPoint, 3 * sizeof(SkPoint));
443909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrPoint += 3;
444909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrVerb += 1;
445909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            break;
446909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        case SkPath::kCubic_Verb:
447909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            memcpy(pts, fCurrPoint, 4 * sizeof(SkPoint));
448909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrPoint += 4;
449909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrVerb += 1;
450909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            break;
451909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        case SkPath::kDone_Verb:
452909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            break;
453909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        default:
4540c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com            SkDEBUGFAIL("unexpected verb in quadclippper2 iter");
455909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            break;
456909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
457909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return verb;
458909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
459909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
460909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com///////////////////////////////////////////////////////////////////////////////
461909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
462909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com#ifdef SK_DEBUG
463909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic void assert_monotonic(const SkScalar coord[], int count) {
464909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (coord[0] > coord[(count - 1) * 2]) {
465909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int i = 1; i < count; i++) {
466909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkASSERT(coord[2 * (i - 1)] >= coord[i * 2]);
467909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
468909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else if (coord[0] < coord[(count - 1) * 2]) {
469909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int i = 1; i < count; i++) {
470909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkASSERT(coord[2 * (i - 1)] <= coord[i * 2]);
471909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
472909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {
473909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int i = 1; i < count; i++) {
474909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkASSERT(coord[2 * (i - 1)] == coord[i * 2]);
475909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
476909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
477909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
478909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
479909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid sk_assert_monotonic_y(const SkPoint pts[], int count) {
480909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (count > 1) {
481909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        assert_monotonic(&pts[0].fY, count);
482909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
483909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
484909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
485909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid sk_assert_monotonic_x(const SkPoint pts[], int count) {
486909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (count > 1) {
487909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        assert_monotonic(&pts[0].fX, count);
488909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
489909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
490909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com#endif
491