Flutter Engine
The Flutter Engine
create_test_font.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2014 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// Running create_test_font generates ./tools/fonts/test_font_index.inc
9// and ./tools/fonts/test_font_<generic name>.inc which are read by
10// ./tools/fonts/TestFontMgr.cpp
11
12#include "include/core/SkFont.h"
16#include "include/core/SkPath.h"
17#include "include/core/SkSpan.h"
22#include "src/base/SkUTF.h"
23#include "src/core/SkOSFile.h"
24#include "src/core/SkPathPriv.h"
25#include "src/utils/SkOSPath.h"
26
27#include <stdio.h>
28
29#if defined(SK_FONTMGR_CORETEXT_AVAILABLE)
31#endif
32
33#if defined(SK_FONTMGR_FONTCONFIG_AVAILABLE)
35#endif
36
37#if defined(SK_FONTMGR_FREETYPE_EMPTY_AVAILABLE)
39#endif
40
41namespace {
42
43struct NamedFontStyle {
44 char const * const fName;
45 char const * const fIdentifierName;
46 SkFontStyle const fStyle;
47};
48
49struct FontDesc {
50 NamedFontStyle const fNamedStyle;
51 char const * const fFile;
52};
53
54struct FontFamilyDesc {
55 char const * const fGenericName;
56 char const * const fFamilyName;
57 char const * const fIdentifierName;
58 SkSpan<const FontDesc> const fFonts;
59};
60
61} // namespace
62
63static FILE* font_header(const char* family) {
64 SkString outPath(SkOSPath::Join(".", "tools"));
65 outPath = SkOSPath::Join(outPath.c_str(), "fonts");
66 outPath = SkOSPath::Join(outPath.c_str(), "test_font_");
67 SkString fam(family);
68 do {
69 int dashIndex = fam.find("-");
70 if (dashIndex < 0) {
71 break;
72 }
73 fam.data()[dashIndex] = '_';
74 } while (true);
75 outPath.append(fam);
76 outPath.append(".inc");
77 FILE* out = fopen(outPath.c_str(), "w");
78
79 static const char kHeader[] =
80 "/*\n"
81 " * Copyright 2015 Google Inc.\n"
82 " *\n"
83 " * Use of this source code is governed by a BSD-style license that can be\n"
84 " * found in the LICENSE file.\n"
85 " */\n"
86 "\n"
87 "// Auto-generated by ";
88 fprintf(out, "%s%s\n\n", kHeader, SkOSPath::Basename(__FILE__).c_str());
89 return out;
90}
91
92enum {
94};
95
96static ptrdiff_t last_line_length(const SkString& str) {
97 const char* first = str.c_str();
98 const char* last = first + str.size();
99 const char* ptr = last;
100 while (ptr > first && *--ptr != '\n')
101 ;
102 return last - ptr - 1;
103}
104
105static void output_fixed(SkScalar num, int emSize, SkString* out) {
106 uint32_t hex = (uint32_t)(num * 65536 / emSize);
107 out->appendf("0x%08x,", hex);
108 *out += (int) last_line_length(*out) >= kMaxLineLength ? '\n' : ' ';
109}
110
111static void output_scalar(SkScalar num, int emSize, SkString* out) {
112 num /= emSize;
113 if (num == (int) num) {
114 out->appendS32((int) num);
115 } else {
116 SkString str;
117 str.printf("%1.6g", num);
118 int width = (int) str.size();
119 const char* cStr = str.c_str();
120 while (cStr[width - 1] == '0') {
121 --width;
122 }
123 str.remove(width, str.size() - width);
124 out->appendf("%sf", str.c_str());
125 }
126 *out += ',';
127 *out += (int) last_line_length(*out) >= kMaxLineLength ? '\n' : ' ';
128}
129
130static int output_points(const SkPoint* pts, int emSize, int count, SkString* ptsOut) {
131 for (int index = 0; index < count; ++index) {
132 output_scalar(pts[index].fX, emSize, ptsOut);
133 output_scalar(pts[index].fY, emSize, ptsOut);
134 }
135 return count;
136}
137
138static void output_path_data(const SkFont& font,
139 int emSize, SkString* ptsOut, SkTDArray<SkPath::Verb>* verbs,
141 for (SkUnichar index = 0x00; index < 0x7f; ++index) {
142 uint16_t glyphID = font.unicharToGlyph(index);
143 SkPath path;
144 font.getPath(glyphID, &path);
145 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
146 *verbs->append() = (SkPath::Verb)verb;
147 switch (verb) {
149 output_points(&pts[0], emSize, 1, ptsOut);
150 break;
152 output_points(&pts[1], emSize, 1, ptsOut);
153 break;
155 output_points(&pts[1], emSize, 2, ptsOut);
156 break;
158 output_points(&pts[1], emSize, 3, ptsOut);
159 break;
161 break;
162 default:
163 SkDEBUGFAIL("bad verb");
164 SkASSERT(0);
165 }
166 }
167 *verbs->append() = SkPath::kDone_Verb;
168 *charCodes->append() = index;
170 font.getWidths(&glyphID, 1, &width);
171 // SkASSERT(floor(width) == width); // not true for Hiragino Maru Gothic Pro
172 *widths->append() = width;
173 if (0 == index) {
174 index = 0x1f; // skip the rest of the control codes
175 }
176 }
177}
178
179static int offset_str_len(unsigned num) {
180 if (num == (unsigned) -1) {
181 return 10;
182 }
183 unsigned result = 1;
184 unsigned ref = 10;
185 while (ref <= num) {
186 ++result;
187 ref *= 10;
188 }
189 return result;
190}
191
192static SkString strip_final(const SkString& str) {
193 SkString result(str);
194 if (result.endsWith("\n")) {
195 result.remove(result.size() - 1, 1);
196 }
197 if (result.endsWith(" ")) {
198 result.remove(result.size() - 1, 1);
199 }
200 if (result.endsWith(",")) {
201 result.remove(result.size() - 1, 1);
202 }
203 return result;
204}
205
206static void output_font(sk_sp<SkTypeface> face, const char* identifier, FILE* out) {
207 const int emSize = face->getUnitsPerEm() * 2;
208 SkFont font;
210 font.setSize(emSize);
211 font.setTypeface(std::move(face));
212
214 SkTDArray<unsigned> charCodes;
216 SkString ptsOut;
217 output_path_data(font, emSize, &ptsOut, &verbs, &charCodes, &widths);
218 fprintf(out, "const SkScalar %sPoints[] = {\n", identifier);
219 ptsOut = strip_final(ptsOut);
220 fprintf(out, "%s", ptsOut.c_str());
221 fprintf(out, "\n};\n\n");
222 fprintf(out, "const unsigned char %sVerbs[] = {\n", identifier);
223 int verbCount = verbs.size();
224 int outChCount = 0;
225 for (int index = 0; index < verbCount;) {
226 SkPath::Verb verb = verbs[index];
228 SkASSERT(SkTFitsIn<uint8_t>(verb));
229 fprintf(out, "%u", verb);
230 if (++index < verbCount) {
231 outChCount += 3;
232 fprintf(out, "%c", ',');
233 if (outChCount >= kMaxLineLength) {
234 outChCount = 0;
235 fprintf(out, "%c", '\n');
236 } else {
237 fprintf(out, "%c", ' ');
238 }
239 }
240 }
241 fprintf(out, "\n};\n\n");
242
243 // all fonts are now 0x00, 0x20 - 0xFE
244 // don't need to generate or output character codes?
245 fprintf(out, "const SkUnichar %sCharCodes[] = {\n", identifier);
246 int offsetCount = charCodes.size();
247 for (int index = 0; index < offsetCount;) {
248 unsigned offset = charCodes[index];
249 fprintf(out, "%u", offset);
250 if (++index < offsetCount) {
251 outChCount += offset_str_len(offset) + 2;
252 fprintf(out, "%c", ',');
253 if (outChCount >= kMaxLineLength) {
254 outChCount = 0;
255 fprintf(out, "%c", '\n');
256 } else {
257 fprintf(out, "%c", ' ');
258 }
259 }
260 }
261 fprintf(out, "\n};\n\n");
262
263 SkString widthsStr;
264 fprintf(out, "const SkFixed %sWidths[] = {\n", identifier);
265 for (int index = 0; index < offsetCount; ++index) {
266 output_fixed(widths[index], emSize, &widthsStr);
267 }
268 widthsStr = strip_final(widthsStr);
269 fprintf(out, "%s\n};\n\n", widthsStr.c_str());
270
271 fprintf(out, "const size_t %sCharCodesCount = std::size(%sCharCodes);\n\n",
273
274 SkFontMetrics metrics;
275 font.getMetrics(&metrics);
276 fprintf(out, "const SkFontMetrics %sMetrics = {\n", identifier);
277 SkString metricsStr;
278 metricsStr.printf("0x%08x, ", metrics.fFlags);
279 output_scalar(metrics.fTop, emSize, &metricsStr);
280 output_scalar(metrics.fAscent, emSize, &metricsStr);
281 output_scalar(metrics.fDescent, emSize, &metricsStr);
282 output_scalar(metrics.fBottom, emSize, &metricsStr);
283 output_scalar(metrics.fLeading, emSize, &metricsStr);
284 output_scalar(metrics.fAvgCharWidth, emSize, &metricsStr);
285 output_scalar(metrics.fMaxCharWidth, emSize, &metricsStr);
286 output_scalar(metrics.fXMin, emSize, &metricsStr);
287 output_scalar(metrics.fXMax, emSize, &metricsStr);
288 output_scalar(metrics.fXHeight, emSize, &metricsStr);
289 output_scalar(metrics.fCapHeight, emSize, &metricsStr);
290 output_scalar(metrics.fUnderlineThickness, emSize, &metricsStr);
291 output_scalar(metrics.fUnderlinePosition, emSize, &metricsStr);
292 output_scalar(metrics.fStrikeoutThickness, emSize, &metricsStr);
293 output_scalar(metrics.fStrikeoutPosition, emSize, &metricsStr);
294 metricsStr = strip_final(metricsStr);
295 fprintf(out, "%s\n};\n\n", metricsStr.c_str());
296}
297
298static SkString identifier(const FontFamilyDesc& family, const FontDesc& font) {
299 SkString id(family.fIdentifierName);
300 id.append(font.fNamedStyle.fIdentifierName);
301 return id;
302}
303
304static void generate_fonts(const char* basepath,
305 const SkSpan<const FontFamilyDesc>& families,
307 SkASSERT_RELEASE(mgr);
308 FILE* out = nullptr;
309 for (const FontFamilyDesc& family : families) {
310 out = font_header(family.fGenericName);
311 for (const FontDesc& font : family.fFonts) {
312 SkString filepath(SkOSPath::Join(basepath, font.fFile));
313 SkASSERTF(sk_exists(filepath.c_str()), "The file %s does not exist.", filepath.c_str());
314 sk_sp<SkTypeface> resourceTypeface = mgr->makeFromFile(filepath.c_str(), 0);
315 SkASSERTF(resourceTypeface, "The file %s is not a font.", filepath.c_str());
316 output_font(std::move(resourceTypeface), identifier(family, font).c_str(), out);
317 }
318 fclose(out);
319 }
320}
321
322static const char* slant_to_string(SkFontStyle::Slant slant) {
323 switch (slant) {
324 case SkFontStyle::kUpright_Slant: return "SkFontStyle::kUpright_Slant";
325 case SkFontStyle::kItalic_Slant : return "SkFontStyle::kItalic_Slant" ;
326 case SkFontStyle::kOblique_Slant: return "SkFontStyle::kOblique_Slant";
327 default: SK_ABORT("Unknown slant");
328 }
329}
330
332 const FontDesc* defaultFont)
333{
334 FILE* out = font_header("index");
335 fprintf(out, "static SkTestFontData gTestFonts[] = {\n");
336 for (const FontFamilyDesc& family : families) {
337 for (const FontDesc& font : family.fFonts) {
338 SkString identifierStr = identifier(family, font);
339 const char* identifier = identifierStr.c_str();
340 const SkFontStyle& style = font.fNamedStyle.fStyle;
341 fprintf(out,
342 " { %sPoints, %sVerbs,\n"
343 " %sCharCodes, %sCharCodesCount, %sWidths,\n"
344 " %sMetrics, \"Toy %s\", SkFontStyle(%d,%d,%s)\n"
345 " },\n",
348 identifier, family.fFamilyName,
349 style.weight(), style.width(), slant_to_string(style.slant()));
350 }
351 }
352 fprintf(out, "};\n\n");
353 fprintf(out,
354 "struct SubFont {\n"
355 " const char* fFamilyName;\n"
356 " const char* fStyleName;\n"
357 " SkFontStyle fStyle;\n"
358 " SkTestFontData& fFont;\n"
359 " const char* fFile;\n"
360 "};\n\n"
361 "const SubFont gSubFonts[] = {\n");
362 int defaultIndex = -1;
363 int testFontsIndex = 0;
364 for (const FontFamilyDesc& family : families) {
365 for (const FontDesc& font : family.fFonts) {
366 if (&font == defaultFont) {
367 defaultIndex = testFontsIndex;
368 }
369 const SkFontStyle& style = font.fNamedStyle.fStyle;
370 fprintf(out,
371 " { \"%s\", \"%s\", SkFontStyle(%d,%d,%s), gTestFonts[%d], \"%s\" },\n",
372 family.fGenericName, font.fNamedStyle.fName,
373 style.weight(), style.width(), slant_to_string(style.slant()),
374 testFontsIndex, font.fFile);
375 testFontsIndex++;
376 }
377 }
378 testFontsIndex = 0;
379 for (const FontFamilyDesc& family : families) {
380 for (const FontDesc& font : family.fFonts) {
381 fprintf(out,
382 " { \"Toy %s\", \"%s\", SkFontStyle(%d,%d,%s), gTestFonts[%d], \"%s\" },\n",
383 family.fFamilyName, font.fNamedStyle.fName,
384 font.fNamedStyle.fStyle.weight(), font.fNamedStyle.fStyle.width(),
385 slant_to_string(font.fNamedStyle.fStyle.slant()), testFontsIndex, font.fFile);
386 testFontsIndex++;
387 }
388 }
389 fprintf(out, "};\n\n");
390 SkASSERT(defaultIndex >= 0);
391 fprintf(out, "const size_t gDefaultFontIndex = %d;\n", defaultIndex);
392 fclose(out);
393}
394
395int main(int , char * const []) {
396 constexpr NamedFontStyle normal = {"Normal", "Normal", SkFontStyle::Normal() };
397 constexpr NamedFontStyle bold = {"Bold", "Bold", SkFontStyle::Bold() };
398 constexpr NamedFontStyle italic = {"Italic", "Italic", SkFontStyle::Italic() };
399 constexpr NamedFontStyle bolditalic = {"Bold Italic", "BoldItalic", SkFontStyle::BoldItalic()};
400
401 static constexpr FontDesc kMonoFonts[] = {
402 {normal, "LiberationMono-Regular.ttf"},
403 {bold, "LiberationMono-Bold.ttf"},
404 {italic, "LiberationMono-Italic.ttf"},
405 {bolditalic, "LiberationMono-BoldItalic.ttf"},
406 };
407
408 static constexpr FontDesc kSansFonts[] = {
409 {normal, "LiberationSans-Regular.ttf"},
410 {bold, "LiberationSans-Bold.ttf"},
411 {italic, "LiberationSans-Italic.ttf"},
412 {bolditalic, "LiberationSans-BoldItalic.ttf"},
413 };
414
415 static constexpr FontDesc kSerifFonts[] = {
416 {normal, "LiberationSerif-Regular.ttf"},
417 {bold, "LiberationSerif-Bold.ttf"},
418 {italic, "LiberationSerif-Italic.ttf"},
419 {bolditalic, "LiberationSerif-BoldItalic.ttf"},
420 };
421
422 static constexpr FontFamilyDesc kFamiliesData[] = {
423 {"monospace", "Liberation Mono", "LiberationMono", kMonoFonts},
424 {"sans-serif", "Liberation Sans", "LiberationSans", kSansFonts},
425 {"serif", "Liberation Serif", "LiberationSerif", kSerifFonts},
426 };
427
428 static constexpr SkSpan<const FontFamilyDesc> kFamilies(kFamiliesData);
429
431#if defined(SK_FONTMGR_FONTCONFIG_AVAILABLE)
432 mgr = SkFontMgr_New_FontConfig(nullptr);
433#elif defined(SK_FONTMGR_CORETEXT_AVAILABLE)
434 mgr = SkFontMgr_New_CoreText(nullptr);
435#elif defined(SK_FONTMGR_FREETYPE_EMPTY_AVAILABLE)
437#else
438 SkDEBUGFAIL("Unsupported FontMgr");
439#endif
440
441#if defined(SK_BUILD_FOR_UNIX)
442#define SK_FONT_FOLDER "/usr/share/fonts/truetype/liberation/"
443#elif defined(SK_BUILD_FOR_MAC)
444#define SK_FONT_FOLDER "/Library/Fonts/"
445#else
446#error "Unsupported OS"
447#endif
448
449 generate_fonts(SK_FONT_FOLDER, kFamilies, mgr);
450 generate_index(kFamilies, &kFamilies[1].fFonts[0]);
451 return 0;
452}
SkStrokeRec::Style fStyle
const char * fName
int count
Definition: FontMgrTest.cpp:50
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SkASSERTF(cond, fmt,...)
Definition: SkAssert.h:117
SK_API sk_sp< SkFontMgr > SkFontMgr_New_Custom_Empty()
SK_API sk_sp< SkFontMgr > SkFontMgr_New_FontConfig(FcConfig *fc)
SK_API sk_sp< SkFontMgr > SkFontMgr_New_CoreText(CTFontCollectionRef)
bool sk_exists(const char *path, SkFILE_Flags=(SkFILE_Flags) 0)
@ kClose
SkPath::RawIter returns 0 points.
@ kCubic
SkPath::RawIter returns 4 points.
@ kQuad
SkPath::RawIter returns 3 points.
@ kMove
SkPath::RawIter returns 1 point.
@ kLine
SkPath::RawIter returns 2 points.
int32_t SkUnichar
Definition: SkTypes.h:175
const SkScalar widths[]
Definition: StrokerTest.cpp:39
sk_sp< SkTypeface > makeFromFile(const char path[], int ttcIndex=0) const
Definition: SkFontMgr.cpp:143
Slant slant() const
Definition: SkFontStyle.h:64
static constexpr SkFontStyle Italic()
Definition: SkFontStyle.h:72
int width() const
Definition: SkFontStyle.h:63
int weight() const
Definition: SkFontStyle.h:62
static constexpr SkFontStyle BoldItalic()
Definition: SkFontStyle.h:75
static constexpr SkFontStyle Bold()
Definition: SkFontStyle.h:69
static constexpr SkFontStyle Normal()
Definition: SkFontStyle.h:66
Definition: SkFont.h:35
@ kAntiAlias
may have transparent pixels on glyph edges
static SkString Join(const char *rootPath, const char *relativePath)
Definition: SkOSPath.cpp:14
static SkString Basename(const char *fullPath)
Definition: SkOSPath.cpp:23
Definition: SkPath.h:59
@ kMove_Verb
Definition: SkPath.h:1466
@ kDone_Verb
Definition: SkPath.h:1472
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:534
void void void void void void void remove(size_t offset, size_t length)
Definition: SkString.cpp:592
size_t size() const
Definition: SkString.h:131
const char * data() const
Definition: SkString.h:132
int find(const char substring[]) const
Definition: SkString.h:158
void append(const char text[])
Definition: SkString.h:203
const char * c_str() const
Definition: SkString.h:133
int size() const
Definition: SkTDArray.h:138
T * append()
Definition: SkTDArray.h:191
int getUnitsPerEm() const
Definition: SkTypeface.cpp:436
static SkString identifier(const FontFamilyDesc &family, const FontDesc &font)
static void generate_index(const SkSpan< const FontFamilyDesc > &families, const FontDesc *defaultFont)
static FILE * font_header(const char *family)
static const char * slant_to_string(SkFontStyle::Slant slant)
static void output_scalar(SkScalar num, int emSize, SkString *out)
@ kMaxLineLength
static int offset_str_len(unsigned num)
static void output_path_data(const SkFont &font, int emSize, SkString *ptsOut, SkTDArray< SkPath::Verb > *verbs, SkTDArray< unsigned > *charCodes, SkTDArray< SkScalar > *widths)
static int output_points(const SkPoint *pts, int emSize, int count, SkString *ptsOut)
static SkString strip_final(const SkString &str)
static ptrdiff_t last_line_length(const SkString &str)
static void output_font(sk_sp< SkTypeface > face, const char *identifier, FILE *out)
static void output_fixed(SkScalar num, int emSize, SkString *out)
int main(int, char *const [])
static void generate_fonts(const char *basepath, const SkSpan< const FontFamilyDesc > &families, sk_sp< const SkFontMgr > mgr)
float SkScalar
Definition: extension.cpp:12
GAsyncResult * result
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.
SkScalar w
int32_t width
SeparatedVector2 offset
SkScalar fTop
greatest extent above origin of any glyph bounding box, typically negative; deprecated with variable ...
Definition: SkFontMetrics.h:53
SkScalar fLeading
distance to add between lines, typically positive or zero
Definition: SkFontMetrics.h:57
SkScalar fAvgCharWidth
average character width, zero if unknown
Definition: SkFontMetrics.h:58
SkScalar fStrikeoutPosition
distance from baseline to bottom of stroke, typically negative
Definition: SkFontMetrics.h:67
SkScalar fStrikeoutThickness
strikeout thickness
Definition: SkFontMetrics.h:66
SkScalar fMaxCharWidth
maximum character width, zero if unknown
Definition: SkFontMetrics.h:59
SkScalar fBottom
greatest extent below origin of any glyph bounding box, typically positive; deprecated with variable ...
Definition: SkFontMetrics.h:56
uint32_t fFlags
FontMetricsFlags indicating which metrics are valid.
Definition: SkFontMetrics.h:52
SkScalar fAscent
distance to reserve above baseline, typically negative
Definition: SkFontMetrics.h:54
SkScalar fXHeight
height of lower-case 'x', zero if unknown, typically negative
Definition: SkFontMetrics.h:62
SkScalar fUnderlineThickness
underline thickness
Definition: SkFontMetrics.h:64
SkScalar fDescent
distance to reserve below baseline, typically positive
Definition: SkFontMetrics.h:55
SkScalar fCapHeight
height of an upper-case letter, zero if unknown, typically negative
Definition: SkFontMetrics.h:63
SkScalar fXMin
greatest extent to left of origin of any glyph bounding box, typically negative; deprecated with vari...
Definition: SkFontMetrics.h:60
SkScalar fUnderlinePosition
distance from baseline to top of stroke, typically positive
Definition: SkFontMetrics.h:65
SkScalar fXMax
greatest extent to right of origin of any glyph bounding box, typically positive; deprecated with var...
Definition: SkFontMetrics.h:61
const uintptr_t id