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 13static inline void clamp_le(SkScalar& value, SkScalar max) { 14 if (value > max) { 15 value = max; 16 } 17} 18 19static inline void clamp_ge(SkScalar& value, SkScalar min) { 20 if (value < min) { 21 value = min; 22 } 23} 24 25SkQuadClipper::SkQuadClipper() {} 26 27void SkQuadClipper::setClip(const SkIRect& clip) { 28 // conver to scalars, since that's where we'll see the points 29 fClip.set(clip); 30} 31 32/////////////////////////////////////////////////////////////////////////////// 33 34static 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 SkScalar A = c0 - c1 - c1 + c2; 41 SkScalar B = 2*(c1 - c0); 42 SkScalar C = c0 - target; 43 44 SkScalar roots[2]; // we only expect one, but make room for 2 for safety 45 int count = SkFindUnitQuadRoots(A, B, C, roots); 46 if (count) { 47 *t = roots[0]; 48 return true; 49 } 50 return false; 51} 52 53static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) { 54 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 */ 63bool 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 if (srcPts[0].fY > srcPts[2].fY) { 68 dst[0] = srcPts[2]; 69 dst[1] = srcPts[1]; 70 dst[2] = srcPts[0]; 71 reverse = true; 72 } else { 73 memcpy(dst, srcPts, 3 * sizeof(SkPoint)); 74 reverse = false; 75 } 76 77 // are we completely above or below 78 const SkScalar ctop = fClip.fTop; 79 const SkScalar cbot = fClip.fBottom; 80 if (dst[2].fY <= ctop || dst[0].fY >= cbot) { 81 return false; 82 } 83 84 SkScalar t; 85 SkPoint tmp[5]; // for SkChopQuadAt 86 87 // are we partially above 88 if (dst[0].fY < ctop) { 89 if (chopMonoQuadAtY(dst, ctop, &t)) { 90 // take the 2nd chopped quad 91 SkChopQuadAt(dst, tmp, t); 92 dst[0] = tmp[2]; 93 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 for (int i = 0; i < 3; i++) { 98 if (dst[i].fY < ctop) { 99 dst[i].fY = ctop; 100 } 101 } 102 } 103 } 104 105 // are we partially below 106 if (dst[2].fY > cbot) { 107 if (chopMonoQuadAtY(dst, cbot, &t)) { 108 SkChopQuadAt(dst, tmp, t); 109 dst[1] = tmp[1]; 110 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 for (int i = 0; i < 3; i++) { 115 if (dst[i].fY > cbot) { 116 dst[i].fY = cbot; 117 } 118 } 119 } 120 } 121 122 if (reverse) { 123 SkTSwap<SkPoint>(dst[0], dst[2]); 124 } 125 return true; 126} 127 128