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

Unified 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, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/utils/SkWhitelistChecksums.cpp ('k') | tests/PictureTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/utils/SkWhitelistTypefaces.cpp
diff --git a/src/utils/SkWhitelistTypefaces.cpp b/src/utils/SkWhitelistTypefaces.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..99f3644a97f6ef6376739ae761e039fe9ef4c5b6
--- /dev/null
+++ b/src/utils/SkWhitelistTypefaces.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkChecksum.h"
+#include "SkFontDescriptor.h"
+#include "SkStream.h"
+#include "SkString.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+#include "SkWhitelistChecksums.cpp"
+
+#define WHITELIST_DEBUG 0
+
+extern void WhitelistSerializeTypeface(const SkTypeface*, SkWStream* );
+extern SkTypeface* WhitelistDeserializeTypeface(SkStream* );
+extern bool CheckChecksums();
+extern bool GenerateChecksums();
+
+#if WHITELIST_DEBUG
+static bool timesNewRomanSerializedNameOnly = false;
+#endif
+
+struct NameRecord {
+ unsigned short fPlatformID;
+ unsigned short fEncodingID;
+ unsigned short fLanguageID;
+ unsigned short fNameID;
+ unsigned short fLength;
+ unsigned short fOffset;
+};
+
+struct NameTable {
bungeman-skia 2015/08/31 15:59:32 Why not SkOTTableName?
+ unsigned short fFormat;
+ unsigned short fCount;
+ unsigned short fStringOffset;
+ NameRecord fRecord[1];
+};
+
+#define SUBNAME_PREFIX "sk_"
+
+static unsigned short swizzle(unsigned short x) {
+ return x << 8 | (x >> 8 & 0xff);
+}
+
+static bool font_name_is_local(const char* fontName, SkTypeface::Style style) {
+ if (!strcmp(fontName, "DejaVu Sans")) {
+ return true;
+ }
+ SkTypeface* defaultFace = SkTypeface::CreateFromName(nullptr, style);
+ SkTypeface* foundFace = SkTypeface::CreateFromName(fontName, style);
+ return defaultFace != foundFace;
+}
+
+static int name_table(const NameTable* nameTable, int tableIndex, const char** stringLocPtr) {
+ int nameTableCount = swizzle(nameTable->fCount);
+ for (int i = 0; i < nameTableCount; ++i) {
+ const NameRecord* nameRecord = &nameTable->fRecord[i];
+ int recordNameID = swizzle(nameRecord->fNameID);
+ if (recordNameID != tableIndex) {
+ continue;
+ }
+ int stringLen = swizzle(nameRecord->fLength);
+ if (!stringLen) {
+ break;
+ }
+ int recordOffset = swizzle(nameRecord->fOffset);
+ const char* stringLoc = (const char* ) nameTable + swizzle(nameTable->fStringOffset);
+ stringLoc += recordOffset;
+ *stringLocPtr = stringLoc;
+ return stringLen;
+ }
+ return -1;
+}
+
+static int whitelist_name_index(const SkTypeface* tf) {
+ static const SkFontTableTag nameTag = SkSetFourByteTag('n', 'a', 'm', 'e');
+ size_t nameSize = tf->getTableSize(nameTag);
+ if (!nameSize) {
+ return -1;
+ }
+ SkTDArray<char> name;
+ name.setCount((int) nameSize);
+ tf->getTableData(nameTag, 0, nameSize, name.begin());
+ const NameTable* nameTable = (const NameTable* ) name.begin();
+ const char* stringLoc;
+ 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
+ if (stringLen < 0) {
+ stringLen = name_table(nameTable, 16, &stringLoc);
+ }
+ if (stringLen < 0) {
+ stringLen = name_table(nameTable, 21, &stringLoc);
+ }
+ if (stringLen < 0) {
+ return -1;
+ }
+ SkString fontNameStr;
+ if (!*stringLoc) {
+ stringLen /= 2;
+ for (int i = 0; i < stringLen; ++i) {
+ fontNameStr.appendUnichar(swizzle(((const uint16_t*) stringLoc)[i]));
+ }
+ } else {
+ fontNameStr.resize(stringLen);
+ strncpy(fontNameStr.writable_str(), stringLoc, stringLen);
+ }
+ // check against permissible list of names
+ for (int i = 0; i < whitelistCount; ++i) {
+ if (fontNameStr.equals(whitelist[i].fFontName)) {
+ return i;
+ }
+ }
+ for (int i = 0; i < whitelistCount; ++i) {
+ if (fontNameStr.startsWith(whitelist[i].fFontName)) {
+#if WHITELIST_DEBUG
+ SkDebugf("partial match whitelist=\"%s\" fontName=\"%s\"\n", whitelist[i].fFontName,
+ fontNameStr.c_str());
+#endif
+ return -1;
+ }
+ }
+#if WHITELIST_DEBUG
+ SkDebugf("no match fontName=\"%s\"\n", fontNameStr.c_str());
+#endif
+ return -1;
+}
+
+static uint32_t compute_checksum(const SkTypeface* tf) {
+ SkFontData* fontData = tf->createFontData();
+ if (!fontData) {
+ return 0;
+ }
+ SkStreamAsset* fontStream = fontData->getStream();
+ if (!fontStream) {
+ return 0;
+ }
+ SkTDArray<char> data;
+ size_t length = fontStream->getLength();
+ if (!length) {
+ return 0;
+ }
+ data.setCount((int) length);
+ if (!fontStream->peek(data.begin(), length)) {
+ return 0;
+ }
+ return SkChecksum::Murmur3(data.begin(), length);
+}
+
+static void serialize_sub(const char* fontName, SkTypeface::Style style, SkWStream* wstream) {
+ SkFontDescriptor desc(style);
+ SkString subName(SUBNAME_PREFIX);
+ subName.append(fontName);
+ const char* familyName = subName.c_str();
+ desc.setFamilyName(familyName);
+ desc.serialize(wstream);
+#if WHITELIST_DEBUG
+ for (int i = 0; i < whitelistCount; ++i) {
+ if (!strcmp(fontName, whitelist[i].fFontName)) {
+ if (!whitelist[i].fSerializedSub) {
+ whitelist[i].fSerializedSub = true;
+ SkDebugf("%s %s\n", __FUNCTION__, familyName);
+ }
+ break;
+ }
+ }
+#endif
+}
+
+static bool is_local(const SkTypeface* tf) {
+ bool isLocal = false;
+ SkFontDescriptor desc(tf->style());
+ tf->getFontDescriptor(&desc, &isLocal);
+ return isLocal;
+}
+
+static void serialize_full(const SkTypeface* tf, SkWStream* wstream) {
+ bool isLocal = false;
+ SkFontDescriptor desc(tf->style());
+ tf->getFontDescriptor(&desc, &isLocal);
+
+ // Embed font data if it's a local font.
+ if (isLocal && !desc.hasFontData()) {
+ desc.setFontData(tf->createFontData());
+ }
+ desc.serialize(wstream);
+}
+
+static void serialize_name_only(const SkTypeface* tf, SkWStream* wstream) {
+ bool isLocal = false;
+ SkFontDescriptor desc(tf->style());
+ tf->getFontDescriptor(&desc, &isLocal);
+ SkASSERT(!isLocal);
+#if WHITELIST_DEBUG
+ const char* familyName = desc.getFamilyName();
+ if (familyName) {
+ if (!strcmp(familyName, "Times New Roman")) {
+ if (!timesNewRomanSerializedNameOnly) {
+ timesNewRomanSerializedNameOnly = true;
+ SkDebugf("%s %s\n", __FUNCTION__, familyName);
+ }
+ } else {
+ for (int i = 0; i < whitelistCount; ++i) {
+ if (!strcmp(familyName, whitelist[i].fFontName)) {
+ if (!whitelist[i].fSerializedNameOnly) {
+ whitelist[i].fSerializedNameOnly = true;
+ SkDebugf("%s %s\n", __FUNCTION__, familyName);
+ }
+ break;
+ }
+ }
+ }
+ }
+#endif
+ desc.serialize(wstream);
+}
+
+void WhitelistSerializeTypeface(const SkTypeface* tf, SkWStream* wstream) {
+ if (!is_local(tf)) {
+ serialize_name_only(tf, wstream);
+ return;
+ }
+ int whitelistIndex = whitelist_name_index(tf);
+ if (whitelistIndex < 0) {
+ serialize_full(tf, wstream);
+ return;
+ }
+ const char* fontName = whitelist[whitelistIndex].fFontName;
+ if (!font_name_is_local(fontName, tf->style())) {
+#if WHITELIST_DEBUG
+ SkDebugf("name not found locally \"%s\" style=%d\n", fontName, tf->style());
+#endif
+ serialize_full(tf, wstream);
+ return;
+ }
+ uint32_t checksum = compute_checksum(tf);
+ if (whitelist[whitelistIndex].fChecksum != checksum) {
+#if WHITELIST_DEBUG
+ if (whitelist[whitelistIndex].fChecksum) {
+ SkDebugf("!!! checksum changed !!!\n");
+ }
+ SkDebugf("checksum updated\n");
+ SkDebugf(" { \"%s\", 0x%08x },\n", fontName, checksum);
+#endif
+ whitelist[whitelistIndex].fChecksum = checksum;
+ }
+ serialize_sub(fontName, tf->style(), wstream);
+}
+
+SkTypeface* WhitelistDeserializeTypeface(SkStream* stream) {
+ SkFontDescriptor desc(stream);
+ SkFontData* data = desc.detachFontData();
+ if (data) {
+ SkTypeface* typeface = SkTypeface::CreateFromFontData(data);
+ if (typeface) {
+ return typeface;
+ }
+ }
+ const char* familyName = desc.getFamilyName();
+ if (!strncmp(SUBNAME_PREFIX, familyName, sizeof(SUBNAME_PREFIX) - 1)) {
+ familyName += sizeof(SUBNAME_PREFIX) - 1;
+ }
+ return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle());
+}
+
+bool CheckChecksums() {
+ for (int i = 0; i < whitelistCount; ++i) {
+ const char* fontName = whitelist[i].fFontName;
+ SkTypeface* tf = SkTypeface::CreateFromName(fontName, SkTypeface::kNormal);
+ uint32_t checksum = compute_checksum(tf);
+ if (whitelist[i].fChecksum != checksum) {
+ return false;
+ }
+ }
+ return true;
+}
+
+const char checksumFileName[] = "SkWhitelistChecksums.cpp";
+
+const char checksumHeader[] =
+"/*" "\n"
+" * Copyright 2015 Google Inc." "\n"
+" *" "\n"
+" * Use of this source code is governed by a BSD-style license that can be" "\n"
+" * found in the LICENSE file." "\n"
+" *" "\n"
+" * %s() in %s generated %s." "\n"
+" * Run 'whitelist_typefaces --generate' to create anew." "\n"
+" */" "\n"
+"" "\n"
+"#include \"SkTDArray.h\"" "\n"
+"" "\n"
+"struct Whitelist {" "\n"
+" const char* fFontName;" "\n"
+" uint32_t fChecksum;" "\n"
+" bool fSerializedNameOnly;" "\n"
+" bool fSerializedSub;" "\n"
+"};" "\n"
+"" "\n"
+"static Whitelist whitelist[] = {" "\n";
+
+const char checksumEntry[] =
+" { \"%s\", 0x%08x, false, false }," "\n";
+
+const char checksumTrailer[] =
+"};" "\n"
+"" "\n"
+"static const int whitelistCount = (int) SK_ARRAY_COUNT(whitelist);" "\n";
+
+
+#include "SkOSFile.h"
+
+bool GenerateChecksums() {
+ SkFILE* file = sk_fopen(checksumFileName, kWrite_SkFILE_Flag);
+ if (!file) {
+ SkDebugf("Can't open %s for writing.\n", checksumFileName);
+ return false;
+ }
+ SkString line;
+ line.printf(checksumHeader, __FUNCTION__, __FILE__, checksumFileName);
+ sk_fwrite(line.c_str(), line.size(), file);
+ for (int i = 0; i < whitelistCount; ++i) {
+ const char* fontName = whitelist[i].fFontName;
+ SkTypeface* tf = SkTypeface::CreateFromName(fontName, SkTypeface::kNormal);
+ uint32_t checksum = compute_checksum(tf);
+ line.printf(checksumEntry, fontName, checksum);
+ sk_fwrite(line.c_str(), line.size(), file);
+ }
+ sk_fwrite(checksumTrailer, sizeof(checksumTrailer) - 1, file);
+ sk_fclose(file);
+ return true;
+}
« 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