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