1 /*
2 * Copyright 2011 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/SkBitmap.h"
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorFilter.h"
14 #include "include/core/SkImageFilter.h"
15 #include "include/core/SkPaint.h"
16 #include "include/core/SkPoint.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkScalar.h"
20 #include "include/core/SkShader.h"
21 #include "include/core/SkSize.h"
22 #include "include/core/SkString.h"
23 #include "include/core/SkTileMode.h"
24 #include "include/core/SkTypes.h"
25 #include "include/effects/SkGradientShader.h"
26 #include "include/effects/SkImageFilters.h"
27 #include "include/effects/SkTableColorFilter.h"
28
29 #include <math.h>
30 #include <utility>
31
make_shader0(int w,int h)32 static sk_sp<SkShader> make_shader0(int w, int h) {
33 SkPoint pts[] = { {0, 0}, {SkIntToScalar(w), SkIntToScalar(h)} };
34 SkColor colors[] = {
35 SK_ColorBLACK, SK_ColorGREEN, SK_ColorCYAN,
36 SK_ColorRED, 0, SK_ColorBLUE, SK_ColorWHITE
37 };
38 return SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors),
39 SkTileMode::kClamp);
40 }
make_bm0(SkBitmap * bm)41 static void make_bm0(SkBitmap* bm) {
42 int W = 120;
43 int H = 120;
44 bm->allocN32Pixels(W, H);
45 bm->eraseColor(SK_ColorTRANSPARENT);
46
47 SkCanvas canvas(*bm);
48 SkPaint paint;
49 paint.setShader(make_shader0(W, H));
50 canvas.drawPaint(paint);
51 }
make_shader1(int w,int h)52 static sk_sp<SkShader> make_shader1(int w, int h) {
53 SkScalar cx = SkIntToScalar(w)/2;
54 SkScalar cy = SkIntToScalar(h)/2;
55 SkColor colors[] = {
56 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
57 };
58 return SkGradientShader::MakeRadial(SkPoint::Make(cx, cy), cx, colors, nullptr,
59 SK_ARRAY_COUNT(colors), SkTileMode::kClamp);
60 }
make_bm1(SkBitmap * bm)61 static void make_bm1(SkBitmap* bm) {
62 int W = 120;
63 int H = 120;
64 SkScalar cx = SkIntToScalar(W)/2;
65 SkScalar cy = SkIntToScalar(H)/2;
66 bm->allocN32Pixels(W, H);
67 bm->eraseColor(SK_ColorTRANSPARENT);
68
69 SkCanvas canvas(*bm);
70 SkPaint paint;
71 paint.setShader(make_shader1(W, H));
72 paint.setAntiAlias(true);
73 canvas.drawCircle(cx, cy, cx, paint);
74 }
75
make_table0(uint8_t table[])76 static void make_table0(uint8_t table[]) {
77 for (int i = 0; i < 256; ++i) {
78 int n = i >> 5;
79 table[i] = (n << 5) | (n << 2) | (n >> 1);
80 }
81 }
make_table1(uint8_t table[])82 static void make_table1(uint8_t table[]) {
83 for (int i = 0; i < 256; ++i) {
84 table[i] = i * i / 255;
85 }
86 }
make_table2(uint8_t table[])87 static void make_table2(uint8_t table[]) {
88 for (int i = 0; i < 256; ++i) {
89 float fi = i / 255.0f;
90 table[i] = static_cast<uint8_t>(sqrtf(fi) * 255);
91 }
92 }
93
make_null_cf()94 static sk_sp<SkColorFilter> make_null_cf() {
95 return nullptr;
96 }
97
make_cf0()98 static sk_sp<SkColorFilter> make_cf0() {
99 uint8_t table[256]; make_table0(table);
100 return SkTableColorFilter::Make(table);
101 }
make_cf1()102 static sk_sp<SkColorFilter> make_cf1() {
103 uint8_t table[256]; make_table1(table);
104 return SkTableColorFilter::Make(table);
105 }
make_cf2()106 static sk_sp<SkColorFilter> make_cf2() {
107 uint8_t table[256]; make_table2(table);
108 return SkTableColorFilter::Make(table);
109 }
make_cf3()110 static sk_sp<SkColorFilter> make_cf3() {
111 uint8_t table0[256]; make_table0(table0);
112 uint8_t table1[256]; make_table1(table1);
113 uint8_t table2[256]; make_table2(table2);
114 return SkTableColorFilter::MakeARGB(nullptr, table0, table1, table2);
115 }
116
117 class TableColorFilterGM : public skiagm::GM {
118 public:
TableColorFilterGM()119 TableColorFilterGM() {}
120
121 protected:
onShortName()122 SkString onShortName() override {
123 return SkString("tablecolorfilter");
124 }
125
onISize()126 SkISize onISize() override {
127 return {700, 1650};
128 }
129
onDraw(SkCanvas * canvas)130 void onDraw(SkCanvas* canvas) override {
131 canvas->drawColor(0xFFDDDDDD);
132 canvas->translate(20, 20);
133
134 static sk_sp<SkColorFilter> (*gColorFilterMakers[])() = {
135 make_null_cf, make_cf0, make_cf1, make_cf2, make_cf3
136 };
137 static void (*gBitmapMakers[])(SkBitmap*) = { make_bm0, make_bm1 };
138
139 // This test will be done once for each bitmap with the results stacked vertically.
140 // For a single bitmap the resulting image will be the following:
141 // - A first line with the original bitmap, followed by the image drawn once
142 // with each of the N color filters
143 // - N lines of the bitmap drawn N times, this will cover all N*N combinations of
144 // pair of color filters in order to test the collapsing of consecutive table
145 // color filters.
146 //
147 // Here is a graphical representation of the result for 2 bitmaps and 2 filters
148 // with the number corresponding to the number of filters the bitmap goes through:
149 //
150 // --bitmap1
151 // 011
152 // 22
153 // 22
154 // --bitmap2
155 // 011
156 // 22
157 // 22
158
159 SkScalar x = 0, y = 0;
160 for (size_t bitmapMaker = 0; bitmapMaker < SK_ARRAY_COUNT(gBitmapMakers); ++bitmapMaker) {
161 SkBitmap bm;
162 gBitmapMakers[bitmapMaker](&bm);
163
164 SkScalar xOffset = SkScalar(bm.width() * 9 / 8);
165 SkScalar yOffset = SkScalar(bm.height() * 9 / 8);
166
167 // Draw the first element of the first line
168 x = 0;
169 SkPaint paint;
170 canvas->drawBitmap(bm, x, y, &paint);
171
172 // Draws the rest of the first line for this bitmap
173 // each draw being at xOffset of the previous one
174 for (unsigned i = 1; i < SK_ARRAY_COUNT(gColorFilterMakers); ++i) {
175 x += xOffset;
176 paint.setColorFilter(gColorFilterMakers[i]());
177 canvas->drawBitmap(bm, x, y, &paint);
178 }
179
180 paint.setColorFilter(nullptr);
181
182 for (unsigned i = 0; i < SK_ARRAY_COUNT(gColorFilterMakers); ++i) {
183 sk_sp<SkColorFilter> colorFilter1(gColorFilterMakers[i]());
184 sk_sp<SkImageFilter> imageFilter1(SkImageFilters::ColorFilter(
185 std::move(colorFilter1), nullptr));
186
187 // Move down to the next line and draw it
188 // each draw being at xOffset of the previous one
189 y += yOffset;
190 x = 0;
191 for (unsigned j = 1; j < SK_ARRAY_COUNT(gColorFilterMakers); ++j) {
192 sk_sp<SkColorFilter> colorFilter2(gColorFilterMakers[j]());
193 sk_sp<SkImageFilter> imageFilter2(SkImageFilters::ColorFilter(
194 std::move(colorFilter2), imageFilter1, nullptr));
195 paint.setImageFilter(std::move(imageFilter2));
196 canvas->drawBitmap(bm, x, y, &paint);
197 x += xOffset;
198 }
199 }
200
201 // Move down one line to the beginning of the block for next bitmap
202 y += yOffset;
203 }
204 }
205
206 private:
207 using INHERITED = GM;
208 };
209 DEF_GM( return new TableColorFilterGM; )
210
211 //////////////////////////////////////////////////////////////////////////////
212
213 class ComposeColorFilterGM : public skiagm::GM {
214 enum {
215 COLOR_COUNT = 3,
216 MODE_COUNT = 4,
217 };
218 const SkColor* fColors;
219 const SkBlendMode* fModes;
220 const char* fName;
221
222 public:
ComposeColorFilterGM(const SkColor colors[],const SkBlendMode modes[],const char * name)223 ComposeColorFilterGM(const SkColor colors[], const SkBlendMode modes[], const char* name)
224 : fColors(colors), fModes(modes), fName(name) {}
225
226 private:
onShortName()227 SkString onShortName() override { return SkString(fName); }
228
onISize()229 SkISize onISize() override { return {790, 790}; }
230
onDraw(SkCanvas * canvas)231 void onDraw(SkCanvas* canvas) override {
232 SkBitmap bm;
233 make_bm1(&bm);
234
235 canvas->drawColor(0xFFDDDDDD);
236
237 const int MODES = MODE_COUNT * COLOR_COUNT;
238 sk_sp<SkColorFilter> filters[MODES];
239 int index = 0;
240 for (int i = 0; i < MODE_COUNT; ++i) {
241 for (int j = 0; j < COLOR_COUNT; ++j) {
242 filters[index++] = SkColorFilters::Blend(fColors[j], fModes[i]);
243 }
244 }
245
246 SkPaint paint;
247 paint.setShader(make_shader1(50, 50));
248 SkRect r = SkRect::MakeWH(50, 50);
249 const SkScalar spacer = 10;
250
251 canvas->translate(spacer, spacer);
252
253 canvas->drawRect(r, paint); // orig
254
255 for (int i = 0; i < MODES; ++i) {
256 paint.setColorFilter(filters[i]);
257
258 canvas->save();
259 canvas->translate((i + 1) * (r.width() + spacer), 0);
260 canvas->drawRect(r, paint);
261 canvas->restore();
262
263 canvas->save();
264 canvas->translate(0, (i + 1) * (r.width() + spacer));
265 canvas->drawRect(r, paint);
266 canvas->restore();
267 }
268
269 canvas->translate(r.width() + spacer, r.width() + spacer);
270
271 for (int y = 0; y < MODES; ++y) {
272 canvas->save();
273 for (int x = 0; x < MODES; ++x) {
274 paint.setColorFilter(filters[y]->makeComposed(filters[x]));
275 canvas->drawRect(r, paint);
276 canvas->translate(r.width() + spacer, 0);
277 }
278 canvas->restore();
279 canvas->translate(0, r.height() + spacer);
280 }
281 }
282 };
283
284 const SkColor gColors0[] = { SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW };
285 const SkBlendMode gModes0[] = {
286 SkBlendMode::kOverlay,
287 SkBlendMode::kDarken,
288 SkBlendMode::kColorBurn,
289 SkBlendMode::kExclusion,
290 };
291 DEF_GM( return new ComposeColorFilterGM(gColors0, gModes0, "colorcomposefilter_wacky"); )
292
293 const SkColor gColors1[] = { 0x80FF0000, 0x8000FF00, 0x800000FF };
294 const SkBlendMode gModes1[] = {
295 SkBlendMode::kSrcOver,
296 SkBlendMode::kXor,
297 SkBlendMode::kDstOut,
298 SkBlendMode::kSrcATop,
299 };
300 DEF_GM( return new ComposeColorFilterGM(gColors1, gModes1, "colorcomposefilter_alpha"); )
301