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