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