blob: 3e465556ad176adb49cc30b071a26448f263431d [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"
Mike Klein33d20552017-03-22 13:47:51 -04009#include "sk_tool_utils.h"
robertphillips05a4cf52016-09-08 09:02:43 -070010#include "SkAnimTimer.h"
11#include "SkBlurMaskFilter.h"
12#include "SkGaussianEdgeShader.h"
Robert Phillipsa29a9562016-10-20 09:40:55 -040013#include "SkRRectsGaussianEdgeMaskFilter.h"
robertphillips05a4cf52016-09-08 09:02:43 -070014#include "SkPath.h"
15#include "SkPathOps.h"
16#include "SkRRect.h"
17#include "SkStroke.h"
18
19constexpr int kNumCols = 2;
20constexpr int kNumRows = 5;
21constexpr int kCellSize = 128;
22constexpr SkScalar kPad = 8.0f;
Robert Phillips40085e62016-10-18 12:58:29 -040023constexpr SkScalar kInitialBlurRadius = 8.0f;
robertphillips05a4cf52016-09-08 09:02:43 -070024constexpr SkScalar kPeriod = 8.0f;
25constexpr int kClipOffset = 32;
26
27///////////////////////////////////////////////////////////////////////////////////////////////////
robertphillips05a4cf52016-09-08 09:02:43 -070028
robertphillips2af83ac2016-09-12 12:02:16 -070029class Object {
30public:
31 virtual ~Object() {}
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -040032 // When it returns true, this call will have placed a device-space _circle, rect or
33 // simple circular_ RRect in "rr"
34 virtual bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const = 0;
robertphillipsf619a7a2016-09-12 17:25:50 -070035 virtual SkPath asPath(SkScalar inset) const = 0;
robertphillips2af83ac2016-09-12 12:02:16 -070036 virtual void draw(SkCanvas* canvas, const SkPaint& paint) const = 0;
37 virtual void clip(SkCanvas* canvas) const = 0;
38 virtual bool contains(const SkRect& r) const = 0;
39 virtual const SkRect& bounds() const = 0;
40};
robertphillips05a4cf52016-09-08 09:02:43 -070041
robertphillips2af83ac2016-09-12 12:02:16 -070042typedef Object* (*PFMakeMthd)(const SkRect& r);
43
44class RRect : public Object {
45public:
46 RRect(const SkRect& r) {
47 fRRect = SkRRect::MakeRectXY(r, 4*kPad, 4*kPad);
robertphillips05a4cf52016-09-08 09:02:43 -070048 }
robertphillips05a4cf52016-09-08 09:02:43 -070049
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -040050 bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
51 if (!ctm.isSimilarity()) { // the corners have to remain circular
52 return false;
53 }
54
55 SkScalar scales[2];
56 if (!ctm.getMinMaxScales(scales)) {
57 return false;
58 }
59
60 SkASSERT(SkScalarNearlyEqual(scales[0], scales[1]));
61
62 SkRect devRect;
63 ctm.mapRect(&devRect, fRRect.rect());
64
65 SkScalar scaledRad = scales[0] * fRRect.getSimpleRadii().fX;
66
67 *rr = SkRRect::MakeRectXY(devRect, scaledRad, scaledRad);
robertphillips2af83ac2016-09-12 12:02:16 -070068 return true;
69 }
robertphillips05a4cf52016-09-08 09:02:43 -070070
robertphillipsf619a7a2016-09-12 17:25:50 -070071 SkPath asPath(SkScalar inset) const override {
72 SkRRect tmp = fRRect;
73 tmp.inset(inset, inset);
robertphillips2af83ac2016-09-12 12:02:16 -070074 SkPath p;
robertphillipsf619a7a2016-09-12 17:25:50 -070075 p.addRRect(tmp);
robertphillips2af83ac2016-09-12 12:02:16 -070076 return p;
77 }
robertphillips05a4cf52016-09-08 09:02:43 -070078
robertphillips2af83ac2016-09-12 12:02:16 -070079 void draw(SkCanvas* canvas, const SkPaint& paint) const override {
80 canvas->drawRRect(fRRect, paint);
81 }
robertphillips05a4cf52016-09-08 09:02:43 -070082
robertphillips2af83ac2016-09-12 12:02:16 -070083 void clip(SkCanvas* canvas) const override {
84 canvas->clipRRect(fRRect);
85 }
86
87 bool contains(const SkRect& r) const override {
88 return fRRect.contains(r);
89 }
90
91 const SkRect& bounds() const override {
92 return fRRect.getBounds();
93 }
94
95 static Object* Make(const SkRect& r) {
96 return new RRect(r);
97 }
98
99private:
100 SkRRect fRRect;
101};
102
103class StrokedRRect : public Object {
104public:
105 StrokedRRect(const SkRect& r) {
106 fRRect = SkRRect::MakeRectXY(r, 2*kPad, 2*kPad);
107 fStrokedBounds = r.makeOutset(kPad, kPad);
108 }
109
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400110 bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
robertphillips2af83ac2016-09-12 12:02:16 -0700111 return false;
112 }
113
robertphillipsf619a7a2016-09-12 17:25:50 -0700114 SkPath asPath(SkScalar inset) const override {
115 SkRRect tmp = fRRect;
116 tmp.inset(inset, inset);
117
robertphillips2af83ac2016-09-12 12:02:16 -0700118 // In this case we want the outline of the stroked rrect
119 SkPaint paint;
120 paint.setAntiAlias(true);
121 paint.setStyle(SkPaint::kStroke_Style);
122 paint.setStrokeWidth(kPad);
123
robertphillips05a4cf52016-09-08 09:02:43 -0700124 SkPath p, stroked;
robertphillipsf619a7a2016-09-12 17:25:50 -0700125 p.addRRect(tmp);
robertphillips05a4cf52016-09-08 09:02:43 -0700126 SkStroke stroke(paint);
127 stroke.strokePath(p, &stroked);
robertphillips2af83ac2016-09-12 12:02:16 -0700128 return stroked;
robertphillips05a4cf52016-09-08 09:02:43 -0700129 }
130
robertphillips2af83ac2016-09-12 12:02:16 -0700131 void draw(SkCanvas* canvas, const SkPaint& paint) const override {
132 SkPaint stroke(paint);
133 stroke.setStyle(SkPaint::kStroke_Style);
134 stroke.setStrokeWidth(kPad);
robertphillips05a4cf52016-09-08 09:02:43 -0700135
robertphillips2af83ac2016-09-12 12:02:16 -0700136 canvas->drawRRect(fRRect, stroke);
robertphillips05a4cf52016-09-08 09:02:43 -0700137 }
138
robertphillips2af83ac2016-09-12 12:02:16 -0700139 void clip(SkCanvas* canvas) const override {
robertphillipsf619a7a2016-09-12 17:25:50 -0700140 canvas->clipPath(this->asPath(0.0f));
robertphillips05a4cf52016-09-08 09:02:43 -0700141 }
142
robertphillips2af83ac2016-09-12 12:02:16 -0700143 bool contains(const SkRect& r) const override {
144 return false;
robertphillips05a4cf52016-09-08 09:02:43 -0700145 }
146
robertphillips2af83ac2016-09-12 12:02:16 -0700147 const SkRect& bounds() const override {
148 return fStrokedBounds;
149 }
robertphillips05a4cf52016-09-08 09:02:43 -0700150
robertphillips2af83ac2016-09-12 12:02:16 -0700151 static Object* Make(const SkRect& r) {
152 return new StrokedRRect(r);
153 }
robertphillips05a4cf52016-09-08 09:02:43 -0700154
robertphillips2af83ac2016-09-12 12:02:16 -0700155private:
156 SkRRect fRRect;
157 SkRect fStrokedBounds;
158};
robertphillips05a4cf52016-09-08 09:02:43 -0700159
robertphillips2af83ac2016-09-12 12:02:16 -0700160class Oval : public Object {
161public:
162 Oval(const SkRect& r) {
163 fRRect = SkRRect::MakeOval(r);
164 }
165
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400166 bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
167 if (!ctm.isSimilarity()) { // circles have to remain circles
168 return false;
169 }
170
171 SkRect devRect;
172 ctm.mapRect(&devRect, fRRect.rect());
173 *rr = SkRRect::MakeOval(devRect);
robertphillips2af83ac2016-09-12 12:02:16 -0700174 return true;
175 }
176
robertphillipsf619a7a2016-09-12 17:25:50 -0700177 SkPath asPath(SkScalar inset) const override {
178 SkRRect tmp = fRRect;
179 tmp.inset(inset, inset);
180
robertphillips2af83ac2016-09-12 12:02:16 -0700181 SkPath p;
robertphillipsf619a7a2016-09-12 17:25:50 -0700182 p.addRRect(tmp);
robertphillips2af83ac2016-09-12 12:02:16 -0700183 return p;
184 }
185
186 void draw(SkCanvas* canvas, const SkPaint& paint) const override {
187 canvas->drawRRect(fRRect, paint);
188 }
189
190 void clip(SkCanvas* canvas) const override {
191 canvas->clipRRect(fRRect);
192 }
193
194 bool contains(const SkRect& r) const override {
195 return fRRect.contains(r);
196 }
197
198 const SkRect& bounds() const override {
199 return fRRect.getBounds();
200 }
201
202 static Object* Make(const SkRect& r) {
203 return new Oval(r);
204 }
205
206private:
207 SkRRect fRRect;
208};
209
210class Rect : public Object {
211public:
212 Rect(const SkRect& r) : fRect(r) { }
213
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400214 bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
215 if (!ctm.rectStaysRect()) {
216 return false;
217 }
218
219 SkRect devRect;
220 ctm.mapRect(&devRect, fRect);
221 *rr = SkRRect::MakeRect(devRect);
robertphillips2af83ac2016-09-12 12:02:16 -0700222 return true;
223 }
224
robertphillipsf619a7a2016-09-12 17:25:50 -0700225 SkPath asPath(SkScalar inset) const override {
226 SkRect tmp = fRect;
227 tmp.inset(inset, inset);
228
robertphillips2af83ac2016-09-12 12:02:16 -0700229 SkPath p;
robertphillipsf619a7a2016-09-12 17:25:50 -0700230 p.addRect(tmp);
robertphillips2af83ac2016-09-12 12:02:16 -0700231 return p;
232 }
233
234 void draw(SkCanvas* canvas, const SkPaint& paint) const override {
235 canvas->drawRect(fRect, paint);
236 }
237
238 void clip(SkCanvas* canvas) const override {
239 canvas->clipRect(fRect);
240 }
241
242 bool contains(const SkRect& r) const override {
243 return fRect.contains(r);
244 }
245
246 const SkRect& bounds() const override {
247 return fRect;
248 }
249
250 static Object* Make(const SkRect& r) {
251 return new Rect(r);
252 }
253
254private:
255 SkRect fRect;
256};
257
258class Pentagon : public Object {
259public:
260 Pentagon(const SkRect& r) {
261 SkPoint points[5] = {
262 { 0.000000f, -1.000000f },
263 { -0.951056f, -0.309017f },
264 { -0.587785f, 0.809017f },
265 { 0.587785f, 0.809017f },
266 { 0.951057f, -0.309017f },
267 };
268
269 SkScalar height = r.height()/2.0f;
270 SkScalar width = r.width()/2.0f;
271
272 fPath.moveTo(r.centerX() + points[0].fX * width, r.centerY() + points[0].fY * height);
273 fPath.lineTo(r.centerX() + points[1].fX * width, r.centerY() + points[1].fY * height);
274 fPath.lineTo(r.centerX() + points[2].fX * width, r.centerY() + points[2].fY * height);
275 fPath.lineTo(r.centerX() + points[3].fX * width, r.centerY() + points[3].fY * height);
276 fPath.lineTo(r.centerX() + points[4].fX * width, r.centerY() + points[4].fY * height);
277 fPath.close();
278 }
279
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400280 bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
robertphillips2af83ac2016-09-12 12:02:16 -0700281 return false;
282 }
283
robertphillipsf619a7a2016-09-12 17:25:50 -0700284 SkPath asPath(SkScalar inset) const override { return fPath; }
robertphillips2af83ac2016-09-12 12:02:16 -0700285
286 void draw(SkCanvas* canvas, const SkPaint& paint) const override {
287 canvas->drawPath(fPath, paint);
288 }
289
290 void clip(SkCanvas* canvas) const override {
robertphillipsf619a7a2016-09-12 17:25:50 -0700291 canvas->clipPath(this->asPath(0.0f));
robertphillips2af83ac2016-09-12 12:02:16 -0700292 }
293
294 bool contains(const SkRect& r) const override {
295 return false;
296 }
297
298 const SkRect& bounds() const override {
299 return fPath.getBounds();
300 }
301
302 static Object* Make(const SkRect& r) {
303 return new Pentagon(r);
304 }
305
306private:
307 SkPath fPath;
308};
robertphillips05a4cf52016-09-08 09:02:43 -0700309
310///////////////////////////////////////////////////////////////////////////////////////////////////
311namespace skiagm {
312
313// This GM attempts to mimic Android's reveal animation
314class RevealGM : public GM {
315public:
robertphillips2af83ac2016-09-12 12:02:16 -0700316 enum Mode {
317 kGaussianEdge_Mode,
318 kBlurMask_Mode,
319 kRRectsGaussianEdge_Mode,
320
321 kLast_Mode = kRRectsGaussianEdge_Mode
322 };
robertphillips2af83ac2016-09-12 12:02:16 -0700323 static const int kModeCount = kLast_Mode + 1;
324
Robert Phillipsa29a9562016-10-20 09:40:55 -0400325 enum CoverageGeom {
326 kRect_CoverageGeom,
327 kRRect_CoverageGeom,
328 kDRRect_CoverageGeom,
329 kPath_CoverageGeom,
330
331 kLast_CoverageGeom = kPath_CoverageGeom
332 };
333 static const int kCoverageGeomCount = kLast_CoverageGeom + 1;
334
Robert Phillips40085e62016-10-18 12:58:29 -0400335 RevealGM()
336 : fFraction(0.5f)
337 , fMode(kRRectsGaussianEdge_Mode)
338 , fPause(false)
Robert Phillipsa29a9562016-10-20 09:40:55 -0400339 , fBlurRadius(kInitialBlurRadius)
340 , fCoverageGeom(kRect_CoverageGeom) {
robertphillips05a4cf52016-09-08 09:02:43 -0700341 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
342 }
343
344protected:
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400345 bool runAsBench() const override { return true; }
robertphillips05a4cf52016-09-08 09:02:43 -0700346
347 SkString onShortName() override {
348 return SkString("reveal");
349 }
350
351 SkISize onISize() override {
352 return SkISize::Make(kNumCols * kCellSize, kNumRows * kCellSize);
353 }
354
355 void onDraw(SkCanvas* canvas) override {
robertphillips2af83ac2016-09-12 12:02:16 -0700356 PFMakeMthd clipMakes[kNumCols] = { Oval::Make, Rect::Make };
357 PFMakeMthd drawMakes[kNumRows] = {
358 RRect::Make, StrokedRRect::Make, Oval::Make, Rect::Make, Pentagon::Make
robertphillips05a4cf52016-09-08 09:02:43 -0700359 };
360
361 SkPaint strokePaint;
robertphillips05a4cf52016-09-08 09:02:43 -0700362 strokePaint.setStyle(SkPaint::kStroke_Style);
363 strokePaint.setStrokeWidth(0.0f);
364
365 for (int y = 0; y < kNumRows; ++y) {
366 for (int x = 0; x < kNumCols; ++x) {
367 SkRect cell = SkRect::MakeXYWH(SkIntToScalar(x*kCellSize),
368 SkIntToScalar(y*kCellSize),
369 SkIntToScalar(kCellSize),
370 SkIntToScalar(kCellSize));
371
robertphillips2af83ac2016-09-12 12:02:16 -0700372 canvas->save();
373 canvas->clipRect(cell);
374
robertphillips05a4cf52016-09-08 09:02:43 -0700375 cell.inset(kPad, kPad);
376 SkPoint clipCenter = SkPoint::Make(cell.centerX() - kClipOffset,
377 cell.centerY() + kClipOffset);
robertphillips05a4cf52016-09-08 09:02:43 -0700378 SkScalar curSize = kCellSize * fFraction;
robertphillips2af83ac2016-09-12 12:02:16 -0700379 const SkRect clipRect = SkRect::MakeLTRB(clipCenter.fX - curSize,
380 clipCenter.fY - curSize,
381 clipCenter.fX + curSize,
382 clipCenter.fY + curSize);
383
Ben Wagner145dbcd2016-11-03 14:40:50 -0400384 std::unique_ptr<Object> clipObj((*clipMakes[x])(clipRect));
385 std::unique_ptr<Object> drawObj((*drawMakes[y])(cell));
robertphillips05a4cf52016-09-08 09:02:43 -0700386
387 // The goal is to replace this clipped draw (which clips the
388 // shadow) with a draw using the geometric clip
robertphillips2af83ac2016-09-12 12:02:16 -0700389 if (kGaussianEdge_Mode == fMode) {
robertphillips05a4cf52016-09-08 09:02:43 -0700390 canvas->save();
robertphillips2af83ac2016-09-12 12:02:16 -0700391 clipObj->clip(canvas);
392
393 // Draw with GaussianEdgeShader
394 SkPaint paint;
395 paint.setAntiAlias(true);
396 // G channel is an F6.2 radius
Robert Phillips40085e62016-10-18 12:58:29 -0400397 int iBlurRad = (int)(4.0f * fBlurRadius);
398 paint.setColor(SkColorSetARGB(255, iBlurRad >> 8, iBlurRad & 0xFF, 0));
robertphillips2af83ac2016-09-12 12:02:16 -0700399 paint.setShader(SkGaussianEdgeShader::Make());
400 drawObj->draw(canvas, paint);
robertphillips05a4cf52016-09-08 09:02:43 -0700401 canvas->restore();
robertphillips2af83ac2016-09-12 12:02:16 -0700402 } else if (kBlurMask_Mode == fMode) {
403 SkPath clippedPath;
robertphillips05a4cf52016-09-08 09:02:43 -0700404
Robert Phillips40085e62016-10-18 12:58:29 -0400405 SkScalar sigma = fBlurRadius / 4.0f;
robertphillipsf619a7a2016-09-12 17:25:50 -0700406
robertphillips2af83ac2016-09-12 12:02:16 -0700407 if (clipObj->contains(drawObj->bounds())) {
robertphillipsf619a7a2016-09-12 17:25:50 -0700408 clippedPath = drawObj->asPath(2.0f*sigma);
robertphillips2af83ac2016-09-12 12:02:16 -0700409 } else {
robertphillipsf619a7a2016-09-12 17:25:50 -0700410 SkPath drawnPath = drawObj->asPath(2.0f*sigma);
411 SkPath clipPath = clipObj->asPath(2.0f*sigma);
robertphillips05a4cf52016-09-08 09:02:43 -0700412
robertphillips2af83ac2016-09-12 12:02:16 -0700413 SkAssertResult(Op(clipPath, drawnPath, kIntersect_SkPathOp, &clippedPath));
414 }
robertphillips05a4cf52016-09-08 09:02:43 -0700415
416 SkPaint blurPaint;
417 blurPaint.setAntiAlias(true);
robertphillipsf619a7a2016-09-12 17:25:50 -0700418 blurPaint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, sigma));
robertphillips05a4cf52016-09-08 09:02:43 -0700419 canvas->drawPath(clippedPath, blurPaint);
robertphillips2af83ac2016-09-12 12:02:16 -0700420 } else {
421 SkASSERT(kRRectsGaussianEdge_Mode == fMode);
422
423 SkRect cover = drawObj->bounds();
424 SkAssertResult(cover.intersect(clipObj->bounds()));
425
426 SkPaint paint;
427
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400428 SkRRect devSpaceClipRR, devSpaceDrawnRR;
robertphillips2af83ac2016-09-12 12:02:16 -0700429
Robert Phillipsd2fe3bc2016-10-20 11:58:40 -0400430 if (clipObj->asDevSpaceRRect(canvas->getTotalMatrix(), &devSpaceClipRR) &&
431 drawObj->asDevSpaceRRect(canvas->getTotalMatrix(), &devSpaceDrawnRR)) {
432 paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceClipRR,
433 devSpaceDrawnRR,
Robert Phillipsa29a9562016-10-20 09:40:55 -0400434 fBlurRadius));
robertphillips2af83ac2016-09-12 12:02:16 -0700435 }
436
Robert Phillipsa29a9562016-10-20 09:40:55 -0400437 strokePaint.setColor(SK_ColorBLUE);
438
439 switch (fCoverageGeom) {
440 case kRect_CoverageGeom:
441 canvas->drawRect(cover, paint);
442 canvas->drawRect(cover, strokePaint);
443 break;
444 case kRRect_CoverageGeom: {
445 const SkRRect rrect = SkRRect::MakeRectXY(
446 cover.makeOutset(10.0f, 10.0f),
447 10.0f, 10.0f);
448 canvas->drawRRect(rrect, paint);
449 canvas->drawRRect(rrect, strokePaint);
450 break;
451 }
452 case kDRRect_CoverageGeom: {
453 const SkRRect inner = SkRRect::MakeRectXY(cover.makeInset(10.0f, 10.0f),
454 10.0f, 10.0f);
455 const SkRRect outer = SkRRect::MakeRectXY(
456 cover.makeOutset(10.0f, 10.0f),
457 10.0f, 10.0f);
458 canvas->drawDRRect(outer, inner, paint);
459 canvas->drawDRRect(outer, inner, strokePaint);
460 break;
461 }
462 case kPath_CoverageGeom: {
463 SkPath path;
464 path.moveTo(cover.fLeft, cover.fTop);
465 path.lineTo(cover.centerX(), cover.centerY());
466 path.lineTo(cover.fRight, cover.fTop);
467 path.lineTo(cover.fRight, cover.fBottom);
468 path.lineTo(cover.centerX(), cover.centerY());
469 path.lineTo(cover.fLeft, cover.fBottom);
470 path.close();
471 canvas->drawPath(path, paint);
472 canvas->drawPath(path, strokePaint);
473 break;
474 }
475 }
robertphillips05a4cf52016-09-08 09:02:43 -0700476 }
robertphillips2af83ac2016-09-12 12:02:16 -0700477
478 // Draw the clip and draw objects for reference
robertphillips2af83ac2016-09-12 12:02:16 -0700479 strokePaint.setColor(SK_ColorRED);
robertphillipsf619a7a2016-09-12 17:25:50 -0700480 canvas->drawPath(drawObj->asPath(0.0f), strokePaint);
robertphillips2af83ac2016-09-12 12:02:16 -0700481 strokePaint.setColor(SK_ColorGREEN);
robertphillipsf619a7a2016-09-12 17:25:50 -0700482 canvas->drawPath(clipObj->asPath(0.0f), strokePaint);
robertphillips2af83ac2016-09-12 12:02:16 -0700483
484 canvas->restore();
robertphillips05a4cf52016-09-08 09:02:43 -0700485 }
486 }
487 }
488
489 bool onHandleKey(SkUnichar uni) override {
490 switch (uni) {
491 case 'C':
robertphillips2af83ac2016-09-12 12:02:16 -0700492 fMode = (Mode)((fMode + 1) % kModeCount);
robertphillips05a4cf52016-09-08 09:02:43 -0700493 return true;
Robert Phillips40085e62016-10-18 12:58:29 -0400494 case '+':
495 fBlurRadius += 1.0f;
496 return true;
497 case '-':
498 fBlurRadius = SkTMax(1.0f, fBlurRadius - 1.0f);
499 return true;
robertphillipsf619a7a2016-09-12 17:25:50 -0700500 case 'p':
501 fPause = !fPause;
502 return true;
Robert Phillipsa29a9562016-10-20 09:40:55 -0400503 case 'G':
504 fCoverageGeom = (CoverageGeom) ((fCoverageGeom+1) % kCoverageGeomCount);
505 return true;
robertphillips05a4cf52016-09-08 09:02:43 -0700506 }
507
508 return false;
509 }
510
511 bool onAnimate(const SkAnimTimer& timer) override {
robertphillipsf619a7a2016-09-12 17:25:50 -0700512 if (!fPause) {
513 fFraction = timer.pingPong(kPeriod, 0.0f, 0.0f, 1.0f);
514 }
robertphillips05a4cf52016-09-08 09:02:43 -0700515 return true;
516 }
517
518private:
Robert Phillipsa29a9562016-10-20 09:40:55 -0400519 SkScalar fFraction;
520 Mode fMode;
521 bool fPause;
522 float fBlurRadius;
523 CoverageGeom fCoverageGeom;
robertphillips05a4cf52016-09-08 09:02:43 -0700524
525 typedef GM INHERITED;
526};
527
528//////////////////////////////////////////////////////////////////////////////
529
530DEF_GM(return new RevealGM;)
531}