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