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