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

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: remove string change 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
« no previous file with comments | « src/utils/SkWhitelistChecksums.cpp ('k') | tests/PictureTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 {
bungeman-skia 2015/08/31 15:59:32 Why not SkOTTableName?
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);
bungeman-skia 2015/08/31 15:59:32 Any reason not to use SkOTTableName::Iterator or L
caryclark 2015/09/01 12:17:37 I'll switch over to LocalizedStrings_NameTable in
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 fontNameStr.appendUnichar(swizzle(((const uint16_t*) stringLoc)[i])) ;
106 }
107 } else {
108 fontNameStr.resize(stringLen);
109 strncpy(fontNameStr.writable_str(), stringLoc, stringLen);
110 }
111 // check against permissible list of names
112 for (int i = 0; i < whitelistCount; ++i) {
113 if (fontNameStr.equals(whitelist[i].fFontName)) {
114 return i;
115 }
116 }
117 for (int i = 0; i < whitelistCount; ++i) {
118 if (fontNameStr.startsWith(whitelist[i].fFontName)) {
119 #if WHITELIST_DEBUG
120 SkDebugf("partial match whitelist=\"%s\" fontName=\"%s\"\n", whiteli st[i].fFontName,
121 fontNameStr.c_str());
122 #endif
123 return -1;
124 }
125 }
126 #if WHITELIST_DEBUG
127 SkDebugf("no match fontName=\"%s\"\n", fontNameStr.c_str());
128 #endif
129 return -1;
130 }
131
132 static uint32_t compute_checksum(const SkTypeface* tf) {
133 SkFontData* fontData = tf->createFontData();
134 if (!fontData) {
135 return 0;
136 }
137 SkStreamAsset* fontStream = fontData->getStream();
138 if (!fontStream) {
139 return 0;
140 }
141 SkTDArray<char> data;
142 size_t length = fontStream->getLength();
143 if (!length) {
144 return 0;
145 }
146 data.setCount((int) length);
147 if (!fontStream->peek(data.begin(), length)) {
148 return 0;
149 }
150 return SkChecksum::Murmur3(data.begin(), length);
151 }
152
153 static void serialize_sub(const char* fontName, SkTypeface::Style style, SkWStre am* wstream) {
154 SkFontDescriptor desc(style);
155 SkString subName(SUBNAME_PREFIX);
156 subName.append(fontName);
157 const char* familyName = subName.c_str();
158 desc.setFamilyName(familyName);
159 desc.serialize(wstream);
160 #if WHITELIST_DEBUG
161 for (int i = 0; i < whitelistCount; ++i) {
162 if (!strcmp(fontName, whitelist[i].fFontName)) {
163 if (!whitelist[i].fSerializedSub) {
164 whitelist[i].fSerializedSub = true;
165 SkDebugf("%s %s\n", __FUNCTION__, familyName);
166 }
167 break;
168 }
169 }
170 #endif
171 }
172
173 static bool is_local(const SkTypeface* tf) {
174 bool isLocal = false;
175 SkFontDescriptor desc(tf->style());
176 tf->getFontDescriptor(&desc, &isLocal);
177 return isLocal;
178 }
179
180 static void serialize_full(const SkTypeface* tf, SkWStream* wstream) {
181 bool isLocal = false;
182 SkFontDescriptor desc(tf->style());
183 tf->getFontDescriptor(&desc, &isLocal);
184
185 // Embed font data if it's a local font.
186 if (isLocal && !desc.hasFontData()) {
187 desc.setFontData(tf->createFontData());
188 }
189 desc.serialize(wstream);
190 }
191
192 static void serialize_name_only(const SkTypeface* tf, SkWStream* wstream) {
193 bool isLocal = false;
194 SkFontDescriptor desc(tf->style());
195 tf->getFontDescriptor(&desc, &isLocal);
196 SkASSERT(!isLocal);
197 #if WHITELIST_DEBUG
198 const char* familyName = desc.getFamilyName();
199 if (familyName) {
200 if (!strcmp(familyName, "Times New Roman")) {
201 if (!timesNewRomanSerializedNameOnly) {
202 timesNewRomanSerializedNameOnly = true;
203 SkDebugf("%s %s\n", __FUNCTION__, familyName);
204 }
205 } else {
206 for (int i = 0; i < whitelistCount; ++i) {
207 if (!strcmp(familyName, whitelist[i].fFontName)) {
208 if (!whitelist[i].fSerializedNameOnly) {
209 whitelist[i].fSerializedNameOnly = true;
210 SkDebugf("%s %s\n", __FUNCTION__, familyName);
211 }
212 break;
213 }
214 }
215 }
216 }
217 #endif
218 desc.serialize(wstream);
219 }
220
221 void WhitelistSerializeTypeface(const SkTypeface* tf, SkWStream* wstream) {
222 if (!is_local(tf)) {
223 serialize_name_only(tf, wstream);
224 return;
225 }
226 int whitelistIndex = whitelist_name_index(tf);
227 if (whitelistIndex < 0) {
228 serialize_full(tf, wstream);
229 return;
230 }
231 const char* fontName = whitelist[whitelistIndex].fFontName;
232 if (!font_name_is_local(fontName, tf->style())) {
233 #if WHITELIST_DEBUG
234 SkDebugf("name not found locally \"%s\" style=%d\n", fontName, tf->style ());
235 #endif
236 serialize_full(tf, wstream);
237 return;
238 }
239 uint32_t checksum = compute_checksum(tf);
240 if (whitelist[whitelistIndex].fChecksum != checksum) {
241 #if WHITELIST_DEBUG
242 if (whitelist[whitelistIndex].fChecksum) {
243 SkDebugf("!!! checksum changed !!!\n");
244 }
245 SkDebugf("checksum updated\n");
246 SkDebugf(" { \"%s\", 0x%08x },\n", fontName, checksum);
247 #endif
248 whitelist[whitelistIndex].fChecksum = checksum;
249 }
250 serialize_sub(fontName, tf->style(), wstream);
251 }
252
253 SkTypeface* WhitelistDeserializeTypeface(SkStream* stream) {
254 SkFontDescriptor desc(stream);
255 SkFontData* data = desc.detachFontData();
256 if (data) {
257 SkTypeface* typeface = SkTypeface::CreateFromFontData(data);
258 if (typeface) {
259 return typeface;
260 }
261 }
262 const char* familyName = desc.getFamilyName();
263 if (!strncmp(SUBNAME_PREFIX, familyName, sizeof(SUBNAME_PREFIX) - 1)) {
264 familyName += sizeof(SUBNAME_PREFIX) - 1;
265 }
266 return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle());
267 }
268
269 bool CheckChecksums() {
270 for (int i = 0; i < whitelistCount; ++i) {
271 const char* fontName = whitelist[i].fFontName;
272 SkTypeface* tf = SkTypeface::CreateFromName(fontName, SkTypeface::kNorma l);
273 uint32_t checksum = compute_checksum(tf);
274 if (whitelist[i].fChecksum != checksum) {
275 return false;
276 }
277 }
278 return true;
279 }
280
281 const char checksumFileName[] = "SkWhitelistChecksums.cpp";
282
283 const char checksumHeader[] =
284 "/*" "\n"
285 " * Copyright 2015 Google Inc." "\n"
286 " *" "\n"
287 " * Use of this source code is governed by a BSD-style license that can be" "\n"
288 " * found in the LICENSE file." "\n"
289 " *" "\n"
290 " * %s() in %s generated %s." "\n"
291 " * Run 'whitelist_typefaces --generate' to create anew." "\n"
292 " */" "\n"
293 "" "\n"
294 "#include \"SkTDArray.h\"" "\n"
295 "" "\n"
296 "struct Whitelist {" "\n"
297 " const char* fFontName;" "\n"
298 " uint32_t fChecksum;" "\n"
299 " bool fSerializedNameOnly;" "\n"
300 " bool fSerializedSub;" "\n"
301 "};" "\n"
302 "" "\n"
303 "static Whitelist whitelist[] = {" "\n" ;
304
305 const char checksumEntry[] =
306 " { \"%s\", 0x%08x, false, false }," "\n" ;
307
308 const char checksumTrailer[] =
309 "};" "\n"
310 "" "\n"
311 "static const int whitelistCount = (int) SK_ARRAY_COUNT(whitelist);" "\n" ;
312
313
314 #include "SkOSFile.h"
315
316 bool GenerateChecksums() {
317 SkFILE* file = sk_fopen(checksumFileName, kWrite_SkFILE_Flag);
318 if (!file) {
319 SkDebugf("Can't open %s for writing.\n", checksumFileName);
320 return false;
321 }
322 SkString line;
323 line.printf(checksumHeader, __FUNCTION__, __FILE__, checksumFileName);
324 sk_fwrite(line.c_str(), line.size(), file);
325 for (int i = 0; i < whitelistCount; ++i) {
326 const char* fontName = whitelist[i].fFontName;
327 SkTypeface* tf = SkTypeface::CreateFromName(fontName, SkTypeface::kNorma l);
328 uint32_t checksum = compute_checksum(tf);
329 line.printf(checksumEntry, fontName, checksum);
330 sk_fwrite(line.c_str(), line.size(), file);
331 }
332 sk_fwrite(checksumTrailer, sizeof(checksumTrailer) - 1, file);
333 sk_fclose(file);
334 return true;
335 }
OLDNEW
« no previous file with comments | « src/utils/SkWhitelistChecksums.cpp ('k') | tests/PictureTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698