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