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
14SkTDict<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
103TrueType font itself.
104• In the absence of such an entry in the “name” table, derive a PostScript name
105from the name by which the font is known in the host operating system: on a
106Windows system, it is based on the lfFaceName field in a LOGFONT structure; in
107the Mac OS, it is based on the name of the FONDresource. If the name contains
108any spaces, the spaces are removed.
109If the font in a source document uses a bold or italic style, but there is no font
110data for that style, the host operating system will synthesize the style. In this case,
111a comma and the style name (one of Bold, Italic, or BoldItalic) are appended to the
112font 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
118by underscores in the value of BaseFont. For instance, as illustrated in Example
1195.7, the name “MinionMM 366 465 11 ” (which ends with a space character)
120becomes /MinionMM_366_465_11_.
121         */
122    }
123
124    return gPdfStandardFonts;
125}
126
127SkTypeface* 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
155SkPdfFont* 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
196SkPdfFont* 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
230SkPdfFont* 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
258SkPdfFont* 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
271SkPdfType0Font* 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
280SkPdfType1Font* 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
289SkPdfType3Font* 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
300SkPdfTrueTypeFont* 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
309SkPdfMultiMasterFont* 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
318static 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
332SkPdfToUnicode::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
427SkPdfType0Font::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
447SkTDict<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
456SkPdfEncoding* 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