blob: a686efbdd2ae4172827eb4687029cd0945116ad3 [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
reedafdbedb2015-01-14 13:16:26 -08008#include "Resources.h"
Ben Wagnerb2c4ea62018-08-08 11:36:17 -04009#include "Sample.h"
reed339cdbf2015-02-05 22:02:37 -080010#include "SkAnimTimer.h"
reedafdbedb2015-01-14 13:16:26 -080011#include "SkCanvas.h"
12#include "SkInterpolator.h"
reed73f6cfc2015-11-09 08:36:05 -080013#include "SkGradientShader.h"
14#include "SkData.h"
bungemand3ebb482015-08-05 13:57:49 -070015#include "SkPath.h"
reedafdbedb2015-01-14 13:16:26 -080016#include "SkSurface.h"
17#include "SkRandom.h"
18#include "SkTime.h"
19
Cary Clarka24712e2018-09-05 18:41:40 +000020static sk_sp<SkSurface> make_surface(SkCanvas* canvas, const SkImageInfo& info) {
21 auto surface = canvas->makeSurface(info);
22 if (!surface) {
23 surface = SkSurface::MakeRaster(info);
24 }
25 return surface;
26}
27
reed5671c5b2016-03-09 14:47:34 -080028static sk_sp<SkShader> make_shader(const SkRect& bounds) {
Hal Canaryc465d132017-12-08 10:21:31 -050029 sk_sp<SkImage> image(GetResourceAsImage("images/mandrill_128.png"));
Mike Reed0acd7952017-04-28 11:12:19 -040030 return image ? image->makeShader() : nullptr;
reed73f6cfc2015-11-09 08:36:05 -080031}
32
reedafdbedb2015-01-14 13:16:26 -080033#define N 128
reed09519db2015-01-17 19:36:08 -080034#define ANGLE_DELTA 3
35#define SCALE_DELTA (SK_Scalar1 / 32)
reedafdbedb2015-01-14 13:16:26 -080036
reed9ce9d672016-03-17 10:51:11 -070037static sk_sp<SkImage> make_image() {
reed09519db2015-01-17 19:36:08 -080038 SkImageInfo info = SkImageInfo::MakeN32(N, N, kOpaque_SkAlphaType);
reede8f30622016-03-23 18:59:25 -070039 auto surface(SkSurface::MakeRaster(info));
reedafdbedb2015-01-14 13:16:26 -080040 SkCanvas* canvas = surface->getCanvas();
reed09519db2015-01-17 19:36:08 -080041 canvas->drawColor(SK_ColorWHITE);
reedafdbedb2015-01-14 13:16:26 -080042
43 SkPath path;
44 path.setFillType(SkPath::kEvenOdd_FillType);
45
46 path.addRect(SkRect::MakeWH(N/2, N));
47 path.addRect(SkRect::MakeWH(N, N/2));
48 path.moveTo(0, 0); path.lineTo(N, 0); path.lineTo(0, N); path.close();
49
reed73f6cfc2015-11-09 08:36:05 -080050 SkPaint paint;
reed5671c5b2016-03-09 14:47:34 -080051 paint.setShader(make_shader(SkRect::MakeWH(N, N)));
halcanary9d524f22016-03-29 09:03:52 -070052
reed73f6cfc2015-11-09 08:36:05 -080053 canvas->drawPath(path, paint);
reed9ce9d672016-03-17 10:51:11 -070054 return surface->makeImageSnapshot();
reedafdbedb2015-01-14 13:16:26 -080055}
56
reed9ce9d672016-03-17 10:51:11 -070057static sk_sp<SkImage> zoom_up(SkSurface* origSurf, SkImage* orig) {
reed73f6cfc2015-11-09 08:36:05 -080058 const SkScalar S = 16; // amount to scale up
reed09519db2015-01-17 19:36:08 -080059 const int D = 2; // dimension scaling for the offscreen
60 // since we only view the center, don't need to produce the entire thing
halcanary9d524f22016-03-29 09:03:52 -070061
reed09519db2015-01-17 19:36:08 -080062 SkImageInfo info = SkImageInfo::MakeN32(orig->width() * D, orig->height() * D,
63 kOpaque_SkAlphaType);
reede8f30622016-03-23 18:59:25 -070064 auto surface(origSurf->makeSurface(info));
reed09519db2015-01-17 19:36:08 -080065 SkCanvas* canvas = surface->getCanvas();
66 canvas->drawColor(SK_ColorWHITE);
67 canvas->scale(S, S);
68 canvas->translate(-SkScalarHalf(orig->width()) * (S - D) / S,
69 -SkScalarHalf(orig->height()) * (S - D) / S);
halcanary96fcdcc2015-08-27 07:41:13 -070070 canvas->drawImage(orig, 0, 0, nullptr);
halcanary9d524f22016-03-29 09:03:52 -070071
reed09519db2015-01-17 19:36:08 -080072 if (S > 3) {
73 SkPaint paint;
74 paint.setColor(SK_ColorWHITE);
75 for (int i = 1; i < orig->height(); ++i) {
76 SkScalar y = SkIntToScalar(i);
77 canvas->drawLine(0, y, SkIntToScalar(orig->width()), y, paint);
78 }
79 for (int i = 1; i < orig->width(); ++i) {
80 SkScalar x = SkIntToScalar(i);
81 canvas->drawLine(x, 0, x, SkIntToScalar(orig->height()), paint);
82 }
83 }
reed9ce9d672016-03-17 10:51:11 -070084 return surface->makeImageSnapshot();
reed09519db2015-01-17 19:36:08 -080085}
86
reedafdbedb2015-01-14 13:16:26 -080087struct AnimValue {
88 SkScalar fValue;
89 SkScalar fMin;
90 SkScalar fMax;
91 SkScalar fMod;
92
93 operator SkScalar() const { return fValue; }
94
95 void set(SkScalar value, SkScalar min, SkScalar max) {
96 fValue = value;
97 fMin = min;
98 fMax = max;
99 fMod = 0;
100 }
101
102 void setMod(SkScalar value, SkScalar mod) {
103 fValue = value;
104 fMin = 0;
105 fMax = 0;
106 fMod = mod;
107 }
108
109 SkScalar inc(SkScalar delta) {
110 fValue += delta;
111 return this->fixUp();
112 }
113
114 SkScalar fixUp() {
115 if (fMod) {
116 fValue = SkScalarMod(fValue, fMod);
117 } else {
118 if (fValue > fMax) {
119 fValue = fMax;
120 } else if (fValue < fMin) {
121 fValue = fMin;
122 }
123 }
124 return fValue;
125 }
126};
127
reed09519db2015-01-17 19:36:08 -0800128static void draw_box_frame(SkCanvas* canvas, int width, int height) {
129 SkPaint p;
130 p.setStyle(SkPaint::kStroke_Style);
131 p.setColor(SK_ColorRED);
132 SkRect r = SkRect::MakeIWH(width, height);
133 r.inset(0.5f, 0.5f);
134 canvas->drawRect(r, p);
135 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
136 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
137}
reedafdbedb2015-01-14 13:16:26 -0800138
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400139class FilterQualityView : public Sample {
reed9ce9d672016-03-17 10:51:11 -0700140 sk_sp<SkImage> fImage;
141 AnimValue fScale, fAngle;
142 SkSize fCell;
143 SkInterpolator fTrans;
144 SkMSec fCurrTime;
145 bool fShowFatBits;
reedafdbedb2015-01-14 13:16:26 -0800146
147public:
Brian Osman176c3b22017-07-12 15:52:56 -0400148 FilterQualityView() : fTrans(2, 2), fShowFatBits(true) {
reed09519db2015-01-17 19:36:08 -0800149 fCell.set(256, 256);
150
reedafdbedb2015-01-14 13:16:26 -0800151 fScale.set(1, SK_Scalar1 / 8, 1);
152 fAngle.setMod(0, 360);
153
154 SkScalar values[2];
155 fTrans.setMirror(true);
156 fTrans.setReset(true);
157
reed339cdbf2015-02-05 22:02:37 -0800158 fCurrTime = 0;
159
reedafdbedb2015-01-14 13:16:26 -0800160 fTrans.setRepeatCount(999);
161 values[0] = values[1] = 0;
reed339cdbf2015-02-05 22:02:37 -0800162 fTrans.setKeyFrame(0, fCurrTime, values);
reedafdbedb2015-01-14 13:16:26 -0800163 values[0] = values[1] = 1;
reed339cdbf2015-02-05 22:02:37 -0800164 fTrans.setKeyFrame(1, fCurrTime + 2000, values);
reedafdbedb2015-01-14 13:16:26 -0800165 }
166
167protected:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400168 bool onQuery(Sample::Event* evt) override {
169 if (Sample::TitleQ(*evt)) {
170 Sample::TitleR(evt, "FilterQuality");
reedafdbedb2015-01-14 13:16:26 -0800171 return true;
172 }
173 SkUnichar uni;
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400174 if (Sample::CharQ(*evt, &uni)) {
reedafdbedb2015-01-14 13:16:26 -0800175 switch (uni) {
Brian Osmanede860e2017-11-22 16:36:07 -0500176 case '1': fAngle.inc(-ANGLE_DELTA); return true;
177 case '2': fAngle.inc( ANGLE_DELTA); return true;
178 case '3': fScale.inc(-SCALE_DELTA); return true;
179 case '4': fScale.inc( SCALE_DELTA); return true;
180 case '5': fShowFatBits = !fShowFatBits; return true;
reedafdbedb2015-01-14 13:16:26 -0800181 default: break;
182 }
183 }
184 return this->INHERITED::onQuery(evt);
185 }
186
reed93a12152015-03-16 10:08:34 -0700187 void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
reed09519db2015-01-17 19:36:08 -0800188 SkScalar dx, SkScalar dy) {
reedafdbedb2015-01-14 13:16:26 -0800189 SkPaint paint;
190 paint.setAntiAlias(true);
reed93a12152015-03-16 10:08:34 -0700191 paint.setFilterQuality(filter);
reedafdbedb2015-01-14 13:16:26 -0800192
reed09519db2015-01-17 19:36:08 -0800193 SkAutoCanvasRestore acr(canvas, true);
194
195 canvas->translate(dx, dy);
196
197 canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
reedafdbedb2015-01-14 13:16:26 -0800198 canvas->scale(fScale, fScale);
199 canvas->rotate(fAngle);
reed9ce9d672016-03-17 10:51:11 -0700200 canvas->drawImage(fImage.get(), -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
reedafdbedb2015-01-14 13:16:26 -0800201 &paint);
reed09519db2015-01-17 19:36:08 -0800202
203 if (false) {
204 acr.restore();
205 draw_box_frame(canvas, size.width(), size.height());
206 }
207 }
208
reed93a12152015-03-16 10:08:34 -0700209 void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
reed09519db2015-01-17 19:36:08 -0800210 SkCanvas* origCanvas = canvas;
211 SkAutoCanvasRestore acr(canvas, true);
212
213 SkISize size = SkISize::Make(fImage->width(), fImage->height());
214
reede8f30622016-03-23 18:59:25 -0700215 sk_sp<SkSurface> surface;
reed09519db2015-01-17 19:36:08 -0800216 if (fShowFatBits) {
217 // scale up so we don't clip rotations
218 SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
219 kOpaque_SkAlphaType);
Cary Clarka24712e2018-09-05 18:41:40 +0000220 surface = make_surface(canvas, info);
reed09519db2015-01-17 19:36:08 -0800221 canvas = surface->getCanvas();
222 canvas->drawColor(SK_ColorWHITE);
223 size.set(info.width(), info.height());
224 } else {
225 canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
226 SkScalarHalf(fCell.height() - fImage->height()));
227 }
228 this->drawTheImage(canvas, size, filter, dx, dy);
229
230 if (surface) {
reed9ce9d672016-03-17 10:51:11 -0700231 sk_sp<SkImage> orig(surface->makeImageSnapshot());
reede8f30622016-03-23 18:59:25 -0700232 sk_sp<SkImage> zoomed(zoom_up(surface.get(), orig.get()));
reed9ce9d672016-03-17 10:51:11 -0700233 origCanvas->drawImage(zoomed.get(),
reed09519db2015-01-17 19:36:08 -0800234 SkScalarHalf(fCell.width() - zoomed->width()),
235 SkScalarHalf(fCell.height() - zoomed->height()));
236 }
237 }
238
239 void drawBorders(SkCanvas* canvas) {
240 SkPaint p;
241 p.setStyle(SkPaint::kStroke_Style);
242 p.setColor(SK_ColorBLUE);
243
244 SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
245 r.inset(SK_ScalarHalf, SK_ScalarHalf);
246 canvas->drawRect(r, p);
247 canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
248 canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
reedafdbedb2015-01-14 13:16:26 -0800249 }
250
Brian Osman176c3b22017-07-12 15:52:56 -0400251 void onOnceBeforeDraw() override {
252 fImage = make_image();
253 }
254
mtklein36352bf2015-03-25 18:17:31 -0700255 void onDrawContent(SkCanvas* canvas) override {
reed09519db2015-01-17 19:36:08 -0800256 fCell.set(this->height() / 2, this->height() / 2);
257
reedafdbedb2015-01-14 13:16:26 -0800258 SkScalar trans[2];
reed339cdbf2015-02-05 22:02:37 -0800259 fTrans.timeToValues(fCurrTime, trans);
reedafdbedb2015-01-14 13:16:26 -0800260
reed09519db2015-01-17 19:36:08 -0800261 for (int y = 0; y < 2; ++y) {
262 for (int x = 0; x < 2; ++x) {
263 int index = y * 2 + x;
264 SkAutoCanvasRestore acr(canvas, true);
265 canvas->translate(fCell.width() * x, fCell.height() * y);
266 SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
267 r.inset(4, 4);
268 canvas->clipRect(r);
reed93a12152015-03-16 10:08:34 -0700269 this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
reed09519db2015-01-17 19:36:08 -0800270 }
reedafdbedb2015-01-14 13:16:26 -0800271 }
272
reed09519db2015-01-17 19:36:08 -0800273 this->drawBorders(canvas);
274
275 const SkScalar textX = fCell.width() * 2 + 30;
276
reedafdbedb2015-01-14 13:16:26 -0800277 SkPaint paint;
278 paint.setAntiAlias(true);
reed09519db2015-01-17 19:36:08 -0800279 paint.setTextSize(36);
reedafdbedb2015-01-14 13:16:26 -0800280 SkString str;
281 str.appendScalar(fScale);
Cary Clark2a475ea2017-04-28 15:35:12 -0400282 canvas->drawString(str, textX, 100, paint);
reedafdbedb2015-01-14 13:16:26 -0800283 str.reset(); str.appendScalar(fAngle);
Cary Clark2a475ea2017-04-28 15:35:12 -0400284 canvas->drawString(str, textX, 150, paint);
reedafdbedb2015-01-14 13:16:26 -0800285
286 str.reset(); str.appendScalar(trans[0]);
Cary Clark2a475ea2017-04-28 15:35:12 -0400287 canvas->drawString(str, textX, 200, paint);
reedafdbedb2015-01-14 13:16:26 -0800288 str.reset(); str.appendScalar(trans[1]);
Cary Clark2a475ea2017-04-28 15:35:12 -0400289 canvas->drawString(str, textX, 250, paint);
reed339cdbf2015-02-05 22:02:37 -0800290 }
reed09519db2015-01-17 19:36:08 -0800291
mtklein36352bf2015-03-25 18:17:31 -0700292 bool onAnimate(const SkAnimTimer& timer) override {
reed339cdbf2015-02-05 22:02:37 -0800293 fCurrTime = timer.msec();
294 return true;
reed09519db2015-01-17 19:36:08 -0800295 }
reedafdbedb2015-01-14 13:16:26 -0800296
reedafdbedb2015-01-14 13:16:26 -0800297private:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400298 typedef Sample INHERITED;
reedafdbedb2015-01-14 13:16:26 -0800299};
300
301//////////////////////////////////////////////////////////////////////////////
302
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400303DEF_SAMPLE( return new FilterQualityView(); )