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 "sk_tool_utils.h"
10 #include "SkCanvas.h"
11 #include "SkCommonFlags.h"
12 #include "SkFontMetrics.h"
13 #include "SkFontMgr.h"
14 #include "SkFontPriv.h"
15 #include "SkPath.h"
16 #include "SkGraphics.h"
17 #include "SkTypeface.h"
18 
19 // limit this just so we don't take too long to draw
20 #define MAX_FAMILIES    30
21 
drawString(SkCanvas * canvas,const SkString & text,SkScalar x,SkScalar y,const SkFont & font)22 static SkScalar drawString(SkCanvas* canvas, const SkString& text, SkScalar x,
23                            SkScalar y, const SkFont& font) {
24     canvas->drawString(text, x, y, font, SkPaint());
25     return x + font.measureText(text.c_str(), text.size(), kUTF8_SkTextEncoding);
26 }
27 
drawCharacter(SkCanvas * canvas,uint32_t character,SkScalar x,SkScalar y,const SkFont & origFont,SkFontMgr * fm,const char * fontName,const char * bcp47[],int bcp47Count,const SkFontStyle & fontStyle)28 static SkScalar drawCharacter(SkCanvas* canvas, uint32_t character, SkScalar x,
29                               SkScalar y, const SkFont& origFont, SkFontMgr* fm,
30                               const char* fontName, const char* bcp47[], int bcp47Count,
31                               const SkFontStyle& fontStyle) {
32     SkFont font = origFont;
33     // find typeface containing the requested character and draw it
34     SkString ch;
35     ch.appendUnichar(character);
36     sk_sp<SkTypeface> typeface(fm->matchFamilyStyleCharacter(fontName, fontStyle,
37                                                              bcp47, bcp47Count, character));
38     font.setTypeface(typeface);
39     x = drawString(canvas, ch, x, y, font) + 20;
40 
41     if (nullptr == typeface) {
42         return x;
43     }
44 
45     // repeat the process, but this time use the family name of the typeface
46     // from the first pass.  This emulates the behavior in Blink where it
47     // it expects to get the same glyph when following this pattern.
48     SkString familyName;
49     typeface->getFamilyName(&familyName);
50     font.setTypeface(fm->legacyMakeTypeface(familyName.c_str(), typeface->fontStyle()));
51     return drawString(canvas, ch, x, y, font) + 20;
52 }
53 
54 static const char* zh = "zh";
55 static const char* ja = "ja";
56 
57 class FontMgrGM : public skiagm::GM {
58 public:
FontMgrGM()59     FontMgrGM() {
60         SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
61 
62         fName.set("fontmgr_iter");
63         fFM = SkFontMgr::RefDefault();
64         fName.append(sk_tool_utils::platform_font_manager());
65     }
66 
67 protected:
onShortName()68     SkString onShortName() override {
69         return fName;
70     }
71 
onISize()72     SkISize onISize() override {
73         return SkISize::Make(1536, 768);
74     }
75 
onDraw(SkCanvas * canvas)76     void onDraw(SkCanvas* canvas) override {
77         SkScalar y = 20;
78         SkFont font;
79         font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
80         font.setSubpixel(true);
81         font.setSize(17);
82 
83         SkFontMgr* fm = fFM.get();
84         int count = SkMin32(fm->countFamilies(), MAX_FAMILIES);
85 
86         for (int i = 0; i < count; ++i) {
87             SkString familyName;
88             fm->getFamilyName(i, &familyName);
89             font.setTypeface(nullptr);
90             (void)drawString(canvas, familyName, 20, y, font);
91 
92             SkScalar x = 220;
93 
94             sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
95             for (int j = 0; j < set->count(); ++j) {
96                 SkString sname;
97                 SkFontStyle fs;
98                 set->getStyle(j, &fs, &sname);
99                 sname.appendf(" [%d %d %d]", fs.weight(), fs.width(), fs.slant());
100 
101                 font.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
102                 x = drawString(canvas, sname, x, y, font) + 20;
103 
104                 // check to see that we get different glyphs in japanese and chinese
105                 x = drawCharacter(canvas, 0x5203, x, y, font, fm, familyName.c_str(), &zh, 1, fs);
106                 x = drawCharacter(canvas, 0x5203, x, y, font, fm, familyName.c_str(), &ja, 1, fs);
107                 // check that emoji characters are found
108                 x = drawCharacter(canvas, 0x1f601, x, y, font, fm, familyName.c_str(), nullptr,0, fs);
109             }
110             y += 24;
111         }
112     }
113 
114 private:
115     sk_sp<SkFontMgr> fFM;
116     SkString fName;
117     typedef GM INHERITED;
118 };
119 
120 class FontMgrMatchGM : public skiagm::GM {
121     sk_sp<SkFontMgr> fFM;
122 
123 public:
FontMgrMatchGM()124     FontMgrMatchGM() : fFM(SkFontMgr::RefDefault()) {
125         SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
126     }
127 
128 protected:
onShortName()129     SkString onShortName() override {
130         SkString name("fontmgr_match");
131         name.append(sk_tool_utils::platform_font_manager());
132         return name;
133     }
134 
onISize()135     SkISize onISize() override {
136         return SkISize::Make(640, 1024);
137     }
138 
iterateFamily(SkCanvas * canvas,const SkFont & font,SkFontStyleSet * fset)139     void iterateFamily(SkCanvas* canvas, const SkFont& font, SkFontStyleSet* fset) {
140         SkFont f(font);
141         SkScalar y = 0;
142 
143         for (int j = 0; j < fset->count(); ++j) {
144             SkString sname;
145             SkFontStyle fs;
146             fset->getStyle(j, &fs, &sname);
147 
148             sname.appendf(" [%d %d]", fs.weight(), fs.width());
149 
150             f.setTypeface(sk_sp<SkTypeface>(fset->createTypeface(j)));
151             (void)drawString(canvas, sname, 0, y, f);
152             y += 24;
153         }
154     }
155 
exploreFamily(SkCanvas * canvas,const SkFont & font,SkFontStyleSet * fset)156     void exploreFamily(SkCanvas* canvas, const SkFont& font, SkFontStyleSet* fset) {
157         SkFont f(font);
158         SkScalar y = 0;
159 
160         for (int weight = 100; weight <= 900; weight += 200) {
161             for (int width = 1; width <= 9; width += 2) {
162                 SkFontStyle fs(weight, width, SkFontStyle::kUpright_Slant);
163                 sk_sp<SkTypeface> face(fset->matchStyle(fs));
164                 if (face) {
165                     SkString str;
166                     str.printf("request [%d %d]", fs.weight(), fs.width());
167                     f.setTypeface(std::move(face));
168                     (void)drawString(canvas, str, 0, y, f);
169                     y += 24;
170                 }
171             }
172         }
173     }
174 
onDraw(SkCanvas * canvas)175     void onDraw(SkCanvas* canvas) override {
176         SkFont font;
177         font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
178         font.setSubpixel(true);
179         font.setSize(17);
180 
181         const char* gNames[] = {
182             "Helvetica Neue", "Arial", "sans"
183         };
184 
185         sk_sp<SkFontStyleSet> fset;
186         for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) {
187             fset.reset(fFM->matchFamily(gNames[i]));
188             if (fset->count() > 0) {
189                 break;
190             }
191         }
192         if (nullptr == fset.get()) {
193             return;
194         }
195 
196         canvas->translate(20, 40);
197         this->exploreFamily(canvas, font, fset.get());
198         canvas->translate(150, 0);
199         this->iterateFamily(canvas, font, fset.get());
200     }
201 
202 private:
203     typedef GM INHERITED;
204 };
205 
206 class FontMgrBoundsGM : public skiagm::GM {
207 public:
FontMgrBoundsGM(double scale,double skew)208     FontMgrBoundsGM(double scale, double skew)
209         : fScaleX(SkDoubleToScalar(scale))
210         , fSkewX(SkDoubleToScalar(skew))
211     {
212         fName.set("fontmgr_bounds");
213         if (scale != 1 || skew != 0) {
214             fName.appendf("_%g_%g", scale, skew);
215         }
216         fName.append(sk_tool_utils::platform_font_manager());
217         fFM = SkFontMgr::RefDefault();
218     }
219 
show_bounds(SkCanvas * canvas,const SkFont & font,SkScalar x,SkScalar y,SkColor boundsColor)220     static void show_bounds(SkCanvas* canvas, const SkFont& font, SkScalar x, SkScalar y,
221                             SkColor boundsColor)
222     {
223         SkRect fontBounds = SkFontPriv::GetFontBounds(font).makeOffset(x, y);
224 
225         SkPaint boundsPaint;
226         boundsPaint.setAntiAlias(true);
227         boundsPaint.setColor(boundsColor);
228         boundsPaint.setStyle(SkPaint::kStroke_Style);
229         canvas->drawRect(fontBounds, boundsPaint);
230 
231         SkFontMetrics fm;
232         font.getMetrics(&fm);
233         SkPaint metricsPaint(boundsPaint);
234         metricsPaint.setStyle(SkPaint::kFill_Style);
235         metricsPaint.setAlpha(0x40);
236         if ((fm.fFlags & SkFontMetrics::kUnderlinePositionIsValid_Flag) &&
237             (fm.fFlags & SkFontMetrics::kUnderlinePositionIsValid_Flag))
238         {
239             SkRect underline{ fontBounds.fLeft,  fm.fUnderlinePosition+y,
240                               fontBounds.fRight, fm.fUnderlinePosition+y + fm.fUnderlineThickness };
241             canvas->drawRect(underline, metricsPaint);
242         }
243 
244         if ((fm.fFlags & SkFontMetrics::kStrikeoutPositionIsValid_Flag) &&
245             (fm.fFlags & SkFontMetrics::kStrikeoutPositionIsValid_Flag))
246         {
247             SkRect strikeout{ fontBounds.fLeft,  fm.fStrikeoutPosition+y - fm.fStrikeoutThickness,
248                               fontBounds.fRight, fm.fStrikeoutPosition+y };
249             canvas->drawRect(strikeout, metricsPaint);
250         }
251 
252         SkGlyphID left = 0, right = 0, top = 0, bottom = 0;
253         {
254             int numGlyphs = font.getTypefaceOrDefault()->countGlyphs();
255             SkRect min = {0, 0, 0, 0};
256             for (int i = 0; i < numGlyphs; ++i) {
257                 SkGlyphID glyphId = i;
258                 SkRect cur;
259                 font.getBounds(&glyphId, 1, &cur, nullptr);
260                 if (cur.fLeft   < min.fLeft  ) { min.fLeft   = cur.fLeft;   left   = i; }
261                 if (cur.fTop    < min.fTop   ) { min.fTop    = cur.fTop ;   top    = i; }
262                 if (min.fRight  < cur.fRight ) { min.fRight  = cur.fRight;  right  = i; }
263                 if (min.fBottom < cur.fBottom) { min.fBottom = cur.fBottom; bottom = i; }
264             }
265         }
266         SkGlyphID str[] = { left, right, top, bottom };
267         SkPoint location[] = {
268             {fontBounds.left(), fontBounds.centerY()},
269             {fontBounds.right(), fontBounds.centerY()},
270             {fontBounds.centerX(), fontBounds.top()},
271             {fontBounds.centerX(), fontBounds.bottom()}
272         };
273 
274         SkFont labelFont;
275         labelFont.setEdging(SkFont::Edging::kAntiAlias);
276         labelFont.setTypeface(sk_tool_utils::create_portable_typeface());
277 
278         if (FLAGS_veryVerbose) {
279             SkString name;
280             font.getTypefaceOrDefault()->getFamilyName(&name);
281             canvas->drawString(name, fontBounds.fLeft, fontBounds.fBottom, labelFont, SkPaint());
282         }
283         for (size_t i = 0; i < SK_ARRAY_COUNT(str); ++i) {
284             SkPath path;
285             font.getPath(str[i], &path);
286             path.offset(x, y);
287             SkPaint::Style style = path.isEmpty() ? SkPaint::kFill_Style : SkPaint::kStroke_Style;
288             SkPaint glyphPaint;
289             glyphPaint.setStyle(style);
290             canvas->drawSimpleText(&str[i], sizeof(str[0]), kGlyphID_SkTextEncoding, x, y, font, glyphPaint);
291 
292             if (FLAGS_veryVerbose) {
293                 SkString glyphStr;
294                 glyphStr.appendS32(str[i]);
295                 canvas->drawString(glyphStr, location[i].fX, location[i].fY, labelFont, SkPaint());
296             }
297 
298         }
299 
300     }
301 
302 protected:
onShortName()303     SkString onShortName() override {
304         return fName;
305     }
306 
onISize()307     SkISize onISize() override {
308         return SkISize::Make(1024, 850);
309     }
310 
onDraw(SkCanvas * canvas)311     void onDraw(SkCanvas* canvas) override {
312         SkFont font;
313         font.setEdging(SkFont::Edging::kAntiAlias);
314         font.setSubpixel(true);
315         font.setSize(100);
316         font.setScaleX(fScaleX);
317         font.setSkewX(fSkewX);
318 
319         const SkColor boundsColors[2] = { SK_ColorRED, SK_ColorBLUE };
320 
321         SkFontMgr* fm = fFM.get();
322         int count = SkMin32(fm->countFamilies(), 32);
323 
324         int index = 0;
325         SkScalar x = 0, y = 0;
326 
327         canvas->translate(10, 120);
328 
329         for (int i = 0; i < count; ++i) {
330             sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
331             for (int j = 0; j < set->count() && j < 3; ++j) {
332                 font.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
333                 // Fonts with lots of glyphs are interesting, but can take a long time to find
334                 // the glyphs which make up the maximum extent.
335                 if (font.getTypefaceOrDefault() && font.getTypefaceOrDefault()->countGlyphs() < 1000) {
336                     SkRect fontBounds = SkFontPriv::GetFontBounds(font);
337                     x -= fontBounds.fLeft;
338                     show_bounds(canvas, font, x, y, boundsColors[index & 1]);
339                     x += fontBounds.fRight + 20;
340                     index += 1;
341                     if (x > 900) {
342                         x = 0;
343                         y += 160;
344                     }
345                     if (y >= 700) {
346                         return;
347                     }
348                 }
349             }
350         }
351     }
352 
353 private:
354     sk_sp<SkFontMgr> fFM;
355     SkString fName;
356     SkScalar fScaleX, fSkewX;
357     typedef GM INHERITED;
358 };
359 
360 //////////////////////////////////////////////////////////////////////////////
361 
362 DEF_GM(return new FontMgrGM;)
363 DEF_GM(return new FontMgrMatchGM;)
364 DEF_GM(return new FontMgrBoundsGM(1.0, 0);)
365 DEF_GM(return new FontMgrBoundsGM(0.75, 0);)
366 DEF_GM(return new FontMgrBoundsGM(1.0, -0.25);)
367