1 /*
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"
12 #include "SkAnimTimer.h"
13 #include "SkCanvas.h"
14 #include "SkInterpolator.h"
15 #include "SkGradientShader.h"
16 #include "SkData.h"
17 #include "SkPath.h"
18 #include "SkSurface.h"
19 #include "SkRandom.h"
20 #include "SkTime.h"
21
make_surface(SkCanvas * canvas,const SkImageInfo & info)22 static sk_sp<SkSurface> make_surface(SkCanvas* canvas, const SkImageInfo& info) {
23 auto surface = canvas->makeSurface(info);
24 if (!surface) {
25 surface = SkSurface::MakeRaster(info);
26 }
27 return surface;
28 }
29
make_shader(const SkRect & bounds)30 static sk_sp<SkShader> make_shader(const SkRect& bounds) {
31 sk_sp<SkImage> image(GetResourceAsImage("mandrill_128.png"));
32 if (!image) {
33 return nullptr;
34 }
35 return image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
36 }
37
38 #define N 128
39 #define ANGLE_DELTA 3
40 #define SCALE_DELTA (SK_Scalar1 / 32)
41
make_image()42 static sk_sp<SkImage> make_image() {
43 SkImageInfo info = SkImageInfo::MakeN32(N, N, kOpaque_SkAlphaType);
44 auto surface(SkSurface::MakeRaster(info));
45 SkCanvas* canvas = surface->getCanvas();
46 canvas->drawColor(SK_ColorWHITE);
47
48 SkPath path;
49 path.setFillType(SkPath::kEvenOdd_FillType);
50
51 path.addRect(SkRect::MakeWH(N/2, N));
52 path.addRect(SkRect::MakeWH(N, N/2));
53 path.moveTo(0, 0); path.lineTo(N, 0); path.lineTo(0, N); path.close();
54
55 SkPaint paint;
56 paint.setShader(make_shader(SkRect::MakeWH(N, N)));
57
58 canvas->drawPath(path, paint);
59 return surface->makeImageSnapshot();
60 }
61
zoom_up(SkSurface * origSurf,SkImage * orig)62 static sk_sp<SkImage> zoom_up(SkSurface* origSurf, SkImage* orig) {
63 const SkScalar S = 16; // amount to scale up
64 const int D = 2; // dimension scaling for the offscreen
65 // since we only view the center, don't need to produce the entire thing
66
67 SkImageInfo info = SkImageInfo::MakeN32(orig->width() * D, orig->height() * D,
68 kOpaque_SkAlphaType);
69 auto surface(origSurf->makeSurface(info));
70 SkCanvas* canvas = surface->getCanvas();
71 canvas->drawColor(SK_ColorWHITE);
72 canvas->scale(S, S);
73 canvas->translate(-SkScalarHalf(orig->width()) * (S - D) / S,
74 -SkScalarHalf(orig->height()) * (S - D) / S);
75 canvas->drawImage(orig, 0, 0, nullptr);
76
77 if (S > 3) {
78 SkPaint paint;
79 paint.setColor(SK_ColorWHITE);
80 for (int i = 1; i < orig->height(); ++i) {
81 SkScalar y = SkIntToScalar(i);
82 canvas->drawLine(0, y, SkIntToScalar(orig->width()), y, paint);
83 }
84 for (int i = 1; i < orig->width(); ++i) {
85 SkScalar x = SkIntToScalar(i);
86 canvas->drawLine(x, 0, x, SkIntToScalar(orig->height()), paint);
87 }
88 }
89 return surface->makeImageSnapshot();
90 }
91
92 struct AnimValue {
93 SkScalar fValue;
94 SkScalar fMin;
95 SkScalar fMax;
96 SkScalar fMod;
97
operator SkScalarAnimValue98 operator SkScalar() const { return fValue; }
99
setAnimValue100 void set(SkScalar value, SkScalar min, SkScalar max) {
101 fValue = value;
102 fMin = min;
103 fMax = max;
104 fMod = 0;
105 }
106
setModAnimValue107 void setMod(SkScalar value, SkScalar mod) {
108 fValue = value;
109 fMin = 0;
110 fMax = 0;
111 fMod = mod;
112 }
113
incAnimValue114 SkScalar inc(SkScalar delta) {
115 fValue += delta;
116 return this->fixUp();
117 }
118
fixUpAnimValue119 SkScalar fixUp() {
120 if (fMod) {
121 fValue = SkScalarMod(fValue, fMod);
122 } else {
123 if (fValue > fMax) {
124 fValue = fMax;
125 } else if (fValue < fMin) {
126 fValue = fMin;
127 }
128 }
129 return fValue;
130 }
131 };
132
draw_box_frame(SkCanvas * canvas,int width,int height)133 static void draw_box_frame(SkCanvas* canvas, int width, int height) {
134 SkPaint p;
135 p.setStyle(SkPaint::kStroke_Style);
136 p.setColor(SK_ColorRED);
137 SkRect r = SkRect::MakeIWH(width, height);
138 r.inset(0.5f, 0.5f);
139 canvas->drawRect(r, p);
140 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
141 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
142 }
143
144 class FilterQualityView : public SampleView {
145 sk_sp<SkImage> fImage;
146 AnimValue fScale, fAngle;
147 SkSize fCell;
148 SkInterpolator fTrans;
149 SkMSec fCurrTime;
150 bool fShowFatBits;
151
152 public:
FilterQualityView()153 FilterQualityView() : fImage(make_image()), fTrans(2, 2), fShowFatBits(true) {
154 fCell.set(256, 256);
155
156 fScale.set(1, SK_Scalar1 / 8, 1);
157 fAngle.setMod(0, 360);
158
159 SkScalar values[2];
160 fTrans.setMirror(true);
161 fTrans.setReset(true);
162
163 fCurrTime = 0;
164
165 fTrans.setRepeatCount(999);
166 values[0] = values[1] = 0;
167 fTrans.setKeyFrame(0, fCurrTime, values);
168 values[0] = values[1] = 1;
169 fTrans.setKeyFrame(1, fCurrTime + 2000, values);
170 }
171
172 protected:
onQuery(SkEvent * evt)173 bool onQuery(SkEvent* evt) override {
174 if (SampleCode::TitleQ(*evt)) {
175 SampleCode::TitleR(evt, "FilterQuality");
176 return true;
177 }
178 SkUnichar uni;
179 if (SampleCode::CharQ(*evt, &uni)) {
180 switch (uni) {
181 case '1': fAngle.inc(-ANGLE_DELTA); this->inval(nullptr); return true;
182 case '2': fAngle.inc( ANGLE_DELTA); this->inval(nullptr); return true;
183 case '3': fScale.inc(-SCALE_DELTA); this->inval(nullptr); return true;
184 case '4': fScale.inc( SCALE_DELTA); this->inval(nullptr); return true;
185 case '5': fShowFatBits = !fShowFatBits; this->inval(nullptr); return true;
186 default: break;
187 }
188 }
189 return this->INHERITED::onQuery(evt);
190 }
191
drawTheImage(SkCanvas * canvas,const SkISize & size,SkFilterQuality filter,SkScalar dx,SkScalar dy)192 void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
193 SkScalar dx, SkScalar dy) {
194 SkPaint paint;
195 paint.setAntiAlias(true);
196 paint.setFilterQuality(filter);
197
198 SkAutoCanvasRestore acr(canvas, true);
199
200 canvas->translate(dx, dy);
201
202 canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
203 canvas->scale(fScale, fScale);
204 canvas->rotate(fAngle);
205 canvas->drawImage(fImage.get(), -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
206 &paint);
207
208 if (false) {
209 acr.restore();
210 draw_box_frame(canvas, size.width(), size.height());
211 }
212 }
213
drawHere(SkCanvas * canvas,SkFilterQuality filter,SkScalar dx,SkScalar dy)214 void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
215 SkCanvas* origCanvas = canvas;
216 SkAutoCanvasRestore acr(canvas, true);
217
218 SkISize size = SkISize::Make(fImage->width(), fImage->height());
219
220 sk_sp<SkSurface> surface;
221 if (fShowFatBits) {
222 // scale up so we don't clip rotations
223 SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
224 kOpaque_SkAlphaType);
225 surface = make_surface(canvas, info);
226 canvas = surface->getCanvas();
227 canvas->drawColor(SK_ColorWHITE);
228 size.set(info.width(), info.height());
229 } else {
230 canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
231 SkScalarHalf(fCell.height() - fImage->height()));
232 }
233 this->drawTheImage(canvas, size, filter, dx, dy);
234
235 if (surface) {
236 sk_sp<SkImage> orig(surface->makeImageSnapshot());
237 sk_sp<SkImage> zoomed(zoom_up(surface.get(), orig.get()));
238 origCanvas->drawImage(zoomed.get(),
239 SkScalarHalf(fCell.width() - zoomed->width()),
240 SkScalarHalf(fCell.height() - zoomed->height()));
241 }
242 }
243
drawBorders(SkCanvas * canvas)244 void drawBorders(SkCanvas* canvas) {
245 SkPaint p;
246 p.setStyle(SkPaint::kStroke_Style);
247 p.setColor(SK_ColorBLUE);
248
249 SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
250 r.inset(SK_ScalarHalf, SK_ScalarHalf);
251 canvas->drawRect(r, p);
252 canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
253 canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
254 }
255
onDrawContent(SkCanvas * canvas)256 void onDrawContent(SkCanvas* canvas) override {
257 fCell.set(this->height() / 2, this->height() / 2);
258
259 SkScalar trans[2];
260 fTrans.timeToValues(fCurrTime, trans);
261
262 for (int y = 0; y < 2; ++y) {
263 for (int x = 0; x < 2; ++x) {
264 int index = y * 2 + x;
265 SkAutoCanvasRestore acr(canvas, true);
266 canvas->translate(fCell.width() * x, fCell.height() * y);
267 SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
268 r.inset(4, 4);
269 canvas->clipRect(r);
270 this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
271 }
272 }
273
274 this->drawBorders(canvas);
275
276 const SkScalar textX = fCell.width() * 2 + 30;
277
278 SkPaint paint;
279 paint.setAntiAlias(true);
280 paint.setTextSize(36);
281 SkString str;
282 str.appendScalar(fScale);
283 canvas->drawText(str.c_str(), str.size(), textX, 100, paint);
284 str.reset(); str.appendScalar(fAngle);
285 canvas->drawText(str.c_str(), str.size(), textX, 150, paint);
286
287 str.reset(); str.appendScalar(trans[0]);
288 canvas->drawText(str.c_str(), str.size(), textX, 200, paint);
289 str.reset(); str.appendScalar(trans[1]);
290 canvas->drawText(str.c_str(), str.size(), textX, 250, paint);
291 }
292
onAnimate(const SkAnimTimer & timer)293 bool onAnimate(const SkAnimTimer& timer) override {
294 fCurrTime = timer.msec();
295 return true;
296 }
297
handleKey(SkKey key)298 virtual bool handleKey(SkKey key) {
299 this->inval(nullptr);
300 return true;
301 }
302
303 private:
304 typedef SampleView INHERITED;
305 };
306
307 //////////////////////////////////////////////////////////////////////////////
308
MyFactory()309 static SkView* MyFactory() { return new FilterQualityView; }
310 static SkViewRegister reg(MyFactory);
311