1/*
2 * Copyright 2013 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#include "SkCanvas.h"
10#include "SkFontMgr.h"
11#include "SkGraphics.h"
12#include "SkTypeface.h"
13
14#ifdef SK_BUILD_FOR_WIN
15    #include "SkTypeface_win.h"
16#endif
17
18// limit this just so we don't take too long to draw
19#define MAX_FAMILIES    30
20
21static SkScalar drawString(SkCanvas* canvas, const SkString& text, SkScalar x,
22                           SkScalar y, const SkPaint& paint) {
23    canvas->drawText(text.c_str(), text.size(), x, y, paint);
24    return x + paint.measureText(text.c_str(), text.size());
25}
26
27static SkScalar drawCharacter(SkCanvas* canvas, uint32_t character, SkScalar x,
28                              SkScalar y, SkPaint& paint, SkFontMgr* fm,
29                              const char* fontName, const char* bcp47[], int bcp47Count,
30                              const SkFontStyle& fontStyle) {
31    // find typeface containing the requested character and draw it
32    SkString ch;
33    ch.appendUnichar(character);
34    SkTypeface* typeface = fm->matchFamilyStyleCharacter(fontName, fontStyle,
35                                                         bcp47, bcp47Count, character);
36    SkSafeUnref(paint.setTypeface(typeface));
37    x = drawString(canvas, ch, x, y, paint) + 20;
38
39    if (nullptr == typeface) {
40        return x;
41    }
42
43    // repeat the process, but this time use the family name of the typeface
44    // from the first pass.  This emulates the behavior in Blink where it
45    // it expects to get the same glyph when following this pattern.
46    SkString familyName;
47    typeface->getFamilyName(&familyName);
48    SkTypeface* typefaceCopy = fm->legacyCreateTypeface(familyName.c_str(), typeface->style());
49    SkSafeUnref(paint.setTypeface(typefaceCopy));
50    return drawString(canvas, ch, x, y, paint) + 20;
51}
52
53static const char* zh = "zh";
54static const char* ja = "ja";
55
56class FontMgrGM : public skiagm::GM {
57public:
58    FontMgrGM(SkFontMgr* fontMgr = nullptr) {
59        SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
60
61        fName.set("fontmgr_iter");
62        if (fontMgr) {
63            fName.append("_factory");
64            fFM.reset(fontMgr);
65        } else {
66            fFM.reset(SkFontMgr::RefDefault());
67        }
68        fName.append(sk_tool_utils::platform_os_name());
69        fName.append(sk_tool_utils::platform_extra_config("GDI"));
70    }
71
72protected:
73    SkString onShortName() override {
74        return fName;
75    }
76
77    SkISize onISize() override {
78        return SkISize::Make(1536, 768);
79    }
80
81    void onDraw(SkCanvas* canvas) override {
82        SkScalar y = 20;
83        SkPaint paint;
84        paint.setAntiAlias(true);
85        paint.setLCDRenderText(true);
86        paint.setSubpixelText(true);
87        paint.setTextSize(17);
88
89        SkFontMgr* fm = fFM;
90        int count = SkMin32(fm->countFamilies(), MAX_FAMILIES);
91
92        for (int i = 0; i < count; ++i) {
93            SkString familyName;
94            fm->getFamilyName(i, &familyName);
95            paint.setTypeface(nullptr);
96            (void)drawString(canvas, familyName, 20, y, paint);
97
98            SkScalar x = 220;
99
100            SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i));
101            for (int j = 0; j < set->count(); ++j) {
102                SkString sname;
103                SkFontStyle fs;
104                set->getStyle(j, &fs, &sname);
105                sname.appendf(" [%d %d %d]", fs.weight(), fs.width(), fs.isItalic());
106
107                SkSafeUnref(paint.setTypeface(set->createTypeface(j)));
108                x = drawString(canvas, sname, x, y, paint) + 20;
109
110                // check to see that we get different glyphs in japanese and chinese
111                x = drawCharacter(canvas, 0x5203, x, y, paint, fm, familyName.c_str(), &zh, 1, fs);
112                x = drawCharacter(canvas, 0x5203, x, y, paint, fm, familyName.c_str(), &ja, 1, fs);
113                // check that emoji characters are found
114                x = drawCharacter(canvas, 0x1f601, x, y, paint, fm, familyName.c_str(), nullptr,0, fs);
115            }
116            y += 24;
117        }
118    }
119
120private:
121    SkAutoTUnref<SkFontMgr> fFM;
122    SkString fName;
123    typedef GM INHERITED;
124};
125
126class FontMgrMatchGM : public skiagm::GM {
127    SkAutoTUnref<SkFontMgr> fFM;
128
129public:
130    FontMgrMatchGM() : fFM(SkFontMgr::RefDefault()) {
131        SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
132    }
133
134protected:
135    SkString onShortName() override {
136        SkString name("fontmgr_match");
137        name.append(sk_tool_utils::platform_os_name());
138        name.append(sk_tool_utils::platform_extra_config("GDI"));
139        return name;
140    }
141
142    SkISize onISize() override {
143        return SkISize::Make(640, 1024);
144    }
145
146    void iterateFamily(SkCanvas* canvas, const SkPaint& paint,
147                       SkFontStyleSet* fset) {
148        SkPaint p(paint);
149        SkScalar y = 0;
150
151        for (int j = 0; j < fset->count(); ++j) {
152            SkString sname;
153            SkFontStyle fs;
154            fset->getStyle(j, &fs, &sname);
155
156            sname.appendf(" [%d %d]", fs.weight(), fs.width());
157
158            SkSafeUnref(p.setTypeface(fset->createTypeface(j)));
159            (void)drawString(canvas, sname, 0, y, p);
160            y += 24;
161        }
162    }
163
164    void exploreFamily(SkCanvas* canvas, const SkPaint& paint,
165                       SkFontStyleSet* fset) {
166        SkPaint p(paint);
167        SkScalar y = 0;
168
169        for (int weight = 100; weight <= 900; weight += 200) {
170            for (int width = 1; width <= 9; width += 2) {
171                SkFontStyle fs(weight, width, SkFontStyle::kUpright_Slant);
172                SkTypeface* face = fset->matchStyle(fs);
173                if (face) {
174                    SkString str;
175                    str.printf("request [%d %d]", fs.weight(), fs.width());
176                    p.setTypeface(face)->unref();
177                    (void)drawString(canvas, str, 0, y, p);
178                    y += 24;
179                }
180            }
181        }
182    }
183
184    void onDraw(SkCanvas* canvas) override {
185        SkPaint paint;
186        paint.setAntiAlias(true);
187        paint.setLCDRenderText(true);
188        paint.setSubpixelText(true);
189        paint.setTextSize(17);
190
191        static const char* gNames[] = {
192            "Helvetica Neue", "Arial"
193        };
194
195        SkAutoTUnref<SkFontStyleSet> fset;
196        for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) {
197            fset.reset(fFM->matchFamily(gNames[i]));
198            if (fset->count() > 0) {
199                break;
200            }
201        }
202        if (nullptr == fset.get()) {
203            return;
204        }
205
206        canvas->translate(20, 40);
207        this->exploreFamily(canvas, paint, fset);
208        canvas->translate(150, 0);
209        this->iterateFamily(canvas, paint, fset);
210    }
211
212private:
213    typedef GM INHERITED;
214};
215
216class FontMgrBoundsGM : public skiagm::GM {
217public:
218    FontMgrBoundsGM(double scale, double skew)
219        : fScaleX(SkDoubleToScalar(scale))
220        , fSkewX(SkDoubleToScalar(skew))
221    {
222        fName.set("fontmgr_bounds");
223        if (scale != 1 || skew != 0) {
224            fName.appendf("_%g_%g", scale, skew);
225        }
226        fName.append(sk_tool_utils::platform_os_name());
227        fName.append(sk_tool_utils::platform_extra_config("GDI"));
228        fFM.reset(SkFontMgr::RefDefault());
229    }
230
231    static void show_bounds(SkCanvas* canvas, const SkPaint& paint, SkScalar x, SkScalar y,
232                            SkColor boundsColor) {
233        const char str[] = "jyHO[]{}@-_&%$";
234
235        for (int i = 0; str[i]; ++i) {
236            canvas->drawText(&str[i], 1, x, y, paint);
237        }
238
239        SkRect r = paint.getFontBounds();
240        r.offset(x, y);
241        SkPaint p(paint);
242        p.setColor(boundsColor);
243        canvas->drawRect(r, p);
244    }
245
246protected:
247    SkString onShortName() override {
248        return fName;
249    }
250
251    SkISize onISize() override {
252        return SkISize::Make(1024, 850);
253    }
254
255    void onDraw(SkCanvas* canvas) override {
256        SkPaint paint;
257        paint.setAntiAlias(true);
258        paint.setSubpixelText(true);
259        paint.setTextSize(100);
260        paint.setStyle(SkPaint::kStroke_Style);
261        paint.setTextScaleX(fScaleX);
262        paint.setTextSkewX(fSkewX);
263
264        const SkColor boundsColors[2] = { SK_ColorRED, SK_ColorBLUE };
265
266        SkFontMgr* fm = fFM;
267        int count = SkMin32(fm->countFamilies(), 32);
268
269        int index = 0;
270        SkScalar x = 0, y = 0;
271
272        canvas->translate(80, 120);
273
274        for (int i = 0; i < count; ++i) {
275            SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i));
276            for (int j = 0; j < set->count(); ++j) {
277                SkSafeUnref(paint.setTypeface(set->createTypeface(j)));
278                if (paint.getTypeface()) {
279                    show_bounds(canvas, paint, x, y, boundsColors[index & 1]);
280                    index += 1;
281                    x += 160;
282                    if (0 == (index % 6)) {
283                        x = 0;
284                        y += 160;
285                    }
286                    if (index >= 30) {
287                        return;
288                    }
289                }
290            }
291        }
292    }
293
294private:
295    SkAutoTUnref<SkFontMgr> fFM;
296    SkString fName;
297    SkScalar fScaleX, fSkewX;
298    typedef GM INHERITED;
299};
300
301//////////////////////////////////////////////////////////////////////////////
302
303DEF_GM(return new FontMgrGM;)
304DEF_GM(return new FontMgrMatchGM;)
305DEF_GM(return new FontMgrBoundsGM(1.0, 0);)
306DEF_GM(return new FontMgrBoundsGM(0.75, 0);)
307DEF_GM(return new FontMgrBoundsGM(1.0, -0.25);)
308
309#ifdef SK_BUILD_FOR_WIN
310DEF_GM(return new FontMgrGM(SkFontMgr_New_DirectWrite());)
311#endif
312