1 /* 2 * Copyright 2021 Google LLC 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 /* 9 * This GM creates the same gradients as the Chromium test fillrect_gradient: 10 * http://osscs/chromium/chromium/src/+/main:third_party/blink/web_tests/fast/canvas/fillrect_gradient.html 11 */ 12 13 #include "gm/gm.h" 14 #include "include/core/SkCanvas.h" 15 #include "include/core/SkColor.h" 16 #include "include/core/SkPaint.h" 17 #include "include/core/SkPoint.h" 18 #include "include/core/SkRect.h" 19 #include "include/core/SkRefCnt.h" 20 #include "include/core/SkScalar.h" 21 #include "include/core/SkShader.h" 22 #include "include/core/SkSize.h" 23 #include "include/core/SkString.h" 24 #include "include/core/SkTileMode.h" 25 #include "include/effects/SkGradientShader.h" 26 27 const int kCellSize = 50; 28 const int kNumColumns = 2; 29 const int kNumRows = 9; 30 const int kPadSize = 10; 31 32 class FillrectGradientGM : public skiagm::GM { 33 public: FillrectGradientGM()34 FillrectGradientGM() {} 35 36 protected: 37 struct GradientStop { 38 float pos; 39 SkColor color; 40 }; 41 onShortName()42 SkString onShortName() override { 43 return SkString("fillrect_gradient"); 44 } 45 onISize()46 SkISize onISize() override { 47 return SkISize::Make(kNumColumns * (kCellSize + kPadSize), 48 kNumRows * (kCellSize + kPadSize)); 49 } 50 drawGradient(SkCanvas * canvas,std::initializer_list<GradientStop> stops)51 void drawGradient(SkCanvas* canvas, std::initializer_list<GradientStop> stops) { 52 std::vector<SkColor> colors; 53 std::vector<SkScalar> positions; 54 colors.reserve(stops.size()); 55 positions.reserve(stops.size()); 56 57 for (const GradientStop& stop : stops) { 58 colors.push_back(stop.color); 59 positions.push_back(stop.pos); 60 } 61 62 static constexpr SkPoint points[] = { 63 SkPoint::Make(kCellSize, 0), 64 SkPoint::Make(kCellSize, kCellSize), 65 }; 66 67 // Draw the gradient linearly. 68 sk_sp<SkShader> shader = SkGradientShader::MakeLinear(points, 69 colors.data(), 70 positions.data(), 71 colors.size(), 72 SkTileMode::kClamp); 73 SkPaint paint; 74 paint.setShader(shader); 75 canvas->drawRect(SkRect::MakeXYWH(0, 0, kCellSize, kCellSize), paint); 76 77 canvas->save(); 78 canvas->translate(kCellSize + kPadSize, 0); 79 80 // Draw the gradient radially. 81 shader = SkGradientShader::MakeRadial(SkPoint::Make(kCellSize / 2, kCellSize / 2), 82 kCellSize / 2, 83 colors.data(), 84 positions.data(), 85 colors.size(), 86 SkTileMode::kClamp); 87 paint.setShader(shader); 88 canvas->drawRect(SkRect::MakeXYWH(0, 0, kCellSize, kCellSize), paint); 89 90 canvas->restore(); 91 canvas->translate(0, kCellSize + kPadSize); 92 } 93 onDraw(SkCanvas * canvas)94 void onDraw(SkCanvas* canvas) override { 95 // Simple gradient: Green to white 96 this->drawGradient(canvas, {{0.0f, SK_ColorGREEN}, {1.0f, SK_ColorWHITE}}); 97 98 // Multiple sections: Green to white to red 99 this->drawGradient(canvas, 100 {{0.0f, SK_ColorGREEN}, {0.5f, SK_ColorWHITE}, {1.0f, SK_ColorRED}}); 101 102 // No stops at 0.0 or 1.0: Larger green to white to larger red 103 this->drawGradient(canvas, 104 {{0.4f, SK_ColorGREEN}, {0.5f, SK_ColorWHITE}, {0.6f, SK_ColorRED}}); 105 106 // Only one stop, at zero: Solid red 107 this->drawGradient(canvas, {{0.0f, SK_ColorRED}}); 108 109 // Only one stop, at 1.0: Solid red 110 this->drawGradient(canvas, {{1.0f, SK_ColorRED}}); 111 112 // Only one stop, in the middle: Solid red 113 this->drawGradient(canvas, {{0.5f, SK_ColorRED}}); 114 115 // Disjoint gradients (multiple stops at the same offset) 116 // Blue to white in the top (inner) half, red to yellow in the bottom (outer) half 117 this->drawGradient(canvas, 118 {{0.0f, SK_ColorBLUE}, 119 {0.5f, SK_ColorWHITE}, 120 {0.5f, SK_ColorRED}, 121 {1.0f, SK_ColorYELLOW}}); 122 123 // Ignored stops: Blue to white, red to yellow (same as previous) 124 this->drawGradient(canvas, 125 {{0.0f, SK_ColorBLUE}, 126 {0.5f, SK_ColorWHITE}, 127 {0.5f, SK_ColorGRAY}, 128 {0.5f, SK_ColorCYAN}, 129 {0.5f, SK_ColorRED}, 130 {1.0f, SK_ColorYELLOW}}); 131 132 // Unsorted stops: Blue to white, red to yellow 133 // Unlike Chrome, we don't sort the stops, so this renders differently than the prior cell. 134 this->drawGradient(canvas, 135 {{0.5f, SK_ColorWHITE}, 136 {0.5f, SK_ColorGRAY}, 137 {1.0f, SK_ColorYELLOW}, 138 {0.5f, SK_ColorCYAN}, 139 {0.5f, SK_ColorRED}, 140 {0.0f, SK_ColorBLUE}}); 141 } 142 143 private: 144 using INHERITED = skiagm::GM; 145 }; 146 147 DEF_GM(return new FillrectGradientGM;) 148