604a767a4fb482bc21d1d3edc1195a76481ebbb3
[platform/upstream/libSkiaSharp.git] / gm / xfermodes.cpp
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 "SkBitmap.h"
10 #include "SkShader.h"
11 #include "SkXfermode.h"
12 #include "SkPM4f.h"
13
14 enum 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
36 const struct {
37     SkBlendMode fMode;
38     const char* fLabel;
39     int         fSourceTypeMask;  // The source types to use this
40     // mode with. See draw_mode for
41     // an explanation of each type.
42     // PDF has to play some tricks
43     // to support the base modes,
44     // test those more extensively.
45 } gModes[] = {
46     { SkBlendMode::kClear,        "Clear",        kAll_SrcType   },
47     { SkBlendMode::kSrc,          "Src",          kAll_SrcType   },
48     { SkBlendMode::kDst,          "Dst",          kAll_SrcType   },
49     { SkBlendMode::kSrcOver,      "SrcOver",      kAll_SrcType   },
50     { SkBlendMode::kDstOver,      "DstOver",      kAll_SrcType   },
51     { SkBlendMode::kSrcIn,        "SrcIn",        kAll_SrcType   },
52     { SkBlendMode::kDstIn,        "DstIn",        kAll_SrcType   },
53     { SkBlendMode::kSrcOut,       "SrcOut",       kAll_SrcType   },
54     { SkBlendMode::kDstOut,       "DstOut",       kAll_SrcType   },
55     { SkBlendMode::kSrcATop,      "SrcATop",      kAll_SrcType   },
56     { SkBlendMode::kDstATop,      "DstATop",      kAll_SrcType   },
57
58     { SkBlendMode::kXor,          "Xor",          kBasic_SrcType },
59     { SkBlendMode::kPlus,         "Plus",         kBasic_SrcType },
60     { SkBlendMode::kModulate,     "Modulate",     kAll_SrcType   },
61     { SkBlendMode::kScreen,       "Screen",       kBasic_SrcType },
62     { SkBlendMode::kOverlay,      "Overlay",      kBasic_SrcType },
63     { SkBlendMode::kDarken,       "Darken",       kBasic_SrcType },
64     { SkBlendMode::kLighten,      "Lighten",      kBasic_SrcType },
65     { SkBlendMode::kColorDodge,   "ColorDodge",   kBasic_SrcType },
66     { SkBlendMode::kColorBurn,    "ColorBurn",    kBasic_SrcType },
67     { SkBlendMode::kHardLight,    "HardLight",    kBasic_SrcType },
68     { SkBlendMode::kSoftLight,    "SoftLight",    kBasic_SrcType },
69     { SkBlendMode::kDifference,   "Difference",   kBasic_SrcType },
70     { SkBlendMode::kExclusion,    "Exclusion",    kBasic_SrcType },
71     { SkBlendMode::kMultiply,     "Multiply",     kAll_SrcType   },
72     { SkBlendMode::kHue,          "Hue",          kBasic_SrcType },
73     { SkBlendMode::kSaturation,   "Saturation",   kBasic_SrcType },
74     { SkBlendMode::kColor,        "Color",        kBasic_SrcType },
75     { SkBlendMode::kLuminosity,   "Luminosity",   kBasic_SrcType },
76 };
77
78 static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst,
79                          SkBitmap* transparent) {
80     src->allocN32Pixels(w, h);
81     src->eraseColor(SK_ColorTRANSPARENT);
82
83     SkPaint p;
84     p.setAntiAlias(true);
85
86     SkRect r;
87     SkScalar ww = SkIntToScalar(w);
88     SkScalar hh = SkIntToScalar(h);
89
90     {
91         SkCanvas c(*src);
92         p.setColor(sk_tool_utils::color_to_565(0xFFFFCC44));
93         r.set(0, 0, ww*3/4, hh*3/4);
94         c.drawOval(r, p);
95     }
96
97     dst->allocN32Pixels(w, h);
98     dst->eraseColor(SK_ColorTRANSPARENT);
99
100     {
101         SkCanvas c(*dst);
102         p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
103         r.set(ww/3, hh/3, ww*19/20, hh*19/20);
104         c.drawRect(r, p);
105     }
106
107     transparent->allocN32Pixels(w, h);
108     transparent->eraseColor(SK_ColorTRANSPARENT);
109 }
110
111 static uint16_t gData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
112
113 class XfermodesGM : public skiagm::GM {
114     SkBitmap    fBG;
115     SkBitmap    fSrcB, fDstB, fTransparent;
116
117     /* The srcType argument indicates what to draw for the source part. Skia
118      * uses the implied shape of the drawing command and these modes
119      * demonstrate that.
120      */
121     void draw_mode(SkCanvas* canvas, SkBlendMode mode, SrcType srcType, SkScalar x, SkScalar y) {
122         SkPaint p;
123         SkMatrix m;
124         bool restoreNeeded = false;
125         m.setTranslate(x, y);
126
127         canvas->drawBitmap(fSrcB, x, y, &p);
128         p.setBlendMode(mode);
129         switch (srcType) {
130             case kSmallTransparentImage_SrcType: {
131                 m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);
132
133                 SkAutoCanvasRestore acr(canvas, true);
134                 canvas->concat(m);
135                 canvas->drawBitmap(fTransparent, 0, 0, &p);
136                 break;
137             }
138             case kQuarterClearInLayer_SrcType: {
139                 SkRect bounds = SkRect::MakeXYWH(x, y, SkIntToScalar(W),
140                                                  SkIntToScalar(H));
141                 canvas->saveLayer(&bounds, &p);
142                 restoreNeeded = true;
143                 p.setBlendMode(SkBlendMode::kSrcOver);
144                 // Fall through.
145             }
146             case kQuarterClear_SrcType: {
147                 SkScalar halfW = SkIntToScalar(W) / 2;
148                 SkScalar halfH = SkIntToScalar(H) / 2;
149                 p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
150                 SkRect r = SkRect::MakeXYWH(x + halfW, y, halfW,
151                                             SkIntToScalar(H));
152                 canvas->drawRect(r, p);
153                 p.setColor(sk_tool_utils::color_to_565(0xFFAA66FF));
154                 r = SkRect::MakeXYWH(x, y + halfH, SkIntToScalar(W), halfH);
155                 canvas->drawRect(r, p);
156                 break;
157             }
158             case kRectangleWithMask_SrcType: {
159                 canvas->save();
160                 restoreNeeded = true;
161                 SkScalar w = SkIntToScalar(W);
162                 SkScalar h = SkIntToScalar(H);
163                 SkRect r = SkRect::MakeXYWH(x, y + h / 4, w, h * 23 / 60);
164                 canvas->clipRect(r);
165                 // Fall through.
166             }
167             case kRectangle_SrcType: {
168                 SkScalar w = SkIntToScalar(W);
169                 SkScalar h = SkIntToScalar(H);
170                 SkRect r = SkRect::MakeXYWH(x + w / 3, y + h / 3,
171                                             w * 37 / 60, h * 37 / 60);
172                 p.setColor(sk_tool_utils::color_to_565(0xFF66AAFF));
173                 canvas->drawRect(r, p);
174                 break;
175             }
176             case kSmallRectangleImageWithAlpha_SrcType:
177                 m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);
178                 // Fall through.
179             case kRectangleImageWithAlpha_SrcType:
180                 p.setAlpha(0x88);
181                 // Fall through.
182             case kRectangleImage_SrcType: {
183                 SkAutoCanvasRestore acr(canvas, true);
184                 canvas->concat(m);
185                 canvas->drawBitmap(fDstB, 0, 0, &p);
186                 break;
187             }
188             default:
189                 break;
190         }
191
192         if (restoreNeeded) {
193             canvas->restore();
194         }
195     }
196
197     void onOnceBeforeDraw() override {
198         fBG.installPixels(SkImageInfo::Make(2, 2, kARGB_4444_SkColorType,
199                                             kOpaque_SkAlphaType),
200                           gData, 4);
201
202         make_bitmaps(W, H, &fSrcB, &fDstB, &fTransparent);
203     }
204
205 public:
206     const static int W = 64;
207     const static int H = 64;
208     XfermodesGM() {}
209
210 protected:
211     SkString onShortName() override {
212         return SkString("xfermodes");
213     }
214
215     SkISize onISize() override {
216         return SkISize::Make(1990, 570);
217     }
218
219     void onDraw(SkCanvas* canvas) override {
220         canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
221
222         const SkScalar w = SkIntToScalar(W);
223         const SkScalar h = SkIntToScalar(H);
224         SkMatrix m;
225         m.setScale(SkIntToScalar(6), SkIntToScalar(6));
226         auto s = SkShader::MakeBitmapShader(fBG, SkShader::kRepeat_TileMode,
227                                             SkShader::kRepeat_TileMode, &m);
228
229         SkPaint labelP;
230         labelP.setAntiAlias(true);
231         sk_tool_utils::set_portable_typeface(&labelP);
232         labelP.setTextAlign(SkPaint::kCenter_Align);
233
234         const int W = 5;
235
236         SkScalar x0 = 0;
237         SkScalar y0 = 0;
238         for (int sourceType = 1; sourceType & kAll_SrcType; sourceType <<= 1) {
239             SkScalar x = x0, y = y0;
240             for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
241                 if ((gModes[i].fSourceTypeMask & sourceType) == 0) {
242                     continue;
243                 }
244                 SkRect r{ x, y, x+w, y+h };
245
246                 SkPaint p;
247                 p.setStyle(SkPaint::kFill_Style);
248                 p.setShader(s);
249                 canvas->drawRect(r, p);
250
251                 canvas->saveLayer(&r, nullptr);
252                 draw_mode(canvas, gModes[i].fMode, static_cast<SrcType>(sourceType),
253                           r.fLeft, r.fTop);
254                 canvas->restore();
255
256                 r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
257                 p.setStyle(SkPaint::kStroke_Style);
258                 p.setShader(nullptr);
259                 canvas->drawRect(r, p);
260
261 #if 1
262                 canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
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
283 private:
284     typedef GM INHERITED;
285 };
286 DEF_GM( return new XfermodesGM; )