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