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