1/* 2 * Copyright 2013 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 "SkArithmeticMode.h" 11#include "SkImage.h" 12#include "SkImageSource.h" 13#include "SkOffsetImageFilter.h" 14#include "SkXfermodeImageFilter.h" 15 16#define WIDTH 600 17#define HEIGHT 700 18#define MARGIN 12 19 20namespace skiagm { 21 22class XfermodeImageFilterGM : public GM { 23public: 24 XfermodeImageFilterGM(){ 25 this->setBGColor(0xFF000000); 26 } 27 28protected: 29 SkString onShortName() override { 30 return SkString("xfermodeimagefilter"); 31 } 32 33 SkISize onISize() override { 34 return SkISize::Make(WIDTH, HEIGHT); 35 } 36 37 void onOnceBeforeDraw() override { 38 fBitmap = sk_tool_utils::create_string_bitmap(80, 80, 0xD000D000, 15, 65, 96, "e"); 39 40 fCheckerboard.reset(SkImage::NewFromBitmap( 41 sk_tool_utils::create_checkerboard_bitmap(80, 80, 42 sk_tool_utils::color_to_565(0xFFA0A0A0), 43 sk_tool_utils::color_to_565(0xFF404040), 44 8))); 45 } 46 47 void onDraw(SkCanvas* canvas) override { 48 canvas->clear(SK_ColorBLACK); 49 SkPaint paint; 50 51 const struct { 52 SkXfermode::Mode fMode; 53 const char* fLabel; 54 } gModes[] = { 55 { SkXfermode::kClear_Mode, "Clear" }, 56 { SkXfermode::kSrc_Mode, "Src" }, 57 { SkXfermode::kDst_Mode, "Dst" }, 58 { SkXfermode::kSrcOver_Mode, "SrcOver" }, 59 { SkXfermode::kDstOver_Mode, "DstOver" }, 60 { SkXfermode::kSrcIn_Mode, "SrcIn" }, 61 { SkXfermode::kDstIn_Mode, "DstIn" }, 62 { SkXfermode::kSrcOut_Mode, "SrcOut" }, 63 { SkXfermode::kDstOut_Mode, "DstOut" }, 64 { SkXfermode::kSrcATop_Mode, "SrcATop" }, 65 { SkXfermode::kDstATop_Mode, "DstATop" }, 66 { SkXfermode::kXor_Mode, "Xor" }, 67 68 { SkXfermode::kPlus_Mode, "Plus" }, 69 { SkXfermode::kModulate_Mode, "Modulate" }, 70 { SkXfermode::kScreen_Mode, "Screen" }, 71 { SkXfermode::kOverlay_Mode, "Overlay" }, 72 { SkXfermode::kDarken_Mode, "Darken" }, 73 { SkXfermode::kLighten_Mode, "Lighten" }, 74 { SkXfermode::kColorDodge_Mode, "ColorDodge" }, 75 { SkXfermode::kColorBurn_Mode, "ColorBurn" }, 76 { SkXfermode::kHardLight_Mode, "HardLight" }, 77 { SkXfermode::kSoftLight_Mode, "SoftLight" }, 78 { SkXfermode::kDifference_Mode, "Difference" }, 79 { SkXfermode::kExclusion_Mode, "Exclusion" }, 80 { SkXfermode::kMultiply_Mode, "Multiply" }, 81 { SkXfermode::kHue_Mode, "Hue" }, 82 { SkXfermode::kSaturation_Mode, "Saturation" }, 83 { SkXfermode::kColor_Mode, "Color" }, 84 { SkXfermode::kLuminosity_Mode, "Luminosity" }, 85 }; 86 87 int x = 0, y = 0; 88 SkAutoTUnref<SkImageFilter> background(SkImageSource::Create(fCheckerboard)); 89 for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) { 90 SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(gModes[i].fMode)); 91 SkAutoTUnref<SkImageFilter> filter(SkXfermodeImageFilter::Create(mode, background)); 92 paint.setImageFilter(filter); 93 DrawClippedBitmap(canvas, fBitmap, paint, x, y); 94 x += fBitmap.width() + MARGIN; 95 if (x + fBitmap.width() > WIDTH) { 96 x = 0; 97 y += fBitmap.height() + MARGIN; 98 } 99 } 100 // Test arithmetic mode as image filter 101 SkAutoTUnref<SkXfermode> mode(SkArithmeticMode::Create(0, SK_Scalar1, SK_Scalar1, 0)); 102 SkAutoTUnref<SkImageFilter> filter(SkXfermodeImageFilter::Create(mode, background)); 103 paint.setImageFilter(filter); 104 DrawClippedBitmap(canvas, fBitmap, paint, x, y); 105 x += fBitmap.width() + MARGIN; 106 if (x + fBitmap.width() > WIDTH) { 107 x = 0; 108 y += fBitmap.height() + MARGIN; 109 } 110 // Test nullptr mode 111 filter.reset(SkXfermodeImageFilter::Create(nullptr, background)); 112 paint.setImageFilter(filter); 113 DrawClippedBitmap(canvas, fBitmap, paint, x, y); 114 x += fBitmap.width() + MARGIN; 115 if (x + fBitmap.width() > WIDTH) { 116 x = 0; 117 y += fBitmap.height() + MARGIN; 118 } 119 SkRect clipRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width() + 4), 120 SkIntToScalar(fBitmap.height() + 4)); 121 // Test offsets on SrcMode (uses fixed-function blend) 122 SkAutoTUnref<SkImage> bitmapImage(SkImage::NewFromBitmap(fBitmap)); 123 SkAutoTUnref<SkImageFilter> foreground(SkImageSource::Create(bitmapImage)); 124 SkAutoTUnref<SkImageFilter> offsetForeground(SkOffsetImageFilter::Create( 125 SkIntToScalar(4), SkIntToScalar(-4), foreground)); 126 SkAutoTUnref<SkImageFilter> offsetBackground(SkOffsetImageFilter::Create( 127 SkIntToScalar(4), SkIntToScalar(4), background)); 128 mode.reset(SkXfermode::Create(SkXfermode::kSrcOver_Mode)); 129 filter.reset(SkXfermodeImageFilter::Create(mode, offsetBackground, offsetForeground)); 130 paint.setImageFilter(filter); 131 DrawClippedPaint(canvas, clipRect, paint, x, y); 132 x += fBitmap.width() + MARGIN; 133 if (x + fBitmap.width() > WIDTH) { 134 x = 0; 135 y += fBitmap.height() + MARGIN; 136 } 137 // Test offsets on Darken (uses shader blend) 138 mode.reset(SkXfermode::Create(SkXfermode::kDarken_Mode)); 139 filter.reset(SkXfermodeImageFilter::Create(mode, offsetBackground, offsetForeground)); 140 paint.setImageFilter(filter); 141 DrawClippedPaint(canvas, clipRect, paint, x, y); 142 x += fBitmap.width() + MARGIN; 143 if (x + fBitmap.width() > WIDTH) { 144 x = 0; 145 y += fBitmap.height() + MARGIN; 146 } 147 // Test cropping 148 static const size_t nbSamples = 3; 149 SkXfermode::Mode sampledModes[nbSamples] = {SkXfermode::kOverlay_Mode, 150 SkXfermode::kSrcOver_Mode, 151 SkXfermode::kPlus_Mode}; 152 int offsets[nbSamples][4] = {{ 10, 10, -16, -16}, 153 { 10, 10, 10, 10}, 154 {-10, -10, -6, -6}}; 155 for (size_t i = 0; i < nbSamples; ++i) { 156 SkIRect cropRect = SkIRect::MakeXYWH(offsets[i][0], 157 offsets[i][1], 158 fBitmap.width() + offsets[i][2], 159 fBitmap.height() + offsets[i][3]); 160 SkImageFilter::CropRect rect(SkRect::Make(cropRect)); 161 mode.reset(SkXfermode::Create(sampledModes[i])); 162 filter.reset(SkXfermodeImageFilter::Create( 163 mode, offsetBackground, offsetForeground, &rect)); 164 paint.setImageFilter(filter); 165 DrawClippedPaint(canvas, clipRect, paint, x, y); 166 x += fBitmap.width() + MARGIN; 167 if (x + fBitmap.width() > WIDTH) { 168 x = 0; 169 y += fBitmap.height() + MARGIN; 170 } 171 } 172 // Test small bg, large fg with Screen (uses shader blend) 173 mode.reset(SkXfermode::Create(SkXfermode::kScreen_Mode)); 174 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(10, 10, 60, 60)); 175 SkAutoTUnref<SkImageFilter> cropped( 176 SkOffsetImageFilter::Create(0, 0, foreground, &cropRect)); 177 filter.reset(SkXfermodeImageFilter::Create(mode, cropped, background)); 178 paint.setImageFilter(filter); 179 DrawClippedPaint(canvas, clipRect, paint, x, y); 180 x += fBitmap.width() + MARGIN; 181 if (x + fBitmap.width() > WIDTH) { 182 x = 0; 183 y += fBitmap.height() + MARGIN; 184 } 185 // Test small fg, large bg with Screen (uses shader blend) 186 filter.reset(SkXfermodeImageFilter::Create(mode, background, cropped)); 187 paint.setImageFilter(filter); 188 DrawClippedPaint(canvas, clipRect, paint, x, y); 189 x += fBitmap.width() + MARGIN; 190 if (x + fBitmap.width() > WIDTH) { 191 x = 0; 192 y += fBitmap.height() + MARGIN; 193 } 194 } 195 196private: 197 static void DrawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint, 198 int x, int y) { 199 canvas->save(); 200 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 201 canvas->clipRect(SkRect::MakeWH( 202 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()))); 203 canvas->drawBitmap(bitmap, 0, 0, &paint); 204 canvas->restore(); 205 } 206 207 static void DrawClippedPaint(SkCanvas* canvas, const SkRect& rect, const SkPaint& paint, 208 int x, int y) { 209 canvas->save(); 210 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 211 canvas->clipRect(rect); 212 canvas->drawPaint(paint); 213 canvas->restore(); 214 } 215 216 SkBitmap fBitmap; 217 SkAutoTUnref<SkImage> fCheckerboard; 218 219 typedef GM INHERITED; 220}; 221 222////////////////////////////////////////////////////////////////////////////// 223 224DEF_GM( return new XfermodeImageFilterGM; ); 225 226} 227