diff --git a/gm/circulararcs.cpp b/gm/circulararcs.cpp index 393b98020e..fbe3fe8d40 100644 --- a/gm/circulararcs.cpp +++ b/gm/circulararcs.cpp @@ -263,3 +263,83 @@ DEF_SIMPLE_GM(crbug_888453, canvas, 480, 150) { x += 2 * r + 4; } } + +DEF_SIMPLE_GM(circular_arc_stroke_matrix, canvas, 820, 1090) { + static constexpr SkScalar kRadius = 40.f; + static constexpr SkScalar kStrokeWidth = 5.f; + static constexpr SkScalar kStart = 89.f; + static constexpr SkScalar kSweep = 180.f/SK_ScalarPI; // one radian + + SkTArray matrices; + matrices.push_back().setRotate(kRadius, kRadius, 45.f); + matrices.push_back(SkMatrix::I()); + matrices.push_back().setAll(-1, 0, 2*kRadius, + 0, 1, 0, + 0, 0, 1); + matrices.push_back().setAll( 1, 0, 0, + 0, -1, 2*kRadius, + 0, 0, 1); + matrices.push_back().setAll( 1, 0, 0, + 0, -1, 2*kRadius, + 0, 0, 1); + matrices.push_back().setAll( 0, -1, 2*kRadius, + -1, 0, 2*kRadius, + 0, 0, 1); + matrices.push_back().setAll( 0, -1, 2*kRadius, + 1, 0, 0, + 0, 0, 1); + matrices.push_back().setAll( 0, 1, 0, + 1, 0, 0, + 0, 0, 1); + matrices.push_back().setAll( 0, 1, 0, + -1, 0, 2*kRadius, + 0, 0, 1); + int baseMatrixCnt = matrices.count(); + + + SkMatrix tinyCW; + tinyCW.setRotate(0.001f, kRadius, kRadius); + for (int i = 0; i < baseMatrixCnt; ++i) { + matrices.push_back().setConcat(matrices[i], tinyCW); + } + SkMatrix tinyCCW; + tinyCCW.setRotate(-0.001f, kRadius, kRadius); + for (int i = 0; i < baseMatrixCnt; ++i) { + matrices.push_back().setConcat(matrices[i], tinyCCW); + } + SkMatrix cw45; + cw45.setRotate(45.f, kRadius, kRadius); + for (int i = 0; i < baseMatrixCnt; ++i) { + matrices.push_back().setConcat(matrices[i], cw45); + } + + int x = 0; + int y = 0; + static constexpr SkScalar kPad = 2*kStrokeWidth; + canvas->translate(kPad, kPad); + auto bounds = SkRect::MakeWH(2*kRadius, 2*kRadius); + for (auto cap : {SkPaint::kRound_Cap, SkPaint::kButt_Cap, SkPaint::kSquare_Cap}) { + for (const auto& m : matrices) { + SkPaint paint; + paint.setStrokeCap(cap); + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(kStrokeWidth); + canvas->save(); + canvas->translate(x * (2*kRadius + kPad), y * (2*kRadius + kPad)); + canvas->concat(m); + paint.setColor(SK_ColorRED); + paint.setAlpha(0x80); + canvas->drawArc(bounds, kStart, kSweep, false, paint); + paint.setColor(SK_ColorBLUE); + paint.setAlpha(0x80); + canvas->drawArc(bounds, kStart, kSweep - 360.f, false, paint); + canvas->restore(); + ++x; + if (x == baseMatrixCnt) { + x = 0; + ++y; + } + } + } +} diff --git a/src/gpu/ops/GrOvalOpFactory.cpp b/src/gpu/ops/GrOvalOpFactory.cpp index 5e32b0a972..4021f3e85e 100644 --- a/src/gpu/ops/GrOvalOpFactory.cpp +++ b/src/gpu/ops/GrOvalOpFactory.cpp @@ -1110,10 +1110,13 @@ public: startPoint.normalize(); stopPoint.normalize(); - // If the matrix included scale (on one axis) we need to swap our start and end points - if ((viewMatrix.getScaleX() < 0) != (viewMatrix.getScaleY() < 0)) { - using std::swap; - swap(startPoint, stopPoint); + // We know the matrix is a similarity here. Detect mirroring which will affect how we + // should orient the clip planes for arcs. + SkASSERT(viewMatrix.isSimilarity()); + auto upperLeftDet = viewMatrix.getScaleX()*viewMatrix.getScaleY() - + viewMatrix.getSkewX() *viewMatrix.getSkewY(); + if (upperLeftDet < 0) { + std::swap(startPoint, stopPoint); } fRoundCaps = style.strokeRec().getWidth() > 0 &&