• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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