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 "SkFontDescriptor.h" 9 #include "SkOpts.h" 10 #include "SkStream.h" 11 #include "SkString.h" 12 #include "SkTypeface.h" 13 #include "SkUtils.h" 14 #include "../sfnt/SkOTUtils.h" 15 16 #include "SkWhitelistChecksums.inc" 17 18 #define WHITELIST_DEBUG 0 19 20 extern void WhitelistSerializeTypeface(const SkTypeface*, SkWStream* ); 21 sk_sp<SkTypeface> WhitelistDeserializeTypeface(SkStream* ); 22 extern bool CheckChecksums(); 23 extern bool GenerateChecksums(); 24 25 #if WHITELIST_DEBUG 26 static bool timesNewRomanSerializedNameOnly = false; 27 #endif 28 29 #define SUBNAME_PREFIX "sk_" 30 31 static bool font_name_is_local(const char* fontName, SkFontStyle style) { 32 if (!strcmp(fontName, "DejaVu Sans")) { 33 return true; 34 } 35 sk_sp<SkTypeface> defaultFace(SkTypeface::MakeFromName(nullptr, style)); 36 sk_sp<SkTypeface> foundFace(SkTypeface::MakeFromName(fontName, style)); 37 return defaultFace != foundFace; 38 } 39 40 static int whitelist_name_index(const SkTypeface* tf) { 41 42 SkString fontNameStr; 43 sk_sp<SkTypeface::LocalizedStrings> nameIter( 44 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*tf)); 45 SkTypeface::LocalizedString familyNameLocalized; 46 while (nameIter->next(&familyNameLocalized)) { 47 fontNameStr = familyNameLocalized.fString; 48 // check against permissible list of names 49 for (int i = 0; i < whitelistCount; ++i) { 50 if (fontNameStr.equals(whitelist[i].fFontName)) { 51 return i; 52 } 53 } 54 } 55 #if WHITELIST_DEBUG 56 sk_sp<SkTypeface::LocalizedStrings> debugIter( 57 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*tf)); 58 while (debugIter->next(&familyNameLocalized)) { 59 SkDebugf("no match fontName=\"%s\"\n", familyNameLocalized.fString.c_str()); 60 } 61 #endif 62 return -1; 63 } 64 65 static uint32_t compute_checksum(const SkTypeface* tf) { 66 std::unique_ptr<SkFontData> fontData = tf->makeFontData(); 67 if (!fontData) { 68 return 0; 69 } 70 SkStreamAsset* fontStream = fontData->getStream(); 71 if (!fontStream) { 72 return 0; 73 } 74 SkTDArray<char> data; 75 size_t length = fontStream->getLength(); 76 if (!length) { 77 return 0; 78 } 79 data.setCount((int) length); 80 if (!fontStream->peek(data.begin(), length)) { 81 return 0; 82 } 83 return SkOpts::hash(data.begin(), length); 84 } 85 86 static void serialize_sub(const char* fontName, SkFontStyle style, SkWStream* wstream) { 87 SkFontDescriptor desc; 88 SkString subName(SUBNAME_PREFIX); 89 subName.append(fontName); 90 const char* familyName = subName.c_str(); 91 desc.setFamilyName(familyName); 92 desc.setStyle(style); 93 desc.serialize(wstream); 94 #if WHITELIST_DEBUG 95 for (int i = 0; i < whitelistCount; ++i) { 96 if (!strcmp(fontName, whitelist[i].fFontName)) { 97 if (!whitelist[i].fSerializedSub) { 98 whitelist[i].fSerializedSub = true; 99 SkDebugf("%s %s\n", __FUNCTION__, familyName); 100 } 101 break; 102 } 103 } 104 #endif 105 } 106 107 static bool is_local(const SkTypeface* tf) { 108 bool isLocal = false; 109 SkFontDescriptor desc; 110 tf->getFontDescriptor(&desc, &isLocal); 111 return isLocal; 112 } 113 114 static void serialize_full(const SkTypeface* tf, SkWStream* wstream) { 115 bool isLocal = false; 116 SkFontDescriptor desc; 117 tf->getFontDescriptor(&desc, &isLocal); 118 119 // Embed font data if it's a local font. 120 if (isLocal && !desc.hasFontData()) { 121 desc.setFontData(tf->makeFontData()); 122 } 123 desc.serialize(wstream); 124 } 125 126 static void serialize_name_only(const SkTypeface* tf, SkWStream* wstream) { 127 bool isLocal = false; 128 SkFontDescriptor desc; 129 tf->getFontDescriptor(&desc, &isLocal); 130 SkASSERT(!isLocal); 131 #if WHITELIST_DEBUG 132 const char* familyName = desc.getFamilyName(); 133 if (familyName) { 134 if (!strcmp(familyName, "Times New Roman")) { 135 if (!timesNewRomanSerializedNameOnly) { 136 timesNewRomanSerializedNameOnly = true; 137 SkDebugf("%s %s\n", __FUNCTION__, familyName); 138 } 139 } else { 140 for (int i = 0; i < whitelistCount; ++i) { 141 if (!strcmp(familyName, whitelist[i].fFontName)) { 142 if (!whitelist[i].fSerializedNameOnly) { 143 whitelist[i].fSerializedNameOnly = true; 144 SkDebugf("%s %s\n", __FUNCTION__, familyName); 145 } 146 break; 147 } 148 } 149 } 150 } 151 #endif 152 desc.serialize(wstream); 153 } 154 155 void WhitelistSerializeTypeface(const SkTypeface* tf, SkWStream* wstream) { 156 if (!is_local(tf)) { 157 serialize_name_only(tf, wstream); 158 return; 159 } 160 int whitelistIndex = whitelist_name_index(tf); 161 if (whitelistIndex < 0) { 162 serialize_full(tf, wstream); 163 return; 164 } 165 const char* fontName = whitelist[whitelistIndex].fFontName; 166 if (!font_name_is_local(fontName, tf->fontStyle())) { 167 #if WHITELIST_DEBUG 168 SkDebugf("name not found locally \"%s\" style=%d\n", fontName, tf->style()); 169 #endif 170 serialize_full(tf, wstream); 171 return; 172 } 173 uint32_t checksum = compute_checksum(tf); 174 if (whitelist[whitelistIndex].fChecksum != checksum) { 175 #if WHITELIST_DEBUG 176 if (whitelist[whitelistIndex].fChecksum) { 177 SkDebugf("!!! checksum changed !!!\n"); 178 } 179 SkDebugf("checksum updated\n"); 180 SkDebugf(" { \"%s\", 0x%08x },\n", fontName, checksum); 181 #endif 182 whitelist[whitelistIndex].fChecksum = checksum; 183 } 184 serialize_sub(fontName, tf->fontStyle(), wstream); 185 } 186 187 sk_sp<SkTypeface> WhitelistDeserializeTypeface(SkStream* stream) { 188 SkFontDescriptor desc; 189 if (!SkFontDescriptor::Deserialize(stream, &desc)) { 190 return nullptr; 191 } 192 193 std::unique_ptr<SkFontData> data = desc.detachFontData(); 194 if (data) { 195 sk_sp<SkTypeface> typeface(SkTypeface::MakeFromFontData(std::move(data))); 196 if (typeface) { 197 return typeface; 198 } 199 } 200 const char* familyName = desc.getFamilyName(); 201 if (!strncmp(SUBNAME_PREFIX, familyName, sizeof(SUBNAME_PREFIX) - 1)) { 202 familyName += sizeof(SUBNAME_PREFIX) - 1; 203 } 204 return SkTypeface::MakeFromName(familyName, desc.getStyle()); 205 } 206 207 bool CheckChecksums() { 208 for (int i = 0; i < whitelistCount; ++i) { 209 const char* fontName = whitelist[i].fFontName; 210 sk_sp<SkTypeface> tf(SkTypeface::MakeFromName(fontName, SkFontStyle())); 211 uint32_t checksum = compute_checksum(tf.get()); 212 if (whitelist[i].fChecksum != checksum) { 213 return false; 214 } 215 } 216 return true; 217 } 218 219 const char checksumFileName[] = "SkWhitelistChecksums.inc"; 220 221 const char checksumHeader[] = 222 "/*" "\n" 223 " * Copyright 2015 Google Inc." "\n" 224 " *" "\n" 225 " * Use of this source code is governed by a BSD-style license that can be" "\n" 226 " * found in the LICENSE file." "\n" 227 " *" "\n" 228 " * %s() in %s generated %s." "\n" 229 " * Run 'whitelist_typefaces --generate' to create anew." "\n" 230 " */" "\n" 231 "" "\n" 232 "#include \"SkTDArray.h\"" "\n" 233 "" "\n" 234 "struct Whitelist {" "\n" 235 " const char* fFontName;" "\n" 236 " uint32_t fChecksum;" "\n" 237 " bool fSerializedNameOnly;" "\n" 238 " bool fSerializedSub;" "\n" 239 "};" "\n" 240 "" "\n" 241 "static Whitelist whitelist[] = {" "\n"; 242 243 const char checksumEntry[] = 244 " { \"%s\", 0x%08x, false, false }," "\n"; 245 246 const char checksumTrailer[] = 247 "};" "\n" 248 "" "\n" 249 "static const int whitelistCount = (int) SK_ARRAY_COUNT(whitelist);" "\n"; 250 251 252 #include "SkOSFile.h" 253 254 bool GenerateChecksums() { 255 FILE* file = sk_fopen(checksumFileName, kWrite_SkFILE_Flag); 256 if (!file) { 257 SkDebugf("Can't open %s for writing.\n", checksumFileName); 258 return false; 259 } 260 SkString line; 261 line.printf(checksumHeader, __FUNCTION__, __FILE__, checksumFileName); 262 sk_fwrite(line.c_str(), line.size(), file); 263 for (int i = 0; i < whitelistCount; ++i) { 264 const char* fontName = whitelist[i].fFontName; 265 sk_sp<SkTypeface> tf(SkTypeface::MakeFromName(fontName, SkFontStyle())); 266 uint32_t checksum = compute_checksum(tf.get()); 267 line.printf(checksumEntry, fontName, checksum); 268 sk_fwrite(line.c_str(), line.size(), file); 269 } 270 sk_fwrite(checksumTrailer, sizeof(checksumTrailer) - 1, file); 271 sk_fclose(file); 272 return true; 273 } 274