2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
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"
32 static sk_sp<SkShader> make_shader0(int w, int h) {
33 SkPoint pts[] = { {0, 0}, {SkIntToScalar(w), SkIntToScalar(h)} };
35 SK_ColorBLACK, SK_ColorGREEN, SK_ColorCYAN,
36 SK_ColorRED, 0, SK_ColorBLUE, SK_ColorWHITE
38 return SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors),
41 static void make_bm0(SkBitmap* bm) {
44 bm->allocN32Pixels(W, H);
45 bm->eraseColor(SK_ColorTRANSPARENT);
49 paint.setShader(make_shader0(W, H));
50 canvas.drawPaint(paint);
52 static sk_sp<SkShader> make_shader1(int w, int h) {
53 SkScalar cx = SkIntToScalar(w)/2;
54 SkScalar cy = SkIntToScalar(h)/2;
56 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
58 return SkGradientShader::MakeRadial(SkPoint::Make(cx, cy), cx, colors, nullptr,
59 SK_ARRAY_COUNT(colors), SkTileMode::kClamp);
61 static void make_bm1(SkBitmap* bm) {
64 SkScalar cx = SkIntToScalar(W)/2;
65 SkScalar cy = SkIntToScalar(H)/2;
66 bm->allocN32Pixels(W, H);
67 bm->eraseColor(SK_ColorTRANSPARENT);
71 paint.setShader(make_shader1(W, H));
72 paint.setAntiAlias(true);
73 canvas.drawCircle(cx, cy, cx, paint);
76 static void make_table0(uint8_t table[]) {
77 for (int i = 0; i < 256; ++i) {
79 table[i] = (n << 5) | (n << 2) | (n >> 1);
82 static void make_table1(uint8_t table[]) {
83 for (int i = 0; i < 256; ++i) {
84 table[i] = i * i / 255;
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);
94 static sk_sp<SkColorFilter> make_null_cf() {
98 static sk_sp<SkColorFilter> make_cf0() {
99 uint8_t table[256]; make_table0(table);
100 return SkTableColorFilter::Make(table);
102 static sk_sp<SkColorFilter> make_cf1() {
103 uint8_t table[256]; make_table1(table);
104 return SkTableColorFilter::Make(table);
106 static sk_sp<SkColorFilter> make_cf2() {
107 uint8_t table[256]; make_table2(table);
108 return SkTableColorFilter::Make(table);
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);
117 class TableColorFilterGM : public skiagm::GM {
119 TableColorFilterGM() {}
122 SkString onShortName() override {
123 return SkString("tablecolorfilter");
126 SkISize onISize() override {
130 void onDraw(SkCanvas* canvas) override {
131 canvas->drawColor(0xFFDDDDDD);
132 canvas->translate(20, 20);
134 static sk_sp<SkColorFilter> (*gColorFilterMakers[])() = {
135 make_null_cf, make_cf0, make_cf1, make_cf2, make_cf3
137 static void (*gBitmapMakers[])(SkBitmap*) = { make_bm0, make_bm1 };
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
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:
159 SkScalar x = 0, y = 0;
160 for (size_t bitmapMaker = 0; bitmapMaker < SK_ARRAY_COUNT(gBitmapMakers); ++bitmapMaker) {
162 gBitmapMakers[bitmapMaker](&bm);
164 SkScalar xOffset = SkScalar(bm.width() * 9 / 8);
165 SkScalar yOffset = SkScalar(bm.height() * 9 / 8);
167 // Draw the first element of the first line
170 SkSamplingOptions sampling;
172 canvas->drawImage(bm.asImage(), x, y);
174 // Draws the rest of the first line for this bitmap
175 // each draw being at xOffset of the previous one
176 for (unsigned i = 1; i < SK_ARRAY_COUNT(gColorFilterMakers); ++i) {
178 paint.setColorFilter(gColorFilterMakers[i]());
179 canvas->drawImage(bm.asImage(), x, y, sampling, &paint);
182 paint.setColorFilter(nullptr);
184 for (unsigned i = 0; i < SK_ARRAY_COUNT(gColorFilterMakers); ++i) {
185 sk_sp<SkColorFilter> colorFilter1(gColorFilterMakers[i]());
186 sk_sp<SkImageFilter> imageFilter1(SkImageFilters::ColorFilter(
187 std::move(colorFilter1), nullptr));
189 // Move down to the next line and draw it
190 // each draw being at xOffset of the previous one
193 for (unsigned j = 1; j < SK_ARRAY_COUNT(gColorFilterMakers); ++j) {
194 sk_sp<SkColorFilter> colorFilter2(gColorFilterMakers[j]());
195 sk_sp<SkImageFilter> imageFilter2(SkImageFilters::ColorFilter(
196 std::move(colorFilter2), imageFilter1, nullptr));
197 paint.setImageFilter(std::move(imageFilter2));
198 canvas->drawImage(bm.asImage(), x, y, sampling, &paint);
203 // Move down one line to the beginning of the block for next bitmap
209 using INHERITED = GM;
211 DEF_GM( return new TableColorFilterGM; )
213 //////////////////////////////////////////////////////////////////////////////
215 class ComposeColorFilterGM : public skiagm::GM {
220 const SkColor* fColors;
221 const SkBlendMode* fModes;
225 ComposeColorFilterGM(const SkColor colors[], const SkBlendMode modes[], const char* name)
226 : fColors(colors), fModes(modes), fName(name) {}
229 SkString onShortName() override { return SkString(fName); }
231 SkISize onISize() override { return {790, 790}; }
233 void onDraw(SkCanvas* canvas) override {
237 canvas->drawColor(0xFFDDDDDD);
239 const int MODES = MODE_COUNT * COLOR_COUNT;
240 sk_sp<SkColorFilter> filters[MODES];
242 for (int i = 0; i < MODE_COUNT; ++i) {
243 for (int j = 0; j < COLOR_COUNT; ++j) {
244 filters[index++] = SkColorFilters::Blend(fColors[j], fModes[i]);
249 paint.setShader(make_shader1(50, 50));
250 SkRect r = SkRect::MakeWH(50, 50);
251 const SkScalar spacer = 10;
253 canvas->translate(spacer, spacer);
255 canvas->drawRect(r, paint); // orig
257 for (int i = 0; i < MODES; ++i) {
258 paint.setColorFilter(filters[i]);
261 canvas->translate((i + 1) * (r.width() + spacer), 0);
262 canvas->drawRect(r, paint);
266 canvas->translate(0, (i + 1) * (r.width() + spacer));
267 canvas->drawRect(r, paint);
271 canvas->translate(r.width() + spacer, r.width() + spacer);
273 for (int y = 0; y < MODES; ++y) {
275 for (int x = 0; x < MODES; ++x) {
276 paint.setColorFilter(filters[y]->makeComposed(filters[x]));
277 canvas->drawRect(r, paint);
278 canvas->translate(r.width() + spacer, 0);
281 canvas->translate(0, r.height() + spacer);
286 const SkColor gColors0[] = { SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW };
287 const SkBlendMode gModes0[] = {
288 SkBlendMode::kOverlay,
289 SkBlendMode::kDarken,
290 SkBlendMode::kColorBurn,
291 SkBlendMode::kExclusion,
293 DEF_GM( return new ComposeColorFilterGM(gColors0, gModes0, "colorcomposefilter_wacky"); )
295 const SkColor gColors1[] = { 0x80FF0000, 0x8000FF00, 0x800000FF };
296 const SkBlendMode gModes1[] = {
297 SkBlendMode::kSrcOver,
299 SkBlendMode::kDstOut,
300 SkBlendMode::kSrcATop,
302 DEF_GM( return new ComposeColorFilterGM(gColors1, gModes1, "colorcomposefilter_alpha"); )