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