blob: 12a04a6d6000307468c324079b4206a043357f53 [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"
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
reed09519db2015-01-17 19:36:08 -080020static SkSurface* make_surface(SkCanvas* canvas, const SkImageInfo& info) {
21 SkSurface* surface = canvas->newSurface(info);
22 if (!surface) {
23 surface = SkSurface::NewRaster(info);
24 }
25 return surface;
26}
27
reedafdbedb2015-01-14 13:16:26 -080028#define N 128
reed09519db2015-01-17 19:36:08 -080029#define ANGLE_DELTA 3
30#define SCALE_DELTA (SK_Scalar1 / 32)
reedafdbedb2015-01-14 13:16:26 -080031
32static SkImage* make_image() {
reed09519db2015-01-17 19:36:08 -080033 SkImageInfo info = SkImageInfo::MakeN32(N, N, kOpaque_SkAlphaType);
reedafdbedb2015-01-14 13:16:26 -080034 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
35 SkCanvas* canvas = surface->getCanvas();
reed09519db2015-01-17 19:36:08 -080036 canvas->drawColor(SK_ColorWHITE);
reedafdbedb2015-01-14 13:16:26 -080037
38 SkPath path;
39 path.setFillType(SkPath::kEvenOdd_FillType);
40
41 path.addRect(SkRect::MakeWH(N/2, N));
42 path.addRect(SkRect::MakeWH(N, N/2));
43 path.moveTo(0, 0); path.lineTo(N, 0); path.lineTo(0, N); path.close();
44
45 canvas->drawPath(path, SkPaint());
46 return surface->newImageSnapshot();
47}
48
reed09519db2015-01-17 19:36:08 -080049static SkImage* zoom_up(SkImage* orig) {
50 const SkScalar S = 8; // amount to scale up
51 const int D = 2; // dimension scaling for the offscreen
52 // since we only view the center, don't need to produce the entire thing
53
54 SkImageInfo info = SkImageInfo::MakeN32(orig->width() * D, orig->height() * D,
55 kOpaque_SkAlphaType);
56 SkAutoTUnref<SkSurface> surface(orig->newSurface(info));
57 SkCanvas* canvas = surface->getCanvas();
58 canvas->drawColor(SK_ColorWHITE);
59 canvas->scale(S, S);
60 canvas->translate(-SkScalarHalf(orig->width()) * (S - D) / S,
61 -SkScalarHalf(orig->height()) * (S - D) / S);
62 canvas->drawImage(orig, 0, 0, NULL);
63
64 if (S > 3) {
65 SkPaint paint;
66 paint.setColor(SK_ColorWHITE);
67 for (int i = 1; i < orig->height(); ++i) {
68 SkScalar y = SkIntToScalar(i);
69 canvas->drawLine(0, y, SkIntToScalar(orig->width()), y, paint);
70 }
71 for (int i = 1; i < orig->width(); ++i) {
72 SkScalar x = SkIntToScalar(i);
73 canvas->drawLine(x, 0, x, SkIntToScalar(orig->height()), paint);
74 }
75 }
76 return surface->newImageSnapshot();
77}
78
reedafdbedb2015-01-14 13:16:26 -080079struct AnimValue {
80 SkScalar fValue;
81 SkScalar fMin;
82 SkScalar fMax;
83 SkScalar fMod;
84
85 operator SkScalar() const { return fValue; }
86
87 void set(SkScalar value, SkScalar min, SkScalar max) {
88 fValue = value;
89 fMin = min;
90 fMax = max;
91 fMod = 0;
92 }
93
94 void setMod(SkScalar value, SkScalar mod) {
95 fValue = value;
96 fMin = 0;
97 fMax = 0;
98 fMod = mod;
99 }
100
101 SkScalar inc(SkScalar delta) {
102 fValue += delta;
103 return this->fixUp();
104 }
105
106 SkScalar fixUp() {
107 if (fMod) {
108 fValue = SkScalarMod(fValue, fMod);
109 } else {
110 if (fValue > fMax) {
111 fValue = fMax;
112 } else if (fValue < fMin) {
113 fValue = fMin;
114 }
115 }
116 return fValue;
117 }
118};
119
reed09519db2015-01-17 19:36:08 -0800120static void draw_box_frame(SkCanvas* canvas, int width, int height) {
121 SkPaint p;
122 p.setStyle(SkPaint::kStroke_Style);
123 p.setColor(SK_ColorRED);
124 SkRect r = SkRect::MakeIWH(width, height);
125 r.inset(0.5f, 0.5f);
126 canvas->drawRect(r, p);
127 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
128 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
129}
reedafdbedb2015-01-14 13:16:26 -0800130
131class FilterQualityView : public SampleView {
132 SkAutoTUnref<SkImage> fImage;
133 AnimValue fScale, fAngle;
reed09519db2015-01-17 19:36:08 -0800134 SkSize fCell;
reedafdbedb2015-01-14 13:16:26 -0800135 SkInterpolator fTrans;
reed339cdbf2015-02-05 22:02:37 -0800136 SkMSec fCurrTime;
reed09519db2015-01-17 19:36:08 -0800137 bool fShowFatBits;
reedafdbedb2015-01-14 13:16:26 -0800138
139public:
reed09519db2015-01-17 19:36:08 -0800140 FilterQualityView() : fImage(make_image()), fTrans(2, 2), fShowFatBits(true) {
141 fCell.set(256, 256);
142
reedafdbedb2015-01-14 13:16:26 -0800143 fScale.set(1, SK_Scalar1 / 8, 1);
144 fAngle.setMod(0, 360);
145
146 SkScalar values[2];
147 fTrans.setMirror(true);
148 fTrans.setReset(true);
149
reed339cdbf2015-02-05 22:02:37 -0800150 fCurrTime = 0;
151
reedafdbedb2015-01-14 13:16:26 -0800152 fTrans.setRepeatCount(999);
153 values[0] = values[1] = 0;
reed339cdbf2015-02-05 22:02:37 -0800154 fTrans.setKeyFrame(0, fCurrTime, values);
reedafdbedb2015-01-14 13:16:26 -0800155 values[0] = values[1] = 1;
reed339cdbf2015-02-05 22:02:37 -0800156 fTrans.setKeyFrame(1, fCurrTime + 2000, values);
reedafdbedb2015-01-14 13:16:26 -0800157 }
158
159protected:
mtklein36352bf2015-03-25 18:17:31 -0700160 bool onQuery(SkEvent* evt) override {
reedafdbedb2015-01-14 13:16:26 -0800161 if (SampleCode::TitleQ(*evt)) {
162 SampleCode::TitleR(evt, "FilterQuality");
163 return true;
164 }
165 SkUnichar uni;
166 if (SampleCode::CharQ(*evt, &uni)) {
167 switch (uni) {
168 case '1': fAngle.inc(-ANGLE_DELTA); this->inval(NULL); return true;
169 case '2': fAngle.inc( ANGLE_DELTA); this->inval(NULL); return true;
170 case '3': fScale.inc(-SCALE_DELTA); this->inval(NULL); return true;
171 case '4': fScale.inc( SCALE_DELTA); this->inval(NULL); return true;
reed09519db2015-01-17 19:36:08 -0800172 case '5': fShowFatBits = !fShowFatBits; this->inval(NULL); return true;
reedafdbedb2015-01-14 13:16:26 -0800173 default: break;
174 }
175 }
176 return this->INHERITED::onQuery(evt);
177 }
178
reed93a12152015-03-16 10:08:34 -0700179 void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
reed09519db2015-01-17 19:36:08 -0800180 SkScalar dx, SkScalar dy) {
reedafdbedb2015-01-14 13:16:26 -0800181 SkPaint paint;
182 paint.setAntiAlias(true);
reed93a12152015-03-16 10:08:34 -0700183 paint.setFilterQuality(filter);
reedafdbedb2015-01-14 13:16:26 -0800184
reed09519db2015-01-17 19:36:08 -0800185 SkAutoCanvasRestore acr(canvas, true);
186
187 canvas->translate(dx, dy);
188
189 canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
reedafdbedb2015-01-14 13:16:26 -0800190 canvas->scale(fScale, fScale);
191 canvas->rotate(fAngle);
192 canvas->drawImage(fImage, -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
193 &paint);
reed09519db2015-01-17 19:36:08 -0800194
195 if (false) {
196 acr.restore();
197 draw_box_frame(canvas, size.width(), size.height());
198 }
199 }
200
reed93a12152015-03-16 10:08:34 -0700201 void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
reed09519db2015-01-17 19:36:08 -0800202 SkCanvas* origCanvas = canvas;
203 SkAutoCanvasRestore acr(canvas, true);
204
205 SkISize size = SkISize::Make(fImage->width(), fImage->height());
206
207 SkAutoTUnref<SkSurface> surface;
208 if (fShowFatBits) {
209 // scale up so we don't clip rotations
210 SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
211 kOpaque_SkAlphaType);
212 surface.reset(make_surface(canvas, info));
213 canvas = surface->getCanvas();
214 canvas->drawColor(SK_ColorWHITE);
215 size.set(info.width(), info.height());
216 } else {
217 canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
218 SkScalarHalf(fCell.height() - fImage->height()));
219 }
220 this->drawTheImage(canvas, size, filter, dx, dy);
221
222 if (surface) {
223 SkAutoTUnref<SkImage> orig(surface->newImageSnapshot());
224 SkAutoTUnref<SkImage> zoomed(zoom_up(orig));
225 origCanvas->drawImage(zoomed,
226 SkScalarHalf(fCell.width() - zoomed->width()),
227 SkScalarHalf(fCell.height() - zoomed->height()));
228 }
229 }
230
231 void drawBorders(SkCanvas* canvas) {
232 SkPaint p;
233 p.setStyle(SkPaint::kStroke_Style);
234 p.setColor(SK_ColorBLUE);
235
236 SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
237 r.inset(SK_ScalarHalf, SK_ScalarHalf);
238 canvas->drawRect(r, p);
239 canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
240 canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
reedafdbedb2015-01-14 13:16:26 -0800241 }
242
mtklein36352bf2015-03-25 18:17:31 -0700243 void onDrawContent(SkCanvas* canvas) override {
reed09519db2015-01-17 19:36:08 -0800244 fCell.set(this->height() / 2, this->height() / 2);
245
reedafdbedb2015-01-14 13:16:26 -0800246 SkScalar trans[2];
reed339cdbf2015-02-05 22:02:37 -0800247 fTrans.timeToValues(fCurrTime, trans);
reedafdbedb2015-01-14 13:16:26 -0800248
reed09519db2015-01-17 19:36:08 -0800249 for (int y = 0; y < 2; ++y) {
250 for (int x = 0; x < 2; ++x) {
251 int index = y * 2 + x;
252 SkAutoCanvasRestore acr(canvas, true);
253 canvas->translate(fCell.width() * x, fCell.height() * y);
254 SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
255 r.inset(4, 4);
256 canvas->clipRect(r);
reed93a12152015-03-16 10:08:34 -0700257 this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
reed09519db2015-01-17 19:36:08 -0800258 }
reedafdbedb2015-01-14 13:16:26 -0800259 }
260
reed09519db2015-01-17 19:36:08 -0800261 this->drawBorders(canvas);
262
263 const SkScalar textX = fCell.width() * 2 + 30;
264
reedafdbedb2015-01-14 13:16:26 -0800265 SkPaint paint;
266 paint.setAntiAlias(true);
reed09519db2015-01-17 19:36:08 -0800267 paint.setTextSize(36);
reedafdbedb2015-01-14 13:16:26 -0800268 SkString str;
269 str.appendScalar(fScale);
reed09519db2015-01-17 19:36:08 -0800270 canvas->drawText(str.c_str(), str.size(), textX, 100, paint);
reedafdbedb2015-01-14 13:16:26 -0800271 str.reset(); str.appendScalar(fAngle);
reed09519db2015-01-17 19:36:08 -0800272 canvas->drawText(str.c_str(), str.size(), textX, 150, paint);
reedafdbedb2015-01-14 13:16:26 -0800273
274 str.reset(); str.appendScalar(trans[0]);
reed09519db2015-01-17 19:36:08 -0800275 canvas->drawText(str.c_str(), str.size(), textX, 200, paint);
reedafdbedb2015-01-14 13:16:26 -0800276 str.reset(); str.appendScalar(trans[1]);
reed09519db2015-01-17 19:36:08 -0800277 canvas->drawText(str.c_str(), str.size(), textX, 250, paint);
reed339cdbf2015-02-05 22:02:37 -0800278 }
reed09519db2015-01-17 19:36:08 -0800279
mtklein36352bf2015-03-25 18:17:31 -0700280 bool onAnimate(const SkAnimTimer& timer) override {
reed339cdbf2015-02-05 22:02:37 -0800281 fCurrTime = timer.msec();
282 return true;
reed09519db2015-01-17 19:36:08 -0800283 }
reedafdbedb2015-01-14 13:16:26 -0800284
285 virtual bool handleKey(SkKey key) {
286 this->inval(NULL);
287 return true;
288 }
289
290private:
291 typedef SampleView INHERITED;
292};
293
294//////////////////////////////////////////////////////////////////////////////
295
296static SkView* MyFactory() { return new FilterQualityView; }
297static SkViewRegister reg(MyFactory);