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/SkTestFontMgr.cpp 11 12 #include "SkFont.h" 13 #include "SkFontMetrics.h" 14 #include "SkFontStyle.h" 15 #include "SkOSFile.h" 16 #include "SkOSPath.h" 17 #include "SkPath.h" 18 #include "SkSpan.h" 19 #include "SkStream.h" 20 #include "SkTArray.h" 21 #include "SkTSort.h" 22 #include "SkTypeface.h" 23 #include "SkUTF.h" 24 25 #include <stdio.h> 26 27 namespace { 28 29 struct NamedFontStyle { 30 char const * const fName; 31 char const * const fIdentifierName; 32 SkFontStyle const fStyle; 33 }; 34 35 struct FontDesc { 36 NamedFontStyle const fNamedStyle; 37 char const * const fFile; 38 }; 39 40 struct FontFamilyDesc { 41 char const * const fGenericName; 42 char const * const fFamilyName; 43 char const * const fIdentifierName; 44 SkSpan<const FontDesc> const fFonts; 45 }; 46 47 } // namespace 48 49 static FILE* font_header(const char* family) { 50 SkString outPath(SkOSPath::Join(".", "tools")); 51 outPath = SkOSPath::Join(outPath.c_str(), "fonts"); 52 outPath = SkOSPath::Join(outPath.c_str(), "test_font_"); 53 SkString fam(family); 54 do { 55 int dashIndex = fam.find("-"); 56 if (dashIndex < 0) { 57 break; 58 } 59 fam.writable_str()[dashIndex] = '_'; 60 } while (true); 61 outPath.append(fam); 62 outPath.append(".inc"); 63 FILE* out = fopen(outPath.c_str(), "w"); 64 65 static const char kHeader[] = 66 "/*\n" 67 " * Copyright 2015 Google Inc.\n" 68 " *\n" 69 " * Use of this source code is governed by a BSD-style license that can be\n" 70 " * found in the LICENSE file.\n" 71 " */\n" 72 "\n" 73 "// Auto-generated by "; 74 fprintf(out, "%s%s\n\n", kHeader, SkOSPath::Basename(__FILE__).c_str()); 75 return out; 76 } 77 78 enum { 79 kMaxLineLength = 80, 80 }; 81 82 static ptrdiff_t last_line_length(const SkString& str) { 83 const char* first = str.c_str(); 84 const char* last = first + str.size(); 85 const char* ptr = last; 86 while (ptr > first && *--ptr != '\n') 87 ; 88 return last - ptr - 1; 89 } 90 91 static void output_fixed(SkScalar num, int emSize, SkString* out) { 92 int hex = (int) (num * 65536 / emSize); 93 out->appendf("0x%08x,", hex); 94 *out += (int) last_line_length(*out) >= kMaxLineLength ? '\n' : ' '; 95 } 96 97 static void output_scalar(SkScalar num, int emSize, SkString* out) { 98 num /= emSize; 99 if (num == (int) num) { 100 out->appendS32((int) num); 101 } else { 102 SkString str; 103 str.printf("%1.6g", num); 104 int width = (int) str.size(); 105 const char* cStr = str.c_str(); 106 while (cStr[width - 1] == '0') { 107 --width; 108 } 109 str.remove(width, str.size() - width); 110 out->appendf("%sf", str.c_str()); 111 } 112 *out += ','; 113 *out += (int) last_line_length(*out) >= kMaxLineLength ? '\n' : ' '; 114 } 115 116 static int output_points(const SkPoint* pts, int emSize, int count, SkString* ptsOut) { 117 for (int index = 0; index < count; ++index) { 118 output_scalar(pts[index].fX, emSize, ptsOut); 119 output_scalar(pts[index].fY, emSize, ptsOut); 120 } 121 return count; 122 } 123 124 static void output_path_data(const SkFont& font, 125 int emSize, SkString* ptsOut, SkTDArray<SkPath::Verb>* verbs, 126 SkTDArray<unsigned>* charCodes, SkTDArray<SkScalar>* widths) { 127 for (SkUnichar index = 0x00; index < 0x7f; ++index) { 128 uint16_t glyphID = font.unicharToGlyph(index); 129 SkPath path; 130 font.getPath(glyphID, &path); 131 SkPath::RawIter iter(path); 132 SkPath::Verb verb; 133 SkPoint pts[4]; 134 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 135 *verbs->append() = verb; 136 switch (verb) { 137 case SkPath::kMove_Verb: 138 output_points(&pts[0], emSize, 1, ptsOut); 139 break; 140 case SkPath::kLine_Verb: 141 output_points(&pts[1], emSize, 1, ptsOut); 142 break; 143 case SkPath::kQuad_Verb: 144 output_points(&pts[1], emSize, 2, ptsOut); 145 break; 146 case SkPath::kCubic_Verb: 147 output_points(&pts[1], emSize, 3, ptsOut); 148 break; 149 case SkPath::kClose_Verb: 150 break; 151 default: 152 SkDEBUGFAIL("bad verb"); 153 SkASSERT(0); 154 } 155 } 156 *verbs->append() = SkPath::kDone_Verb; 157 *charCodes->append() = index; 158 SkScalar width; 159 font.getWidths(&glyphID, 1, &width); 160 // SkASSERT(floor(width) == width); // not true for Hiragino Maru Gothic Pro 161 *widths->append() = width; 162 if (0 == index) { 163 index = 0x1f; // skip the rest of the control codes 164 } 165 } 166 } 167 168 static int offset_str_len(unsigned num) { 169 if (num == (unsigned) -1) { 170 return 10; 171 } 172 unsigned result = 1; 173 unsigned ref = 10; 174 while (ref <= num) { 175 ++result; 176 ref *= 10; 177 } 178 return result; 179 } 180 181 static SkString strip_final(const SkString& str) { 182 SkString result(str); 183 if (result.endsWith("\n")) { 184 result.remove(result.size() - 1, 1); 185 } 186 if (result.endsWith(" ")) { 187 result.remove(result.size() - 1, 1); 188 } 189 if (result.endsWith(",")) { 190 result.remove(result.size() - 1, 1); 191 } 192 return result; 193 } 194 195 static void output_font(sk_sp<SkTypeface> face, const char* identifier, FILE* out) { 196 const int emSize = face->getUnitsPerEm() * 2; 197 SkFont font; 198 font.setEdging(SkFont::Edging::kAntiAlias); 199 font.setSize(emSize); 200 font.setTypeface(std::move(face)); 201 202 SkTDArray<SkPath::Verb> verbs; 203 SkTDArray<unsigned> charCodes; 204 SkTDArray<SkScalar> widths; 205 SkString ptsOut; 206 output_path_data(font, emSize, &ptsOut, &verbs, &charCodes, &widths); 207 fprintf(out, "const SkScalar %sPoints[] = {\n", identifier); 208 ptsOut = strip_final(ptsOut); 209 fprintf(out, "%s", ptsOut.c_str()); 210 fprintf(out, "\n};\n\n"); 211 fprintf(out, "const unsigned char %sVerbs[] = {\n", identifier); 212 int verbCount = verbs.count(); 213 int outChCount = 0; 214 for (int index = 0; index < verbCount;) { 215 SkPath::Verb verb = verbs[index]; 216 SkASSERT(verb >= SkPath::kMove_Verb && verb <= SkPath::kDone_Verb); 217 SkASSERT(SkTFitsIn<uint8_t>(verb)); 218 fprintf(out, "%u", verb); 219 if (++index < verbCount) { 220 outChCount += 3; 221 fprintf(out, "%c", ','); 222 if (outChCount >= kMaxLineLength) { 223 outChCount = 0; 224 fprintf(out, "%c", '\n'); 225 } else { 226 fprintf(out, "%c", ' '); 227 } 228 } 229 } 230 fprintf(out, "\n};\n\n"); 231 232 // all fonts are now 0x00, 0x20 - 0xFE 233 // don't need to generate or output character codes? 234 fprintf(out, "const SkUnichar %sCharCodes[] = {\n", identifier); 235 int offsetCount = charCodes.count(); 236 for (int index = 0; index < offsetCount;) { 237 unsigned offset = charCodes[index]; 238 fprintf(out, "%u", offset); 239 if (++index < offsetCount) { 240 outChCount += offset_str_len(offset) + 2; 241 fprintf(out, "%c", ','); 242 if (outChCount >= kMaxLineLength) { 243 outChCount = 0; 244 fprintf(out, "%c", '\n'); 245 } else { 246 fprintf(out, "%c", ' '); 247 } 248 } 249 } 250 fprintf(out, "\n};\n\n"); 251 252 SkString widthsStr; 253 fprintf(out, "const SkFixed %sWidths[] = {\n", identifier); 254 for (int index = 0; index < offsetCount; ++index) { 255 output_fixed(widths[index], emSize, &widthsStr); 256 } 257 widthsStr = strip_final(widthsStr); 258 fprintf(out, "%s\n};\n\n", widthsStr.c_str()); 259 260 fprintf(out, "const size_t %sCharCodesCount = SK_ARRAY_COUNT(%sCharCodes);\n\n", 261 identifier, identifier); 262 263 SkFontMetrics metrics; 264 font.getMetrics(&metrics); 265 fprintf(out, "const SkFontMetrics %sMetrics = {\n", identifier); 266 SkString metricsStr; 267 metricsStr.printf("0x%08x, ", metrics.fFlags); 268 output_scalar(metrics.fTop, emSize, &metricsStr); 269 output_scalar(metrics.fAscent, emSize, &metricsStr); 270 output_scalar(metrics.fDescent, emSize, &metricsStr); 271 output_scalar(metrics.fBottom, emSize, &metricsStr); 272 output_scalar(metrics.fLeading, emSize, &metricsStr); 273 output_scalar(metrics.fAvgCharWidth, emSize, &metricsStr); 274 output_scalar(metrics.fMaxCharWidth, emSize, &metricsStr); 275 output_scalar(metrics.fXMin, emSize, &metricsStr); 276 output_scalar(metrics.fXMax, emSize, &metricsStr); 277 output_scalar(metrics.fXHeight, emSize, &metricsStr); 278 output_scalar(metrics.fCapHeight, emSize, &metricsStr); 279 output_scalar(metrics.fUnderlineThickness, emSize, &metricsStr); 280 output_scalar(metrics.fUnderlinePosition, emSize, &metricsStr); 281 output_scalar(metrics.fStrikeoutThickness, emSize, &metricsStr); 282 output_scalar(metrics.fStrikeoutPosition, emSize, &metricsStr); 283 metricsStr = strip_final(metricsStr); 284 fprintf(out, "%s\n};\n\n", metricsStr.c_str()); 285 } 286 287 static SkString identifier(const FontFamilyDesc& family, const FontDesc& font) { 288 SkString id(family.fIdentifierName); 289 id.append(font.fNamedStyle.fIdentifierName); 290 return id; 291 } 292 293 static void generate_fonts(const char* basepath, const SkSpan<const FontFamilyDesc>& families) { 294 FILE* out = nullptr; 295 for (const FontFamilyDesc& family : families) { 296 out = font_header(family.fGenericName); 297 for (const FontDesc& font : family.fFonts) { 298 SkString filepath(SkOSPath::Join(basepath, font.fFile)); 299 SkASSERTF(sk_exists(filepath.c_str()), "The file %s does not exist.", filepath.c_str()); 300 sk_sp<SkTypeface> resourceTypeface = SkTypeface::MakeFromFile(filepath.c_str()); 301 SkASSERTF(resourceTypeface, "The file %s is not a font.", filepath.c_str()); 302 output_font(std::move(resourceTypeface), identifier(family, font).c_str(), out); 303 } 304 fclose(out); 305 } 306 } 307 308 static const char* slant_to_string(SkFontStyle::Slant slant) { 309 switch (slant) { 310 case SkFontStyle::kUpright_Slant: return "SkFontStyle::kUpright_Slant"; 311 case SkFontStyle::kItalic_Slant : return "SkFontStyle::kItalic_Slant" ; 312 case SkFontStyle::kOblique_Slant: return "SkFontStyle::kOblique_Slant"; 313 default: SK_ABORT("Unknown slant"); return ""; 314 } 315 } 316 317 static void generate_index(const SkSpan<const FontFamilyDesc>& families, 318 const FontDesc* defaultFont) 319 { 320 FILE* out = font_header("index"); 321 fprintf(out, "static SkTestFontData gTestFonts[] = {\n"); 322 for (const FontFamilyDesc& family : families) { 323 for (const FontDesc& font : family.fFonts) { 324 SkString identifierStr = identifier(family, font); 325 const char* identifier = identifierStr.c_str(); 326 const SkFontStyle& style = font.fNamedStyle.fStyle; 327 fprintf(out, 328 " { %sPoints, %sVerbs,\n" 329 " %sCharCodes, %sCharCodesCount, %sWidths,\n" 330 " %sMetrics, \"Toy %s\", SkFontStyle(%d,%d,%s)\n" 331 " },\n", 332 identifier, identifier, 333 identifier, identifier, identifier, 334 identifier, family.fFamilyName, 335 style.weight(), style.width(), slant_to_string(style.slant())); 336 } 337 } 338 fprintf(out, "};\n\n"); 339 fprintf(out, 340 "struct SubFont {\n" 341 " const char* fFamilyName;\n" 342 " const char* fStyleName;\n" 343 " SkFontStyle fStyle;\n" 344 " SkTestFontData& fFont;\n" 345 " const char* fFile;\n" 346 "};\n\n" 347 "const SubFont gSubFonts[] = {\n"); 348 int defaultIndex = -1; 349 int testFontsIndex = 0; 350 for (const FontFamilyDesc& family : families) { 351 for (const FontDesc& font : family.fFonts) { 352 if (&font == defaultFont) { 353 defaultIndex = testFontsIndex; 354 } 355 const SkFontStyle& style = font.fNamedStyle.fStyle; 356 fprintf(out, 357 " { \"%s\", \"%s\", SkFontStyle(%d,%d,%s), gTestFonts[%d], \"%s\" },\n", 358 family.fGenericName, font.fNamedStyle.fName, 359 style.weight(), style.width(), slant_to_string(style.slant()), 360 testFontsIndex, font.fFile); 361 testFontsIndex++; 362 } 363 } 364 testFontsIndex = 0; 365 for (const FontFamilyDesc& family : families) { 366 for (const FontDesc& font : family.fFonts) { 367 fprintf(out, 368 " { \"Toy %s\", \"%s\", SkFontStyle(%d,%d,%s), gTestFonts[%d], \"%s\" },\n", 369 family.fFamilyName, font.fNamedStyle.fName, 370 font.fNamedStyle.fStyle.weight(), font.fNamedStyle.fStyle.width(), 371 slant_to_string(font.fNamedStyle.fStyle.slant()), testFontsIndex, font.fFile); 372 testFontsIndex++; 373 } 374 } 375 fprintf(out, "};\n\n"); 376 SkASSERT(defaultIndex >= 0); 377 fprintf(out, "const size_t gDefaultFontIndex = %d;\n", defaultIndex); 378 fclose(out); 379 } 380 381 int main(int , char * const []) { 382 constexpr NamedFontStyle normal = {"Normal", "Normal", SkFontStyle::Normal() }; 383 constexpr NamedFontStyle bold = {"Bold", "Bold", SkFontStyle::Bold() }; 384 constexpr NamedFontStyle italic = {"Italic", "Italic", SkFontStyle::Italic() }; 385 constexpr NamedFontStyle bolditalic = {"Bold Italic", "BoldItalic", SkFontStyle::BoldItalic()}; 386 387 static constexpr FontDesc kMonoFonts[] = { 388 {normal, "LiberationMono-Regular.ttf"}, 389 {bold, "LiberationMono-Bold.ttf"}, 390 {italic, "LiberationMono-Italic.ttf"}, 391 {bolditalic, "LiberationMono-BoldItalic.ttf"}, 392 }; 393 394 static constexpr FontDesc kSansFonts[] = { 395 {normal, "LiberationSans-Regular.ttf"}, 396 {bold, "LiberationSans-Bold.ttf"}, 397 {italic, "LiberationSans-Italic.ttf"}, 398 {bolditalic, "LiberationSans-BoldItalic.ttf"}, 399 }; 400 401 static constexpr FontDesc kSerifFonts[] = { 402 {normal, "LiberationSerif-Regular.ttf"}, 403 {bold, "LiberationSerif-Bold.ttf"}, 404 {italic, "LiberationSerif-Italic.ttf"}, 405 {bolditalic, "LiberationSerif-BoldItalic.ttf"}, 406 }; 407 408 static constexpr FontFamilyDesc kFamiliesData[] = { 409 {"monospace", "Liberation Mono", "LiberationMono", { kMonoFonts }}, 410 {"sans-serif", "Liberation Sans", "LiberationSans", { kSansFonts }}, 411 {"serif", "Liberation Serif", "LiberationSerif", { kSerifFonts }}, 412 }; 413 414 static constexpr SkSpan<const FontFamilyDesc> kFamilies(kFamiliesData); 415 416 #ifdef SK_BUILD_FOR_UNIX 417 generate_fonts("/usr/share/fonts/truetype/liberation/", kFamilies); 418 #else 419 generate_fonts("/Library/Fonts/", kFamilies); 420 #endif 421 generate_index(kFamilies, &kFamilies[1].fFonts[0]); 422 return 0; 423 } 424