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
19static 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
31static 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
48static 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
78struct AnimValue {
79    SkScalar fValue;
80    SkScalar fMin;
81    SkScalar fMax;
82    SkScalar fMod;
83
84    operator SkScalar() const { return fValue; }
85
86    void set(SkScalar value, SkScalar min, SkScalar max) {
87        fValue = value;
88        fMin = min;
89        fMax = max;
90        fMod = 0;
91    }
92
93    void setMod(SkScalar value, SkScalar mod) {
94        fValue = value;
95        fMin = 0;
96        fMax = 0;
97        fMod = mod;
98    }
99
100    SkScalar inc(SkScalar delta) {
101        fValue += delta;
102        return this->fixUp();
103    }
104
105    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
119static 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
130class FilterQualityView : public SampleView {
131    SkAutoTUnref<SkImage> fImage;
132    AnimValue             fScale, fAngle;
133    SkSize              fCell;
134    SkInterpolator      fTrans;
135    SkMSec              fCurrTime;
136    bool                fShowFatBits;
137
138public:
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
158protected:
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
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
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
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
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
279    bool onAnimate(const SkAnimTimer& timer) override {
280        fCurrTime = timer.msec();
281        return true;
282    }
283
284    virtual bool handleKey(SkKey key) {
285        this->inval(NULL);
286        return true;
287    }
288
289private:
290    typedef SampleView INHERITED;
291};
292
293//////////////////////////////////////////////////////////////////////////////
294
295static SkView* MyFactory() { return new FilterQualityView; }
296static SkViewRegister reg(MyFactory);
297