Home | History | Annotate | Download | only in PdfViewer
      1 /*
      2  * Copyright 2013 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 "SkPdfFont.h"
      9 
     10 #include "SkPdfNativeTokenizer.h"
     11 #include "SkStream.h"
     12 #include "SkTypeface.h"
     13 
     14 SkTDict<SkPdfStandardFontEntry>& getStandardFonts() {
     15     static SkTDict<SkPdfStandardFontEntry> gPdfStandardFonts(100);
     16 
     17     // TODO (edisonn): , vs - ? what does it mean?
     18     // TODO (edisonn): MT, PS, Oblique=italic?, ... what does it mean?
     19     if (gPdfStandardFonts.count() == 0) {
     20         gPdfStandardFonts.set("Arial", SkPdfStandardFontEntry("Arial", false, false));
     21         gPdfStandardFonts.set("Arial,Bold", SkPdfStandardFontEntry("Arial", true, false));
     22         gPdfStandardFonts.set("Arial,BoldItalic", SkPdfStandardFontEntry("Arial", true, true));
     23         gPdfStandardFonts.set("Arial,Italic", SkPdfStandardFontEntry("Arial", false, true));
     24         gPdfStandardFonts.set("Arial-Bold", SkPdfStandardFontEntry("Arial", true, false));
     25         gPdfStandardFonts.set("Arial-BoldItalic", SkPdfStandardFontEntry("Arial", true, true));
     26         gPdfStandardFonts.set("Arial-BoldItalicMT", SkPdfStandardFontEntry("Arial", true, true));
     27         gPdfStandardFonts.set("Arial-BoldMT", SkPdfStandardFontEntry("Arial", true, false));
     28         gPdfStandardFonts.set("Arial-Italic", SkPdfStandardFontEntry("Arial", false, true));
     29         gPdfStandardFonts.set("Arial-ItalicMT", SkPdfStandardFontEntry("Arial", false, true));
     30         gPdfStandardFonts.set("ArialMT", SkPdfStandardFontEntry("Arial", false, false));
     31         gPdfStandardFonts.set("Courier", SkPdfStandardFontEntry("Courier New", false, false));
     32         gPdfStandardFonts.set("Courier,Bold", SkPdfStandardFontEntry("Courier New", true, false));
     33         gPdfStandardFonts.set("Courier,BoldItalic", SkPdfStandardFontEntry("Courier New", true, true));
     34         gPdfStandardFonts.set("Courier,Italic", SkPdfStandardFontEntry("Courier New", false, true));
     35         gPdfStandardFonts.set("Courier-Bold", SkPdfStandardFontEntry("Courier New", true, false));
     36         gPdfStandardFonts.set("Courier-BoldOblique", SkPdfStandardFontEntry("Courier New", true, true));
     37         gPdfStandardFonts.set("Courier-Oblique", SkPdfStandardFontEntry("Courier New", false, true));
     38         gPdfStandardFonts.set("CourierNew", SkPdfStandardFontEntry("Courier New", false, false));
     39         gPdfStandardFonts.set("CourierNew,Bold", SkPdfStandardFontEntry("Courier New", true, false));
     40         gPdfStandardFonts.set("CourierNew,BoldItalic", SkPdfStandardFontEntry("Courier New", true, true));
     41         gPdfStandardFonts.set("CourierNew,Italic", SkPdfStandardFontEntry("Courier New", false, true));
     42         gPdfStandardFonts.set("CourierNew-Bold", SkPdfStandardFontEntry("Courier New", true, false));
     43         gPdfStandardFonts.set("CourierNew-BoldItalic", SkPdfStandardFontEntry("Courier New", true, true));
     44         gPdfStandardFonts.set("CourierNew-Italic", SkPdfStandardFontEntry("Courier New", false, true));
     45         gPdfStandardFonts.set("CourierNewPS-BoldItalicMT", SkPdfStandardFontEntry("Courier New", true, true));
     46         gPdfStandardFonts.set("CourierNewPS-BoldMT", SkPdfStandardFontEntry("Courier New", true, false));
     47         gPdfStandardFonts.set("CourierNewPS-ItalicMT", SkPdfStandardFontEntry("Courier New", false, true));
     48         gPdfStandardFonts.set("CourierNewPSMT", SkPdfStandardFontEntry("Courier New", false, false));
     49         gPdfStandardFonts.set("Helvetica", SkPdfStandardFontEntry("Helvetica", false, false));
     50         gPdfStandardFonts.set("Helvetica,Bold", SkPdfStandardFontEntry("Helvetica", true, false));
     51         gPdfStandardFonts.set("Helvetica,BoldItalic", SkPdfStandardFontEntry("Helvetica", true, true));
     52         gPdfStandardFonts.set("Helvetica,Italic", SkPdfStandardFontEntry("Helvetica", false, true));
     53         gPdfStandardFonts.set("Helvetica-Bold", SkPdfStandardFontEntry("Helvetica", true, false));
     54         gPdfStandardFonts.set("Helvetica-BoldItalic", SkPdfStandardFontEntry("Helvetica", true, true));
     55         gPdfStandardFonts.set("Helvetica-BoldOblique", SkPdfStandardFontEntry("Helvetica", true, true));
     56         gPdfStandardFonts.set("Helvetica-Italic", SkPdfStandardFontEntry("Helvetica", false, true));
     57         gPdfStandardFonts.set("Helvetica-Oblique", SkPdfStandardFontEntry("Helvetica", false, true));
     58         gPdfStandardFonts.set("Times-Bold", SkPdfStandardFontEntry("Times New Roman", true, false));
     59         gPdfStandardFonts.set("Times-BoldItalic", SkPdfStandardFontEntry("Times New Roman", true, true));
     60         gPdfStandardFonts.set("Times-Italic", SkPdfStandardFontEntry("Times New Roman", false, true));
     61         gPdfStandardFonts.set("Times-Roman", SkPdfStandardFontEntry("Times New Roman", false, false));
     62         gPdfStandardFonts.set("TimesNewRoman", SkPdfStandardFontEntry("Times New Roman", false, false));
     63         gPdfStandardFonts.set("TimesNewRoman,Bold", SkPdfStandardFontEntry("Times New Roman", true, false));
     64         gPdfStandardFonts.set("TimesNewRoman,BoldItalic", SkPdfStandardFontEntry("Times New Roman", true, true));
     65         gPdfStandardFonts.set("TimesNewRoman,Italic", SkPdfStandardFontEntry("Times New Roman", false, true));
     66         gPdfStandardFonts.set("TimesNewRoman-Bold", SkPdfStandardFontEntry("Times New Roman", true, false));
     67         gPdfStandardFonts.set("TimesNewRoman-BoldItalic", SkPdfStandardFontEntry("Times New Roman", true, true));
     68         gPdfStandardFonts.set("TimesNewRoman-Italic", SkPdfStandardFontEntry("Times New Roman", false, true));
     69         gPdfStandardFonts.set("TimesNewRomanPS", SkPdfStandardFontEntry("Times New Roman", false, false));
     70         gPdfStandardFonts.set("TimesNewRomanPS-Bold", SkPdfStandardFontEntry("Times New Roman", true, false));
     71         gPdfStandardFonts.set("TimesNewRomanPS-BoldItalic", SkPdfStandardFontEntry("Times New Roman", true, true));
     72         gPdfStandardFonts.set("TimesNewRomanPS-BoldItalicMT", SkPdfStandardFontEntry("Times New Roman", true, true));
     73         gPdfStandardFonts.set("TimesNewRomanPS-BoldMT", SkPdfStandardFontEntry("Times New Roman", true, false));
     74         gPdfStandardFonts.set("TimesNewRomanPS-Italic", SkPdfStandardFontEntry("Times New Roman", false, true));
     75         gPdfStandardFonts.set("TimesNewRomanPS-ItalicMT", SkPdfStandardFontEntry("Times New Roman", false, true));
     76         gPdfStandardFonts.set("TimesNewRomanPSMT", SkPdfStandardFontEntry("Times New Roman", false, false));
     77         gPdfStandardFonts.set("Symbol", SkPdfStandardFontEntry("Symbol", false, false));
     78         gPdfStandardFonts.set("ZapfDingbats", SkPdfStandardFontEntry("ZapfDingbats", false, false));
     79 
     80         // TODO(edisonn): these are hacks. Load Post Script font name.
     81         // see FT_Get_Postscript_Name
     82         // Font config is not using it, yet.
     83         //https://bugs.freedesktop.org/show_bug.cgi?id=18095
     84 
     85         gPdfStandardFonts.set("Arial-Black", SkPdfStandardFontEntry("Arial", true, false));
     86         gPdfStandardFonts.set("DejaVuSans", SkPdfStandardFontEntry("DejaVu Sans", false, false));
     87         gPdfStandardFonts.set("DejaVuSansMono", SkPdfStandardFontEntry("DejaVuSans Mono", false, false));
     88         gPdfStandardFonts.set("DejaVuSansMono-Bold", SkPdfStandardFontEntry("DejaVuSans Mono", true, false));
     89         gPdfStandardFonts.set("DejaVuSansMono-Oblique", SkPdfStandardFontEntry("DejaVuSans Mono", false, true));
     90         gPdfStandardFonts.set("Georgia-Bold", SkPdfStandardFontEntry("Georgia", true, false));
     91         gPdfStandardFonts.set("Georgia-BoldItalic", SkPdfStandardFontEntry("Georgia", true, true));
     92         gPdfStandardFonts.set("Georgia-Italic", SkPdfStandardFontEntry("Georgia", false, true));
     93         gPdfStandardFonts.set("TrebuchetMS", SkPdfStandardFontEntry("Trebuchet MS", false, false));
     94         gPdfStandardFonts.set("TrebuchetMS-Bold", SkPdfStandardFontEntry("Trebuchet MS", true, false));
     95         gPdfStandardFonts.set("Verdana-Bold", SkPdfStandardFontEntry("Verdana", true, false));
     96         gPdfStandardFonts.set("WenQuanYiMicroHei", SkPdfStandardFontEntry("WenQuanYi Micro Hei", false, false));
     97 
     98         // TODO(edisonn): list all fonts available, buil post script name as in pdf spec
     99         // TODO(edisonn): Does it work in all OSs ?
    100         /*
    101          * The PostScript name for the value of BaseFontis determined in one of two ways:
    102  Use the PostScript name that is an optional entry in the name table of the
    103 TrueType font itself.
    104  In the absence of such an entry in the name table, derive a PostScript name
    105 from the name by which the font is known in the host operating system: on a
    106 Windows system, it is based on the lfFaceName eld in a LOGFONT structure; in
    107 the Mac OS, it is based on the name of the FONDresource. If the name contains
    108 any spaces, the spaces are removed.
    109 If the font in a source document uses a bold or italic style, but there is no font
    110 data for that style, the host operating system will synthesize the style. In this case,
    111 a comma and the style name (one of Bold, Italic, or BoldItalic) are appended to the
    112 font name. For example, for a TrueType font that is a bold variant of the New
    113          */
    114 
    115         /*
    116          * If the value of Subtype is MMType1.
    117  If the PostScript name of the instance contains spaces, the spaces are replaced
    118 by underscores in the value of BaseFont. For instance, as illustrated in Example
    119 5.7, the name MinionMM 366 465 11  (which ends with a space character)
    120 becomes /MinionMM_366_465_11_.
    121          */
    122     }
    123 
    124     return gPdfStandardFonts;
    125 }
    126 
    127 SkTypeface* SkTypefaceFromPdfStandardFont(const char* fontName, bool bold, bool italic) {
    128     SkTDict<SkPdfStandardFontEntry>& standardFontMap = getStandardFonts();
    129 
    130     SkTypeface* typeface = NULL;
    131     SkPdfStandardFontEntry fontData;
    132 
    133     if (standardFontMap.find(fontName, &fontData)) {
    134         // TODO(edisonn): How does the bold/italic specified in standard definition combines with
    135         // the one in /font key? use OR for now.
    136         bold = bold || fontData.fIsBold;
    137         italic = italic || fontData.fIsItalic;
    138 
    139         typeface = SkTypeface::CreateFromName(
    140             fontData.fName,
    141             SkTypeface::Style((bold ? SkTypeface::kBold : 0) |
    142                               (italic ? SkTypeface::kItalic : 0)));
    143     } else {
    144         typeface = SkTypeface::CreateFromName(
    145             fontName,
    146             SkTypeface::kNormal);
    147     }
    148 
    149     if (typeface) {
    150         typeface->ref();
    151     }
    152     return typeface;
    153 }
    154 
    155 SkPdfFont* SkPdfFont::fontFromFontDescriptor(SkPdfNativeDoc* doc, SkPdfFontDescriptorDictionary* fd,
    156                                              bool loadFromName) {
    157     // TODO(edisonn): partial implementation.
    158     // Only one, at most be available
    159     SkPdfStream* pdfStream = NULL;
    160     if (fd->has_FontFile()) {
    161         pdfStream = fd->FontFile(doc);
    162     } else if (fd->has_FontFile2()) {
    163         pdfStream = fd->FontFile2(doc);
    164     } if (fd->has_FontFile3()) {
    165         pdfStream = fd->FontFile3(doc);
    166     } else {
    167         if (loadFromName) {
    168             return fontFromName(doc, fd, fd->FontName(doc).c_str());
    169         }
    170     }
    171 
    172     const unsigned char* uncompressedStream = NULL;
    173     size_t uncompressedStreamLength = 0;
    174 
    175     // TODO(edisonn): report warning to be used in testing.
    176     if (!pdfStream ||
    177             !pdfStream->GetFilteredStreamRef(&uncompressedStream, &uncompressedStreamLength) ||
    178             !uncompressedStream ||
    179             !uncompressedStreamLength) {
    180         return NULL;
    181     }
    182 
    183     SkMemoryStream* skStream = new SkMemoryStream(uncompressedStream, uncompressedStreamLength);
    184     SkTypeface* face = SkTypeface::CreateFromStream(skStream);
    185 
    186     if (face == NULL) {
    187         // TODO(edisonn): report warning to be used in testing.
    188         return NULL;
    189     }
    190 
    191     face->ref();
    192 
    193     return new SkPdfStandardFont(face);
    194 }
    195 
    196 SkPdfFont* fontFromName(SkPdfNativeDoc* doc, SkPdfNativeObject* obj, const char* fontName) {
    197     SkTypeface* typeface = SkTypefaceFromPdfStandardFont(fontName, false, false);
    198     if (typeface != NULL) {
    199         return new SkPdfStandardFont(typeface);
    200     }
    201 
    202     // TODO(edisonn): perf - make a map
    203     for (unsigned int i = 0 ; i < doc->objects(); i++) {
    204         SkPdfNativeObject* obj = doc->object(i);
    205         if (!obj || !obj->isDictionary()) {
    206             continue;
    207         }
    208 
    209         SkPdfFontDescriptorDictionary* fd = obj->asDictionary()->asFontDescriptorDictionary();
    210 
    211         if (!fd->valid()) {
    212             continue;
    213         }
    214 
    215         if (fd->has_FontName() && fd->FontName(doc).equals(fontName)) {
    216             SkPdfFont* font = SkPdfFont::fontFromFontDescriptor(doc, fd, false);
    217             if (font) {
    218                 return font;
    219             } else {
    220                 // failed to load font descriptor
    221                 break;
    222             }
    223         }
    224     }
    225 
    226     // TODO(edisonn): warning/report issue
    227     return SkPdfFont::Default();
    228 }
    229 
    230 SkPdfFont* SkPdfFont::fontFromPdfDictionaryOnce(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict) {
    231     // TODO(edisonn): keep the type in a smart way in the SkPdfNativeObject
    232     // 1) flag, isResolved (1bit): reset at reset, add/remove/update (array) and set(dict)
    233     // in a tree like structure, 3-4 bits for all the datatypes inheriting from obj (int, real, ...)
    234     // if is a dict, reserve a few bytes to encode type of dict, and so on like in a tree
    235     // issue: type can be determined from context! atribute night be missing/wrong
    236     switch (doc->mapper()->mapFontDictionary(dict)) {
    237         case kType0FontDictionary_SkPdfNativeObjectType:
    238             return fontFromType0FontDictionary(doc, dict->asType0FontDictionary());
    239 
    240         case kTrueTypeFontDictionary_SkPdfNativeObjectType:
    241             return fontFromTrueTypeFontDictionary(doc, dict->asTrueTypeFontDictionary());
    242 
    243         case kType1FontDictionary_SkPdfNativeObjectType:
    244             return fontFromType1FontDictionary(doc, dict->asType1FontDictionary());
    245 
    246         case kMultiMasterFontDictionary_SkPdfNativeObjectType:
    247             return fontFromMultiMasterFontDictionary(doc, dict->asMultiMasterFontDictionary());
    248 
    249         case kType3FontDictionary_SkPdfNativeObjectType:
    250             return fontFromType3FontDictionary(doc, dict->asType3FontDictionary());
    251 
    252         default:
    253             // TODO(edisonn): report error?
    254             return NULL;
    255     }
    256 }
    257 
    258 SkPdfFont* SkPdfFont::fontFromPdfDictionary(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict) {
    259     if (dict == NULL) {
    260         return NULL;  // TODO(edisonn): report default one?
    261     }
    262 
    263     if (!dict->hasData(SkPdfNativeObject::kFont_Data)) {
    264         dict->setData(fontFromPdfDictionaryOnce(doc, dict), SkPdfNativeObject::kFont_Data);
    265     }
    266     return (SkPdfFont*)dict->data(SkPdfNativeObject::kFont_Data);
    267 }
    268 
    269 
    270 
    271 SkPdfType0Font* SkPdfFont::fontFromType0FontDictionary(SkPdfNativeDoc* doc,
    272                                                        SkPdfType0FontDictionary* dict) {
    273     if (dict == NULL) {
    274         return NULL;  // default one?
    275     }
    276 
    277     return new SkPdfType0Font(doc, dict);
    278 }
    279 
    280 SkPdfType1Font* SkPdfFont:: fontFromType1FontDictionary(SkPdfNativeDoc* doc,
    281                                                         SkPdfType1FontDictionary* dict) {
    282     if (dict == NULL) {
    283         return NULL;  // default one?
    284     }
    285 
    286     return new SkPdfType1Font(doc, dict);
    287 }
    288 
    289 SkPdfType3Font* SkPdfFont::fontFromType3FontDictionary(SkPdfNativeDoc* doc,
    290                                                        SkPdfType3FontDictionary* dict) {
    291     if (dict == NULL) {
    292         return NULL;  // default one?
    293     }
    294 
    295 
    296 
    297     return new SkPdfType3Font(doc, dict);
    298 }
    299 
    300 SkPdfTrueTypeFont* SkPdfFont::fontFromTrueTypeFontDictionary(SkPdfNativeDoc* doc,
    301                                                              SkPdfTrueTypeFontDictionary* dict) {
    302     if (dict == NULL) {
    303         return NULL;  // default one?
    304     }
    305 
    306     return new SkPdfTrueTypeFont(doc, dict);
    307 }
    308 
    309 SkPdfMultiMasterFont* SkPdfFont::fontFromMultiMasterFontDictionary(
    310         SkPdfNativeDoc* doc, SkPdfMultiMasterFontDictionary* dict) {
    311     if (dict == NULL) {
    312         return NULL;  // default one?
    313     }
    314 
    315     return new SkPdfMultiMasterFont(doc, dict);
    316 }
    317 
    318 static int skstoi(const SkPdfNativeObject* str) {
    319     // TODO(edisonn): report err of it is not a (hex) string
    320     int ret = 0;
    321     for (unsigned int i = 0 ; i < str->lenstr(); i++) {
    322         ret = (ret << 8) + ((unsigned char*)str->c_str())[i];
    323     }
    324     // TODO(edisonn): character larger than 0x0000ffff not supported right now.
    325     return ret & 0x0000ffff;
    326 }
    327 
    328 #define tokenIsKeyword(token,keyword) (token.fType == kKeyword_TokenType && \
    329                                       token.fKeywordLength==sizeof(keyword)-1 && \
    330                                       strncmp(token.fKeyword, keyword, sizeof(keyword)-1) == 0)
    331 
    332 SkPdfToUnicode::SkPdfToUnicode(SkPdfNativeDoc* parsed, SkPdfStream* stream) {
    333     fCMapEncoding = NULL;
    334     fCMapEncodingFlag = NULL;
    335 
    336     if (stream) {
    337         // Since font will be cached, the font has to sit in the per doc allocator, not to be
    338         // freed after the page is done drawing.
    339         SkPdfNativeTokenizer tokenizer(stream, parsed->allocator(), parsed);
    340         PdfToken token;
    341 
    342         fCMapEncoding = new unsigned short[256 * 256];
    343         fCMapEncodingFlag = new unsigned char[256 * 256];
    344         for (int i = 0 ; i < 256 * 256; i++) {
    345             fCMapEncoding[i] = i;
    346             fCMapEncodingFlag[i] = 0;
    347         }
    348 
    349         // TODO(edisonn): deal with multibyte character, or longer strings.
    350         // Right now we deal with up 2 characters, e.g. <0020> but not longer like <00660066006C>
    351         //2 beginbfrange
    352         //<0000> <005E> <0020>
    353         //<005F> <0061> [<00660066> <00660069> <00660066006C>]
    354 
    355         while (tokenizer.readToken(&token)) {
    356 
    357             if (tokenIsKeyword(token, "begincodespacerange")) {
    358                 while (tokenizer.readToken(&token) &&
    359                        !tokenIsKeyword(token, "endcodespacerange")) {
    360 //                    tokenizer.PutBack(token);
    361 //                    tokenizer.readToken(&token);
    362                     // TODO(edisonn): check token type! ignore/report errors.
    363                     int start = skstoi(token.fObject);
    364                     tokenizer.readToken(&token);
    365                     int end = skstoi(token.fObject);
    366                     for (int i = start; i <= end; i++) {
    367                         fCMapEncodingFlag[i] |= 1;
    368                     }
    369                 }
    370             }
    371 
    372             if (tokenIsKeyword(token, "beginbfchar")) {
    373                 while (tokenizer.readToken(&token) && !tokenIsKeyword(token, "endbfchar")) {
    374 //                    tokenizer.PutBack(token);
    375 //                    tokenizer.readToken(&token);
    376                     int from = skstoi(token.fObject);
    377                     tokenizer.readToken(&token);
    378                     int to = skstoi(token.fObject);
    379 
    380                     fCMapEncodingFlag[from] |= 2;
    381                     fCMapEncoding[from] = to;
    382                 }
    383             }
    384 
    385             if (tokenIsKeyword(token, "beginbfrange")) {
    386                 while (tokenizer.readToken(&token) && !tokenIsKeyword(token, "endbfrange")) {
    387 //                    tokenizer.PutBack(token);
    388 //                    tokenizer.readToken(&token);
    389                     int start = skstoi(token.fObject);
    390                     tokenizer.readToken(&token);
    391                     int end = skstoi(token.fObject);
    392 
    393 
    394                     tokenizer.readToken(&token); // [ or just an array directly?
    395                     // do not putback, we will reuse the read. See next commented read.
    396 //                    tokenizer.PutBack(token);
    397 
    398                     // TODO(edisonn): read spec: any string or only hex string?
    399                     if (token.fType == kObject_TokenType && token.fObject->isAnyString()) {
    400 //                        tokenizer.readToken(&token);
    401                         int value = skstoi(token.fObject);
    402 
    403                         for (int i = start; i <= end; i++) {
    404                             fCMapEncodingFlag[i] |= 2;
    405                             fCMapEncoding[i] = value;
    406                             value++;
    407                             // if i != end, verify last byte id not if, ignore/report error
    408                         }
    409 
    410                         // read one string
    411                     } else if (token.fType == kObject_TokenType && token.fObject->isArray()) {
    412 //                        tokenizer.readToken(&token);
    413                         // read array
    414                         for (unsigned int i = 0; i < token.fObject->size(); i++) {
    415                             fCMapEncodingFlag[start + i] |= 2;
    416                             fCMapEncoding[start + i] = skstoi((*token.fObject)[i]);
    417                         }
    418                     } else {
    419                         tokenizer.PutBack(token);
    420                     }
    421                 }
    422             }
    423         }
    424     }
    425 }
    426 
    427 SkPdfType0Font::SkPdfType0Font(SkPdfNativeDoc* doc, SkPdfType0FontDictionary* dict) {
    428     fBaseFont = fontFromName(doc, dict, dict->BaseFont(doc).c_str());
    429     fEncoding = NULL;
    430 
    431     if (dict->has_Encoding()) {
    432         if (dict->isEncodingAName(doc)) {
    433             fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName(doc).c_str());
    434         } else if (dict->isEncodingAStream(doc)) {
    435             // TODO(edisonn): NYI
    436             //fEncoding = loadEncodingFromStream(dict->getEncodingAsStream());
    437         } else {
    438             // TODO(edisonn): error ... warning .. assert?
    439         }
    440     }
    441 
    442     if (dict->has_ToUnicode()) {
    443         fToUnicode = new SkPdfToUnicode(doc, dict->ToUnicode(doc));
    444     }
    445 }
    446 
    447 SkTDict<SkPdfEncoding*>& getStandardEncodings() {
    448     static SkTDict<SkPdfEncoding*> encodings(10);
    449     if (encodings.count() == 0) {
    450         encodings.set("Identity-H", SkPdfIdentityHEncoding::instance());
    451     }
    452 
    453     return encodings;
    454 }
    455 
    456 SkPdfEncoding* SkPdfEncoding::fromName(const char* name) {
    457     SkPdfEncoding* encoding = NULL;
    458     if (!getStandardEncodings().find(name, &encoding)) {
    459         encoding = NULL;
    460     }
    461 
    462 #ifdef PDF_TRACE
    463     if (encoding == NULL) {
    464         printf("Encoding not found: %s\n", name);
    465     }
    466 #endif
    467     return encoding;
    468 }
    469