blob: e36f54ee80e13c83dae4bbf8e76dce526e0062eb [file] [log] [blame]
reed@android.comdd0ac282009-06-20 02:38:16 +00001#include "gm.h"
2#include "SkBitmap.h"
3#include "SkShader.h"
4#include "SkXfermode.h"
5
6namespace skiagm {
7
tomhudson@google.com86bf5c92011-04-26 18:15:03 +00008static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst) {
reed@android.comdd0ac282009-06-20 02:38:16 +00009 src->setConfig(SkBitmap::kARGB_8888_Config, w, h);
10 src->allocPixels();
11 src->eraseColor(0);
12
13 SkCanvas c(*src);
14 SkPaint p;
15 SkRect r;
16 SkScalar ww = SkIntToScalar(w);
17 SkScalar hh = SkIntToScalar(h);
18
19 p.setAntiAlias(true);
tomhudson@google.com86bf5c92011-04-26 18:15:03 +000020 p.setColor(0xFFFFCC44);
reed@android.comdd0ac282009-06-20 02:38:16 +000021 r.set(0, 0, ww*3/4, hh*3/4);
22 c.drawOval(r, p);
tomhudson@google.com86bf5c92011-04-26 18:15:03 +000023
reed@android.comdd0ac282009-06-20 02:38:16 +000024 dst->setConfig(SkBitmap::kARGB_8888_Config, w, h);
25 dst->allocPixels();
26 dst->eraseColor(0);
27 c.setBitmapDevice(*dst);
28
29 p.setColor(0xFF66AAFF);
30 r.set(ww/3, hh/3, ww*19/20, hh*19/20);
31 c.drawRect(r, p);
32}
33
34static uint16_t gBG[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
35
36class XfermodesGM : public GM {
reed@android.comdd0ac282009-06-20 02:38:16 +000037 SkBitmap fBG;
38 SkBitmap fSrcB, fDstB;
39
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +000040 /* The sourceType argument indicates what to draw for the source part. Skia
41 * uses the implied shape of the drawing command and these modes
42 * demonstrate that.
43 *
44 * 0x01: A WxH image with a rectangle in the lower right.
45 * 0x02: Same as 0x01, but with an alpha of 34.5%.
46 * 0x04: Same as 0x02, but scaled down by half.
47 * 0x08: The same rectangle as 0x01, but drawn directly instead in an image.
48 * 0x10: Two rectangles, first on the right half, second on the bottom half.
49 * 0x20: Same as 0x10, but on a layer.
50 */
51 void draw_mode(SkCanvas* canvas, SkXfermode* mode, int sourceType,
reed@google.comf3c1cc92010-12-23 16:45:33 +000052 SkScalar x, SkScalar y) {
reed@android.comdd0ac282009-06-20 02:38:16 +000053 SkPaint p;
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +000054 SkMatrix m;
55 bool restoreNeeded = false;
56 m.setTranslate(x, y);
tomhudson@google.com86bf5c92011-04-26 18:15:03 +000057
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +000058 canvas->drawBitmapMatrix(fSrcB, m, &p);
reed@android.comdd0ac282009-06-20 02:38:16 +000059 p.setXfermode(mode);
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +000060 switch (sourceType) {
61 case 0x20: {
62 SkRect bounds = SkRect::MakeXYWH(x, y, W, H);
63 canvas->saveLayer(&bounds, &p);
64 restoreNeeded = true;
65 p.setXfermodeMode(SkXfermode::kSrcOver_Mode);
66 // Fall through.
67 }
68 case 0x10: {
69 SkScalar halfW = SkIntToScalar(W) / 2;
70 SkScalar halfH = SkIntToScalar(H) / 2;
71 p.setColor(0xFF66AAFF);
72 SkRect r = SkRect::MakeXYWH(x + halfW, y, halfW, H);
73 canvas->drawRect(r, p);
74 p.setColor(0xFFAA66FF);
75 r = SkRect::MakeXYWH(x, y + halfH, W, halfH);
76 canvas->drawRect(r, p);
77 break;
78 }
79 case 0x8: {
80 SkScalar w = SkIntToScalar(W);
81 SkScalar h = SkIntToScalar(H);
82 SkRect r = SkRect::MakeXYWH(x + w / 3, y + h / 3,
83 w * 37 / 60, h * 37 / 60);
84 p.setColor(0xFF66AAFF);
85 canvas->drawRect(r, p);
86 break;
87 }
88 case 0x4:
89 m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);
90 // Fall through.
91 case 0x2:
92 p.setAlpha(0x88);
93 // Fall through.
94 case 0x1:
95 canvas->drawBitmapMatrix(fDstB, m, &p);
96 break;
97 default:
98 break;
99 }
100
101 if (restoreNeeded) {
102 canvas->restore();
103 }
reed@android.comdd0ac282009-06-20 02:38:16 +0000104 }
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000105
reed@android.comdd0ac282009-06-20 02:38:16 +0000106public:
reed@google.comf3c1cc92010-12-23 16:45:33 +0000107 const static int W = 64;
108 const static int H = 64;
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000109 XfermodesGM() {
110 // Do all this work in a temporary so we get a deep copy,
111 // especially of gBG.
112 SkBitmap scratchBitmap;
113 scratchBitmap.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4);
114 scratchBitmap.setPixels(gBG);
115 scratchBitmap.setIsOpaque(true);
116 scratchBitmap.copyTo(&fBG, SkBitmap::kARGB_4444_Config);
117
reed@android.comdd0ac282009-06-20 02:38:16 +0000118 make_bitmaps(W, H, &fSrcB, &fDstB);
119 }
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000120
reed@android.comdd0ac282009-06-20 02:38:16 +0000121protected:
reed@android.com048522d2009-06-23 12:19:41 +0000122 virtual SkString onShortName() {
reed@android.com8015dd82009-06-21 00:49:18 +0000123 return SkString("xfermodes");
124 }
125
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000126 virtual SkISize onISize() {
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +0000127 return make_isize(1590, 640);
reed@android.com048522d2009-06-23 12:19:41 +0000128 }
reed@android.comdd0ac282009-06-20 02:38:16 +0000129
130 void drawBG(SkCanvas* canvas) {
131 canvas->drawColor(SK_ColorWHITE);
reed@android.comdd0ac282009-06-20 02:38:16 +0000132 }
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000133
reed@android.comdd0ac282009-06-20 02:38:16 +0000134 virtual void onDraw(SkCanvas* canvas) {
reed@google.comf3c1cc92010-12-23 16:45:33 +0000135 canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000136
reed@android.comdd0ac282009-06-20 02:38:16 +0000137 this->drawBG(canvas);
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000138
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +0000139 const int kMaxSourceType = 0x20;
reed@android.comdd0ac282009-06-20 02:38:16 +0000140 const struct {
reed@google.comf3c1cc92010-12-23 16:45:33 +0000141 SkXfermode::Mode fMode;
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +0000142 const char* fLabel;
143 int fSourceTypeMask; // The source types to use this
144 // mode with. See draw_mode for
145 // an explanation of each type.
146 // PDF has to play some tricks
147 // to support the base modes,
148 // test those more extensively.
reed@android.comdd0ac282009-06-20 02:38:16 +0000149 } gModes[] = {
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +0000150 { SkXfermode::kClear_Mode, "Clear", 0x3F },
151 { SkXfermode::kSrc_Mode, "Src", 0x3F },
152 { SkXfermode::kDst_Mode, "Dst", 0x3F },
153 { SkXfermode::kSrcOver_Mode, "SrcOver", 0x3F },
154 { SkXfermode::kDstOver_Mode, "DstOver", 0x3F },
155 { SkXfermode::kSrcIn_Mode, "SrcIn", 0x3F },
156 { SkXfermode::kDstIn_Mode, "DstIn", 0x3F },
157 { SkXfermode::kSrcOut_Mode, "SrcOut", 0x3F },
158 { SkXfermode::kDstOut_Mode, "DstOut", 0x3F },
159 { SkXfermode::kSrcATop_Mode, "SrcATop", 0x3F },
160 { SkXfermode::kDstATop_Mode, "DstATop", 0x3F },
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000161
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +0000162 { SkXfermode::kXor_Mode, "Xor", 0x03 },
163 { SkXfermode::kPlus_Mode, "Plus", 0x03 },
164 { SkXfermode::kMultiply_Mode, "Multiply", 0x3F },
165 { SkXfermode::kScreen_Mode, "Screen", 0x03 },
166 { SkXfermode::kOverlay_Mode, "Overlay", 0x03 },
167 { SkXfermode::kDarken_Mode, "Darken", 0x03 },
168 { SkXfermode::kLighten_Mode, "Lighten", 0x03 },
169 { SkXfermode::kColorDodge_Mode, "ColorDodge", 0x03 },
170 { SkXfermode::kColorBurn_Mode, "ColorBurn", 0x03 },
171 { SkXfermode::kHardLight_Mode, "HardLight", 0x03 },
172 { SkXfermode::kSoftLight_Mode, "SoftLight", 0x03 },
173 { SkXfermode::kDifference_Mode, "Difference", 0x03 },
174 { SkXfermode::kExclusion_Mode, "Exclusion", 0x03 },
reed@android.comdd0ac282009-06-20 02:38:16 +0000175 };
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000176
reed@google.comf3c1cc92010-12-23 16:45:33 +0000177 const SkScalar w = SkIntToScalar(W);
178 const SkScalar h = SkIntToScalar(H);
reed@android.comdd0ac282009-06-20 02:38:16 +0000179 SkShader* s = SkShader::CreateBitmapShader(fBG,
180 SkShader::kRepeat_TileMode,
181 SkShader::kRepeat_TileMode);
182 SkMatrix m;
183 m.setScale(SkIntToScalar(6), SkIntToScalar(6));
184 s->setLocalMatrix(m);
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000185
reed@android.comdd0ac282009-06-20 02:38:16 +0000186 SkPaint labelP;
187 labelP.setAntiAlias(true);
188 labelP.setTextAlign(SkPaint::kCenter_Align);
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000189
reed@android.comc9c64222009-06-23 00:09:12 +0000190 const int W = 5;
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000191
reed@android.comdd0ac282009-06-20 02:38:16 +0000192 SkScalar x0 = 0;
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +0000193 SkScalar y0 = 0;
194 for (int sourceType = 1; sourceType <= kMaxSourceType; sourceType *=2) {
195 SkScalar x = x0, y = y0;
reed@android.comdd0ac282009-06-20 02:38:16 +0000196 for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +0000197 if ((gModes[i].fSourceTypeMask & sourceType) == 0) {
198 continue;
199 }
reed@android.comc9c64222009-06-23 00:09:12 +0000200 SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
reed@google.comf3c1cc92010-12-23 16:45:33 +0000201 SkAutoUnref aur(mode);
reed@android.comdd0ac282009-06-20 02:38:16 +0000202 SkRect r;
203 r.set(x, y, x+w, y+h);
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000204
reed@google.comf3c1cc92010-12-23 16:45:33 +0000205 SkPaint p;
reed@android.comdd0ac282009-06-20 02:38:16 +0000206 p.setStyle(SkPaint::kFill_Style);
207 p.setShader(s);
reed@android.comdd0ac282009-06-20 02:38:16 +0000208 canvas->drawRect(r, p);
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000209
reed@google.comf3c1cc92010-12-23 16:45:33 +0000210 canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +0000211 draw_mode(canvas, mode, sourceType, r.fLeft, r.fTop);
reed@google.comf3c1cc92010-12-23 16:45:33 +0000212 canvas->restore();
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000213
reed@google.comf3c1cc92010-12-23 16:45:33 +0000214 r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
215 p.setStyle(SkPaint::kStroke_Style);
216 p.setShader(NULL);
217 canvas->drawRect(r, p);
tomhudson@google.com86bf5c92011-04-26 18:15:03 +0000218
reed@google.comf3c1cc92010-12-23 16:45:33 +0000219#if 1
reed@android.comdd0ac282009-06-20 02:38:16 +0000220 canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
221 x + w/2, y - labelP.getTextSize()/2, labelP);
reed@google.comf3c1cc92010-12-23 16:45:33 +0000222#endif
reed@android.comdd0ac282009-06-20 02:38:16 +0000223 x += w + SkIntToScalar(10);
reed@android.comc9c64222009-06-23 00:09:12 +0000224 if ((i % W) == W - 1) {
reed@android.comdd0ac282009-06-20 02:38:16 +0000225 x = x0;
226 y += h + SkIntToScalar(30);
227 }
228 }
vandebo@chromium.org1c18ca32011-06-24 17:05:17 +0000229 if (y < 320) {
230 if (x > x0) {
231 y += h + SkIntToScalar(30);
232 }
233 y0 = y;
234 } else {
235 x0 += SkIntToScalar(400);
236 y0 = 0;
237 }
reed@android.comdd0ac282009-06-20 02:38:16 +0000238 }
239 s->unref();
240 }
241
242private:
243 typedef GM INHERITED;
244};
245
246//////////////////////////////////////////////////////////////////////////////
247
248static GM* MyFactory(void*) { return new XfermodesGM; }
249static GMRegistry reg(MyFactory);
250
251}