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
22static 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
30static 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
39static 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
59static 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
89struct AnimValue {
90    SkScalar fValue;
91    SkScalar fMin;
92    SkScalar fMax;
93    SkScalar fMod;
94
95    operator SkScalar() const { return fValue; }
96
97    void set(SkScalar value, SkScalar min, SkScalar max) {
98        fValue = value;
99        fMin = min;
100        fMax = max;
101        fMod = 0;
102    }
103
104    void setMod(SkScalar value, SkScalar mod) {
105        fValue = value;
106        fMin = 0;
107        fMax = 0;
108        fMod = mod;
109    }
110
111    SkScalar inc(SkScalar delta) {
112        fValue += delta;
113        return this->fixUp();
114    }
115
116    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
130static 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
141class 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
149public:
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
169protected:
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
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
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
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
253    void onOnceBeforeDraw() override {
254        fImage = make_image();
255    }
256
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
294    bool onAnimate(const SkAnimTimer& timer) override {
295        fCurrTime = timer.msec();
296        return true;
297    }
298
299private:
300    typedef SampleView INHERITED;
301};
302
303//////////////////////////////////////////////////////////////////////////////
304
305static SkView* MyFactory() { return new FilterQualityView; }
306static SkViewRegister reg(MyFactory);
307