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 #include "SkPdfFont.h"
9
10 #include "SkPdfNativeTokenizer.h"
11 #include "SkStream.h"
12 #include "SkTypeface.h"
13
getStandardFonts()14 SkTDict<SkPdfStandardFontEntry>& getStandardFonts() {
15 static SkTDict<SkPdfStandardFontEntry> gPdfStandardFonts(100);
16
17 // TODO (edisonn): , vs - ? what does it mean?
18 // TODO (edisonn): MT, PS, Oblique=italic?, ... what does it mean?
19 if (gPdfStandardFonts.count() == 0) {
20 gPdfStandardFonts.set("Arial", SkPdfStandardFontEntry("Arial", false, false));
21 gPdfStandardFonts.set("Arial,Bold", SkPdfStandardFontEntry("Arial", true, false));
22 gPdfStandardFonts.set("Arial,BoldItalic", SkPdfStandardFontEntry("Arial", true, true));
23 gPdfStandardFonts.set("Arial,Italic", SkPdfStandardFontEntry("Arial", false, true));
24 gPdfStandardFonts.set("Arial-Bold", SkPdfStandardFontEntry("Arial", true, false));
25 gPdfStandardFonts.set("Arial-BoldItalic", SkPdfStandardFontEntry("Arial", true, true));
26 gPdfStandardFonts.set("Arial-BoldItalicMT", SkPdfStandardFontEntry("Arial", true, true));
27 gPdfStandardFonts.set("Arial-BoldMT", SkPdfStandardFontEntry("Arial", true, false));
28 gPdfStandardFonts.set("Arial-Italic", SkPdfStandardFontEntry("Arial", false, true));
29 gPdfStandardFonts.set("Arial-ItalicMT", SkPdfStandardFontEntry("Arial", false, true));
30 gPdfStandardFonts.set("ArialMT", SkPdfStandardFontEntry("Arial", false, false));
31 gPdfStandardFonts.set("Courier", SkPdfStandardFontEntry("Courier New", false, false));
32 gPdfStandardFonts.set("Courier,Bold", SkPdfStandardFontEntry("Courier New", true, false));
33 gPdfStandardFonts.set("Courier,BoldItalic", SkPdfStandardFontEntry("Courier New", true, true));
34 gPdfStandardFonts.set("Courier,Italic", SkPdfStandardFontEntry("Courier New", false, true));
35 gPdfStandardFonts.set("Courier-Bold", SkPdfStandardFontEntry("Courier New", true, false));
36 gPdfStandardFonts.set("Courier-BoldOblique", SkPdfStandardFontEntry("Courier New", true, true));
37 gPdfStandardFonts.set("Courier-Oblique", SkPdfStandardFontEntry("Courier New", false, true));
38 gPdfStandardFonts.set("CourierNew", SkPdfStandardFontEntry("Courier New", false, false));
39 gPdfStandardFonts.set("CourierNew,Bold", SkPdfStandardFontEntry("Courier New", true, false));
40 gPdfStandardFonts.set("CourierNew,BoldItalic", SkPdfStandardFontEntry("Courier New", true, true));
41 gPdfStandardFonts.set("CourierNew,Italic", SkPdfStandardFontEntry("Courier New", false, true));
42 gPdfStandardFonts.set("CourierNew-Bold", SkPdfStandardFontEntry("Courier New", true, false));
43 gPdfStandardFonts.set("CourierNew-BoldItalic", SkPdfStandardFontEntry("Courier New", true, true));
44 gPdfStandardFonts.set("CourierNew-Italic", SkPdfStandardFontEntry("Courier New", false, true));
45 gPdfStandardFonts.set("CourierNewPS-BoldItalicMT", SkPdfStandardFontEntry("Courier New", true, true));
46 gPdfStandardFonts.set("CourierNewPS-BoldMT", SkPdfStandardFontEntry("Courier New", true, false));
47 gPdfStandardFonts.set("CourierNewPS-ItalicMT", SkPdfStandardFontEntry("Courier New", false, true));
48 gPdfStandardFonts.set("CourierNewPSMT", SkPdfStandardFontEntry("Courier New", false, false));
49 gPdfStandardFonts.set("Helvetica", SkPdfStandardFontEntry("Helvetica", false, false));
50 gPdfStandardFonts.set("Helvetica,Bold", SkPdfStandardFontEntry("Helvetica", true, false));
51 gPdfStandardFonts.set("Helvetica,BoldItalic", SkPdfStandardFontEntry("Helvetica", true, true));
52 gPdfStandardFonts.set("Helvetica,Italic", SkPdfStandardFontEntry("Helvetica", false, true));
53 gPdfStandardFonts.set("Helvetica-Bold", SkPdfStandardFontEntry("Helvetica", true, false));
54 gPdfStandardFonts.set("Helvetica-BoldItalic", SkPdfStandardFontEntry("Helvetica", true, true));
55 gPdfStandardFonts.set("Helvetica-BoldOblique", SkPdfStandardFontEntry("Helvetica", true, true));
56 gPdfStandardFonts.set("Helvetica-Italic", SkPdfStandardFontEntry("Helvetica", false, true));
57 gPdfStandardFonts.set("Helvetica-Oblique", SkPdfStandardFontEntry("Helvetica", false, true));
58 gPdfStandardFonts.set("Times-Bold", SkPdfStandardFontEntry("Times New Roman", true, false));
59 gPdfStandardFonts.set("Times-BoldItalic", SkPdfStandardFontEntry("Times New Roman", true, true));
60 gPdfStandardFonts.set("Times-Italic", SkPdfStandardFontEntry("Times New Roman", false, true));
61 gPdfStandardFonts.set("Times-Roman", SkPdfStandardFontEntry("Times New Roman", false, false));
62 gPdfStandardFonts.set("TimesNewRoman", SkPdfStandardFontEntry("Times New Roman", false, false));
63 gPdfStandardFonts.set("TimesNewRoman,Bold", SkPdfStandardFontEntry("Times New Roman", true, false));
64 gPdfStandardFonts.set("TimesNewRoman,BoldItalic", SkPdfStandardFontEntry("Times New Roman", true, true));
65 gPdfStandardFonts.set("TimesNewRoman,Italic", SkPdfStandardFontEntry("Times New Roman", false, true));
66 gPdfStandardFonts.set("TimesNewRoman-Bold", SkPdfStandardFontEntry("Times New Roman", true, false));
67 gPdfStandardFonts.set("TimesNewRoman-BoldItalic", SkPdfStandardFontEntry("Times New Roman", true, true));
68 gPdfStandardFonts.set("TimesNewRoman-Italic", SkPdfStandardFontEntry("Times New Roman", false, true));
69 gPdfStandardFonts.set("TimesNewRomanPS", SkPdfStandardFontEntry("Times New Roman", false, false));
70 gPdfStandardFonts.set("TimesNewRomanPS-Bold", SkPdfStandardFontEntry("Times New Roman", true, false));
71 gPdfStandardFonts.set("TimesNewRomanPS-BoldItalic", SkPdfStandardFontEntry("Times New Roman", true, true));
72 gPdfStandardFonts.set("TimesNewRomanPS-BoldItalicMT", SkPdfStandardFontEntry("Times New Roman", true, true));
73 gPdfStandardFonts.set("TimesNewRomanPS-BoldMT", SkPdfStandardFontEntry("Times New Roman", true, false));
74 gPdfStandardFonts.set("TimesNewRomanPS-Italic", SkPdfStandardFontEntry("Times New Roman", false, true));
75 gPdfStandardFonts.set("TimesNewRomanPS-ItalicMT", SkPdfStandardFontEntry("Times New Roman", false, true));
76 gPdfStandardFonts.set("TimesNewRomanPSMT", SkPdfStandardFontEntry("Times New Roman", false, false));
77 gPdfStandardFonts.set("Symbol", SkPdfStandardFontEntry("Symbol", false, false));
78 gPdfStandardFonts.set("ZapfDingbats", SkPdfStandardFontEntry("ZapfDingbats", false, false));
79
80 // TODO(edisonn): these are hacks. Load Post Script font name.
81 // see FT_Get_Postscript_Name
82 // Font config is not using it, yet.
83 //https://bugs.freedesktop.org/show_bug.cgi?id=18095
84
85 gPdfStandardFonts.set("Arial-Black", SkPdfStandardFontEntry("Arial", true, false));
86 gPdfStandardFonts.set("DejaVuSans", SkPdfStandardFontEntry("DejaVu Sans", false, false));
87 gPdfStandardFonts.set("DejaVuSansMono", SkPdfStandardFontEntry("DejaVuSans Mono", false, false));
88 gPdfStandardFonts.set("DejaVuSansMono-Bold", SkPdfStandardFontEntry("DejaVuSans Mono", true, false));
89 gPdfStandardFonts.set("DejaVuSansMono-Oblique", SkPdfStandardFontEntry("DejaVuSans Mono", false, true));
90 gPdfStandardFonts.set("Georgia-Bold", SkPdfStandardFontEntry("Georgia", true, false));
91 gPdfStandardFonts.set("Georgia-BoldItalic", SkPdfStandardFontEntry("Georgia", true, true));
92 gPdfStandardFonts.set("Georgia-Italic", SkPdfStandardFontEntry("Georgia", false, true));
93 gPdfStandardFonts.set("TrebuchetMS", SkPdfStandardFontEntry("Trebuchet MS", false, false));
94 gPdfStandardFonts.set("TrebuchetMS-Bold", SkPdfStandardFontEntry("Trebuchet MS", true, false));
95 gPdfStandardFonts.set("Verdana-Bold", SkPdfStandardFontEntry("Verdana", true, false));
96 gPdfStandardFonts.set("WenQuanYiMicroHei", SkPdfStandardFontEntry("WenQuanYi Micro Hei", false, false));
97
98 // TODO(edisonn): list all fonts available, buil post script name as in pdf spec
99 // TODO(edisonn): Does it work in all OSs ?
100 /*
101 * The PostScript name for the value of BaseFontis determined in one of two ways:
102 • Use the PostScript name that is an optional entry in the “name” table of the
103 TrueType font itself.
104 • In the absence of such an entry in the “name” table, derive a PostScript name
105 from the name by which the font is known in the host operating system: on a
106 Windows system, it is based on the lfFaceName field in a LOGFONT structure; in
107 the Mac OS, it is based on the name of the FONDresource. If the name contains
108 any spaces, the spaces are removed.
109 If the font in a source document uses a bold or italic style, but there is no font
110 data for that style, the host operating system will synthesize the style. In this case,
111 a comma and the style name (one of Bold, Italic, or BoldItalic) are appended to the
112 font name. For example, for a TrueType font that is a bold variant of the New
113 */
114
115 /*
116 * If the value of Subtype is MMType1.
117 • If the PostScript name of the instance contains spaces, the spaces are replaced
118 by underscores in the value of BaseFont. For instance, as illustrated in Example
119 5.7, the name “MinionMM 366 465 11 ” (which ends with a space character)
120 becomes /MinionMM_366_465_11_.
121 */
122 }
123
124 return gPdfStandardFonts;
125 }
126
SkTypefaceFromPdfStandardFont(const char * fontName,bool bold,bool italic)127 SkTypeface* SkTypefaceFromPdfStandardFont(const char* fontName, bool bold, bool italic) {
128 SkTDict<SkPdfStandardFontEntry>& standardFontMap = getStandardFonts();
129
130 SkTypeface* typeface = NULL;
131 SkPdfStandardFontEntry fontData;
132
133 if (standardFontMap.find(fontName, &fontData)) {
134 // TODO(edisonn): How does the bold/italic specified in standard definition combines with
135 // the one in /font key? use OR for now.
136 bold = bold || fontData.fIsBold;
137 italic = italic || fontData.fIsItalic;
138
139 typeface = SkTypeface::CreateFromName(
140 fontData.fName,
141 SkTypeface::Style((bold ? SkTypeface::kBold : 0) |
142 (italic ? SkTypeface::kItalic : 0)));
143 } else {
144 typeface = SkTypeface::CreateFromName(
145 fontName,
146 SkTypeface::kNormal);
147 }
148
149 if (typeface) {
150 typeface->ref();
151 }
152 return typeface;
153 }
154
fontFromFontDescriptor(SkPdfNativeDoc * doc,SkPdfFontDescriptorDictionary * fd,bool loadFromName)155 SkPdfFont* SkPdfFont::fontFromFontDescriptor(SkPdfNativeDoc* doc, SkPdfFontDescriptorDictionary* fd,
156 bool loadFromName) {
157 // TODO(edisonn): partial implementation.
158 // Only one, at most be available
159 SkPdfStream* pdfStream = NULL;
160 if (fd->has_FontFile()) {
161 pdfStream = fd->FontFile(doc);
162 } else if (fd->has_FontFile2()) {
163 pdfStream = fd->FontFile2(doc);
164 } if (fd->has_FontFile3()) {
165 pdfStream = fd->FontFile3(doc);
166 } else {
167 if (loadFromName) {
168 return fontFromName(doc, fd, fd->FontName(doc).c_str());
169 }
170 }
171
172 const unsigned char* uncompressedStream = NULL;
173 size_t uncompressedStreamLength = 0;
174
175 // TODO(edisonn): report warning to be used in testing.
176 if (!pdfStream ||
177 !pdfStream->GetFilteredStreamRef(&uncompressedStream, &uncompressedStreamLength) ||
178 !uncompressedStream ||
179 !uncompressedStreamLength) {
180 return NULL;
181 }
182
183 SkMemoryStream* skStream = new SkMemoryStream(uncompressedStream, uncompressedStreamLength);
184 SkTypeface* face = SkTypeface::CreateFromStream(skStream);
185
186 if (face == NULL) {
187 // TODO(edisonn): report warning to be used in testing.
188 return NULL;
189 }
190
191 face->ref();
192
193 return new SkPdfStandardFont(face);
194 }
195
fontFromName(SkPdfNativeDoc * doc,SkPdfNativeObject * obj,const char * fontName)196 SkPdfFont* fontFromName(SkPdfNativeDoc* doc, SkPdfNativeObject* obj, const char* fontName) {
197 SkTypeface* typeface = SkTypefaceFromPdfStandardFont(fontName, false, false);
198 if (typeface != NULL) {
199 return new SkPdfStandardFont(typeface);
200 }
201
202 // TODO(edisonn): perf - make a map
203 for (unsigned int i = 0 ; i < doc->objects(); i++) {
204 SkPdfNativeObject* obj = doc->object(i);
205 if (!obj || !obj->isDictionary()) {
206 continue;
207 }
208
209 SkPdfFontDescriptorDictionary* fd = obj->asDictionary()->asFontDescriptorDictionary();
210
211 if (!fd->valid()) {
212 continue;
213 }
214
215 if (fd->has_FontName() && fd->FontName(doc).equals(fontName)) {
216 SkPdfFont* font = SkPdfFont::fontFromFontDescriptor(doc, fd, false);
217 if (font) {
218 return font;
219 } else {
220 // failed to load font descriptor
221 break;
222 }
223 }
224 }
225
226 // TODO(edisonn): warning/report issue
227 return SkPdfFont::Default();
228 }
229
fontFromPdfDictionaryOnce(SkPdfNativeDoc * doc,SkPdfFontDictionary * dict)230 SkPdfFont* SkPdfFont::fontFromPdfDictionaryOnce(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict) {
231 // TODO(edisonn): keep the type in a smart way in the SkPdfNativeObject
232 // 1) flag, isResolved (1bit): reset at reset, add/remove/update (array) and set(dict)
233 // in a tree like structure, 3-4 bits for all the datatypes inheriting from obj (int, real, ...)
234 // if is a dict, reserve a few bytes to encode type of dict, and so on like in a tree
235 // issue: type can be determined from context! atribute night be missing/wrong
236 switch (doc->mapper()->mapFontDictionary(dict)) {
237 case kType0FontDictionary_SkPdfNativeObjectType:
238 return fontFromType0FontDictionary(doc, dict->asType0FontDictionary());
239
240 case kTrueTypeFontDictionary_SkPdfNativeObjectType:
241 return fontFromTrueTypeFontDictionary(doc, dict->asTrueTypeFontDictionary());
242
243 case kType1FontDictionary_SkPdfNativeObjectType:
244 return fontFromType1FontDictionary(doc, dict->asType1FontDictionary());
245
246 case kMultiMasterFontDictionary_SkPdfNativeObjectType:
247 return fontFromMultiMasterFontDictionary(doc, dict->asMultiMasterFontDictionary());
248
249 case kType3FontDictionary_SkPdfNativeObjectType:
250 return fontFromType3FontDictionary(doc, dict->asType3FontDictionary());
251
252 default:
253 // TODO(edisonn): report error?
254 return NULL;
255 }
256 }
257
fontFromPdfDictionary(SkPdfNativeDoc * doc,SkPdfFontDictionary * dict)258 SkPdfFont* SkPdfFont::fontFromPdfDictionary(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict) {
259 if (dict == NULL) {
260 return NULL; // TODO(edisonn): report default one?
261 }
262
263 if (!dict->hasData(SkPdfNativeObject::kFont_Data)) {
264 dict->setData(fontFromPdfDictionaryOnce(doc, dict), SkPdfNativeObject::kFont_Data);
265 }
266 return (SkPdfFont*)dict->data(SkPdfNativeObject::kFont_Data);
267 }
268
269
270
fontFromType0FontDictionary(SkPdfNativeDoc * doc,SkPdfType0FontDictionary * dict)271 SkPdfType0Font* SkPdfFont::fontFromType0FontDictionary(SkPdfNativeDoc* doc,
272 SkPdfType0FontDictionary* dict) {
273 if (dict == NULL) {
274 return NULL; // default one?
275 }
276
277 return new SkPdfType0Font(doc, dict);
278 }
279
fontFromType1FontDictionary(SkPdfNativeDoc * doc,SkPdfType1FontDictionary * dict)280 SkPdfType1Font* SkPdfFont:: fontFromType1FontDictionary(SkPdfNativeDoc* doc,
281 SkPdfType1FontDictionary* dict) {
282 if (dict == NULL) {
283 return NULL; // default one?
284 }
285
286 return new SkPdfType1Font(doc, dict);
287 }
288
fontFromType3FontDictionary(SkPdfNativeDoc * doc,SkPdfType3FontDictionary * dict)289 SkPdfType3Font* SkPdfFont::fontFromType3FontDictionary(SkPdfNativeDoc* doc,
290 SkPdfType3FontDictionary* dict) {
291 if (dict == NULL) {
292 return NULL; // default one?
293 }
294
295
296
297 return new SkPdfType3Font(doc, dict);
298 }
299
fontFromTrueTypeFontDictionary(SkPdfNativeDoc * doc,SkPdfTrueTypeFontDictionary * dict)300 SkPdfTrueTypeFont* SkPdfFont::fontFromTrueTypeFontDictionary(SkPdfNativeDoc* doc,
301 SkPdfTrueTypeFontDictionary* dict) {
302 if (dict == NULL) {
303 return NULL; // default one?
304 }
305
306 return new SkPdfTrueTypeFont(doc, dict);
307 }
308
fontFromMultiMasterFontDictionary(SkPdfNativeDoc * doc,SkPdfMultiMasterFontDictionary * dict)309 SkPdfMultiMasterFont* SkPdfFont::fontFromMultiMasterFontDictionary(
310 SkPdfNativeDoc* doc, SkPdfMultiMasterFontDictionary* dict) {
311 if (dict == NULL) {
312 return NULL; // default one?
313 }
314
315 return new SkPdfMultiMasterFont(doc, dict);
316 }
317
skstoi(const SkPdfNativeObject * str)318 static int skstoi(const SkPdfNativeObject* str) {
319 // TODO(edisonn): report err of it is not a (hex) string
320 int ret = 0;
321 for (unsigned int i = 0 ; i < str->lenstr(); i++) {
322 ret = (ret << 8) + ((unsigned char*)str->c_str())[i];
323 }
324 // TODO(edisonn): character larger than 0x0000ffff not supported right now.
325 return ret & 0x0000ffff;
326 }
327
328 #define tokenIsKeyword(token,keyword) (token.fType == kKeyword_TokenType && \
329 token.fKeywordLength==sizeof(keyword)-1 && \
330 strncmp(token.fKeyword, keyword, sizeof(keyword)-1) == 0)
331
SkPdfToUnicode(SkPdfNativeDoc * parsed,SkPdfStream * stream)332 SkPdfToUnicode::SkPdfToUnicode(SkPdfNativeDoc* parsed, SkPdfStream* stream) {
333 fCMapEncoding = NULL;
334 fCMapEncodingFlag = NULL;
335
336 if (stream) {
337 // Since font will be cached, the font has to sit in the per doc allocator, not to be
338 // freed after the page is done drawing.
339 SkPdfNativeTokenizer tokenizer(stream, parsed->allocator(), parsed);
340 PdfToken token;
341
342 fCMapEncoding = new unsigned short[256 * 256];
343 fCMapEncodingFlag = new unsigned char[256 * 256];
344 for (int i = 0 ; i < 256 * 256; i++) {
345 fCMapEncoding[i] = i;
346 fCMapEncodingFlag[i] = 0;
347 }
348
349 // TODO(edisonn): deal with multibyte character, or longer strings.
350 // Right now we deal with up 2 characters, e.g. <0020> but not longer like <00660066006C>
351 //2 beginbfrange
352 //<0000> <005E> <0020>
353 //<005F> <0061> [<00660066> <00660069> <00660066006C>]
354
355 while (tokenizer.readToken(&token)) {
356
357 if (tokenIsKeyword(token, "begincodespacerange")) {
358 while (tokenizer.readToken(&token) &&
359 !tokenIsKeyword(token, "endcodespacerange")) {
360 // tokenizer.PutBack(token);
361 // tokenizer.readToken(&token);
362 // TODO(edisonn): check token type! ignore/report errors.
363 int start = skstoi(token.fObject);
364 tokenizer.readToken(&token);
365 int end = skstoi(token.fObject);
366 for (int i = start; i <= end; i++) {
367 fCMapEncodingFlag[i] |= 1;
368 }
369 }
370 }
371
372 if (tokenIsKeyword(token, "beginbfchar")) {
373 while (tokenizer.readToken(&token) && !tokenIsKeyword(token, "endbfchar")) {
374 // tokenizer.PutBack(token);
375 // tokenizer.readToken(&token);
376 int from = skstoi(token.fObject);
377 tokenizer.readToken(&token);
378 int to = skstoi(token.fObject);
379
380 fCMapEncodingFlag[from] |= 2;
381 fCMapEncoding[from] = to;
382 }
383 }
384
385 if (tokenIsKeyword(token, "beginbfrange")) {
386 while (tokenizer.readToken(&token) && !tokenIsKeyword(token, "endbfrange")) {
387 // tokenizer.PutBack(token);
388 // tokenizer.readToken(&token);
389 int start = skstoi(token.fObject);
390 tokenizer.readToken(&token);
391 int end = skstoi(token.fObject);
392
393
394 tokenizer.readToken(&token); // [ or just an array directly?
395 // do not putback, we will reuse the read. See next commented read.
396 // tokenizer.PutBack(token);
397
398 // TODO(edisonn): read spec: any string or only hex string?
399 if (token.fType == kObject_TokenType && token.fObject->isAnyString()) {
400 // tokenizer.readToken(&token);
401 int value = skstoi(token.fObject);
402
403 for (int i = start; i <= end; i++) {
404 fCMapEncodingFlag[i] |= 2;
405 fCMapEncoding[i] = value;
406 value++;
407 // if i != end, verify last byte id not if, ignore/report error
408 }
409
410 // read one string
411 } else if (token.fType == kObject_TokenType && token.fObject->isArray()) {
412 // tokenizer.readToken(&token);
413 // read array
414 for (unsigned int i = 0; i < token.fObject->size(); i++) {
415 fCMapEncodingFlag[start + i] |= 2;
416 fCMapEncoding[start + i] = skstoi((*token.fObject)[i]);
417 }
418 } else {
419 tokenizer.PutBack(token);
420 }
421 }
422 }
423 }
424 }
425 }
426
SkPdfType0Font(SkPdfNativeDoc * doc,SkPdfType0FontDictionary * dict)427 SkPdfType0Font::SkPdfType0Font(SkPdfNativeDoc* doc, SkPdfType0FontDictionary* dict) {
428 fBaseFont = fontFromName(doc, dict, dict->BaseFont(doc).c_str());
429 fEncoding = NULL;
430
431 if (dict->has_Encoding()) {
432 if (dict->isEncodingAName(doc)) {
433 fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName(doc).c_str());
434 } else if (dict->isEncodingAStream(doc)) {
435 // TODO(edisonn): NYI
436 //fEncoding = loadEncodingFromStream(dict->getEncodingAsStream());
437 } else {
438 // TODO(edisonn): error ... warning .. assert?
439 }
440 }
441
442 if (dict->has_ToUnicode()) {
443 fToUnicode = new SkPdfToUnicode(doc, dict->ToUnicode(doc));
444 }
445 }
446
getStandardEncodings()447 SkTDict<SkPdfEncoding*>& getStandardEncodings() {
448 static SkTDict<SkPdfEncoding*> encodings(10);
449 if (encodings.count() == 0) {
450 encodings.set("Identity-H", SkPdfIdentityHEncoding::instance());
451 }
452
453 return encodings;
454 }
455
fromName(const char * name)456 SkPdfEncoding* SkPdfEncoding::fromName(const char* name) {
457 SkPdfEncoding* encoding = NULL;
458 if (!getStandardEncodings().find(name, &encoding)) {
459 encoding = NULL;
460 }
461
462 #ifdef PDF_TRACE
463 if (encoding == NULL) {
464 printf("Encoding not found: %s\n", name);
465 }
466 #endif
467 return encoding;
468 }
469