• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
clamp_le(SkScalar & value,SkScalar max)13 static inline void clamp_le(SkScalar& value, SkScalar max) {
14     if (value > max) {
15         value = max;
16     }
17 }
18 
clamp_ge(SkScalar & value,SkScalar min)19 static inline void clamp_ge(SkScalar& value, SkScalar min) {
20     if (value < min) {
21         value = min;
22     }
23 }
24 
SkQuadClipper()25 SkQuadClipper::SkQuadClipper() {}
26 
setClip(const SkIRect & clip)27 void 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 
chopMonoQuadAt(SkScalar c0,SkScalar c1,SkScalar c2,SkScalar target,SkScalar * t)34 static 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 
chopMonoQuadAtY(SkPoint pts[3],SkScalar y,SkScalar * t)53 static 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  */
clipQuad(const SkPoint srcPts[3],SkPoint dst[3])63 bool 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