| /* |
| * Copyright 2018 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/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/SkGradientShader.h" |
| #include "tools/ToolUtils.h" |
| #include "tools/fonts/FontToolUtils.h" |
| |
| // 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 SkColor COLORS[] = { SK_ColorRED, SK_ColorWHITE, SK_ColorBLUE, |
| SK_ColorBLACK, SK_ColorGREEN }; |
| static const SkScalar POS[] = { 0.0, 0.0, 0.5, 1.0, 1.0 }; |
| static const int COLOR_CT = std::size(COLORS); |
| |
| static const SkTileMode TILE_MODES[] = { SkTileMode::kDecal, |
| SkTileMode::kRepeat, |
| SkTileMode::kMirror, |
| SkTileMode::kClamp }; |
| static const char* TILE_NAMES[] = { "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 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 SkGradientShader::MakeLinear(pts, COLORS, POS, COLOR_CT, mode); |
| } |
| |
| static sk_sp<SkShader> make_radial(SkTileMode mode) { |
| // Radius = 0 |
| return SkGradientShader::MakeRadial(CENTER, 0.0, COLORS, POS, COLOR_CT, mode); |
| } |
| |
| static sk_sp<SkShader> make_sweep(SkTileMode mode) { |
| // Start and end angles at 45 |
| static constexpr SkScalar SWEEP_ANG = 45.0; |
| return SkGradientShader::MakeSweep(CENTER.fX, CENTER.fY, COLORS, POS, COLOR_CT, mode, |
| SWEEP_ANG, SWEEP_ANG, 0, nullptr); |
| } |
| |
| static sk_sp<SkShader> make_sweep_zero_ang(SkTileMode mode) { |
| // Start and end angles at 0 |
| return SkGradientShader::MakeSweep(CENTER.fX, CENTER.fY, COLORS, POS, COLOR_CT, mode, |
| 0.0, 0.0, 0, nullptr); |
| } |
| |
| static sk_sp<SkShader> make_2pt_conic(SkTileMode mode) { |
| // Start and end radius = TILE_SIZE, same position |
| return SkGradientShader::MakeTwoPointConical(CENTER, TILE_SIZE / 2, CENTER, TILE_SIZE / 2, |
| COLORS, POS, COLOR_CT, mode); |
| } |
| |
| static sk_sp<SkShader> make_2pt_conic_zero_rad(SkTileMode mode) { |
| // Start and end radius = 0, same position |
| return SkGradientShader::MakeTwoPointConical(CENTER, 0.0, CENTER, 0.0, COLORS, POS, |
| COLOR_CT, 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;) |