blob: 8170453508833778de5623d2ce87283e82dbcb55 [file] [log] [blame]
edisonn@google.com1be794f2013-06-21 21:43:09 +00001#include "SkPdfFont.h"
edisonn@google.com131d4ee2013-06-26 17:48:12 +00002#include "SkPdfParser.h"
edisonn@google.com1be794f2013-06-21 21:43:09 +00003
edisonn@google.comeee4b652013-06-27 13:22:42 +00004#include "SkStream.h"
5#include "SkTypeface.h"
6
edisonn@google.com1be794f2013-06-21 21:43:09 +00007std::map<std::string, SkPdfStandardFontEntry>& getStandardFonts() {
8 static std::map<std::string, SkPdfStandardFontEntry> gPdfStandardFonts;
9
10 // TODO (edisonn): , vs - ? what does it mean?
11 // TODO (edisonn): MT, PS, Oblique=italic?, ... what does it mean?
12 if (gPdfStandardFonts.empty()) {
13 gPdfStandardFonts["Arial"] = {"Arial", false, false};
14 gPdfStandardFonts["Arial,Bold"] = {"Arial", true, false};
15 gPdfStandardFonts["Arial,BoldItalic"] = {"Arial", true, true};
16 gPdfStandardFonts["Arial,Italic"] = {"Arial", false, true};
17 gPdfStandardFonts["Arial-Bold"] = {"Arial", true, false};
18 gPdfStandardFonts["Arial-BoldItalic"] = {"Arial", true, true};
19 gPdfStandardFonts["Arial-BoldItalicMT"] = {"Arial", true, true};
20 gPdfStandardFonts["Arial-BoldMT"] = {"Arial", true, false};
21 gPdfStandardFonts["Arial-Italic"] = {"Arial", false, true};
22 gPdfStandardFonts["Arial-ItalicMT"] = {"Arial", false, true};
23 gPdfStandardFonts["ArialMT"] = {"Arial", false, false};
24 gPdfStandardFonts["Courier"] = {"Courier New", false, false};
25 gPdfStandardFonts["Courier,Bold"] = {"Courier New", true, false};
26 gPdfStandardFonts["Courier,BoldItalic"] = {"Courier New", true, true};
27 gPdfStandardFonts["Courier,Italic"] = {"Courier New", false, true};
28 gPdfStandardFonts["Courier-Bold"] = {"Courier New", true, false};
29 gPdfStandardFonts["Courier-BoldOblique"] = {"Courier New", true, true};
30 gPdfStandardFonts["Courier-Oblique"] = {"Courier New", false, true};
31 gPdfStandardFonts["CourierNew"] = {"Courier New", false, false};
32 gPdfStandardFonts["CourierNew,Bold"] = {"Courier New", true, false};
33 gPdfStandardFonts["CourierNew,BoldItalic"] = {"Courier New", true, true};
34 gPdfStandardFonts["CourierNew,Italic"] = {"Courier New", false, true};
35 gPdfStandardFonts["CourierNew-Bold"] = {"Courier New", true, false};
36 gPdfStandardFonts["CourierNew-BoldItalic"] = {"Courier New", true, true};
37 gPdfStandardFonts["CourierNew-Italic"] = {"Courier New", false, true};
38 gPdfStandardFonts["CourierNewPS-BoldItalicMT"] = {"Courier New", true, true};
39 gPdfStandardFonts["CourierNewPS-BoldMT"] = {"Courier New", true, false};
40 gPdfStandardFonts["CourierNewPS-ItalicMT"] = {"Courier New", false, true};
41 gPdfStandardFonts["CourierNewPSMT"] = {"Courier New", false, false};
42 gPdfStandardFonts["Helvetica"] = {"Helvetica", false, false};
43 gPdfStandardFonts["Helvetica,Bold"] = {"Helvetica", true, false};
44 gPdfStandardFonts["Helvetica,BoldItalic"] = {"Helvetica", true, true};
45 gPdfStandardFonts["Helvetica,Italic"] = {"Helvetica", false, true};
46 gPdfStandardFonts["Helvetica-Bold"] = {"Helvetica", true, false};
47 gPdfStandardFonts["Helvetica-BoldItalic"] = {"Helvetica", true, true};
48 gPdfStandardFonts["Helvetica-BoldOblique"] = {"Helvetica", true, true};
49 gPdfStandardFonts["Helvetica-Italic"] = {"Helvetica", false, true};
50 gPdfStandardFonts["Helvetica-Oblique"] = {"Helvetica", false, true};
51 gPdfStandardFonts["Times-Bold"] = {"Times New Roman", true, false};
52 gPdfStandardFonts["Times-BoldItalic"] = {"Times New Roman", true, true};
53 gPdfStandardFonts["Times-Italic"] = {"Times New Roman", false, true};
54 gPdfStandardFonts["Times-Roman"] = {"Times New Roman", false, false};
55 gPdfStandardFonts["TimesNewRoman"] = {"Times New Roman", false, false};
56 gPdfStandardFonts["TimesNewRoman,Bold"] = {"Times New Roman", true, false};
57 gPdfStandardFonts["TimesNewRoman,BoldItalic"] = {"Times New Roman", true, true};
58 gPdfStandardFonts["TimesNewRoman,Italic"] = {"Times New Roman", false, true};
59 gPdfStandardFonts["TimesNewRoman-Bold"] = {"Times New Roman", true, false};
60 gPdfStandardFonts["TimesNewRoman-BoldItalic"] = {"Times New Roman", true, true};
61 gPdfStandardFonts["TimesNewRoman-Italic"] = {"Times New Roman", false, true};
62 gPdfStandardFonts["TimesNewRomanPS"] = {"Times New Roman", false, false};
63 gPdfStandardFonts["TimesNewRomanPS-Bold"] = {"Times New Roman", true, false};
64 gPdfStandardFonts["TimesNewRomanPS-BoldItalic"] = {"Times New Roman", true, true};
65 gPdfStandardFonts["TimesNewRomanPS-BoldItalicMT"] = {"Times New Roman", true, true};
66 gPdfStandardFonts["TimesNewRomanPS-BoldMT"] = {"Times New Roman", true, false};
67 gPdfStandardFonts["TimesNewRomanPS-Italic"] = {"Times New Roman", false, true};
68 gPdfStandardFonts["TimesNewRomanPS-ItalicMT"] = {"Times New Roman", false, true};
69 gPdfStandardFonts["TimesNewRomanPSMT"] = {"Times New Roman", false, false};
70 gPdfStandardFonts["Symbol"] = {"Symbol", false, false};
71 gPdfStandardFonts["ZapfDingbats"] = {"ZapfDingbats", false, false};
72
73 // TODO(edisonn): these are hacks. Load Post Script font name.
74 // see FT_Get_Postscript_Name
75 // Font config is not using it, yet.
76 //https://bugs.freedesktop.org/show_bug.cgi?id=18095
edisonn@google.comb857a0c2013-06-25 20:45:40 +000077
edisonn@google.com1be794f2013-06-21 21:43:09 +000078 gPdfStandardFonts["Arial-Black"] = {"Arial", true, false};
79 gPdfStandardFonts["DejaVuSans"] = {"DejaVu Sans", false, false};
80 gPdfStandardFonts["DejaVuSansMono"] = {"DejaVuSans Mono", false, false};
81 gPdfStandardFonts["DejaVuSansMono-Bold"] = {"DejaVuSans Mono", true, false};
82 gPdfStandardFonts["DejaVuSansMono-Oblique"] = {"DejaVuSans Mono", false, true};
83 gPdfStandardFonts["Georgia-Bold"] = {"Georgia", true, false};
84 gPdfStandardFonts["Georgia-BoldItalic"] = {"Georgia", true, true};
85 gPdfStandardFonts["Georgia-Italic"] = {"Georgia", false, true};
86 gPdfStandardFonts["TrebuchetMS"] = {"Trebuchet MS", false, false};
87 gPdfStandardFonts["TrebuchetMS-Bold"] = {"Trebuchet MS", true, false};
88 gPdfStandardFonts["Verdana-Bold"] = {"Verdana", true, false};
89 gPdfStandardFonts["WenQuanYiMicroHei"] = {"WenQuanYi Micro Hei", false, false};
edisonn@google.comb857a0c2013-06-25 20:45:40 +000090
91 // TODO(edisonn): list all phonts available, builf post script name as in pdf spec
92 /*
93 * The PostScript name for the value of BaseFontis determined in one of two ways:
94• Use the PostScript name that is an optional entry in the “name” table of the
95TrueType font itself.
96• In the absence of such an entry in the “name” table, derive a PostScript name
97from the name by which the font is known in the host operating system: on a
98Windows system, it is based on the lfFaceName field in a LOGFONT structure; in
99the Mac OS, it is based on the name of the FONDresource. If the name contains
100any spaces, the spaces are removed.
101If the font in a source document uses a bold or italic style, but there is no font
102data for that style, the host operating system will synthesize the style. In this case,
103a comma and the style name (one of Bold, Italic, or BoldItalic) are appended to the
104font name. For example, for a TrueType font that is a bold variant of the New
105 */
106
107 /*
108 * If the value of Subtype is MMType1.
109• If the PostScript name of the instance contains spaces, the spaces are replaced
110by underscores in the value of BaseFont. For instance, as illustrated in Example
1115.7, the name “MinionMM 366 465 11 ” (which ends with a space character)
112becomes /MinionMM_366_465_11_.
113 */
114
115 // might not work on all oses ?
116 //
117
edisonn@google.com1be794f2013-06-21 21:43:09 +0000118 }
119
120 return gPdfStandardFonts;
121}
122
123SkTypeface* SkTypefaceFromPdfStandardFont(const char* fontName, bool bold, bool italic) {
124 std::map<std::string, SkPdfStandardFontEntry>& standardFontMap = getStandardFonts();
125
126 SkTypeface* typeface = NULL;
127 if (standardFontMap.find(fontName) != standardFontMap.end()) {
128 SkPdfStandardFontEntry fontData = standardFontMap[fontName];
129
130 // TODO(edisonn): How does the bold/italic specified in standard definition combines with
131 // the one in /font key? use OR for now.
132 bold = bold || fontData.fIsBold;
133 italic = italic || fontData.fIsItalic;
134
135 typeface = SkTypeface::CreateFromName(
136 fontData.fName,
137 SkTypeface::Style((bold ? SkTypeface::kBold : 0) |
138 (italic ? SkTypeface::kItalic : 0)));
139 } else {
140 typeface = SkTypeface::CreateFromName(
141 fontName,
142 SkTypeface::kNormal);
143 }
144
145 if (typeface) {
146 typeface->ref();
147 }
148 return typeface;
149}
150
edisonn@google.com6e49c342013-06-27 20:03:43 +0000151SkPdfFont* SkPdfFont::fontFromFontDescriptor(SkPdfFontDescriptorDictionary* fd, bool loadFromName) {
152 // TODO(edisonn): partial implementation
edisonn@google.comeee4b652013-06-27 13:22:42 +0000153 // Only one, at most be available
edisonn@google.com6e49c342013-06-27 20:03:43 +0000154 SkPdfStream* pdfStream = NULL;
edisonn@google.comeee4b652013-06-27 13:22:42 +0000155 if (fd->has_FontFile()) {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000156 pdfStream = fd->FontFile();
edisonn@google.comeee4b652013-06-27 13:22:42 +0000157 } else if (fd->has_FontFile2()) {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000158 pdfStream = fd->FontFile2();
edisonn@google.comeee4b652013-06-27 13:22:42 +0000159 } if (fd->has_FontFile3()) {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000160 pdfStream = fd->FontFile3();
edisonn@google.comeee4b652013-06-27 13:22:42 +0000161 } else {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000162 if (loadFromName) {
163 return fontFromName(fd, fd->FontName().c_str());
164 }
edisonn@google.comeee4b652013-06-27 13:22:42 +0000165 }
166
edisonn@google.com6e49c342013-06-27 20:03:43 +0000167 if (!pdfStream || !pdfStream->podofo()->GetStream()) {
168 // TODO(edisonn): report warning to be used in testing.
169 return NULL;
170 }
171
172 char* uncompressedStream = NULL;
173 pdf_long uncompressedStreamLength = 0;
174
175 // TODO(edisonn): get rid of try/catch exceptions! We should not throw on user data!
176 try {
177 pdfStream->podofo()->GetStream()->GetFilteredCopy(&uncompressedStream, &uncompressedStreamLength);
178 } catch (PdfError& e) {
179 // TODO(edisonn): report warning to be used in testing.
180 return NULL;
181 }
182 SkMemoryStream* skStream = new SkMemoryStream(uncompressedStream, uncompressedStreamLength);
183 SkTypeface* face = SkTypeface::CreateFromStream(skStream);
184
185 if (face == NULL) {
186 // TODO(edisonn): report warning to be used in testing.
187 return NULL;
188 }
189
190 face->ref();
191
192 return new SkPdfStandardFont(face);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000193}
194
edisonn@google.com6e49c342013-06-27 20:03:43 +0000195SkPdfFont* fontFromName(SkPdfObject* obj, const char* fontName) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000196 SkTypeface* typeface = SkTypefaceFromPdfStandardFont(fontName, false, false);
197 if (typeface != NULL) {
198 return new SkPdfStandardFont(typeface);
199 }
edisonn@google.comeee4b652013-06-27 13:22:42 +0000200
201 // TODO(edisonn): perf - make a map
202 for (int i = 0 ; i < obj->doc()->GetObjects().GetSize(); i++) {
203 PdfVecObjects& objects = (PdfVecObjects&)obj->doc()->GetObjects();
204 const PdfObject* podofoFont = objects[i];
205 SkPdfFontDescriptorDictionary* fd = NULL;
206 if (mapFontDescriptorDictionary(*obj->doc(), *podofoFont, &fd)) {
207 if (fd->has_FontName() && fd->FontName() == fontName) {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000208 SkPdfFont* font = SkPdfFont::fontFromFontDescriptor(fd, false);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000209 if (font) {
210 return font;
211 } else {
212 // failed to load font descriptor
213 break;
214 }
215 }
216 }
217 }
218
219 // TODO(edisonn): warning/report issue
edisonn@google.com1be794f2013-06-21 21:43:09 +0000220 return SkPdfFont::Default();
221}
222
223SkPdfFont* SkPdfFont::fontFromPdfDictionary(SkPdfFontDictionary* dict) {
224 if (dict == NULL) {
225 return NULL; // TODO(edisonn): report default one?
226 }
227
228 switch (dict->getType()) {
229 case kType0FontDictionary_SkPdfObjectType:
230 return fontFromType0FontDictionary(dict->asType0FontDictionary());
231
232 case kTrueTypeFontDictionary_SkPdfObjectType:
233 return fontFromTrueTypeFontDictionary(dict->asTrueTypeFontDictionary());
234
235 case kType1FontDictionary_SkPdfObjectType:
236 return fontFromType1FontDictionary(dict->asType1FontDictionary());
237
edisonn@google.com1be794f2013-06-21 21:43:09 +0000238 case kMultiMasterFontDictionary_SkPdfObjectType:
239 return fontFromMultiMasterFontDictionary(dict->asMultiMasterFontDictionary());
240
241 case kType3FontDictionary_SkPdfObjectType:
242 return fontFromType3FontDictionary(dict->asType3FontDictionary());
243 }
244 return NULL; // TODO(edisonn): report error?
245}
246
247SkPdfType0Font* SkPdfFont::fontFromType0FontDictionary(SkPdfType0FontDictionary* dict) {
248 if (dict == NULL) {
249 return NULL; // default one?
250 }
251
252 return new SkPdfType0Font(dict);
253}
254
255SkPdfType1Font* SkPdfFont:: fontFromType1FontDictionary(SkPdfType1FontDictionary* dict) {
256 if (dict == NULL) {
257 return NULL; // default one?
258 }
259
260 return new SkPdfType1Font(dict);
261}
262
263SkPdfType3Font* SkPdfFont::fontFromType3FontDictionary(SkPdfType3FontDictionary* dict) {
264 if (dict == NULL) {
265 return NULL; // default one?
266 }
267
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000268
269
edisonn@google.com1be794f2013-06-21 21:43:09 +0000270 return new SkPdfType3Font(dict);
271}
272
273SkPdfTrueTypeFont* SkPdfFont::fontFromTrueTypeFontDictionary(SkPdfTrueTypeFontDictionary* dict) {
274 if (dict == NULL) {
275 return NULL; // default one?
276 }
277
278 return new SkPdfTrueTypeFont(dict);
279}
280
edisonn@google.com1be794f2013-06-21 21:43:09 +0000281SkPdfMultiMasterFont* SkPdfFont::fontFromMultiMasterFontDictionary(SkPdfMultiMasterFontDictionary* dict) {
282 if (dict == NULL) {
283 return NULL; // default one?
284 }
285
286 return new SkPdfMultiMasterFont(dict);
287}
288
289static int skstoi(const SkPdfString* str) {
290 int ret = 0;
291 for (int i = 0 ; i < str->podofo()->GetString().GetLength(); i++) {
292 ret = (ret << 8) + ((unsigned char*)str->podofo()->GetString().GetString())[i];
293 }
294 return ret;
295}
296
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000297SkPdfToUnicode::SkPdfToUnicode(const SkPdfStream* stream) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000298 fCMapEncoding = NULL;
299 fCMapEncodingFlag = NULL;
300
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000301 if (stream) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000302 SkPdfTokenizer tokenizer(stream);
303 PdfToken token;
304
305 fCMapEncoding = new unsigned short[256 * 256];
306 fCMapEncodingFlag = new unsigned char[256 * 256];
307 for (int i = 0 ; i < 256 * 256; i++) {
308 fCMapEncoding[i] = i;
309 fCMapEncodingFlag[i] = 0;
310 }
311
312 // TODO(edisonn): deal with multibyte character, or longer strings.
313 // Ritght now we deal with up 2 characters, e.g. <0020> but not longer like <00660066006C>
314 //2 beginbfrange
315 //<0000> <005E> <0020>
316 //<005F> <0061> [<00660066> <00660069> <00660066006C>]
317
318 while (tokenizer.readToken(&token)) {
319
320 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "begincodespacerange") == 0) {
321 while (tokenizer.readToken(&token) && !(token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "endcodespacerange") == 0)) {
322// tokenizer.PutBack(token);
323// tokenizer.readToken(&token);
324 // TODO(edisonn): check token type! ignore/report errors.
325 int start = skstoi(token.fObject->asString());
326 tokenizer.readToken(&token);
327 int end = skstoi(token.fObject->asString());
328 for (int i = start; i <= end; i++) {
329 fCMapEncodingFlag[i] |= 1;
330 }
331 }
332 }
333
334 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "beginbfchar") == 0) {
335 while (tokenizer.readToken(&token) && !(token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "endbfchar") == 0)) {
336// tokenizer.PutBack(token);
337// tokenizer.readToken(&token);
338 int from = skstoi(token.fObject->asString());
339 tokenizer.readToken(&token);
340 int to = skstoi(token.fObject->asString());
341
342 fCMapEncodingFlag[from] |= 2;
343 fCMapEncoding[from] = to;
344 }
345 }
346
347 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "beginbfrange") == 0) {
348 while (tokenizer.readToken(&token) && !(token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "endbfrange") == 0)) {
349// tokenizer.PutBack(token);
350// tokenizer.readToken(&token);
351 int start = skstoi(token.fObject->asString());
352 tokenizer.readToken(&token);
353 int end = skstoi(token.fObject->asString());
354
355
356 tokenizer.readToken(&token); // [ or just an array directly?
357// tokenizer.PutBack(token);
358
359 if (token.fType == kObject_TokenType && token.fObject->asString()) {
360// tokenizer.readToken(&token);
361 int value = skstoi(token.fObject->asString());
362
363 for (int i = start; i <= end; i++) {
364 fCMapEncodingFlag[i] |= 2;
365 fCMapEncoding[i] = value;
366 value++;
367 // if i != end, verify last byte id not if, ignore/report error
368 }
369
370 // read one string
371 } else if (token.fType == kObject_TokenType && token.fObject->asArray()) {
372// tokenizer.readToken(&token);
373 for (int i = 0; i < token.fObject->asArray()->size(); i++) {
374 fCMapEncodingFlag[start + i] |= 2;
375 fCMapEncoding[start + i] = skstoi((*token.fObject->asArray())[i]->asString());
376 }
377 // read array
378 }
379
380 //fCMapEncodingFlag[from] = 1;
381 //fCMapEncoding[from] = to;
382 }
383 }
384 }
385 }
386}
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000387
388
389SkPdfType0Font::SkPdfType0Font(SkPdfType0FontDictionary* dict) {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000390 fBaseFont = fontFromName(dict, dict->BaseFont().c_str());
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000391 fEncoding = NULL;
392
393 if (dict->has_Encoding()) {
394 if (dict->isEncodingAName()) {
395 fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName().c_str());
396 } else if (dict->isEncodingAStream()) {
397 //fEncoding = loadEncodingFromStream(dict->getEncodingAsStream());
398 } else {
399 // TODO(edisonn): error ... warning .. assert?
400 }
401 }
402
403 if (dict->has_ToUnicode()) {
404 fToUnicode = new SkPdfToUnicode(dict->ToUnicode());
405 }
406}
407
408std::map<std::string, SkPdfEncoding*>& getStandardEncodings() {
409 static std::map<std::string, SkPdfEncoding*> encodings;
410 if (encodings.empty()) {
411 encodings["Identity-H"] = SkPdfIdentityHEncoding::instance();
412 }
413
414 return encodings;
415}
416
417
418SkPdfEncoding* SkPdfEncoding::fromName(const char* name) {
419 SkPdfEncoding* encoding = getStandardEncodings()[name];
420
421#ifdef PDF_TRACE
422 if (encoding == NULL) {
423 printf("Encoding not found: %s\n", name);
424 }
425#endif
426 return encoding;
427}