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/test_font_data.cpp 9 // which is read by ./tools/sk_tool_utils_font.cpp 10 11 #include "Resources.h" 12 #include "SkOSFile.h" 13 #include "SkPaint.h" 14 #include "SkPath.h" 15 #include "SkStream.h" 16 #include "SkTArray.h" 17 #include "SkTSort.h" 18 #include "SkTypeface.h" 19 #include "SkUtils.h" 20 #include <stdio.h> 21 22 // the folllowing include is generated by running dm with 23 // --portableFonts --reportUsedChars 24 #include "test_font_data_chars.cpp" 25 26 #define DEFAULT_FONT_NAME "Liberation Sans" 27 28 static struct FontDesc { 29 const char* fName; 30 SkTypeface::Style fStyle; 31 const char* fFont; 32 const char* fFile; 33 const char* fCharsUsed; 34 int fFontIndex; 35 } gFonts[] = { 36 {"Courier New", SkTypeface::kNormal, "Courier New", "Courier New.ttf", 37 gCourierNew}, 38 {"Courier New", SkTypeface::kBold, "Courier New", "Courier New Bold.ttf", 39 gCourierNew_Bold}, 40 {"Courier New", SkTypeface::kItalic, "Courier New", "Courier New Italic.ttf", 41 gCourierNew_Italic}, 42 {"Courier New", SkTypeface::kBoldItalic, "Courier New", "Courier New Bold Italic.ttf", 43 gCourierNew_BoldItalic}, 44 {"Helvetica", SkTypeface::kNormal, "Liberation Sans", "LiberationSans-Regular.ttf", 45 gLiberationSans}, 46 {"Helvetica", SkTypeface::kBold, "Liberation Sans", "LiberationSans-Bold.ttf", 47 gLiberationSans_Bold}, 48 {"Helvetica", SkTypeface::kItalic, "Liberation Sans", "LiberationSans-Italic.ttf", 49 gLiberationSans_Italic}, 50 {"Helvetica", SkTypeface::kBoldItalic, "Liberation Sans", "LiberationSans-BoldItalic.ttf", 51 gLiberationSans_BoldItalic}, 52 {"Hiragino Maru Gothic Pro", SkTypeface::kNormal, "Hiragino Maru Gothic Pro", "Pro W4.otf", 53 gHiraginoMaruGothicPro}, 54 {"Liberation Sans", SkTypeface::kNormal, "Liberation Sans", "LiberationSans-Regular.ttf", 55 gLiberationSans}, 56 {"Liberation Sans", SkTypeface::kBold, "Liberation Sans", "LiberationSans-Bold.ttf", 57 gLiberationSans_Bold}, 58 {"Liberation Sans", SkTypeface::kItalic, "Liberation Sans", "LiberationSans-Italic.ttf", 59 gLiberationSans_Italic}, 60 {"Liberation Sans", SkTypeface::kBoldItalic, "Liberation Sans", "LiberationSans-BoldItalic.ttf", 61 gLiberationSans_BoldItalic}, 62 {"monospace", SkTypeface::kNormal, "Courier New", "Courier New.ttf", 63 gCourierNew}, 64 {"monospace", SkTypeface::kBold, "Courier New", "Courier New Bold.ttf", 65 gCourierNew_Bold}, 66 {"monospace", SkTypeface::kItalic, "Courier New", "Courier New Italic.ttf", 67 gCourierNew_Italic}, 68 {"monospace", SkTypeface::kBoldItalic, "Courier New", "Courier New Bold Italic.ttf", 69 gCourierNew_BoldItalic}, 70 {"Papyrus", SkTypeface::kNormal, "Papyrus", "Papyrus.ttc", 71 gPapyrus}, 72 {"sans-serif", SkTypeface::kNormal, "Liberation Sans", "LiberationSans-Regular.ttf", 73 gLiberationSans}, 74 {"sans-serif", SkTypeface::kBold, "Liberation Sans", "LiberationSans-Bold.ttf", 75 gLiberationSans_Bold}, 76 {"sans-serif", SkTypeface::kItalic, "Liberation Sans", "LiberationSans-Italic.ttf", 77 gLiberationSans_Italic}, 78 {"sans-serif", SkTypeface::kBoldItalic, "Liberation Sans", "LiberationSans-BoldItalic.ttf", 79 gLiberationSans_BoldItalic}, 80 {"serif", SkTypeface::kNormal, "Times New Roman", "Times New Roman.ttf", 81 gTimesNewRoman}, 82 {"serif", SkTypeface::kBold, "Times New Roman", "Times New Roman Bold.ttf", 83 gTimesNewRoman_Bold}, 84 {"serif", SkTypeface::kItalic, "Times New Roman", "Times New Roman Italic.ttf", 85 gTimesNewRoman_Italic}, 86 {"serif", SkTypeface::kBoldItalic, "Times New Roman", "Times New Roman Bold Italic.ttf", 87 gTimesNewRoman_BoldItalic}, 88 {"Times", SkTypeface::kNormal, "Times New Roman", "Times New Roman.ttf", 89 gTimesNewRoman}, 90 {"Times", SkTypeface::kBold, "Times New Roman", "Times New Roman Bold.ttf", 91 gTimesNewRoman_Bold}, 92 {"Times", SkTypeface::kItalic, "Times New Roman", "Times New Roman Italic.ttf", 93 gTimesNewRoman_Italic}, 94 {"Times", SkTypeface::kBoldItalic, "Times New Roman", "Times New Roman Bold Italic.ttf", 95 gTimesNewRoman_BoldItalic}, 96 {"Times New Roman", SkTypeface::kNormal, "Times New Roman", "Times New Roman.ttf", 97 gTimesNewRoman}, 98 {"Times New Roman", SkTypeface::kBold, "Times New Roman", "Times New Roman Bold.ttf", 99 gTimesNewRoman_Bold}, 100 {"Times New Roman", SkTypeface::kItalic, "Times New Roman", "Times New Roman Italic.ttf", 101 gTimesNewRoman_Italic}, 102 {"Times New Roman", SkTypeface::kBoldItalic, "Times New Roman", "Times New Roman Bold Italic.ttf", 103 gTimesNewRoman_BoldItalic}, 104 {"Times Roman", SkTypeface::kNormal, "Liberation Sans", "LiberationSans-Regular.ttf", 105 gLiberationSans}, 106 }; 107 108 const int gFontsCount = (int) SK_ARRAY_COUNT(gFonts); 109 110 const char* gStyleName[] = { 111 "kNormal", 112 "kBold", 113 "kItalic", 114 "kBoldItalic", 115 }; 116 117 const char gHeader[] = 118 "/*\n" 119 " * Copyright 2014 Google Inc.\n" 120 " *\n" 121 " * Use of this source code is governed by a BSD-style license that can be\n" 122 " * found in the LICENSE file.\n" 123 " */\n" 124 "\n" 125 "// Auto-generated by "; 126 127 static FILE* font_header() { 128 SkString outPath(SkOSPath::SkPathJoin(".", "tools")); 129 outPath = SkOSPath::SkPathJoin(outPath.c_str(), "test_font_data.cpp"); 130 FILE* out = fopen(outPath.c_str(), "w"); 131 fprintf(out, "%s%s\n\n", gHeader, SkOSPath::SkBasename(__FILE__).c_str()); 132 return out; 133 } 134 135 enum { 136 kMaxLineLength = 80, 137 }; 138 139 static ptrdiff_t last_line_length(const SkString& str) { 140 const char* first = str.c_str(); 141 const char* last = first + str.size(); 142 const char* ptr = last; 143 while (ptr > first && *--ptr != '\n') 144 ; 145 return last - ptr - 1; 146 } 147 148 static void output_fixed(SkScalar num, int emSize, SkString* out) { 149 int hex = (int) (num * 65536 / emSize); 150 out->appendf("0x%08x,", hex); 151 *out += (int) last_line_length(*out) >= kMaxLineLength ? '\n' : ' '; 152 } 153 154 static void output_scalar(SkScalar num, int emSize, SkString* out) { 155 num /= emSize; 156 if (num == (int) num) { 157 out->appendS32((int) num); 158 } else { 159 SkString str; 160 str.printf("%1.6g", num); 161 int width = (int) str.size(); 162 const char* cStr = str.c_str(); 163 while (cStr[width - 1] == '0') { 164 --width; 165 } 166 str.remove(width, str.size() - width); 167 out->appendf("%sf", str.c_str()); 168 } 169 *out += ','; 170 *out += (int) last_line_length(*out) >= kMaxLineLength ? '\n' : ' '; 171 } 172 173 static int output_points(const SkPoint* pts, int emSize, int count, SkString* ptsOut) { 174 for (int index = 0; index < count; ++index) { 175 // SkASSERT(floor(pts[index].fX) == pts[index].fX); 176 output_scalar(pts[index].fX, emSize, ptsOut); 177 // SkASSERT(floor(pts[index].fY) == pts[index].fY); 178 output_scalar(pts[index].fY, emSize, ptsOut); 179 } 180 return count; 181 } 182 183 static void output_path_data(const SkPaint& paint, const char* used, 184 int emSize, SkString* ptsOut, SkTDArray<SkPath::Verb>* verbs, 185 SkTDArray<unsigned>* charCodes, SkTDArray<SkScalar>* widths) { 186 while (*used) { 187 SkUnichar index = SkUTF8_NextUnichar(&used); 188 SkPath path; 189 paint.getTextPath((const void*) &index, 2, 0, 0, &path); 190 SkPath::RawIter iter(path); 191 SkPath::Verb verb; 192 SkPoint pts[4]; 193 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 194 *verbs->append() = verb; 195 switch (verb) { 196 case SkPath::kMove_Verb: 197 output_points(&pts[0], emSize, 1, ptsOut); 198 break; 199 case SkPath::kLine_Verb: 200 output_points(&pts[1], emSize, 1, ptsOut); 201 break; 202 case SkPath::kQuad_Verb: 203 output_points(&pts[1], emSize, 2, ptsOut); 204 break; 205 case SkPath::kCubic_Verb: 206 output_points(&pts[1], emSize, 3, ptsOut); 207 break; 208 case SkPath::kClose_Verb: 209 break; 210 default: 211 SkDEBUGFAIL("bad verb"); 212 SkASSERT(0); 213 } 214 } 215 *verbs->append() = SkPath::kDone_Verb; 216 *charCodes->append() = index; 217 SkScalar width; 218 SkDEBUGCODE(int charCount =) paint.getTextWidths((const void*) &index, 2, &width); 219 SkASSERT(charCount == 1); 220 // SkASSERT(floor(width) == width); // not true for Hiragino Maru Gothic Pro 221 *widths->append() = width; 222 } 223 } 224 225 static int offset_str_len(unsigned num) { 226 if (num == (unsigned) -1) { 227 return 10; 228 } 229 unsigned result = 1; 230 unsigned ref = 10; 231 while (ref <= num) { 232 ++result; 233 ref *= 10; 234 } 235 return result; 236 } 237 238 static SkString strip_spaces(const SkString& str) { 239 SkString result; 240 int count = (int) str.size(); 241 for (int index = 0; index < count; ++index) { 242 char c = str[index]; 243 if (c != ' ' && c != '-') { 244 result += c; 245 } 246 } 247 return result; 248 } 249 250 static SkString strip_final(const SkString& str) { 251 SkString result(str); 252 if (result.endsWith("\n")) { 253 result.remove(result.size() - 1, 1); 254 } 255 if (result.endsWith(" ")) { 256 result.remove(result.size() - 1, 1); 257 } 258 if (result.endsWith(",")) { 259 result.remove(result.size() - 1, 1); 260 } 261 return result; 262 } 263 264 static void output_font(SkTypeface* face, const char* name, SkTypeface::Style style, 265 const char* used, FILE* out) { 266 int emSize = face->getUnitsPerEm() * 2; 267 SkPaint paint; 268 paint.setAntiAlias(true); 269 paint.setTextAlign(SkPaint::kLeft_Align); 270 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 271 paint.setTextSize(emSize); 272 SkSafeUnref(paint.setTypeface(face)); 273 SkTDArray<SkPath::Verb> verbs; 274 SkTDArray<unsigned> charCodes; 275 SkTDArray<SkScalar> widths; 276 SkString ptsOut; 277 output_path_data(paint, used, emSize, &ptsOut, &verbs, &charCodes, &widths); 278 SkString fontnameStr(name); 279 SkString strippedStr = strip_spaces(fontnameStr); 280 strippedStr.appendf("%s", gStyleName[style]); 281 const char* fontname = strippedStr.c_str(); 282 fprintf(out, "const SkScalar %sPoints[] = {\n", fontname); 283 ptsOut = strip_final(ptsOut); 284 fprintf(out, "%s", ptsOut.c_str()); 285 fprintf(out, "\n};\n\n"); 286 fprintf(out, "const unsigned char %sVerbs[] = {\n", fontname); 287 int verbCount = verbs.count(); 288 int outChCount = 0; 289 for (int index = 0; index < verbCount;) { 290 SkPath::Verb verb = verbs[index]; 291 SkASSERT(verb >= SkPath::kMove_Verb && verb <= SkPath::kDone_Verb); 292 SkASSERT((unsigned) verb == (unsigned char) verb); 293 fprintf(out, "%u", verb); 294 if (++index < verbCount) { 295 outChCount += 3; 296 fprintf(out, "%c", ','); 297 if (outChCount >= kMaxLineLength) { 298 outChCount = 0; 299 fprintf(out, "%c", '\n'); 300 } else { 301 fprintf(out, "%c", ' '); 302 } 303 } 304 } 305 fprintf(out, "\n};\n\n"); 306 307 fprintf(out, "const unsigned %sCharCodes[] = {\n", fontname); 308 int offsetCount = charCodes.count(); 309 for (int index = 0; index < offsetCount;) { 310 unsigned offset = charCodes[index]; 311 fprintf(out, "%u", offset); 312 if (++index < offsetCount) { 313 outChCount += offset_str_len(offset) + 2; 314 fprintf(out, "%c", ','); 315 if (outChCount >= kMaxLineLength) { 316 outChCount = 0; 317 fprintf(out, "%c", '\n'); 318 } else { 319 fprintf(out, "%c", ' '); 320 } 321 } 322 } 323 fprintf(out, "\n};\n\n"); 324 325 SkString widthsStr; 326 fprintf(out, "const SkFixed %sWidths[] = {\n", fontname); 327 for (int index = 0; index < offsetCount; ++index) { 328 output_fixed(widths[index], emSize, &widthsStr); 329 } 330 widthsStr = strip_final(widthsStr); 331 fprintf(out, "%s\n};\n\n", widthsStr.c_str()); 332 333 fprintf(out, "const int %sCharCodesCount = (int) SK_ARRAY_COUNT(%sCharCodes);\n\n", 334 fontname, fontname); 335 336 SkPaint::FontMetrics metrics; 337 paint.getFontMetrics(&metrics); 338 fprintf(out, "const SkPaint::FontMetrics %sMetrics = {\n", fontname); 339 SkString metricsStr; 340 metricsStr.printf("0x%08x, ", metrics.fFlags); 341 output_scalar(metrics.fTop, emSize, &metricsStr); 342 output_scalar(metrics.fAscent, emSize, &metricsStr); 343 output_scalar(metrics.fDescent, emSize, &metricsStr); 344 output_scalar(metrics.fBottom, emSize, &metricsStr); 345 output_scalar(metrics.fLeading, emSize, &metricsStr); 346 output_scalar(metrics.fAvgCharWidth, emSize, &metricsStr); 347 output_scalar(metrics.fMaxCharWidth, emSize, &metricsStr); 348 output_scalar(metrics.fXMin, emSize, &metricsStr); 349 output_scalar(metrics.fXMax, emSize, &metricsStr); 350 output_scalar(metrics.fXHeight, emSize, &metricsStr); 351 output_scalar(metrics.fCapHeight, emSize, &metricsStr); 352 output_scalar(metrics.fUnderlineThickness, emSize, &metricsStr); 353 output_scalar(metrics.fUnderlinePosition, emSize, &metricsStr); 354 metricsStr = strip_final(metricsStr); 355 fprintf(out, "%s\n};\n\n", metricsStr.c_str()); 356 } 357 358 struct FontWritten { 359 const char* fName; 360 SkTypeface::Style fStyle; 361 }; 362 363 static SkTDArray<FontWritten> gWritten; 364 365 static int written_index(const FontDesc& fontDesc) { 366 for (int index = 0; index < gWritten.count(); ++index) { 367 const FontWritten& writ = gWritten[index]; 368 if (!strcmp(fontDesc.fFont, writ.fName) && fontDesc.fStyle == writ.fStyle) { 369 return index; 370 } 371 } 372 return -1; 373 } 374 375 static void generate_fonts(FILE* out) { 376 for (int index = 0; index < gFontsCount; ++index) { 377 FontDesc& fontDesc = gFonts[index]; 378 int fontIndex = written_index(fontDesc); 379 if (fontIndex >= 0) { 380 fontDesc.fFontIndex = fontIndex; 381 continue; 382 } 383 SkTypeface* systemTypeface = SkTypeface::CreateFromName(fontDesc.fFont, fontDesc.fStyle); 384 SkASSERT(systemTypeface); 385 SkString filepath(GetResourcePath(fontDesc.fFile)); 386 SkASSERT(sk_exists(filepath.c_str())); 387 SkTypeface* resourceTypeface = SkTypeface::CreateFromFile(filepath.c_str()); 388 SkASSERT(resourceTypeface); 389 output_font(resourceTypeface, fontDesc.fFont, fontDesc.fStyle, fontDesc.fCharsUsed, out); 390 fontDesc.fFontIndex = gWritten.count(); 391 FontWritten* writ = gWritten.append(); 392 writ->fName = fontDesc.fFont; 393 writ->fStyle = fontDesc.fStyle; 394 } 395 } 396 397 static void generate_index(const char* defaultName, FILE* out) { 398 int fontCount = gWritten.count(); 399 fprintf(out, 400 "static SkTestFontData gTestFonts[] = {\n"); 401 int fontIndex; 402 for (fontIndex = 0; fontIndex < fontCount; ++fontIndex) { 403 const FontWritten& writ = gWritten[fontIndex]; 404 const char* name = writ.fName; 405 SkString strippedStr = strip_spaces(SkString(name)); 406 strippedStr.appendf("%s", gStyleName[writ.fStyle]); 407 const char* strip = strippedStr.c_str(); 408 fprintf(out, 409 " { %sPoints, %sVerbs, %sCharCodes,\n" 410 " %sCharCodesCount, %sWidths,\n" 411 " %sMetrics, \"%s\", SkTypeface::%s, NULL\n" 412 " },\n", 413 strip, strip, strip, strip, strip, strip, name, gStyleName[writ.fStyle]); 414 } 415 fprintf(out, "};\n\n"); 416 fprintf(out, "const int gTestFontsCount = (int) SK_ARRAY_COUNT(gTestFonts);\n\n"); 417 fprintf(out, 418 "struct SubFont {\n" 419 " const char* fName;\n" 420 " SkTypeface::Style fStyle;\n" 421 " SkTestFontData& fFont;\n" 422 " const char* fFile;\n" 423 "};\n\n" 424 "const SubFont gSubFonts[] = {\n"); 425 int defaultIndex = -1; 426 for (int subIndex = 0; subIndex < gFontsCount; subIndex++) { 427 const FontDesc& desc = gFonts[subIndex]; 428 if (!strcmp(defaultName, desc.fName)) { 429 defaultIndex = subIndex; 430 } 431 fprintf(out, 432 " { \"%s\", SkTypeface::%s, gTestFonts[%d], \"%s\"},\n", desc.fName, 433 gStyleName[desc.fStyle], desc.fFontIndex, desc.fFile); 434 } 435 fprintf(out, "};\n\n"); 436 fprintf(out, "const int gSubFontsCount = (int) SK_ARRAY_COUNT(gSubFonts);\n\n"); 437 SkASSERT(defaultIndex >= 0); 438 fprintf(out, "const int gDefaultFontIndex = %d;\n", defaultIndex); 439 } 440 441 int main(int , char * const []) { 442 #ifndef SK_BUILD_FOR_MAC 443 #error "use fonts installed on Mac" 444 #endif 445 FILE* out = font_header(); 446 generate_fonts(out); 447 generate_index(DEFAULT_FONT_NAME, out); 448 fclose(out); 449 return 0; 450 } 451