diff options
-rw-r--r-- | gm/cubicpaths.cpp | 53 | ||||
-rw-r--r-- | src/core/SkEdgeClipper.cpp | 73 |
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); } |