blob: 8d14e3a66d1db8ffff8f0bd46b8da9793b83d6c9 [file] [log] [blame]
reed@google.comaf0fa6a2013-03-28 13:39:35 +00001/*
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"
Mike Klein33d20552017-03-22 13:47:51 -04009#include "sk_tool_utils.h"
reed@google.comaf0fa6a2013-03-28 13:39:35 +000010#include "SkCanvas.h"
11#include "SkFontMgr.h"
12#include "SkGraphics.h"
13#include "SkTypeface.h"
14
bungeman@google.combfc6cc42013-08-21 15:20:43 +000015#ifdef SK_BUILD_FOR_WIN
reed@google.comd1bcfc92013-08-28 20:31:58 +000016 #include "SkTypeface_win.h"
bungeman@google.combfc6cc42013-08-21 15:20:43 +000017#endif
18
reed@google.comaf0fa6a2013-03-28 13:39:35 +000019// limit this just so we don't take too long to draw
20#define MAX_FAMILIES 30
21
22static SkScalar drawString(SkCanvas* canvas, const SkString& text, SkScalar x,
23 SkScalar y, const SkPaint& paint) {
Cary Clark2a475ea2017-04-28 15:35:12 -040024 canvas->drawString(text, x, y, paint);
reed@google.comaf0fa6a2013-03-28 13:39:35 +000025 return x + paint.measureText(text.c_str(), text.size());
26}
27
djsollen0d393a92014-08-27 07:03:13 -070028static SkScalar drawCharacter(SkCanvas* canvas, uint32_t character, SkScalar x,
29 SkScalar y, SkPaint& paint, SkFontMgr* fm,
bungemanc9232dc2014-11-10 13:29:33 -080030 const char* fontName, const char* bcp47[], int bcp47Count,
djsollen0d393a92014-08-27 07:03:13 -070031 const SkFontStyle& fontStyle) {
32 // find typeface containing the requested character and draw it
33 SkString ch;
34 ch.appendUnichar(character);
bungeman13b9c952016-05-12 10:09:30 -070035 sk_sp<SkTypeface> typeface(fm->matchFamilyStyleCharacter(fontName, fontStyle,
36 bcp47, bcp47Count, character));
37 paint.setTypeface(typeface);
djsollen0d393a92014-08-27 07:03:13 -070038 x = drawString(canvas, ch, x, y, paint) + 20;
39
halcanary96fcdcc2015-08-27 07:41:13 -070040 if (nullptr == typeface) {
djsollen0d393a92014-08-27 07:03:13 -070041 return x;
42 }
43
44 // repeat the process, but this time use the family name of the typeface
45 // from the first pass. This emulates the behavior in Blink where it
46 // it expects to get the same glyph when following this pattern.
47 SkString familyName;
48 typeface->getFamilyName(&familyName);
bungeman13b9c952016-05-12 10:09:30 -070049 paint.setTypeface(sk_sp<SkTypeface>(fm->legacyCreateTypeface(familyName.c_str(),
50 typeface->fontStyle())));
djsollen0d393a92014-08-27 07:03:13 -070051 return drawString(canvas, ch, x, y, paint) + 20;
52}
53
bungemanc9232dc2014-11-10 13:29:33 -080054static const char* zh = "zh";
55static const char* ja = "ja";
56
reed@google.comaf0fa6a2013-03-28 13:39:35 +000057class FontMgrGM : public skiagm::GM {
58public:
Ben Wagner3546ff12017-01-03 13:32:36 -050059 FontMgrGM(sk_sp<SkFontMgr> fontMgr = nullptr) {
60 SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
61
62 fName.set("fontmgr_iter");
63 if (fontMgr) {
64 fName.append("_factory");
65 fFM = std::move(fontMgr);
66 } else {
67 fFM = SkFontMgr::RefDefault();
68 }
69 fName.append(sk_tool_utils::platform_os_name());
70 fName.append(sk_tool_utils::platform_extra_config("GDI"));
71 }
reed@google.comaf0fa6a2013-03-28 13:39:35 +000072
73protected:
mtklein36352bf2015-03-25 18:17:31 -070074 SkString onShortName() override {
bungeman@google.combfc6cc42013-08-21 15:20:43 +000075 return fName;
reed@google.comaf0fa6a2013-03-28 13:39:35 +000076 }
77
mtklein36352bf2015-03-25 18:17:31 -070078 SkISize onISize() override {
djsollen0d393a92014-08-27 07:03:13 -070079 return SkISize::Make(1536, 768);
reed@google.comaf0fa6a2013-03-28 13:39:35 +000080 }
81
mtklein36352bf2015-03-25 18:17:31 -070082 void onDraw(SkCanvas* canvas) override {
reed@google.comaf0fa6a2013-03-28 13:39:35 +000083 SkScalar y = 20;
84 SkPaint paint;
85 paint.setAntiAlias(true);
86 paint.setLCDRenderText(true);
87 paint.setSubpixelText(true);
88 paint.setTextSize(17);
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +000089
Hal Canarycefc4312016-11-04 16:26:16 -040090 SkFontMgr* fm = fFM.get();
reed@google.comaf0fa6a2013-03-28 13:39:35 +000091 int count = SkMin32(fm->countFamilies(), MAX_FAMILIES);
92
93 for (int i = 0; i < count; ++i) {
bungemanc64239a2015-04-29 08:15:31 -070094 SkString familyName;
95 fm->getFamilyName(i, &familyName);
halcanary96fcdcc2015-08-27 07:41:13 -070096 paint.setTypeface(nullptr);
bungemanc64239a2015-04-29 08:15:31 -070097 (void)drawString(canvas, familyName, 20, y, paint);
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +000098
reed@google.comaf0fa6a2013-03-28 13:39:35 +000099 SkScalar x = 220;
reed@google.com964988f2013-03-29 14:57:22 +0000100
Hal Canarycefc4312016-11-04 16:26:16 -0400101 sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
reed@google.comaf0fa6a2013-03-28 13:39:35 +0000102 for (int j = 0; j < set->count(); ++j) {
103 SkString sname;
104 SkFontStyle fs;
105 set->getStyle(j, &fs, &sname);
bungemanb4bb7d82016-04-27 10:21:04 -0700106 sname.appendf(" [%d %d %d]", fs.weight(), fs.width(), fs.slant());
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000107
bungeman13b9c952016-05-12 10:09:30 -0700108 paint.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
reed@google.comaf0fa6a2013-03-28 13:39:35 +0000109 x = drawString(canvas, sname, x, y, paint) + 20;
djsollen0d393a92014-08-27 07:03:13 -0700110
111 // check to see that we get different glyphs in japanese and chinese
bungemanc64239a2015-04-29 08:15:31 -0700112 x = drawCharacter(canvas, 0x5203, x, y, paint, fm, familyName.c_str(), &zh, 1, fs);
113 x = drawCharacter(canvas, 0x5203, x, y, paint, fm, familyName.c_str(), &ja, 1, fs);
djsollen0d393a92014-08-27 07:03:13 -0700114 // check that emoji characters are found
halcanary96fcdcc2015-08-27 07:41:13 -0700115 x = drawCharacter(canvas, 0x1f601, x, y, paint, fm, familyName.c_str(), nullptr,0, fs);
skia.committer@gmail.com6acd09e2013-03-29 07:01:22 +0000116 }
reed@google.comaf0fa6a2013-03-28 13:39:35 +0000117 y += 24;
118 }
119 }
120
reed@google.comaf0fa6a2013-03-28 13:39:35 +0000121private:
Hal Canarycefc4312016-11-04 16:26:16 -0400122 sk_sp<SkFontMgr> fFM;
bungeman@google.combfc6cc42013-08-21 15:20:43 +0000123 SkString fName;
reed@google.comaf0fa6a2013-03-28 13:39:35 +0000124 typedef GM INHERITED;
125};
126
reed@google.com964988f2013-03-29 14:57:22 +0000127class FontMgrMatchGM : public skiagm::GM {
Hal Canarycefc4312016-11-04 16:26:16 -0400128 sk_sp<SkFontMgr> fFM;
reed@google.com964988f2013-03-29 14:57:22 +0000129
130public:
131 FontMgrMatchGM() : fFM(SkFontMgr::RefDefault()) {
132 SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
133 }
skia.committer@gmail.comd55846d2013-03-30 07:01:27 +0000134
reed@google.com964988f2013-03-29 14:57:22 +0000135protected:
mtklein36352bf2015-03-25 18:17:31 -0700136 SkString onShortName() override {
caryclark6531c362015-07-20 13:38:56 -0700137 SkString name("fontmgr_match");
138 name.append(sk_tool_utils::platform_os_name());
139 name.append(sk_tool_utils::platform_extra_config("GDI"));
140 return name;
reed@google.com964988f2013-03-29 14:57:22 +0000141 }
skia.committer@gmail.comd55846d2013-03-30 07:01:27 +0000142
mtklein36352bf2015-03-25 18:17:31 -0700143 SkISize onISize() override {
reed@google.com964988f2013-03-29 14:57:22 +0000144 return SkISize::Make(640, 1024);
145 }
146
147 void iterateFamily(SkCanvas* canvas, const SkPaint& paint,
148 SkFontStyleSet* fset) {
149 SkPaint p(paint);
150 SkScalar y = 0;
151
152 for (int j = 0; j < fset->count(); ++j) {
153 SkString sname;
154 SkFontStyle fs;
155 fset->getStyle(j, &fs, &sname);
156
157 sname.appendf(" [%d %d]", fs.weight(), fs.width());
158
bungeman13b9c952016-05-12 10:09:30 -0700159 p.setTypeface(sk_sp<SkTypeface>(fset->createTypeface(j)));
reed@google.com964988f2013-03-29 14:57:22 +0000160 (void)drawString(canvas, sname, 0, y, p);
161 y += 24;
162 }
163 }
164
165 void exploreFamily(SkCanvas* canvas, const SkPaint& paint,
166 SkFontStyleSet* fset) {
167 SkPaint p(paint);
168 SkScalar y = 0;
169
170 for (int weight = 100; weight <= 900; weight += 200) {
171 for (int width = 1; width <= 9; width += 2) {
172 SkFontStyle fs(weight, width, SkFontStyle::kUpright_Slant);
bungeman13b9c952016-05-12 10:09:30 -0700173 sk_sp<SkTypeface> face(fset->matchStyle(fs));
reed@google.com964988f2013-03-29 14:57:22 +0000174 if (face) {
175 SkString str;
176 str.printf("request [%d %d]", fs.weight(), fs.width());
bungeman13b9c952016-05-12 10:09:30 -0700177 p.setTypeface(std::move(face));
reed@google.com964988f2013-03-29 14:57:22 +0000178 (void)drawString(canvas, str, 0, y, p);
179 y += 24;
180 }
181 }
182 }
183 }
skia.committer@gmail.comd55846d2013-03-30 07:01:27 +0000184
mtklein36352bf2015-03-25 18:17:31 -0700185 void onDraw(SkCanvas* canvas) override {
reed@google.com964988f2013-03-29 14:57:22 +0000186 SkPaint paint;
187 paint.setAntiAlias(true);
188 paint.setLCDRenderText(true);
189 paint.setSubpixelText(true);
190 paint.setTextSize(17);
191
mtkleindbfd7ab2016-09-01 11:24:54 -0700192 const char* gNames[] = {
reed@google.com964988f2013-03-29 14:57:22 +0000193 "Helvetica Neue", "Arial"
194 };
195
Hal Canarycefc4312016-11-04 16:26:16 -0400196 sk_sp<SkFontStyleSet> fset;
skia.committer@gmail.comd55846d2013-03-30 07:01:27 +0000197 for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) {
bungeman@google.com9fc5c682013-11-12 15:25:29 +0000198 fset.reset(fFM->matchFamily(gNames[i]));
199 if (fset->count() > 0) {
reed@google.com964988f2013-03-29 14:57:22 +0000200 break;
201 }
202 }
halcanary96fcdcc2015-08-27 07:41:13 -0700203 if (nullptr == fset.get()) {
reed@google.com964988f2013-03-29 14:57:22 +0000204 return;
205 }
reed@google.com964988f2013-03-29 14:57:22 +0000206
207 canvas->translate(20, 40);
Hal Canarycefc4312016-11-04 16:26:16 -0400208 this->exploreFamily(canvas, paint, fset.get());
reed@google.com964988f2013-03-29 14:57:22 +0000209 canvas->translate(150, 0);
Hal Canarycefc4312016-11-04 16:26:16 -0400210 this->iterateFamily(canvas, paint, fset.get());
reed@google.com964988f2013-03-29 14:57:22 +0000211 }
skia.committer@gmail.comd55846d2013-03-30 07:01:27 +0000212
reed@google.com964988f2013-03-29 14:57:22 +0000213private:
214 typedef GM INHERITED;
215};
216
reeda0c814c2014-10-22 13:20:58 -0700217class FontMgrBoundsGM : public skiagm::GM {
218public:
reed8893e5f2014-12-15 13:27:26 -0800219 FontMgrBoundsGM(double scale, double skew)
220 : fScaleX(SkDoubleToScalar(scale))
221 , fSkewX(SkDoubleToScalar(skew))
222 {
reeda0c814c2014-10-22 13:20:58 -0700223 fName.set("fontmgr_bounds");
reed8893e5f2014-12-15 13:27:26 -0800224 if (scale != 1 || skew != 0) {
225 fName.appendf("_%g_%g", scale, skew);
226 }
caryclark6531c362015-07-20 13:38:56 -0700227 fName.append(sk_tool_utils::platform_os_name());
228 fName.append(sk_tool_utils::platform_extra_config("GDI"));
Ben Wagner3546ff12017-01-03 13:32:36 -0500229 fFM = SkFontMgr::RefDefault();
reeda0c814c2014-10-22 13:20:58 -0700230 }
231
232 static void show_bounds(SkCanvas* canvas, const SkPaint& paint, SkScalar x, SkScalar y,
Ben Wagner219f3622017-07-17 15:32:25 -0400233 SkColor boundsColor)
234 {
235 SkPaint glyphPaint(paint);
236 SkRect fontBounds = glyphPaint.getFontBounds();
237 fontBounds.offset(x, y);
238 SkPaint boundsPaint(glyphPaint);
239 boundsPaint.setColor(boundsColor);
240 canvas->drawRect(fontBounds, boundsPaint);
reeda0c814c2014-10-22 13:20:58 -0700241
Ben Wagner219f3622017-07-17 15:32:25 -0400242 SkPaint::FontMetrics fm;
243 glyphPaint.getFontMetrics(&fm);
244 SkPaint metricsPaint(boundsPaint);
245 metricsPaint.setStyle(SkPaint::kFill_Style);
246 metricsPaint.setAlpha(0x40);
247 if ((fm.fFlags & SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag) &&
248 (fm.fFlags & SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag))
249 {
250 SkRect underline{ fontBounds.fLeft, fm.fUnderlinePosition+y,
251 fontBounds.fRight, fm.fUnderlinePosition+y + fm.fUnderlineThickness };
252 canvas->drawRect(underline, metricsPaint);
reeda0c814c2014-10-22 13:20:58 -0700253 }
tfarinaaa458fb2015-01-05 17:18:51 -0800254
Ben Wagner219f3622017-07-17 15:32:25 -0400255 if ((fm.fFlags & SkPaint::FontMetrics::kStrikeoutPositionIsValid_Flag) &&
256 (fm.fFlags & SkPaint::FontMetrics::kStrikeoutPositionIsValid_Flag))
257 {
258 SkRect strikeout{ fontBounds.fLeft, fm.fStrikeoutPosition+y - fm.fStrikeoutThickness,
259 fontBounds.fRight, fm.fStrikeoutPosition+y };
260 canvas->drawRect(strikeout, metricsPaint);
261 }
262
263 SkGlyphID left = 0, right = 0, top = 0, bottom = 0;
264 {
265 int numGlyphs = glyphPaint.getTypeface()->countGlyphs();
266 SkRect min = {0, 0, 0, 0};
267 glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
268 for (int i = 0; i < numGlyphs; ++i) {
269 SkGlyphID glyphId = i;
270 SkRect cur;
271 glyphPaint.measureText(&glyphId, sizeof(glyphId), &cur);
272 if (cur.fLeft < min.fLeft ) { min.fLeft = cur.fLeft; left = i; }
273 if (cur.fTop < min.fTop ) { min.fTop = cur.fTop ; top = i; }
274 if (min.fRight < cur.fRight ) { min.fRight = cur.fRight; right = i; }
275 if (min.fBottom < cur.fBottom) { min.fBottom = cur.fBottom; bottom = i; }
276 }
277 }
278 SkGlyphID str[] = { left, right, top, bottom };
279 for (size_t i = 0; i < SK_ARRAY_COUNT(str); ++i) {
280 canvas->drawText(&str[i], sizeof(str[0]), x, y, glyphPaint);
281 }
reeda0c814c2014-10-22 13:20:58 -0700282 }
283
284protected:
mtklein36352bf2015-03-25 18:17:31 -0700285 SkString onShortName() override {
reeda0c814c2014-10-22 13:20:58 -0700286 return fName;
287 }
tfarinaaa458fb2015-01-05 17:18:51 -0800288
mtklein36352bf2015-03-25 18:17:31 -0700289 SkISize onISize() override {
reeda0c814c2014-10-22 13:20:58 -0700290 return SkISize::Make(1024, 850);
291 }
tfarinaaa458fb2015-01-05 17:18:51 -0800292
mtklein36352bf2015-03-25 18:17:31 -0700293 void onDraw(SkCanvas* canvas) override {
reeda0c814c2014-10-22 13:20:58 -0700294 SkPaint paint;
295 paint.setAntiAlias(true);
296 paint.setSubpixelText(true);
297 paint.setTextSize(100);
298 paint.setStyle(SkPaint::kStroke_Style);
reed8893e5f2014-12-15 13:27:26 -0800299 paint.setTextScaleX(fScaleX);
300 paint.setTextSkewX(fSkewX);
reeda0c814c2014-10-22 13:20:58 -0700301
302 const SkColor boundsColors[2] = { SK_ColorRED, SK_ColorBLUE };
halcanary9d524f22016-03-29 09:03:52 -0700303
Hal Canarycefc4312016-11-04 16:26:16 -0400304 SkFontMgr* fm = fFM.get();
reeda0c814c2014-10-22 13:20:58 -0700305 int count = SkMin32(fm->countFamilies(), 32);
306
307 int index = 0;
308 SkScalar x = 0, y = 0;
309
Ben Wagner219f3622017-07-17 15:32:25 -0400310 canvas->translate(10, 120);
reeda0c814c2014-10-22 13:20:58 -0700311
312 for (int i = 0; i < count; ++i) {
Hal Canarycefc4312016-11-04 16:26:16 -0400313 sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
Ben Wagner219f3622017-07-17 15:32:25 -0400314 for (int j = 0; j < set->count() && j < 3; ++j) {
bungeman13b9c952016-05-12 10:09:30 -0700315 paint.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
Ben Wagner2112df02017-07-24 11:04:21 -0400316 // Fonts with lots of glyphs are interesting, but can take a long time to find
317 // the glyphs which make up the maximum extent.
318 if (paint.getTypeface() && paint.getTypeface()->countGlyphs() < 1000) {
Ben Wagner219f3622017-07-17 15:32:25 -0400319 SkRect fontBounds = paint.getFontBounds();
320 x -= fontBounds.fLeft;
reeda0c814c2014-10-22 13:20:58 -0700321 show_bounds(canvas, paint, x, y, boundsColors[index & 1]);
Ben Wagner219f3622017-07-17 15:32:25 -0400322 x += fontBounds.fRight + 20;
reeda0c814c2014-10-22 13:20:58 -0700323 index += 1;
Ben Wagner219f3622017-07-17 15:32:25 -0400324 if (x > 900) {
reeda0c814c2014-10-22 13:20:58 -0700325 x = 0;
326 y += 160;
327 }
Ben Wagner219f3622017-07-17 15:32:25 -0400328 if (y >= 700) {
reeda0c814c2014-10-22 13:20:58 -0700329 return;
330 }
331 }
332 }
333 }
334 }
mtklein1c402922015-01-23 11:07:07 -0800335
reeda0c814c2014-10-22 13:20:58 -0700336private:
Hal Canarycefc4312016-11-04 16:26:16 -0400337 sk_sp<SkFontMgr> fFM;
reeda0c814c2014-10-22 13:20:58 -0700338 SkString fName;
reed8893e5f2014-12-15 13:27:26 -0800339 SkScalar fScaleX, fSkewX;
reeda0c814c2014-10-22 13:20:58 -0700340 typedef GM INHERITED;
341};
342
reed@google.comaf0fa6a2013-03-28 13:39:35 +0000343//////////////////////////////////////////////////////////////////////////////
344
halcanary385fe4d2015-08-26 13:07:48 -0700345DEF_GM(return new FontMgrGM;)
346DEF_GM(return new FontMgrMatchGM;)
347DEF_GM(return new FontMgrBoundsGM(1.0, 0);)
348DEF_GM(return new FontMgrBoundsGM(0.75, 0);)
349DEF_GM(return new FontMgrBoundsGM(1.0, -0.25);)
bungeman@google.combfc6cc42013-08-21 15:20:43 +0000350
351#ifdef SK_BUILD_FOR_WIN
halcanary385fe4d2015-08-26 13:07:48 -0700352DEF_GM(return new FontMgrGM(SkFontMgr_New_DirectWrite());)
bungeman@google.combfc6cc42013-08-21 15:20:43 +0000353#endif