blob: 502f34946b710c295ff4da9d411f4986234798ea [file] [log] [blame]
robertphillips7defaa62015-01-27 06:17:22 -08001/*
2 * Copyright 2015 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 "SampleCode.h"
9#include "SkCanvas.h"
10#include "SkInterpolator.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkPath.h"
12#include "SkRRect.h"
robertphillips7defaa62015-01-27 06:17:22 -080013#include "SkTime.h"
14
15// This slide tests out the match up between BW clipping and rendering. It can
16// draw a large rect through some clip geometry and draw the same geometry
17// normally. Which one is drawn first can be toggled. The pair of objects is translated
18// fractionally (via an animator) to expose snapping bugs. The key bindings are:
19// 1-9: the different geometries
20// t: toggle which is drawn first the clip or the normal geometry
robertphillipsc89f6fb2015-02-09 07:47:17 -080021// f: flip-flops which corner the bottom AA clip rect occupies in the complex clip cases
robertphillips7defaa62015-01-27 06:17:22 -080022
23// The possible geometric combinations to test
24enum Geometry {
25 kRect_Geometry,
26 kRRect_Geometry,
27 kCircle_Geometry,
28 kConvexPath_Geometry,
29 kConcavePath_Geometry,
30 kRectAndRect_Geometry,
31 kRectAndRRect_Geometry,
32 kRectAndConvex_Geometry,
33 kRectAndConcave_Geometry
34};
35
36// The basic rect used is [kMin,kMin]..[kMax,kMax]
37static const float kMin = 100.5f;
38static const float kMid = 200.0f;
39static const float kMax = 299.5f;
40
robertphillipsc89f6fb2015-02-09 07:47:17 -080041// The translation applied to the base AA rect in the combination cases
42// (i.e., kRectAndRect through kRectAndConcave)
43static const float kXlate = 100.0f;
44
robertphillips7defaa62015-01-27 06:17:22 -080045SkRect create_rect(const SkPoint& offset) {
46 SkRect r = SkRect::MakeLTRB(kMin, kMin, kMax, kMax);
47 r.offset(offset);
48 return r;
49}
50
51SkRRect create_rrect(const SkPoint& offset) {
52 SkRRect rrect;
53 rrect.setRectXY(create_rect(offset), 10, 10);
54 return rrect;
55}
56
57SkRRect create_circle(const SkPoint& offset) {
58 SkRRect circle;
59 circle.setOval(create_rect(offset));
60 return circle;
61}
62
63SkPath create_convex_path(const SkPoint& offset) {
64 SkPath convexPath;
65 convexPath.moveTo(kMin, kMin);
66 convexPath.lineTo(kMax, kMax);
67 convexPath.lineTo(kMin, kMax);
68 convexPath.close();
69 convexPath.offset(offset.fX, offset.fY);
70 return convexPath;
71}
72
73SkPath create_concave_path(const SkPoint& offset) {
74 SkPath concavePath;
75 concavePath.moveTo(kMin, kMin);
76 concavePath.lineTo(kMid, 105.0f);
77 concavePath.lineTo(kMax, kMin);
78 concavePath.lineTo(295.0f, kMid);
79 concavePath.lineTo(kMax, kMax);
80 concavePath.lineTo(kMid, 295.0f);
81 concavePath.lineTo(kMin, kMax);
82 concavePath.lineTo(105.0f, kMid);
83 concavePath.close();
84
85 concavePath.offset(offset.fX, offset.fY);
86 return concavePath;
87}
88
robertphillips7defaa62015-01-27 06:17:22 -080089static void draw_normal_geom(SkCanvas* canvas, const SkPoint& offset, int geom, bool useAA) {
90 SkPaint p;
91 p.setAntiAlias(useAA);
92 p.setColor(SK_ColorBLACK);
93
94 switch (geom) {
95 case kRect_Geometry: // fall thru
96 case kRectAndRect_Geometry:
97 canvas->drawRect(create_rect(offset), p);
98 break;
99 case kRRect_Geometry: // fall thru
100 case kRectAndRRect_Geometry:
101 canvas->drawRRect(create_rrect(offset), p);
102 break;
103 case kCircle_Geometry:
104 canvas->drawRRect(create_circle(offset), p);
105 break;
106 case kConvexPath_Geometry: // fall thru
107 case kRectAndConvex_Geometry:
108 canvas->drawPath(create_convex_path(offset), p);
109 break;
110 case kConcavePath_Geometry: // fall thru
111 case kRectAndConcave_Geometry:
112 canvas->drawPath(create_concave_path(offset), p);
113 break;
114 }
115}
116
117class ClipDrawMatchView : public SampleView {
118public:
robertphillipsc89f6fb2015-02-09 07:47:17 -0800119 ClipDrawMatchView() : fTrans(2, 5), fGeom(kRect_Geometry), fClipFirst(true), fSign(1) {
robertphillips7defaa62015-01-27 06:17:22 -0800120 SkScalar values[2];
121
122 fTrans.setRepeatCount(999);
123 values[0] = values[1] = 0;
124 fTrans.setKeyFrame(0, SkTime::GetMSecs() + 1000, values);
125 values[1] = 1;
126 fTrans.setKeyFrame(1, SkTime::GetMSecs() + 2000, values);
127 values[0] = values[1] = 1;
128 fTrans.setKeyFrame(2, SkTime::GetMSecs() + 3000, values);
129 values[1] = 0;
130 fTrans.setKeyFrame(3, SkTime::GetMSecs() + 4000, values);
131 values[0] = 0;
132 fTrans.setKeyFrame(4, SkTime::GetMSecs() + 5000, values);
133 }
134
135protected:
mtklein36352bf2015-03-25 18:17:31 -0700136 bool onQuery(SkEvent* evt) override {
robertphillips7defaa62015-01-27 06:17:22 -0800137 if (SampleCode::TitleQ(*evt)) {
138 SampleCode::TitleR(evt, "ClipDrawMatch");
139 return true;
140 }
141 SkUnichar uni;
142 if (SampleCode::CharQ(*evt, &uni)) {
143 switch (uni) {
halcanary96fcdcc2015-08-27 07:41:13 -0700144 case '1': fGeom = kRect_Geometry; this->inval(nullptr); return true;
145 case '2': fGeom = kRRect_Geometry; this->inval(nullptr); return true;
146 case '3': fGeom = kCircle_Geometry; this->inval(nullptr); return true;
147 case '4': fGeom = kConvexPath_Geometry; this->inval(nullptr); return true;
148 case '5': fGeom = kConcavePath_Geometry; this->inval(nullptr); return true;
149 case '6': fGeom = kRectAndRect_Geometry; this->inval(nullptr); return true;
150 case '7': fGeom = kRectAndRRect_Geometry; this->inval(nullptr); return true;
151 case '8': fGeom = kRectAndConvex_Geometry; this->inval(nullptr); return true;
152 case '9': fGeom = kRectAndConcave_Geometry; this->inval(nullptr); return true;
153 case 'f': fSign = -fSign; this->inval(nullptr); return true;
154 case 't': fClipFirst = !fClipFirst; this->inval(nullptr); return true;
robertphillips7defaa62015-01-27 06:17:22 -0800155 default: break;
156 }
157 }
158 return this->INHERITED::onQuery(evt);
159 }
160
robertphillipsc89f6fb2015-02-09 07:47:17 -0800161 void drawClippedGeom(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
162
163 int count = canvas->save();
164
165 switch (fGeom) {
166 case kRect_Geometry:
167 canvas->clipRect(create_rect(offset), SkRegion::kReplace_Op, useAA);
168 break;
169 case kRRect_Geometry:
170 canvas->clipRRect(create_rrect(offset), SkRegion::kReplace_Op, useAA);
171 break;
172 case kCircle_Geometry:
173 canvas->clipRRect(create_circle(offset), SkRegion::kReplace_Op, useAA);
174 break;
175 case kConvexPath_Geometry:
176 canvas->clipPath(create_convex_path(offset), SkRegion::kReplace_Op, useAA);
177 break;
178 case kConcavePath_Geometry:
179 canvas->clipPath(create_concave_path(offset), SkRegion::kReplace_Op, useAA);
180 break;
181 case kRectAndRect_Geometry: {
182 SkRect r = create_rect(offset);
183 r.offset(fSign * kXlate, fSign * kXlate);
184 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
185 canvas->clipRect(create_rect(offset), SkRegion::kIntersect_Op, useAA);
186 } break;
187 case kRectAndRRect_Geometry: {
188 SkRect r = create_rect(offset);
189 r.offset(fSign * kXlate, fSign * kXlate);
190 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
191 canvas->clipRRect(create_rrect(offset), SkRegion::kIntersect_Op, useAA);
192 } break;
193 case kRectAndConvex_Geometry: {
194 SkRect r = create_rect(offset);
195 r.offset(fSign * kXlate, fSign * kXlate);
196 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
197 canvas->clipPath(create_convex_path(offset), SkRegion::kIntersect_Op, useAA);
198 } break;
199 case kRectAndConcave_Geometry: {
200 SkRect r = create_rect(offset);
201 r.offset(fSign * kXlate, fSign * kXlate);
202 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
203 canvas->clipPath(create_concave_path(offset), SkRegion::kIntersect_Op, useAA);
204 } break;
205 }
206
207 SkISize size = canvas->getDeviceSize();
208 SkRect bigR = SkRect::MakeWH(SkIntToScalar(size.width()), SkIntToScalar(size.height()));
209
210 SkPaint p;
211 p.setColor(SK_ColorRED);
212
213 canvas->drawRect(bigR, p);
214 canvas->restoreToCount(count);
215 }
216
robertphillips7defaa62015-01-27 06:17:22 -0800217 // Draw a big red rect through some clip geometry and also draw that same
218 // geometry in black. The order in which they are drawn can be swapped.
219 // This tests whether the clip and normally drawn geometry match up.
220 void drawGeometry(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
221 if (fClipFirst) {
robertphillipsc89f6fb2015-02-09 07:47:17 -0800222 this->drawClippedGeom(canvas, offset, useAA);
robertphillips7defaa62015-01-27 06:17:22 -0800223 }
224
225 draw_normal_geom(canvas, offset, fGeom, useAA);
226
227 if (!fClipFirst) {
robertphillipsc89f6fb2015-02-09 07:47:17 -0800228 this->drawClippedGeom(canvas, offset, useAA);
robertphillips7defaa62015-01-27 06:17:22 -0800229 }
230 }
231
mtklein36352bf2015-03-25 18:17:31 -0700232 void onDrawContent(SkCanvas* canvas) override {
robertphillips7defaa62015-01-27 06:17:22 -0800233 SkScalar trans[2];
234 fTrans.timeToValues(SkTime::GetMSecs(), trans);
235
236 SkPoint offset;
237 offset.set(trans[0], trans[1]);
238
239 int saveCount = canvas->save();
240 this->drawGeometry(canvas, offset, false);
241 canvas->restoreToCount(saveCount);
242
halcanary96fcdcc2015-08-27 07:41:13 -0700243 this->inval(nullptr);
robertphillips7defaa62015-01-27 06:17:22 -0800244 }
245
246private:
247 SkInterpolator fTrans;
248 Geometry fGeom;
249 bool fClipFirst;
robertphillipsc89f6fb2015-02-09 07:47:17 -0800250 int fSign;
robertphillips7defaa62015-01-27 06:17:22 -0800251
252 typedef SampleView INHERITED;
253};
254
255//////////////////////////////////////////////////////////////////////////////
256
257static SkView* MyFactory() { return new ClipDrawMatchView; }
258static SkViewRegister reg(MyFactory);