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