Home | History | Annotate | Download | only in utils
      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