1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2018 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker /*
9*c8dee2aaSAndroid Build Coastguard Worker * This GM presents a variety of gradients meant to test the correctness of the analytic unrolled
10*c8dee2aaSAndroid Build Coastguard Worker * binary gradient colorizer, which can handle arbitrary gradients with 1 to 8 interpolation
11*c8dee2aaSAndroid Build Coastguard Worker * intervals. These intervals can be either hardstops or smooth color transitions.
12*c8dee2aaSAndroid Build Coastguard Worker *
13*c8dee2aaSAndroid Build Coastguard Worker * It produces an image similar to that of GM_hardstop_gradients, but is arranged as follows:
14*c8dee2aaSAndroid Build Coastguard Worker *
15*c8dee2aaSAndroid Build Coastguard Worker * | Clamp |
16*c8dee2aaSAndroid Build Coastguard Worker * |________________|
17*c8dee2aaSAndroid Build Coastguard Worker * | M1 M2 M3 M4 |
18*c8dee2aaSAndroid Build Coastguard Worker * ___________|________________|
19*c8dee2aaSAndroid Build Coastguard Worker * 1 |
20*c8dee2aaSAndroid Build Coastguard Worker * 2 |
21*c8dee2aaSAndroid Build Coastguard Worker * 3 |
22*c8dee2aaSAndroid Build Coastguard Worker * 4 |
23*c8dee2aaSAndroid Build Coastguard Worker * 5 |
24*c8dee2aaSAndroid Build Coastguard Worker * 6 |
25*c8dee2aaSAndroid Build Coastguard Worker * 7 |
26*c8dee2aaSAndroid Build Coastguard Worker * 8 |
27*c8dee2aaSAndroid Build Coastguard Worker * The M-modes are different ways of interlveaving hardstops with smooth transitions:
28*c8dee2aaSAndroid Build Coastguard Worker * - M1 = All smooth transitions
29*c8dee2aaSAndroid Build Coastguard Worker * - M2 = All hard stops
30*c8dee2aaSAndroid Build Coastguard Worker * - M5 = Alternating smooth then hard
31*c8dee2aaSAndroid Build Coastguard Worker * - M6 = Alternating hard then smooth
32*c8dee2aaSAndroid Build Coastguard Worker *
33*c8dee2aaSAndroid Build Coastguard Worker * Only clamping is tested since this is focused more on within the interpolation region behavior,
34*c8dee2aaSAndroid Build Coastguard Worker * compared to overall behavior.
35*c8dee2aaSAndroid Build Coastguard Worker */
36*c8dee2aaSAndroid Build Coastguard Worker
37*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
52*c8dee2aaSAndroid Build Coastguard Worker
53*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
54*c8dee2aaSAndroid Build Coastguard Worker
55*c8dee2aaSAndroid Build Coastguard Worker // All positions must be divided by the target interval count, which will produce the expected
56*c8dee2aaSAndroid Build Coastguard Worker // normalized position array for that interval number (assuming an appropriate color count is
57*c8dee2aaSAndroid Build Coastguard Worker // provided).
58*c8dee2aaSAndroid Build Coastguard Worker const int M1_POSITIONS[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
59*c8dee2aaSAndroid Build Coastguard Worker const int M2_POSITIONS[] = { 0, 1,1, 2,2, 3,3, 4,4, 5,5, 6,6, 7,7, 8 };
60*c8dee2aaSAndroid Build Coastguard Worker const int M3_POSITIONS[] = { 0, 1, 2,2, 3, 4,4, 5, 6,6, 7, 8 };
61*c8dee2aaSAndroid Build Coastguard Worker const int M4_POSITIONS[] = { 0, 1,1, 2, 3,3, 4, 5,5, 6, 7,7, 8 };
62*c8dee2aaSAndroid Build Coastguard Worker
63*c8dee2aaSAndroid Build Coastguard Worker // Color count = index of first occurrence of interval count value in Mx_POSITIONS array.
64*c8dee2aaSAndroid Build Coastguard Worker const int INT1_COLOR_COUNTS[] = { 2, 2, 2, 2 };
65*c8dee2aaSAndroid Build Coastguard Worker const int INT2_COLOR_COUNTS[] = { 3, 4, 3, 4 };
66*c8dee2aaSAndroid Build Coastguard Worker const int INT3_COLOR_COUNTS[] = { 4, 6, 5, 5 };
67*c8dee2aaSAndroid Build Coastguard Worker const int INT4_COLOR_COUNTS[] = { 5, 8, 6, 7 };
68*c8dee2aaSAndroid Build Coastguard Worker const int INT5_COLOR_COUNTS[] = { 6, 10, 8, 8 };
69*c8dee2aaSAndroid Build Coastguard Worker const int INT6_COLOR_COUNTS[] = { 7, 12, 9, 10 };
70*c8dee2aaSAndroid Build Coastguard Worker const int INT7_COLOR_COUNTS[] = { 8, 14, 11, 11 };
71*c8dee2aaSAndroid Build Coastguard Worker const int INT8_COLOR_COUNTS[] = { 9, 16, 12, 13 };
72*c8dee2aaSAndroid Build Coastguard Worker
73*c8dee2aaSAndroid Build Coastguard Worker // Cycle through defined colors for positions 0 through 8.
74*c8dee2aaSAndroid Build Coastguard Worker const SkColor COLORS[] = {
75*c8dee2aaSAndroid Build Coastguard Worker SK_ColorDKGRAY,
76*c8dee2aaSAndroid Build Coastguard Worker SK_ColorRED,
77*c8dee2aaSAndroid Build Coastguard Worker SK_ColorYELLOW,
78*c8dee2aaSAndroid Build Coastguard Worker SK_ColorGREEN,
79*c8dee2aaSAndroid Build Coastguard Worker SK_ColorCYAN,
80*c8dee2aaSAndroid Build Coastguard Worker SK_ColorBLUE,
81*c8dee2aaSAndroid Build Coastguard Worker SK_ColorMAGENTA,
82*c8dee2aaSAndroid Build Coastguard Worker SK_ColorBLACK,
83*c8dee2aaSAndroid Build Coastguard Worker SK_ColorLTGRAY
84*c8dee2aaSAndroid Build Coastguard Worker };
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker const int* INTERVAL_COLOR_COUNTS[] = {
87*c8dee2aaSAndroid Build Coastguard Worker INT1_COLOR_COUNTS,
88*c8dee2aaSAndroid Build Coastguard Worker INT2_COLOR_COUNTS,
89*c8dee2aaSAndroid Build Coastguard Worker INT3_COLOR_COUNTS,
90*c8dee2aaSAndroid Build Coastguard Worker INT4_COLOR_COUNTS,
91*c8dee2aaSAndroid Build Coastguard Worker INT5_COLOR_COUNTS,
92*c8dee2aaSAndroid Build Coastguard Worker INT6_COLOR_COUNTS,
93*c8dee2aaSAndroid Build Coastguard Worker INT7_COLOR_COUNTS,
94*c8dee2aaSAndroid Build Coastguard Worker INT8_COLOR_COUNTS
95*c8dee2aaSAndroid Build Coastguard Worker };
96*c8dee2aaSAndroid Build Coastguard Worker const int COLOR_COUNT = std::size(COLORS);
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker const int* M_POSITIONS[] = {
99*c8dee2aaSAndroid Build Coastguard Worker M1_POSITIONS,
100*c8dee2aaSAndroid Build Coastguard Worker M2_POSITIONS,
101*c8dee2aaSAndroid Build Coastguard Worker M3_POSITIONS,
102*c8dee2aaSAndroid Build Coastguard Worker M4_POSITIONS
103*c8dee2aaSAndroid Build Coastguard Worker };
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker const int WIDTH = 500;
106*c8dee2aaSAndroid Build Coastguard Worker const int HEIGHT = 500;
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker const int NUM_ROWS = 8;
109*c8dee2aaSAndroid Build Coastguard Worker const int NUM_COLS = 4;
110*c8dee2aaSAndroid Build Coastguard Worker
111*c8dee2aaSAndroid Build Coastguard Worker const int CELL_WIDTH = WIDTH / NUM_COLS;
112*c8dee2aaSAndroid Build Coastguard Worker const int CELL_HEIGHT = HEIGHT / NUM_ROWS;
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker const int PAD_WIDTH = 3;
115*c8dee2aaSAndroid Build Coastguard Worker const int PAD_HEIGHT = 3;
116*c8dee2aaSAndroid Build Coastguard Worker
117*c8dee2aaSAndroid Build Coastguard Worker const int RECT_WIDTH = CELL_WIDTH - (2 * PAD_WIDTH);
118*c8dee2aaSAndroid Build Coastguard Worker const int RECT_HEIGHT = CELL_HEIGHT - (2 * PAD_HEIGHT);
119*c8dee2aaSAndroid Build Coastguard Worker
shade_rect(SkCanvas * canvas,sk_sp<SkShader> shader,int cellRow,int cellCol)120*c8dee2aaSAndroid Build Coastguard Worker static void shade_rect(SkCanvas* canvas, sk_sp<SkShader> shader, int cellRow, int cellCol) {
121*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
122*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(shader);
123*c8dee2aaSAndroid Build Coastguard Worker
124*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
125*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(SkIntToScalar(cellCol * CELL_WIDTH + PAD_WIDTH),
126*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(cellRow * CELL_HEIGHT + PAD_HEIGHT));
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker const SkRect rect = SkRect::MakeWH(SkIntToScalar(RECT_WIDTH), SkIntToScalar(RECT_HEIGHT));
129*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(rect, paint);
130*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker
133*c8dee2aaSAndroid Build Coastguard Worker class AnalyticGradientShaderGM : public skiagm::GM {
134*c8dee2aaSAndroid Build Coastguard Worker public:
AnalyticGradientShaderGM()135*c8dee2aaSAndroid Build Coastguard Worker AnalyticGradientShaderGM() {
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker
139*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const140*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("analytic_gradients"); }
141*c8dee2aaSAndroid Build Coastguard Worker
getISize()142*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return SkISize::Make(1024, 512); }
143*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)144*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
145*c8dee2aaSAndroid Build Coastguard Worker const SkPoint points[2] = { SkPoint::Make(0, 0), SkPoint::Make(RECT_WIDTH, 0.0) };
146*c8dee2aaSAndroid Build Coastguard Worker
147*c8dee2aaSAndroid Build Coastguard Worker for (int cellRow = 0; cellRow < NUM_ROWS; cellRow++) {
148*c8dee2aaSAndroid Build Coastguard Worker // Each interval has 4 different color counts, one per mode
149*c8dee2aaSAndroid Build Coastguard Worker const int* colorCounts = INTERVAL_COLOR_COUNTS[cellRow]; // Has len = 4
150*c8dee2aaSAndroid Build Coastguard Worker
151*c8dee2aaSAndroid Build Coastguard Worker for (int cellCol = 0; cellCol < NUM_COLS; cellCol++) {
152*c8dee2aaSAndroid Build Coastguard Worker // create_gradient_points(cellRow, cellCol, points);
153*c8dee2aaSAndroid Build Coastguard Worker
154*c8dee2aaSAndroid Build Coastguard Worker // Get the color count dependent on interval and mode
155*c8dee2aaSAndroid Build Coastguard Worker int colorCount = colorCounts[cellCol];
156*c8dee2aaSAndroid Build Coastguard Worker // Get the positions given the mode
157*c8dee2aaSAndroid Build Coastguard Worker const int* layout = M_POSITIONS[cellCol];
158*c8dee2aaSAndroid Build Coastguard Worker
159*c8dee2aaSAndroid Build Coastguard Worker // Collect positions and colors specific to the interval+mode normalizing the
160*c8dee2aaSAndroid Build Coastguard Worker // position based on the interval count (== cellRow+1)
161*c8dee2aaSAndroid Build Coastguard Worker AutoSTMalloc<4, SkColor> colors(colorCount);
162*c8dee2aaSAndroid Build Coastguard Worker AutoSTMalloc<4, SkScalar> positions(colorCount);
163*c8dee2aaSAndroid Build Coastguard Worker int j = 0;
164*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < colorCount; i++) {
165*c8dee2aaSAndroid Build Coastguard Worker positions[i] = SkIntToScalar(layout[i]) / (cellRow + 1);
166*c8dee2aaSAndroid Build Coastguard Worker colors[i] = COLORS[j % COLOR_COUNT];
167*c8dee2aaSAndroid Build Coastguard Worker j++;
168*c8dee2aaSAndroid Build Coastguard Worker }
169*c8dee2aaSAndroid Build Coastguard Worker
170*c8dee2aaSAndroid Build Coastguard Worker auto shader = SkGradientShader::MakeLinear(
171*c8dee2aaSAndroid Build Coastguard Worker points,
172*c8dee2aaSAndroid Build Coastguard Worker colors.get(),
173*c8dee2aaSAndroid Build Coastguard Worker positions.get(),
174*c8dee2aaSAndroid Build Coastguard Worker colorCount,
175*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp,
176*c8dee2aaSAndroid Build Coastguard Worker 0,
177*c8dee2aaSAndroid Build Coastguard Worker nullptr);
178*c8dee2aaSAndroid Build Coastguard Worker
179*c8dee2aaSAndroid Build Coastguard Worker shade_rect(canvas, shader, cellRow, cellCol);
180*c8dee2aaSAndroid Build Coastguard Worker }
181*c8dee2aaSAndroid Build Coastguard Worker }
182*c8dee2aaSAndroid Build Coastguard Worker }
183*c8dee2aaSAndroid Build Coastguard Worker
184*c8dee2aaSAndroid Build Coastguard Worker private:
185*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = skiagm::GM;
186*c8dee2aaSAndroid Build Coastguard Worker };
187*c8dee2aaSAndroid Build Coastguard Worker
188*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new AnalyticGradientShaderGM;)
189