Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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();
94 int count = std::min(fm->countFamilies(), MAX_FAMILIES);
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
250 SkRect fontBounds = SkFontPriv::GetFontBounds(font);
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 {
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 {
335 font.setEdging(SkFont::Edging::kAntiAlias);
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
SkColor4f color
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 static SkString SkStringPrintf()
Definition SkString.h:287
uint16_t SkGlyphID
Definition SkTypes.h:179
SkISize getISize() override
Definition fontmgr.cpp:331
bool onGetControls(SkMetaData *controls) override
Definition fontmgr.cpp:222
SkString getName() const override
Definition fontmgr.cpp:213
FontMgrBoundsGM(float scale, float skew)
Definition fontmgr.cpp:210
void onOnceBeforeDraw() override
Definition fontmgr.cpp:220
void onSetControls(const SkMetaData &controls) override
Definition fontmgr.cpp:227
DrawResult onDraw(SkCanvas *canvas, SkString *errorMsg) override
Definition fontmgr.cpp:333
void onOnceBeforeDraw() override
Definition fontmgr.cpp:77
SkString getName() const override
Definition fontmgr.cpp:82
SkISize getISize() override
Definition fontmgr.cpp:84
DrawResult onDraw(SkCanvas *canvas, SkString *errorMsg) override
Definition fontmgr.cpp:86
SkString getName() const override
Definition fontmgr.cpp:138
void onOnceBeforeDraw() override
Definition fontmgr.cpp:133
DrawResult onDraw(SkCanvas *canvas, SkString *errorMsg) override
Definition fontmgr.cpp:178
SkISize getISize() override
Definition fontmgr.cpp:140
void drawRect(const SkRect &rect, const SkPaint &paint)
void drawSimpleText(const void *text, size_t byteLength, SkTextEncoding encoding, SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
void translate(SkScalar dx, SkScalar dy)
void rotate(SkScalar degrees)
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
sk_sp< SkTypeface > matchFamilyStyleCharacter(const char familyName[], const SkFontStyle &, const char *bcp47[], int bcp47Count, SkUnichar character) const
void getFamilyName(int index, SkString *familyName) const
Definition SkFontMgr.cpp:97
int countFamilies() const
Definition SkFontMgr.cpp:93
sk_sp< SkTypeface > legacyMakeTypeface(const char familyName[], SkFontStyle style) const
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
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)
void setBool(const char name[], bool value)
bool findBool(const char name[], bool *value=nullptr) const
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)
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
T * get() const
Definition SkRefCnt.h:303
SkScalar width()
Definition gm.h:159
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
const char * name
Definition fuchsia.cc:50
#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
font
Font Metadata and Metrics.
DrawResult
Definition gm.h:104
const Scalar scale
SkScalar fStrikeoutPosition
distance from baseline to bottom of stroke, typically negative
SkScalar fStrikeoutThickness
strikeout thickness
uint32_t fFlags
FontMetricsFlags indicating which metrics are valid.
SkScalar fUnderlineThickness
underline thickness
@ kStrikeoutPositionIsValid_Flag
set if fStrikeoutPosition is valid
@ kStrikeoutThicknessIsValid_Flag
set if fStrikeoutThickness is valid
@ kUnderlinePositionIsValid_Flag
set if fUnderlinePosition is valid
@ kUnderlineThicknessIsValid_Flag
set if fUnderlineThickness is valid
SkScalar fUnderlinePosition
distance from baseline to top of stroke, typically positive
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