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 
23 class SkPdfType0Font;
24 class SkPdfType1Font;
25 class SkPdfType3Font;
26 class SkPdfTrueTypeFont;
27 class SkPdfMultiMasterFont;
28 class SkPdfFont;
29 
30 struct SkPdfStandardFontEntry {
31     // We don't own this pointer!
32     const char* fName;
33     bool fIsBold;
34     bool fIsItalic;
SkPdfStandardFontEntrySkPdfStandardFontEntry35     SkPdfStandardFontEntry()
36     : fName(NULL),
37       fIsBold(false),
38       fIsItalic(false) {}
39 
SkPdfStandardFontEntrySkPdfStandardFontEntry40     SkPdfStandardFontEntry(const char* name, bool bold, bool italic)
41         : fName(name),
42           fIsBold(bold),
43           fIsItalic(italic) {}
44 };
45 
46 SkTDict<SkPdfStandardFontEntry>& getStandardFonts();
47 SkTypeface* SkTypefaceFromPdfStandardFont(const char* fontName, bool bold, bool italic);
48 SkPdfFont* fontFromName(SkPdfNativeDoc* doc, SkPdfNativeObject* obj, const char* fontName);
49 
50 struct SkUnencodedText {
51     void* text;
52     int len;
53 
54 public:
SkUnencodedTextSkUnencodedText55     SkUnencodedText(const SkPdfString* obj) {
56         text = (void*)obj->c_str();
57         len = (int) obj->lenstr();
58     }
59 };
60 
61 struct SkDecodedText {
62     uint16_t* text;
63     int len;
64 public:
65     unsigned int operator[](int i) const { return text[i]; }
sizeSkDecodedText66     int size() const { return len; }
67 };
68 
69 struct SkUnicodeText {
70     uint16_t* text;
71     int len;
72 
73 public:
74     unsigned int operator[](int i) const { return text[i]; }
sizeSkUnicodeText75     int size() const { return len; }
76 };
77 
78 class SkPdfEncoding {
79 public:
~SkPdfEncoding()80     virtual ~SkPdfEncoding() {}
81     virtual bool decodeText(const SkUnencodedText& textIn, SkDecodedText* textOut) const = 0;
82     static SkPdfEncoding* fromName(const char* name);
83 };
84 
85 SkTDict<SkPdfEncoding*>& getStandardEncodings();
86 
87 class SkPdfToUnicode {
88     // TODO(edisonn): hide public members
89 public:
90     unsigned short* fCMapEncoding;
91     unsigned char* fCMapEncodingFlag;
92 
93     SkPdfToUnicode(SkPdfNativeDoc* parsed, SkPdfStream* stream);
94 };
95 
96 
97 class SkPdfIdentityHEncoding : public SkPdfEncoding {
98 public:
~SkPdfIdentityHEncoding()99     virtual ~SkPdfIdentityHEncoding() {}
decodeText(const SkUnencodedText & textIn,SkDecodedText * textOut)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 
instance()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
121 class SkPdfDefaultEncoding : public SkPdfEncoding {
122 public:
~SkPdfDefaultEncoding()123     virtual ~SkPdfDefaultEncoding() {}
decodeText(const SkUnencodedText & textIn,SkDecodedText * textOut)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 
instance()138     static SkPdfDefaultEncoding* instance() {
139         static SkPdfDefaultEncoding* inst = new SkPdfDefaultEncoding();
140         return inst;
141     }
142 };
143 
144 class SkPdfCIDToGIDMapIdentityEncoding : public SkPdfEncoding {
145 public:
~SkPdfCIDToGIDMapIdentityEncoding()146     virtual ~SkPdfCIDToGIDMapIdentityEncoding() {}
decodeText(const SkUnencodedText & textIn,SkDecodedText * textOut)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 
instance()161     static SkPdfCIDToGIDMapIdentityEncoding* instance() {
162         static SkPdfCIDToGIDMapIdentityEncoding* inst = new SkPdfCIDToGIDMapIdentityEncoding();
163         return inst;
164     }
165 };
166 
167 class SkPdfFont {
168 public:
169     SkPdfFont* fBaseFont;
170     SkPdfEncoding* fEncoding;
171     SkPdfToUnicode* fToUnicode;
172 
173 
174 public:
SkPdfFont()175     SkPdfFont() : fBaseFont(NULL), fEncoding(SkPdfDefaultEncoding::instance()), fToUnicode(NULL) {}
176 
~SkPdfFont()177     virtual ~SkPdfFont() {
178         // TODO(edisonn): NYI (will leak for now)
179     }
180 
encoding()181     const SkPdfEncoding* encoding() const {return fEncoding;}
182 
drawText(const SkDecodedText & text,SkPaint * paint,SkPdfContext * pdfContext,SkCanvas * canvas)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 
ToUnicode(const SkDecodedText & textIn,SkUnicodeText * textOut)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 
ToUnicode(unsigned int ch)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);
Default()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 
251 public:
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 
256 private:
257     static SkPdfFont* fontFromPdfDictionaryOnce(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict);
258 };
259 
260 class SkPdfStandardFont : public SkPdfFont {
261     SkTypeface* fTypeface;
262 
263 public:
SkPdfStandardFont(SkTypeface * typeface)264     SkPdfStandardFont(SkTypeface* typeface) : fTypeface(typeface) {}
265 
266 public:
drawOneChar(unsigned int ch,SkPaint * paint,SkPdfContext * pdfContext,SkCanvas * canvas)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 
afterWord(SkPaint * paint,SkMatrix * matrix)282     virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {}
283 };
284 
285 class SkPdfType0Font : public SkPdfFont {
286 public:
287     SkPdfType0Font(SkPdfNativeDoc* doc, SkPdfType0FontDictionary* dict);
288 
289 public:
290 
drawOneChar(unsigned int ch,SkPaint * paint,SkPdfContext * pdfContext,SkCanvas * canvas)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 
afterWord(SkPaint * paint,SkMatrix * matrix)296     virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {
297     }
298 };
299 
300 class SkPdfType1Font : public SkPdfFont {
301 public:
SkPdfType1Font(SkPdfNativeDoc * doc,SkPdfType1FontDictionary * dict)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 
317 public:
drawOneChar(unsigned int ch,SkPaint * paint,SkPdfContext * pdfContext,SkCanvas * canvas)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 
afterWord(SkPaint * paint,SkMatrix * matrix)323       virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {
324 
325       }
326 };
327 
328 class SkPdfTrueTypeFont : public SkPdfType1Font {
329 public:
SkPdfTrueTypeFont(SkPdfNativeDoc * doc,SkPdfTrueTypeFontDictionary * dict)330     SkPdfTrueTypeFont(SkPdfNativeDoc* doc, SkPdfTrueTypeFontDictionary* dict)
331             : SkPdfType1Font(doc, dict) {}
332 };
333 
334 class SkPdfMultiMasterFont : public SkPdfType1Font {
335 public:
SkPdfMultiMasterFont(SkPdfNativeDoc * doc,SkPdfMultiMasterFontDictionary * dict)336     SkPdfMultiMasterFont(SkPdfNativeDoc* doc, SkPdfMultiMasterFontDictionary* dict)
337             : SkPdfType1Font(doc, dict) {}
338 };
339 /*
340 class CIDToGIDMap {
341     virtual unsigned int map(unsigned int cid) = 0;
342     static CIDToGIDMap* fromName(const char* name);
343 };
344 
345 class 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 
354 CIDToGIDMap* 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 }
366 CIDToGIDMap* fCidToGid;
367 */
368 
369 class 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 
385 public:
SkPdfType3Font(SkPdfNativeDoc * parsed,SkPdfType3FontDictionary * dict)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 
446 public:
drawOneChar(unsigned int ch,SkPaint * paint,SkPdfContext * pdfContext,SkCanvas * canvas)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 
afterWord(SkPaint * paint,SkMatrix * matrix)476     virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {}
477 };
478 
479 #endif  // SkPdfFont_DEFINED
480