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 "include/core/SkCanvas.h"
9 #include "include/core/SkData.h"
10 #include "include/core/SkFont.h"
11 #include "include/core/SkPath.h"
12 #include "include/core/SkSurface.h"
13 #include "include/core/SkTime.h"
14 #include "include/effects/SkGradientShader.h"
15 #include "include/utils/SkInterpolator.h"
16 #include "include/utils/SkRandom.h"
17 #include "samplecode/Sample.h"
18 #include "tools/Resources.h"
19 #include "tools/timer/TimeUtils.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:
name()169 SkString name() override { return SkString("FilterQuality"); }
170
onChar(SkUnichar uni)171 bool onChar(SkUnichar uni) override {
172 switch (uni) {
173 case '1': fAngle.inc(-ANGLE_DELTA); return true;
174 case '2': fAngle.inc( ANGLE_DELTA); return true;
175 case '3': fScale.inc(-SCALE_DELTA); return true;
176 case '4': fScale.inc( SCALE_DELTA); return true;
177 case '5': fShowFatBits = !fShowFatBits; return true;
178 default: break;
179 }
180 return false;
181 }
182
drawTheImage(SkCanvas * canvas,const SkISize & size,SkFilterQuality filter,SkScalar dx,SkScalar dy)183 void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
184 SkScalar dx, SkScalar dy) {
185 SkPaint paint;
186 paint.setAntiAlias(true);
187 paint.setFilterQuality(filter);
188
189 SkAutoCanvasRestore acr(canvas, true);
190
191 canvas->translate(dx, dy);
192
193 canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
194 canvas->scale(fScale, fScale);
195 canvas->rotate(fAngle);
196 canvas->drawImage(fImage.get(), -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
197 &paint);
198
199 if (false) {
200 acr.restore();
201 draw_box_frame(canvas, size.width(), size.height());
202 }
203 }
204
drawHere(SkCanvas * canvas,SkFilterQuality filter,SkScalar dx,SkScalar dy)205 void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
206 SkCanvas* origCanvas = canvas;
207 SkAutoCanvasRestore acr(canvas, true);
208
209 SkISize size = SkISize::Make(fImage->width(), fImage->height());
210
211 sk_sp<SkSurface> surface;
212 if (fShowFatBits) {
213 // scale up so we don't clip rotations
214 SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
215 kOpaque_SkAlphaType);
216 surface = make_surface(canvas, info);
217 canvas = surface->getCanvas();
218 canvas->drawColor(SK_ColorWHITE);
219 size.set(info.width(), info.height());
220 } else {
221 canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
222 SkScalarHalf(fCell.height() - fImage->height()));
223 }
224 this->drawTheImage(canvas, size, filter, dx, dy);
225
226 if (surface) {
227 sk_sp<SkImage> orig(surface->makeImageSnapshot());
228 sk_sp<SkImage> zoomed(zoom_up(surface.get(), orig.get()));
229 origCanvas->drawImage(zoomed.get(),
230 SkScalarHalf(fCell.width() - zoomed->width()),
231 SkScalarHalf(fCell.height() - zoomed->height()));
232 }
233 }
234
drawBorders(SkCanvas * canvas)235 void drawBorders(SkCanvas* canvas) {
236 SkPaint p;
237 p.setStyle(SkPaint::kStroke_Style);
238 p.setColor(SK_ColorBLUE);
239
240 SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
241 r.inset(SK_ScalarHalf, SK_ScalarHalf);
242 canvas->drawRect(r, p);
243 canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
244 canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
245 }
246
onOnceBeforeDraw()247 void onOnceBeforeDraw() override {
248 fImage = make_image();
249 }
250
onDrawContent(SkCanvas * canvas)251 void onDrawContent(SkCanvas* canvas) override {
252 fCell.set(this->height() / 2, this->height() / 2);
253
254 SkScalar trans[2];
255 fTrans.timeToValues(fCurrTime, trans);
256
257 for (int y = 0; y < 2; ++y) {
258 for (int x = 0; x < 2; ++x) {
259 int index = y * 2 + x;
260 SkAutoCanvasRestore acr(canvas, true);
261 canvas->translate(fCell.width() * x, fCell.height() * y);
262 SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
263 r.inset(4, 4);
264 canvas->clipRect(r);
265 this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
266 }
267 }
268
269 this->drawBorders(canvas);
270
271 const SkScalar textX = fCell.width() * 2 + 30;
272
273 SkFont font(nullptr, 36);
274 SkPaint paint;
275 canvas->drawString(SkStringPrintf("%.8g", (float)fScale), textX, 100, font, paint);
276 canvas->drawString(SkStringPrintf("%.8g", (float)fAngle), textX, 150, font, paint);
277 canvas->drawString(SkStringPrintf("%.8g", trans[0] ), textX, 200, font, paint);
278 canvas->drawString(SkStringPrintf("%.8g", trans[1] ), textX, 250, font, paint);
279 }
280
onAnimate(double nanos)281 bool onAnimate(double nanos) override {
282 fCurrTime = TimeUtils::NanosToMSec(nanos);
283 return true;
284 }
285
286 private:
287 typedef Sample INHERITED;
288 };
289
290 //////////////////////////////////////////////////////////////////////////////
291
292 DEF_SAMPLE( return new FilterQualityView(); )
293