1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2009 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 9cb93a386Sopenharmony_ci#include "src/core/SkQuadClipper.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include <utility> 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ciSkQuadClipper::SkQuadClipper() { 14cb93a386Sopenharmony_ci fClip.setEmpty(); 15cb93a386Sopenharmony_ci} 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_civoid SkQuadClipper::setClip(const SkIRect& clip) { 18cb93a386Sopenharmony_ci // conver to scalars, since that's where we'll see the points 19cb93a386Sopenharmony_ci fClip.set(clip); 20cb93a386Sopenharmony_ci} 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_cistatic bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2, 25cb93a386Sopenharmony_ci SkScalar target, SkScalar* t) { 26cb93a386Sopenharmony_ci /* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2 27cb93a386Sopenharmony_ci * We solve for t, using quadratic equation, hence we have to rearrange 28cb93a386Sopenharmony_ci * our cooefficents to look like At^2 + Bt + C 29cb93a386Sopenharmony_ci */ 30cb93a386Sopenharmony_ci SkScalar A = c0 - c1 - c1 + c2; 31cb93a386Sopenharmony_ci SkScalar B = 2*(c1 - c0); 32cb93a386Sopenharmony_ci SkScalar C = c0 - target; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci SkScalar roots[2]; // we only expect one, but make room for 2 for safety 35cb93a386Sopenharmony_ci int count = SkFindUnitQuadRoots(A, B, C, roots); 36cb93a386Sopenharmony_ci if (count) { 37cb93a386Sopenharmony_ci *t = roots[0]; 38cb93a386Sopenharmony_ci return true; 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci return false; 41cb93a386Sopenharmony_ci} 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_cistatic bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) { 44cb93a386Sopenharmony_ci return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t); 45cb93a386Sopenharmony_ci} 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci/* If we somehow returned the fact that we had to flip the pts in Y, we could 50cb93a386Sopenharmony_ci communicate that to setQuadratic, and then avoid having to flip it back 51cb93a386Sopenharmony_ci here (only to have setQuadratic do the flip again) 52cb93a386Sopenharmony_ci */ 53cb93a386Sopenharmony_cibool SkQuadClipper::clipQuad(const SkPoint srcPts[3], SkPoint dst[3]) { 54cb93a386Sopenharmony_ci bool reverse; 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci // we need the data to be monotonically increasing in Y 57cb93a386Sopenharmony_ci if (srcPts[0].fY > srcPts[2].fY) { 58cb93a386Sopenharmony_ci dst[0] = srcPts[2]; 59cb93a386Sopenharmony_ci dst[1] = srcPts[1]; 60cb93a386Sopenharmony_ci dst[2] = srcPts[0]; 61cb93a386Sopenharmony_ci reverse = true; 62cb93a386Sopenharmony_ci } else { 63cb93a386Sopenharmony_ci memcpy(dst, srcPts, 3 * sizeof(SkPoint)); 64cb93a386Sopenharmony_ci reverse = false; 65cb93a386Sopenharmony_ci } 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci // are we completely above or below 68cb93a386Sopenharmony_ci const SkScalar ctop = fClip.fTop; 69cb93a386Sopenharmony_ci const SkScalar cbot = fClip.fBottom; 70cb93a386Sopenharmony_ci if (dst[2].fY <= ctop || dst[0].fY >= cbot) { 71cb93a386Sopenharmony_ci return false; 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci SkScalar t; 75cb93a386Sopenharmony_ci SkPoint tmp[5]; // for SkChopQuadAt 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci // are we partially above 78cb93a386Sopenharmony_ci if (dst[0].fY < ctop) { 79cb93a386Sopenharmony_ci if (chopMonoQuadAtY(dst, ctop, &t)) { 80cb93a386Sopenharmony_ci // take the 2nd chopped quad 81cb93a386Sopenharmony_ci SkChopQuadAt(dst, tmp, t); 82cb93a386Sopenharmony_ci dst[0] = tmp[2]; 83cb93a386Sopenharmony_ci dst[1] = tmp[3]; 84cb93a386Sopenharmony_ci } else { 85cb93a386Sopenharmony_ci // if chopMonoQuadAtY failed, then we may have hit inexact numerics 86cb93a386Sopenharmony_ci // so we just clamp against the top 87cb93a386Sopenharmony_ci for (int i = 0; i < 3; i++) { 88cb93a386Sopenharmony_ci if (dst[i].fY < ctop) { 89cb93a386Sopenharmony_ci dst[i].fY = ctop; 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci } 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ci // are we partially below 96cb93a386Sopenharmony_ci if (dst[2].fY > cbot) { 97cb93a386Sopenharmony_ci if (chopMonoQuadAtY(dst, cbot, &t)) { 98cb93a386Sopenharmony_ci SkChopQuadAt(dst, tmp, t); 99cb93a386Sopenharmony_ci dst[1] = tmp[1]; 100cb93a386Sopenharmony_ci dst[2] = tmp[2]; 101cb93a386Sopenharmony_ci } else { 102cb93a386Sopenharmony_ci // if chopMonoQuadAtY failed, then we may have hit inexact numerics 103cb93a386Sopenharmony_ci // so we just clamp against the bottom 104cb93a386Sopenharmony_ci for (int i = 0; i < 3; i++) { 105cb93a386Sopenharmony_ci if (dst[i].fY > cbot) { 106cb93a386Sopenharmony_ci dst[i].fY = cbot; 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci } 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci if (reverse) { 113cb93a386Sopenharmony_ci using std::swap; 114cb93a386Sopenharmony_ci swap(dst[0], dst[2]); 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci return true; 117cb93a386Sopenharmony_ci} 118