1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 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/SkCanvas.h"
11cb93a386Sopenharmony_ci#include "include/core/SkClipOp.h"
12cb93a386Sopenharmony_ci#include "include/core/SkColor.h"
13cb93a386Sopenharmony_ci#include "include/core/SkFont.h"
14cb93a386Sopenharmony_ci#include "include/core/SkFontTypes.h"
15cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
16cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
17cb93a386Sopenharmony_ci#include "include/core/SkPathBuilder.h"
18cb93a386Sopenharmony_ci#include "include/core/SkPoint.h"
19cb93a386Sopenharmony_ci#include "include/core/SkRect.h"
20cb93a386Sopenharmony_ci#include "include/core/SkScalar.h"
21cb93a386Sopenharmony_ci#include "include/core/SkShader.h"
22cb93a386Sopenharmony_ci#include "include/core/SkSize.h"
23cb93a386Sopenharmony_ci#include "include/core/SkString.h"
24cb93a386Sopenharmony_ci#include "include/core/SkTileMode.h"
25cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h"
26cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
27cb93a386Sopenharmony_ci#include "include/effects/SkGradientShader.h"
28cb93a386Sopenharmony_ci#include "tools/ToolUtils.h"
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_cistatic sk_sp<SkImage> make_img(int w, int h) {
31cb93a386Sopenharmony_ci    auto surf = SkSurface::MakeRaster(SkImageInfo::MakeN32(w, h, kOpaque_SkAlphaType));
32cb93a386Sopenharmony_ci    auto canvas = surf->getCanvas();
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci    SkScalar wScalar = SkIntToScalar(w);
35cb93a386Sopenharmony_ci    SkScalar hScalar = SkIntToScalar(h);
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_ci    SkPoint     pt = { wScalar / 2, hScalar / 2 };
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    SkScalar    radius = 3 * std::max(wScalar, hScalar);
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ci    SkColor colors[] = {SK_ColorDKGRAY,
42cb93a386Sopenharmony_ci                        ToolUtils::color_to_565(0xFF222255),
43cb93a386Sopenharmony_ci                        ToolUtils::color_to_565(0xFF331133),
44cb93a386Sopenharmony_ci                        ToolUtils::color_to_565(0xFF884422),
45cb93a386Sopenharmony_ci                        ToolUtils::color_to_565(0xFF000022),
46cb93a386Sopenharmony_ci                        SK_ColorWHITE,
47cb93a386Sopenharmony_ci                        ToolUtils::color_to_565(0xFFAABBCC)};
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci    SkScalar    pos[] = {0,
50cb93a386Sopenharmony_ci                         SK_Scalar1 / 6,
51cb93a386Sopenharmony_ci                         2 * SK_Scalar1 / 6,
52cb93a386Sopenharmony_ci                         3 * SK_Scalar1 / 6,
53cb93a386Sopenharmony_ci                         4 * SK_Scalar1 / 6,
54cb93a386Sopenharmony_ci                         5 * SK_Scalar1 / 6,
55cb93a386Sopenharmony_ci                         SK_Scalar1};
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_ci    SkPaint paint;
58cb93a386Sopenharmony_ci    SkRect rect = SkRect::MakeWH(wScalar, hScalar);
59cb93a386Sopenharmony_ci    SkMatrix mat = SkMatrix::I();
60cb93a386Sopenharmony_ci    for (int i = 0; i < 4; ++i) {
61cb93a386Sopenharmony_ci        paint.setShader(SkGradientShader::MakeRadial(
62cb93a386Sopenharmony_ci                        pt, radius,
63cb93a386Sopenharmony_ci                        colors, pos,
64cb93a386Sopenharmony_ci                        SK_ARRAY_COUNT(colors),
65cb93a386Sopenharmony_ci                        SkTileMode::kRepeat,
66cb93a386Sopenharmony_ci                        0, &mat));
67cb93a386Sopenharmony_ci        canvas->drawRect(rect, paint);
68cb93a386Sopenharmony_ci        rect.inset(wScalar / 8, hScalar / 8);
69cb93a386Sopenharmony_ci        mat.preTranslate(6 * wScalar, 6 * hScalar);
70cb93a386Sopenharmony_ci        mat.postScale(SK_Scalar1 / 3, SK_Scalar1 / 3);
71cb93a386Sopenharmony_ci    }
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_ci    SkFont font(ToolUtils::create_portable_typeface(), wScalar / 2.2f);
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_ci    paint.setShader(nullptr);
76cb93a386Sopenharmony_ci    paint.setColor(SK_ColorLTGRAY);
77cb93a386Sopenharmony_ci    constexpr char kTxt[] = "Skia";
78cb93a386Sopenharmony_ci    SkPoint texPos = { wScalar / 17, hScalar / 2 + font.getSize() / 2.5f };
79cb93a386Sopenharmony_ci    canvas->drawSimpleText(kTxt, SK_ARRAY_COUNT(kTxt)-1, SkTextEncoding::kUTF8,
80cb93a386Sopenharmony_ci                           texPos.fX, texPos.fY, font, paint);
81cb93a386Sopenharmony_ci    paint.setColor(SK_ColorBLACK);
82cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kStroke_Style);
83cb93a386Sopenharmony_ci    paint.setStrokeWidth(SK_Scalar1);
84cb93a386Sopenharmony_ci    canvas->drawSimpleText(kTxt, SK_ARRAY_COUNT(kTxt)-1, SkTextEncoding::kUTF8,
85cb93a386Sopenharmony_ci                           texPos.fX, texPos.fY, font, paint);
86cb93a386Sopenharmony_ci    return surf->makeImageSnapshot();
87cb93a386Sopenharmony_ci}
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_cinamespace skiagm {
90cb93a386Sopenharmony_ci/**
91cb93a386Sopenharmony_ci * This GM tests convex polygon clips.
92cb93a386Sopenharmony_ci */
93cb93a386Sopenharmony_ciclass ConvexPolyClip : public GM {
94cb93a386Sopenharmony_cipublic:
95cb93a386Sopenharmony_ci    ConvexPolyClip() {
96cb93a386Sopenharmony_ci        this->setBGColor(0xFFFFFFFF);
97cb93a386Sopenharmony_ci    }
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ciprotected:
100cb93a386Sopenharmony_ci    SkString onShortName() override {
101cb93a386Sopenharmony_ci        return SkString("convex_poly_clip");
102cb93a386Sopenharmony_ci    }
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_ci    SkISize onISize() override {
105cb93a386Sopenharmony_ci        // When benchmarking the saveLayer set of draws is skipped.
106cb93a386Sopenharmony_ci        int w = 435;
107cb93a386Sopenharmony_ci        if (kBench_Mode != this->getMode()) {
108cb93a386Sopenharmony_ci            w *= 2;
109cb93a386Sopenharmony_ci        }
110cb93a386Sopenharmony_ci        return SkISize::Make(w, 540);
111cb93a386Sopenharmony_ci    }
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci    void onOnceBeforeDraw() override {
114cb93a386Sopenharmony_ci        // On < c++17, emplace_back() returns a void :(
115cb93a386Sopenharmony_ci        auto emplace_back = [](std::vector<Clip>& clips) -> Clip& {
116cb93a386Sopenharmony_ci            clips.emplace_back();
117cb93a386Sopenharmony_ci            return clips.back();
118cb93a386Sopenharmony_ci        };
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ci        emplace_back(fClips).setPath(SkPath::Polygon({
121cb93a386Sopenharmony_ci            {  5.f,   5.f},
122cb93a386Sopenharmony_ci            {100.f,  20.f},
123cb93a386Sopenharmony_ci            { 15.f, 100.f},
124cb93a386Sopenharmony_ci        }, false));
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci        SkPathBuilder hexagon;
127cb93a386Sopenharmony_ci        constexpr SkScalar kRadius = 45.f;
128cb93a386Sopenharmony_ci        const SkPoint center = { kRadius, kRadius };
129cb93a386Sopenharmony_ci        for (int i = 0; i < 6; ++i) {
130cb93a386Sopenharmony_ci            SkScalar angle = 2 * SK_ScalarPI * i / 6;
131cb93a386Sopenharmony_ci            SkPoint point = { SkScalarCos(angle), SkScalarSin(angle) };
132cb93a386Sopenharmony_ci            point.scale(kRadius);
133cb93a386Sopenharmony_ci            point = center + point;
134cb93a386Sopenharmony_ci            if (0 == i) {
135cb93a386Sopenharmony_ci                hexagon.moveTo(point);
136cb93a386Sopenharmony_ci            } else {
137cb93a386Sopenharmony_ci                hexagon.lineTo(point);
138cb93a386Sopenharmony_ci            }
139cb93a386Sopenharmony_ci        }
140cb93a386Sopenharmony_ci        emplace_back(fClips).setPath(hexagon.snapshot());
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ci        SkMatrix scaleM;
143cb93a386Sopenharmony_ci        scaleM.setScale(1.1f, 0.4f, kRadius, kRadius);
144cb93a386Sopenharmony_ci        emplace_back(fClips).setPath(hexagon.detach().makeTransform(scaleM));
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci        emplace_back(fClips).setRect(SkRect::MakeXYWH(8.3f, 11.6f, 78.2f, 72.6f));
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_ci        SkRect rect = SkRect::MakeLTRB(10.f, 12.f, 80.f, 86.f);
149cb93a386Sopenharmony_ci        SkMatrix rotM;
150cb93a386Sopenharmony_ci        rotM.setRotate(23.f, rect.centerX(), rect.centerY());
151cb93a386Sopenharmony_ci        emplace_back(fClips).setPath(SkPath::Rect(rect).makeTransform(rotM));
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci        fImg = make_img(100, 100);
154cb93a386Sopenharmony_ci    }
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci    void onDraw(SkCanvas* canvas) override {
157cb93a386Sopenharmony_ci        SkScalar y = 0;
158cb93a386Sopenharmony_ci        constexpr SkScalar kMargin = 10.f;
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci        SkPaint bgPaint;
161cb93a386Sopenharmony_ci        bgPaint.setAlpha(0x15);
162cb93a386Sopenharmony_ci        SkISize size = canvas->getBaseLayerSize();
163cb93a386Sopenharmony_ci        canvas->drawImageRect(fImg, SkRect::MakeIWH(size.fWidth, size.fHeight),
164cb93a386Sopenharmony_ci                              SkSamplingOptions(), &bgPaint);
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci        constexpr char kTxt[] = "Clip Me!";
167cb93a386Sopenharmony_ci        SkFont         font(ToolUtils::create_portable_typeface(), 23);
168cb93a386Sopenharmony_ci        SkScalar textW = font.measureText(kTxt, SK_ARRAY_COUNT(kTxt)-1, SkTextEncoding::kUTF8);
169cb93a386Sopenharmony_ci        SkPaint txtPaint;
170cb93a386Sopenharmony_ci        txtPaint.setColor(SK_ColorDKGRAY);
171cb93a386Sopenharmony_ci
172cb93a386Sopenharmony_ci        SkScalar startX = 0;
173cb93a386Sopenharmony_ci        int testLayers = kBench_Mode != this->getMode();
174cb93a386Sopenharmony_ci        for (int doLayer = 0; doLayer <= testLayers; ++doLayer) {
175cb93a386Sopenharmony_ci            for (const Clip& clip : fClips) {
176cb93a386Sopenharmony_ci                SkScalar x = startX;
177cb93a386Sopenharmony_ci                for (int aa = 0; aa < 2; ++aa) {
178cb93a386Sopenharmony_ci                    if (doLayer) {
179cb93a386Sopenharmony_ci                        SkRect bounds;
180cb93a386Sopenharmony_ci                        clip.getBounds(&bounds);
181cb93a386Sopenharmony_ci                        bounds.outset(2, 2);
182cb93a386Sopenharmony_ci                        bounds.offset(x, y);
183cb93a386Sopenharmony_ci                        canvas->saveLayer(&bounds, nullptr);
184cb93a386Sopenharmony_ci                    } else {
185cb93a386Sopenharmony_ci                        canvas->save();
186cb93a386Sopenharmony_ci                    }
187cb93a386Sopenharmony_ci                    canvas->translate(x, y);
188cb93a386Sopenharmony_ci                    clip.setOnCanvas(canvas, SkClipOp::kIntersect, SkToBool(aa));
189cb93a386Sopenharmony_ci                    canvas->drawImage(fImg, 0, 0);
190cb93a386Sopenharmony_ci                    canvas->restore();
191cb93a386Sopenharmony_ci                    x += fImg->width() + kMargin;
192cb93a386Sopenharmony_ci                }
193cb93a386Sopenharmony_ci                for (int aa = 0; aa < 2; ++aa) {
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_ci                    SkPaint clipOutlinePaint;
196cb93a386Sopenharmony_ci                    clipOutlinePaint.setAntiAlias(true);
197cb93a386Sopenharmony_ci                    clipOutlinePaint.setColor(0x50505050);
198cb93a386Sopenharmony_ci                    clipOutlinePaint.setStyle(SkPaint::kStroke_Style);
199cb93a386Sopenharmony_ci                    clipOutlinePaint.setStrokeWidth(0);
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_ci                    if (doLayer) {
202cb93a386Sopenharmony_ci                        SkRect bounds;
203cb93a386Sopenharmony_ci                        clip.getBounds(&bounds);
204cb93a386Sopenharmony_ci                        bounds.outset(2, 2);
205cb93a386Sopenharmony_ci                        bounds.offset(x, y);
206cb93a386Sopenharmony_ci                        canvas->saveLayer(&bounds, nullptr);
207cb93a386Sopenharmony_ci                    } else {
208cb93a386Sopenharmony_ci                        canvas->save();
209cb93a386Sopenharmony_ci                    }
210cb93a386Sopenharmony_ci                    canvas->translate(x, y);
211cb93a386Sopenharmony_ci                    SkPath closedClipPath = clip.asClosedPath();
212cb93a386Sopenharmony_ci                    canvas->drawPath(closedClipPath, clipOutlinePaint);
213cb93a386Sopenharmony_ci                    clip.setOnCanvas(canvas, SkClipOp::kIntersect, SkToBool(aa));
214cb93a386Sopenharmony_ci                    canvas->scale(1.f, 1.8f);
215cb93a386Sopenharmony_ci                    canvas->drawSimpleText(kTxt, SK_ARRAY_COUNT(kTxt)-1, SkTextEncoding::kUTF8,
216cb93a386Sopenharmony_ci                                     0, 1.5f * font.getSize(), font, txtPaint);
217cb93a386Sopenharmony_ci                    canvas->restore();
218cb93a386Sopenharmony_ci                    x += textW + 2 * kMargin;
219cb93a386Sopenharmony_ci                }
220cb93a386Sopenharmony_ci                y += fImg->height() + kMargin;
221cb93a386Sopenharmony_ci            }
222cb93a386Sopenharmony_ci            y = 0;
223cb93a386Sopenharmony_ci            startX += 2 * fImg->width() + SkScalarCeilToInt(2 * textW) + 6 * kMargin;
224cb93a386Sopenharmony_ci        }
225cb93a386Sopenharmony_ci    }
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci    bool runAsBench() const override { return true; }
228cb93a386Sopenharmony_ci
229cb93a386Sopenharmony_ciprivate:
230cb93a386Sopenharmony_ci    class Clip {
231cb93a386Sopenharmony_ci    public:
232cb93a386Sopenharmony_ci        enum ClipType {
233cb93a386Sopenharmony_ci            kNone_ClipType,
234cb93a386Sopenharmony_ci            kPath_ClipType,
235cb93a386Sopenharmony_ci            kRect_ClipType
236cb93a386Sopenharmony_ci        };
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_ci        Clip () : fClipType(kNone_ClipType) {}
239cb93a386Sopenharmony_ci
240cb93a386Sopenharmony_ci        void setOnCanvas(SkCanvas* canvas, SkClipOp op, bool aa) const {
241cb93a386Sopenharmony_ci            switch (fClipType) {
242cb93a386Sopenharmony_ci                case kPath_ClipType:
243cb93a386Sopenharmony_ci                    canvas->clipPath(fPathBuilder.snapshot(), op, aa);
244cb93a386Sopenharmony_ci                    break;
245cb93a386Sopenharmony_ci                case kRect_ClipType:
246cb93a386Sopenharmony_ci                    canvas->clipRect(fRect, op, aa);
247cb93a386Sopenharmony_ci                    break;
248cb93a386Sopenharmony_ci                case kNone_ClipType:
249cb93a386Sopenharmony_ci                    SkDEBUGFAIL("Uninitialized Clip.");
250cb93a386Sopenharmony_ci                    break;
251cb93a386Sopenharmony_ci            }
252cb93a386Sopenharmony_ci        }
253cb93a386Sopenharmony_ci
254cb93a386Sopenharmony_ci        SkPath asClosedPath() const {
255cb93a386Sopenharmony_ci            switch (fClipType) {
256cb93a386Sopenharmony_ci                case kPath_ClipType:
257cb93a386Sopenharmony_ci                    return SkPathBuilder(fPathBuilder).close().detach();
258cb93a386Sopenharmony_ci                    break;
259cb93a386Sopenharmony_ci                case kRect_ClipType:
260cb93a386Sopenharmony_ci                    return SkPath::Rect(fRect);
261cb93a386Sopenharmony_ci                case kNone_ClipType:
262cb93a386Sopenharmony_ci                    SkDEBUGFAIL("Uninitialized Clip.");
263cb93a386Sopenharmony_ci                    break;
264cb93a386Sopenharmony_ci            }
265cb93a386Sopenharmony_ci            return SkPath();
266cb93a386Sopenharmony_ci        }
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci        void setPath(const SkPath& path) {
269cb93a386Sopenharmony_ci            fClipType = kPath_ClipType;
270cb93a386Sopenharmony_ci            fPathBuilder = path;
271cb93a386Sopenharmony_ci        }
272cb93a386Sopenharmony_ci
273cb93a386Sopenharmony_ci        void setRect(const SkRect& rect) {
274cb93a386Sopenharmony_ci            fClipType = kRect_ClipType;
275cb93a386Sopenharmony_ci            fRect = rect;
276cb93a386Sopenharmony_ci            fPathBuilder.reset();
277cb93a386Sopenharmony_ci        }
278cb93a386Sopenharmony_ci
279cb93a386Sopenharmony_ci        ClipType getType() const { return fClipType; }
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci        void getBounds(SkRect* bounds) const {
282cb93a386Sopenharmony_ci            switch (fClipType) {
283cb93a386Sopenharmony_ci                case kPath_ClipType:
284cb93a386Sopenharmony_ci                    *bounds = fPathBuilder.computeBounds();
285cb93a386Sopenharmony_ci                    break;
286cb93a386Sopenharmony_ci                case kRect_ClipType:
287cb93a386Sopenharmony_ci                    *bounds = fRect;
288cb93a386Sopenharmony_ci                    break;
289cb93a386Sopenharmony_ci                case kNone_ClipType:
290cb93a386Sopenharmony_ci                    SkDEBUGFAIL("Uninitialized Clip.");
291cb93a386Sopenharmony_ci                    break;
292cb93a386Sopenharmony_ci            }
293cb93a386Sopenharmony_ci        }
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_ci    private:
296cb93a386Sopenharmony_ci        ClipType fClipType;
297cb93a386Sopenharmony_ci        SkPathBuilder fPathBuilder;
298cb93a386Sopenharmony_ci        SkRect fRect;
299cb93a386Sopenharmony_ci    };
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_ci    std::vector<Clip> fClips;
302cb93a386Sopenharmony_ci    sk_sp<SkImage>    fImg;;
303cb93a386Sopenharmony_ci
304cb93a386Sopenharmony_ci    using INHERITED = GM;
305cb93a386Sopenharmony_ci};
306cb93a386Sopenharmony_ci
307cb93a386Sopenharmony_ciDEF_GM(return new ConvexPolyClip;)
308cb93a386Sopenharmony_ci}  // namespace skiagm
309