SkEdgeClipper.cpp revision 181172d5642fce4a4c1d339a6e3c5e4a8079b11a
1909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com/*
2909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com * Copyright (C) 2009 The Android Open Source Project
3909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com *
4909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com * Licensed under the Apache License, Version 2.0 (the "License");
5909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com * you may not use this file except in compliance with the License.
6909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com * You may obtain a copy of the License at
7909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com *
8909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com *      http://www.apache.org/licenses/LICENSE-2.0
9909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com *
10909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com * Unless required by applicable law or agreed to in writing, software
11909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com * distributed under the License is distributed on an "AS IS" BASIS,
12909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com * See the License for the specific language governing permissions and
14909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com * limitations under the License.
15909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com */
16909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
17909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com#include "SkEdgeClipper.h"
18909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com#include "SkGeometry.h"
19909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
20909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool quick_reject(const SkRect& bounds, const SkRect& clip) {
21909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return bounds.fTop >= clip.fBottom || bounds.fBottom <= clip.fTop;
22909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
23909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
24909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic inline void clamp_le(SkScalar& value, SkScalar max) {
25909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (value > max) {
26909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        value = max;
27909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
28909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
29909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
30909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic inline void clamp_ge(SkScalar& value, SkScalar min) {
31909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (value < min) {
32909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        value = min;
33909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
34909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
35909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
36909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com/*  src[] must be monotonic in Y. This routine copies src into dst, and sorts
37909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com it to be increasing in Y. If it had to reverse the order of the points,
38909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com it returns true, otherwise it returns false
39909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com */
40909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool sort_increasing_Y(SkPoint dst[], const SkPoint src[], int count) {
41909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // we need the data to be monotonically increasing in Y
42909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (src[0].fY > src[count - 1].fY) {
43909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int i = 0; i < count; i++) {
44909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            dst[i] = src[count - i - 1];
45909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
46909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return true;
47909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {
48909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        memcpy(dst, src, count * sizeof(SkPoint));
49909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return false;
50909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
51909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
52909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
53909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com///////////////////////////////////////////////////////////////////////////////
54909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
55909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2,
56909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                           SkScalar target, SkScalar* t) {
57909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    /* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2
58909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com     *  We solve for t, using quadratic equation, hence we have to rearrange
59909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com     * our cooefficents to look like At^2 + Bt + C
60909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com     */
61909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar A = c0 - c1 - c1 + c2;
62909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar B = 2*(c1 - c0);
63909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar C = c0 - target;
64909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
65909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar roots[2];  // we only expect one, but make room for 2 for safety
66909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    int count = SkFindUnitQuadRoots(A, B, C, roots);
67909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (count) {
68909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        *t = roots[0];
69909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return true;
70909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
71909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return false;
72909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
73909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
74909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
75909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
76909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
77909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
78909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool chopMonoQuadAtX(SkPoint pts[3], SkScalar x, SkScalar* t) {
79909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return chopMonoQuadAt(pts[0].fX, pts[1].fX, pts[2].fX, x, t);
80909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
81909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
82909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com// Modify pts[] in place so that it is clipped in Y to the clip rect
83909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
84909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar t;
85909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPoint tmp[5]; // for SkChopQuadAt
86909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
87909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially above
88909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fY < clip.fTop) {
89909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoQuadAtY(pts, clip.fTop, &t)) {
90909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // take the 2nd chopped quad
91909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopQuadAt(pts, tmp, t);
92909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[2].fY, clip.fTop);
93909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[3].fY, clip.fTop);
94909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[0] = tmp[2];
95909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[3];
96909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
97909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
98909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the top
99909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int i = 0; i < 3; i++) {
100909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                if (pts[i].fY < clip.fTop) {
101909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                    pts[i].fY = clip.fTop;
102909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                }
103909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
104909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
105909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
106909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
107909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially below
108909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[2].fY > clip.fBottom) {
109909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoQuadAtY(pts, clip.fBottom, &t)) {
110909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopQuadAt(pts, tmp, t);
111909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[1].fY, clip.fBottom);
112909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[2].fY, clip.fBottom);
113909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[1];
114909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[2] = tmp[2];
115909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
116909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
117909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the bottom
118909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int i = 0; i < 3; i++) {
119909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                if (pts[i].fY > clip.fBottom) {
120909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                    pts[i].fY = clip.fBottom;
121909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                }
122909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
123909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
124909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
125909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
126909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
127909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com// srcPts[] must be monotonic in X and Y
128909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid SkEdgeClipper::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
129909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPoint pts[3];
130909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    bool reverse = sort_increasing_Y(pts, srcPts, 3);
131909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
132909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we completely above or below
133909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[2].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
134909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
135909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
136909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
137909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // Now chop so that pts is contained within clip in Y
138909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    chop_quad_in_Y(pts, clip);
139909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
140909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX > pts[2].fX) {
141909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkTSwap<SkPoint>(pts[0], pts[2]);
142909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        reverse = !reverse;
143909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
144909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkASSERT(pts[0].fX <= pts[1].fX);
145909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkASSERT(pts[1].fX <= pts[2].fX);
146909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
147909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // Now chop in X has needed, and record the segments
148909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
149909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[2].fX <= clip.fLeft) {  // wholly to the left
150909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
151909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
152909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
153909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX >= clip.fRight) {  // wholly to the right
154909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
155909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
156909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
157909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
158909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar t;
159909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPoint tmp[5]; // for SkChopQuadAt
160909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
161909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially to the left
162909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX < clip.fLeft) {
163909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoQuadAtX(pts, clip.fLeft, &t)) {
164909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopQuadAt(pts, tmp, t);
165909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse);
166909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[2].fX, clip.fLeft);
167909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[3].fX, clip.fLeft);
168909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[0] = tmp[2];
169909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[3];
170909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
171909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
172909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the left
173909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
174181172d5642fce4a4c1d339a6e3c5e4a8079b11areed@android.com            return;
175909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
176909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
177909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
178909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially to the right
179909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[2].fX > clip.fRight) {
180909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoQuadAtX(pts, clip.fRight, &t)) {
181909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopQuadAt(pts, tmp, t);
182909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[1].fX, clip.fRight);
183909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[2].fX, clip.fRight);
184909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendQuad(tmp, reverse);
185909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse);
186909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
187909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
188909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the right
189909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
190909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
191909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {    // wholly inside the clip
192909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        this->appendQuad(pts, reverse);
193909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
194909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
195909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
196909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.combool SkEdgeClipper::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
197909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint = fPoints;
198909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrVerb = fVerbs;
199909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
200909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkRect  bounds;
201909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    bounds.set(srcPts, 3);
202909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
203909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (!quick_reject(bounds, clip)) {
204909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkPoint monoY[5];
205909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        int countY = SkChopQuadAtYExtrema(srcPts, monoY);
206909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int y = 0; y <= countY; y++) {
207909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkPoint monoX[5];
208909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX);
209909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int x = 0; x <= countX; x++) {
210909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                this->clipMonoQuad(&monoX[x * 2], clip);
211909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
212909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
213909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
214909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
215909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
216909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
217909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *fCurrVerb = SkPath::kDone_Verb;
218909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint = fPoints;
219909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrVerb = fVerbs;
220909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return SkPath::kDone_Verb != fVerbs[0];
221909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
222909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
223909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com///////////////////////////////////////////////////////////////////////////////
224909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
225909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
226909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                                 SkScalar D, SkScalar t) {
227909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
228909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
229909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
230909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com/*  Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the
231909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    t value such that cubic(t) = target
232909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com */
233909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
234909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                           SkScalar target, SkScalar* t) {
235909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com //   SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3);
236909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkASSERT(c0 < target && target < c3);
237909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
238909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar D = c0;
239909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar A = c3 + 3*(c1 - c2) - c0;
240909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar B = 3*(c2 - c1 - c1 + c0);
241909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar C = 3*(c1 - c0);
242909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
243909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar minT = 0;
244909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar maxT = SK_Scalar1;
245909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    for (int i = 0; i < 8; i++) {
246909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkScalar mid = SkScalarAve(minT, maxT);
247909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkScalar coord = eval_cubic_coeff(A, B, C, D, mid);
248909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (coord < target) {
249909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            minT = mid;
250909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
251909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            maxT = mid;
252909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
253909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
254909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *t = SkScalarAve(minT, maxT);
255909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return true;
256909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
257909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
258909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool chopMonoCubicAtY(SkPoint pts[4], SkScalar y, SkScalar* t) {
259909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, t);
260909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
261909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
262909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic bool chopMonoCubicAtX(SkPoint pts[4], SkScalar x, SkScalar* t) {
263909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return chopMonoCubicAt(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, x, t);
264909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
265909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
266909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com// Modify pts[] in place so that it is clipped in Y to the clip rect
267909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
268909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar t;
269909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPoint tmp[7]; // for SkChopCubicAt
270909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
271909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially above
272909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fY < clip.fTop) {
273909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoCubicAtY(pts, clip.fTop, &t)) {
274909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopCubicAt(pts, tmp, t);
275909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[3].fY, clip.fTop);
276909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[4].fY, clip.fTop);
277909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[5].fY, clip.fTop);
278909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[0] = tmp[3];
279909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[4];
280909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[2] = tmp[5];
281909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
282909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoCubicAtY failed, then we may have hit inexact numerics
283909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the top
284909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int i = 0; i < 4; i++) {
285909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                clamp_ge(pts[i].fY, clip.fTop);
286909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
287909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
288909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
289909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
290909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially below
291909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[3].fY > clip.fBottom) {
292909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoCubicAtY(pts, clip.fBottom, &t)) {
293909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopCubicAt(pts, tmp, t);
294909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[1].fY, clip.fBottom);
295909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[2].fY, clip.fBottom);
296909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[3].fY, clip.fBottom);
297909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[1];
298909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[2] = tmp[2];
299909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[3] = tmp[3];
300909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
301909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoCubicAtY failed, then we may have hit inexact numerics
302909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the bottom
303909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int i = 0; i < 4; i++) {
304909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                clamp_le(pts[i].fY, clip.fBottom);
305909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
306909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
307909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
308909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
309909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
310909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com// srcPts[] must be monotonic in X and Y
311909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
312909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPoint pts[4];
313909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    bool reverse = sort_increasing_Y(pts, src, 4);
314909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
315909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we completely above or below
316909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[3].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
317909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
318909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
319909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
320909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // Now chop so that pts is contained within clip in Y
321909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    chop_cubic_in_Y(pts, clip);
322909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
323909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX > pts[3].fX) {
324909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkTSwap<SkPoint>(pts[0], pts[3]);
325909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkTSwap<SkPoint>(pts[1], pts[2]);
326909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        reverse = !reverse;
327909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
328909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
329909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // Now chop in X has needed, and record the segments
330909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
331909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[3].fX <= clip.fLeft) {  // wholly to the left
332909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
333909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
334909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
335909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX >= clip.fRight) {  // wholly to the right
336909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
337909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        return;
338909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
339909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
340909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkScalar t;
341909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPoint tmp[7];
342909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
343909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially to the left
344909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[0].fX < clip.fLeft) {
345909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoCubicAtX(pts, clip.fLeft, &t)) {
346909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopCubicAt(pts, tmp, t);
347909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
348909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[3].fX, clip.fLeft);
349909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[4].fX, clip.fLeft);
350909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_ge(tmp[5].fX, clip.fLeft);
351909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[0] = tmp[3];
352909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[1] = tmp[4];
353909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            pts[2] = tmp[5];
354909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
355909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonocubicAtY failed, then we may have hit inexact numerics
356909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the left
357909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
358181172d5642fce4a4c1d339a6e3c5e4a8079b11areed@android.com            return;
359909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
360909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
361909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
362909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    // are we partially to the right
363909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (pts[3].fX > clip.fRight) {
364909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        if (chopMonoCubicAtX(pts, clip.fRight, &t)) {
365909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkChopCubicAt(pts, tmp, t);
366909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[1].fX, clip.fRight);
367909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[2].fX, clip.fRight);
368909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            clamp_le(tmp[3].fX, clip.fRight);
369909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendCubic(tmp, reverse);
370909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
371909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        } else {
372909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // if chopMonoCubicAtX failed, then we may have hit inexact numerics
373909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            // so we just clamp against the right
374909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
375909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
376909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {    // wholly inside the clip
377909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        this->appendCubic(pts, reverse);
378909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
379909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
380909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
381909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.combool SkEdgeClipper::clipCubic(const SkPoint srcPts[4], const SkRect& clip) {
382909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint = fPoints;
383909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrVerb = fVerbs;
384909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
385909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkRect  bounds;
386909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    bounds.set(srcPts, 4);
387909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
388909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (!quick_reject(bounds, clip)) {
389909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkPoint monoY[10];
390909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        int countY = SkChopCubicAtYExtrema(srcPts, monoY);
391909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int y = 0; y <= countY; y++) {
392909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        //    sk_assert_monotonic_y(&monoY[y * 3], 4);
393909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkPoint monoX[10];
394909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX);
395909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            for (int x = 0; x <= countX; x++) {
396909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            //    sk_assert_monotonic_y(&monoX[x * 3], 4);
397909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            //    sk_assert_monotonic_x(&monoX[x * 3], 4);
398909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                this->clipMonoCubic(&monoX[x * 3], clip);
399909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
400909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
401909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            }
402909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
403909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
404909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
405909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *fCurrVerb = SkPath::kDone_Verb;
406909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint = fPoints;
407909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrVerb = fVerbs;
408909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return SkPath::kDone_Verb != fVerbs[0];
409909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
410909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
411909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com///////////////////////////////////////////////////////////////////////////////
412909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
413909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid SkEdgeClipper::appendVLine(SkScalar x, SkScalar y0, SkScalar y1,
414909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com                                bool reverse) {
415909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *fCurrVerb++ = SkPath::kLine_Verb;
416909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
417909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (reverse) {
418909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        SkTSwap<SkScalar>(y0, y1);
419909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
420909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint[0].set(x, y0);
421909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint[1].set(x, y1);
422909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint += 2;
423909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
424909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
425909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid SkEdgeClipper::appendQuad(const SkPoint pts[3], bool reverse) {
426909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *fCurrVerb++ = SkPath::kQuad_Verb;
427909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
428909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (reverse) {
429909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        fCurrPoint[0] = pts[2];
430909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        fCurrPoint[2] = pts[0];
431909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {
432909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        fCurrPoint[0] = pts[0];
433909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        fCurrPoint[2] = pts[2];
434909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
435909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint[1] = pts[1];
436909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint += 3;
437909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
438909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
439909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid SkEdgeClipper::appendCubic(const SkPoint pts[4], bool reverse) {
440909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    *fCurrVerb++ = SkPath::kCubic_Verb;
441909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
442909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (reverse) {
443909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int i = 0; i < 4; i++) {
444909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrPoint[i] = pts[3 - i];
445909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
446909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {
447909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        memcpy(fCurrPoint, pts, 4 * sizeof(SkPoint));
448909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
449909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    fCurrPoint += 4;
450909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
451909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
452909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comSkPath::Verb SkEdgeClipper::next(SkPoint pts[]) {
453909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    SkPath::Verb verb = *fCurrVerb;
454909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
455909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    switch (verb) {
456909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        case SkPath::kLine_Verb:
457909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            memcpy(pts, fCurrPoint, 2 * sizeof(SkPoint));
458909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrPoint += 2;
459909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrVerb += 1;
460909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            break;
461909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        case SkPath::kQuad_Verb:
462909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            memcpy(pts, fCurrPoint, 3 * sizeof(SkPoint));
463909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrPoint += 3;
464909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrVerb += 1;
465909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            break;
466909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        case SkPath::kCubic_Verb:
467909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            memcpy(pts, fCurrPoint, 4 * sizeof(SkPoint));
468909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrPoint += 4;
469909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            fCurrVerb += 1;
470909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            break;
471909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        case SkPath::kDone_Verb:
472909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            break;
473909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        default:
474909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkASSERT(!"unexpected verb in quadclippper2 iter");
475909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            break;
476909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
477909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    return verb;
478909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
479909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
480909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com///////////////////////////////////////////////////////////////////////////////
481909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
482909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com#ifdef SK_DEBUG
483909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comstatic void assert_monotonic(const SkScalar coord[], int count) {
484909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (coord[0] > coord[(count - 1) * 2]) {
485909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int i = 1; i < count; i++) {
486909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkASSERT(coord[2 * (i - 1)] >= coord[i * 2]);
487909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
488909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else if (coord[0] < coord[(count - 1) * 2]) {
489909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int i = 1; i < count; i++) {
490909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkASSERT(coord[2 * (i - 1)] <= coord[i * 2]);
491909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
492909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    } else {
493909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        for (int i = 1; i < count; i++) {
494909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com            SkASSERT(coord[2 * (i - 1)] == coord[i * 2]);
495909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        }
496909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
497909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
498909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
499909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid sk_assert_monotonic_y(const SkPoint pts[], int count) {
500909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (count > 1) {
501909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        assert_monotonic(&pts[0].fY, count);
502909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
503909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
504909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com
505909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.comvoid sk_assert_monotonic_x(const SkPoint pts[], int count) {
506909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    if (count > 1) {
507909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com        assert_monotonic(&pts[0].fX, count);
508909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com    }
509909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com}
510909994fbae0ffb532f42feac8859f8d86bbf64dereed@android.com#endif
511