blob: c37fcae457c4cc8e1b9a2521cbeb649b8d20f8e7 [file] [log] [blame]
reedafdbedb2015-01-14 13:16:26 -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 "gm.h"
9
10#include "Resources.h"
11#include "SampleCode.h"
reed339cdbf2015-02-05 22:02:37 -080012#include "SkAnimTimer.h"
reedafdbedb2015-01-14 13:16:26 -080013#include "SkCanvas.h"
14#include "SkInterpolator.h"
reed73f6cfc2015-11-09 08:36:05 -080015#include "SkGradientShader.h"
16#include "SkData.h"
bungemand3ebb482015-08-05 13:57:49 -070017#include "SkPath.h"
reedafdbedb2015-01-14 13:16:26 -080018#include "SkSurface.h"
19#include "SkRandom.h"
20#include "SkTime.h"
21
reed09519db2015-01-17 19:36:08 -080022static SkSurface* make_surface(SkCanvas* canvas, const SkImageInfo& info) {
23 SkSurface* surface = canvas->newSurface(info);
24 if (!surface) {
25 surface = SkSurface::NewRaster(info);
26 }
27 return surface;
28}
29
reed73f6cfc2015-11-09 08:36:05 -080030static SkShader* make_shader(const SkRect& bounds) {
31#if 0
32 const SkPoint pts[] = {
33 { bounds.left(), bounds.top() },
34 { bounds.right(), bounds.bottom() },
35 };
36 const SkColor colors[] = {
37 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK,
38 SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW,
39 };
40 return SkGradientShader::CreateLinear(pts,
41 colors, nullptr, SK_ARRAY_COUNT(colors),
42 SkShader::kClamp_TileMode);
43#else
bungemanfbd87d62015-11-10 13:29:43 -080044 SkAutoTUnref<SkImage> image(GetResourceAsImage("mandrill_128.png"));
45 if (nullptr == image) {
46 return nullptr;
47 }
reed73f6cfc2015-11-09 08:36:05 -080048 return image->newShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
49#endif
50}
51
reedafdbedb2015-01-14 13:16:26 -080052#define N 128
reed09519db2015-01-17 19:36:08 -080053#define ANGLE_DELTA 3
54#define SCALE_DELTA (SK_Scalar1 / 32)
reedafdbedb2015-01-14 13:16:26 -080055
56static SkImage* make_image() {
reed09519db2015-01-17 19:36:08 -080057 SkImageInfo info = SkImageInfo::MakeN32(N, N, kOpaque_SkAlphaType);
reedafdbedb2015-01-14 13:16:26 -080058 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
59 SkCanvas* canvas = surface->getCanvas();
reed09519db2015-01-17 19:36:08 -080060 canvas->drawColor(SK_ColorWHITE);
reedafdbedb2015-01-14 13:16:26 -080061
62 SkPath path;
63 path.setFillType(SkPath::kEvenOdd_FillType);
64
65 path.addRect(SkRect::MakeWH(N/2, N));
66 path.addRect(SkRect::MakeWH(N, N/2));
67 path.moveTo(0, 0); path.lineTo(N, 0); path.lineTo(0, N); path.close();
68
reed73f6cfc2015-11-09 08:36:05 -080069 SkPaint paint;
bungemanfbd87d62015-11-10 13:29:43 -080070 SkSafeUnref(paint.setShader(make_shader(SkRect::MakeWH(N, N))));
reed73f6cfc2015-11-09 08:36:05 -080071
72 canvas->drawPath(path, paint);
reedafdbedb2015-01-14 13:16:26 -080073 return surface->newImageSnapshot();
74}
75
reed7b6945b2015-09-24 00:50:58 -070076static SkImage* zoom_up(SkSurface* origSurf, SkImage* orig) {
reed73f6cfc2015-11-09 08:36:05 -080077 const SkScalar S = 16; // amount to scale up
reed09519db2015-01-17 19:36:08 -080078 const int D = 2; // dimension scaling for the offscreen
79 // since we only view the center, don't need to produce the entire thing
80
81 SkImageInfo info = SkImageInfo::MakeN32(orig->width() * D, orig->height() * D,
82 kOpaque_SkAlphaType);
reed7b6945b2015-09-24 00:50:58 -070083 SkAutoTUnref<SkSurface> surface(origSurf->newSurface(info));
reed09519db2015-01-17 19:36:08 -080084 SkCanvas* canvas = surface->getCanvas();
85 canvas->drawColor(SK_ColorWHITE);
86 canvas->scale(S, S);
87 canvas->translate(-SkScalarHalf(orig->width()) * (S - D) / S,
88 -SkScalarHalf(orig->height()) * (S - D) / S);
halcanary96fcdcc2015-08-27 07:41:13 -070089 canvas->drawImage(orig, 0, 0, nullptr);
reed09519db2015-01-17 19:36:08 -080090
91 if (S > 3) {
92 SkPaint paint;
93 paint.setColor(SK_ColorWHITE);
94 for (int i = 1; i < orig->height(); ++i) {
95 SkScalar y = SkIntToScalar(i);
96 canvas->drawLine(0, y, SkIntToScalar(orig->width()), y, paint);
97 }
98 for (int i = 1; i < orig->width(); ++i) {
99 SkScalar x = SkIntToScalar(i);
100 canvas->drawLine(x, 0, x, SkIntToScalar(orig->height()), paint);
101 }
102 }
103 return surface->newImageSnapshot();
104}
105
reedafdbedb2015-01-14 13:16:26 -0800106struct AnimValue {
107 SkScalar fValue;
108 SkScalar fMin;
109 SkScalar fMax;
110 SkScalar fMod;
111
112 operator SkScalar() const { return fValue; }
113
114 void set(SkScalar value, SkScalar min, SkScalar max) {
115 fValue = value;
116 fMin = min;
117 fMax = max;
118 fMod = 0;
119 }
120
121 void setMod(SkScalar value, SkScalar mod) {
122 fValue = value;
123 fMin = 0;
124 fMax = 0;
125 fMod = mod;
126 }
127
128 SkScalar inc(SkScalar delta) {
129 fValue += delta;
130 return this->fixUp();
131 }
132
133 SkScalar fixUp() {
134 if (fMod) {
135 fValue = SkScalarMod(fValue, fMod);
136 } else {
137 if (fValue > fMax) {
138 fValue = fMax;
139 } else if (fValue < fMin) {
140 fValue = fMin;
141 }
142 }
143 return fValue;
144 }
145};
146
reed09519db2015-01-17 19:36:08 -0800147static void draw_box_frame(SkCanvas* canvas, int width, int height) {
148 SkPaint p;
149 p.setStyle(SkPaint::kStroke_Style);
150 p.setColor(SK_ColorRED);
151 SkRect r = SkRect::MakeIWH(width, height);
152 r.inset(0.5f, 0.5f);
153 canvas->drawRect(r, p);
154 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
155 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
156}
reedafdbedb2015-01-14 13:16:26 -0800157
158class FilterQualityView : public SampleView {
159 SkAutoTUnref<SkImage> fImage;
160 AnimValue fScale, fAngle;
reed09519db2015-01-17 19:36:08 -0800161 SkSize fCell;
reedafdbedb2015-01-14 13:16:26 -0800162 SkInterpolator fTrans;
reed339cdbf2015-02-05 22:02:37 -0800163 SkMSec fCurrTime;
reed09519db2015-01-17 19:36:08 -0800164 bool fShowFatBits;
reedafdbedb2015-01-14 13:16:26 -0800165
166public:
reed09519db2015-01-17 19:36:08 -0800167 FilterQualityView() : fImage(make_image()), fTrans(2, 2), fShowFatBits(true) {
168 fCell.set(256, 256);
169
reedafdbedb2015-01-14 13:16:26 -0800170 fScale.set(1, SK_Scalar1 / 8, 1);
171 fAngle.setMod(0, 360);
172
173 SkScalar values[2];
174 fTrans.setMirror(true);
175 fTrans.setReset(true);
176
reed339cdbf2015-02-05 22:02:37 -0800177 fCurrTime = 0;
178
reedafdbedb2015-01-14 13:16:26 -0800179 fTrans.setRepeatCount(999);
180 values[0] = values[1] = 0;
reed339cdbf2015-02-05 22:02:37 -0800181 fTrans.setKeyFrame(0, fCurrTime, values);
reedafdbedb2015-01-14 13:16:26 -0800182 values[0] = values[1] = 1;
reed339cdbf2015-02-05 22:02:37 -0800183 fTrans.setKeyFrame(1, fCurrTime + 2000, values);
reedafdbedb2015-01-14 13:16:26 -0800184 }
185
186protected:
mtklein36352bf2015-03-25 18:17:31 -0700187 bool onQuery(SkEvent* evt) override {
reedafdbedb2015-01-14 13:16:26 -0800188 if (SampleCode::TitleQ(*evt)) {
189 SampleCode::TitleR(evt, "FilterQuality");
190 return true;
191 }
192 SkUnichar uni;
193 if (SampleCode::CharQ(*evt, &uni)) {
194 switch (uni) {
halcanary96fcdcc2015-08-27 07:41:13 -0700195 case '1': fAngle.inc(-ANGLE_DELTA); this->inval(nullptr); return true;
196 case '2': fAngle.inc( ANGLE_DELTA); this->inval(nullptr); return true;
197 case '3': fScale.inc(-SCALE_DELTA); this->inval(nullptr); return true;
198 case '4': fScale.inc( SCALE_DELTA); this->inval(nullptr); return true;
199 case '5': fShowFatBits = !fShowFatBits; this->inval(nullptr); return true;
reedafdbedb2015-01-14 13:16:26 -0800200 default: break;
201 }
202 }
203 return this->INHERITED::onQuery(evt);
204 }
205
reed93a12152015-03-16 10:08:34 -0700206 void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
reed09519db2015-01-17 19:36:08 -0800207 SkScalar dx, SkScalar dy) {
reedafdbedb2015-01-14 13:16:26 -0800208 SkPaint paint;
209 paint.setAntiAlias(true);
reed93a12152015-03-16 10:08:34 -0700210 paint.setFilterQuality(filter);
reedafdbedb2015-01-14 13:16:26 -0800211
reed09519db2015-01-17 19:36:08 -0800212 SkAutoCanvasRestore acr(canvas, true);
213
214 canvas->translate(dx, dy);
215
216 canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
reedafdbedb2015-01-14 13:16:26 -0800217 canvas->scale(fScale, fScale);
218 canvas->rotate(fAngle);
219 canvas->drawImage(fImage, -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
220 &paint);
reed09519db2015-01-17 19:36:08 -0800221
222 if (false) {
223 acr.restore();
224 draw_box_frame(canvas, size.width(), size.height());
225 }
226 }
227
reed93a12152015-03-16 10:08:34 -0700228 void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
reed09519db2015-01-17 19:36:08 -0800229 SkCanvas* origCanvas = canvas;
230 SkAutoCanvasRestore acr(canvas, true);
231
232 SkISize size = SkISize::Make(fImage->width(), fImage->height());
233
234 SkAutoTUnref<SkSurface> surface;
235 if (fShowFatBits) {
236 // scale up so we don't clip rotations
237 SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
238 kOpaque_SkAlphaType);
239 surface.reset(make_surface(canvas, info));
240 canvas = surface->getCanvas();
241 canvas->drawColor(SK_ColorWHITE);
242 size.set(info.width(), info.height());
243 } else {
244 canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
245 SkScalarHalf(fCell.height() - fImage->height()));
246 }
247 this->drawTheImage(canvas, size, filter, dx, dy);
248
249 if (surface) {
250 SkAutoTUnref<SkImage> orig(surface->newImageSnapshot());
reed7b6945b2015-09-24 00:50:58 -0700251 SkAutoTUnref<SkImage> zoomed(zoom_up(surface, orig));
reed09519db2015-01-17 19:36:08 -0800252 origCanvas->drawImage(zoomed,
253 SkScalarHalf(fCell.width() - zoomed->width()),
254 SkScalarHalf(fCell.height() - zoomed->height()));
255 }
256 }
257
258 void drawBorders(SkCanvas* canvas) {
259 SkPaint p;
260 p.setStyle(SkPaint::kStroke_Style);
261 p.setColor(SK_ColorBLUE);
262
263 SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
264 r.inset(SK_ScalarHalf, SK_ScalarHalf);
265 canvas->drawRect(r, p);
266 canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
267 canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
reedafdbedb2015-01-14 13:16:26 -0800268 }
269
mtklein36352bf2015-03-25 18:17:31 -0700270 void onDrawContent(SkCanvas* canvas) override {
reed09519db2015-01-17 19:36:08 -0800271 fCell.set(this->height() / 2, this->height() / 2);
272
reedafdbedb2015-01-14 13:16:26 -0800273 SkScalar trans[2];
reed339cdbf2015-02-05 22:02:37 -0800274 fTrans.timeToValues(fCurrTime, trans);
reedafdbedb2015-01-14 13:16:26 -0800275
reed09519db2015-01-17 19:36:08 -0800276 for (int y = 0; y < 2; ++y) {
277 for (int x = 0; x < 2; ++x) {
278 int index = y * 2 + x;
279 SkAutoCanvasRestore acr(canvas, true);
280 canvas->translate(fCell.width() * x, fCell.height() * y);
281 SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
282 r.inset(4, 4);
283 canvas->clipRect(r);
reed93a12152015-03-16 10:08:34 -0700284 this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
reed09519db2015-01-17 19:36:08 -0800285 }
reedafdbedb2015-01-14 13:16:26 -0800286 }
287
reed09519db2015-01-17 19:36:08 -0800288 this->drawBorders(canvas);
289
290 const SkScalar textX = fCell.width() * 2 + 30;
291
reedafdbedb2015-01-14 13:16:26 -0800292 SkPaint paint;
293 paint.setAntiAlias(true);
reed09519db2015-01-17 19:36:08 -0800294 paint.setTextSize(36);
reedafdbedb2015-01-14 13:16:26 -0800295 SkString str;
296 str.appendScalar(fScale);
reed09519db2015-01-17 19:36:08 -0800297 canvas->drawText(str.c_str(), str.size(), textX, 100, paint);
reedafdbedb2015-01-14 13:16:26 -0800298 str.reset(); str.appendScalar(fAngle);
reed09519db2015-01-17 19:36:08 -0800299 canvas->drawText(str.c_str(), str.size(), textX, 150, paint);
reedafdbedb2015-01-14 13:16:26 -0800300
301 str.reset(); str.appendScalar(trans[0]);
reed09519db2015-01-17 19:36:08 -0800302 canvas->drawText(str.c_str(), str.size(), textX, 200, paint);
reedafdbedb2015-01-14 13:16:26 -0800303 str.reset(); str.appendScalar(trans[1]);
reed09519db2015-01-17 19:36:08 -0800304 canvas->drawText(str.c_str(), str.size(), textX, 250, paint);
reed339cdbf2015-02-05 22:02:37 -0800305 }
reed09519db2015-01-17 19:36:08 -0800306
mtklein36352bf2015-03-25 18:17:31 -0700307 bool onAnimate(const SkAnimTimer& timer) override {
reed339cdbf2015-02-05 22:02:37 -0800308 fCurrTime = timer.msec();
309 return true;
reed09519db2015-01-17 19:36:08 -0800310 }
reedafdbedb2015-01-14 13:16:26 -0800311
312 virtual bool handleKey(SkKey key) {
halcanary96fcdcc2015-08-27 07:41:13 -0700313 this->inval(nullptr);
reedafdbedb2015-01-14 13:16:26 -0800314 return true;
315 }
316
317private:
318 typedef SampleView INHERITED;
319};
320
321//////////////////////////////////////////////////////////////////////////////
322
323static SkView* MyFactory() { return new FilterQualityView; }
324static SkViewRegister reg(MyFactory);