| /* | |
| * Copyright 2013 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "gm/gm.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkColor.h" | |
| #include "include/core/SkMatrix.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkPoint.h" | |
| #include "include/core/SkRRect.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkScalar.h" | |
| #include "include/core/SkShader.h" | |
| #include "include/core/SkSize.h" | |
| #include "include/core/SkString.h" | |
| #include "include/core/SkTileMode.h" | |
| #include "include/core/SkTypes.h" | |
| #include "include/effects/SkGradient.h" | |
| #include "include/private/SkTArray.h" | |
| #include "src/core/SkRandom.h" | |
| #include "tools/ToolUtils.h" | |
| #include <array> | |
| using namespace skia_private; | |
| namespace skiagm { | |
| static SkColor gen_color(SkRandom* rand) { | |
| SkScalar hsv[3]; | |
| hsv[0] = rand->nextRangeF(0.0f, 360.0f); | |
| hsv[1] = rand->nextRangeF(0.75f, 1.0f); | |
| hsv[2] = rand->nextRangeF(0.75f, 1.0f); | |
| return ToolUtils::color_to_565(SkHSVToColor(hsv)); | |
| } | |
| class RoundRectGM : public GM { | |
| public: | |
| RoundRectGM() { | |
| this->setBGColor(0xFF000000); | |
| this->makePaints(); | |
| this->makeMatrices(); | |
| } | |
| protected: | |
| SkString getName() const override { return SkString("roundrects"); } | |
| SkISize getISize() override { return SkISize::Make(1200, 900); } | |
| void makePaints() { | |
| { | |
| // no AA | |
| SkPaint p; | |
| fPaints.push_back(p); | |
| } | |
| { | |
| // AA | |
| SkPaint p; | |
| p.setAntiAlias(true); | |
| fPaints.push_back(p); | |
| } | |
| { | |
| // AA with stroke style | |
| SkPaint p; | |
| p.setAntiAlias(true); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| p.setStrokeWidth(SkIntToScalar(5)); | |
| fPaints.push_back(p); | |
| } | |
| { | |
| // AA with stroke style, width = 0 | |
| SkPaint p; | |
| p.setAntiAlias(true); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| fPaints.push_back(p); | |
| } | |
| { | |
| // AA with stroke and fill style | |
| SkPaint p; | |
| p.setAntiAlias(true); | |
| p.setStyle(SkPaint::kStrokeAndFill_Style); | |
| p.setStrokeWidth(SkIntToScalar(3)); | |
| fPaints.push_back(p); | |
| } | |
| } | |
| void makeMatrices() { | |
| { | |
| SkMatrix m; | |
| m.setIdentity(); | |
| fMatrices.push_back(m); | |
| } | |
| { | |
| SkMatrix m; | |
| m.setScale(SkIntToScalar(3), SkIntToScalar(2)); | |
| fMatrices.push_back(m); | |
| } | |
| { | |
| SkMatrix m; | |
| m.setScale(SkIntToScalar(2), SkIntToScalar(2)); | |
| fMatrices.push_back(m); | |
| } | |
| { | |
| SkMatrix m; | |
| m.setScale(SkIntToScalar(1), SkIntToScalar(2)); | |
| fMatrices.push_back(m); | |
| } | |
| { | |
| SkMatrix m; | |
| m.setScale(SkIntToScalar(4), SkIntToScalar(1)); | |
| fMatrices.push_back(m); | |
| } | |
| { | |
| SkMatrix m; | |
| m.setRotate(SkIntToScalar(90)); | |
| fMatrices.push_back(m); | |
| } | |
| { | |
| SkMatrix m; | |
| m.setSkew(SkIntToScalar(2), SkIntToScalar(3)); | |
| fMatrices.push_back(m); | |
| } | |
| { | |
| SkMatrix m; | |
| m.setRotate(SkIntToScalar(60)); | |
| fMatrices.push_back(m); | |
| } | |
| } | |
| void onDraw(SkCanvas* canvas) override { | |
| SkRandom rand(1); | |
| canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1); | |
| const SkRect kRect = SkRect::MakeLTRB(-20, -30, 20, 30); | |
| SkRRect circleRRect; | |
| circleRRect.setRectXY(kRect, 5, 5); | |
| const SkScalar kXStart = 60.0f; | |
| const SkScalar kYStart = 80.0f; | |
| const int kXStep = 150; | |
| const int kYStep = 160; | |
| int maxX = fMatrices.size(); | |
| SkPaint rectPaint; | |
| rectPaint.setAntiAlias(true); | |
| rectPaint.setStyle(SkPaint::kStroke_Style); | |
| rectPaint.setStrokeWidth(SkIntToScalar(0)); | |
| rectPaint.setColor(SK_ColorLTGRAY); | |
| int testCount = 0; | |
| for (int i = 0; i < fPaints.size(); ++i) { | |
| for (int j = 0; j < fMatrices.size(); ++j) { | |
| canvas->save(); | |
| SkMatrix mat = fMatrices[j]; | |
| // position the roundrect, and make it at off-integer coords. | |
| mat.postTranslate(kXStart + SK_Scalar1 * kXStep * (testCount % maxX) + | |
| SK_Scalar1 / 4, | |
| kYStart + SK_Scalar1 * kYStep * (testCount / maxX) + | |
| 3 * SK_Scalar1 / 4); | |
| canvas->concat(mat); | |
| SkColor color = gen_color(&rand); | |
| fPaints[i].setColor(color); | |
| canvas->drawRect(kRect, rectPaint); | |
| canvas->drawRRect(circleRRect, fPaints[i]); | |
| canvas->restore(); | |
| ++testCount; | |
| } | |
| } | |
| // special cases | |
| // non-scaled tall and skinny roundrect | |
| for (int i = 0; i < fPaints.size(); ++i) { | |
| SkRect rect = SkRect::MakeLTRB(-20, -60, 20, 60); | |
| SkRRect ellipseRect; | |
| ellipseRect.setRectXY(rect, 5, 10); | |
| canvas->save(); | |
| // position the roundrect, and make it at off-integer coords. | |
| canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.55f + SK_Scalar1 / 4, | |
| kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4); | |
| SkColor color = gen_color(&rand); | |
| fPaints[i].setColor(color); | |
| canvas->drawRect(rect, rectPaint); | |
| canvas->drawRRect(ellipseRect, fPaints[i]); | |
| canvas->restore(); | |
| } | |
| // non-scaled wide and short roundrect | |
| for (int i = 0; i < fPaints.size(); ++i) { | |
| SkRect rect = SkRect::MakeLTRB(-80, -30, 80, 30); | |
| SkRRect ellipseRect; | |
| ellipseRect.setRectXY(rect, 20, 5); | |
| canvas->save(); | |
| // position the roundrect, and make it at off-integer coords. | |
| canvas->translate(kXStart + SK_Scalar1 * kXStep * 4 + SK_Scalar1 / 4, | |
| kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + | |
| SK_ScalarHalf * kYStep); | |
| SkColor color = gen_color(&rand); | |
| fPaints[i].setColor(color); | |
| canvas->drawRect(rect, rectPaint); | |
| canvas->drawRRect(ellipseRect, fPaints[i]); | |
| canvas->restore(); | |
| } | |
| // super skinny roundrect | |
| for (int i = 0; i < fPaints.size(); ++i) { | |
| SkRect rect = SkRect::MakeLTRB(0, -60, 1, 60); | |
| SkRRect circleRect; | |
| circleRect.setRectXY(rect, 5, 5); | |
| canvas->save(); | |
| // position the roundrect, and make it at off-integer coords. | |
| canvas->translate(kXStart + SK_Scalar1 * kXStep * 3.25f + SK_Scalar1 / 4, | |
| kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4); | |
| SkColor color = gen_color(&rand); | |
| fPaints[i].setColor(color); | |
| canvas->drawRRect(circleRect, fPaints[i]); | |
| canvas->restore(); | |
| } | |
| // super short roundrect | |
| for (int i = 0; i < fPaints.size(); ++i) { | |
| SkRect rect = SkRect::MakeLTRB(-80, -1, 80, 0); | |
| SkRRect circleRect; | |
| circleRect.setRectXY(rect, 5, 5); | |
| canvas->save(); | |
| // position the roundrect, and make it at off-integer coords. | |
| canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.5f + SK_Scalar1 / 4, | |
| kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + | |
| SK_ScalarHalf * kYStep); | |
| SkColor color = gen_color(&rand); | |
| fPaints[i].setColor(color); | |
| canvas->drawRRect(circleRect, fPaints[i]); | |
| canvas->restore(); | |
| } | |
| // radial gradient | |
| SkPoint center = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0)); | |
| SkColor4f colors[] = { SkColors::kBlue, SkColors::kRed, SkColors::kGreen }; | |
| SkScalar pos[] = { 0, SK_ScalarHalf, SK_Scalar1 }; | |
| auto shader = SkShaders::RadialGradient(center, 20, | |
| {{colors, pos, SkTileMode::kClamp}, {}}); | |
| for (int i = 0; i < fPaints.size(); ++i) { | |
| canvas->save(); | |
| // position the path, and make it at off-integer coords. | |
| canvas->translate(kXStart + SK_Scalar1 * kXStep * 0 + SK_Scalar1 / 4, | |
| kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + | |
| SK_ScalarHalf * kYStep); | |
| SkColor color = gen_color(&rand); | |
| fPaints[i].setColor(color); | |
| fPaints[i].setShader(shader); | |
| canvas->drawRect(kRect, rectPaint); | |
| canvas->drawRRect(circleRRect, fPaints[i]); | |
| fPaints[i].setShader(nullptr); | |
| canvas->restore(); | |
| } | |
| // strokes and radii | |
| { | |
| static constexpr auto radii = std::to_array<std::array<SkScalar, 2>>({ | |
| {10,10}, | |
| {5,15}, | |
| {5,15}, | |
| {5,15}, | |
| }); | |
| static constexpr auto strokeWidths = std::to_array<SkScalar>({ | |
| 20, 10, 20, 40 | |
| }); | |
| for (int i = 0; i < 4; ++i) { | |
| SkRRect circleRect; | |
| circleRect.setRectXY(kRect, radii[i][0], radii[i][1]); | |
| canvas->save(); | |
| // position the roundrect, and make it at off-integer coords. | |
| canvas->translate(kXStart + SK_Scalar1 * kXStep * 5 + SK_Scalar1 / 4, | |
| kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + | |
| SK_ScalarHalf * kYStep); | |
| SkColor color = gen_color(&rand); | |
| SkPaint p; | |
| p.setAntiAlias(true); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| p.setStrokeWidth(strokeWidths[i]); | |
| p.setColor(color); | |
| canvas->drawRRect(circleRect, p); | |
| canvas->restore(); | |
| } | |
| } | |
| // test old entry point ( skbug.com/40034920 ) | |
| { | |
| canvas->save(); | |
| canvas->translate(kXStart + SK_Scalar1 * kXStep * 5 + SK_Scalar1 / 4, | |
| kYStart + SK_Scalar1 * kYStep * 4 + SK_Scalar1 / 4 + | |
| SK_ScalarHalf * kYStep); | |
| const SkColor color = gen_color(&rand); | |
| SkPaint p; | |
| p.setColor(color); | |
| const SkRect oooRect = { 20, 30, -20, -30 }; // intentionally out of order | |
| canvas->drawRoundRect(oooRect, 10, 10, p); | |
| canvas->restore(); | |
| } | |
| // rrect with stroke > radius/2 | |
| { | |
| SkRect smallRect = { -30, -20, 30, 20 }; | |
| SkRRect circleRect; | |
| circleRect.setRectXY(smallRect, 5, 5); | |
| canvas->save(); | |
| // position the roundrect, and make it at off-integer coords. | |
| canvas->translate(kXStart + SK_Scalar1 * kXStep * 5 + SK_Scalar1 / 4, | |
| kYStart - SK_Scalar1 * kYStep + 73 * SK_Scalar1 / 4 + | |
| SK_ScalarHalf * kYStep); | |
| SkColor color = gen_color(&rand); | |
| SkPaint p; | |
| p.setAntiAlias(true); | |
| p.setStyle(SkPaint::kStroke_Style); | |
| p.setStrokeWidth(25); | |
| p.setColor(color); | |
| canvas->drawRRect(circleRect, p); | |
| canvas->restore(); | |
| } | |
| } | |
| private: | |
| TArray<SkPaint> fPaints; | |
| TArray<SkMatrix> fMatrices; | |
| using INHERITED = GM; | |
| }; | |
| ////////////////////////////////////////////////////////////////////////////// | |
| DEF_GM( return new RoundRectGM; ) | |
| } // namespace skiagm |