1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.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.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com#include "SkLineClipper.h"
970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
10bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.comtemplate <typename T> T pin_unsorted(T value, T limit0, T limit1) {
11bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    if (limit1 < limit0) {
12bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com        SkTSwap(limit0, limit1);
13bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    }
14bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    // now the limits are sorted
15bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    SkASSERT(limit0 <= limit1);
16bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com
17bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    if (value < limit0) {
18bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com        value = limit0;
19bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    } else if (value > limit1) {
20bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com        value = limit1;
21bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    }
22bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    return value;
23bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com}
24bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com
2570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com// return X coordinate of intersection with horizontal line at Y
2670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.comstatic SkScalar sect_with_horizontal(const SkPoint src[2], SkScalar Y) {
2770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    SkScalar dy = src[1].fY - src[0].fY;
2870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    if (SkScalarNearlyZero(dy)) {
2970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        return SkScalarAve(src[0].fX, src[1].fX);
3070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    } else {
31160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        // need the extra precision so we don't compute a value that exceeds
32160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        // our original limits
33160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        double X0 = src[0].fX;
34160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        double Y0 = src[0].fY;
35160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        double X1 = src[1].fX;
36160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        double Y1 = src[1].fY;
37160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        double result = X0 + ((double)Y - Y0) * (X1 - X0) / (Y1 - Y0);
38fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
39bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com        // The computed X value might still exceed [X0..X1] due to quantum flux
40bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com        // when the doubles were added and subtracted, so we have to pin the
41bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com        // answer :(
42bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com        return (float)pin_unsorted(result, X0, X1);
4370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    }
4470149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com}
4570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
4670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com// return Y coordinate of intersection with vertical line at X
4770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.comstatic SkScalar sect_with_vertical(const SkPoint src[2], SkScalar X) {
4870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    SkScalar dx = src[1].fX - src[0].fX;
4970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    if (SkScalarNearlyZero(dx)) {
5070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        return SkScalarAve(src[0].fY, src[1].fY);
5170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    } else {
52160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        // need the extra precision so we don't compute a value that exceeds
53160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        // our original limits
54160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        double X0 = src[0].fX;
55160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        double Y0 = src[0].fY;
56160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        double X1 = src[1].fX;
57160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        double Y1 = src[1].fY;
58160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        double result = Y0 + ((double)X - X0) * (Y1 - Y0) / (X1 - X0);
59160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        return (float)result;
6070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    }
6170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com}
6270149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
63e28ff55d980d2992618b6b721c848aba96cf759areed@android.com///////////////////////////////////////////////////////////////////////////////
64e28ff55d980d2992618b6b721c848aba96cf759areed@android.com
65a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.comstatic inline bool nestedLT(SkScalar a, SkScalar b, SkScalar dim) {
66a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com    return a <= b && (a < b || dim > 0);
67a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com}
68a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com
69a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com// returns true if outer contains inner, even if inner is empty.
70a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com// note: outer.contains(inner) always returns false if inner is empty.
71a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.comstatic inline bool containsNoEmptyCheck(const SkRect& outer,
72a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com                                        const SkRect& inner) {
73a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com    return  outer.fLeft <= inner.fLeft && outer.fTop <= inner.fTop &&
74a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com            outer.fRight >= inner.fRight && outer.fBottom >= inner.fBottom;
75a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com}
76a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com
77e28ff55d980d2992618b6b721c848aba96cf759areed@android.combool SkLineClipper::IntersectLine(const SkPoint src[2], const SkRect& clip,
78e28ff55d980d2992618b6b721c848aba96cf759areed@android.com                                  SkPoint dst[2]) {
79e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    SkRect bounds;
80fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
81e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    bounds.set(src, 2);
82a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com    if (containsNoEmptyCheck(clip, bounds)) {
83e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        if (src != dst) {
84e28ff55d980d2992618b6b721c848aba96cf759areed@android.com            memcpy(dst, src, 2 * sizeof(SkPoint));
85e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        }
86e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        return true;
87e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    }
88a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com    // check for no overlap, and only permit coincident edges if the line
89a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com    // and the edge are colinear
90a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com    if (nestedLT(bounds.fRight, clip.fLeft, bounds.width()) ||
91a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com        nestedLT(clip.fRight, bounds.fLeft, bounds.width()) ||
92a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com        nestedLT(bounds.fBottom, clip.fTop, bounds.height()) ||
93a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com        nestedLT(clip.fBottom, bounds.fTop, bounds.height())) {
94a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com        return false;
95a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com    }
96e28ff55d980d2992618b6b721c848aba96cf759areed@android.com
97e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    int index0, index1;
98fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
99e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    if (src[0].fY < src[1].fY) {
100e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        index0 = 0;
101e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        index1 = 1;
102e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    } else {
103e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        index0 = 1;
104e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        index1 = 0;
105e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    }
106e28ff55d980d2992618b6b721c848aba96cf759areed@android.com
107e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    SkPoint tmp[2];
108e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    memcpy(tmp, src, sizeof(tmp));
109e28ff55d980d2992618b6b721c848aba96cf759areed@android.com
110e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    // now compute Y intersections
111e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    if (tmp[index0].fY < clip.fTop) {
112e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        tmp[index0].set(sect_with_horizontal(src, clip.fTop), clip.fTop);
113e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    }
114e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    if (tmp[index1].fY > clip.fBottom) {
115e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        tmp[index1].set(sect_with_horizontal(src, clip.fBottom), clip.fBottom);
116e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    }
117fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
118e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    if (tmp[0].fX < tmp[1].fX) {
119e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        index0 = 0;
120e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        index1 = 1;
121e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    } else {
122e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        index0 = 1;
123e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        index1 = 0;
124e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    }
125e28ff55d980d2992618b6b721c848aba96cf759areed@android.com
126e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    // check for quick-reject in X again, now that we may have been chopped
127a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com    if ((tmp[index1].fX <= clip.fLeft || tmp[index0].fX >= clip.fRight) &&
128a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com        tmp[index0].fX < tmp[index1].fX) {
129a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com        // only reject if we have a non-zero width
130e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        return false;
131e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    }
132e28ff55d980d2992618b6b721c848aba96cf759areed@android.com
133e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    if (tmp[index0].fX < clip.fLeft) {
134e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        tmp[index0].set(clip.fLeft, sect_with_vertical(src, clip.fLeft));
135e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    }
136e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    if (tmp[index1].fX > clip.fRight) {
137e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        tmp[index1].set(clip.fRight, sect_with_vertical(src, clip.fRight));
138e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    }
139a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com#ifdef SK_DEBUG
140a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com    bounds.set(tmp, 2);
141a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com    SkASSERT(containsNoEmptyCheck(clip, bounds));
142a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com#endif
143e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    memcpy(dst, tmp, sizeof(tmp));
144e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    return true;
145e28ff55d980d2992618b6b721c848aba96cf759areed@android.com}
146e28ff55d980d2992618b6b721c848aba96cf759areed@android.com
147160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com#ifdef SK_DEBUG
148160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com// return value between the two limits, where the limits are either ascending
149160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com// or descending.
150160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.comstatic bool is_between_unsorted(SkScalar value,
151160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com                                SkScalar limit0, SkScalar limit1) {
152160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com    if (limit0 < limit1) {
153160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        return limit0 <= value && value <= limit1;
154160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com    } else {
155160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        return limit1 <= value && value <= limit0;
156160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com    }
157160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com}
158160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com#endif
159160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com
1600e51577a14f903ffeafa117a75954baeb173ffb9humper@google.com#ifdef SK_DEBUG
161bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com// This is an example of why we need to pin the result computed in
162bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com// sect_with_horizontal. If we didn't explicitly pin, is_between_unsorted would
163bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com// fail.
164bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com//
165bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.comstatic void sect_with_horizontal_test_for_pin_results() {
166bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    const SkPoint pts[] = {
167fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        { -540000,    -720000 },
1684b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org        { -9.10000017e-05f, 9.99999996e-13f }
169bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    };
170bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    float x = sect_with_horizontal(pts, 0);
171bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    SkASSERT(is_between_unsorted(x, pts[0].fX, pts[1].fX));
172bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com}
173bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com#endif
174bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com
17570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.comint SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip,
17670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com                            SkPoint lines[]) {
177bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com#ifdef SK_DEBUG
178bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    {
179bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com        static bool gOnce;
180bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com        if (!gOnce) {
181bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com            sect_with_horizontal_test_for_pin_results();
182bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com            gOnce = true;
183bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com        }
184bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com    }
185bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com#endif
186bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com
18770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    int index0, index1;
18870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
18970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    if (pts[0].fY < pts[1].fY) {
19070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        index0 = 0;
19170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        index1 = 1;
19270149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    } else {
19370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        index0 = 1;
19470149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        index1 = 0;
19570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    }
19670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
19770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    // Check if we're completely clipped out in Y (above or below
19870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
19970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    if (pts[index1].fY <= clip.fTop) {  // we're above the clip
20070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        return 0;
20170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    }
20270149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    if (pts[index0].fY >= clip.fBottom) {  // we're below the clip
20370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        return 0;
20470149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    }
205fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
20670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    // Chop in Y to produce a single segment, stored in tmp[0..1]
20770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
20870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    SkPoint tmp[2];
20970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    memcpy(tmp, pts, sizeof(tmp));
21070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
21170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    // now compute intersections
21270149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    if (pts[index0].fY < clip.fTop) {
21370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        tmp[index0].set(sect_with_horizontal(pts, clip.fTop), clip.fTop);
214160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        SkASSERT(is_between_unsorted(tmp[index0].fX, pts[0].fX, pts[1].fX));
21570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    }
21670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    if (tmp[index1].fY > clip.fBottom) {
21770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        tmp[index1].set(sect_with_horizontal(pts, clip.fBottom), clip.fBottom);
218160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com        SkASSERT(is_between_unsorted(tmp[index1].fX, pts[0].fX, pts[1].fX));
21970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    }
22070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
22170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    // Chop it into 1..3 segments that are wholly within the clip in X.
22270149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
22370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    // temp storage for up to 3 segments
22470149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    SkPoint resultStorage[kMaxPoints];
22570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    SkPoint* result;    // points to our results, either tmp or resultStorage
22670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    int lineCount = 1;
227e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com    bool reverse;
22870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
22970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    if (pts[0].fX < pts[1].fX) {
23070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        index0 = 0;
23170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        index1 = 1;
232e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com        reverse = false;
23370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    } else {
23470149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        index0 = 1;
23570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        index1 = 0;
236e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com        reverse = true;
23770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    }
238e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com
23970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    if (tmp[index1].fX <= clip.fLeft) {  // wholly to the left
24070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        tmp[0].fX = tmp[1].fX = clip.fLeft;
24170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        result = tmp;
242e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com        reverse = false;
24370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    } else if (tmp[index0].fX >= clip.fRight) {    // wholly to the right
24470149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        tmp[0].fX = tmp[1].fX = clip.fRight;
24570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        result = tmp;
246e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com        reverse = false;
24770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    } else {
24870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        result = resultStorage;
24970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        SkPoint* r = result;
250fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
25170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        if (tmp[index0].fX < clip.fLeft) {
25270149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com            r->set(clip.fLeft, tmp[index0].fY);
25370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com            r += 1;
254160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com            r->set(clip.fLeft, sect_with_vertical(tmp, clip.fLeft));
255160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com            SkASSERT(is_between_unsorted(r->fY, tmp[0].fY, tmp[1].fY));
25670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        } else {
25770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com            *r = tmp[index0];
25870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        }
25970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        r += 1;
26070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
26170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        if (tmp[index1].fX > clip.fRight) {
262160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com            r->set(clip.fRight, sect_with_vertical(tmp, clip.fRight));
263160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com            SkASSERT(is_between_unsorted(r->fY, tmp[0].fY, tmp[1].fY));
26470149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com            r += 1;
26570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com            r->set(clip.fRight, tmp[index1].fY);
26670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        } else {
26770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com            *r = tmp[index1];
26870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        }
26970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
270a8c7f7702fb4bbedb615031bc653c5cd161a038ecommit-bot@chromium.org        lineCount = SkToInt(r - result);
27170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    }
27270149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com
27370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    // Now copy the results into the caller's lines[] parameter
274e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com    if (reverse) {
27570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        // copy the pts in reverse order to maintain winding order
27670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        for (int i = 0; i <= lineCount; i++) {
27770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com            lines[lineCount - i] = result[i];
27870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        }
27970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    } else {
28070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com        memcpy(lines, result, (lineCount + 1) * sizeof(SkPoint));
28170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    }
28270149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com    return lineCount;
28370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com}
284