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