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// TODO(edisonn): this file not commented much on purpose.
9// It will probably need heavy refactoring soon anyway to support all encodings, fonts and
10// proper text sizing and spacing
11
12#ifndef SkPdfFont_DEFINED
13#define SkPdfFont_DEFINED
14
15#include "SkPdfContext.h"
16#include "SkPdfHeaders_autogen.h"
17#include "SkPdfMapper_autogen.h"
18#include "SkPdfUtils.h"
19#include "SkTypeface.h"
20#include "SkTDict.h"
21#include "SkUtils.h"
22
23class SkPdfType0Font;
24class SkPdfType1Font;
25class SkPdfType3Font;
26class SkPdfTrueTypeFont;
27class SkPdfMultiMasterFont;
28class SkPdfFont;
29
30struct SkPdfStandardFontEntry {
31    // We don't own this pointer!
32    const char* fName;
33    bool fIsBold;
34    bool fIsItalic;
35    SkPdfStandardFontEntry()
36    : fName(NULL),
37      fIsBold(false),
38      fIsItalic(false) {}
39
40    SkPdfStandardFontEntry(const char* name, bool bold, bool italic)
41        : fName(name),
42          fIsBold(bold),
43          fIsItalic(italic) {}
44};
45
46SkTDict<SkPdfStandardFontEntry>& getStandardFonts();
47SkTypeface* SkTypefaceFromPdfStandardFont(const char* fontName, bool bold, bool italic);
48SkPdfFont* fontFromName(SkPdfNativeDoc* doc, SkPdfNativeObject* obj, const char* fontName);
49
50struct SkUnencodedText {
51    void* text;
52    int len;
53
54public:
55    SkUnencodedText(const SkPdfString* obj) {
56        text = (void*)obj->c_str();
57        len = (int) obj->lenstr();
58    }
59};
60
61struct SkDecodedText {
62    uint16_t* text;
63    int len;
64public:
65    unsigned int operator[](int i) const { return text[i]; }
66    int size() const { return len; }
67};
68
69struct SkUnicodeText {
70    uint16_t* text;
71    int len;
72
73public:
74    unsigned int operator[](int i) const { return text[i]; }
75    int size() const { return len; }
76};
77
78class SkPdfEncoding {
79public:
80    virtual ~SkPdfEncoding() {}
81    virtual bool decodeText(const SkUnencodedText& textIn, SkDecodedText* textOut) const = 0;
82    static SkPdfEncoding* fromName(const char* name);
83};
84
85SkTDict<SkPdfEncoding*>& getStandardEncodings();
86
87class SkPdfToUnicode {
88    // TODO(edisonn): hide public members
89public:
90    unsigned short* fCMapEncoding;
91    unsigned char* fCMapEncodingFlag;
92
93    SkPdfToUnicode(SkPdfNativeDoc* parsed, SkPdfStream* stream);
94};
95
96
97class SkPdfIdentityHEncoding : public SkPdfEncoding {
98public:
99    virtual ~SkPdfIdentityHEncoding() {}
100    virtual bool decodeText(const SkUnencodedText& textIn, SkDecodedText* textOut) const {
101        // TODO(edisonn): SkASSERT(textIn.len % 2 == 0); or report error?
102
103        uint16_t* text = (uint16_t*)textIn.text;
104        textOut->text = new uint16_t[textIn.len / 2];
105        textOut->len = textIn.len / 2;
106
107        for (int i = 0; i < textOut->len; i++) {
108            textOut->text[i] = ((text[i] << 8) & 0xff00) | ((text[i] >> 8) & 0x00ff);
109        }
110
111        return true;
112    }
113
114    static SkPdfIdentityHEncoding* instance() {
115        static SkPdfIdentityHEncoding* inst = new SkPdfIdentityHEncoding();
116        return inst;
117    }
118};
119
120// TODO(edisonn): using this one when no encoding is specified
121class SkPdfDefaultEncoding : public SkPdfEncoding {
122public:
123    virtual ~SkPdfDefaultEncoding() {}
124    virtual bool decodeText(const SkUnencodedText& textIn, SkDecodedText* textOut) const {
125        // TODO(edisonn): SkASSERT(textIn.len % 2 == 0); or report error?
126
127        unsigned char* text = (unsigned char*)textIn.text;
128        textOut->text = new uint16_t[textIn.len];
129        textOut->len = textIn.len;
130
131        for (int i = 0; i < textOut->len; i++) {
132            textOut->text[i] = text[i];
133        }
134
135        return true;
136    }
137
138    static SkPdfDefaultEncoding* instance() {
139        static SkPdfDefaultEncoding* inst = new SkPdfDefaultEncoding();
140        return inst;
141    }
142};
143
144class SkPdfCIDToGIDMapIdentityEncoding : public SkPdfEncoding {
145public:
146    virtual ~SkPdfCIDToGIDMapIdentityEncoding() {}
147    virtual bool decodeText(const SkUnencodedText& textIn, SkDecodedText* textOut) const {
148        // TODO(edisonn): SkASSERT(textIn.len % 2 == 0); or report error?
149
150        uint16_t* text = (uint16_t*)textIn.text;
151        textOut->text = new uint16_t[textIn.len / 2];
152        textOut->len = textIn.len / 2;
153
154        for (int i = 0; i < textOut->len; i++) {
155            textOut->text[i] = ((text[i] << 8) & 0xff00) | ((text[i] >> 8) & 0x00ff);
156        }
157
158        return true;
159    }
160
161    static SkPdfCIDToGIDMapIdentityEncoding* instance() {
162        static SkPdfCIDToGIDMapIdentityEncoding* inst = new SkPdfCIDToGIDMapIdentityEncoding();
163        return inst;
164    }
165};
166
167class SkPdfFont {
168public:
169    SkPdfFont* fBaseFont;
170    SkPdfEncoding* fEncoding;
171    SkPdfToUnicode* fToUnicode;
172
173
174public:
175    SkPdfFont() : fBaseFont(NULL), fEncoding(SkPdfDefaultEncoding::instance()), fToUnicode(NULL) {}
176
177    virtual ~SkPdfFont() {
178        // TODO(edisonn): NYI (will leak for now)
179    }
180
181    const SkPdfEncoding* encoding() const {return fEncoding;}
182
183    void drawText(const SkDecodedText& text, SkPaint* paint, SkPdfContext* pdfContext,
184                  SkCanvas* canvas) {
185        for (int i = 0 ; i < text.size(); i++) {
186            canvas->setMatrix(pdfContext->fGraphicsState.fMatrixTm);
187#ifdef PDF_TRACE
188            SkPoint point = SkPoint::Make(SkDoubleToScalar(0), SkDoubleToScalar(0));
189            pdfContext->fGraphicsState.fMatrixTm.mapPoints(&point, 1);
190            printf("DrawText at (%f, %f)\n", SkScalarToDouble(point.x()),
191                                             SkScalarToDouble(point.y()));
192#endif  // PDF_TRACE
193
194#ifdef PDF_TRACE_DRAWTEXT
195            SkPaint col;
196            col.setColor(SK_ColorMAGENTA);
197            SkRect rect = SkRect::MakeXYWH(SkDoubleToScalar(0.0),
198                                           SkDoubleToScalar(0.0),
199                                           SkDoubleToScalar(10.0),
200                                           SkDoubleToScalar(10.0));
201            canvas->save();
202            canvas->setMatrix(pdfContext->fGraphicsState.fMatrixTm);
203            canvas->drawRect(rect, col);
204            canvas->restore();
205#endif
206            double width = drawOneChar(text[i], paint, pdfContext, canvas);
207            pdfContext->fGraphicsState.fMatrixTm.preTranslate(SkDoubleToScalar(width),
208                                                              SkDoubleToScalar(0.0));
209        }
210    }
211
212    void ToUnicode(const SkDecodedText& textIn, SkUnicodeText* textOut) const {
213        if (fToUnicode) {
214            textOut->text = new uint16_t[textIn.len];
215            textOut->len = textIn.len;
216            for (int i = 0; i < textIn.len; i++) {
217                textOut->text[i] = fToUnicode->fCMapEncoding[textIn.text[i]];
218            }
219        } else {
220            textOut->text = textIn.text;
221            textOut->len = textIn.len;
222        }
223    };
224
225    inline unsigned int ToUnicode(unsigned int ch) const {
226        if (fToUnicode && fToUnicode->fCMapEncoding) {
227            return fToUnicode->fCMapEncoding[ch];
228        } else {
229            return ch;
230        }
231    };
232
233    static SkPdfFont* fontFromPdfDictionary(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict);
234    static SkPdfFont* Default() {return fontFromName(NULL, NULL, "TimesNewRoman");}
235
236    static SkPdfType0Font* fontFromType0FontDictionary(SkPdfNativeDoc* doc,
237                                                       SkPdfType0FontDictionary* dict);
238    static SkPdfType1Font* fontFromType1FontDictionary(SkPdfNativeDoc* doc,
239                                                       SkPdfType1FontDictionary* dict);
240    static SkPdfType3Font* fontFromType3FontDictionary(SkPdfNativeDoc* doc,
241                                                       SkPdfType3FontDictionary* dict);
242    static SkPdfTrueTypeFont* fontFromTrueTypeFontDictionary(SkPdfNativeDoc* doc,
243                                                             SkPdfTrueTypeFontDictionary* dict);
244    static SkPdfMultiMasterFont* fontFromMultiMasterFontDictionary(
245            SkPdfNativeDoc* doc, SkPdfMultiMasterFontDictionary* dict);
246
247    static SkPdfFont* fontFromFontDescriptor(SkPdfNativeDoc* doc,
248                                             SkPdfFontDescriptorDictionary* fd,
249                                             bool loadFromName = true);
250
251public:
252    virtual double drawOneChar(unsigned int ch, SkPaint* paint, SkPdfContext* pdfContext,
253                               SkCanvas* canvas) = 0;
254    virtual void afterWord(SkPaint* paint, SkMatrix* matrix) = 0;
255
256private:
257    static SkPdfFont* fontFromPdfDictionaryOnce(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict);
258};
259
260class SkPdfStandardFont : public SkPdfFont {
261    SkTypeface* fTypeface;
262
263public:
264    SkPdfStandardFont(SkTypeface* typeface) : fTypeface(typeface) {}
265
266public:
267    virtual double drawOneChar(unsigned int ch, SkPaint* paint, SkPdfContext* pdfContext,
268                               SkCanvas* canvas) {
269        paint->setTypeface(fTypeface);
270        paint->setTextEncoding(SkPaint::kUTF8_TextEncoding);
271
272        unsigned long ch4 = ch;
273        char utf8[10];
274        size_t len = SkUTF8_FromUnichar((SkUnichar) ch4, utf8);
275
276        canvas->drawText(utf8, len, SkDoubleToScalar(0), SkDoubleToScalar(0), *paint);
277
278        SkScalar textWidth = paint->measureText(utf8, len);
279        return SkScalarToDouble(textWidth);
280    }
281
282    virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {}
283};
284
285class SkPdfType0Font : public SkPdfFont {
286public:
287    SkPdfType0Font(SkPdfNativeDoc* doc, SkPdfType0FontDictionary* dict);
288
289public:
290
291    virtual double drawOneChar(unsigned int ch, SkPaint* paint, SkPdfContext* pdfContext,
292                               SkCanvas* canvas) {
293        return fBaseFont->drawOneChar(ToUnicode(ch), paint, pdfContext, canvas);
294    }
295
296    virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {
297    }
298};
299
300class SkPdfType1Font : public SkPdfFont {
301public:
302    SkPdfType1Font(SkPdfNativeDoc* doc, SkPdfType1FontDictionary* dict) {
303        if (dict->has_FontDescriptor()) {
304            fBaseFont = SkPdfFont::fontFromFontDescriptor(doc, dict->FontDescriptor(doc));
305        } else {
306            fBaseFont = fontFromName(doc, dict, dict->BaseFont(doc).c_str());
307        }
308
309        if (dict->isEncodingAName(doc)) {
310            fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName(doc).c_str());
311        } else if (dict->isEncodingADictionary(doc)) {
312            //SkPdfDictionary* dictEnc = dict->getEncodingAsDictionary(doc);
313        }
314        dict->FontDescriptor(doc);
315    }
316
317public:
318      virtual double drawOneChar(unsigned int ch, SkPaint* paint, SkPdfContext* pdfContext,
319                                 SkCanvas* canvas) {
320          return fBaseFont->drawOneChar(ToUnicode(ch), paint, pdfContext, canvas);
321      }
322
323      virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {
324
325      }
326};
327
328class SkPdfTrueTypeFont : public SkPdfType1Font {
329public:
330    SkPdfTrueTypeFont(SkPdfNativeDoc* doc, SkPdfTrueTypeFontDictionary* dict)
331            : SkPdfType1Font(doc, dict) {}
332};
333
334class SkPdfMultiMasterFont : public SkPdfType1Font {
335public:
336    SkPdfMultiMasterFont(SkPdfNativeDoc* doc, SkPdfMultiMasterFontDictionary* dict)
337            : SkPdfType1Font(doc, dict) {}
338};
339/*
340class CIDToGIDMap {
341    virtual unsigned int map(unsigned int cid) = 0;
342    static CIDToGIDMap* fromName(const char* name);
343};
344
345class CIDToGIDMap_Identity {
346    virtual unsigned int map(unsigned int cid) { return cid; }
347
348    static CIDToGIDMap_Identity* instance() {
349        static CIDToGIDMap_Identity* inst = new CIDToGIDMap_Identity();
350        return inst;
351    }
352};
353
354CIDToGIDMap* CIDToGIDMap::fromName(const char* name) {
355    // The only one supported right now is Identity
356    if (strcmp(name, "Identity") == 0) {
357        return CIDToGIDMap_Identity::instance();
358    }
359
360#ifdef PDF_TRACE
361    // TODO(edisonn): warning/report
362    printf("Unknown CIDToGIDMap: %s\n", name);
363#endif
364    return NULL;
365}
366CIDToGIDMap* fCidToGid;
367*/
368
369class SkPdfType3Font : public SkPdfFont {
370    struct Type3FontChar {
371        SkPdfNativeObject* fObj;
372        double fWidth;
373    };
374
375    SkPdfDictionary* fCharProcs;
376    SkPdfEncodingDictionary* fEncodingDict;
377    unsigned int fFirstChar;
378    unsigned int fLastChar;
379
380    SkRect fFontBBox;
381    SkMatrix fFonMatrix;
382
383    Type3FontChar* fChars;
384
385public:
386    SkPdfType3Font(SkPdfNativeDoc* parsed, SkPdfType3FontDictionary* dict) {
387        fBaseFont = fontFromName(parsed, dict, dict->BaseFont(parsed).c_str());
388
389        if (dict->has_Encoding()) {
390            if (dict->isEncodingAName(parsed)) {
391                 fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName(parsed).c_str());
392            } else if (dict->isEncodingAEncodingdictionary(parsed)) {
393                 // No encoding.
394                 fEncoding = SkPdfDefaultEncoding::instance();
395                 fEncodingDict = dict->getEncodingAsEncodingdictionary(parsed);
396            }
397        }
398
399        // null?
400        fCharProcs = dict->CharProcs(parsed);
401
402        fToUnicode = NULL;
403        if (dict->has_ToUnicode()) {
404            fToUnicode = new SkPdfToUnicode(parsed, dict->ToUnicode(parsed));
405        }
406
407        fFirstChar = (unsigned int)dict->FirstChar(parsed);
408        fLastChar = (unsigned int)dict->LastChar(parsed);
409        fFonMatrix = dict->has_FontMatrix() ? dict->FontMatrix(parsed) : SkMatrix::I();
410
411        if (dict->has_FontBBox()) {
412            fFontBBox = dict->FontBBox(parsed);
413        }
414
415        fChars = new Type3FontChar[fLastChar - fFirstChar + 1];
416
417        memset(fChars, 0, sizeof(fChars[0]) * (fLastChar - fFirstChar + 1));
418
419        const SkPdfArray* widths = dict->Widths(parsed);
420        for (unsigned int i = 0 ; i < widths->size(); i++) {
421            if ((fFirstChar + i) >= fFirstChar && (fFirstChar + i) <= fLastChar) {
422                fChars[i].fWidth = (*widths)[i]->numberValue();
423            } else {
424                // TODO(edisonn): report pdf corruption
425            }
426        }
427
428        const SkPdfArray* diffs = fEncodingDict->Differences(parsed);
429        unsigned int j = fFirstChar;
430        for (unsigned int i = 0 ; i < diffs->size(); i++) {
431            if ((*diffs)[i]->isInteger()) {
432                j = (unsigned int)(*diffs)[i]->intValue();
433            } else if ((*diffs)[i]->isName()) {
434                if (j >= fFirstChar && j <= fLastChar) {
435                    fChars[j - fFirstChar].fObj = fCharProcs->get((*diffs)[i]);
436                } else {
437                    // TODO(edisonn): report pdf corruption
438                }
439                j++;
440            } else {
441                // TODO(edisonn): report bad pdf
442            }
443        }
444    }
445
446public:
447    virtual double drawOneChar(unsigned int ch, SkPaint* paint, SkPdfContext* pdfContext,
448                               SkCanvas* canvas) {
449        if (ch < fFirstChar || ch > fLastChar || !fChars[ch - fFirstChar].fObj) {
450            return fBaseFont->drawOneChar(ToUnicode(ch), paint, pdfContext, canvas);
451        }
452
453#ifdef PDF_TRACE
454        printf("Type 3 char to unicode: %c\n", ToUnicode(ch));
455        if (ToUnicode(ch) == 'A') {
456            printf("break;\n");
457        }
458#endif
459
460        // TODO(edisonn): is it better to resolve the reference at load time, or now?
461        doType3Char(pdfContext,
462                    canvas,
463                    pdfContext->fPdfDoc->resolveReference(fChars[ch - fFirstChar].fObj),
464                    fFontBBox,
465                    fFonMatrix,
466                    pdfContext->fGraphicsState.fCurFontSize);
467
468        // TODO(edisonn): verify/test translate code, not tested yet
469        pdfContext->fGraphicsState.fMatrixTm.preTranslate(
470                SkDoubleToScalar(pdfContext->fGraphicsState.fCurFontSize *
471                                     fChars[ch - fFirstChar].fWidth),
472                SkDoubleToScalar(0.0));
473        return fChars[ch - fFirstChar].fWidth;
474    }
475
476    virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {}
477};
478
479#endif  // SkPdfFont_DEFINED
480