| /* | |
| * Copyright 2018 Google LLC | |
| * | |
| * 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/SkFont.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkPoint.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkRefCnt.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 "tools/ToolUtils.h" | |
| #include "tools/fonts/FontToolUtils.h" | |
| #include <array> | |
| // NOTE: The positions define hardstops for the red and green borders. For the repeating degenerate | |
| // gradients, that means the red and green are never visible, so the average color used should only | |
| // be based off of the white, blue, black blend. | |
| static const SkColor4f COLORS[] = { SkColors::kRed, SkColors::kWhite, SkColors::kBlue, | |
| SkColors::kBlack, SkColors::kGreen }; | |
| static const SkScalar POS[] = { 0.0, 0.0, 0.5, 1.0, 1.0 }; | |
| static constexpr auto TILE_MODES = std::to_array<SkTileMode>({ | |
| SkTileMode::kDecal, | |
| SkTileMode::kRepeat, | |
| SkTileMode::kMirror, | |
| SkTileMode::kClamp, | |
| }); | |
| static constexpr auto TILE_NAMES = std::to_array<const char*>({"decal", "repeat", "mirror", "clamp"}); | |
| static const int TILE_MODE_CT = std::size(TILE_MODES); | |
| static constexpr int TILE_SIZE = 100; | |
| static constexpr int TILE_GAP = 10; | |
| static const SkPoint CENTER = SkPoint::Make(TILE_SIZE / 2, TILE_SIZE / 2); | |
| typedef sk_sp<SkShader> (*GradientFactory)(SkTileMode tm); | |
| static SkGradient grad(SkTileMode tm) { | |
| return {{COLORS, POS, tm}, {}}; | |
| } | |
| static void draw_tile_header(SkCanvas* canvas) { | |
| canvas->save(); | |
| SkFont font(ToolUtils::DefaultPortableTypeface(), 12); | |
| for (int i = 0; i < TILE_MODE_CT; ++i) { | |
| canvas->drawString(TILE_NAMES[i], 0, 0, font, SkPaint()); | |
| canvas->translate(TILE_SIZE + TILE_GAP, 0); | |
| } | |
| canvas->restore(); | |
| // Now adjust to start at rows below the header | |
| canvas->translate(0, 2 * TILE_GAP); | |
| } | |
| static void draw_row(SkCanvas* canvas, const char* desc, GradientFactory factory) { | |
| canvas->save(); | |
| SkPaint text; | |
| text.setAntiAlias(true); | |
| SkFont font(ToolUtils::DefaultPortableTypeface(), 12); | |
| canvas->translate(0, TILE_GAP); | |
| canvas->drawString(desc, 0, 0, font, text); | |
| canvas->translate(0, TILE_GAP); | |
| SkPaint paint; | |
| paint.setColor(SK_ColorBLACK); | |
| paint.setStyle(SkPaint::kStrokeAndFill_Style); | |
| paint.setStrokeWidth(2.0f); | |
| for (int i = 0; i < TILE_MODE_CT; ++i) { | |
| paint.setShader(factory(TILE_MODES[i])); | |
| canvas->drawRect(SkRect::MakeWH(TILE_SIZE, TILE_SIZE), paint); | |
| canvas->translate(TILE_SIZE + TILE_GAP, 0); | |
| } | |
| canvas->restore(); | |
| // Now adjust to start the next row below this one (1 gap for text and 2 gap for margin) | |
| canvas->translate(0, 3 * TILE_GAP + TILE_SIZE); | |
| } | |
| static sk_sp<SkShader> make_linear(SkTileMode mode) { | |
| // Same position | |
| SkPoint pts[2] = {CENTER, CENTER}; | |
| return SkShaders::LinearGradient(pts, grad(mode)); | |
| } | |
| static sk_sp<SkShader> make_radial(SkTileMode mode) { | |
| // Radius = 0 | |
| return SkShaders::RadialGradient(CENTER, 0.0, grad(mode)); | |
| } | |
| static sk_sp<SkShader> make_sweep(SkTileMode mode) { | |
| // Start and end angles at 45 | |
| static constexpr SkScalar SWEEP_ANG = 45.0; | |
| return SkShaders::SweepGradient(CENTER, SWEEP_ANG, SWEEP_ANG, grad(mode)); | |
| } | |
| static sk_sp<SkShader> make_sweep_zero_ang(SkTileMode mode) { | |
| // Start and end angles at 0 | |
| return SkShaders::SweepGradient(CENTER, 0, 0, grad(mode)); | |
| } | |
| static sk_sp<SkShader> make_2pt_conic(SkTileMode mode) { | |
| // Start and end radius = TILE_SIZE, same position | |
| return SkShaders::TwoPointConicalGradient(CENTER, TILE_SIZE / 2, CENTER, TILE_SIZE / 2, | |
| grad(mode)); | |
| } | |
| static sk_sp<SkShader> make_2pt_conic_zero_rad(SkTileMode mode) { | |
| // Start and end radius = 0, same position | |
| return SkShaders::TwoPointConicalGradient(CENTER, 0.0, CENTER, 0.0, grad(mode)); | |
| } | |
| class DegenerateGradientGM : public skiagm::GM { | |
| public: | |
| DegenerateGradientGM() { | |
| } | |
| protected: | |
| SkString getName() const override { return SkString("degenerate_gradients"); } | |
| SkISize getISize() override { return SkISize::Make(800, 800); } | |
| void onDraw(SkCanvas* canvas) override { | |
| canvas->translate(3 * TILE_GAP, 3 * TILE_GAP); | |
| draw_tile_header(canvas); | |
| draw_row(canvas, "linear: empty, blue, blue, green", make_linear); | |
| draw_row(canvas, "radial: empty, blue, blue, green", make_radial); | |
| draw_row(canvas, "sweep-0: empty, blue, blue, green", make_sweep_zero_ang); | |
| draw_row(canvas, "sweep-45: empty, blue, blue, red 45 degree sector then green", | |
| make_sweep); | |
| draw_row(canvas, "2pt-conic-0: empty, blue, blue, green", make_2pt_conic_zero_rad); | |
| draw_row(canvas, "2pt-conic-1: empty, blue, blue, full red circle on green", | |
| make_2pt_conic); | |
| } | |
| private: | |
| using INHERITED = skiagm::GM; | |
| }; | |
| DEF_GM(return new DegenerateGradientGM;) |