1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2009 The Android Open Source Project
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h"
9cb93a386Sopenharmony_ci#include "src/core/SkQuadClipper.h"
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include <utility>
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_ciSkQuadClipper::SkQuadClipper() {
14cb93a386Sopenharmony_ci    fClip.setEmpty();
15cb93a386Sopenharmony_ci}
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_civoid SkQuadClipper::setClip(const SkIRect& clip) {
18cb93a386Sopenharmony_ci    // conver to scalars, since that's where we'll see the points
19cb93a386Sopenharmony_ci    fClip.set(clip);
20cb93a386Sopenharmony_ci}
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cistatic bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2,
25cb93a386Sopenharmony_ci                           SkScalar target, SkScalar* t) {
26cb93a386Sopenharmony_ci    /* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2
27cb93a386Sopenharmony_ci     *  We solve for t, using quadratic equation, hence we have to rearrange
28cb93a386Sopenharmony_ci     * our cooefficents to look like At^2 + Bt + C
29cb93a386Sopenharmony_ci     */
30cb93a386Sopenharmony_ci    SkScalar A = c0 - c1 - c1 + c2;
31cb93a386Sopenharmony_ci    SkScalar B = 2*(c1 - c0);
32cb93a386Sopenharmony_ci    SkScalar C = c0 - target;
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci    SkScalar roots[2];  // we only expect one, but make room for 2 for safety
35cb93a386Sopenharmony_ci    int count = SkFindUnitQuadRoots(A, B, C, roots);
36cb93a386Sopenharmony_ci    if (count) {
37cb93a386Sopenharmony_ci        *t = roots[0];
38cb93a386Sopenharmony_ci        return true;
39cb93a386Sopenharmony_ci    }
40cb93a386Sopenharmony_ci    return false;
41cb93a386Sopenharmony_ci}
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_cistatic bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
44cb93a386Sopenharmony_ci    return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
45cb93a386Sopenharmony_ci}
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci/*  If we somehow returned the fact that we had to flip the pts in Y, we could
50cb93a386Sopenharmony_ci communicate that to setQuadratic, and then avoid having to flip it back
51cb93a386Sopenharmony_ci here (only to have setQuadratic do the flip again)
52cb93a386Sopenharmony_ci */
53cb93a386Sopenharmony_cibool SkQuadClipper::clipQuad(const SkPoint srcPts[3], SkPoint dst[3]) {
54cb93a386Sopenharmony_ci    bool reverse;
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci    // we need the data to be monotonically increasing in Y
57cb93a386Sopenharmony_ci    if (srcPts[0].fY > srcPts[2].fY) {
58cb93a386Sopenharmony_ci        dst[0] = srcPts[2];
59cb93a386Sopenharmony_ci        dst[1] = srcPts[1];
60cb93a386Sopenharmony_ci        dst[2] = srcPts[0];
61cb93a386Sopenharmony_ci        reverse = true;
62cb93a386Sopenharmony_ci    } else {
63cb93a386Sopenharmony_ci        memcpy(dst, srcPts, 3 * sizeof(SkPoint));
64cb93a386Sopenharmony_ci        reverse = false;
65cb93a386Sopenharmony_ci    }
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ci    // are we completely above or below
68cb93a386Sopenharmony_ci    const SkScalar ctop = fClip.fTop;
69cb93a386Sopenharmony_ci    const SkScalar cbot = fClip.fBottom;
70cb93a386Sopenharmony_ci    if (dst[2].fY <= ctop || dst[0].fY >= cbot) {
71cb93a386Sopenharmony_ci        return false;
72cb93a386Sopenharmony_ci    }
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci    SkScalar t;
75cb93a386Sopenharmony_ci    SkPoint tmp[5]; // for SkChopQuadAt
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_ci    // are we partially above
78cb93a386Sopenharmony_ci    if (dst[0].fY < ctop) {
79cb93a386Sopenharmony_ci        if (chopMonoQuadAtY(dst, ctop, &t)) {
80cb93a386Sopenharmony_ci            // take the 2nd chopped quad
81cb93a386Sopenharmony_ci            SkChopQuadAt(dst, tmp, t);
82cb93a386Sopenharmony_ci            dst[0] = tmp[2];
83cb93a386Sopenharmony_ci            dst[1] = tmp[3];
84cb93a386Sopenharmony_ci        } else {
85cb93a386Sopenharmony_ci            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
86cb93a386Sopenharmony_ci            // so we just clamp against the top
87cb93a386Sopenharmony_ci            for (int i = 0; i < 3; i++) {
88cb93a386Sopenharmony_ci                if (dst[i].fY < ctop) {
89cb93a386Sopenharmony_ci                    dst[i].fY = ctop;
90cb93a386Sopenharmony_ci                }
91cb93a386Sopenharmony_ci            }
92cb93a386Sopenharmony_ci        }
93cb93a386Sopenharmony_ci    }
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci    // are we partially below
96cb93a386Sopenharmony_ci    if (dst[2].fY > cbot) {
97cb93a386Sopenharmony_ci        if (chopMonoQuadAtY(dst, cbot, &t)) {
98cb93a386Sopenharmony_ci            SkChopQuadAt(dst, tmp, t);
99cb93a386Sopenharmony_ci            dst[1] = tmp[1];
100cb93a386Sopenharmony_ci            dst[2] = tmp[2];
101cb93a386Sopenharmony_ci        } else {
102cb93a386Sopenharmony_ci            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
103cb93a386Sopenharmony_ci            // so we just clamp against the bottom
104cb93a386Sopenharmony_ci            for (int i = 0; i < 3; i++) {
105cb93a386Sopenharmony_ci                if (dst[i].fY > cbot) {
106cb93a386Sopenharmony_ci                    dst[i].fY = cbot;
107cb93a386Sopenharmony_ci                }
108cb93a386Sopenharmony_ci            }
109cb93a386Sopenharmony_ci        }
110cb93a386Sopenharmony_ci    }
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci    if (reverse) {
113cb93a386Sopenharmony_ci        using std::swap;
114cb93a386Sopenharmony_ci        swap(dst[0], dst[2]);
115cb93a386Sopenharmony_ci    }
116cb93a386Sopenharmony_ci    return true;
117cb93a386Sopenharmony_ci}
118