1 /* 2 * Copyright 2018 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "gm.h" 9 #include "SkFont.h" 10 #include "SkGradientShader.h" 11 12 // NOTE: The positions define hardstops for the red and green borders. For the repeating degenerate 13 // gradients, that means the red and green are never visible, so the average color used should only 14 // be based off of the white, blue, black blend. 15 static const SkColor COLORS[] = { SK_ColorRED, SK_ColorWHITE, SK_ColorBLUE, 16 SK_ColorBLACK, SK_ColorGREEN }; 17 static const SkScalar POS[] = { 0.0, 0.0, 0.5, 1.0, 1.0 }; 18 static const int COLOR_CT = SK_ARRAY_COUNT(COLORS); 19 20 static const SkShader::TileMode TILE_MODES[] = { SkShader::kDecal_TileMode, 21 SkShader::kRepeat_TileMode, 22 SkShader::kMirror_TileMode, 23 SkShader::kClamp_TileMode }; 24 static const char* TILE_NAMES[] = { "decal", "repeat", "mirror", "clamp" }; 25 static const int TILE_MODE_CT = SK_ARRAY_COUNT(TILE_MODES); 26 27 static constexpr int TILE_SIZE = 100; 28 static constexpr int TILE_GAP = 10; 29 30 static const SkPoint CENTER = SkPoint::Make(TILE_SIZE / 2, TILE_SIZE / 2); 31 32 typedef sk_sp<SkShader> (*GradientFactory)(SkShader::TileMode tm); 33 34 static void draw_tile_header(SkCanvas* canvas) { 35 canvas->save(); 36 37 for (int i = 0; i < TILE_MODE_CT; ++i) { 38 canvas->drawString(TILE_NAMES[i], 0, 0, SkFont(), SkPaint()); 39 canvas->translate(TILE_SIZE + TILE_GAP, 0); 40 } 41 42 canvas->restore(); 43 44 // Now adjust to start at rows below the header 45 canvas->translate(0, 2 * TILE_GAP); 46 } 47 48 static void draw_row(SkCanvas* canvas, const char* desc, GradientFactory factory) { 49 canvas->save(); 50 51 SkPaint text; 52 text.setAntiAlias(true); 53 54 canvas->translate(0, TILE_GAP); 55 canvas->drawString(desc, 0, 0, SkFont(), text); 56 canvas->translate(0, TILE_GAP); 57 58 SkPaint paint; 59 paint.setColor(SK_ColorBLACK); 60 paint.setStyle(SkPaint::kStrokeAndFill_Style); 61 paint.setStrokeWidth(2.0f); 62 63 for (int i = 0; i < TILE_MODE_CT; ++i) { 64 paint.setShader(factory(TILE_MODES[i])); 65 canvas->drawRect(SkRect::MakeWH(TILE_SIZE, TILE_SIZE), paint); 66 canvas->translate(TILE_SIZE + TILE_GAP, 0); 67 } 68 69 canvas->restore(); 70 71 // Now adjust to start the next row below this one (1 gap for text and 2 gap for margin) 72 canvas->translate(0, 3 * TILE_GAP + TILE_SIZE); 73 } 74 75 static sk_sp<SkShader> make_linear(SkShader::TileMode mode) { 76 // Same position 77 SkPoint pts[2] = {CENTER, CENTER}; 78 return SkGradientShader::MakeLinear(pts, COLORS, POS, COLOR_CT, mode); 79 } 80 81 static sk_sp<SkShader> make_radial(SkShader::TileMode mode) { 82 // Radius = 0 83 return SkGradientShader::MakeRadial(CENTER, 0.0, COLORS, POS, COLOR_CT, mode); 84 } 85 86 static sk_sp<SkShader> make_sweep(SkShader::TileMode mode) { 87 // Start and end angles at 45 88 static constexpr SkScalar SWEEP_ANG = 45.0; 89 return SkGradientShader::MakeSweep(CENTER.fX, CENTER.fY, COLORS, POS, COLOR_CT, mode, 90 SWEEP_ANG, SWEEP_ANG, 0, nullptr); 91 } 92 93 static sk_sp<SkShader> make_sweep_zero_ang(SkShader::TileMode mode) { 94 // Start and end angles at 0 95 return SkGradientShader::MakeSweep(CENTER.fX, CENTER.fY, COLORS, POS, COLOR_CT, mode, 96 0.0, 0.0, 0, nullptr); 97 } 98 99 static sk_sp<SkShader> make_2pt_conic(SkShader::TileMode mode) { 100 // Start and end radius = TILE_SIZE, same position 101 return SkGradientShader::MakeTwoPointConical(CENTER, TILE_SIZE / 2, CENTER, TILE_SIZE / 2, 102 COLORS, POS, COLOR_CT, mode); 103 } 104 105 static sk_sp<SkShader> make_2pt_conic_zero_rad(SkShader::TileMode mode) { 106 // Start and end radius = 0, same position 107 return SkGradientShader::MakeTwoPointConical(CENTER, 0.0, CENTER, 0.0, COLORS, POS, 108 COLOR_CT, mode); 109 } 110 111 class DegenerateGradientGM : public skiagm::GM { 112 public: 113 DegenerateGradientGM() { 114 115 } 116 117 protected: 118 SkString onShortName() override { 119 return SkString("degenerate_gradients"); 120 } 121 122 SkISize onISize() override { 123 return SkISize::Make(800, 800); 124 } 125 126 void onDraw(SkCanvas* canvas) override { 127 canvas->translate(3 * TILE_GAP, 3 * TILE_GAP); 128 draw_tile_header(canvas); 129 130 draw_row(canvas, "linear: empty, blue, blue, green", make_linear); 131 draw_row(canvas, "radial: empty, blue, blue, green", make_radial); 132 draw_row(canvas, "sweep-0: empty, blue, blue, green", make_sweep_zero_ang); 133 draw_row(canvas, "sweep-45: empty, blue, blue, red 45 degree sector then green", 134 make_sweep); 135 draw_row(canvas, "2pt-conic-0: empty, blue, blue, green", make_2pt_conic_zero_rad); 136 draw_row(canvas, "2pt-conic-1: empty, blue, blue, full red circle on green", 137 make_2pt_conic); 138 } 139 140 private: 141 typedef skiagm::GM INHERITED; 142 }; 143 144 DEF_GM(return new DegenerateGradientGM;) 145