blob: abe1a9097d1cc028ffe4805e323759972b4a8669 [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
reede8f30622016-03-23 18:59:25 -070022static sk_sp<SkSurface> make_surface(SkCanvas* canvas, const SkImageInfo& info) {
23 auto surface = canvas->makeSurface(info);
reed09519db2015-01-17 19:36:08 -080024 if (!surface) {
reede8f30622016-03-23 18:59:25 -070025 surface = SkSurface::MakeRaster(info);
reed09519db2015-01-17 19:36:08 -080026 }
27 return surface;
28}
29
reed5671c5b2016-03-09 14:47:34 -080030static sk_sp<SkShader> make_shader(const SkRect& bounds) {
reed9ce9d672016-03-17 10:51:11 -070031 sk_sp<SkImage> image(GetResourceAsImage("mandrill_128.png"));
Mike Reed0acd7952017-04-28 11:12:19 -040032 return image ? image->makeShader() : nullptr;
reed73f6cfc2015-11-09 08:36:05 -080033}
34
reedafdbedb2015-01-14 13:16:26 -080035#define N 128
reed09519db2015-01-17 19:36:08 -080036#define ANGLE_DELTA 3
37#define SCALE_DELTA (SK_Scalar1 / 32)
reedafdbedb2015-01-14 13:16:26 -080038
reed9ce9d672016-03-17 10:51:11 -070039static sk_sp<SkImage> make_image() {
reed09519db2015-01-17 19:36:08 -080040 SkImageInfo info = SkImageInfo::MakeN32(N, N, kOpaque_SkAlphaType);
reede8f30622016-03-23 18:59:25 -070041 auto surface(SkSurface::MakeRaster(info));
reedafdbedb2015-01-14 13:16:26 -080042 SkCanvas* canvas = surface->getCanvas();
reed09519db2015-01-17 19:36:08 -080043 canvas->drawColor(SK_ColorWHITE);
reedafdbedb2015-01-14 13:16:26 -080044
45 SkPath path;
46 path.setFillType(SkPath::kEvenOdd_FillType);
47
48 path.addRect(SkRect::MakeWH(N/2, N));
49 path.addRect(SkRect::MakeWH(N, N/2));
50 path.moveTo(0, 0); path.lineTo(N, 0); path.lineTo(0, N); path.close();
51
reed73f6cfc2015-11-09 08:36:05 -080052 SkPaint paint;
reed5671c5b2016-03-09 14:47:34 -080053 paint.setShader(make_shader(SkRect::MakeWH(N, N)));
halcanary9d524f22016-03-29 09:03:52 -070054
reed73f6cfc2015-11-09 08:36:05 -080055 canvas->drawPath(path, paint);
reed9ce9d672016-03-17 10:51:11 -070056 return surface->makeImageSnapshot();
reedafdbedb2015-01-14 13:16:26 -080057}
58
reed9ce9d672016-03-17 10:51:11 -070059static sk_sp<SkImage> zoom_up(SkSurface* origSurf, SkImage* orig) {
reed73f6cfc2015-11-09 08:36:05 -080060 const SkScalar S = 16; // amount to scale up
reed09519db2015-01-17 19:36:08 -080061 const int D = 2; // dimension scaling for the offscreen
62 // since we only view the center, don't need to produce the entire thing
halcanary9d524f22016-03-29 09:03:52 -070063
reed09519db2015-01-17 19:36:08 -080064 SkImageInfo info = SkImageInfo::MakeN32(orig->width() * D, orig->height() * D,
65 kOpaque_SkAlphaType);
reede8f30622016-03-23 18:59:25 -070066 auto surface(origSurf->makeSurface(info));
reed09519db2015-01-17 19:36:08 -080067 SkCanvas* canvas = surface->getCanvas();
68 canvas->drawColor(SK_ColorWHITE);
69 canvas->scale(S, S);
70 canvas->translate(-SkScalarHalf(orig->width()) * (S - D) / S,
71 -SkScalarHalf(orig->height()) * (S - D) / S);
halcanary96fcdcc2015-08-27 07:41:13 -070072 canvas->drawImage(orig, 0, 0, nullptr);
halcanary9d524f22016-03-29 09:03:52 -070073
reed09519db2015-01-17 19:36:08 -080074 if (S > 3) {
75 SkPaint paint;
76 paint.setColor(SK_ColorWHITE);
77 for (int i = 1; i < orig->height(); ++i) {
78 SkScalar y = SkIntToScalar(i);
79 canvas->drawLine(0, y, SkIntToScalar(orig->width()), y, paint);
80 }
81 for (int i = 1; i < orig->width(); ++i) {
82 SkScalar x = SkIntToScalar(i);
83 canvas->drawLine(x, 0, x, SkIntToScalar(orig->height()), paint);
84 }
85 }
reed9ce9d672016-03-17 10:51:11 -070086 return surface->makeImageSnapshot();
reed09519db2015-01-17 19:36:08 -080087}
88
reedafdbedb2015-01-14 13:16:26 -080089struct AnimValue {
90 SkScalar fValue;
91 SkScalar fMin;
92 SkScalar fMax;
93 SkScalar fMod;
94
95 operator SkScalar() const { return fValue; }
96
97 void set(SkScalar value, SkScalar min, SkScalar max) {
98 fValue = value;
99 fMin = min;
100 fMax = max;
101 fMod = 0;
102 }
103
104 void setMod(SkScalar value, SkScalar mod) {
105 fValue = value;
106 fMin = 0;
107 fMax = 0;
108 fMod = mod;
109 }
110
111 SkScalar inc(SkScalar delta) {
112 fValue += delta;
113 return this->fixUp();
114 }
115
116 SkScalar fixUp() {
117 if (fMod) {
118 fValue = SkScalarMod(fValue, fMod);
119 } else {
120 if (fValue > fMax) {
121 fValue = fMax;
122 } else if (fValue < fMin) {
123 fValue = fMin;
124 }
125 }
126 return fValue;
127 }
128};
129
reed09519db2015-01-17 19:36:08 -0800130static void draw_box_frame(SkCanvas* canvas, int width, int height) {
131 SkPaint p;
132 p.setStyle(SkPaint::kStroke_Style);
133 p.setColor(SK_ColorRED);
134 SkRect r = SkRect::MakeIWH(width, height);
135 r.inset(0.5f, 0.5f);
136 canvas->drawRect(r, p);
137 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
138 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
139}
reedafdbedb2015-01-14 13:16:26 -0800140
141class FilterQualityView : public SampleView {
reed9ce9d672016-03-17 10:51:11 -0700142 sk_sp<SkImage> fImage;
143 AnimValue fScale, fAngle;
144 SkSize fCell;
145 SkInterpolator fTrans;
146 SkMSec fCurrTime;
147 bool fShowFatBits;
reedafdbedb2015-01-14 13:16:26 -0800148
149public:
Brian Osman176c3b22017-07-12 15:52:56 -0400150 FilterQualityView() : fTrans(2, 2), fShowFatBits(true) {
reed09519db2015-01-17 19:36:08 -0800151 fCell.set(256, 256);
152
reedafdbedb2015-01-14 13:16:26 -0800153 fScale.set(1, SK_Scalar1 / 8, 1);
154 fAngle.setMod(0, 360);
155
156 SkScalar values[2];
157 fTrans.setMirror(true);
158 fTrans.setReset(true);
159
reed339cdbf2015-02-05 22:02:37 -0800160 fCurrTime = 0;
161
reedafdbedb2015-01-14 13:16:26 -0800162 fTrans.setRepeatCount(999);
163 values[0] = values[1] = 0;
reed339cdbf2015-02-05 22:02:37 -0800164 fTrans.setKeyFrame(0, fCurrTime, values);
reedafdbedb2015-01-14 13:16:26 -0800165 values[0] = values[1] = 1;
reed339cdbf2015-02-05 22:02:37 -0800166 fTrans.setKeyFrame(1, fCurrTime + 2000, values);
reedafdbedb2015-01-14 13:16:26 -0800167 }
168
169protected:
mtklein36352bf2015-03-25 18:17:31 -0700170 bool onQuery(SkEvent* evt) override {
reedafdbedb2015-01-14 13:16:26 -0800171 if (SampleCode::TitleQ(*evt)) {
172 SampleCode::TitleR(evt, "FilterQuality");
173 return true;
174 }
175 SkUnichar uni;
176 if (SampleCode::CharQ(*evt, &uni)) {
177 switch (uni) {
halcanary96fcdcc2015-08-27 07:41:13 -0700178 case '1': fAngle.inc(-ANGLE_DELTA); this->inval(nullptr); return true;
179 case '2': fAngle.inc( ANGLE_DELTA); this->inval(nullptr); return true;
180 case '3': fScale.inc(-SCALE_DELTA); this->inval(nullptr); return true;
181 case '4': fScale.inc( SCALE_DELTA); this->inval(nullptr); return true;
182 case '5': fShowFatBits = !fShowFatBits; this->inval(nullptr); return true;
reedafdbedb2015-01-14 13:16:26 -0800183 default: break;
184 }
185 }
186 return this->INHERITED::onQuery(evt);
187 }
188
reed93a12152015-03-16 10:08:34 -0700189 void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
reed09519db2015-01-17 19:36:08 -0800190 SkScalar dx, SkScalar dy) {
reedafdbedb2015-01-14 13:16:26 -0800191 SkPaint paint;
192 paint.setAntiAlias(true);
reed93a12152015-03-16 10:08:34 -0700193 paint.setFilterQuality(filter);
reedafdbedb2015-01-14 13:16:26 -0800194
reed09519db2015-01-17 19:36:08 -0800195 SkAutoCanvasRestore acr(canvas, true);
196
197 canvas->translate(dx, dy);
198
199 canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
reedafdbedb2015-01-14 13:16:26 -0800200 canvas->scale(fScale, fScale);
201 canvas->rotate(fAngle);
reed9ce9d672016-03-17 10:51:11 -0700202 canvas->drawImage(fImage.get(), -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
reedafdbedb2015-01-14 13:16:26 -0800203 &paint);
reed09519db2015-01-17 19:36:08 -0800204
205 if (false) {
206 acr.restore();
207 draw_box_frame(canvas, size.width(), size.height());
208 }
209 }
210
reed93a12152015-03-16 10:08:34 -0700211 void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
reed09519db2015-01-17 19:36:08 -0800212 SkCanvas* origCanvas = canvas;
213 SkAutoCanvasRestore acr(canvas, true);
214
215 SkISize size = SkISize::Make(fImage->width(), fImage->height());
216
reede8f30622016-03-23 18:59:25 -0700217 sk_sp<SkSurface> surface;
reed09519db2015-01-17 19:36:08 -0800218 if (fShowFatBits) {
219 // scale up so we don't clip rotations
220 SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
221 kOpaque_SkAlphaType);
reede8f30622016-03-23 18:59:25 -0700222 surface = make_surface(canvas, info);
reed09519db2015-01-17 19:36:08 -0800223 canvas = surface->getCanvas();
224 canvas->drawColor(SK_ColorWHITE);
225 size.set(info.width(), info.height());
226 } else {
227 canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
228 SkScalarHalf(fCell.height() - fImage->height()));
229 }
230 this->drawTheImage(canvas, size, filter, dx, dy);
231
232 if (surface) {
reed9ce9d672016-03-17 10:51:11 -0700233 sk_sp<SkImage> orig(surface->makeImageSnapshot());
reede8f30622016-03-23 18:59:25 -0700234 sk_sp<SkImage> zoomed(zoom_up(surface.get(), orig.get()));
reed9ce9d672016-03-17 10:51:11 -0700235 origCanvas->drawImage(zoomed.get(),
reed09519db2015-01-17 19:36:08 -0800236 SkScalarHalf(fCell.width() - zoomed->width()),
237 SkScalarHalf(fCell.height() - zoomed->height()));
238 }
239 }
240
241 void drawBorders(SkCanvas* canvas) {
242 SkPaint p;
243 p.setStyle(SkPaint::kStroke_Style);
244 p.setColor(SK_ColorBLUE);
245
246 SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
247 r.inset(SK_ScalarHalf, SK_ScalarHalf);
248 canvas->drawRect(r, p);
249 canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
250 canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
reedafdbedb2015-01-14 13:16:26 -0800251 }
252
Brian Osman176c3b22017-07-12 15:52:56 -0400253 void onOnceBeforeDraw() override {
254 fImage = make_image();
255 }
256
mtklein36352bf2015-03-25 18:17:31 -0700257 void onDrawContent(SkCanvas* canvas) override {
reed09519db2015-01-17 19:36:08 -0800258 fCell.set(this->height() / 2, this->height() / 2);
259
reedafdbedb2015-01-14 13:16:26 -0800260 SkScalar trans[2];
reed339cdbf2015-02-05 22:02:37 -0800261 fTrans.timeToValues(fCurrTime, trans);
reedafdbedb2015-01-14 13:16:26 -0800262
reed09519db2015-01-17 19:36:08 -0800263 for (int y = 0; y < 2; ++y) {
264 for (int x = 0; x < 2; ++x) {
265 int index = y * 2 + x;
266 SkAutoCanvasRestore acr(canvas, true);
267 canvas->translate(fCell.width() * x, fCell.height() * y);
268 SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
269 r.inset(4, 4);
270 canvas->clipRect(r);
reed93a12152015-03-16 10:08:34 -0700271 this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
reed09519db2015-01-17 19:36:08 -0800272 }
reedafdbedb2015-01-14 13:16:26 -0800273 }
274
reed09519db2015-01-17 19:36:08 -0800275 this->drawBorders(canvas);
276
277 const SkScalar textX = fCell.width() * 2 + 30;
278
reedafdbedb2015-01-14 13:16:26 -0800279 SkPaint paint;
280 paint.setAntiAlias(true);
reed09519db2015-01-17 19:36:08 -0800281 paint.setTextSize(36);
reedafdbedb2015-01-14 13:16:26 -0800282 SkString str;
283 str.appendScalar(fScale);
Cary Clark2a475ea2017-04-28 15:35:12 -0400284 canvas->drawString(str, textX, 100, paint);
reedafdbedb2015-01-14 13:16:26 -0800285 str.reset(); str.appendScalar(fAngle);
Cary Clark2a475ea2017-04-28 15:35:12 -0400286 canvas->drawString(str, textX, 150, paint);
reedafdbedb2015-01-14 13:16:26 -0800287
288 str.reset(); str.appendScalar(trans[0]);
Cary Clark2a475ea2017-04-28 15:35:12 -0400289 canvas->drawString(str, textX, 200, paint);
reedafdbedb2015-01-14 13:16:26 -0800290 str.reset(); str.appendScalar(trans[1]);
Cary Clark2a475ea2017-04-28 15:35:12 -0400291 canvas->drawString(str, textX, 250, paint);
reed339cdbf2015-02-05 22:02:37 -0800292 }
reed09519db2015-01-17 19:36:08 -0800293
mtklein36352bf2015-03-25 18:17:31 -0700294 bool onAnimate(const SkAnimTimer& timer) override {
reed339cdbf2015-02-05 22:02:37 -0800295 fCurrTime = timer.msec();
296 return true;
reed09519db2015-01-17 19:36:08 -0800297 }
reedafdbedb2015-01-14 13:16:26 -0800298
299 virtual bool handleKey(SkKey key) {
halcanary96fcdcc2015-08-27 07:41:13 -0700300 this->inval(nullptr);
reedafdbedb2015-01-14 13:16:26 -0800301 return true;
302 }
303
304private:
305 typedef SampleView INHERITED;
306};
307
308//////////////////////////////////////////////////////////////////////////////
309
310static SkView* MyFactory() { return new FilterQualityView; }
311static SkViewRegister reg(MyFactory);