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 "SkBitmap.h" 11#include "SkShader.h" 12#include "SkPM4f.h" 13 14enum SrcType { 15 //! A WxH image with a rectangle in the lower right. 16 kRectangleImage_SrcType = 0x01, 17 //! kRectangleImage_SrcType with an alpha of 34.5%. 18 kRectangleImageWithAlpha_SrcType = 0x02, 19 //! kRectnagleImageWithAlpha_SrcType scaled down by half. 20 kSmallRectangleImageWithAlpha_SrcType = 0x04, 21 //! kRectangleImage_SrcType drawn directly instead in an image. 22 kRectangle_SrcType = 0x08, 23 //! Two rectangles, first on the right half, second on the bottom half. 24 kQuarterClear_SrcType = 0x10, 25 //! kQuarterClear_SrcType in a layer. 26 kQuarterClearInLayer_SrcType = 0x20, 27 //! A W/2xH/2 transparent image. 28 kSmallTransparentImage_SrcType = 0x40, 29 //! kRectangleImage_SrcType drawn directly with a mask. 30 kRectangleWithMask_SrcType = 0x80, 31 32 kAll_SrcType = 0xFF, //!< All the source types. 33 kBasic_SrcType = 0x03, //!< Just basic source types. 34}; 35 36const struct { 37 SkBlendMode fMode; 38 int fSourceTypeMask; // The source types to use this 39 // mode with. See draw_mode for 40 // an explanation of each type. 41 // PDF has to play some tricks 42 // to support the base modes, 43 // test those more extensively. 44} gModes[] = { 45 { SkBlendMode::kClear, kAll_SrcType }, 46 { SkBlendMode::kSrc, kAll_SrcType }, 47 { SkBlendMode::kDst, kAll_SrcType }, 48 { SkBlendMode::kSrcOver, kAll_SrcType }, 49 { SkBlendMode::kDstOver, kAll_SrcType }, 50 { SkBlendMode::kSrcIn, kAll_SrcType }, 51 { SkBlendMode::kDstIn, kAll_SrcType }, 52 { SkBlendMode::kSrcOut, kAll_SrcType }, 53 { SkBlendMode::kDstOut, kAll_SrcType }, 54 { SkBlendMode::kSrcATop, kAll_SrcType }, 55 { SkBlendMode::kDstATop, kAll_SrcType }, 56 57 { SkBlendMode::kXor, kBasic_SrcType }, 58 { SkBlendMode::kPlus, kBasic_SrcType }, 59 { SkBlendMode::kModulate, kAll_SrcType }, 60 { SkBlendMode::kScreen, kBasic_SrcType }, 61 { SkBlendMode::kOverlay, kBasic_SrcType }, 62 { SkBlendMode::kDarken, kBasic_SrcType }, 63 { SkBlendMode::kLighten, kBasic_SrcType }, 64 { SkBlendMode::kColorDodge, kBasic_SrcType }, 65 { SkBlendMode::kColorBurn, kBasic_SrcType }, 66 { SkBlendMode::kHardLight, kBasic_SrcType }, 67 { SkBlendMode::kSoftLight, kBasic_SrcType }, 68 { SkBlendMode::kDifference, kBasic_SrcType }, 69 { SkBlendMode::kExclusion, kBasic_SrcType }, 70 { SkBlendMode::kMultiply, kAll_SrcType }, 71 { SkBlendMode::kHue, kBasic_SrcType }, 72 { SkBlendMode::kSaturation, kBasic_SrcType }, 73 { SkBlendMode::kColor, kBasic_SrcType }, 74 { SkBlendMode::kLuminosity, kBasic_SrcType }, 75}; 76 77static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst, 78 SkBitmap* transparent) { 79 src->allocN32Pixels(w, h); 80 src->eraseColor(SK_ColorTRANSPARENT); 81 82 SkPaint p; 83 p.setAntiAlias(true); 84 85 SkRect r; 86 SkScalar ww = SkIntToScalar(w); 87 SkScalar hh = SkIntToScalar(h); 88 89 { 90 SkCanvas c(*src); 91 p.setColor(sk_tool_utils::color_to_565(0xFFFFCC44)); 92 r.set(0, 0, ww*3/4, hh*3/4); 93 c.drawOval(r, p); 94 } 95 96 dst->allocN32Pixels(w, h); 97 dst->eraseColor(SK_ColorTRANSPARENT); 98 99 { 100 SkCanvas c(*dst); 101 p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF)); 102 r.set(ww/3, hh/3, ww*19/20, hh*19/20); 103 c.drawRect(r, p); 104 } 105 106 transparent->allocN32Pixels(w, h); 107 transparent->eraseColor(SK_ColorTRANSPARENT); 108} 109 110static uint16_t gData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF }; 111 112class XfermodesGM : public skiagm::GM { 113 SkBitmap fBG; 114 SkBitmap fSrcB, fDstB, fTransparent; 115 116 /* The srcType argument indicates what to draw for the source part. Skia 117 * uses the implied shape of the drawing command and these modes 118 * demonstrate that. 119 */ 120 void draw_mode(SkCanvas* canvas, SkBlendMode mode, SrcType srcType, SkScalar x, SkScalar y) { 121 SkPaint p; 122 SkMatrix m; 123 bool restoreNeeded = false; 124 m.setTranslate(x, y); 125 126 canvas->drawBitmap(fSrcB, x, y, &p); 127 p.setBlendMode(mode); 128 switch (srcType) { 129 case kSmallTransparentImage_SrcType: { 130 m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y); 131 132 SkAutoCanvasRestore acr(canvas, true); 133 canvas->concat(m); 134 canvas->drawBitmap(fTransparent, 0, 0, &p); 135 break; 136 } 137 case kQuarterClearInLayer_SrcType: { 138 SkRect bounds = SkRect::MakeXYWH(x, y, SkIntToScalar(W), 139 SkIntToScalar(H)); 140 canvas->saveLayer(&bounds, &p); 141 restoreNeeded = true; 142 p.setBlendMode(SkBlendMode::kSrcOver); 143 // Fall through. 144 } 145 case kQuarterClear_SrcType: { 146 SkScalar halfW = SkIntToScalar(W) / 2; 147 SkScalar halfH = SkIntToScalar(H) / 2; 148 p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF)); 149 SkRect r = SkRect::MakeXYWH(x + halfW, y, halfW, 150 SkIntToScalar(H)); 151 canvas->drawRect(r, p); 152 p.setColor(sk_tool_utils::color_to_565(0xFFAA66FF)); 153 r = SkRect::MakeXYWH(x, y + halfH, SkIntToScalar(W), halfH); 154 canvas->drawRect(r, p); 155 break; 156 } 157 case kRectangleWithMask_SrcType: { 158 canvas->save(); 159 restoreNeeded = true; 160 SkScalar w = SkIntToScalar(W); 161 SkScalar h = SkIntToScalar(H); 162 SkRect r = SkRect::MakeXYWH(x, y + h / 4, w, h * 23 / 60); 163 canvas->clipRect(r); 164 // Fall through. 165 } 166 case kRectangle_SrcType: { 167 SkScalar w = SkIntToScalar(W); 168 SkScalar h = SkIntToScalar(H); 169 SkRect r = SkRect::MakeXYWH(x + w / 3, y + h / 3, 170 w * 37 / 60, h * 37 / 60); 171 p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF)); 172 canvas->drawRect(r, p); 173 break; 174 } 175 case kSmallRectangleImageWithAlpha_SrcType: 176 m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y); 177 // Fall through. 178 case kRectangleImageWithAlpha_SrcType: 179 p.setAlpha(0x88); 180 // Fall through. 181 case kRectangleImage_SrcType: { 182 SkAutoCanvasRestore acr(canvas, true); 183 canvas->concat(m); 184 canvas->drawBitmap(fDstB, 0, 0, &p); 185 break; 186 } 187 default: 188 break; 189 } 190 191 if (restoreNeeded) { 192 canvas->restore(); 193 } 194 } 195 196 void onOnceBeforeDraw() override { 197 fBG.installPixels(SkImageInfo::Make(2, 2, kARGB_4444_SkColorType, 198 kOpaque_SkAlphaType), 199 gData, 4); 200 201 make_bitmaps(W, H, &fSrcB, &fDstB, &fTransparent); 202 } 203 204public: 205 const static int W = 64; 206 const static int H = 64; 207 XfermodesGM() {} 208 209protected: 210 SkString onShortName() override { 211 return SkString("xfermodes"); 212 } 213 214 SkISize onISize() override { 215 return SkISize::Make(1990, 570); 216 } 217 218 void onDraw(SkCanvas* canvas) override { 219 canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); 220 221 const SkScalar w = SkIntToScalar(W); 222 const SkScalar h = SkIntToScalar(H); 223 SkMatrix m; 224 m.setScale(SkIntToScalar(6), SkIntToScalar(6)); 225 auto s = SkShader::MakeBitmapShader(fBG, SkShader::kRepeat_TileMode, 226 SkShader::kRepeat_TileMode, &m); 227 228 SkPaint labelP; 229 labelP.setAntiAlias(true); 230 sk_tool_utils::set_portable_typeface(&labelP); 231 labelP.setTextAlign(SkPaint::kCenter_Align); 232 233 const int W = 5; 234 235 SkScalar x0 = 0; 236 SkScalar y0 = 0; 237 for (int sourceType = 1; sourceType & kAll_SrcType; sourceType <<= 1) { 238 SkScalar x = x0, y = y0; 239 for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) { 240 if ((gModes[i].fSourceTypeMask & sourceType) == 0) { 241 continue; 242 } 243 SkRect r{ x, y, x+w, y+h }; 244 245 SkPaint p; 246 p.setStyle(SkPaint::kFill_Style); 247 p.setShader(s); 248 canvas->drawRect(r, p); 249 250 canvas->saveLayer(&r, nullptr); 251 draw_mode(canvas, gModes[i].fMode, static_cast<SrcType>(sourceType), 252 r.fLeft, r.fTop); 253 canvas->restore(); 254 255 r.inset(-SK_ScalarHalf, -SK_ScalarHalf); 256 p.setStyle(SkPaint::kStroke_Style); 257 p.setShader(nullptr); 258 canvas->drawRect(r, p); 259 260#if 1 261 const char* label = SkBlendMode_Name(gModes[i].fMode); 262 canvas->drawString(label, 263 x + w/2, y - labelP.getTextSize()/2, labelP); 264#endif 265 x += w + SkIntToScalar(10); 266 if ((i % W) == W - 1) { 267 x = x0; 268 y += h + SkIntToScalar(30); 269 } 270 } 271 if (y < 320) { 272 if (x > x0) { 273 y += h + SkIntToScalar(30); 274 } 275 y0 = y; 276 } else { 277 x0 += SkIntToScalar(400); 278 y0 = 0; 279 } 280 } 281 } 282 283private: 284 typedef GM INHERITED; 285}; 286DEF_GM( return new XfermodesGM; ) 287