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