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#include "Resources.h"
9#include "SkOSFile.h"
10#include "SkTestScalerContext.h"
11#include "SkThread.h"
12#include "SkUtils.h"
13#include "sk_tool_utils.h"
14
15namespace sk_tool_utils {
16
17#include "test_font_data.cpp"
18
19static void release_portable_typefaces() {
20    // We'll clean this up in our own tests, but disable for clients.
21    // Chrome seems to have funky multi-process things going on in unit tests that
22    // makes this unsafe to delete when the main process atexit()s.
23    // SkLazyPtr does the same sort of thing.
24#if SK_DEVELOPER
25    for (int index = 0; index < gTestFontsCount; ++index) {
26        SkTestFontData& fontData = gTestFonts[index];
27        SkSafeUnref(fontData.fFontCache);
28    }
29#endif
30}
31
32SK_DECLARE_STATIC_MUTEX(gTestFontMutex);
33
34SkTypeface* create_font(const char* name, SkTypeface::Style style) {
35    SkTestFontData* fontData = NULL;
36    const SubFont* sub;
37    if (name) {
38        for (int index = 0; index < gSubFontsCount; ++index) {
39            sub = &gSubFonts[index];
40            if (!strcmp(name, sub->fName) && sub->fStyle == style) {
41                fontData = &sub->fFont;
42                break;
43            }
44        }
45        if (!fontData) {
46            SkDebugf("missing %s %d\n", name, style);
47            return SkTypeface::CreateFromName(name, style);
48        }
49    } else {
50        sub = &gSubFonts[gDefaultFontIndex];
51        fontData = &sub->fFont;
52    }
53    SkTestFont* font;
54    {
55        SkAutoMutexAcquire ac(gTestFontMutex);
56        if (fontData->fFontCache) {
57            font = SkSafeRef(fontData->fFontCache);
58        } else {
59            font = SkNEW_ARGS(SkTestFont, (*fontData));
60            SkDEBUGCODE(font->fDebugName = sub->fName);
61            SkDEBUGCODE(font->fDebugStyle = sub->fStyle);
62            fontData->fFontCache = SkSafeRef(font);
63            atexit(release_portable_typefaces);
64        }
65    }
66    return SkNEW_ARGS(SkTestTypeface, (font, SkFontStyle(style)));
67}
68
69
70SkTypeface* resource_font(const char* name, SkTypeface::Style style) {
71    const char* file = NULL;
72    if (name) {
73        for (int index = 0; index < gSubFontsCount; ++index) {
74            const SubFont& sub = gSubFonts[index];
75            if (!strcmp(name, sub.fName) && sub.fStyle == style) {
76                file = sub.fFile;
77                break;
78            }
79        }
80        if (!file) {
81            return SkTypeface::CreateFromName(name, style);
82        }
83    } else {
84        file = gSubFonts[gDefaultFontIndex].fFile;
85    }
86    SkString filepath(GetResourcePath(file));
87    if (sk_exists(filepath.c_str())) {
88        return SkTypeface::CreateFromFile(filepath.c_str());
89    }
90    return SkTypeface::CreateFromName(name, style);
91}
92
93#ifdef SK_DEBUG
94#include <stdio.h>
95
96char const * const gStyleName[] = {
97    "",
98    "_Bold",
99    "_Italic",
100    "_BoldItalic",
101};
102
103static SkString strip_spaces(const char* str) {
104    SkString result;
105    int count = (int) strlen(str);
106    for (int index = 0; index < count; ++index) {
107        char c = str[index];
108        if (c != ' ' && c != '-') {
109            result += c;
110        }
111    }
112    return result;
113}
114
115const char gHeader[] =
116"/*\n"
117" * Copyright 2014 Google Inc.\n"
118" *\n"
119" * Use of this source code is governed by a BSD-style license that can be\n"
120" * found in the LICENSE file.\n"
121" */\n"
122"\n"
123"// Auto-generated by ";
124
125static FILE* font_header() {
126    SkString pathStr(GetResourcePath());
127    pathStr = SkOSPath::Join(pathStr.c_str(), "..");
128    pathStr = SkOSPath::Join(pathStr.c_str(), "tools");
129    pathStr = SkOSPath::Join(pathStr.c_str(), "test_font_data_chars.cpp");
130    FILE* out = fopen(pathStr.c_str(), "w");
131    fprintf(out, "%s%s\n\n", gHeader, SkOSPath::Basename(__FILE__).c_str());
132    return out;
133}
134
135void report_used_chars() {
136    FILE* out = font_header();
137    for (int index = 0; index < gTestFontsCount; ++index) {
138        SkTestFontData& fontData = gTestFonts[index];
139        SkTestFont* font = fontData.fFontCache;
140        if (!font) {
141            continue;
142        }
143        SkString name(strip_spaces(font->debugFontName()));
144        fprintf(out, "const char g%s%s[] =\n", name.c_str(), gStyleName[font->fDebugStyle]);
145        SkString used("    \"");
146        for (int c = ' '; c <= '~'; ++c) {
147            int bitOffset = c - ' ';
148            if (font->fDebugBits[bitOffset >> 3] & (1 << (bitOffset & 7))) {
149                if (c == '"' || c == '\\') {
150                    used += '\\';
151                }
152                used += c;
153            }
154        }
155        if (used.size() > 1) {
156            fprintf(out, "%s\"", used.c_str());
157        }
158        int oIndex = 0;
159        while (font->fDebugOverage[oIndex]) {
160            uint16_t uni = font->fDebugOverage[oIndex];
161            size_t byteCount = SkUTF16_ToUTF8(&uni, 1, NULL);
162            SkAutoSTMalloc<10, char> utf8(byteCount);
163            SkUTF16_ToUTF8(&uni, 1, utf8);
164            for (unsigned byteIndex = 0; byteIndex < byteCount; ++byteIndex) {
165                char unibyte = utf8[byteIndex];
166                fprintf(out, " \"\\x%02X\"", (unsigned char) unibyte);
167            }
168            if (++oIndex >= (int) sizeof(font->fDebugOverage)) {
169                break;
170            }
171        }
172       fprintf(out, ";\n");
173    }
174    fclose(out);
175}
176#endif
177
178}
179