Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/utils/SkWhitelistTypefaces.cpp

Issue 1317913005: whitelist fallback typefaces (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix compiler bugs Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 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 "SkChecksum.h"
9 #include "SkFontDescriptor.h"
10 #include "SkStream.h"
11 #include "SkString.h"
12 #include "SkTypeface.h"
13 #include "SkUtils.h"
14
15 #include "SkWhitelistChecksums.cpp"
16
17 #define WHITELIST_DEBUG 0
18
19 extern void WhitelistSerializeTypeface(const SkTypeface*, SkWStream* );
20 extern SkTypeface* WhitelistDeserializeTypeface(SkStream* );
21 extern bool CheckChecksums();
22 extern bool GenerateChecksums();
23
24 #if WHITELIST_DEBUG
25 static bool timesNewRomanSerializedNameOnly = false;
26 #endif
27
28 struct NameRecord {
29 unsigned short fPlatformID;
30 unsigned short fEncodingID;
31 unsigned short fLanguageID;
32 unsigned short fNameID;
33 unsigned short fLength;
34 unsigned short fOffset;
35 };
36
37 struct NameTable {
38 unsigned short fFormat;
39 unsigned short fCount;
40 unsigned short fStringOffset;
41 NameRecord fRecord[1];
42 };
43
44 #define SUBNAME_PREFIX "sk_"
45
46 static unsigned short swizzle(unsigned short x) {
47 return x << 8 | (x >> 8 & 0xff);
48 }
49
50 static bool font_name_is_local(const char* fontName, SkTypeface::Style style) {
51 if (!strcmp(fontName, "DejaVu Sans")) {
52 return true;
53 }
54 SkTypeface* defaultFace = SkTypeface::CreateFromName(nullptr, style);
55 SkTypeface* foundFace = SkTypeface::CreateFromName(fontName, style);
56 return defaultFace != foundFace;
57 }
58
59 static int name_table(const NameTable* nameTable, int tableIndex, const char** s tringLocPtr) {
60 int nameTableCount = swizzle(nameTable->fCount);
61 for (int i = 0; i < nameTableCount; ++i) {
62 const NameRecord* nameRecord = &nameTable->fRecord[i];
63 int recordNameID = swizzle(nameRecord->fNameID);
64 if (recordNameID != tableIndex) {
65 continue;
66 }
67 int stringLen = swizzle(nameRecord->fLength);
68 if (!stringLen) {
69 break;
70 }
71 int recordOffset = swizzle(nameRecord->fOffset);
72 const char* stringLoc = (const char* ) nameTable + swizzle(nameTable->fS tringOffset);
73 stringLoc += recordOffset;
74 *stringLocPtr = stringLoc;
75 return stringLen;
76 }
77 return -1;
78 }
79
80 static int whitelist_name_index(const SkTypeface* tf) {
81 static const SkFontTableTag nameTag = SkSetFourByteTag('n', 'a', 'm', 'e');
82 size_t nameSize = tf->getTableSize(nameTag);
83 if (!nameSize) {
84 return -1;
85 }
86 SkTDArray<char> name;
87 name.setCount((int) nameSize);
88 tf->getTableData(nameTag, 0, nameSize, name.begin());
89 const NameTable* nameTable = (const NameTable* ) name.begin();
90 const char* stringLoc;
91 int stringLen = name_table(nameTable, 1, &stringLoc);
92 if (stringLen < 0) {
93 stringLen = name_table(nameTable, 16, &stringLoc);
94 }
95 if (stringLen < 0) {
96 stringLen = name_table(nameTable, 21, &stringLoc);
97 }
98 if (stringLen < 0) {
99 return -1;
100 }
101 SkString fontNameStr;
102 if (!*stringLoc) {
103 stringLen /= 2;
104 for (int i = 0; i < stringLen; ++i) {
105 SkUnichar uni = swizzle(((const uint16_t*) stringLoc)[i]);
106 size_t uniSize = SkUTF8_FromUnichar(uni, NULL);
107 int oldSize = (int) fontNameStr.size();
108 fontNameStr.resize(oldSize + uniSize);
109 char* writeStr = fontNameStr.writable_str() + oldSize;
110 (void) SkUTF8_FromUnichar(uni, writeStr);
111 }
112 } else {
113 fontNameStr.resize(stringLen);
114 strncpy(fontNameStr.writable_str(), stringLoc, stringLen);
115 }
116 // check against permissible list of names
117 for (int i = 0; i < whitelistCount; ++i) {
118 if (fontNameStr.equals(whitelist[i].fFontName)) {
119 return i;
120 }
121 }
122 for (int i = 0; i < whitelistCount; ++i) {
123 if (fontNameStr.startsWith(whitelist[i].fFontName)) {
124 #if WHITELIST_DEBUG
125 SkDebugf("partial match whitelist=\"%s\" fontName=\"%s\"\n", whiteli st[i].fFontName,
126 fontNameStr.c_str());
127 #endif
128 return -1;
129 }
130 }
131 #if WHITELIST_DEBUG
132 SkDebugf("no match fontName=\"%s\"\n", fontNameStr.c_str());
133 #endif
134 return -1;
135 }
136
137 static uint32_t compute_checksum(const SkTypeface* tf) {
138 SkFontData* fontData = tf->createFontData();
139 if (!fontData) {
140 return 0;
141 }
142 SkStreamAsset* fontStream = fontData->getStream();
143 if (!fontStream) {
144 return 0;
145 }
146 SkTDArray<char> data;
147 size_t length = fontStream->getLength();
148 if (!length) {
149 return 0;
150 }
151 data.setCount((int) length);
152 if (!fontStream->peek(data.begin(), length)) {
153 return 0;
154 }
155 return SkChecksum::Murmur3(data.begin(), length);
156 }
157
158 static void serialize_sub(const char* fontName, SkTypeface::Style style, SkWStre am* wstream) {
159 SkFontDescriptor desc(style);
160 SkString subName(SUBNAME_PREFIX);
161 subName.append(fontName);
162 const char* familyName = subName.c_str();
163 desc.setFamilyName(familyName);
164 desc.serialize(wstream);
165 #if WHITELIST_DEBUG
166 for (int i = 0; i < whitelistCount; ++i) {
167 if (!strcmp(fontName, whitelist[i].fFontName)) {
168 if (!whitelist[i].fSerializedSub) {
169 whitelist[i].fSerializedSub = true;
170 SkDebugf("%s %s\n", __FUNCTION__, familyName);
171 }
172 break;
173 }
174 }
175 #endif
176 }
177
178 static bool is_local(const SkTypeface* tf) {
179 bool isLocal = false;
180 SkFontDescriptor desc(tf->style());
181 tf->getFontDescriptor(&desc, &isLocal);
182 return isLocal;
183 }
184
185 static void serialize_full(const SkTypeface* tf, SkWStream* wstream) {
186 bool isLocal = false;
187 SkFontDescriptor desc(tf->style());
188 tf->getFontDescriptor(&desc, &isLocal);
189
190 // Embed font data if it's a local font.
191 if (isLocal && !desc.hasFontData()) {
192 desc.setFontData(tf->createFontData());
193 }
194 desc.serialize(wstream);
195 }
196
197 static void serialize_name_only(const SkTypeface* tf, SkWStream* wstream) {
198 bool isLocal = false;
199 SkFontDescriptor desc(tf->style());
200 tf->getFontDescriptor(&desc, &isLocal);
201 SkASSERT(!isLocal);
202 #if WHITELIST_DEBUG
203 const char* familyName = desc.getFamilyName();
204 if (familyName) {
205 if (!strcmp(familyName, "Times New Roman")) {
206 if (!timesNewRomanSerializedNameOnly) {
207 timesNewRomanSerializedNameOnly = true;
208 SkDebugf("%s %s\n", __FUNCTION__, familyName);
209 }
210 } else {
211 for (int i = 0; i < whitelistCount; ++i) {
212 if (!strcmp(familyName, whitelist[i].fFontName)) {
213 if (!whitelist[i].fSerializedNameOnly) {
214 whitelist[i].fSerializedNameOnly = true;
215 SkDebugf("%s %s\n", __FUNCTION__, familyName);
216 }
217 break;
218 }
219 }
220 }
221 }
222 #endif
223 desc.serialize(wstream);
224 }
225
226 void WhitelistSerializeTypeface(const SkTypeface* tf, SkWStream* wstream) {
227 if (!is_local(tf)) {
228 serialize_name_only(tf, wstream);
229 return;
230 }
231 int whitelistIndex = whitelist_name_index(tf);
232 if (whitelistIndex < 0) {
233 serialize_full(tf, wstream);
234 return;
235 }
236 const char* fontName = whitelist[whitelistIndex].fFontName;
237 if (!font_name_is_local(fontName, tf->style())) {
238 #if WHITELIST_DEBUG
239 SkDebugf("name not found locally \"%s\" style=%d\n", fontName, tf->style ());
240 #endif
241 serialize_full(tf, wstream);
242 return;
243 }
244 uint32_t checksum = compute_checksum(tf);
245 if (whitelist[whitelistIndex].fChecksum != checksum) {
246 #if WHITELIST_DEBUG
247 if (whitelist[whitelistIndex].fChecksum) {
248 SkDebugf("!!! checksum changed !!!\n");
249 }
250 SkDebugf("checksum updated\n");
251 SkDebugf(" { \"%s\", 0x%08x },\n", fontName, checksum);
252 #endif
253 whitelist[whitelistIndex].fChecksum = checksum;
254 }
255 serialize_sub(fontName, tf->style(), wstream);
256 }
257
258 SkTypeface* WhitelistDeserializeTypeface(SkStream* stream) {
259 SkFontDescriptor desc(stream);
260 SkFontData* data = desc.detachFontData();
261 if (data) {
262 SkTypeface* typeface = SkTypeface::CreateFromFontData(data);
263 if (typeface) {
264 return typeface;
265 }
266 }
267 const char* familyName = desc.getFamilyName();
268 if (!strncmp(SUBNAME_PREFIX, familyName, sizeof(SUBNAME_PREFIX) - 1)) {
269 familyName += sizeof(SUBNAME_PREFIX) - 1;
270 }
271 return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle());
272 }
273
274 bool CheckChecksums() {
275 for (int i = 0; i < whitelistCount; ++i) {
276 const char* fontName = whitelist[i].fFontName;
277 SkTypeface* tf = SkTypeface::CreateFromName(fontName, SkTypeface::kNorma l);
278 uint32_t checksum = compute_checksum(tf);
279 if (whitelist[i].fChecksum != checksum) {
280 return false;
281 }
282 }
283 return true;
284 }
285
286 const char checksumFileName[] = "SkWhitelistChecksums.cpp";
287
288 const char checksumHeader[] =
289 "/*" "\n"
290 " * Copyright 2015 Google Inc." "\n"
291 " *" "\n"
292 " * Use of this source code is governed by a BSD-style license that can be" "\n"
293 " * found in the LICENSE file." "\n"
294 " *" "\n"
295 " * %s() in %s generated %s." "\n"
296 " * Run 'whitelist_typefaces --generate' to create anew." "\n"
297 " */" "\n"
298 "" "\n"
299 "#include \"SkTDArray.h\"" "\n"
300 "" "\n"
301 "struct Whitelist {" "\n"
302 " const char* fFontName;" "\n"
303 " uint32_t fChecksum;" "\n"
304 " bool fSerializedNameOnly;" "\n"
305 " bool fSerializedSub;" "\n"
306 "};" "\n"
307 "" "\n"
308 "static Whitelist whitelist[] = {" "\n" ;
309
310 const char checksumEntry[] =
311 " { \"%s\", 0x%08x, false, false }," "\n" ;
312
313 const char checksumTrailer[] =
314 "};" "\n"
315 "" "\n"
316 "static const int whitelistCount = (int) SK_ARRAY_COUNT(whitelist);" "\n" ;
317
318
319 #include "SkOSFile.h"
320
321 bool GenerateChecksums() {
322 SkFILE* file = sk_fopen(checksumFileName, kWrite_SkFILE_Flag);
323 if (!file) {
324 SkDebugf("Can't open %s for writing.\n", checksumFileName);
325 return false;
326 }
327 SkString line;
328 line.printf(checksumHeader, __FUNCTION__, __FILE__, checksumFileName);
329 sk_fwrite(line.c_str(), line.size(), file);
330 for (int i = 0; i < whitelistCount; ++i) {
331 const char* fontName = whitelist[i].fFontName;
332 SkTypeface* tf = SkTypeface::CreateFromName(fontName, SkTypeface::kNorma l);
333 uint32_t checksum = compute_checksum(tf);
334 line.printf(checksumEntry, fontName, checksum);
335 sk_fwrite(line.c_str(), line.size(), file);
336 }
337 sk_fwrite(checksumTrailer, sizeof(checksumTrailer) - 1, file);
338 sk_fclose(file);
339 return true;
340 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698