1 /*
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 "include/core/SkCanvas.h"
9 #include "include/core/SkPath.h"
10 #include "include/core/SkRRect.h"
11 #include "include/core/SkTime.h"
12 #include "include/utils/SkInterpolator.h"
13 #include "samplecode/Sample.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
21 // f: flip-flops which corner the bottom AA clip rect occupies in the complex clip cases
22
23 // The possible geometric combinations to test
24 enum 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]
37 static const float kMin = 100.5f;
38 static const float kMid = 200.0f;
39 static const float kMax = 299.5f;
40
41 // The translation applied to the base AA rect in the combination cases
42 // (i.e., kRectAndRect through kRectAndConcave)
43 static const float kXlate = 100.0f;
44
create_rect(const SkPoint & offset)45 SkRect create_rect(const SkPoint& offset) {
46 SkRect r = SkRect::MakeLTRB(kMin, kMin, kMax, kMax);
47 r.offset(offset);
48 return r;
49 }
50
create_rrect(const SkPoint & offset)51 SkRRect create_rrect(const SkPoint& offset) {
52 SkRRect rrect;
53 rrect.setRectXY(create_rect(offset), 10, 10);
54 return rrect;
55 }
56
create_circle(const SkPoint & offset)57 SkRRect create_circle(const SkPoint& offset) {
58 SkRRect circle;
59 circle.setOval(create_rect(offset));
60 return circle;
61 }
62
create_convex_path(const SkPoint & offset)63 SkPath 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
create_concave_path(const SkPoint & offset)73 SkPath 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
draw_normal_geom(SkCanvas * canvas,const SkPoint & offset,int geom,bool useAA)89 static 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
117 class ClipDrawMatchView : public Sample {
118 SkInterpolator fTrans;
119 Geometry fGeom;
120 bool fClipFirst = true;
121 int fSign = 1;
122 const double fStart = SkTime::GetMSecs();
123
124 public:
ClipDrawMatchView()125 ClipDrawMatchView() : fTrans(2, 5), fGeom(kRect_Geometry) {}
126
127 private:
onOnceBeforeDraw()128 void onOnceBeforeDraw() override {
129 SkScalar values[2];
130
131 fTrans.setRepeatCount(999);
132 values[0] = values[1] = 0;
133 fTrans.setKeyFrame(0, GetMSecs() + 1000, values);
134 values[1] = 1;
135 fTrans.setKeyFrame(1, GetMSecs() + 2000, values);
136 values[0] = values[1] = 1;
137 fTrans.setKeyFrame(2, GetMSecs() + 3000, values);
138 values[1] = 0;
139 fTrans.setKeyFrame(3, GetMSecs() + 4000, values);
140 values[0] = 0;
141 fTrans.setKeyFrame(4, GetMSecs() + 5000, values);
142 }
143
name()144 SkString name() override { return SkString("ClipDrawMatch"); }
145
onChar(SkUnichar uni)146 bool onChar(SkUnichar uni) override {
147 switch (uni) {
148 case '1': fGeom = kRect_Geometry; return true;
149 case '2': fGeom = kRRect_Geometry; return true;
150 case '3': fGeom = kCircle_Geometry; return true;
151 case '4': fGeom = kConvexPath_Geometry; return true;
152 case '5': fGeom = kConcavePath_Geometry; return true;
153 case '6': fGeom = kRectAndRect_Geometry; return true;
154 case '7': fGeom = kRectAndRRect_Geometry; return true;
155 case '8': fGeom = kRectAndConvex_Geometry; return true;
156 case '9': fGeom = kRectAndConcave_Geometry; return true;
157 case 'f': fSign = -fSign; return true;
158 case 't': fClipFirst = !fClipFirst; return true;
159 default: break;
160 }
161 return false;
162 }
163
drawClippedGeom(SkCanvas * canvas,const SkPoint & offset,bool useAA)164 void drawClippedGeom(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
165
166 int count = canvas->save();
167
168 switch (fGeom) {
169 case kRect_Geometry:
170 canvas->clipRect(create_rect(offset), useAA);
171 break;
172 case kRRect_Geometry:
173 canvas->clipRRect(create_rrect(offset), useAA);
174 break;
175 case kCircle_Geometry:
176 canvas->clipRRect(create_circle(offset), useAA);
177 break;
178 case kConvexPath_Geometry:
179 canvas->clipPath(create_convex_path(offset), useAA);
180 break;
181 case kConcavePath_Geometry:
182 canvas->clipPath(create_concave_path(offset), useAA);
183 break;
184 case kRectAndRect_Geometry: {
185 SkRect r = create_rect(offset);
186 r.offset(fSign * kXlate, fSign * kXlate);
187 canvas->clipRect(r, true); // AA here forces shader clips
188 canvas->clipRect(create_rect(offset), useAA);
189 } break;
190 case kRectAndRRect_Geometry: {
191 SkRect r = create_rect(offset);
192 r.offset(fSign * kXlate, fSign * kXlate);
193 canvas->clipRect(r, true); // AA here forces shader clips
194 canvas->clipRRect(create_rrect(offset), useAA);
195 } break;
196 case kRectAndConvex_Geometry: {
197 SkRect r = create_rect(offset);
198 r.offset(fSign * kXlate, fSign * kXlate);
199 canvas->clipRect(r, true); // AA here forces shader clips
200 canvas->clipPath(create_convex_path(offset), useAA);
201 } break;
202 case kRectAndConcave_Geometry: {
203 SkRect r = create_rect(offset);
204 r.offset(fSign * kXlate, fSign * kXlate);
205 canvas->clipRect(r, true); // AA here forces shader clips
206 canvas->clipPath(create_concave_path(offset), useAA);
207 } break;
208 }
209
210 SkISize size = canvas->getBaseLayerSize();
211 SkRect bigR = SkRect::MakeWH(SkIntToScalar(size.width()), SkIntToScalar(size.height()));
212
213 SkPaint p;
214 p.setColor(SK_ColorRED);
215
216 canvas->drawRect(bigR, p);
217 canvas->restoreToCount(count);
218 }
219
220 // Draw a big red rect through some clip geometry and also draw that same
221 // geometry in black. The order in which they are drawn can be swapped.
222 // This tests whether the clip and normally drawn geometry match up.
drawGeometry(SkCanvas * canvas,const SkPoint & offset,bool useAA)223 void drawGeometry(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
224 if (fClipFirst) {
225 this->drawClippedGeom(canvas, offset, useAA);
226 }
227
228 draw_normal_geom(canvas, offset, fGeom, useAA);
229
230 if (!fClipFirst) {
231 this->drawClippedGeom(canvas, offset, useAA);
232 }
233 }
234
onDrawContent(SkCanvas * canvas)235 void onDrawContent(SkCanvas* canvas) override {
236 SkScalar trans[2];
237 fTrans.timeToValues(GetMSecs(), trans);
238
239 SkPoint offset;
240 offset.set(trans[0], trans[1]);
241
242 int saveCount = canvas->save();
243 this->drawGeometry(canvas, offset, false);
244 canvas->restoreToCount(saveCount);
245 }
246
GetMSecs() const247 SkMSec GetMSecs() const {
248 return static_cast<SkMSec>(SkTime::GetMSecs() - fStart);
249 }
250 };
251
252 DEF_SAMPLE( return new ClipDrawMatchView(); )
253