Line data Source code
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 0 : SkQuadClipper::SkQuadClipper() {
12 0 : fClip.setEmpty();
13 0 : }
14 :
15 0 : void SkQuadClipper::setClip(const SkIRect& clip) {
16 : // conver to scalars, since that's where we'll see the points
17 0 : fClip.set(clip);
18 0 : }
19 :
20 : ///////////////////////////////////////////////////////////////////////////////
21 :
22 0 : 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 0 : SkScalar A = c0 - c1 - c1 + c2;
29 0 : SkScalar B = 2*(c1 - c0);
30 0 : SkScalar C = c0 - target;
31 :
32 : SkScalar roots[2]; // we only expect one, but make room for 2 for safety
33 0 : int count = SkFindUnitQuadRoots(A, B, C, roots);
34 0 : if (count) {
35 0 : *t = roots[0];
36 0 : return true;
37 : }
38 0 : return false;
39 : }
40 :
41 0 : static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
42 0 : 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 0 : 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 0 : if (srcPts[0].fY > srcPts[2].fY) {
56 0 : dst[0] = srcPts[2];
57 0 : dst[1] = srcPts[1];
58 0 : dst[2] = srcPts[0];
59 0 : reverse = true;
60 : } else {
61 0 : memcpy(dst, srcPts, 3 * sizeof(SkPoint));
62 0 : reverse = false;
63 : }
64 :
65 : // are we completely above or below
66 0 : const SkScalar ctop = fClip.fTop;
67 0 : const SkScalar cbot = fClip.fBottom;
68 0 : if (dst[2].fY <= ctop || dst[0].fY >= cbot) {
69 0 : return false;
70 : }
71 :
72 : SkScalar t;
73 : SkPoint tmp[5]; // for SkChopQuadAt
74 :
75 : // are we partially above
76 0 : if (dst[0].fY < ctop) {
77 0 : if (chopMonoQuadAtY(dst, ctop, &t)) {
78 : // take the 2nd chopped quad
79 0 : SkChopQuadAt(dst, tmp, t);
80 0 : dst[0] = tmp[2];
81 0 : 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 0 : for (int i = 0; i < 3; i++) {
86 0 : if (dst[i].fY < ctop) {
87 0 : dst[i].fY = ctop;
88 : }
89 : }
90 : }
91 : }
92 :
93 : // are we partially below
94 0 : if (dst[2].fY > cbot) {
95 0 : if (chopMonoQuadAtY(dst, cbot, &t)) {
96 0 : SkChopQuadAt(dst, tmp, t);
97 0 : dst[1] = tmp[1];
98 0 : 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 0 : for (int i = 0; i < 3; i++) {
103 0 : if (dst[i].fY > cbot) {
104 0 : dst[i].fY = cbot;
105 : }
106 : }
107 : }
108 : }
109 :
110 0 : if (reverse) {
111 0 : SkTSwap<SkPoint>(dst[0], dst[2]);
112 : }
113 0 : return true;
114 : }
|