• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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