aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/cubicpaths.cpp53
-rw-r--r--src/core/SkEdgeClipper.cpp73
2 files changed, 98 insertions, 28 deletions
diff --git a/gm/cubicpaths.cpp b/gm/cubicpaths.cpp
index 74fbe8d58b..ca6c057ec0 100644
--- a/gm/cubicpaths.cpp
+++ b/gm/cubicpaths.cpp
@@ -53,6 +53,58 @@ private:
typedef skiagm::GM INHERITED;
};
+
+class ClippedCubic2GM : public skiagm::GM {
+public:
+ ClippedCubic2GM() {}
+
+protected:
+
+ SkString onShortName() {
+ return SkString("clippedcubic2");
+ }
+
+ SkISize onISize() { return SkISize::Make(1240, 390); }
+
+ void onDraw(SkCanvas* canvas) override {
+ canvas->save();
+ canvas->translate(-2, 20);
+ drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 150));
+ canvas->translate(0, 170);
+ drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 100));
+ canvas->translate(0, 170);
+ drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 30, 150));
+ canvas->translate(0, 170);
+ drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 10, 150));
+ canvas->restore();
+ }
+
+ void drawOne(SkCanvas* canvas, const SkPath& path, const SkRect& clip) {
+ SkPaint framePaint, fillPaint;
+ framePaint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawRect(clip, framePaint);
+ canvas->drawPath(path, framePaint);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, fillPaint);
+ canvas->restore();
+ }
+
+ void onOnceBeforeDraw() override {
+ fPath.moveTo(69.7030518991886f, 0);
+ fPath.cubicTo( 69.7030518991886f, 21.831149999999997f,
+ 58.08369508178456f, 43.66448333333333f, 34.8449814469765f, 65.5f);
+ fPath.cubicTo( 11.608591683531916f, 87.33115f, -0.010765133872116195f, 109.16448333333332f,
+ -0.013089005235602302f, 131);
+ fPath.close();
+ }
+
+ SkPath fPath;
+private:
+ typedef skiagm::GM INHERITED;
+};
+
+
class CubicPathGM : public skiagm::GM {
public:
CubicPathGM() {}
@@ -347,3 +399,4 @@ private:
DEF_GM( return new CubicPathGM; )
DEF_GM( return new CubicClosePathGM; )
DEF_GM( return new ClippedCubicGM; )
+DEF_GM( return new ClippedCubic2GM; )
diff --git a/src/core/SkEdgeClipper.cpp b/src/core/SkEdgeClipper.cpp
index 96fac6121f..02fb4530fd 100644
--- a/src/core/SkEdgeClipper.cpp
+++ b/src/core/SkEdgeClipper.cpp
@@ -270,6 +270,34 @@ static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
}
}
+static void chop_mono_cubic_at_x(SkPoint pts[4], SkScalar x, SkPoint tmp[7]) {
+ if (SkChopMonoCubicAtX(pts, x, tmp)) {
+ return;
+ }
+ 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);
+ x -= D;
+ SkScalar closest = SK_ScalarMax;
+ do {
+ SkScalar loc = ((A * t + B) * t + C) * t;
+ SkScalar dist = SkScalarAbs(loc - x);
+ if (closest > dist) {
+ closest = dist;
+ bestT = t;
+ }
+ lastT = t;
+ t += loc < x ? step : -step;
+ step *= 0.5f;
+ } while (closest > 0.25f && lastT != t);
+ SkChopCubicAt(pts, tmp, bestT);
+}
+
// srcPts[] must be monotonic in X and Y
void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
SkPoint pts[4];
@@ -305,40 +333,29 @@ void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
// are we partially to the left
if (pts[0].fX < clip.fLeft) {
SkPoint tmp[7];
- if (SkChopMonoCubicAtX(pts, clip.fLeft, tmp)) {
- this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
-
- // tmp[3, 4].fX should all be to the right of clip.fLeft.
- // Since we can't trust the numerics of
- // the chopper, we force those conditions now
- tmp[3].fX = clip.fLeft;
- clamp_ge(tmp[4].fX, clip.fLeft);
-
- 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 left
- this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
- return;
- }
+ chop_mono_cubic_at_x(pts, clip.fLeft, tmp);
+ this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
+
+ // tmp[3, 4].fX should all be to the right of clip.fLeft.
+ // Since we can't trust the numerics of
+ // the chopper, we force those conditions now
+ tmp[3].fX = clip.fLeft;
+ clamp_ge(tmp[4].fX, clip.fLeft);
+
+ pts[0] = tmp[3];
+ pts[1] = tmp[4];
+ pts[2] = tmp[5];
}
// are we partially to the right
if (pts[3].fX > clip.fRight) {
SkPoint tmp[7];
- if (SkChopMonoCubicAtX(pts, clip.fRight, tmp)) {
- tmp[3].fX = clip.fRight;
- clamp_le(tmp[2].fX, clip.fRight);
+ chop_mono_cubic_at_x(pts, clip.fRight, tmp);
+ tmp[3].fX = clip.fRight;
+ clamp_le(tmp[2].fX, clip.fRight);
- this->appendCubic(tmp, reverse);
- this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
- } else {
- // if chopMonoCubicAtX failed, then we may have hit inexact numerics
- // so we just clamp against the right
- this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
- }
+ this->appendCubic(tmp, reverse);
+ this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
} else { // wholly inside the clip
this->appendCubic(pts, reverse);
}