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