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