|  | /* | 
|  | * 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.h" | 
|  | #include "SkFont.h" | 
|  | #include "SkGradientShader.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 = SK_ARRAY_COUNT(COLORS); | 
|  |  | 
|  | static const SkShader::TileMode TILE_MODES[] = { SkShader::kDecal_TileMode, | 
|  | SkShader::kRepeat_TileMode, | 
|  | SkShader::kMirror_TileMode, | 
|  | SkShader::kClamp_TileMode }; | 
|  | static const char* TILE_NAMES[] = { "decal", "repeat", "mirror", "clamp" }; | 
|  | static const int TILE_MODE_CT = SK_ARRAY_COUNT(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)(SkShader::TileMode tm); | 
|  |  | 
|  | static void draw_tile_header(SkCanvas* canvas) { | 
|  | canvas->save(); | 
|  |  | 
|  | for (int i = 0; i < TILE_MODE_CT; ++i) { | 
|  | canvas->drawString(TILE_NAMES[i], 0, 0, SkFont(), 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); | 
|  |  | 
|  | canvas->translate(0, TILE_GAP); | 
|  | canvas->drawString(desc, 0, 0, SkFont(), 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(SkShader::TileMode mode) { | 
|  | // Same position | 
|  | SkPoint pts[2] = {CENTER, CENTER}; | 
|  | return SkGradientShader::MakeLinear(pts, COLORS, POS, COLOR_CT, mode); | 
|  | } | 
|  |  | 
|  | static sk_sp<SkShader> make_radial(SkShader::TileMode mode) { | 
|  | // Radius = 0 | 
|  | return SkGradientShader::MakeRadial(CENTER, 0.0, COLORS, POS, COLOR_CT, mode); | 
|  | } | 
|  |  | 
|  | static sk_sp<SkShader> make_sweep(SkShader::TileMode 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(SkShader::TileMode 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(SkShader::TileMode 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(SkShader::TileMode 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 onShortName() override { | 
|  | return SkString("degenerate_gradients"); | 
|  | } | 
|  |  | 
|  | SkISize onISize() 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: | 
|  | typedef skiagm::GM INHERITED; | 
|  | }; | 
|  |  | 
|  | DEF_GM(return new DegenerateGradientGM;) |