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