complexclip.cpp revision dbfd7ab10883f173f5c1b653a233e18dc6142002
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#include "gm.h"
8#include "SkCanvas.h"
9//#include "SkParsePath.h"
10#include "SkPath.h"
11//#include "SkRandom.h"
12
13namespace skiagm {
14
15constexpr SkColor gPathColor = SK_ColorBLACK;
16constexpr SkColor gClipAColor = SK_ColorBLUE;
17constexpr SkColor gClipBColor = SK_ColorRED;
18
19class ComplexClipGM : public GM {
20public:
21    ComplexClipGM(bool aaclip, bool saveLayer, bool invertDraw)
22    : fDoAAClip(aaclip)
23    , fDoSaveLayer(saveLayer)
24    , fInvertDraw(invertDraw) {
25        this->setBGColor(0xFFDEDFDE);
26    }
27
28protected:
29
30
31    SkString onShortName() {
32        SkString str;
33        str.printf("complexclip_%s%s%s",
34                   fDoAAClip ? "aa" : "bw",
35                   fDoSaveLayer ? "_layer" : "",
36                   fInvertDraw ? "_invert" : "");
37        return str;
38    }
39
40    SkISize onISize() { return SkISize::Make(970, 780); }
41
42    virtual void onDraw(SkCanvas* canvas) {
43        SkPath path;
44        path.moveTo(SkIntToScalar(0),   SkIntToScalar(50));
45        path.quadTo(SkIntToScalar(0),   SkIntToScalar(0),   SkIntToScalar(50),  SkIntToScalar(0));
46        path.lineTo(SkIntToScalar(175), SkIntToScalar(0));
47        path.quadTo(SkIntToScalar(200), SkIntToScalar(0),   SkIntToScalar(200), SkIntToScalar(25));
48        path.lineTo(SkIntToScalar(200), SkIntToScalar(150));
49        path.quadTo(SkIntToScalar(200), SkIntToScalar(200), SkIntToScalar(150), SkIntToScalar(200));
50        path.lineTo(SkIntToScalar(0),   SkIntToScalar(200));
51        path.close();
52        path.moveTo(SkIntToScalar(50),  SkIntToScalar(50));
53        path.lineTo(SkIntToScalar(150), SkIntToScalar(50));
54        path.lineTo(SkIntToScalar(150), SkIntToScalar(125));
55        path.quadTo(SkIntToScalar(150), SkIntToScalar(150), SkIntToScalar(125), SkIntToScalar(150));
56        path.lineTo(SkIntToScalar(50),  SkIntToScalar(150));
57        path.close();
58        if (fInvertDraw) {
59            path.setFillType(SkPath::kInverseEvenOdd_FillType);
60        } else {
61            path.setFillType(SkPath::kEvenOdd_FillType);
62        }
63        SkPaint pathPaint;
64        pathPaint.setAntiAlias(true);
65        pathPaint.setColor(gPathColor);
66
67        SkPath clipA;
68        clipA.moveTo(SkIntToScalar(10),  SkIntToScalar(20));
69        clipA.lineTo(SkIntToScalar(165), SkIntToScalar(22));
70        clipA.lineTo(SkIntToScalar(70),  SkIntToScalar(105));
71        clipA.lineTo(SkIntToScalar(165), SkIntToScalar(177));
72        clipA.lineTo(SkIntToScalar(-5),  SkIntToScalar(180));
73        clipA.close();
74
75        SkPath clipB;
76        clipB.moveTo(SkIntToScalar(40),  SkIntToScalar(10));
77        clipB.lineTo(SkIntToScalar(190), SkIntToScalar(15));
78        clipB.lineTo(SkIntToScalar(195), SkIntToScalar(190));
79        clipB.lineTo(SkIntToScalar(40),  SkIntToScalar(185));
80        clipB.lineTo(SkIntToScalar(155), SkIntToScalar(100));
81        clipB.close();
82
83        SkPaint paint;
84        paint.setAntiAlias(true);
85        sk_tool_utils::set_portable_typeface(&paint);
86        paint.setTextSize(SkIntToScalar(20));
87
88        constexpr struct {
89            SkRegion::Op fOp;
90            const char*  fName;
91        } gOps[] = { //extra spaces in names for measureText
92            {SkRegion::kIntersect_Op,         "Isect "},
93            {SkRegion::kDifference_Op,        "Diff " },
94            {SkRegion::kUnion_Op,             "Union "},
95            {SkRegion::kXOR_Op,               "Xor "  },
96            {SkRegion::kReverseDifference_Op, "RDiff "}
97        };
98
99        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
100        canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4);
101
102        if (fDoSaveLayer) {
103            // We want the layer to appear symmetric relative to actual
104            // device boundaries so we need to "undo" the effect of the
105            // scale and translate
106            SkRect bounds = SkRect::MakeLTRB(
107              4.0f/3.0f * -20,
108              4.0f/3.0f * -20,
109              4.0f/3.0f * (this->getISize().fWidth - 20),
110              4.0f/3.0f * (this->getISize().fHeight - 20));
111
112            bounds.inset(SkIntToScalar(100), SkIntToScalar(100));
113            SkPaint boundPaint;
114            boundPaint.setColor(SK_ColorRED);
115            boundPaint.setStyle(SkPaint::kStroke_Style);
116            canvas->drawRect(bounds, boundPaint);
117            canvas->saveLayer(&bounds, nullptr);
118        }
119
120        for (int invBits = 0; invBits < 4; ++invBits) {
121            canvas->save();
122            for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
123                this->drawHairlines(canvas, path, clipA, clipB);
124
125                bool doInvA = SkToBool(invBits & 1);
126                bool doInvB = SkToBool(invBits & 2);
127                canvas->save();
128                    // set clip
129                    clipA.setFillType(doInvA ? SkPath::kInverseEvenOdd_FillType :
130                                      SkPath::kEvenOdd_FillType);
131                    clipB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType :
132                                      SkPath::kEvenOdd_FillType);
133                    canvas->clipPath(clipA, SkRegion::kIntersect_Op, fDoAAClip);
134                    canvas->clipPath(clipB, gOps[op].fOp, fDoAAClip);
135
136                    // In the inverse case we need to prevent the draw from covering the whole
137                    // canvas.
138                    if (fInvertDraw) {
139                        SkRect rectClip = clipA.getBounds();
140                        rectClip.join(path.getBounds());
141                        rectClip.join(path.getBounds());
142                        rectClip.outset(5, 5);
143                        canvas->clipRect(rectClip);
144                    }
145
146                    // draw path clipped
147                    canvas->drawPath(path, pathPaint);
148                canvas->restore();
149
150
151                SkScalar txtX = SkIntToScalar(45);
152                paint.setColor(gClipAColor);
153                const char* aTxt = doInvA ? "InvA " : "A ";
154                canvas->drawText(aTxt, strlen(aTxt), txtX, SkIntToScalar(220), paint);
155                txtX += paint.measureText(aTxt, strlen(aTxt));
156                paint.setColor(SK_ColorBLACK);
157                canvas->drawText(gOps[op].fName, strlen(gOps[op].fName),
158                                    txtX, SkIntToScalar(220), paint);
159                txtX += paint.measureText(gOps[op].fName, strlen(gOps[op].fName));
160                paint.setColor(gClipBColor);
161                const char* bTxt = doInvB ? "InvB " : "B ";
162                canvas->drawText(bTxt, strlen(bTxt), txtX, SkIntToScalar(220), paint);
163
164                canvas->translate(SkIntToScalar(250),0);
165            }
166            canvas->restore();
167            canvas->translate(0, SkIntToScalar(250));
168        }
169
170        if (fDoSaveLayer) {
171            canvas->restore();
172        }
173    }
174private:
175    void drawHairlines(SkCanvas* canvas, const SkPath& path,
176                       const SkPath& clipA, const SkPath& clipB) {
177        SkPaint paint;
178        paint.setAntiAlias(true);
179        paint.setStyle(SkPaint::kStroke_Style);
180        const SkAlpha fade = 0x33;
181
182        // draw path in hairline
183        paint.setColor(gPathColor); paint.setAlpha(fade);
184        canvas->drawPath(path, paint);
185
186        // draw clips in hair line
187        paint.setColor(gClipAColor); paint.setAlpha(fade);
188        canvas->drawPath(clipA, paint);
189        paint.setColor(gClipBColor); paint.setAlpha(fade);
190        canvas->drawPath(clipB, paint);
191    }
192
193    bool fDoAAClip;
194    bool fDoSaveLayer;
195    bool fInvertDraw;
196
197    typedef GM INHERITED;
198};
199
200//////////////////////////////////////////////////////////////////////////////
201
202DEF_GM(return new ComplexClipGM(false, false, false);)
203DEF_GM(return new ComplexClipGM(false, false, true);)
204DEF_GM(return new ComplexClipGM(false, true, false);)
205DEF_GM(return new ComplexClipGM(false, true, true);)
206DEF_GM(return new ComplexClipGM(true, false, false);)
207DEF_GM(return new ComplexClipGM(true, false, true);)
208DEF_GM(return new ComplexClipGM(true, true, false);)
209DEF_GM(return new ComplexClipGM(true, true, true);)
210}
211