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