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