/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "gm.h" #include "sk_tool_utils.h" #include "SkCanvas.h" #include "SkColorFilterImageFilter.h" #include "SkGradientShader.h" #include "SkTableColorFilter.h" static sk_sp make_shader0(int w, int h) { SkPoint pts[] = { {0, 0}, {SkIntToScalar(w), SkIntToScalar(h)} }; SkColor colors[] = { SK_ColorBLACK, SK_ColorGREEN, SK_ColorCYAN, SK_ColorRED, 0, SK_ColorBLUE, SK_ColorWHITE }; return SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode); } static void make_bm0(SkBitmap* bm) { int W = 120; int H = 120; bm->allocN32Pixels(W, H); bm->eraseColor(SK_ColorTRANSPARENT); SkCanvas canvas(*bm); SkPaint paint; paint.setShader(make_shader0(W, H)); canvas.drawPaint(paint); } static sk_sp make_shader1(int w, int h) { SkScalar cx = SkIntToScalar(w)/2; SkScalar cy = SkIntToScalar(h)/2; SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, }; return SkGradientShader::MakeRadial(SkPoint::Make(cx, cy), cx, colors, nullptr, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode); } static void make_bm1(SkBitmap* bm) { int W = 120; int H = 120; SkScalar cx = SkIntToScalar(W)/2; SkScalar cy = SkIntToScalar(H)/2; bm->allocN32Pixels(W, H); bm->eraseColor(SK_ColorTRANSPARENT); SkCanvas canvas(*bm); SkPaint paint; paint.setShader(make_shader1(W, H)); paint.setAntiAlias(true); canvas.drawCircle(cx, cy, cx, paint); } static void make_table0(uint8_t table[]) { for (int i = 0; i < 256; ++i) { int n = i >> 5; table[i] = (n << 5) | (n << 2) | (n >> 1); } } static void make_table1(uint8_t table[]) { for (int i = 0; i < 256; ++i) { table[i] = i * i / 255; } } static void make_table2(uint8_t table[]) { for (int i = 0; i < 256; ++i) { float fi = i / 255.0f; table[i] = static_cast(sqrtf(fi) * 255); } } static sk_sp make_null_cf() { return nullptr; } static sk_sp make_cf0() { uint8_t table[256]; make_table0(table); return SkTableColorFilter::Make(table); } static sk_sp make_cf1() { uint8_t table[256]; make_table1(table); return SkTableColorFilter::Make(table); } static sk_sp make_cf2() { uint8_t table[256]; make_table2(table); return SkTableColorFilter::Make(table); } static sk_sp make_cf3() { uint8_t table0[256]; make_table0(table0); uint8_t table1[256]; make_table1(table1); uint8_t table2[256]; make_table2(table2); return SkTableColorFilter::MakeARGB(nullptr, table0, table1, table2); } class TableColorFilterGM : public skiagm::GM { public: TableColorFilterGM() {} protected: virtual SkString onShortName() { return SkString("tablecolorfilter"); } virtual SkISize onISize() { return SkISize::Make(700, 1650); } virtual void onDraw(SkCanvas* canvas) { canvas->drawColor(sk_tool_utils::color_to_565(0xFFDDDDDD)); canvas->translate(20, 20); static sk_sp (*gColorFilterMakers[])() = { make_null_cf, make_cf0, make_cf1, make_cf2, make_cf3 }; static void (*gBitmapMakers[])(SkBitmap*) = { make_bm0, make_bm1 }; // This test will be done once for each bitmap with the results stacked vertically. // For a single bitmap the resulting image will be the following: // - A first line with the original bitmap, followed by the image drawn once // with each of the N color filters // - N lines of the bitmap drawn N times, this will cover all N*N combinations of // pair of color filters in order to test the collpsing of consecutive table // color filters. // // Here is a graphical representation of the result for 2 bitmaps and 2 filters // with the number corresponding to the number of filters the bitmap goes through: // // --bitmap1 // 011 // 22 // 22 // --bitmap2 // 011 // 22 // 22 SkScalar x = 0, y = 0; for (size_t bitmapMaker = 0; bitmapMaker < SK_ARRAY_COUNT(gBitmapMakers); ++bitmapMaker) { SkBitmap bm; gBitmapMakers[bitmapMaker](&bm); SkScalar xOffset = SkScalar(bm.width() * 9 / 8); SkScalar yOffset = SkScalar(bm.height() * 9 / 8); // Draw the first element of the first line x = 0; SkPaint paint; canvas->drawBitmap(bm, x, y, &paint); // Draws the rest of the first line for this bitmap // each draw being at xOffset of the previous one for (unsigned i = 1; i < SK_ARRAY_COUNT(gColorFilterMakers); ++i) { x += xOffset; paint.setColorFilter(gColorFilterMakers[i]()); canvas->drawBitmap(bm, x, y, &paint); } paint.setColorFilter(nullptr); for (unsigned i = 0; i < SK_ARRAY_COUNT(gColorFilterMakers); ++i) { sk_sp colorFilter1(gColorFilterMakers[i]()); sk_sp imageFilter1(SkColorFilterImageFilter::Make( std::move(colorFilter1), nullptr)); // Move down to the next line and draw it // each draw being at xOffset of the previous one y += yOffset; x = 0; for (unsigned j = 1; j < SK_ARRAY_COUNT(gColorFilterMakers); ++j) { sk_sp colorFilter2(gColorFilterMakers[j]()); sk_sp imageFilter2(SkColorFilterImageFilter::Make( std::move(colorFilter2), imageFilter1, nullptr)); paint.setImageFilter(std::move(imageFilter2)); canvas->drawBitmap(bm, x, y, &paint); x += xOffset; } } // Move down one line to the beginning of the block for next bitmap y += yOffset; } } private: typedef GM INHERITED; }; DEF_GM( return new TableColorFilterGM; ) ////////////////////////////////////////////////////////////////////////////// class ComposeColorFilterGM : public skiagm::GM { enum { COLOR_COUNT = 3, MODE_COUNT = 4, }; const SkColor* fColors; const SkBlendMode* fModes; SkString fName; public: ComposeColorFilterGM(const SkColor colors[], const SkBlendMode modes[], const char suffix[]) : fColors(colors), fModes(modes) { fName.printf("colorcomposefilter_%s", suffix); } protected: virtual SkString onShortName() { return fName; } virtual SkISize onISize() { return SkISize::Make(790, 790); } virtual void onDraw(SkCanvas* canvas) { SkBitmap bm; make_bm1(&bm); canvas->drawColor(sk_tool_utils::color_to_565(0xFFDDDDDD)); const int MODES = MODE_COUNT * COLOR_COUNT; sk_sp filters[MODES]; int index = 0; for (int i = 0; i < MODE_COUNT; ++i) { for (int j = 0; j < COLOR_COUNT; ++j) { filters[index++] = SkColorFilter::MakeModeFilter(fColors[j], fModes[i]); } } SkPaint paint; paint.setShader(make_shader1(50, 50)); SkRect r = SkRect::MakeWH(50, 50); const SkScalar spacer = 10; canvas->translate(spacer, spacer); canvas->drawRect(r, paint); // orig for (int i = 0; i < MODES; ++i) { paint.setColorFilter(filters[i]); canvas->save(); canvas->translate((i + 1) * (r.width() + spacer), 0); canvas->drawRect(r, paint); canvas->restore(); canvas->save(); canvas->translate(0, (i + 1) * (r.width() + spacer)); canvas->drawRect(r, paint); canvas->restore(); } canvas->translate(r.width() + spacer, r.width() + spacer); for (int y = 0; y < MODES; ++y) { canvas->save(); for (int x = 0; x < MODES; ++x) { paint.setColorFilter(filters[y]->makeComposed(filters[x])); canvas->drawRect(r, paint); canvas->translate(r.width() + spacer, 0); } canvas->restore(); canvas->translate(0, r.height() + spacer); } } private: typedef GM INHERITED; }; const SkColor gColors0[] = { SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW }; const SkBlendMode gModes0[] = { SkBlendMode::kOverlay, SkBlendMode::kDarken, SkBlendMode::kColorBurn, SkBlendMode::kExclusion, }; DEF_GM( return new ComposeColorFilterGM(gColors0, gModes0, "wacky"); ) const SkColor gColors1[] = { 0x80FF0000, 0x8000FF00, 0x800000FF }; const SkBlendMode gModes1[] = { SkBlendMode::kSrcOver, SkBlendMode::kXor, SkBlendMode::kDstOut, SkBlendMode::kSrcATop, }; DEF_GM( return new ComposeColorFilterGM(gColors1, gModes1, "alpha"); )