From 9e779d495130009926fc5394a8971eec20494e5f Mon Sep 17 00:00:00 2001 From: reed Date: Tue, 17 Feb 2015 11:43:14 -0800 Subject: [PATCH] add gm for path-arcs, and catch degenerate arc in conic-case BUG=skia:3428 Review URL: https://codereview.chromium.org/931183002 --- gm/addarc.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/core/SkPath.h | 2 -- src/core/SkPath.cpp | 18 +++++++++++--- 3 files changed, 84 insertions(+), 5 deletions(-) diff --git a/gm/addarc.cpp b/gm/addarc.cpp index 67d752a..8bdbca3 100644 --- a/gm/addarc.cpp +++ b/gm/addarc.cpp @@ -162,3 +162,72 @@ private: typedef skiagm::GM INHERITED; }; DEF_GM( return new StrokeCircleGM; ) + +////////////////////// + +static void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start, + SkScalar end, bool ccw) { + SkRect bounds = { x - r, y - r, x + r, y + r }; + SkScalar sweep = ccw ? end - start : start - end; + path->arcTo(bounds, start, sweep, false); +} + +// Lifted from canvas-arc-circumference-fill-diffs.html +class ManyArcsGM : public skiagm::GM { +public: + ManyArcsGM() {} + +protected: + SkString onShortName() SK_OVERRIDE { return SkString("manyarcs"); } + + SkISize onISize() SK_OVERRIDE { return SkISize::Make(620, 330); } + + void onDraw(SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + + canvas->translate(10, 10); + + // 20 angles. + SkScalar sweepAngles[] = { + -123.7f, -2.3f, -2, -1, -0.3f, -0.000001f, 0, 0.000001f, 0.3f, 0.7f, + 1, 1.3f, 1.5f, 1.7f, 1.99999f, 2, 2.00001f, 2.3f, 4.3f, 3934723942837.3f + }; + for (size_t i = 0; i < SK_ARRAY_COUNT(sweepAngles); ++i) { + sweepAngles[i] *= 180; + } + + SkScalar startAngles[] = { -1, -0.5f, 0, 0.5f }; + for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) { + startAngles[i] *= 180; + } + + bool anticlockwise = false; + SkScalar sign = 1; + for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles) * 2; ++i) { + if (i == SK_ARRAY_COUNT(startAngles)) { + anticlockwise = true; + sign = -1; + } + SkScalar startAngle = startAngles[i % SK_ARRAY_COUNT(startAngles)] * sign; + canvas->save(); + for (size_t j = 0; j < SK_ARRAY_COUNT(sweepAngles); ++j) { + SkPath path; + path.moveTo(0, 2); + html_canvas_arc(&path, 18, 15, 10, startAngle, startAngle + (sweepAngles[j] * sign), + anticlockwise); + path.lineTo(0, 28); + canvas->drawPath(path, paint); + canvas->translate(30, 0); + } + canvas->restore(); + canvas->translate(0, 40); + } + } + +private: + typedef skiagm::GM INHERITED; +}; +DEF_GM( return new ManyArcsGM; ) + diff --git a/include/core/SkPath.h b/include/core/SkPath.h index a0d6059..2d1a8e3 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,7 +5,6 @@ * found in the LICENSE file. */ - #ifndef SkPath_DEFINED #define SkPath_DEFINED diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 461ab3a..de3d297 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -934,14 +934,23 @@ static int build_arc_points(const SkRect& oval, const SkVector& start, const SkV return SkBuildQuadArc(start, stop, dir, &matrix, pts); } #else +/** + * If this returns 0, then the caller should just line-to the singlePt, else it should + * ignore singlePt and append the specified number of conics. + */ static int build_arc_conics(const SkRect& oval, const SkVector& start, const SkVector& stop, - SkRotationDirection dir, SkConic conics[SkConic::kMaxConicsForArc]) { + SkRotationDirection dir, SkConic conics[SkConic::kMaxConicsForArc], + SkPoint* singlePt) { SkMatrix matrix; matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); matrix.postTranslate(oval.centerX(), oval.centerY()); - return SkConic::BuildUnitArc(start, stop, dir, &matrix, conics); + int count = SkConic::BuildUnitArc(start, stop, dir, &matrix, conics); + if (0 == count) { + matrix.mapXY(start.x(), start.y(), singlePt); + } + return count; } #endif @@ -1176,8 +1185,9 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, this->quadTo(pts[i], pts[i+1]); } #else + SkPoint singlePt; SkConic conics[SkConic::kMaxConicsForArc]; - int count = build_arc_conics(oval, startV, stopV, dir, conics); + int count = build_arc_conics(oval, startV, stopV, dir, conics, &singlePt); if (count) { this->incReserve(count * 2 + 1); const SkPoint& pt = conics[0].fPts[0]; @@ -1185,6 +1195,8 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, for (int i = 0; i < count; ++i) { this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW); } + } else { + forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt); } #endif } -- 2.7.4