1 /*
2 * Copyright 2014 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/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkColorFilter.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkPoint.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkRefCnt.h"
16 #include "include/core/SkShader.h"
17 #include "include/core/SkSize.h"
18 #include "include/core/SkString.h"
19 #include "include/core/SkTileMode.h"
20 #include "include/core/SkTypes.h"
21 #include "include/effects/SkColorMatrixFilter.h"
22 #include "include/effects/SkGradientShader.h"
23 #include "tools/Resources.h"
24
25 #include <vector>
26 #include <tuple>
27
make_shader(const SkRect & bounds)28 static sk_sp<SkShader> make_shader(const SkRect& bounds) {
29 const SkPoint pts[] = {
30 { bounds.left(), bounds.top() },
31 { bounds.right(), bounds.bottom() },
32 };
33 const SkColor colors[] = {
34 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK,
35 SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW,
36 };
37 return SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors),
38 SkTileMode::kClamp);
39 }
40
41 typedef void (*InstallPaint)(SkPaint*, uint32_t, uint32_t);
42
install_nothing(SkPaint * paint,uint32_t,uint32_t)43 static void install_nothing(SkPaint* paint, uint32_t, uint32_t) {
44 paint->setColorFilter(nullptr);
45 }
46
install_lighting(SkPaint * paint,uint32_t mul,uint32_t add)47 static void install_lighting(SkPaint* paint, uint32_t mul, uint32_t add) {
48 paint->setColorFilter(SkColorMatrixFilter::MakeLightingFilter(mul, add));
49 }
50
51 class ColorFiltersGM : public skiagm::GM {
onShortName()52 SkString onShortName() override { return SkString("lightingcolorfilter"); }
53
onISize()54 SkISize onISize() override { return {620, 430}; }
55
onDraw(SkCanvas * canvas)56 void onDraw(SkCanvas* canvas) override {
57 SkRect r = {0, 0, 600, 50};
58
59 SkPaint paint;
60 paint.setShader(make_shader(r));
61
62 const struct {
63 InstallPaint fProc;
64 uint32_t fData0, fData1;
65 } rec[] = {
66 { install_nothing, 0, 0 },
67 { install_lighting, 0xFF0000, 0 },
68 { install_lighting, 0x00FF00, 0 },
69 { install_lighting, 0x0000FF, 0 },
70 { install_lighting, 0x000000, 0xFF0000 },
71 { install_lighting, 0x000000, 0x00FF00 },
72 { install_lighting, 0x000000, 0x0000FF },
73 };
74
75 canvas->translate(10, 10);
76 for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) {
77 rec[i].fProc(&paint, rec[i].fData0, rec[i].fData1);
78 canvas->drawRect(r, paint);
79 canvas->translate(0, r.height() + 10);
80 }
81 }
82 };
83
84 DEF_GM(return new ColorFiltersGM;)
85
86 class HSLColorFilterGM : public skiagm::GM {
87 protected:
onShortName()88 SkString onShortName() override { return SkString("hslcolorfilter"); }
89
onISize()90 SkISize onISize() override { return { 840, 1100 }; }
91
onOnceBeforeDraw()92 void onOnceBeforeDraw() override {
93 sk_sp<SkImage> mandrill = GetResourceAsImage("images/mandrill_256.png");
94 const auto lm = SkMatrix::MakeRectToRect(SkRect::MakeWH(mandrill->width(),
95 mandrill->height()),
96 SkRect::MakeWH(kWheelSize, kWheelSize),
97 SkMatrix::kFill_ScaleToFit);
98 fShaders.push_back(mandrill->makeShader(&lm));
99
100 static constexpr SkColor gGrads[][4] = {
101 { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffff0000 },
102 { 0xdfc08040, 0xdf8040c0, 0xdf40c080, 0xdfc08040 },
103 };
104
105 for (const auto& cols : gGrads) {
106 fShaders.push_back(SkGradientShader::MakeSweep(kWheelSize / 2, kWheelSize / 2,
107 cols, nullptr, SK_ARRAY_COUNT(cols),
108 SkTileMode::kRepeat, -90, 270, 0,
109 nullptr));
110 }
111 }
112
onDraw(SkCanvas * canvas)113 void onDraw(SkCanvas* canvas) override {
114 using std::make_tuple;
115
116 static constexpr struct {
117 std::tuple<float, float> h, s, l;
118 } gTests[] = {
119 { make_tuple(-0.5f, 0.5f), make_tuple( 0.0f, 0.0f), make_tuple( 0.0f, 0.0f) },
120 { make_tuple( 0.0f, 0.0f), make_tuple(-1.0f, 1.0f), make_tuple( 0.0f, 0.0f) },
121 { make_tuple( 0.0f, 0.0f), make_tuple( 0.0f, 0.0f), make_tuple(-1.0f, 1.0f) },
122 };
123
124 const auto rect = SkRect::MakeWH(kWheelSize, kWheelSize);
125
126 canvas->drawColor(0xffcccccc);
127 SkPaint paint;
128
129 for (const auto& shader : fShaders) {
130 paint.setShader(shader);
131
132 for (const auto& tst: gTests) {
133 canvas->translate(0, kWheelSize * 0.1f);
134
135 const auto dh = (std::get<1>(tst.h) - std::get<0>(tst.h)) / (kSteps - 1),
136 ds = (std::get<1>(tst.s) - std::get<0>(tst.s)) / (kSteps - 1),
137 dl = (std::get<1>(tst.l) - std::get<0>(tst.l)) / (kSteps - 1);
138 auto h = std::get<0>(tst.h),
139 s = std::get<0>(tst.s),
140 l = std::get<0>(tst.l);
141 {
142 SkAutoCanvasRestore acr(canvas, true);
143 for (size_t i = 0; i < kSteps; ++i) {
144 paint.setColorFilter(make_filter(h, s, l));
145 canvas->translate(kWheelSize * 0.1f, 0);
146 canvas->drawRect(rect, paint);
147 canvas->translate(kWheelSize * 1.1f, 0);
148 h += dh;
149 s += ds;
150 l += dl;
151 }
152 }
153 canvas->translate(0, kWheelSize * 1.1f);
154 }
155 canvas->translate(0, kWheelSize * 0.1f);
156 }
157 }
158
159 private:
160 static constexpr SkScalar kWheelSize = 100;
161 static constexpr size_t kSteps = 7;
162
make_filter(float h,float s,float l)163 static sk_sp<SkColorFilter> make_filter(float h, float s, float l) {
164 // These are roughly AE semantics.
165 const auto h_bias = h,
166 h_scale = 1.0f,
167 s_bias = std::max(s, 0.0f),
168 s_scale = 1 - std::abs(s),
169 l_bias = std::max(l, 0.0f),
170 l_scale = 1 - std::abs(l);
171
172 const float cm[20] = {
173 h_scale, 0, 0, 0, h_bias,
174 0, s_scale, 0, 0, s_bias,
175 0, 0, l_scale, 0, l_bias,
176 0, 0, 0, 1, 0,
177 };
178
179 return SkColorFilters::HSLAMatrix(cm);
180 }
181
182 std::vector<sk_sp<SkShader>> fShaders;
183 };
184
185 DEF_GM(return new HSLColorFilterGM;)
186