Flutter Engine
The Flutter Engine
fontmgr.cpp
Go to the documentation of this file.
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/gm.h"
11#include "include/core/SkFont.h"
18#include "include/core/SkPath.h"
21#include "include/core/SkRect.h"
24#include "include/core/SkSize.h"
29#include "src/core/SkFontPriv.h"
30#include "tools/SkMetaData.h"
31#include "tools/ToolUtils.h"
33
34#include <utility>
35
36// limit this just so we don't take too long to draw
37#define MAX_FAMILIES 30
38
40 SkScalar y, const SkFont& font) {
41 canvas->drawString(text, x, y, font, SkPaint());
42 return x + font.measureText(text.c_str(), text.size(), SkTextEncoding::kUTF8);
43}
44
46 SkScalar y, const SkFont& origFont, SkFontMgr* fm,
47 const char* fontName, const char* bcp47[], int bcp47Count,
48 const SkFontStyle& fontStyle) {
49 SkFont font = origFont;
50 // find typeface containing the requested character and draw it
51 SkString ch;
53 sk_sp<SkTypeface> typeface(fm->matchFamilyStyleCharacter(fontName, fontStyle,
54 bcp47, bcp47Count, character));
55 font.setTypeface(typeface);
56 x = drawString(canvas, ch, x, y, font) + 20;
57
58 if (nullptr == typeface) {
59 return x;
60 }
61
62 // repeat the process, but this time use the family name of the typeface
63 // from the first pass. This emulates the behavior in Blink where it
64 // it expects to get the same glyph when following this pattern.
65 SkString familyName;
66 typeface->getFamilyName(&familyName);
67 font.setTypeface(fm->legacyMakeTypeface(familyName.c_str(), typeface->fontStyle()));
68 return drawString(canvas, ch, x, y, font) + 20;
69}
70
71static const char* zh = "zh";
72static const char* ja = "ja";
73
74class FontMgrGM : public skiagm::GM {
76
77 void onOnceBeforeDraw() override {
78 SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
80 }
81
82 SkString getName() const override { return SkString("fontmgr_iter"); }
83
84 SkISize getISize() override { return {1536, 768}; }
85
86 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
87 SkScalar y = 20;
90 font.setSubpixel(true);
91 font.setSize(17);
92
93 SkFontMgr* fm = fFM.get();
95 if (count == 0) {
96 *errorMsg = "No families in SkFontMgr";
97 return DrawResult::kSkip;
98 }
99
100 for (int i = 0; i < count; ++i) {
101 SkString familyName;
102 fm->getFamilyName(i, &familyName);
103 font.setTypeface(ToolUtils::DefaultTypeface());
104 (void)drawString(canvas, familyName, 20, y, font);
105
106 SkScalar x = 220;
107
109 for (int j = 0; j < set->count(); ++j) {
110 SkString sname;
111 SkFontStyle fs;
112 set->getStyle(j, &fs, &sname);
113 sname.appendf(" [%d %d %d]", fs.weight(), fs.width(), fs.slant());
114
115 font.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
116 x = drawString(canvas, sname, x, y, font) + 20;
117
118 // check to see that we get different glyphs in japanese and chinese
119 x = drawCharacter(canvas, 0x5203, x, y, font, fm, familyName.c_str(), &zh, 1, fs);
120 x = drawCharacter(canvas, 0x5203, x, y, font, fm, familyName.c_str(), &ja, 1, fs);
121 // check that emoji characters are found
122 x = drawCharacter(canvas, 0x1f601, x, y, font, fm, familyName.c_str(), nullptr,0, fs);
123 }
124 y += 24;
125 }
126 return DrawResult::kOk;
127 }
128};
129
132
133 void onOnceBeforeDraw() override {
135 SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
136 }
137
138 SkString getName() const override { return SkString("fontmgr_match"); }
139
140 SkISize getISize() override { return {640, 1024}; }
141
142 void iterateFamily(SkCanvas* canvas, const SkFont& font, SkFontStyleSet* fset) {
143 SkFont f(font);
144 SkScalar y = 0;
145
146 for (int j = 0; j < fset->count(); ++j) {
147 SkString sname;
148 SkFontStyle fs;
149 fset->getStyle(j, &fs, &sname);
150
151 sname.appendf(" [%d %d]", fs.weight(), fs.width());
152
153 f.setTypeface(sk_sp<SkTypeface>(fset->createTypeface(j)));
154 (void)drawString(canvas, sname, 0, y, f);
155 y += 24;
156 }
157 }
158
159 void exploreFamily(SkCanvas* canvas, const SkFont& font, SkFontStyleSet* fset) {
160 SkFont f(font);
161 SkScalar y = 0;
162
163 for (int weight = 100; weight <= 900; weight += 200) {
164 for (int width = 1; width <= 9; width += 2) {
166 sk_sp<SkTypeface> face(fset->matchStyle(fs));
167 if (face) {
168 SkString str;
169 str.printf("request [%d %d]", fs.weight(), fs.width());
170 f.setTypeface(std::move(face));
171 (void)drawString(canvas, str, 0, y, f);
172 y += 24;
173 }
174 }
175 }
176 }
177
178 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
181 font.setSubpixel(true);
182 font.setSize(17);
183
184 const char* gNames[] = {
185 "Helvetica Neue", "Arial", "sans"
186 };
187
189 for (size_t i = 0; i < std::size(gNames); ++i) {
190 fset = fFM->matchFamily(gNames[i]);
191 if (fset->count() > 0) {
192 break;
193 }
194 }
195 if (!fset || fset->count() == 0) {
196 *errorMsg = "No SkFontStyleSet";
197 return DrawResult::kSkip;
198 }
199
200 canvas->translate(20, 40);
201 this->exploreFamily(canvas, font, fset.get());
202 canvas->translate(150, 0);
203 this->iterateFamily(canvas, font, fset.get());
204 return DrawResult::kOk;
205 }
206};
207
209public:
210 FontMgrBoundsGM(float scale, float skew) : fScaleX(scale) , fSkewX(skew) {}
211
212private:
213 SkString getName() const override {
214 if (fScaleX != 1 || fSkewX != 0) {
215 return SkStringPrintf("fontmgr_bounds_%g_%g", fScaleX, fSkewX);
216 }
217 return SkString("fontmgr_bounds");
218 }
219
220 void onOnceBeforeDraw() override { fFM = ToolUtils::TestFontMgr(); }
221
222 bool onGetControls(SkMetaData* controls) override {
223 controls->setBool("Label Bounds", fLabelBounds);
224 return true;
225 }
226
227 void onSetControls(const SkMetaData& controls) override {
228 controls.findBool("Label Bounds", &fLabelBounds);
229 }
230
231 static SkRect show_bounds(SkCanvas* canvas, const SkFont& font, SkScalar x, SkScalar y,
232 SkColor boundsColor, bool labelBounds)
233 {
234 SkGlyphID left = 0, right = 0, top = 0, bottom = 0;
237 {
238 int numGlyphs = font.getTypeface()->countGlyphs();
239 for (int i = 0; i < numGlyphs; ++i) {
240 SkGlyphID glyphId = i;
241 SkRect cur;
242 font.getBounds(&glyphId, 1, &cur, nullptr);
243 if (cur.fLeft < min.fLeft ) { min.fLeft = cur.fLeft; left = i; }
244 if (cur.fTop < min.fTop ) { min.fTop = cur.fTop ; top = i; }
245 if (min.fRight < cur.fRight ) { min.fRight = cur.fRight; right = i; }
246 if (min.fBottom < cur.fBottom) { min.fBottom = cur.fBottom; bottom = i; }
247 }
248 }
249
251
252 SkRect drawBounds = min;
253 drawBounds.join(fontBounds);
254
255 SkAutoCanvasRestore acr(canvas, true);
256 canvas->translate(x - drawBounds.left(), y);
257
258 SkPaint boundsPaint;
259 boundsPaint.setAntiAlias(true);
260 boundsPaint.setColor(boundsColor);
261 boundsPaint.setStyle(SkPaint::kStroke_Style);
262 canvas->drawRect(fontBounds, boundsPaint);
263
264 const SkScalar intervals[] = { 10.f, 10.f };
265 boundsPaint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0.f));
266 canvas->drawRect(min, boundsPaint);
267
268 SkFontMetrics fm;
269 font.getMetrics(&fm);
270 SkPaint metricsPaint(boundsPaint);
271 metricsPaint.setStyle(SkPaint::kFill_Style);
272 metricsPaint.setAlphaf(0.25f);
275 {
276 SkRect underline{ min.fLeft, fm.fUnderlinePosition,
278 canvas->drawRect(underline, metricsPaint);
279 }
280
283 {
284 SkRect strikeout{ min.fLeft, fm.fStrikeoutPosition - fm.fStrikeoutThickness,
285 min.fRight, fm.fStrikeoutPosition };
286 canvas->drawRect(strikeout, metricsPaint);
287 }
288
289 struct GlyphToDraw {
291 SkPoint location;
292 SkScalar rotation;
293 } glyphsToDraw [] = {
294 {left, {min.left(), min.centerY()}, 270},
295 {right, {min.right(), min.centerY()}, 90},
296 {top, {min.centerX(), min.top() }, 0},
297 {bottom, {min.centerX(), min.bottom() }, 180},
298 };
299
300 SkFont labelFont;
303
304 if (labelBounds) {
306 font.getTypeface()->getFamilyName(&name);
307 canvas->drawString(name, min.fLeft, min.fBottom, labelFont, SkPaint());
308 }
309 for (const GlyphToDraw& glyphToDraw : glyphsToDraw) {
310 SkPath path;
311 font.getPath(glyphToDraw.id, &path);
313 SkPaint glyphPaint;
314 glyphPaint.setStyle(style);
315 canvas->drawSimpleText(&glyphToDraw.id, sizeof(glyphToDraw.id),
316 SkTextEncoding::kGlyphID, 0, 0, font, glyphPaint);
317
318 if (labelBounds) {
319 SkAutoCanvasRestore acr2(canvas, true);
320 canvas->translate(glyphToDraw.location.fX, glyphToDraw.location.fY);
321 canvas->rotate(glyphToDraw.rotation);
322 SkString glyphStr;
323 glyphStr.appendS32(glyphToDraw.id);
324 canvas->drawString(glyphStr, 0, 0, labelFont, SkPaint());
325 }
326 }
327
328 return drawBounds;
329 }
330
331 SkISize getISize() override { return {1024, 850}; }
332
333 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
336 font.setSubpixel(true);
337 font.setSize(100);
338 font.setScaleX(fScaleX);
339 font.setSkewX(fSkewX);
340
341 const SkColor boundsColors[2] = { SK_ColorRED, SK_ColorBLUE };
342
343 SkFontMgr* fm = fFM.get();
344 int count = std::min(fm->countFamilies(), 32);
345 if (count == 0) {
346 *errorMsg = "No families in SkFontMgr under test.";
347 return DrawResult::kSkip;
348 }
349
350 int index = 0;
351 SkScalar x = 0, y = 0;
352
353 canvas->translate(10, 120);
354
355 for (int i = 0; i < count; ++i) {
357 for (int j = 0; j < set->count() && j < 3; ++j) {
358 font.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
359 // Fonts with lots of glyphs are interesting, but can take a long time to find
360 // the glyphs which make up the maximum extent.
361 SkTypeface* typeface = font.getTypeface();
362 if (typeface && 0 < typeface->countGlyphs() && typeface->countGlyphs() < 1000) {
363 SkColor color = boundsColors[index & 1];
364 SkRect drawBounds = show_bounds(canvas, font, x, y, color, fLabelBounds);
365 x += drawBounds.width() + 20;
366 index += 1;
367 if (x > 900) {
368 x = 0;
369 y += 160;
370 }
371 if (y >= 700) {
372 return DrawResult::kOk;
373 }
374 }
375 }
376 }
377 return DrawResult::kOk;
378 }
379
381 const SkScalar fScaleX;
382 const SkScalar fSkewX;
383 bool fLabelBounds = false;
384};
385
386//////////////////////////////////////////////////////////////////////////////
387
388DEF_GM(return new FontMgrGM;)
389DEF_GM(return new FontMgrMatchGM;)
390DEF_GM(return new FontMgrBoundsGM(1, 0);)
391DEF_GM(return new FontMgrBoundsGM(0.75f, 0);)
392DEF_GM(return new FontMgrBoundsGM(1, -0.25f);)
int count
Definition: FontMgrTest.cpp:50
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
@ kUTF8
uses bytes to represent UTF-8 or ASCII
@ kGlyphID
uses two byte words to represent glyph indices
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
#define SK_ScalarInfinity
Definition: SkScalar.h:26
#define SK_ScalarNegativeInfinity
Definition: SkScalar.h:27
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
uint16_t SkGlyphID
Definition: SkTypes.h:179
FontMgrBoundsGM(float scale, float skew)
Definition: fontmgr.cpp:210
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawSimpleText(const void *text, size_t byteLength, SkTextEncoding encoding, SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
Definition: SkCanvas.cpp:2413
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
void rotate(SkScalar degrees)
Definition: SkCanvas.cpp:1300
void drawString(const char str[], SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
Definition: SkCanvas.h:1803
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
sk_sp< SkFontStyleSet > createStyleSet(int index) const
Definition: SkFontMgr.cpp:101
sk_sp< SkTypeface > matchFamilyStyleCharacter(const char familyName[], const SkFontStyle &, const char *bcp47[], int bcp47Count, SkUnichar character) const
Definition: SkFontMgr.cpp:114
void getFamilyName(int index, SkString *familyName) const
Definition: SkFontMgr.cpp:97
sk_sp< SkFontStyleSet > matchFamily(const char familyName[]) const
Definition: SkFontMgr.cpp:105
int countFamilies() const
Definition: SkFontMgr.cpp:93
sk_sp< SkTypeface > legacyMakeTypeface(const char familyName[], SkFontStyle style) const
Definition: SkFontMgr.cpp:150
static SkRect GetFontBounds(const SkFont &)
Definition: SkFont.cpp:354
virtual sk_sp< SkTypeface > createTypeface(int index)=0
virtual sk_sp< SkTypeface > matchStyle(const SkFontStyle &pattern)=0
virtual int count()=0
virtual void getStyle(int index, SkFontStyle *, SkString *style)=0
Slant slant() const
Definition: SkFontStyle.h:64
int width() const
Definition: SkFontStyle.h:63
int weight() const
Definition: SkFontStyle.h:62
Definition: SkFont.h:35
void setTypeface(sk_sp< SkTypeface > tf)
Definition: SkFont.cpp:90
void setEdging(Edging edging)
Definition: SkFont.cpp:121
@ kAntiAlias
may have transparent pixels on glyph edges
@ kSubpixelAntiAlias
glyph positioned in pixel using transparency
static size_t SetFontCacheLimit(size_t bytes)
Definition: SkGraphics.cpp:52
void setBool(const char name[], bool value)
Definition: SkMetaData.cpp:46
bool findBool(const char name[], bool *value=nullptr) const
Definition: SkMetaData.cpp:149
void setStyle(Style style)
Definition: SkPaint.cpp:105
void setColor(SkColor color)
Definition: SkPaint.cpp:119
void setAntiAlias(bool aa)
Definition: SkPaint.h:170
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
@ kFill_Style
set to fill geometry
Definition: SkPaint.h:193
void setPathEffect(sk_sp< SkPathEffect > pathEffect)
Definition: SkPath.h:59
void appendUnichar(SkUnichar uni)
Definition: SkString.h:207
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:534
void appendS32(int32_t value)
Definition: SkString.h:208
const char * c_str() const
Definition: SkString.h:133
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:550
int countGlyphs() const
Definition: SkTypeface.cpp:432
void getFamilyName(SkString *name) const
Definition: SkTypeface.cpp:459
SkFontStyle fontStyle() const
Definition: SkTypeface.h:55
T * get() const
Definition: SkRefCnt.h:303
Definition: gm.h:110
SkScalar width()
Definition: gm.h:159
skiagm::DrawResult DrawResult
Definition: gm.h:112
DlColor color
float SkScalar
Definition: extension.cpp:12
static SkScalar drawString(SkCanvas *canvas, const SkString &text, SkScalar x, SkScalar y, const SkFont &font)
Definition: fontmgr.cpp:39
static SkScalar 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)
Definition: fontmgr.cpp:45
#define MAX_FAMILIES
Definition: fontmgr.cpp:37
static const char * ja
Definition: fontmgr.cpp:72
static const char * zh
Definition: fontmgr.cpp:71
#define DEF_GM(CODE)
Definition: gm.h:40
static float min(float r, float g, float b)
Definition: hsl.cpp:48
std::u16string text
double y
double x
sk_sp< SkTypeface > DefaultPortableTypeface()
SkFont DefaultFont()
sk_sp< SkTypeface > DefaultTypeface()
sk_sp< SkFontMgr > TestFontMgr()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
font
Font Metadata and Metrics.
DrawResult
Definition: gm.h:104
const Scalar scale
SkScalar fStrikeoutPosition
distance from baseline to bottom of stroke, typically negative
Definition: SkFontMetrics.h:67
SkScalar fStrikeoutThickness
strikeout thickness
Definition: SkFontMetrics.h:66
uint32_t fFlags
FontMetricsFlags indicating which metrics are valid.
Definition: SkFontMetrics.h:52
SkScalar fUnderlineThickness
underline thickness
Definition: SkFontMetrics.h:64
@ kStrikeoutPositionIsValid_Flag
set if fStrikeoutPosition is valid
Definition: SkFontMetrics.h:48
@ kStrikeoutThicknessIsValid_Flag
set if fStrikeoutThickness is valid
Definition: SkFontMetrics.h:47
@ kUnderlinePositionIsValid_Flag
set if fUnderlinePosition is valid
Definition: SkFontMetrics.h:46
@ kUnderlineThicknessIsValid_Flag
set if fUnderlineThickness is valid
Definition: SkFontMetrics.h:45
SkScalar fUnderlinePosition
distance from baseline to top of stroke, typically positive
Definition: SkFontMetrics.h:65
Definition: SkSize.h:16
SkScalar fBottom
larger y-axis bounds
Definition: extension.cpp:17
constexpr float left() const
Definition: SkRect.h:734
SkScalar fLeft
smaller x-axis bounds
Definition: extension.cpp:14
SkScalar fRight
larger x-axis bounds
Definition: extension.cpp:16
constexpr float width() const
Definition: SkRect.h:762
void join(const SkRect &r)
Definition: SkRect.cpp:126
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15
const uintptr_t id