aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkEdgeClipper.cpp
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2015-08-20 10:35:43 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-08-20 10:35:43 -0700
commit05424f77fa8812b6c9e3a21def954e2c8971886a (patch)
treeddba02337940f4a66e54bfc64e2373feb27506db /src/core/SkEdgeClipper.cpp
parent63926683c583e8497d9d907977e773663cb4bd9e (diff)
fix cubic clip in y
Follow on to https://codereview.chromium.org/1299243002/ Clip using a geometric solution if the algebraic solution fails in Y as well as in X. If the root finder discovers real roots that are sufficiently far apart, the root in the range of 0..1 can contain so much error that it is computed to be slightly smaller than 0 or larger than 1. In this case, binary search the mono curve for the actual answer. R=reed@google.com Review URL: https://codereview.chromium.org/1303873003
Diffstat (limited to 'src/core/SkEdgeClipper.cpp')
-rw-r--r--src/core/SkEdgeClipper.cpp105
1 files changed, 51 insertions, 54 deletions
diff --git a/src/core/SkEdgeClipper.cpp b/src/core/SkEdgeClipper.cpp
index 02fb4530fd..c6a4fb2971 100644
--- a/src/core/SkEdgeClipper.cpp
+++ b/src/core/SkEdgeClipper.cpp
@@ -225,63 +225,15 @@ bool SkEdgeClipper::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
///////////////////////////////////////////////////////////////////////////////
-// Modify pts[] in place so that it is clipped in Y to the clip rect
-static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
-
- // are we partially above
- if (pts[0].fY < clip.fTop) {
- SkPoint tmp[7];
- if (SkChopMonoCubicAtY(pts, clip.fTop, tmp)) {
- // tmp[3, 4].fY should all be to the below clip.fTop.
- // Since we can't trust the numerics of
- // the chopper, we force those conditions now
- tmp[3].fY = clip.fTop;
- clamp_ge(tmp[4].fY, clip.fTop);
-
- pts[0] = tmp[3];
- pts[1] = tmp[4];
- pts[2] = tmp[5];
- } else {
- // if chopMonoCubicAtY failed, then we may have hit inexact numerics
- // so we just clamp against the top
- for (int i = 0; i < 4; i++) {
- clamp_ge(pts[i].fY, clip.fTop);
- }
- }
- }
-
- // are we partially below
- if (pts[3].fY > clip.fBottom) {
- SkPoint tmp[7];
- if (SkChopMonoCubicAtY(pts, clip.fBottom, tmp)) {
- tmp[3].fY = clip.fBottom;
- clamp_le(tmp[2].fY, clip.fBottom);
-
- pts[1] = tmp[1];
- pts[2] = tmp[2];
- pts[3] = tmp[3];
- } else {
- // if chopMonoCubicAtY failed, then we may have hit inexact numerics
- // so we just clamp against the bottom
- for (int i = 0; i < 4; i++) {
- clamp_le(pts[i].fY, clip.fBottom);
- }
- }
- }
-}
-
-static void chop_mono_cubic_at_x(SkPoint pts[4], SkScalar x, SkPoint tmp[7]) {
- if (SkChopMonoCubicAtX(pts, x, tmp)) {
- return;
- }
+static SkScalar mono_cubic_closestT(const SkScalar src[], SkScalar x) {
SkScalar t = 0.5f;
SkScalar lastT;
SkScalar bestT SK_INIT_TO_AVOID_WARNING;
SkScalar step = 0.25f;
- SkScalar D = pts[0].fX;
- SkScalar A = pts[3].fX + 3*(pts[1].fX - pts[2].fX) - D;
- SkScalar B = 3*(pts[2].fX - pts[1].fX - pts[1].fX + D);
- SkScalar C = 3*(pts[1].fX - D);
+ SkScalar D = src[0];
+ SkScalar A = src[6] + 3*(src[2] - src[4]) - D;
+ SkScalar B = 3*(src[4] - src[2] - src[2] + D);
+ SkScalar C = 3*(src[2] - D);
x -= D;
SkScalar closest = SK_ScalarMax;
do {
@@ -295,7 +247,52 @@ static void chop_mono_cubic_at_x(SkPoint pts[4], SkScalar x, SkPoint tmp[7]) {
t += loc < x ? step : -step;
step *= 0.5f;
} while (closest > 0.25f && lastT != t);
- SkChopCubicAt(pts, tmp, bestT);
+ return bestT;
+}
+
+static void chop_mono_cubic_at_y(SkPoint src[4], SkScalar y, SkPoint dst[7]) {
+ if (SkChopMonoCubicAtY(src, y, dst)) {
+ return;
+ }
+ SkChopCubicAt(src, dst, mono_cubic_closestT(&src->fY, y));
+}
+
+// Modify pts[] in place so that it is clipped in Y to the clip rect
+static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
+
+ // are we partially above
+ if (pts[0].fY < clip.fTop) {
+ SkPoint tmp[7];
+ chop_mono_cubic_at_y(pts, clip.fTop, tmp);
+ // tmp[3, 4].fY should all be to the below clip.fTop.
+ // Since we can't trust the numerics of
+ // the chopper, we force those conditions now
+ tmp[3].fY = clip.fTop;
+ clamp_ge(tmp[4].fY, clip.fTop);
+
+ pts[0] = tmp[3];
+ pts[1] = tmp[4];
+ pts[2] = tmp[5];
+ }
+
+ // are we partially below
+ if (pts[3].fY > clip.fBottom) {
+ SkPoint tmp[7];
+ chop_mono_cubic_at_y(pts, clip.fBottom, tmp);
+ tmp[3].fY = clip.fBottom;
+ clamp_le(tmp[2].fY, clip.fBottom);
+
+ pts[1] = tmp[1];
+ pts[2] = tmp[2];
+ pts[3] = tmp[3];
+ }
+}
+
+static void chop_mono_cubic_at_x(SkPoint src[4], SkScalar x, SkPoint dst[7]) {
+ if (SkChopMonoCubicAtX(src, x, dst)) {
+ return;
+ }
+ SkChopCubicAt(src, dst, mono_cubic_closestT(&src->fX, x));
}
// srcPts[] must be monotonic in X and Y