Home | History | Annotate | Download | only in core
      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