blob: fcde929ea7e544685a18a776f59e9f44b919e5ca [file] [log] [blame]
reed@android.comc07d23a2009-02-06 13:30:58 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2009 The Android Open Source Project
reed@android.comc07d23a2009-02-06 13:30:58 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.comc07d23a2009-02-06 13:30:58 +00006 */
7
8#include "SkQuadClipper.h"
9#include "SkGeometry.h"
10
vandebo@chromium.orga728e352012-03-28 20:29:38 +000011SkQuadClipper::SkQuadClipper() {
12 fClip.setEmpty();
13}
reed@android.combb135862009-11-18 13:47:40 +000014
15void 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
reed@android.com77f0ef72009-11-17 18:47:52 +000022static bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2,
23 SkScalar target, SkScalar* t) {
reed@android.comc07d23a2009-02-06 13:30:58 +000024 /* 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 */
reed@android.com77f0ef72009-11-17 18:47:52 +000028 SkScalar A = c0 - c1 - c1 + c2;
29 SkScalar B = 2*(c1 - c0);
30 SkScalar C = c0 - target;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000031
reed@android.comc07d23a2009-02-06 13:30:58 +000032 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
reed@android.com77f0ef72009-11-17 18:47:52 +000041static 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
reed@android.com3a0cd7f2009-11-17 19:39:51 +000045///////////////////////////////////////////////////////////////////////////////
46
reed@android.combb135862009-11-18 13:47:40 +000047/* 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 */
51bool SkQuadClipper::clipQuad(const SkPoint srcPts[3], SkPoint dst[3]) {
52 bool reverse;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000053
reed@android.combb135862009-11-18 13:47:40 +000054 // 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 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000064
reed@android.combb135862009-11-18 13:47:40 +000065 // 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 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000071
reed@android.combb135862009-11-18 13:47:40 +000072 SkScalar t;
73 SkPoint tmp[5]; // for SkChopQuadAt
rmistry@google.comfbfcd562012-08-23 18:09:54 +000074
reed@android.combb135862009-11-18 13:47:40 +000075 // 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 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000092
reed@android.combb135862009-11-18 13:47:40 +000093 // 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 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000109
reed@android.combb135862009-11-18 13:47:40 +0000110 if (reverse) {
111 SkTSwap<SkPoint>(dst[0], dst[2]);
112 }
113 return true;
114}