blob: 72fd5b5c68ec018e9a4b172fe06a8aebb488e085 [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.come50d9a12013-10-10 20:58:22 +000010#include "SkPdfNativeTokenizer.h"
edisonn@google.comeee4b652013-06-27 13:22:42 +000011#include "SkStream.h"
12#include "SkTypeface.h"
13
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
edisonn@google.come50d9a12013-10-10 20:58:22 +000098 // TODO(edisonn): list all fonts available, buil post script name as in pdf spec
99 // TODO(edisonn): Does it work in all OSs ?
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000100 /*
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
103TrueType font itself.
104• In the absence of such an entry in the “name” table, derive a PostScript name
105from the name by which the font is known in the host operating system: on a
106Windows system, it is based on the lfFaceName field in a LOGFONT structure; in
107the Mac OS, it is based on the name of the FONDresource. If the name contains
108any spaces, the spaces are removed.
109If the font in a source document uses a bold or italic style, but there is no font
110data for that style, the host operating system will synthesize the style. In this case,
111a comma and the style name (one of Bold, Italic, or BoldItalic) are appended to the
112font 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
118by underscores in the value of BaseFont. For instance, as illustrated in Example
1195.7, the name “MinionMM 366 465 11 ” (which ends with a space character)
120becomes /MinionMM_366_465_11_.
121 */
edisonn@google.com1be794f2013-06-21 21:43:09 +0000122 }
123
124 return gPdfStandardFonts;
125}
126
127SkTypeface* SkTypefaceFromPdfStandardFont(const char* fontName, bool bold, bool italic) {
edisonn@google.com063d7072013-08-16 15:05:08 +0000128 SkTDict<SkPdfStandardFontEntry>& standardFontMap = getStandardFonts();
edisonn@google.com1be794f2013-06-21 21:43:09 +0000129
130 SkTypeface* typeface = NULL;
edisonn@google.com063d7072013-08-16 15:05:08 +0000131 SkPdfStandardFontEntry fontData;
edisonn@google.com1be794f2013-06-21 21:43:09 +0000132
edisonn@google.com063d7072013-08-16 15:05:08 +0000133 if (standardFontMap.find(fontName, &fontData)) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000134 // 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
edisonn@google.come50d9a12013-10-10 20:58:22 +0000155SkPdfFont* SkPdfFont::fontFromFontDescriptor(SkPdfNativeDoc* doc, SkPdfFontDescriptorDictionary* fd,
156 bool loadFromName) {
157 // TODO(edisonn): partial implementation.
edisonn@google.comeee4b652013-06-27 13:22:42 +0000158 // Only one, at most be available
edisonn@google.com6e49c342013-06-27 20:03:43 +0000159 SkPdfStream* pdfStream = NULL;
edisonn@google.comeee4b652013-06-27 13:22:42 +0000160 if (fd->has_FontFile()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000161 pdfStream = fd->FontFile(doc);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000162 } else if (fd->has_FontFile2()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000163 pdfStream = fd->FontFile2(doc);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000164 } if (fd->has_FontFile3()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000165 pdfStream = fd->FontFile3(doc);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000166 } else {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000167 if (loadFromName) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000168 return fontFromName(doc, fd, fd->FontName(doc).c_str());
edisonn@google.com6e49c342013-06-27 20:03:43 +0000169 }
edisonn@google.comeee4b652013-06-27 13:22:42 +0000170 }
171
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000172 const unsigned char* uncompressedStream = NULL;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000173 size_t uncompressedStreamLength = 0;
edisonn@google.com6e49c342013-06-27 20:03:43 +0000174
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000175 // TODO(edisonn): report warning to be used in testing.
176 if (!pdfStream ||
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000177 !pdfStream->GetFilteredStreamRef(&uncompressedStream, &uncompressedStreamLength) ||
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000178 !uncompressedStream ||
179 !uncompressedStreamLength) {
edisonn@google.com6e49c342013-06-27 20:03:43 +0000180 return NULL;
181 }
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000182
edisonn@google.com6e49c342013-06-27 20:03:43 +0000183 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);
edisonn@google.comeee4b652013-06-27 13:22:42 +0000194}
195
edisonn@google.com3aa35552013-08-14 18:26:20 +0000196SkPdfFont* fontFromName(SkPdfNativeDoc* doc, SkPdfNativeObject* obj, const char* fontName) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000197 SkTypeface* typeface = SkTypefaceFromPdfStandardFont(fontName, false, false);
198 if (typeface != NULL) {
199 return new SkPdfStandardFont(typeface);
200 }
edisonn@google.comeee4b652013-06-27 13:22:42 +0000201
202 // TODO(edisonn): perf - make a map
edisonn@google.com571c70b2013-07-10 17:09:50 +0000203 for (unsigned int i = 0 ; i < doc->objects(); i++) {
edisonn@google.com3aa35552013-08-14 18:26:20 +0000204 SkPdfNativeObject* obj = doc->object(i);
edisonn@google.comb44334c2013-07-23 20:47:05 +0000205 if (!obj || !obj->isDictionary()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000206 continue;
207 }
edisonn@google.comab03e682013-06-28 18:51:20 +0000208
edisonn@google.com571c70b2013-07-10 17:09:50 +0000209 SkPdfFontDescriptorDictionary* fd = obj->asDictionary()->asFontDescriptorDictionary();
210
211 if (!fd->valid()) {
212 continue;
213 }
214
edisonn@google.com063d7072013-08-16 15:05:08 +0000215 if (fd->has_FontName() && fd->FontName(doc).equals(fontName)) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000216 SkPdfFont* font = SkPdfFont::fontFromFontDescriptor(doc, fd, false);
217 if (font) {
218 return font;
219 } else {
220 // failed to load font descriptor
221 break;
edisonn@google.comeee4b652013-06-27 13:22:42 +0000222 }
223 }
224 }
225
226 // TODO(edisonn): warning/report issue
edisonn@google.com1be794f2013-06-21 21:43:09 +0000227 return SkPdfFont::Default();
228}
229
edisonn@google.com3aa35552013-08-14 18:26:20 +0000230SkPdfFont* SkPdfFont::fontFromPdfDictionaryOnce(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict) {
231 // TODO(edisonn): keep the type in a smart way in the SkPdfNativeObject
edisonn@google.com571c70b2013-07-10 17:09:50 +0000232 // 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, ...)
edisonn@google.come50d9a12013-10-10 20:58:22 +0000234 // if is a dict, reserve a few bytes to encode type of dict, and so on like in a tree
edisonn@google.com571c70b2013-07-10 17:09:50 +0000235 // issue: type can be determined from context! atribute night be missing/wrong
236 switch (doc->mapper()->mapFontDictionary(dict)) {
edisonn@google.com3aa35552013-08-14 18:26:20 +0000237 case kType0FontDictionary_SkPdfNativeObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000238 return fontFromType0FontDictionary(doc, dict->asType0FontDictionary());
239
edisonn@google.com3aa35552013-08-14 18:26:20 +0000240 case kTrueTypeFontDictionary_SkPdfNativeObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000241 return fontFromTrueTypeFontDictionary(doc, dict->asTrueTypeFontDictionary());
242
edisonn@google.com3aa35552013-08-14 18:26:20 +0000243 case kType1FontDictionary_SkPdfNativeObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000244 return fontFromType1FontDictionary(doc, dict->asType1FontDictionary());
245
edisonn@google.com3aa35552013-08-14 18:26:20 +0000246 case kMultiMasterFontDictionary_SkPdfNativeObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000247 return fontFromMultiMasterFontDictionary(doc, dict->asMultiMasterFontDictionary());
248
edisonn@google.com3aa35552013-08-14 18:26:20 +0000249 case kType3FontDictionary_SkPdfNativeObjectType:
edisonn@google.com571c70b2013-07-10 17:09:50 +0000250 return fontFromType3FontDictionary(doc, dict->asType3FontDictionary());
251
252 default:
253 // TODO(edisonn): report error?
254 return NULL;
255 }
256}
257
edisonn@google.com3aa35552013-08-14 18:26:20 +0000258SkPdfFont* SkPdfFont::fontFromPdfDictionary(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000259 if (dict == NULL) {
260 return NULL; // TODO(edisonn): report default one?
261 }
262
edisonn@google.com3aa35552013-08-14 18:26:20 +0000263 if (!dict->hasData(SkPdfNativeObject::kFont_Data)) {
264 dict->setData(fontFromPdfDictionaryOnce(doc, dict), SkPdfNativeObject::kFont_Data);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000265 }
edisonn@google.com3aa35552013-08-14 18:26:20 +0000266 return (SkPdfFont*)dict->data(SkPdfNativeObject::kFont_Data);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000267}
268
edisonn@google.com571c70b2013-07-10 17:09:50 +0000269
270
edisonn@google.come50d9a12013-10-10 20:58:22 +0000271SkPdfType0Font* SkPdfFont::fontFromType0FontDictionary(SkPdfNativeDoc* doc,
272 SkPdfType0FontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000273 if (dict == NULL) {
274 return NULL; // default one?
275 }
276
edisonn@google.com571c70b2013-07-10 17:09:50 +0000277 return new SkPdfType0Font(doc, dict);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000278}
279
edisonn@google.come50d9a12013-10-10 20:58:22 +0000280SkPdfType1Font* SkPdfFont:: fontFromType1FontDictionary(SkPdfNativeDoc* doc,
281 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.come50d9a12013-10-10 20:58:22 +0000289SkPdfType3Font* SkPdfFont::fontFromType3FontDictionary(SkPdfNativeDoc* doc,
290 SkPdfType3FontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000291 if (dict == NULL) {
292 return NULL; // default one?
293 }
294
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000295
296
edisonn@google.com571c70b2013-07-10 17:09:50 +0000297 return new SkPdfType3Font(doc, dict);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000298}
299
edisonn@google.come50d9a12013-10-10 20:58:22 +0000300SkPdfTrueTypeFont* SkPdfFont::fontFromTrueTypeFontDictionary(SkPdfNativeDoc* doc,
301 SkPdfTrueTypeFontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000302 if (dict == NULL) {
303 return NULL; // default one?
304 }
305
edisonn@google.com571c70b2013-07-10 17:09:50 +0000306 return new SkPdfTrueTypeFont(doc, dict);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000307}
308
edisonn@google.come50d9a12013-10-10 20:58:22 +0000309SkPdfMultiMasterFont* SkPdfFont::fontFromMultiMasterFontDictionary(
310 SkPdfNativeDoc* doc, SkPdfMultiMasterFontDictionary* dict) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000311 if (dict == NULL) {
312 return NULL; // default one?
313 }
314
edisonn@google.com571c70b2013-07-10 17:09:50 +0000315 return new SkPdfMultiMasterFont(doc, dict);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000316}
317
edisonn@google.com3aa35552013-08-14 18:26:20 +0000318static int skstoi(const SkPdfNativeObject* str) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000319 // TODO(edisonn): report err of it is not a (hex) string
edisonn@google.com1be794f2013-06-21 21:43:09 +0000320 int ret = 0;
edisonn@google.come878e722013-07-29 19:10:58 +0000321 for (unsigned int i = 0 ; i < str->lenstr(); i++) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000322 ret = (ret << 8) + ((unsigned char*)str->c_str())[i];
edisonn@google.com1be794f2013-06-21 21:43:09 +0000323 }
edisonn@google.com1acab362013-07-25 22:03:22 +0000324 // TODO(edisonn): character larger than 0x0000ffff not supported right now.
325 return ret & 0x0000ffff;
edisonn@google.com1be794f2013-06-21 21:43:09 +0000326}
327
edisonn@google.come50d9a12013-10-10 20:58:22 +0000328#define tokenIsKeyword(token,keyword) (token.fType == kKeyword_TokenType && \
329 token.fKeywordLength==sizeof(keyword)-1 && \
330 strncmp(token.fKeyword, keyword, sizeof(keyword)-1) == 0)
edisonn@google.com571c70b2013-07-10 17:09:50 +0000331
edisonn@google.com3aa35552013-08-14 18:26:20 +0000332SkPdfToUnicode::SkPdfToUnicode(SkPdfNativeDoc* parsed, SkPdfStream* stream) : fParsed(parsed) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000333 fCMapEncoding = NULL;
334 fCMapEncodingFlag = NULL;
335
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000336 if (stream) {
edisonn@google.com2ccc3af2013-07-23 17:43:18 +0000337 // 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 = fParsed->tokenizerOfStream(stream, parsed->allocator());
edisonn@google.com1be794f2013-06-21 21:43:09 +0000340 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.
edisonn@google.come50d9a12013-10-10 20:58:22 +0000350 // Right now we deal with up 2 characters, e.g. <0020> but not longer like <00660066006C>
edisonn@google.com1be794f2013-06-21 21:43:09 +0000351 //2 beginbfrange
352 //<0000> <005E> <0020>
353 //<005F> <0061> [<00660066> <00660069> <00660066006C>]
354
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000355 while (tokenizer->readToken(&token)) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000356
edisonn@google.com571c70b2013-07-10 17:09:50 +0000357 if (tokenIsKeyword(token, "begincodespacerange")) {
edisonn@google.come50d9a12013-10-10 20:58:22 +0000358 while (tokenizer->readToken(&token) &&
359 !tokenIsKeyword(token, "endcodespacerange")) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000360// tokenizer->PutBack(token);
361// tokenizer->readToken(&token);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000362 // TODO(edisonn): check token type! ignore/report errors.
edisonn@google.com571c70b2013-07-10 17:09:50 +0000363 int start = skstoi(token.fObject);
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000364 tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000365 int end = skstoi(token.fObject);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000366 for (int i = start; i <= end; i++) {
367 fCMapEncodingFlag[i] |= 1;
368 }
369 }
370 }
371
edisonn@google.com571c70b2013-07-10 17:09:50 +0000372 if (tokenIsKeyword(token, "beginbfchar")) {
373 while (tokenizer->readToken(&token) && !tokenIsKeyword(token, "endbfchar")) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000374// tokenizer->PutBack(token);
375// tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000376 int from = skstoi(token.fObject);
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000377 tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000378 int to = skstoi(token.fObject);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000379
380 fCMapEncodingFlag[from] |= 2;
381 fCMapEncoding[from] = to;
382 }
383 }
384
edisonn@google.com571c70b2013-07-10 17:09:50 +0000385 if (tokenIsKeyword(token, "beginbfrange")) {
386 while (tokenizer->readToken(&token) && !tokenIsKeyword(token, "endbfrange")) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000387// tokenizer->PutBack(token);
388// tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000389 int start = skstoi(token.fObject);
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000390 tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000391 int end = skstoi(token.fObject);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000392
393
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000394 tokenizer->readToken(&token); // [ or just an array directly?
edisonn@google.come50d9a12013-10-10 20:58:22 +0000395 // do not putback, we will reuse the read. See next commented read.
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000396// tokenizer->PutBack(token);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000397
edisonn@google.com571c70b2013-07-10 17:09:50 +0000398 // TODO(edisonn): read spec: any string or only hex string?
399 if (token.fType == kObject_TokenType && token.fObject->isAnyString()) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000400// tokenizer->readToken(&token);
edisonn@google.com571c70b2013-07-10 17:09:50 +0000401 int value = skstoi(token.fObject);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000402
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
edisonn@google.com571c70b2013-07-10 17:09:50 +0000411 } else if (token.fType == kObject_TokenType && token.fObject->isArray()) {
edisonn@google.com3aac1f92013-07-02 22:42:53 +0000412// tokenizer->readToken(&token);
edisonn@google.come50d9a12013-10-10 20:58:22 +0000413 // read array
edisonn@google.com571c70b2013-07-10 17:09:50 +0000414 for (unsigned int i = 0; i < token.fObject->size(); i++) {
edisonn@google.com1be794f2013-06-21 21:43:09 +0000415 fCMapEncodingFlag[start + i] |= 2;
edisonn@google.com571c70b2013-07-10 17:09:50 +0000416 fCMapEncoding[start + i] = skstoi((*token.fObject)[i]);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000417 }
edisonn@google.come50d9a12013-10-10 20:58:22 +0000418 } else {
419 tokenizer->PutBack(token);
edisonn@google.com1be794f2013-06-21 21:43:09 +0000420 }
edisonn@google.com1be794f2013-06-21 21:43:09 +0000421 }
422 }
423 }
424 }
425}
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000426
edisonn@google.com3aa35552013-08-14 18:26:20 +0000427SkPdfType0Font::SkPdfType0Font(SkPdfNativeDoc* doc, SkPdfType0FontDictionary* dict) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000428 fBaseFont = fontFromName(doc, dict, dict->BaseFont(doc).c_str());
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000429 fEncoding = NULL;
430
431 if (dict->has_Encoding()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000432 if (dict->isEncodingAName(doc)) {
433 fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName(doc).c_str());
434 } else if (dict->isEncodingAStream(doc)) {
edisonn@google.come50d9a12013-10-10 20:58:22 +0000435 // TODO(edisonn): NYI
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000436 //fEncoding = loadEncodingFromStream(dict->getEncodingAsStream());
437 } else {
438 // TODO(edisonn): error ... warning .. assert?
439 }
440 }
441
442 if (dict->has_ToUnicode()) {
edisonn@google.com571c70b2013-07-10 17:09:50 +0000443 fToUnicode = new SkPdfToUnicode(doc, dict->ToUnicode(doc));
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000444 }
445}
446
edisonn@google.com063d7072013-08-16 15:05:08 +0000447SkTDict<SkPdfEncoding*>& getStandardEncodings() {
448 static SkTDict<SkPdfEncoding*> encodings(10);
449 if (encodings.count() == 0) {
450 encodings.set("Identity-H", SkPdfIdentityHEncoding::instance());
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000451 }
452
453 return encodings;
454}
455
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000456SkPdfEncoding* SkPdfEncoding::fromName(const char* name) {
edisonn@google.com063d7072013-08-16 15:05:08 +0000457 SkPdfEncoding* encoding = NULL;
458 if (!getStandardEncodings().find(name, &encoding)) {
edisonn@google.com063d7072013-08-16 15:05:08 +0000459 encoding = NULL;
460 }
edisonn@google.comb857a0c2013-06-25 20:45:40 +0000461
462#ifdef PDF_TRACE
463 if (encoding == NULL) {
464 printf("Encoding not found: %s\n", name);
465 }
466#endif
467 return encoding;
468}