blob: 8e2fb46dc9e7ddce4f2aec3ccb55c566e2e304be [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
19
20// The possible geometric combinations to test
21enum Geometry {
22 kRect_Geometry,
23 kRRect_Geometry,
24 kCircle_Geometry,
25 kConvexPath_Geometry,
26 kConcavePath_Geometry,
27 kRectAndRect_Geometry,
28 kRectAndRRect_Geometry,
29 kRectAndConvex_Geometry,
30 kRectAndConcave_Geometry
31};
32
33// The basic rect used is [kMin,kMin]..[kMax,kMax]
34static const float kMin = 100.5f;
35static const float kMid = 200.0f;
36static const float kMax = 299.5f;
37
38SkRect create_rect(const SkPoint& offset) {
39 SkRect r = SkRect::MakeLTRB(kMin, kMin, kMax, kMax);
40 r.offset(offset);
41 return r;
42}
43
44SkRRect create_rrect(const SkPoint& offset) {
45 SkRRect rrect;
46 rrect.setRectXY(create_rect(offset), 10, 10);
47 return rrect;
48}
49
50SkRRect create_circle(const SkPoint& offset) {
51 SkRRect circle;
52 circle.setOval(create_rect(offset));
53 return circle;
54}
55
56SkPath create_convex_path(const SkPoint& offset) {
57 SkPath convexPath;
58 convexPath.moveTo(kMin, kMin);
59 convexPath.lineTo(kMax, kMax);
60 convexPath.lineTo(kMin, kMax);
61 convexPath.close();
62 convexPath.offset(offset.fX, offset.fY);
63 return convexPath;
64}
65
66SkPath create_concave_path(const SkPoint& offset) {
67 SkPath concavePath;
68 concavePath.moveTo(kMin, kMin);
69 concavePath.lineTo(kMid, 105.0f);
70 concavePath.lineTo(kMax, kMin);
71 concavePath.lineTo(295.0f, kMid);
72 concavePath.lineTo(kMax, kMax);
73 concavePath.lineTo(kMid, 295.0f);
74 concavePath.lineTo(kMin, kMax);
75 concavePath.lineTo(105.0f, kMid);
76 concavePath.close();
77
78 concavePath.offset(offset.fX, offset.fY);
79 return concavePath;
80}
81
82static void draw_clipped_geom(SkCanvas* canvas, const SkPoint& offset, int geom, bool useAA) {
83
84 int count = canvas->save();
85
86 switch (geom) {
87 case kRect_Geometry:
88 canvas->clipRect(create_rect(offset), SkRegion::kReplace_Op, useAA);
89 break;
90 case kRRect_Geometry:
91 canvas->clipRRect(create_rrect(offset), SkRegion::kReplace_Op, useAA);
92 break;
93 case kCircle_Geometry:
94 canvas->clipRRect(create_circle(offset), SkRegion::kReplace_Op, useAA);
95 break;
96 case kConvexPath_Geometry:
97 canvas->clipPath(create_convex_path(offset), SkRegion::kReplace_Op, useAA);
98 break;
99 case kConcavePath_Geometry:
100 canvas->clipPath(create_concave_path(offset), SkRegion::kReplace_Op, useAA);
101 break;
102 case kRectAndRect_Geometry: {
103 SkRect r = create_rect(offset);
104 r.offset(-100.0f, -100.0f);
105 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
106 canvas->clipRect(create_rect(offset), SkRegion::kIntersect_Op, useAA);
107 } break;
108 case kRectAndRRect_Geometry: {
109 SkRect r = create_rect(offset);
110 r.offset(-100.0f, -100.0f);
111 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
112 canvas->clipRRect(create_rrect(offset), SkRegion::kIntersect_Op, useAA);
113 } break;
114 case kRectAndConvex_Geometry: {
115 SkRect r = create_rect(offset);
116 r.offset(-100.0f, -100.0f);
117 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
118 canvas->clipPath(create_convex_path(offset), SkRegion::kIntersect_Op, useAA);
119 } break;
120 case kRectAndConcave_Geometry: {
121 SkRect r = create_rect(offset);
122 r.offset(-100.0f, -100.0f);
123 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
124 canvas->clipPath(create_concave_path(offset), SkRegion::kIntersect_Op, useAA);
125 } break;
126 }
127
128 SkISize size = canvas->getDeviceSize();
129 SkRect bigR = SkRect::MakeWH(SkIntToScalar(size.width()), SkIntToScalar(size.height()));
130
131 SkPaint p;
132 p.setColor(SK_ColorRED);
133
134 canvas->drawRect(bigR, p);
135 canvas->restoreToCount(count);
136}
137
138static void draw_normal_geom(SkCanvas* canvas, const SkPoint& offset, int geom, bool useAA) {
139 SkPaint p;
140 p.setAntiAlias(useAA);
141 p.setColor(SK_ColorBLACK);
142
143 switch (geom) {
144 case kRect_Geometry: // fall thru
145 case kRectAndRect_Geometry:
146 canvas->drawRect(create_rect(offset), p);
147 break;
148 case kRRect_Geometry: // fall thru
149 case kRectAndRRect_Geometry:
150 canvas->drawRRect(create_rrect(offset), p);
151 break;
152 case kCircle_Geometry:
153 canvas->drawRRect(create_circle(offset), p);
154 break;
155 case kConvexPath_Geometry: // fall thru
156 case kRectAndConvex_Geometry:
157 canvas->drawPath(create_convex_path(offset), p);
158 break;
159 case kConcavePath_Geometry: // fall thru
160 case kRectAndConcave_Geometry:
161 canvas->drawPath(create_concave_path(offset), p);
162 break;
163 }
164}
165
166class ClipDrawMatchView : public SampleView {
167public:
168 ClipDrawMatchView() : fTrans(2, 5), fGeom(kRect_Geometry), fClipFirst(true) {
169 SkScalar values[2];
170
171 fTrans.setRepeatCount(999);
172 values[0] = values[1] = 0;
173 fTrans.setKeyFrame(0, SkTime::GetMSecs() + 1000, values);
174 values[1] = 1;
175 fTrans.setKeyFrame(1, SkTime::GetMSecs() + 2000, values);
176 values[0] = values[1] = 1;
177 fTrans.setKeyFrame(2, SkTime::GetMSecs() + 3000, values);
178 values[1] = 0;
179 fTrans.setKeyFrame(3, SkTime::GetMSecs() + 4000, values);
180 values[0] = 0;
181 fTrans.setKeyFrame(4, SkTime::GetMSecs() + 5000, values);
182 }
183
184protected:
185 bool onQuery(SkEvent* evt) SK_OVERRIDE {
186 if (SampleCode::TitleQ(*evt)) {
187 SampleCode::TitleR(evt, "ClipDrawMatch");
188 return true;
189 }
190 SkUnichar uni;
191 if (SampleCode::CharQ(*evt, &uni)) {
192 switch (uni) {
193 case '1': fGeom = kRect_Geometry; this->inval(NULL); return true;
194 case '2': fGeom = kRRect_Geometry; this->inval(NULL); return true;
195 case '3': fGeom = kCircle_Geometry; this->inval(NULL); return true;
196 case '4': fGeom = kConvexPath_Geometry; this->inval(NULL); return true;
197 case '5': fGeom = kConcavePath_Geometry; this->inval(NULL); return true;
198 case '6': fGeom = kRectAndRect_Geometry; this->inval(NULL); return true;
199 case '7': fGeom = kRectAndRRect_Geometry; this->inval(NULL); return true;
200 case '8': fGeom = kRectAndConvex_Geometry; this->inval(NULL); return true;
201 case '9': fGeom = kRectAndConcave_Geometry; this->inval(NULL); return true;
202 case 't': fClipFirst = !fClipFirst; this->inval(NULL); return true;
203 default: break;
204 }
205 }
206 return this->INHERITED::onQuery(evt);
207 }
208
209 // Draw a big red rect through some clip geometry and also draw that same
210 // geometry in black. The order in which they are drawn can be swapped.
211 // This tests whether the clip and normally drawn geometry match up.
212 void drawGeometry(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
213 if (fClipFirst) {
214 draw_clipped_geom(canvas, offset, fGeom, useAA);
215 }
216
217 draw_normal_geom(canvas, offset, fGeom, useAA);
218
219 if (!fClipFirst) {
220 draw_clipped_geom(canvas, offset, fGeom, useAA);
221 }
222 }
223
224 void onDrawContent(SkCanvas* canvas) SK_OVERRIDE {
225 SkScalar trans[2];
226 fTrans.timeToValues(SkTime::GetMSecs(), trans);
227
228 SkPoint offset;
229 offset.set(trans[0], trans[1]);
230
231 int saveCount = canvas->save();
232 this->drawGeometry(canvas, offset, false);
233 canvas->restoreToCount(saveCount);
234
235 this->inval(NULL);
236 }
237
238private:
239 SkInterpolator fTrans;
240 Geometry fGeom;
241 bool fClipFirst;
242
243 typedef SampleView INHERITED;
244};
245
246//////////////////////////////////////////////////////////////////////////////
247
248static SkView* MyFactory() { return new ClipDrawMatchView; }
249static SkViewRegister reg(MyFactory);