• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkClipOp.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkFont.h"
13 #include "include/core/SkFontTypes.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPath.h"
16 #include "include/core/SkRect.h"
17 #include "include/core/SkScalar.h"
18 #include "include/core/SkSize.h"
19 #include "include/core/SkString.h"
20 #include "include/core/SkTypeface.h"
21 #include "include/core/SkTypes.h"
22 #include "src/core/SkClipOpPriv.h"
23 #include "tools/ToolUtils.h"
24 
25 #include <string.h>
26 
27 namespace skiagm {
28 
29 constexpr SkColor gPathColor = SK_ColorBLACK;
30 constexpr SkColor gClipAColor = SK_ColorBLUE;
31 constexpr SkColor gClipBColor = SK_ColorRED;
32 
33 class ComplexClipGM : public GM {
34 public:
ComplexClipGM(bool aaclip,bool saveLayer,bool invertDraw)35     ComplexClipGM(bool aaclip, bool saveLayer, bool invertDraw)
36     : fDoAAClip(aaclip)
37     , fDoSaveLayer(saveLayer)
38     , fInvertDraw(invertDraw) {
39         this->setBGColor(0xFFDEDFDE);
40     }
41 
42 protected:
onShortName()43     SkString onShortName() override {
44         SkString str;
45         str.printf("complexclip_%s%s%s",
46                    fDoAAClip ? "aa" : "bw",
47                    fDoSaveLayer ? "_layer" : "",
48                    fInvertDraw ? "_invert" : "");
49         return str;
50     }
51 
onISize()52     SkISize onISize() override { return SkISize::Make(970, 780); }
53 
onDraw(SkCanvas * canvas)54     void onDraw(SkCanvas* canvas) override {
55         SkPath path;
56         path.moveTo(0,   50)
57             .quadTo(0,   0,   50,  0)
58             .lineTo(175, 0)
59             .quadTo(200, 0,   200, 25)
60             .lineTo(200, 150)
61             .quadTo(200, 200, 150, 200)
62             .lineTo(0,   200)
63             .close()
64             .moveTo(50,  50)
65             .lineTo(150, 50)
66             .lineTo(150, 125)
67             .quadTo(150, 150, 125, 150)
68             .lineTo(50,  150)
69             .close();
70         if (fInvertDraw) {
71             path.setFillType(SkPath::kInverseEvenOdd_FillType);
72         } else {
73             path.setFillType(SkPath::kEvenOdd_FillType);
74         }
75         SkPaint pathPaint;
76         pathPaint.setAntiAlias(true);
77         pathPaint.setColor(gPathColor);
78 
79         SkPath clipA;
80         clipA.addPoly({{10,  20}, {165, 22}, {70,  105}, {165, 177}, {-5,  180}}, false).close();
81 
82         SkPath clipB;
83         clipB.addPoly({{40,  10}, {190, 15}, {195, 190}, {40,  185}, {155, 100}}, false).close();
84 
85         SkFont font(ToolUtils::create_portable_typeface(), 20);
86 
87         constexpr struct {
88             SkClipOp fOp;
89             const char*      fName;
90         } gOps[] = { //extra spaces in names for measureText
91             {kIntersect_SkClipOp,         "Isect "},
92             {kDifference_SkClipOp,        "Diff " },
93             {kUnion_SkClipOp,             "Union "},
94             {kXOR_SkClipOp,               "Xor "  },
95             {kReverseDifference_SkClipOp, "RDiff "}
96         };
97 
98         canvas->translate(20, 20);
99         canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4);
100 
101         if (fDoSaveLayer) {
102             // We want the layer to appear symmetric relative to actual
103             // device boundaries so we need to "undo" the effect of the
104             // scale and translate
105             SkRect bounds = SkRect::MakeLTRB(
106               4.0f/3.0f * -20,
107               4.0f/3.0f * -20,
108               4.0f/3.0f * (this->getISize().fWidth - 20),
109               4.0f/3.0f * (this->getISize().fHeight - 20));
110 
111             bounds.inset(100, 100);
112             SkPaint boundPaint;
113             boundPaint.setColor(SK_ColorRED);
114             boundPaint.setStyle(SkPaint::kStroke_Style);
115             canvas->drawRect(bounds, boundPaint);
116             canvas->clipRect(bounds);
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, 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                 SkPaint paint;
152                 SkScalar txtX = 45;
153                 paint.setColor(gClipAColor);
154                 const char* aTxt = doInvA ? "InvA " : "A ";
155                 canvas->drawSimpleText(aTxt, strlen(aTxt), SkTextEncoding::kUTF8, txtX, 220, font, paint);
156                 txtX += font.measureText(aTxt, strlen(aTxt), SkTextEncoding::kUTF8);
157                 paint.setColor(SK_ColorBLACK);
158                 canvas->drawSimpleText(gOps[op].fName, strlen(gOps[op].fName), SkTextEncoding::kUTF8, txtX, 220,
159                                        font, paint);
160                 txtX += font.measureText(gOps[op].fName, strlen(gOps[op].fName), SkTextEncoding::kUTF8);
161                 paint.setColor(gClipBColor);
162                 const char* bTxt = doInvB ? "InvB " : "B ";
163                 canvas->drawSimpleText(bTxt, strlen(bTxt), SkTextEncoding::kUTF8, txtX, 220, font, paint);
164 
165                 canvas->translate(250,0);
166             }
167             canvas->restore();
168             canvas->translate(0, 250);
169         }
170 
171         if (fDoSaveLayer) {
172             canvas->restore();
173         }
174     }
175 private:
drawHairlines(SkCanvas * canvas,const SkPath & path,const SkPath & clipA,const SkPath & clipB)176     void drawHairlines(SkCanvas* canvas, const SkPath& path,
177                        const SkPath& clipA, const SkPath& clipB) {
178         SkPaint paint;
179         paint.setAntiAlias(true);
180         paint.setStyle(SkPaint::kStroke_Style);
181         const SkAlpha fade = 0x33;
182 
183         // draw path in hairline
184         paint.setColor(gPathColor); paint.setAlpha(fade);
185         canvas->drawPath(path, paint);
186 
187         // draw clips in hair line
188         paint.setColor(gClipAColor); paint.setAlpha(fade);
189         canvas->drawPath(clipA, paint);
190         paint.setColor(gClipBColor); paint.setAlpha(fade);
191         canvas->drawPath(clipB, paint);
192     }
193 
194     bool fDoAAClip;
195     bool fDoSaveLayer;
196     bool fInvertDraw;
197 
198     typedef GM INHERITED;
199 };
200 
201 //////////////////////////////////////////////////////////////////////////////
202 
203 DEF_GM(return new ComplexClipGM(false, false, false);)
204 DEF_GM(return new ComplexClipGM(false, false, true);)
205 DEF_GM(return new ComplexClipGM(false, true, false);)
206 DEF_GM(return new ComplexClipGM(false, true, true);)
207 DEF_GM(return new ComplexClipGM(true, false, false);)
208 DEF_GM(return new ComplexClipGM(true, false, true);)
209 DEF_GM(return new ComplexClipGM(true, true, false);)
210 DEF_GM(return new ComplexClipGM(true, true, true);)
211 }
212