blob: e0cbd2cc1b9366cc42a71be13d629f68aa4e2a46 [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;
edisonn@google.comab03e682013-06-28 18:51:20 +0000206
edisonn@google.comeee4b652013-06-27 13:22:42 +0000207 if (mapFontDescriptorDictionary(*obj->doc(), *podofoFont, &fd)) {
208 if (fd->has_FontName() && fd->FontName() == fontName) {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000209 SkPdfFont* font = SkPdfFont::fontFromFontDescriptor(fd, false);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000210 if (font) {
211 return font;
212 } else {
213 // failed to load font descriptor
214 break;
215 }
216 }
217 }
218 }
219
220 // TODO(edisonn): warning/report issue
edisonn@google.com1be794f2013-06-21 21:43:09 +0000221 return SkPdfFont::Default();
222}
223
224SkPdfFont* SkPdfFont::fontFromPdfDictionary(SkPdfFontDictionary* dict) {
225 if (dict == NULL) {
226 return NULL; // TODO(edisonn): report default one?
227 }
228
229 switch (dict->getType()) {
230 case kType0FontDictionary_SkPdfObjectType:
231 return fontFromType0FontDictionary(dict->asType0FontDictionary());
232
233 case kTrueTypeFontDictionary_SkPdfObjectType:
234 return fontFromTrueTypeFontDictionary(dict->asTrueTypeFontDictionary());
235
236 case kType1FontDictionary_SkPdfObjectType:
237 return fontFromType1FontDictionary(dict->asType1FontDictionary());
238
edisonn@google.com1be794f2013-06-21 21:43:09 +0000239 case kMultiMasterFontDictionary_SkPdfObjectType:
240 return fontFromMultiMasterFontDictionary(dict->asMultiMasterFontDictionary());
241
242 case kType3FontDictionary_SkPdfObjectType:
243 return fontFromType3FontDictionary(dict->asType3FontDictionary());
244 }
245 return NULL; // TODO(edisonn): report error?
246}
247
248SkPdfType0Font* SkPdfFont::fontFromType0FontDictionary(SkPdfType0FontDictionary* dict) {
249 if (dict == NULL) {
250 return NULL; // default one?
251 }
252
253 return new SkPdfType0Font(dict);
254}
255
256SkPdfType1Font* SkPdfFont:: fontFromType1FontDictionary(SkPdfType1FontDictionary* dict) {
257 if (dict == NULL) {
258 return NULL; // default one?
259 }
260
261 return new SkPdfType1Font(dict);
262}
263
264SkPdfType3Font* SkPdfFont::fontFromType3FontDictionary(SkPdfType3FontDictionary* dict) {
265 if (dict == NULL) {
266 return NULL; // default one?
267 }
268
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000269
270
edisonn@google.com1be794f2013-06-21 21:43:09 +0000271 return new SkPdfType3Font(dict);
272}
273
274SkPdfTrueTypeFont* SkPdfFont::fontFromTrueTypeFontDictionary(SkPdfTrueTypeFontDictionary* dict) {
275 if (dict == NULL) {
276 return NULL; // default one?
277 }
278
279 return new SkPdfTrueTypeFont(dict);
280}
281
edisonn@google.com1be794f2013-06-21 21:43:09 +0000282SkPdfMultiMasterFont* SkPdfFont::fontFromMultiMasterFontDictionary(SkPdfMultiMasterFontDictionary* dict) {
283 if (dict == NULL) {
284 return NULL; // default one?
285 }
286
287 return new SkPdfMultiMasterFont(dict);
288}
289
290static int skstoi(const SkPdfString* str) {
291 int ret = 0;
292 for (int i = 0 ; i < str->podofo()->GetString().GetLength(); i++) {
293 ret = (ret << 8) + ((unsigned char*)str->podofo()->GetString().GetString())[i];
294 }
295 return ret;
296}
297
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000298SkPdfToUnicode::SkPdfToUnicode(const SkPdfStream* stream) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000299 fCMapEncoding = NULL;
300 fCMapEncodingFlag = NULL;
301
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000302 if (stream) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000303 SkPdfTokenizer tokenizer(stream);
304 PdfToken token;
305
306 fCMapEncoding = new unsigned short[256 * 256];
307 fCMapEncodingFlag = new unsigned char[256 * 256];
308 for (int i = 0 ; i < 256 * 256; i++) {
309 fCMapEncoding[i] = i;
310 fCMapEncodingFlag[i] = 0;
311 }
312
313 // TODO(edisonn): deal with multibyte character, or longer strings.
314 // Ritght now we deal with up 2 characters, e.g. <0020> but not longer like <00660066006C>
315 //2 beginbfrange
316 //<0000> <005E> <0020>
317 //<005F> <0061> [<00660066> <00660069> <00660066006C>]
318
319 while (tokenizer.readToken(&token)) {
320
321 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "begincodespacerange") == 0) {
322 while (tokenizer.readToken(&token) && !(token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "endcodespacerange") == 0)) {
323// tokenizer.PutBack(token);
324// tokenizer.readToken(&token);
325 // TODO(edisonn): check token type! ignore/report errors.
326 int start = skstoi(token.fObject->asString());
327 tokenizer.readToken(&token);
328 int end = skstoi(token.fObject->asString());
329 for (int i = start; i <= end; i++) {
330 fCMapEncodingFlag[i] |= 1;
331 }
332 }
333 }
334
335 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "beginbfchar") == 0) {
336 while (tokenizer.readToken(&token) && !(token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "endbfchar") == 0)) {
337// tokenizer.PutBack(token);
338// tokenizer.readToken(&token);
339 int from = skstoi(token.fObject->asString());
340 tokenizer.readToken(&token);
341 int to = skstoi(token.fObject->asString());
342
343 fCMapEncodingFlag[from] |= 2;
344 fCMapEncoding[from] = to;
345 }
346 }
347
348 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "beginbfrange") == 0) {
349 while (tokenizer.readToken(&token) && !(token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "endbfrange") == 0)) {
350// tokenizer.PutBack(token);
351// tokenizer.readToken(&token);
352 int start = skstoi(token.fObject->asString());
353 tokenizer.readToken(&token);
354 int end = skstoi(token.fObject->asString());
355
356
357 tokenizer.readToken(&token); // [ or just an array directly?
358// tokenizer.PutBack(token);
359
360 if (token.fType == kObject_TokenType && token.fObject->asString()) {
361// tokenizer.readToken(&token);
362 int value = skstoi(token.fObject->asString());
363
364 for (int i = start; i <= end; i++) {
365 fCMapEncodingFlag[i] |= 2;
366 fCMapEncoding[i] = value;
367 value++;
368 // if i != end, verify last byte id not if, ignore/report error
369 }
370
371 // read one string
372 } else if (token.fType == kObject_TokenType && token.fObject->asArray()) {
373// tokenizer.readToken(&token);
374 for (int i = 0; i < token.fObject->asArray()->size(); i++) {
375 fCMapEncodingFlag[start + i] |= 2;
376 fCMapEncoding[start + i] = skstoi((*token.fObject->asArray())[i]->asString());
377 }
378 // read array
379 }
380
381 //fCMapEncodingFlag[from] = 1;
382 //fCMapEncoding[from] = to;
383 }
384 }
385 }
386 }
387}
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000388
389
390SkPdfType0Font::SkPdfType0Font(SkPdfType0FontDictionary* dict) {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000391 fBaseFont = fontFromName(dict, dict->BaseFont().c_str());
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000392 fEncoding = NULL;
393
394 if (dict->has_Encoding()) {
395 if (dict->isEncodingAName()) {
396 fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName().c_str());
397 } else if (dict->isEncodingAStream()) {
398 //fEncoding = loadEncodingFromStream(dict->getEncodingAsStream());
399 } else {
400 // TODO(edisonn): error ... warning .. assert?
401 }
402 }
403
404 if (dict->has_ToUnicode()) {
405 fToUnicode = new SkPdfToUnicode(dict->ToUnicode());
406 }
407}
408
409std::map<std::string, SkPdfEncoding*>& getStandardEncodings() {
410 static std::map<std::string, SkPdfEncoding*> encodings;
411 if (encodings.empty()) {
412 encodings["Identity-H"] = SkPdfIdentityHEncoding::instance();
413 }
414
415 return encodings;
416}
417
418
419SkPdfEncoding* SkPdfEncoding::fromName(const char* name) {
420 SkPdfEncoding* encoding = getStandardEncodings()[name];
421
422#ifdef PDF_TRACE
423 if (encoding == NULL) {
424 printf("Encoding not found: %s\n", name);
425 }
426#endif
427 return encoding;
428}