blob: 42c8056da86ad37a4dc9dbeaed4b70dfc09b8ddd [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.comeee4b652013-06-27 13:22:42 +0000151static SkPdfFont* fontFromFontDescriptor(SkPdfFontDescriptorDictionary* fd) {
152 // Only one, at most be available
153 if (fd->has_FontFile()) {
154
155 } else if (fd->has_FontFile2()) {
156 SkPdfStream* pdfStream = fd->FontFile2();
157
158 if (!pdfStream->podofo()->GetStream()) {
159 // TODO(edisonn): report warning to be used in testing.
160 return NULL;
161 }
162
163 char* uncompressedStream = NULL;
164 pdf_long uncompressedStreamLength = 0;
165
166 // TODO(edisonn): get rid of try/catch exceptions! We should not throw on user data!
167 try {
168 pdfStream->podofo()->GetStream()->GetFilteredCopy(&uncompressedStream, &uncompressedStreamLength);
169 } catch (PdfError& e) {
170 // TODO(edisonn): report warning to be used in testing.
171 return NULL;
172 }
173 SkMemoryStream* skStream = new SkMemoryStream(uncompressedStream, uncompressedStreamLength);
174 SkTypeface* face = SkTypeface::CreateFromStream(skStream);
175
176 if (face == NULL) {
177 // TODO(edisonn): report warning to be used in testing.
178 return NULL;
179 }
180
181 face->ref();
182
183 return new SkPdfStandardFont(face);
184 } if (fd->has_FontFile3()) {
185
186 } else {
187
188 }
189
190 return NULL;
191}
192
edisonn@google.com1be794f2013-06-21 21:43:09 +0000193SkPdfFont* SkPdfFontFromName(SkPdfObject* obj, const char* fontName) {
194 SkTypeface* typeface = SkTypefaceFromPdfStandardFont(fontName, false, false);
195 if (typeface != NULL) {
196 return new SkPdfStandardFont(typeface);
197 }
edisonn@google.comeee4b652013-06-27 13:22:42 +0000198
199 // TODO(edisonn): perf - make a map
200 for (int i = 0 ; i < obj->doc()->GetObjects().GetSize(); i++) {
201 PdfVecObjects& objects = (PdfVecObjects&)obj->doc()->GetObjects();
202 const PdfObject* podofoFont = objects[i];
203 SkPdfFontDescriptorDictionary* fd = NULL;
204 if (mapFontDescriptorDictionary(*obj->doc(), *podofoFont, &fd)) {
205 if (fd->has_FontName() && fd->FontName() == fontName) {
206 SkPdfFont* font = fontFromFontDescriptor(fd);
207 if (font) {
208 return font;
209 } else {
210 // failed to load font descriptor
211 break;
212 }
213 }
214 }
215 }
216
217 // TODO(edisonn): warning/report issue
edisonn@google.com1be794f2013-06-21 21:43:09 +0000218 return SkPdfFont::Default();
219}
220
221SkPdfFont* SkPdfFont::fontFromPdfDictionary(SkPdfFontDictionary* dict) {
222 if (dict == NULL) {
223 return NULL; // TODO(edisonn): report default one?
224 }
225
226 switch (dict->getType()) {
227 case kType0FontDictionary_SkPdfObjectType:
228 return fontFromType0FontDictionary(dict->asType0FontDictionary());
229
230 case kTrueTypeFontDictionary_SkPdfObjectType:
231 return fontFromTrueTypeFontDictionary(dict->asTrueTypeFontDictionary());
232
233 case kType1FontDictionary_SkPdfObjectType:
234 return fontFromType1FontDictionary(dict->asType1FontDictionary());
235
236 case kCIDFontDictionary_SkPdfObjectType:
237 return fontFromCIDFontDictionary(dict->asCIDFontDictionary());
238
239 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
282SkPdfCIDFont* SkPdfFont::fontFromCIDFontDictionary(SkPdfCIDFontDictionary* dict) {
283 if (dict == NULL) {
284 return NULL; // default one?
285 }
286
287 return new SkPdfCIDFont(dict);
288}
289
290SkPdfMultiMasterFont* SkPdfFont::fontFromMultiMasterFontDictionary(SkPdfMultiMasterFontDictionary* dict) {
291 if (dict == NULL) {
292 return NULL; // default one?
293 }
294
295 return new SkPdfMultiMasterFont(dict);
296}
297
298static int skstoi(const SkPdfString* str) {
299 int ret = 0;
300 for (int i = 0 ; i < str->podofo()->GetString().GetLength(); i++) {
301 ret = (ret << 8) + ((unsigned char*)str->podofo()->GetString().GetString())[i];
302 }
303 return ret;
304}
305
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000306SkPdfToUnicode::SkPdfToUnicode(const SkPdfStream* stream) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000307 fCMapEncoding = NULL;
308 fCMapEncodingFlag = NULL;
309
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000310 if (stream) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000311 SkPdfTokenizer tokenizer(stream);
312 PdfToken token;
313
314 fCMapEncoding = new unsigned short[256 * 256];
315 fCMapEncodingFlag = new unsigned char[256 * 256];
316 for (int i = 0 ; i < 256 * 256; i++) {
317 fCMapEncoding[i] = i;
318 fCMapEncodingFlag[i] = 0;
319 }
320
321 // TODO(edisonn): deal with multibyte character, or longer strings.
322 // Ritght now we deal with up 2 characters, e.g. <0020> but not longer like <00660066006C>
323 //2 beginbfrange
324 //<0000> <005E> <0020>
325 //<005F> <0061> [<00660066> <00660069> <00660066006C>]
326
327 while (tokenizer.readToken(&token)) {
328
329 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "begincodespacerange") == 0) {
330 while (tokenizer.readToken(&token) && !(token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "endcodespacerange") == 0)) {
331// tokenizer.PutBack(token);
332// tokenizer.readToken(&token);
333 // TODO(edisonn): check token type! ignore/report errors.
334 int start = skstoi(token.fObject->asString());
335 tokenizer.readToken(&token);
336 int end = skstoi(token.fObject->asString());
337 for (int i = start; i <= end; i++) {
338 fCMapEncodingFlag[i] |= 1;
339 }
340 }
341 }
342
343 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "beginbfchar") == 0) {
344 while (tokenizer.readToken(&token) && !(token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "endbfchar") == 0)) {
345// tokenizer.PutBack(token);
346// tokenizer.readToken(&token);
347 int from = skstoi(token.fObject->asString());
348 tokenizer.readToken(&token);
349 int to = skstoi(token.fObject->asString());
350
351 fCMapEncodingFlag[from] |= 2;
352 fCMapEncoding[from] = to;
353 }
354 }
355
356 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "beginbfrange") == 0) {
357 while (tokenizer.readToken(&token) && !(token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "endbfrange") == 0)) {
358// tokenizer.PutBack(token);
359// tokenizer.readToken(&token);
360 int start = skstoi(token.fObject->asString());
361 tokenizer.readToken(&token);
362 int end = skstoi(token.fObject->asString());
363
364
365 tokenizer.readToken(&token); // [ or just an array directly?
366// tokenizer.PutBack(token);
367
368 if (token.fType == kObject_TokenType && token.fObject->asString()) {
369// tokenizer.readToken(&token);
370 int value = skstoi(token.fObject->asString());
371
372 for (int i = start; i <= end; i++) {
373 fCMapEncodingFlag[i] |= 2;
374 fCMapEncoding[i] = value;
375 value++;
376 // if i != end, verify last byte id not if, ignore/report error
377 }
378
379 // read one string
380 } else if (token.fType == kObject_TokenType && token.fObject->asArray()) {
381// tokenizer.readToken(&token);
382 for (int i = 0; i < token.fObject->asArray()->size(); i++) {
383 fCMapEncodingFlag[start + i] |= 2;
384 fCMapEncoding[start + i] = skstoi((*token.fObject->asArray())[i]->asString());
385 }
386 // read array
387 }
388
389 //fCMapEncodingFlag[from] = 1;
390 //fCMapEncoding[from] = to;
391 }
392 }
393 }
394 }
395}
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000396
397
398SkPdfType0Font::SkPdfType0Font(SkPdfType0FontDictionary* dict) {
399 fBaseFont = SkPdfFontFromName(dict, dict->BaseFont().c_str());
400 fEncoding = NULL;
401
402 if (dict->has_Encoding()) {
403 if (dict->isEncodingAName()) {
404 fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName().c_str());
405 } else if (dict->isEncodingAStream()) {
406 //fEncoding = loadEncodingFromStream(dict->getEncodingAsStream());
407 } else {
408 // TODO(edisonn): error ... warning .. assert?
409 }
410 }
411
412 if (dict->has_ToUnicode()) {
413 fToUnicode = new SkPdfToUnicode(dict->ToUnicode());
414 }
415}
416
417std::map<std::string, SkPdfEncoding*>& getStandardEncodings() {
418 static std::map<std::string, SkPdfEncoding*> encodings;
419 if (encodings.empty()) {
420 encodings["Identity-H"] = SkPdfIdentityHEncoding::instance();
421 }
422
423 return encodings;
424}
425
426
427SkPdfEncoding* SkPdfEncoding::fromName(const char* name) {
428 SkPdfEncoding* encoding = getStandardEncodings()[name];
429
430#ifdef PDF_TRACE
431 if (encoding == NULL) {
432 printf("Encoding not found: %s\n", name);
433 }
434#endif
435 return encoding;
436}