blob: 3c7de7d56a93ef89123845e2b91b7011d8c0dd19 [file] [log] [blame]
robertphillips05a4cf52016-09-08 09:02:43 -07001/*
2 * Copyright 2016 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 "gm.h"
9#include "SkAnimTimer.h"
10#include "SkBlurMaskFilter.h"
11#include "SkGaussianEdgeShader.h"
Robert Phillipsa29a9562016-10-20 09:40:55 -040012#include "SkRRectsGaussianEdgeMaskFilter.h"
robertphillips05a4cf52016-09-08 09:02:43 -070013#include "SkPath.h"
14#include "SkPathOps.h"
15#include "SkRRect.h"
16#include "SkStroke.h"
17
18constexpr int kNumCols = 2;
19constexpr int kNumRows = 5;
20constexpr int kCellSize = 128;
21constexpr SkScalar kPad = 8.0f;
Robert Phillips40085e62016-10-18 12:58:29 -040022constexpr SkScalar kInitialBlurRadius = 8.0f;
robertphillips05a4cf52016-09-08 09:02:43 -070023constexpr SkScalar kPeriod = 8.0f;
24constexpr int kClipOffset = 32;
25
26///////////////////////////////////////////////////////////////////////////////////////////////////
robertphillips05a4cf52016-09-08 09:02:43 -070027
robertphillips2af83ac2016-09-12 12:02:16 -070028class Object {
29public:
30 virtual ~Object() {}
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -040031 // When it returns true, this call will have placed a device-space _circle, rect or
32 // simple circular_ RRect in "rr"
33 virtual bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const = 0;
robertphillipsf619a7a2016-09-12 17:25:50 -070034 virtual SkPath asPath(SkScalar inset) const = 0;
robertphillips2af83ac2016-09-12 12:02:16 -070035 virtual void draw(SkCanvas* canvas, const SkPaint& paint) const = 0;
36 virtual void clip(SkCanvas* canvas) const = 0;
37 virtual bool contains(const SkRect& r) const = 0;
38 virtual const SkRect& bounds() const = 0;
39};
robertphillips05a4cf52016-09-08 09:02:43 -070040
robertphillips2af83ac2016-09-12 12:02:16 -070041typedef Object* (*PFMakeMthd)(const SkRect& r);
42
43class RRect : public Object {
44public:
45 RRect(const SkRect& r) {
46 fRRect = SkRRect::MakeRectXY(r, 4*kPad, 4*kPad);
robertphillips05a4cf52016-09-08 09:02:43 -070047 }
robertphillips05a4cf52016-09-08 09:02:43 -070048
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -040049 bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
50 if (!ctm.isSimilarity()) { // the corners have to remain circular
51 return false;
52 }
53
54 SkScalar scales[2];
55 if (!ctm.getMinMaxScales(scales)) {
56 return false;
57 }
58
59 SkASSERT(SkScalarNearlyEqual(scales[0], scales[1]));
60
61 SkRect devRect;
62 ctm.mapRect(&devRect, fRRect.rect());
63
64 SkScalar scaledRad = scales[0] * fRRect.getSimpleRadii().fX;
65
66 *rr = SkRRect::MakeRectXY(devRect, scaledRad, scaledRad);
robertphillips2af83ac2016-09-12 12:02:16 -070067 return true;
68 }
robertphillips05a4cf52016-09-08 09:02:43 -070069
robertphillipsf619a7a2016-09-12 17:25:50 -070070 SkPath asPath(SkScalar inset) const override {
71 SkRRect tmp = fRRect;
72 tmp.inset(inset, inset);
robertphillips2af83ac2016-09-12 12:02:16 -070073 SkPath p;
robertphillipsf619a7a2016-09-12 17:25:50 -070074 p.addRRect(tmp);
robertphillips2af83ac2016-09-12 12:02:16 -070075 return p;
76 }
robertphillips05a4cf52016-09-08 09:02:43 -070077
robertphillips2af83ac2016-09-12 12:02:16 -070078 void draw(SkCanvas* canvas, const SkPaint& paint) const override {
79 canvas->drawRRect(fRRect, paint);
80 }
robertphillips05a4cf52016-09-08 09:02:43 -070081
robertphillips2af83ac2016-09-12 12:02:16 -070082 void clip(SkCanvas* canvas) const override {
83 canvas->clipRRect(fRRect);
84 }
85
86 bool contains(const SkRect& r) const override {
87 return fRRect.contains(r);
88 }
89
90 const SkRect& bounds() const override {
91 return fRRect.getBounds();
92 }
93
94 static Object* Make(const SkRect& r) {
95 return new RRect(r);
96 }
97
98private:
99 SkRRect fRRect;
100};
101
102class StrokedRRect : public Object {
103public:
104 StrokedRRect(const SkRect& r) {
105 fRRect = SkRRect::MakeRectXY(r, 2*kPad, 2*kPad);
106 fStrokedBounds = r.makeOutset(kPad, kPad);
107 }
108
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400109 bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
robertphillips2af83ac2016-09-12 12:02:16 -0700110 return false;
111 }
112
robertphillipsf619a7a2016-09-12 17:25:50 -0700113 SkPath asPath(SkScalar inset) const override {
114 SkRRect tmp = fRRect;
115 tmp.inset(inset, inset);
116
robertphillips2af83ac2016-09-12 12:02:16 -0700117 // In this case we want the outline of the stroked rrect
118 SkPaint paint;
119 paint.setAntiAlias(true);
120 paint.setStyle(SkPaint::kStroke_Style);
121 paint.setStrokeWidth(kPad);
122
robertphillips05a4cf52016-09-08 09:02:43 -0700123 SkPath p, stroked;
robertphillipsf619a7a2016-09-12 17:25:50 -0700124 p.addRRect(tmp);
robertphillips05a4cf52016-09-08 09:02:43 -0700125 SkStroke stroke(paint);
126 stroke.strokePath(p, &stroked);
robertphillips2af83ac2016-09-12 12:02:16 -0700127 return stroked;
robertphillips05a4cf52016-09-08 09:02:43 -0700128 }
129
robertphillips2af83ac2016-09-12 12:02:16 -0700130 void draw(SkCanvas* canvas, const SkPaint& paint) const override {
131 SkPaint stroke(paint);
132 stroke.setStyle(SkPaint::kStroke_Style);
133 stroke.setStrokeWidth(kPad);
robertphillips05a4cf52016-09-08 09:02:43 -0700134
robertphillips2af83ac2016-09-12 12:02:16 -0700135 canvas->drawRRect(fRRect, stroke);
robertphillips05a4cf52016-09-08 09:02:43 -0700136 }
137
robertphillips2af83ac2016-09-12 12:02:16 -0700138 void clip(SkCanvas* canvas) const override {
robertphillipsf619a7a2016-09-12 17:25:50 -0700139 canvas->clipPath(this->asPath(0.0f));
robertphillips05a4cf52016-09-08 09:02:43 -0700140 }
141
robertphillips2af83ac2016-09-12 12:02:16 -0700142 bool contains(const SkRect& r) const override {
143 return false;
robertphillips05a4cf52016-09-08 09:02:43 -0700144 }
145
robertphillips2af83ac2016-09-12 12:02:16 -0700146 const SkRect& bounds() const override {
147 return fStrokedBounds;
148 }
robertphillips05a4cf52016-09-08 09:02:43 -0700149
robertphillips2af83ac2016-09-12 12:02:16 -0700150 static Object* Make(const SkRect& r) {
151 return new StrokedRRect(r);
152 }
robertphillips05a4cf52016-09-08 09:02:43 -0700153
robertphillips2af83ac2016-09-12 12:02:16 -0700154private:
155 SkRRect fRRect;
156 SkRect fStrokedBounds;
157};
robertphillips05a4cf52016-09-08 09:02:43 -0700158
robertphillips2af83ac2016-09-12 12:02:16 -0700159class Oval : public Object {
160public:
161 Oval(const SkRect& r) {
162 fRRect = SkRRect::MakeOval(r);
163 }
164
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400165 bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
166 if (!ctm.isSimilarity()) { // circles have to remain circles
167 return false;
168 }
169
170 SkRect devRect;
171 ctm.mapRect(&devRect, fRRect.rect());
172 *rr = SkRRect::MakeOval(devRect);
robertphillips2af83ac2016-09-12 12:02:16 -0700173 return true;
174 }
175
robertphillipsf619a7a2016-09-12 17:25:50 -0700176 SkPath asPath(SkScalar inset) const override {
177 SkRRect tmp = fRRect;
178 tmp.inset(inset, inset);
179
robertphillips2af83ac2016-09-12 12:02:16 -0700180 SkPath p;
robertphillipsf619a7a2016-09-12 17:25:50 -0700181 p.addRRect(tmp);
robertphillips2af83ac2016-09-12 12:02:16 -0700182 return p;
183 }
184
185 void draw(SkCanvas* canvas, const SkPaint& paint) const override {
186 canvas->drawRRect(fRRect, paint);
187 }
188
189 void clip(SkCanvas* canvas) const override {
190 canvas->clipRRect(fRRect);
191 }
192
193 bool contains(const SkRect& r) const override {
194 return fRRect.contains(r);
195 }
196
197 const SkRect& bounds() const override {
198 return fRRect.getBounds();
199 }
200
201 static Object* Make(const SkRect& r) {
202 return new Oval(r);
203 }
204
205private:
206 SkRRect fRRect;
207};
208
209class Rect : public Object {
210public:
211 Rect(const SkRect& r) : fRect(r) { }
212
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400213 bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
214 if (!ctm.rectStaysRect()) {
215 return false;
216 }
217
218 SkRect devRect;
219 ctm.mapRect(&devRect, fRect);
220 *rr = SkRRect::MakeRect(devRect);
robertphillips2af83ac2016-09-12 12:02:16 -0700221 return true;
222 }
223
robertphillipsf619a7a2016-09-12 17:25:50 -0700224 SkPath asPath(SkScalar inset) const override {
225 SkRect tmp = fRect;
226 tmp.inset(inset, inset);
227
robertphillips2af83ac2016-09-12 12:02:16 -0700228 SkPath p;
robertphillipsf619a7a2016-09-12 17:25:50 -0700229 p.addRect(tmp);
robertphillips2af83ac2016-09-12 12:02:16 -0700230 return p;
231 }
232
233 void draw(SkCanvas* canvas, const SkPaint& paint) const override {
234 canvas->drawRect(fRect, paint);
235 }
236
237 void clip(SkCanvas* canvas) const override {
238 canvas->clipRect(fRect);
239 }
240
241 bool contains(const SkRect& r) const override {
242 return fRect.contains(r);
243 }
244
245 const SkRect& bounds() const override {
246 return fRect;
247 }
248
249 static Object* Make(const SkRect& r) {
250 return new Rect(r);
251 }
252
253private:
254 SkRect fRect;
255};
256
257class Pentagon : public Object {
258public:
259 Pentagon(const SkRect& r) {
260 SkPoint points[5] = {
261 { 0.000000f, -1.000000f },
262 { -0.951056f, -0.309017f },
263 { -0.587785f, 0.809017f },
264 { 0.587785f, 0.809017f },
265 { 0.951057f, -0.309017f },
266 };
267
268 SkScalar height = r.height()/2.0f;
269 SkScalar width = r.width()/2.0f;
270
271 fPath.moveTo(r.centerX() + points[0].fX * width, r.centerY() + points[0].fY * height);
272 fPath.lineTo(r.centerX() + points[1].fX * width, r.centerY() + points[1].fY * height);
273 fPath.lineTo(r.centerX() + points[2].fX * width, r.centerY() + points[2].fY * height);
274 fPath.lineTo(r.centerX() + points[3].fX * width, r.centerY() + points[3].fY * height);
275 fPath.lineTo(r.centerX() + points[4].fX * width, r.centerY() + points[4].fY * height);
276 fPath.close();
277 }
278
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400279 bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
robertphillips2af83ac2016-09-12 12:02:16 -0700280 return false;
281 }
282
robertphillipsf619a7a2016-09-12 17:25:50 -0700283 SkPath asPath(SkScalar inset) const override { return fPath; }
robertphillips2af83ac2016-09-12 12:02:16 -0700284
285 void draw(SkCanvas* canvas, const SkPaint& paint) const override {
286 canvas->drawPath(fPath, paint);
287 }
288
289 void clip(SkCanvas* canvas) const override {
robertphillipsf619a7a2016-09-12 17:25:50 -0700290 canvas->clipPath(this->asPath(0.0f));
robertphillips2af83ac2016-09-12 12:02:16 -0700291 }
292
293 bool contains(const SkRect& r) const override {
294 return false;
295 }
296
297 const SkRect& bounds() const override {
298 return fPath.getBounds();
299 }
300
301 static Object* Make(const SkRect& r) {
302 return new Pentagon(r);
303 }
304
305private:
306 SkPath fPath;
307};
robertphillips05a4cf52016-09-08 09:02:43 -0700308
309///////////////////////////////////////////////////////////////////////////////////////////////////
310namespace skiagm {
311
312// This GM attempts to mimic Android's reveal animation
313class RevealGM : public GM {
314public:
robertphillips2af83ac2016-09-12 12:02:16 -0700315 enum Mode {
316 kGaussianEdge_Mode,
317 kBlurMask_Mode,
318 kRRectsGaussianEdge_Mode,
319
320 kLast_Mode = kRRectsGaussianEdge_Mode
321 };
robertphillips2af83ac2016-09-12 12:02:16 -0700322 static const int kModeCount = kLast_Mode + 1;
323
Robert Phillipsa29a9562016-10-20 09:40:55 -0400324 enum CoverageGeom {
325 kRect_CoverageGeom,
326 kRRect_CoverageGeom,
327 kDRRect_CoverageGeom,
328 kPath_CoverageGeom,
329
330 kLast_CoverageGeom = kPath_CoverageGeom
331 };
332 static const int kCoverageGeomCount = kLast_CoverageGeom + 1;
333
Robert Phillips40085e62016-10-18 12:58:29 -0400334 RevealGM()
335 : fFraction(0.5f)
336 , fMode(kRRectsGaussianEdge_Mode)
337 , fPause(false)
Robert Phillipsa29a9562016-10-20 09:40:55 -0400338 , fBlurRadius(kInitialBlurRadius)
339 , fCoverageGeom(kRect_CoverageGeom) {
robertphillips05a4cf52016-09-08 09:02:43 -0700340 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
341 }
342
343protected:
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400344 bool runAsBench() const override { return true; }
robertphillips05a4cf52016-09-08 09:02:43 -0700345
346 SkString onShortName() override {
347 return SkString("reveal");
348 }
349
350 SkISize onISize() override {
351 return SkISize::Make(kNumCols * kCellSize, kNumRows * kCellSize);
352 }
353
354 void onDraw(SkCanvas* canvas) override {
robertphillips2af83ac2016-09-12 12:02:16 -0700355 PFMakeMthd clipMakes[kNumCols] = { Oval::Make, Rect::Make };
356 PFMakeMthd drawMakes[kNumRows] = {
357 RRect::Make, StrokedRRect::Make, Oval::Make, Rect::Make, Pentagon::Make
robertphillips05a4cf52016-09-08 09:02:43 -0700358 };
359
360 SkPaint strokePaint;
robertphillips05a4cf52016-09-08 09:02:43 -0700361 strokePaint.setStyle(SkPaint::kStroke_Style);
362 strokePaint.setStrokeWidth(0.0f);
363
364 for (int y = 0; y < kNumRows; ++y) {
365 for (int x = 0; x < kNumCols; ++x) {
366 SkRect cell = SkRect::MakeXYWH(SkIntToScalar(x*kCellSize),
367 SkIntToScalar(y*kCellSize),
368 SkIntToScalar(kCellSize),
369 SkIntToScalar(kCellSize));
370
robertphillips2af83ac2016-09-12 12:02:16 -0700371 canvas->save();
372 canvas->clipRect(cell);
373
robertphillips05a4cf52016-09-08 09:02:43 -0700374 cell.inset(kPad, kPad);
375 SkPoint clipCenter = SkPoint::Make(cell.centerX() - kClipOffset,
376 cell.centerY() + kClipOffset);
robertphillips05a4cf52016-09-08 09:02:43 -0700377 SkScalar curSize = kCellSize * fFraction;
robertphillips2af83ac2016-09-12 12:02:16 -0700378 const SkRect clipRect = SkRect::MakeLTRB(clipCenter.fX - curSize,
379 clipCenter.fY - curSize,
380 clipCenter.fX + curSize,
381 clipCenter.fY + curSize);
382
Ben Wagner145dbcd2016-11-03 14:40:50 -0400383 std::unique_ptr<Object> clipObj((*clipMakes[x])(clipRect));
384 std::unique_ptr<Object> drawObj((*drawMakes[y])(cell));
robertphillips05a4cf52016-09-08 09:02:43 -0700385
386 // The goal is to replace this clipped draw (which clips the
387 // shadow) with a draw using the geometric clip
robertphillips2af83ac2016-09-12 12:02:16 -0700388 if (kGaussianEdge_Mode == fMode) {
robertphillips05a4cf52016-09-08 09:02:43 -0700389 canvas->save();
robertphillips2af83ac2016-09-12 12:02:16 -0700390 clipObj->clip(canvas);
391
392 // Draw with GaussianEdgeShader
393 SkPaint paint;
394 paint.setAntiAlias(true);
395 // G channel is an F6.2 radius
Robert Phillips40085e62016-10-18 12:58:29 -0400396 int iBlurRad = (int)(4.0f * fBlurRadius);
397 paint.setColor(SkColorSetARGB(255, iBlurRad >> 8, iBlurRad & 0xFF, 0));
robertphillips2af83ac2016-09-12 12:02:16 -0700398 paint.setShader(SkGaussianEdgeShader::Make());
399 drawObj->draw(canvas, paint);
robertphillips05a4cf52016-09-08 09:02:43 -0700400 canvas->restore();
robertphillips2af83ac2016-09-12 12:02:16 -0700401 } else if (kBlurMask_Mode == fMode) {
402 SkPath clippedPath;
robertphillips05a4cf52016-09-08 09:02:43 -0700403
Robert Phillips40085e62016-10-18 12:58:29 -0400404 SkScalar sigma = fBlurRadius / 4.0f;
robertphillipsf619a7a2016-09-12 17:25:50 -0700405
robertphillips2af83ac2016-09-12 12:02:16 -0700406 if (clipObj->contains(drawObj->bounds())) {
robertphillipsf619a7a2016-09-12 17:25:50 -0700407 clippedPath = drawObj->asPath(2.0f*sigma);
robertphillips2af83ac2016-09-12 12:02:16 -0700408 } else {
robertphillipsf619a7a2016-09-12 17:25:50 -0700409 SkPath drawnPath = drawObj->asPath(2.0f*sigma);
410 SkPath clipPath = clipObj->asPath(2.0f*sigma);
robertphillips05a4cf52016-09-08 09:02:43 -0700411
robertphillips2af83ac2016-09-12 12:02:16 -0700412 SkAssertResult(Op(clipPath, drawnPath, kIntersect_SkPathOp, &clippedPath));
413 }
robertphillips05a4cf52016-09-08 09:02:43 -0700414
415 SkPaint blurPaint;
416 blurPaint.setAntiAlias(true);
robertphillipsf619a7a2016-09-12 17:25:50 -0700417 blurPaint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, sigma));
robertphillips05a4cf52016-09-08 09:02:43 -0700418 canvas->drawPath(clippedPath, blurPaint);
robertphillips2af83ac2016-09-12 12:02:16 -0700419 } else {
420 SkASSERT(kRRectsGaussianEdge_Mode == fMode);
421
422 SkRect cover = drawObj->bounds();
423 SkAssertResult(cover.intersect(clipObj->bounds()));
424
425 SkPaint paint;
426
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400427 SkRRect devSpaceClipRR, devSpaceDrawnRR;
robertphillips2af83ac2016-09-12 12:02:16 -0700428
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400429 if (clipObj->asDevSpaceRRect(canvas->getTotalMatrix(), &devSpaceClipRR) &&
430 drawObj->asDevSpaceRRect(canvas->getTotalMatrix(), &devSpaceDrawnRR)) {
431 paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceClipRR,
432 devSpaceDrawnRR,
Robert Phillipsa29a9562016-10-20 09:40:55 -0400433 fBlurRadius));
robertphillips2af83ac2016-09-12 12:02:16 -0700434 }
435
Robert Phillipsa29a9562016-10-20 09:40:55 -0400436 strokePaint.setColor(SK_ColorBLUE);
437
438 switch (fCoverageGeom) {
439 case kRect_CoverageGeom:
440 canvas->drawRect(cover, paint);
441 canvas->drawRect(cover, strokePaint);
442 break;
443 case kRRect_CoverageGeom: {
444 const SkRRect rrect = SkRRect::MakeRectXY(
445 cover.makeOutset(10.0f, 10.0f),
446 10.0f, 10.0f);
447 canvas->drawRRect(rrect, paint);
448 canvas->drawRRect(rrect, strokePaint);
449 break;
450 }
451 case kDRRect_CoverageGeom: {
452 const SkRRect inner = SkRRect::MakeRectXY(cover.makeInset(10.0f, 10.0f),
453 10.0f, 10.0f);
454 const SkRRect outer = SkRRect::MakeRectXY(
455 cover.makeOutset(10.0f, 10.0f),
456 10.0f, 10.0f);
457 canvas->drawDRRect(outer, inner, paint);
458 canvas->drawDRRect(outer, inner, strokePaint);
459 break;
460 }
461 case kPath_CoverageGeom: {
462 SkPath path;
463 path.moveTo(cover.fLeft, cover.fTop);
464 path.lineTo(cover.centerX(), cover.centerY());
465 path.lineTo(cover.fRight, cover.fTop);
466 path.lineTo(cover.fRight, cover.fBottom);
467 path.lineTo(cover.centerX(), cover.centerY());
468 path.lineTo(cover.fLeft, cover.fBottom);
469 path.close();
470 canvas->drawPath(path, paint);
471 canvas->drawPath(path, strokePaint);
472 break;
473 }
474 }
robertphillips05a4cf52016-09-08 09:02:43 -0700475 }
robertphillips2af83ac2016-09-12 12:02:16 -0700476
477 // Draw the clip and draw objects for reference
robertphillips2af83ac2016-09-12 12:02:16 -0700478 strokePaint.setColor(SK_ColorRED);
robertphillipsf619a7a2016-09-12 17:25:50 -0700479 canvas->drawPath(drawObj->asPath(0.0f), strokePaint);
robertphillips2af83ac2016-09-12 12:02:16 -0700480 strokePaint.setColor(SK_ColorGREEN);
robertphillipsf619a7a2016-09-12 17:25:50 -0700481 canvas->drawPath(clipObj->asPath(0.0f), strokePaint);
robertphillips2af83ac2016-09-12 12:02:16 -0700482
483 canvas->restore();
robertphillips05a4cf52016-09-08 09:02:43 -0700484 }
485 }
486 }
487
488 bool onHandleKey(SkUnichar uni) override {
489 switch (uni) {
490 case 'C':
robertphillips2af83ac2016-09-12 12:02:16 -0700491 fMode = (Mode)((fMode + 1) % kModeCount);
robertphillips05a4cf52016-09-08 09:02:43 -0700492 return true;
Robert Phillips40085e62016-10-18 12:58:29 -0400493 case '+':
494 fBlurRadius += 1.0f;
495 return true;
496 case '-':
497 fBlurRadius = SkTMax(1.0f, fBlurRadius - 1.0f);
498 return true;
robertphillipsf619a7a2016-09-12 17:25:50 -0700499 case 'p':
500 fPause = !fPause;
501 return true;
Robert Phillipsa29a9562016-10-20 09:40:55 -0400502 case 'G':
503 fCoverageGeom = (CoverageGeom) ((fCoverageGeom+1) % kCoverageGeomCount);
504 return true;
robertphillips05a4cf52016-09-08 09:02:43 -0700505 }
506
507 return false;
508 }
509
510 bool onAnimate(const SkAnimTimer& timer) override {
robertphillipsf619a7a2016-09-12 17:25:50 -0700511 if (!fPause) {
512 fFraction = timer.pingPong(kPeriod, 0.0f, 0.0f, 1.0f);
513 }
robertphillips05a4cf52016-09-08 09:02:43 -0700514 return true;
515 }
516
517private:
Robert Phillipsa29a9562016-10-20 09:40:55 -0400518 SkScalar fFraction;
519 Mode fMode;
520 bool fPause;
521 float fBlurRadius;
522 CoverageGeom fCoverageGeom;
robertphillips05a4cf52016-09-08 09:02:43 -0700523
524 typedef GM INHERITED;
525};
526
527//////////////////////////////////////////////////////////////////////////////
528
529DEF_GM(return new RevealGM;)
530}