blob: 264564d22704c80219074e8b784f39f8abf01c64 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
Mike Reedebfce6d2016-12-12 10:02:12 -05007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
9#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040010#include "include/core/SkClipOp.h"
11#include "include/core/SkColor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkFont.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040013#include "include/core/SkFontTypes.h"
14#include "include/core/SkPaint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "include/core/SkPath.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040016#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"
Mike Reed121c2af2020-03-10 14:02:56 -040023#include "tools/Resources.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "tools/ToolUtils.h"
bsalomon@google.com807cec42011-03-10 19:20:15 +000025
Ben Wagner7fde8e12019-05-01 17:28:53 -040026#include <string.h>
27
bsalomon@google.com807cec42011-03-10 19:20:15 +000028namespace skiagm {
29
mtkleindbfd7ab2016-09-01 11:24:54 -070030constexpr SkColor gPathColor = SK_ColorBLACK;
31constexpr SkColor gClipAColor = SK_ColorBLUE;
32constexpr SkColor gClipBColor = SK_ColorRED;
reed@google.coma8f60f22011-12-08 16:18:29 +000033
bsalomon@google.com807cec42011-03-10 19:20:15 +000034class ComplexClipGM : public GM {
35public:
bsalomon6ae83cf2014-12-17 14:38:49 -080036 ComplexClipGM(bool aaclip, bool saveLayer, bool invertDraw)
robertphillips@google.com50a69a02012-07-12 13:48:46 +000037 : fDoAAClip(aaclip)
bsalomon6ae83cf2014-12-17 14:38:49 -080038 , fDoSaveLayer(saveLayer)
39 , fInvertDraw(invertDraw) {
caryclarkceb9f3b2015-06-12 10:00:11 -070040 this->setBGColor(0xFFDEDFDE);
bsalomon@google.com807cec42011-03-10 19:20:15 +000041 }
42
43protected:
Mike Reedbc414ed2018-08-16 22:49:55 -040044 SkString onShortName() override {
reed@google.coma8f60f22011-12-08 16:18:29 +000045 SkString str;
bsalomon6ae83cf2014-12-17 14:38:49 -080046 str.printf("complexclip_%s%s%s",
robertphillips@google.com50a69a02012-07-12 13:48:46 +000047 fDoAAClip ? "aa" : "bw",
bsalomon6ae83cf2014-12-17 14:38:49 -080048 fDoSaveLayer ? "_layer" : "",
49 fInvertDraw ? "_invert" : "");
reed@google.coma8f60f22011-12-08 16:18:29 +000050 return str;
bsalomon@google.com807cec42011-03-10 19:20:15 +000051 }
52
Mike Reedbc414ed2018-08-16 22:49:55 -040053 SkISize onISize() override { return SkISize::Make(970, 780); }
bsalomon@google.com807cec42011-03-10 19:20:15 +000054
Mike Reedbc414ed2018-08-16 22:49:55 -040055 void onDraw(SkCanvas* canvas) override {
bsalomon@google.com807cec42011-03-10 19:20:15 +000056 SkPath path;
Mike Reedbc414ed2018-08-16 22:49:55 -040057 path.moveTo(0, 50)
58 .quadTo(0, 0, 50, 0)
59 .lineTo(175, 0)
60 .quadTo(200, 0, 200, 25)
61 .lineTo(200, 150)
62 .quadTo(200, 200, 150, 200)
63 .lineTo(0, 200)
64 .close()
65 .moveTo(50, 50)
66 .lineTo(150, 50)
67 .lineTo(150, 125)
68 .quadTo(150, 150, 125, 150)
69 .lineTo(50, 150)
70 .close();
bsalomon6ae83cf2014-12-17 14:38:49 -080071 if (fInvertDraw) {
Mike Reed7d34dc72019-11-26 12:17:17 -050072 path.setFillType(SkPathFillType::kInverseEvenOdd);
bsalomon6ae83cf2014-12-17 14:38:49 -080073 } else {
Mike Reed7d34dc72019-11-26 12:17:17 -050074 path.setFillType(SkPathFillType::kEvenOdd);
bsalomon6ae83cf2014-12-17 14:38:49 -080075 }
bsalomon@google.com807cec42011-03-10 19:20:15 +000076 SkPaint pathPaint;
77 pathPaint.setAntiAlias(true);
reed@google.coma8f60f22011-12-08 16:18:29 +000078 pathPaint.setColor(gPathColor);
bsalomon@google.com807cec42011-03-10 19:20:15 +000079
80 SkPath clipA;
Mike Reedbc414ed2018-08-16 22:49:55 -040081 clipA.addPoly({{10, 20}, {165, 22}, {70, 105}, {165, 177}, {-5, 180}}, false).close();
bsalomon@google.com807cec42011-03-10 19:20:15 +000082
83 SkPath clipB;
Mike Reedbc414ed2018-08-16 22:49:55 -040084 clipB.addPoly({{40, 10}, {190, 15}, {195, 190}, {40, 185}, {155, 100}}, false).close();
bsalomon@google.com807cec42011-03-10 19:20:15 +000085
Mike Kleinea3f0142019-03-20 11:12:10 -050086 SkFont font(ToolUtils::create_portable_typeface(), 20);
bsalomon@google.com807cec42011-03-10 19:20:15 +000087
mtkleindbfd7ab2016-09-01 11:24:54 -070088 constexpr struct {
Mike Reedc1f77742016-12-09 09:00:50 -050089 SkClipOp fOp;
reed73603f32016-09-20 08:42:38 -070090 const char* fName;
bsalomon@google.com807cec42011-03-10 19:20:15 +000091 } gOps[] = { //extra spaces in names for measureText
Mike Reedc1f77742016-12-09 09:00:50 -050092 {kIntersect_SkClipOp, "Isect "},
93 {kDifference_SkClipOp, "Diff " },
94 {kUnion_SkClipOp, "Union "},
95 {kXOR_SkClipOp, "Xor " },
96 {kReverseDifference_SkClipOp, "RDiff "}
bsalomon@google.com807cec42011-03-10 19:20:15 +000097 };
98
Mike Reedbc414ed2018-08-16 22:49:55 -040099 canvas->translate(20, 20);
bsalomon@google.com807cec42011-03-10 19:20:15 +0000100 canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4);
bsalomon@google.com807cec42011-03-10 19:20:15 +0000101
robertphillips@google.com54bb7ab2012-07-13 14:55:25 +0000102 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(
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000107 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));
robertphillips@google.com54bb7ab2012-07-13 14:55:25 +0000111
Mike Reedbc414ed2018-08-16 22:49:55 -0400112 bounds.inset(100, 100);
robertphillips@google.com50a69a02012-07-12 13:48:46 +0000113 SkPaint boundPaint;
114 boundPaint.setColor(SK_ColorRED);
115 boundPaint.setStyle(SkPaint::kStroke_Style);
116 canvas->drawRect(bounds, boundPaint);
Ben Wagner788a2dc2018-05-09 13:23:38 -0400117 canvas->clipRect(bounds);
halcanary96fcdcc2015-08-27 07:41:13 -0700118 canvas->saveLayer(&bounds, nullptr);
robertphillips@google.com50a69a02012-07-12 13:48:46 +0000119 }
120
reed@google.coma8f60f22011-12-08 16:18:29 +0000121 for (int invBits = 0; invBits < 4; ++invBits) {
122 canvas->save();
bsalomon@google.com807cec42011-03-10 19:20:15 +0000123 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
reed@google.coma8f60f22011-12-08 16:18:29 +0000124 this->drawHairlines(canvas, path, clipA, clipB);
125
126 bool doInvA = SkToBool(invBits & 1);
127 bool doInvB = SkToBool(invBits & 2);
bsalomon@google.com807cec42011-03-10 19:20:15 +0000128 canvas->save();
129 // set clip
Mike Reed7d34dc72019-11-26 12:17:17 -0500130 clipA.setFillType(doInvA ? SkPathFillType::kInverseEvenOdd :
131 SkPathFillType::kEvenOdd);
132 clipB.setFillType(doInvB ? SkPathFillType::kInverseEvenOdd :
133 SkPathFillType::kEvenOdd);
reed66998382016-09-21 11:15:07 -0700134 canvas->clipPath(clipA, fDoAAClip);
reed@google.coma8f60f22011-12-08 16:18:29 +0000135 canvas->clipPath(clipB, gOps[op].fOp, fDoAAClip);
bsalomon@google.com807cec42011-03-10 19:20:15 +0000136
bsalomon6ae83cf2014-12-17 14:38:49 -0800137 // In the inverse case we need to prevent the draw from covering the whole
138 // canvas.
139 if (fInvertDraw) {
140 SkRect rectClip = clipA.getBounds();
141 rectClip.join(path.getBounds());
142 rectClip.join(path.getBounds());
143 rectClip.outset(5, 5);
144 canvas->clipRect(rectClip);
145 }
146
bsalomon@google.com807cec42011-03-10 19:20:15 +0000147 // draw path clipped
148 canvas->drawPath(path, pathPaint);
149 canvas->restore();
150
bsalomon@google.com807cec42011-03-10 19:20:15 +0000151
Mike Reed2e6db182018-12-15 13:45:33 -0500152 SkPaint paint;
Mike Reedbc414ed2018-08-16 22:49:55 -0400153 SkScalar txtX = 45;
reed@google.coma8f60f22011-12-08 16:18:29 +0000154 paint.setColor(gClipAColor);
155 const char* aTxt = doInvA ? "InvA " : "A ";
Ben Wagner51e15a62019-05-07 15:38:46 -0400156 canvas->drawSimpleText(aTxt, strlen(aTxt), SkTextEncoding::kUTF8, txtX, 220, font, paint);
157 txtX += font.measureText(aTxt, strlen(aTxt), SkTextEncoding::kUTF8);
bsalomon@google.com807cec42011-03-10 19:20:15 +0000158 paint.setColor(SK_ColorBLACK);
Ben Wagner51e15a62019-05-07 15:38:46 -0400159 canvas->drawSimpleText(gOps[op].fName, strlen(gOps[op].fName), SkTextEncoding::kUTF8, txtX, 220,
Mike Reed2e6db182018-12-15 13:45:33 -0500160 font, paint);
Ben Wagner51e15a62019-05-07 15:38:46 -0400161 txtX += font.measureText(gOps[op].fName, strlen(gOps[op].fName), SkTextEncoding::kUTF8);
reed@google.coma8f60f22011-12-08 16:18:29 +0000162 paint.setColor(gClipBColor);
163 const char* bTxt = doInvB ? "InvB " : "B ";
Ben Wagner51e15a62019-05-07 15:38:46 -0400164 canvas->drawSimpleText(bTxt, strlen(bTxt), SkTextEncoding::kUTF8, txtX, 220, font, paint);
bsalomon@google.com807cec42011-03-10 19:20:15 +0000165
Mike Reedbc414ed2018-08-16 22:49:55 -0400166 canvas->translate(250,0);
bsalomon@google.com807cec42011-03-10 19:20:15 +0000167 }
reed@google.coma8f60f22011-12-08 16:18:29 +0000168 canvas->restore();
Mike Reedbc414ed2018-08-16 22:49:55 -0400169 canvas->translate(0, 250);
bsalomon@google.com807cec42011-03-10 19:20:15 +0000170 }
robertphillips@google.com50a69a02012-07-12 13:48:46 +0000171
robertphillips@google.com54bb7ab2012-07-13 14:55:25 +0000172 if (fDoSaveLayer) {
robertphillips@google.com50a69a02012-07-12 13:48:46 +0000173 canvas->restore();
174 }
bsalomon@google.com807cec42011-03-10 19:20:15 +0000175 }
176private:
reed@google.coma8f60f22011-12-08 16:18:29 +0000177 void drawHairlines(SkCanvas* canvas, const SkPath& path,
178 const SkPath& clipA, const SkPath& clipB) {
179 SkPaint paint;
180 paint.setAntiAlias(true);
181 paint.setStyle(SkPaint::kStroke_Style);
182 const SkAlpha fade = 0x33;
183
184 // draw path in hairline
185 paint.setColor(gPathColor); paint.setAlpha(fade);
186 canvas->drawPath(path, paint);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000187
reed@google.coma8f60f22011-12-08 16:18:29 +0000188 // draw clips in hair line
189 paint.setColor(gClipAColor); paint.setAlpha(fade);
190 canvas->drawPath(clipA, paint);
191 paint.setColor(gClipBColor); paint.setAlpha(fade);
192 canvas->drawPath(clipB, paint);
193 }
194
bsalomon6ae83cf2014-12-17 14:38:49 -0800195 bool fDoAAClip;
196 bool fDoSaveLayer;
197 bool fInvertDraw;
198
bsalomon@google.com807cec42011-03-10 19:20:15 +0000199 typedef GM INHERITED;
200};
201
202//////////////////////////////////////////////////////////////////////////////
203
halcanary385fe4d2015-08-26 13:07:48 -0700204DEF_GM(return new ComplexClipGM(false, false, false);)
205DEF_GM(return new ComplexClipGM(false, false, true);)
206DEF_GM(return new ComplexClipGM(false, true, false);)
207DEF_GM(return new ComplexClipGM(false, true, true);)
208DEF_GM(return new ComplexClipGM(true, false, false);)
209DEF_GM(return new ComplexClipGM(true, false, true);)
210DEF_GM(return new ComplexClipGM(true, true, false);)
211DEF_GM(return new ComplexClipGM(true, true, true);)
bsalomon@google.com807cec42011-03-10 19:20:15 +0000212}
Mike Reed121c2af2020-03-10 14:02:56 -0400213
214DEF_SIMPLE_GM(clip_shader, canvas, 840, 650) {
215 auto img = GetResourceAsImage("images/yellow_rose.png");
216 auto sh = img->makeShader();
217
218 SkRect r = SkRect::MakeIWH(img->width(), img->height());
219 SkPaint p;
220
221 canvas->translate(10, 10);
222 canvas->drawImage(img, 0, 0, nullptr);
223
224 canvas->save();
225 canvas->translate(img->width() + 10, 0);
226 canvas->clipShader(sh, SkClipOp::kIntersect);
227 p.setColor(SK_ColorRED);
228 canvas->drawRect(r, p);
229 canvas->restore();
230
231 canvas->save();
232 canvas->translate(0, img->height() + 10);
233 canvas->clipShader(sh, SkClipOp::kDifference);
234 p.setColor(SK_ColorGREEN);
235 canvas->drawRect(r, p);
236 canvas->restore();
237
238 canvas->save();
239 canvas->translate(img->width() + 10, img->height() + 10);
240 canvas->clipShader(sh, SkClipOp::kIntersect);
241 canvas->save();
Mike Reed1f607332020-05-21 12:11:27 -0400242 SkMatrix lm = SkMatrix::Scale(1.0f/5, 1.0f/5);
Mike Reed121c2af2020-03-10 14:02:56 -0400243 canvas->clipShader(img->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, &lm));
244 canvas->drawImage(img, 0, 0, nullptr);
245
246 canvas->restore();
247 canvas->restore();
248}
Mike Reed84a9eb52020-03-12 13:55:44 -0400249
250DEF_SIMPLE_GM(clip_shader_layer, canvas, 430, 320) {
251 auto img = GetResourceAsImage("images/yellow_rose.png");
252 auto sh = img->makeShader();
253
254 SkRect r = SkRect::MakeIWH(img->width(), img->height());
255
256 canvas->translate(10, 10);
257 // now add the cool clip
258 canvas->clipRect(r);
259 canvas->clipShader(sh);
260 // now draw a layer with the same image, and watch it get restored w/ the clip
261 canvas->saveLayer(&r, nullptr);
262 canvas->drawColor(0xFFFF0000);
263 canvas->restore();
264}