blob: f8dfa05983294798d99ad12d6e8862013d6b39a6 [file] [log] [blame]
edisonn@google.comcf2cfa12013-08-21 16:31:37 +00001/*
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
edisonn@google.com1be794f2013-06-21 21:43:09 +00008#include "SkPdfFont.h"
9
edisonn@google.comeee4b652013-06-27 13:22:42 +000010#include "SkStream.h"
11#include "SkTypeface.h"
edisonn@google.com571c70b2013-07-10 17:09:50 +000012#include "SkPdfNativeTokenizer.h"
edisonn@google.comeee4b652013-06-27 13:22:42 +000013
edisonn@google.com063d7072013-08-16 15:05:08 +000014SkTDict<SkPdfStandardFontEntry>& getStandardFonts() {
15 static SkTDict<SkPdfStandardFontEntry> gPdfStandardFonts(100);
edisonn@google.com1be794f2013-06-21 21:43:09 +000016
17 // TODO (edisonn): , vs - ? what does it mean?
18 // TODO (edisonn): MT, PS, Oblique=italic?, ... what does it mean?
edisonn@google.com063d7072013-08-16 15:05:08 +000019 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));
edisonn@google.com1be794f2013-06-21 21:43:09 +000079
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
edisonn@google.comb857a0c2013-06-25 20:45:40 +000084
edisonn@google.com063d7072013-08-16 15:05:08 +000085 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));
edisonn@google.comb857a0c2013-06-25 20:45:40 +000097
98 // TODO(edisonn): list all phonts available, builf post script name as in pdf spec
99 /*
100 * The PostScript name for the value of BaseFontis determined in one of two ways:
101• Use the PostScript name that is an optional entry in the “name” table of the
102TrueType font itself.
103• In the absence of such an entry in the “name” table, derive a PostScript name
104from the name by which the font is known in the host operating system: on a
105Windows system, it is based on the lfFaceName field in a LOGFONT structure; in
106the Mac OS, it is based on the name of the FONDresource. If the name contains
107any spaces, the spaces are removed.
108If the font in a source document uses a bold or italic style, but there is no font
109data for that style, the host operating system will synthesize the style. In this case,
110a comma and the style name (one of Bold, Italic, or BoldItalic) are appended to the
111font name. For example, for a TrueType font that is a bold variant of the New
112 */
113
114 /*
115 * If the value of Subtype is MMType1.
116• If the PostScript name of the instance contains spaces, the spaces are replaced
117by underscores in the value of BaseFont. For instance, as illustrated in Example
1185.7, the name “MinionMM 366 465 11 ” (which ends with a space character)
119becomes /MinionMM_366_465_11_.
120 */
121
122 // might not work on all oses ?
123 //
124
edisonn@google.com1be794f2013-06-21 21:43:09 +0000125 }
126
127 return gPdfStandardFonts;
128}
129
130SkTypeface* SkTypefaceFromPdfStandardFont(const char* fontName, bool bold, bool italic) {
edisonn@google.com063d7072013-08-16 15:05:08 +0000131 SkTDict<SkPdfStandardFontEntry>& standardFontMap = getStandardFonts();
edisonn@google.com1be794f2013-06-21 21:43:09 +0000132
133 SkTypeface* typeface = NULL;
edisonn@google.com063d7072013-08-16 15:05:08 +0000134 SkPdfStandardFontEntry fontData;
edisonn@google.com1be794f2013-06-21 21:43:09 +0000135
edisonn@google.com063d7072013-08-16 15:05:08 +0000136 if (standardFontMap.find(fontName, &fontData)) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000137 // TODO(edisonn): How does the bold/italic specified in standard definition combines with
138 // the one in /font key? use OR for now.
139 bold = bold || fontData.fIsBold;
140 italic = italic || fontData.fIsItalic;
141
142 typeface = SkTypeface::CreateFromName(
143 fontData.fName,
144 SkTypeface::Style((bold ? SkTypeface::kBold : 0) |
145 (italic ? SkTypeface::kItalic : 0)));
146 } else {
147 typeface = SkTypeface::CreateFromName(
148 fontName,
149 SkTypeface::kNormal);
150 }
151
152 if (typeface) {
153 typeface->ref();
154 }
155 return typeface;
156}
157
edisonn@google.com3aa35552013-08-14 18:26:20 +0000158SkPdfFont* SkPdfFont::fontFromFontDescriptor(SkPdfNativeDoc* doc, SkPdfFontDescriptorDictionary* fd, bool loadFromName) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000159 // TODO(edisonn): partial implementation ... also const handling ...
edisonn@google.comeee4b652013-06-27 13:22:42 +0000160 // Only one, at most be available
edisonn@google.com6e49c342013-06-27 20:03:43 +0000161 SkPdfStream* pdfStream = NULL;
edisonn@google.comeee4b652013-06-27 13:22:42 +0000162 if (fd->has_FontFile()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000163 pdfStream = fd->FontFile(doc);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000164 } else if (fd->has_FontFile2()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000165 pdfStream = fd->FontFile2(doc);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000166 } if (fd->has_FontFile3()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000167 pdfStream = fd->FontFile3(doc);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000168 } else {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000169 if (loadFromName) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000170 return fontFromName(doc, fd, fd->FontName(doc).c_str());
edisonn@google.com6e49c342013-06-27 20:03:43 +0000171 }
edisonn@google.comeee4b652013-06-27 13:22:42 +0000172 }
173
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000174 const unsigned char* uncompressedStream = NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000175 size_t uncompressedStreamLength = 0;
edisonn@google.com6e49c342013-06-27 20:03:43 +0000176
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000177 // TODO(edisonn): report warning to be used in testing.
178 if (!pdfStream ||
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000179 !pdfStream->GetFilteredStreamRef(&uncompressedStream, &uncompressedStreamLength) ||
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000180 !uncompressedStream ||
181 !uncompressedStreamLength) {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000182 return NULL;
183 }
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000184
edisonn@google.com6e49c342013-06-27 20:03:43 +0000185 SkMemoryStream* skStream = new SkMemoryStream(uncompressedStream, uncompressedStreamLength);
186 SkTypeface* face = SkTypeface::CreateFromStream(skStream);
187
188 if (face == NULL) {
189 // TODO(edisonn): report warning to be used in testing.
190 return NULL;
191 }
192
193 face->ref();
194
195 return new SkPdfStandardFont(face);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000196}
197
edisonn@google.com3aa35552013-08-14 18:26:20 +0000198SkPdfFont* fontFromName(SkPdfNativeDoc* doc, SkPdfNativeObject* obj, const char* fontName) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000199 SkTypeface* typeface = SkTypefaceFromPdfStandardFont(fontName, false, false);
200 if (typeface != NULL) {
201 return new SkPdfStandardFont(typeface);
202 }
edisonn@google.comeee4b652013-06-27 13:22:42 +0000203
204 // TODO(edisonn): perf - make a map
edisonn@google.com571c70b2013-07-10 17:09:50 +0000205 for (unsigned int i = 0 ; i < doc->objects(); i++) {
edisonn@google.com3aa35552013-08-14 18:26:20 +0000206 SkPdfNativeObject* obj = doc->object(i);
edisonn@google.comb44334c2013-07-23 20:47:05 +0000207 if (!obj || !obj->isDictionary()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000208 continue;
209 }
edisonn@google.comab03e682013-06-28 18:51:20 +0000210
edisonn@google.com571c70b2013-07-10 17:09:50 +0000211 SkPdfFontDescriptorDictionary* fd = obj->asDictionary()->asFontDescriptorDictionary();
212
213 if (!fd->valid()) {
214 continue;
215 }
216
edisonn@google.com063d7072013-08-16 15:05:08 +0000217 if (fd->has_FontName() && fd->FontName(doc).equals(fontName)) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000218 SkPdfFont* font = SkPdfFont::fontFromFontDescriptor(doc, fd, false);
219 if (font) {
220 return font;
221 } else {
222 // failed to load font descriptor
223 break;
edisonn@google.comeee4b652013-06-27 13:22:42 +0000224 }
225 }
226 }
227
228 // TODO(edisonn): warning/report issue
edisonn@google.com1be794f2013-06-21 21:43:09 +0000229 return SkPdfFont::Default();
230}
231
edisonn@google.com3aa35552013-08-14 18:26:20 +0000232SkPdfFont* SkPdfFont::fontFromPdfDictionaryOnce(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict) {
233 // TODO(edisonn): keep the type in a smart way in the SkPdfNativeObject
edisonn@google.com571c70b2013-07-10 17:09:50 +0000234 // 1) flag, isResolved (1bit): reset at reset, add/remove/update (array) and set(dict)
235 // in a tree like structure, 3-4 bits for all the datatypes inheriting from obj (int, real, ...)
236 // if is a dict, reserveve a few bytes to encode type of dict, and so on like in a tree
237 // issue: type can be determined from context! atribute night be missing/wrong
238 switch (doc->mapper()->mapFontDictionary(dict)) {
edisonn@google.com3aa35552013-08-14 18:26:20 +0000239 case kType0FontDictionary_SkPdfNativeObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000240 return fontFromType0FontDictionary(doc, dict->asType0FontDictionary());
241
edisonn@google.com3aa35552013-08-14 18:26:20 +0000242 case kTrueTypeFontDictionary_SkPdfNativeObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000243 return fontFromTrueTypeFontDictionary(doc, dict->asTrueTypeFontDictionary());
244
edisonn@google.com3aa35552013-08-14 18:26:20 +0000245 case kType1FontDictionary_SkPdfNativeObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000246 return fontFromType1FontDictionary(doc, dict->asType1FontDictionary());
247
edisonn@google.com3aa35552013-08-14 18:26:20 +0000248 case kMultiMasterFontDictionary_SkPdfNativeObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000249 return fontFromMultiMasterFontDictionary(doc, dict->asMultiMasterFontDictionary());
250
edisonn@google.com3aa35552013-08-14 18:26:20 +0000251 case kType3FontDictionary_SkPdfNativeObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000252 return fontFromType3FontDictionary(doc, dict->asType3FontDictionary());
253
254 default:
255 // TODO(edisonn): report error?
256 return NULL;
257 }
258}
259
edisonn@google.com3aa35552013-08-14 18:26:20 +0000260SkPdfFont* SkPdfFont::fontFromPdfDictionary(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000261 if (dict == NULL) {
262 return NULL; // TODO(edisonn): report default one?
263 }
264
edisonn@google.com3aa35552013-08-14 18:26:20 +0000265 if (!dict->hasData(SkPdfNativeObject::kFont_Data)) {
266 dict->setData(fontFromPdfDictionaryOnce(doc, dict), SkPdfNativeObject::kFont_Data);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000267 }
edisonn@google.com3aa35552013-08-14 18:26:20 +0000268 return (SkPdfFont*)dict->data(SkPdfNativeObject::kFont_Data);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000269}
270
edisonn@google.com571c70b2013-07-10 17:09:50 +0000271
272
edisonn@google.com3aa35552013-08-14 18:26:20 +0000273SkPdfType0Font* SkPdfFont::fontFromType0FontDictionary(SkPdfNativeDoc* doc, SkPdfType0FontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000274 if (dict == NULL) {
275 return NULL; // default one?
276 }
277
edisonn@google.com571c70b2013-07-10 17:09:50 +0000278 return new SkPdfType0Font(doc, dict);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000279}
280
edisonn@google.com3aa35552013-08-14 18:26:20 +0000281SkPdfType1Font* SkPdfFont:: fontFromType1FontDictionary(SkPdfNativeDoc* doc, SkPdfType1FontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000282 if (dict == NULL) {
283 return NULL; // default one?
284 }
285
edisonn@google.com571c70b2013-07-10 17:09:50 +0000286 return new SkPdfType1Font(doc, dict);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000287}
288
edisonn@google.com3aa35552013-08-14 18:26:20 +0000289SkPdfType3Font* SkPdfFont::fontFromType3FontDictionary(SkPdfNativeDoc* doc, SkPdfType3FontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000290 if (dict == NULL) {
291 return NULL; // default one?
292 }
293
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000294
295
edisonn@google.com571c70b2013-07-10 17:09:50 +0000296 return new SkPdfType3Font(doc, dict);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000297}
298
edisonn@google.com3aa35552013-08-14 18:26:20 +0000299SkPdfTrueTypeFont* SkPdfFont::fontFromTrueTypeFontDictionary(SkPdfNativeDoc* doc, SkPdfTrueTypeFontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000300 if (dict == NULL) {
301 return NULL; // default one?
302 }
303
edisonn@google.com571c70b2013-07-10 17:09:50 +0000304 return new SkPdfTrueTypeFont(doc, dict);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000305}
306
edisonn@google.com3aa35552013-08-14 18:26:20 +0000307SkPdfMultiMasterFont* SkPdfFont::fontFromMultiMasterFontDictionary(SkPdfNativeDoc* doc, SkPdfMultiMasterFontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000308 if (dict == NULL) {
309 return NULL; // default one?
310 }
311
edisonn@google.com571c70b2013-07-10 17:09:50 +0000312 return new SkPdfMultiMasterFont(doc, dict);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000313}
314
edisonn@google.com3aa35552013-08-14 18:26:20 +0000315static int skstoi(const SkPdfNativeObject* str) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000316 // TODO(edisonn): report err of it is not a (hex) string
edisonn@google.com1be794f2013-06-21 21:43:09 +0000317 int ret = 0;
edisonn@google.come878e722013-07-29 19:10:58 +0000318 for (unsigned int i = 0 ; i < str->lenstr(); i++) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000319 ret = (ret << 8) + ((unsigned char*)str->c_str())[i];
edisonn@google.com1be794f2013-06-21 21:43:09 +0000320 }
edisonn@google.com1acab362013-07-25 22:03:22 +0000321 // TODO(edisonn): character larger than 0x0000ffff not supported right now.
322 return ret & 0x0000ffff;
edisonn@google.com1be794f2013-06-21 21:43:09 +0000323}
324
edisonn@google.com571c70b2013-07-10 17:09:50 +0000325#define tokenIsKeyword(token,keyword) (token.fType == kKeyword_TokenType && token.fKeywordLength==sizeof(keyword)-1 && strncmp(token.fKeyword, keyword, sizeof(keyword)-1) == 0)
326
edisonn@google.com3aa35552013-08-14 18:26:20 +0000327SkPdfToUnicode::SkPdfToUnicode(SkPdfNativeDoc* parsed, SkPdfStream* stream) : fParsed(parsed) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000328 fCMapEncoding = NULL;
329 fCMapEncodingFlag = NULL;
330
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000331 if (stream) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000332 // Since font will be cached, the font has to sit in the per doc allocator, not to be
333 // freed after the page is done drawing.
334 SkPdfNativeTokenizer* tokenizer = fParsed->tokenizerOfStream(stream, parsed->allocator());
edisonn@google.com1be794f2013-06-21 21:43:09 +0000335 PdfToken token;
336
337 fCMapEncoding = new unsigned short[256 * 256];
338 fCMapEncodingFlag = new unsigned char[256 * 256];
339 for (int i = 0 ; i < 256 * 256; i++) {
340 fCMapEncoding[i] = i;
341 fCMapEncodingFlag[i] = 0;
342 }
343
344 // TODO(edisonn): deal with multibyte character, or longer strings.
345 // Ritght now we deal with up 2 characters, e.g. <0020> but not longer like <00660066006C>
346 //2 beginbfrange
347 //<0000> <005E> <0020>
348 //<005F> <0061> [<00660066> <00660069> <00660066006C>]
349
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000350 while (tokenizer->readToken(&token)) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000351
edisonn@google.com571c70b2013-07-10 17:09:50 +0000352 // TODO(edisonn): perf, macro that would make equal first for token.fKeywordLength with sizeof(keyword), instead od strlen, make sure it is keyword, not a char*
353 if (tokenIsKeyword(token, "begincodespacerange")) {
354 while (tokenizer->readToken(&token) && !tokenIsKeyword(token, "endcodespacerange")) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000355// tokenizer->PutBack(token);
356// tokenizer->readToken(&token);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000357 // TODO(edisonn): check token type! ignore/report errors.
edisonn@google.com571c70b2013-07-10 17:09:50 +0000358 int start = skstoi(token.fObject);
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000359 tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000360 int end = skstoi(token.fObject);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000361 for (int i = start; i <= end; i++) {
362 fCMapEncodingFlag[i] |= 1;
363 }
364 }
365 }
366
edisonn@google.com571c70b2013-07-10 17:09:50 +0000367 if (tokenIsKeyword(token, "beginbfchar")) {
368 while (tokenizer->readToken(&token) && !tokenIsKeyword(token, "endbfchar")) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000369// tokenizer->PutBack(token);
370// tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000371 int from = skstoi(token.fObject);
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000372 tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000373 int to = skstoi(token.fObject);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000374
375 fCMapEncodingFlag[from] |= 2;
376 fCMapEncoding[from] = to;
377 }
378 }
379
edisonn@google.com571c70b2013-07-10 17:09:50 +0000380 if (tokenIsKeyword(token, "beginbfrange")) {
381 while (tokenizer->readToken(&token) && !tokenIsKeyword(token, "endbfrange")) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000382// tokenizer->PutBack(token);
383// tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000384 int start = skstoi(token.fObject);
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000385 tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000386 int end = skstoi(token.fObject);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000387
388
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000389 tokenizer->readToken(&token); // [ or just an array directly?
390// tokenizer->PutBack(token);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000391
edisonn@google.com571c70b2013-07-10 17:09:50 +0000392 // TODO(edisonn): read spec: any string or only hex string?
393 if (token.fType == kObject_TokenType && token.fObject->isAnyString()) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000394// tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000395 int value = skstoi(token.fObject);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000396
397 for (int i = start; i <= end; i++) {
398 fCMapEncodingFlag[i] |= 2;
399 fCMapEncoding[i] = value;
400 value++;
401 // if i != end, verify last byte id not if, ignore/report error
402 }
403
404 // read one string
edisonn@google.com571c70b2013-07-10 17:09:50 +0000405 } else if (token.fType == kObject_TokenType && token.fObject->isArray()) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000406// tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000407 for (unsigned int i = 0; i < token.fObject->size(); i++) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000408 fCMapEncodingFlag[start + i] |= 2;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000409 fCMapEncoding[start + i] = skstoi((*token.fObject)[i]);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000410 }
411 // read array
412 }
413
414 //fCMapEncodingFlag[from] = 1;
415 //fCMapEncoding[from] = to;
416 }
417 }
418 }
419 }
420}
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000421
422
edisonn@google.com3aa35552013-08-14 18:26:20 +0000423SkPdfType0Font::SkPdfType0Font(SkPdfNativeDoc* doc, SkPdfType0FontDictionary* dict) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000424 fBaseFont = fontFromName(doc, dict, dict->BaseFont(doc).c_str());
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000425 fEncoding = NULL;
426
427 if (dict->has_Encoding()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000428 if (dict->isEncodingAName(doc)) {
429 fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName(doc).c_str());
430 } else if (dict->isEncodingAStream(doc)) {
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000431 //fEncoding = loadEncodingFromStream(dict->getEncodingAsStream());
432 } else {
433 // TODO(edisonn): error ... warning .. assert?
434 }
435 }
436
437 if (dict->has_ToUnicode()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000438 fToUnicode = new SkPdfToUnicode(doc, dict->ToUnicode(doc));
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000439 }
440}
441
edisonn@google.com063d7072013-08-16 15:05:08 +0000442SkTDict<SkPdfEncoding*>& getStandardEncodings() {
443 static SkTDict<SkPdfEncoding*> encodings(10);
444 if (encodings.count() == 0) {
445 encodings.set("Identity-H", SkPdfIdentityHEncoding::instance());
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000446 }
447
448 return encodings;
449}
450
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000451SkPdfEncoding* SkPdfEncoding::fromName(const char* name) {
edisonn@google.com063d7072013-08-16 15:05:08 +0000452 SkPdfEncoding* encoding = NULL;
453 if (!getStandardEncodings().find(name, &encoding)) {
454 // TODO(edisonn): if the function return false, and we a guaranteed that the value is not
455 // changed, delete this set to null
456 encoding = NULL;
457 }
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000458
459#ifdef PDF_TRACE
460 if (encoding == NULL) {
461 printf("Encoding not found: %s\n", name);
462 }
463#endif
464 return encoding;
465}