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