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