summaryrefslogtreecommitdiff
path: root/noncore/unsupported/qpdf/xpdf/GfxFont.cc
Unidiff
Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/GfxFont.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/unsupported/qpdf/xpdf/GfxFont.cc1247
1 files changed, 1247 insertions, 0 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/GfxFont.cc b/noncore/unsupported/qpdf/xpdf/GfxFont.cc
new file mode 100644
index 0000000..518f97b
--- a/dev/null
+++ b/noncore/unsupported/qpdf/xpdf/GfxFont.cc
@@ -0,0 +1,1247 @@
1//========================================================================
2//
3// GfxFont.cc
4//
5// Copyright 1996-2001 Derek B. Noonburg
6//
7//========================================================================
8
9#ifdef __GNUC__
10#pragma implementation
11#endif
12
13#include <aconf.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <ctype.h>
18#include "gmem.h"
19#include "Error.h"
20#include "Object.h"
21#include "Dict.h"
22#include "GlobalParams.h"
23#include "CMap.h"
24#include "CharCodeToUnicode.h"
25#include "FontEncodingTables.h"
26#include "BuiltinFontTables.h"
27#include "FontFile.h"
28#include "GfxFont.h"
29
30//------------------------------------------------------------------------
31
32struct StdFontMapEntry {
33 char *altName;
34 char *properName;
35};
36
37static StdFontMapEntry stdFontMap[] = {
38 { "Arial", "Helvetica" },
39 { "Arial,Bold", "Helvetica-Bold" },
40 { "Arial,BoldItalic", "Helvetica-BoldOblique" },
41 { "Arial,Italic", "Helvetica-Oblique" },
42 { "Arial-Bold", "Helvetica-Bold" },
43 { "Arial-BoldItalic", "Helvetica-BoldOblique" },
44 { "Arial-BoldItalicMT", "Helvetica-BoldOblique" },
45 { "Arial-BoldMT", "Helvetica-Bold" },
46 { "Arial-Italic", "Helvetica-Oblique" },
47 { "Arial-ItalicMT", "Helvetica-Oblique" },
48 { "ArialMT", "Helvetica" },
49 { "Courier,Bold", "Courier-Bold" },
50 { "Courier,Italic", "Courier-Oblique" },
51 { "Courier,BoldItalic", "Courier-BoldOblique" },
52 { "CourierNew", "Courier" },
53 { "CourierNew,Bold", "Courier-Bold" },
54 { "CourierNew,BoldItalic", "Courier-BoldOblique" },
55 { "CourierNew,Italic", "Courier-Oblique" },
56 { "CourierNew-Bold", "Courier-Bold" },
57 { "CourierNew-BoldItalic", "Courier-BoldOblique" },
58 { "CourierNew-Italic", "Courier-Oblique" },
59 { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" },
60 { "CourierNewPS-BoldMT", "Courier-Bold" },
61 { "CourierNewPS-ItalicMT", "Courier-Oblique" },
62 { "CourierNewPSMT", "Courier" },
63 { "Helvetica,Bold", "Helvetica-Bold" },
64 { "Helvetica,BoldItalic", "Helvetica-BoldOblique" },
65 { "Helvetica,Italic", "Helvetica-Oblique" },
66 { "Helvetica-BoldItalic", "Helvetica-BoldOblique" },
67 { "Helvetica-Italic", "Helvetica-Oblique" },
68 { "TimesNewRoman", "Times-Roman" },
69 { "TimesNewRoman,Bold", "Times-Bold" },
70 { "TimesNewRoman,BoldItalic", "Times-BoldItalic" },
71 { "TimesNewRoman,Italic", "Times-Italic" },
72 { "TimesNewRoman-Bold", "Times-Bold" },
73 { "TimesNewRoman-BoldItalic", "Times-BoldItalic" },
74 { "TimesNewRoman-Italic", "Times-Italic" },
75 { "TimesNewRomanPS", "Times-Roman" },
76 { "TimesNewRomanPS-Bold", "Times-Bold" },
77 { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" },
78 { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" },
79 { "TimesNewRomanPS-BoldMT", "Times-Bold" },
80 { "TimesNewRomanPS-Italic", "Times-Italic" },
81 { "TimesNewRomanPS-ItalicMT", "Times-Italic" },
82 { "TimesNewRomanPSMT", "Times-Roman" }
83};
84
85//------------------------------------------------------------------------
86// GfxFont
87//------------------------------------------------------------------------
88
89GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) {
90 GString *nameA;
91 GfxFont *font;
92 Object obj1;
93
94 // get base font name
95 nameA = NULL;
96 fontDict->lookup("BaseFont", &obj1);
97 if (obj1.isName()) {
98 nameA = new GString(obj1.getName());
99 }
100 obj1.free();
101
102 // get font type
103 font = NULL;
104 fontDict->lookup("Subtype", &obj1);
105 if (obj1.isName("Type1") || obj1.isName("MMType1")) {
106 font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict);
107 } else if (obj1.isName("Type1C")) {
108 font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict);
109 } else if (obj1.isName("Type3")) {
110 font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict);
111 } else if (obj1.isName("TrueType")) {
112 font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict);
113 } else if (obj1.isName("Type0")) {
114 font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict);
115 } else {
116 error(-1, "Unknown font type: '%s'",
117 obj1.isName() ? obj1.getName() : "???");
118 font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict);
119 }
120 obj1.free();
121
122 return font;
123}
124
125GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) {
126 ok = gFalse;
127 tag = new GString(tagA);
128 id = idA;
129 name = nameA;
130 embFontName = NULL;
131 extFontFile = NULL;
132}
133
134GfxFont::~GfxFont() {
135 delete tag;
136 if (name) {
137 delete name;
138 }
139 if (embFontName) {
140 delete embFontName;
141 }
142 if (extFontFile) {
143 delete extFontFile;
144 }
145}
146
147void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
148 Object obj1, obj2, obj3, obj4;
149 fouble t;
150 int i;
151
152 // assume Times-Roman by default (for substitution purposes)
153 flags = fontSerif;
154
155 embFontID.num = -1;
156 embFontID.gen = -1;
157 missingWidth = 0;
158
159 if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
160
161 // get flags
162 if (obj1.dictLookup("Flags", &obj2)->isInt()) {
163 flags = obj2.getInt();
164 }
165 obj2.free();
166
167 // get name
168 obj1.dictLookup("FontName", &obj2);
169 if (obj2.isName()) {
170 embFontName = new GString(obj2.getName());
171 }
172 obj2.free();
173
174 // look for embedded font file
175 if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) {
176 if (type == fontType1) {
177 embFontID = obj2.getRef();
178 } else {
179 error(-1, "Mismatch between font type and embedded font file");
180 }
181 }
182 obj2.free();
183 if (embFontID.num == -1 &&
184 obj1.dictLookupNF("FontFile2", &obj2)->isRef()) {
185 if (type == fontTrueType || type == fontCIDType2) {
186 embFontID = obj2.getRef();
187 } else {
188 error(-1, "Mismatch between font type and embedded font file");
189 }
190 }
191 obj2.free();
192 if (embFontID.num == -1 &&
193 obj1.dictLookupNF("FontFile3", &obj2)->isRef()) {
194 if (obj2.fetch(xref, &obj3)->isStream()) {
195 obj3.streamGetDict()->lookup("Subtype", &obj4);
196 if (obj4.isName("Type1")) {
197 if (type == fontType1) {
198 embFontID = obj2.getRef();
199 } else {
200 error(-1, "Mismatch between font type and embedded font file");
201 }
202 } else if (obj4.isName("Type1C")) {
203 if (type == fontType1) {
204 type = fontType1C;
205 embFontID = obj2.getRef();
206 } else if (type == fontType1C) {
207 embFontID = obj2.getRef();
208 } else {
209 error(-1, "Mismatch between font type and embedded font file");
210 }
211 } else if (obj4.isName("TrueType")) {
212 if (type == fontTrueType) {
213 embFontID = obj2.getRef();
214 } else {
215 error(-1, "Mismatch between font type and embedded font file");
216 }
217 } else if (obj4.isName("CIDFontType0C")) {
218 if (type == fontCIDType0) {
219 type = fontCIDType0C;
220 embFontID = obj2.getRef();
221 } else {
222 error(-1, "Mismatch between font type and embedded font file");
223 }
224 } else {
225 error(-1, "Unknown embedded font type '%s'",
226 obj4.isName() ? obj4.getName() : "???");
227 }
228 obj4.free();
229 }
230 obj3.free();
231 }
232 obj2.free();
233
234 // look for MissingWidth
235 obj1.dictLookup("MissingWidth", &obj2);
236 if (obj2.isNum()) {
237 missingWidth = obj2.getNum();
238 }
239 obj2.free();
240
241 // get Ascent and Descent
242 obj1.dictLookup("Ascent", &obj2);
243 if (obj2.isNum()) {
244 t = 0.001 * obj2.getNum();
245 // some broken font descriptors set ascent and descent to 0
246 if (t != 0) {
247 ascent = t;
248 }
249 }
250 obj2.free();
251 obj1.dictLookup("Descent", &obj2);
252 if (obj2.isNum()) {
253 t = 0.001 * obj2.getNum();
254 // some broken font descriptors set ascent and descent to 0
255 if (t != 0) {
256 descent = t;
257 }
258 }
259 obj2.free();
260
261 // font FontBBox
262 if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
263 for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
264 if (obj2.arrayGet(i, &obj3)->isNum()) {
265 fontBBox[i] = 0.001 * obj3.getNum();
266 }
267 obj3.free();
268 }
269 }
270 obj2.free();
271
272 }
273 obj1.free();
274}
275
276CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits) {
277 CharCodeToUnicode *ctu;
278 GString *buf;
279 Object obj1;
280 int c;
281
282 if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) {
283 obj1.free();
284 return NULL;
285 }
286 buf = new GString();
287 obj1.streamReset();
288 while ((c = obj1.streamGetChar()) != EOF) {
289 buf->append(c);
290 }
291 obj1.streamClose();
292 obj1.free();
293 ctu = CharCodeToUnicode::parseCMap(buf, nBits);
294 delete buf;
295 return ctu;
296}
297
298void GfxFont::findExtFontFile() {
299 if (name) {
300 if (type == fontType1) {
301 extFontFile = globalParams->findFontFile(name, ".pfa", ".pfb");
302 } else if (type == fontTrueType) {
303 extFontFile = globalParams->findFontFile(name, ".ttf", NULL);
304 }
305 }
306}
307
308char *GfxFont::readExtFontFile(int *len) {
309 FILE *f;
310 char *buf;
311
312 if (!(f = fopen(extFontFile->getCString(), "rb"))) {
313 error(-1, "External font file '%s' vanished", extFontFile->getCString());
314 return NULL;
315 }
316 fseek(f, 0, SEEK_END);
317 *len = (int)ftell(f);
318 fseek(f, 0, SEEK_SET);
319 buf = (char *)gmalloc(*len);
320 if ((int)fread(buf, 1, *len, f) != *len) {
321 error(-1, "Error reading external font file '%s'", extFontFile);
322 }
323 fclose(f);
324 return buf;
325}
326
327char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
328 char *buf;
329 Object obj1, obj2;
330 Stream *str;
331 int c;
332 int size, i;
333
334 obj1.initRef(embFontID.num, embFontID.gen);
335 obj1.fetch(xref, &obj2);
336 if (!obj2.isStream()) {
337 error(-1, "Embedded font file is not a stream");
338 obj2.free();
339 obj1.free();
340 embFontID.num = -1;
341 return NULL;
342 }
343 str = obj2.getStream();
344
345 buf = NULL;
346 i = size = 0;
347 str->reset();
348 while ((c = str->getChar()) != EOF) {
349 if (i == size) {
350 size += 4096;
351 buf = (char *)grealloc(buf, size);
352 }
353 buf[i++] = c;
354 }
355 *len = i;
356 str->close();
357
358 obj2.free();
359 obj1.free();
360
361 return buf;
362}
363
364//------------------------------------------------------------------------
365// Gfx8BitFont
366//------------------------------------------------------------------------
367
368Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
369 GfxFontType typeA, Dict *fontDict):
370 GfxFont(tagA, idA, nameA)
371{
372 BuiltinFont *builtinFont;
373 char **baseEnc;
374 GBool baseEncFromFontFile;
375 char *buf;
376 int len;
377 FontFile *fontFile;
378 int code, code2;
379 char *charName;
380 GBool missing, hex;
381 Unicode toUnicode[256];
382 fouble mul;
383 int firstChar, lastChar;
384 Gushort w;
385 Object obj1, obj2, obj3;
386 int n, i, a, b, m;
387
388 type = typeA;
389 ctu = NULL;
390
391 // Acrobat 4.0 and earlier substituted Base14-compatible fonts
392 // without providing Widths and a FontDescriptor, so we munge the
393 // names into the proper Base14 names. (This table is from
394 // implementation note 44 in the PDF 1.4 spec.)
395 if (name) {
396 a = 0;
397 b = sizeof(stdFontMap) / sizeof(StdFontMapEntry);
398 // invariant: stdFontMap[a].altName <= name < stdFontMap[b].altName
399 while (b - a > 1) {
400 m = (a + b) / 2;
401 if (name->cmp(stdFontMap[m].altName) >= 0) {
402 a = m;
403 } else {
404 b = m;
405 }
406 }
407 if (!name->cmp(stdFontMap[a].altName)) {
408 delete name;
409 name = new GString(stdFontMap[a].properName);
410 }
411 }
412
413 // is it a built-in font?
414 builtinFont = NULL;
415 if (name) {
416 for (i = 0; i < nBuiltinFonts; ++i) {
417 if (!name->cmp(builtinFonts[i].name)) {
418 builtinFont = &builtinFonts[i];
419 break;
420 }
421 }
422 }
423
424 // default ascent/descent values
425 if (builtinFont) {
426 ascent = 0.001 * builtinFont->ascent;
427 descent = 0.001 * builtinFont->descent;
428 fontBBox[0] = 0.001 * builtinFont->bbox[0];
429 fontBBox[1] = 0.001 * builtinFont->bbox[1];
430 fontBBox[2] = 0.001 * builtinFont->bbox[2];
431 fontBBox[3] = 0.001 * builtinFont->bbox[3];
432 } else {
433 ascent = 0.95;
434 descent = -0.35;
435 fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
436 }
437
438 // get info from font descriptor
439 readFontDescriptor(xref, fontDict);
440
441 // look for an external font file
442 findExtFontFile();
443
444 // get font matrix
445 fontMat[0] = fontMat[3] = 1;
446 fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
447 if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
448 for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
449 if (obj1.arrayGet(i, &obj2)->isNum()) {
450 fontMat[i] = obj2.getNum();
451 }
452 obj2.free();
453 }
454 }
455 obj1.free();
456
457 // get Type3 font definition
458 if (type == fontType3) {
459 fontDict->lookup("CharProcs", &charProcs);
460 if (!charProcs.isDict()) {
461 error(-1, "Missing or invalid CharProcs dictionary in Type 3 font");
462 charProcs.free();
463 }
464 }
465
466 //----- build the font encoding -----
467
468 // Encodings start with a base encoding, which can come from
469 // (in order of priority):
470 // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
471 // - MacRoman / MacExpert / WinAnsi / Standard
472 // 2. embedded or external font file
473 // 3. default:
474 // - builtin --> builtin encoding
475 // - TrueType --> MacRomanEncoding
476 // - others --> StandardEncoding
477 // and then add a list of differences (if any) from
478 // FontDict.Encoding.Differences.
479
480 // check FontDict for base encoding
481 hasEncoding = gFalse;
482 baseEnc = NULL;
483 baseEncFromFontFile = gFalse;
484 fontDict->lookup("Encoding", &obj1);
485 if (obj1.isDict()) {
486 obj1.dictLookup("BaseEncoding", &obj2);
487 if (obj2.isName("MacRomanEncoding")) {
488 hasEncoding = gTrue;
489 baseEnc = macRomanEncoding;
490 } else if (obj2.isName("MacExpertEncoding")) {
491 hasEncoding = gTrue;
492 baseEnc = macExpertEncoding;
493 } else if (obj2.isName("WinAnsiEncoding")) {
494 hasEncoding = gTrue;
495 baseEnc = winAnsiEncoding;
496 } else if (obj2.isName("StandardEncoding")) {
497 hasEncoding = gTrue;
498 baseEnc = standardEncoding;
499 }
500 obj2.free();
501 } else if (obj1.isName("MacRomanEncoding")) {
502 hasEncoding = gTrue;
503 baseEnc = macRomanEncoding;
504 } else if (obj1.isName("MacExpertEncoding")) {
505 hasEncoding = gTrue;
506 baseEnc = macExpertEncoding;
507 } else if (obj1.isName("WinAnsiEncoding")) {
508 hasEncoding = gTrue;
509 baseEnc = winAnsiEncoding;
510 } else if (obj1.isName("StandardEncoding")) {
511 hasEncoding = gTrue;
512 baseEnc = standardEncoding;
513 }
514
515 // check embedded or external font file for base encoding
516 fontFile = NULL;
517 buf = NULL;
518 if ((type == fontType1 || type == fontType1C || type == fontTrueType) &&
519 (extFontFile || embFontID.num >= 0)) {
520 if (extFontFile) {
521 buf = readExtFontFile(&len);
522 } else {
523 buf = readEmbFontFile(xref, &len);
524 }
525 if (buf) {
526#if 0
527 if (type == fontType1) {
528 fontFile = new Type1FontFile(buf, len);
529 } else if (type == fontType1C) {
530 fontFile = new Type1CFontFile(buf, len);
531 } else {
532 fontFile = new TrueTypeFontFile(buf, len);
533 }
534 if (fontFile->getName()) {
535 if (embFontName) {
536 delete embFontName;
537 }
538 embFontName = new GString(fontFile->getName());
539 }
540 if (!baseEnc) {
541 baseEnc = fontFile->getEncoding();
542 baseEncFromFontFile = gTrue;
543 }
544#endif
545 gfree(buf);
546 }
547 }
548
549 // get default base encoding
550 if (!baseEnc) {
551 if (builtinFont) {
552 baseEnc = builtinFont->defaultBaseEnc;
553 } else if (type == fontTrueType) {
554 baseEnc = macRomanEncoding;
555 } else {
556 baseEnc = standardEncoding;
557 }
558 }
559
560 // copy the base encoding
561 for (i = 0; i < 256; ++i) {
562 enc[i] = baseEnc[i];
563 if ((encFree[i] = baseEncFromFontFile) && enc[i]) {
564 enc[i] = copyString(baseEnc[i]);
565 }
566 }
567
568 // merge differences into encoding
569 if (obj1.isDict()) {
570 obj1.dictLookup("Differences", &obj2);
571 if (obj2.isArray()) {
572 code = 0;
573 for (i = 0; i < obj2.arrayGetLength(); ++i) {
574 obj2.arrayGet(i, &obj3);
575 if (obj3.isInt()) {
576 code = obj3.getInt();
577 } else if (obj3.isName()) {
578 if (code < 256) {
579 if (encFree[code]) {
580 gfree(enc[code]);
581 }
582 enc[code] = copyString(obj3.getName());
583 encFree[code] = gTrue;
584 }
585 ++code;
586 } else {
587 error(-1, "Wrong type in font encoding resource differences (%s)",
588 obj3.getTypeName());
589 }
590 obj3.free();
591 }
592 }
593 obj2.free();
594 }
595 obj1.free();
596 if (fontFile) {
597 delete fontFile;
598 }
599
600 //----- build the mapping to Unicode -----
601
602 // look for a ToUnicode CMap
603 if (!(ctu = readToUnicodeCMap(fontDict, 8))) {
604
605 // no ToUnicode CMap, so use the char names
606
607 // pass 1: use the name-to-Unicode mapping table
608 missing = hex = gFalse;
609 for (code = 0; code < 256; ++code) {
610 if ((charName = enc[code])) {
611 if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) &&
612 strcmp(charName, ".notdef")) {
613 // if it wasn't in the name-to-Unicode table, check for a
614 // name that looks like 'Axx' or 'xx', where 'A' is any letter
615 // and 'xx' is two hex digits
616 if ((strlen(charName) == 3 &&
617 isalpha(charName[0]) &&
618 isxdigit(charName[1]) && isxdigit(charName[2]) &&
619 ((charName[1] >= 'a' && charName[1] <= 'f') ||
620 (charName[1] >= 'A' && charName[1] <= 'F') ||
621 (charName[2] >= 'a' && charName[2] <= 'f') ||
622 (charName[2] >= 'A' && charName[2] <= 'F'))) ||
623 (strlen(charName) == 2 &&
624 isxdigit(charName[0]) && isxdigit(charName[1]) &&
625 ((charName[0] >= 'a' && charName[0] <= 'f') ||
626 (charName[0] >= 'A' && charName[0] <= 'F') ||
627 (charName[1] >= 'a' && charName[1] <= 'f') ||
628 (charName[1] >= 'A' && charName[1] <= 'F')))) {
629 hex = gTrue;
630 }
631 missing = gTrue;
632 }
633 } else {
634 toUnicode[code] = 0;
635 }
636 }
637
638 // pass 2: try to fill in the missing chars, looking for names of
639 // the form 'Axx', 'xx', 'Ann', or 'nn', where 'A' is any letter,
640 // 'xx' is two hex digits, and 'nn' is 2-4 decimal digits
641 if (missing && globalParams->getMapNumericCharNames()) {
642 for (code = 0; code < 256; ++code) {
643 if ((charName = enc[code]) && !toUnicode[code] &&
644 strcmp(charName, ".notdef")) {
645 n = strlen(charName);
646 code2 = -1;
647 if (hex && n == 3 && isalpha(charName[0]) &&
648 isxdigit(charName[1]) && isxdigit(charName[2])) {
649 sscanf(charName+1, "%x", &code2);
650 } else if (hex && n == 2 &&
651 isxdigit(charName[0]) && isxdigit(charName[1])) {
652 sscanf(charName, "%x", &code2);
653 } else if (!hex && n >= 2 && n <= 4 &&
654 isdigit(charName[0]) && isdigit(charName[1])) {
655 code2 = atoi(charName);
656 } else if (n >= 3 && n <= 5 &&
657 isdigit(charName[1]) && isdigit(charName[2])) {
658 code2 = atoi(charName+1);
659 }
660 if (code2 >= 0 && code2 <= 0xff) {
661 toUnicode[code] = (Unicode)code2;
662 }
663 }
664 }
665 }
666
667 ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode);
668 }
669
670 //----- get the character widths -----
671
672 // initialize all widths
673 for (code = 0; code < 256; ++code) {
674 widths[code] = missingWidth * 0.001;
675 }
676
677 // use widths from font dict, if present
678 fontDict->lookup("FirstChar", &obj1);
679 firstChar = obj1.isInt() ? obj1.getInt() : 0;
680 obj1.free();
681 fontDict->lookup("LastChar", &obj1);
682 lastChar = obj1.isInt() ? obj1.getInt() : 255;
683 obj1.free();
684 mul = (type == fontType3) ? fontMat[0] : fouble(0.001);
685 fontDict->lookup("Widths", &obj1);
686 if (obj1.isArray()) {
687 for (code = firstChar; code <= lastChar; ++code) {
688 obj1.arrayGet(code - firstChar, &obj2);
689 if (obj2.isNum()) {
690 widths[code] = obj2.getNum() * mul;
691 }
692 obj2.free();
693 }
694
695 // use widths from built-in font
696 } else if (builtinFont) {
697 // this is a kludge for broken PDF files that encode char 32
698 // as .notdef
699 if (builtinFont->widths->getWidth("space", &w)) {
700 widths[32] = 0.001 * w;
701 }
702 for (code = 0; code < 256; ++code) {
703 if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
704 widths[code] = 0.001 * w;
705 }
706 }
707
708 // couldn't find widths -- use defaults
709 } else {
710 // this is technically an error -- the Widths entry is required
711 // for all but the Base-14 fonts -- but certain PDF generators
712 // apparently don't include widths for Arial and TimesNewRoman
713 if (isFixedWidth()) {
714 i = 0;
715 } else if (isSerif()) {
716 i = 8;
717 } else {
718 i = 4;
719 }
720 if (isBold()) {
721 i += 2;
722 }
723 if (isItalic()) {
724 i += 1;
725 }
726 builtinFont = builtinFontSubst[i];
727 // this is a kludge for broken PDF files that encode char 32
728 // as .notdef
729 if (builtinFont->widths->getWidth("space", &w)) {
730 widths[32] = 0.001 * w;
731 }
732 for (code = 0; code < 256; ++code) {
733 if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
734 widths[code] = 0.001 * w;
735 }
736 }
737 }
738 obj1.free();
739
740 ok = gTrue;
741}
742
743Gfx8BitFont::~Gfx8BitFont() {
744 int i;
745
746 for (i = 0; i < 256; ++i) {
747 if (encFree[i] && enc[i]) {
748 gfree(enc[i]);
749 }
750 }
751 ctu->decRefCnt();
752 if (charProcs.isDict()) {
753 charProcs.free();
754 }
755}
756
757int Gfx8BitFont::getNextChar(char *s, int len, CharCode *code,
758 Unicode *u, int uSize, int *uLen,
759 fouble *dx, fouble *dy, fouble *ox, fouble *oy) {
760 CharCode c;
761
762 *code = c = (CharCode)(*s & 0xff);
763 *uLen = ctu->mapToUnicode(c, u, uSize);
764 *dx = widths[c];
765 *dy = *ox = *oy = 0;
766 return 1;
767}
768
769CharCodeToUnicode *Gfx8BitFont::getToUnicode() {
770 ctu->incRefCnt();
771 return ctu;
772}
773
774Object *Gfx8BitFont::getCharProc(int code, Object *proc) {
775 if (charProcs.isDict()) {
776 charProcs.dictLookup(enc[code], proc);
777 } else {
778 proc->initNull();
779 }
780 return proc;
781}
782
783//------------------------------------------------------------------------
784// GfxCIDFont
785//------------------------------------------------------------------------
786
787static int cmpWidthExcep(const void *w1, const void *w2) {
788 return ((GfxFontCIDWidthExcep *)w1)->first -
789 ((GfxFontCIDWidthExcep *)w2)->first;
790}
791
792static int cmpWidthExcepV(const void *w1, const void *w2) {
793 return ((GfxFontCIDWidthExcepV *)w1)->first -
794 ((GfxFontCIDWidthExcepV *)w2)->first;
795}
796
797GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
798 Dict *fontDict):
799 GfxFont(tagA, idA, nameA)
800{
801 Dict *desFontDict;
802 GString *collection, *cMapName;
803 Object desFontDictObj;
804 Object obj1, obj2, obj3, obj4, obj5, obj6;
805 int c1, c2;
806 int excepsSize, i, j, k;
807
808 ascent = 0.95;
809 descent = -0.35;
810 fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
811 cMap = NULL;
812 ctu = NULL;
813 widths.defWidth = 1.0;
814 widths.defHeight = -1.0;
815 widths.defVY = 0.880;
816 widths.exceps = NULL;
817 widths.nExceps = 0;
818 widths.excepsV = NULL;
819 widths.nExcepsV = 0;
820 cidToGID = NULL;
821 cidToGIDLen = 0;
822
823 // get the descendant font
824 if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
825 error(-1, "Missing DescendantFonts entry in Type 0 font");
826 obj1.free();
827 goto err1;
828 }
829 if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
830 error(-1, "Bad descendant font in Type 0 font");
831 goto err3;
832 }
833 obj1.free();
834 desFontDict = desFontDictObj.getDict();
835
836 // font type
837 if (!desFontDict->lookup("Subtype", &obj1)) {
838 error(-1, "Missing Subtype entry in Type 0 descendant font");
839 goto err3;
840 }
841 if (obj1.isName("CIDFontType0")) {
842 type = fontCIDType0;
843 } else if (obj1.isName("CIDFontType2")) {
844 type = fontCIDType2;
845 } else {
846 error(-1, "Unknown Type 0 descendant font type '%s'",
847 obj1.isName() ? obj1.getName() : "???");
848 goto err3;
849 }
850 obj1.free();
851
852 // get info from font descriptor
853 readFontDescriptor(xref, desFontDict);
854
855 // look for an external font file
856 findExtFontFile();
857
858 //----- encoding info -----
859
860 // char collection
861 if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
862 error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font");
863 goto err3;
864 }
865 obj1.dictLookup("Registry", &obj2);
866 obj1.dictLookup("Ordering", &obj3);
867 if (!obj2.isString() || !obj3.isString()) {
868 error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
869 goto err4;
870 }
871 collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
872 obj3.free();
873 obj2.free();
874 obj1.free();
875
876 // look for a ToUnicode CMap
877 if (!(ctu = readToUnicodeCMap(fontDict, 16))) {
878
879 // the "Adobe-Identity" and "Adobe-UCS" collections don't have
880 // cidToUnicode files
881 if (collection->cmp("Adobe-Identity") &&
882 collection->cmp("Adobe-UCS")) {
883
884 // look for a user-supplied .cidToUnicode file
885 if (!(ctu = globalParams->getCIDToUnicode(collection))) {
886 error(-1, "Unknown character collection '%s'",
887 collection->getCString());
888 delete collection;
889 goto err2;
890 }
891 }
892 }
893
894 // encoding (i.e., CMap)
895 //~ need to handle a CMap stream here
896 //~ also need to deal with the UseCMap entry in the stream dict
897 if (!fontDict->lookup("Encoding", &obj1)->isName()) {
898 error(-1, "Missing or invalid Encoding entry in Type 0 font");
899 delete collection;
900 goto err3;
901 }
902 cMapName = new GString(obj1.getName());
903 obj1.free();
904 if (!(cMap = globalParams->getCMap(collection, cMapName))) {
905 error(-1, "Unknown CMap '%s' for character collection '%s'",
906 cMapName->getCString(), collection->getCString());
907 delete collection;
908 delete cMapName;
909 goto err2;
910 }
911 delete collection;
912 delete cMapName;
913
914 // CIDToGIDMap (for embedded TrueType fonts)
915 if (type == fontCIDType2) {
916 fontDict->lookup("CIDToGIDMap", &obj1);
917 if (obj1.isStream()) {
918 cidToGIDLen = 0;
919 i = 64;
920 cidToGID = (Gushort *)gmalloc(i * sizeof(Gushort));
921 obj1.streamReset();
922 while ((c1 = obj1.streamGetChar()) != EOF &&
923 (c2 = obj1.streamGetChar()) != EOF) {
924 if (cidToGIDLen == i) {
925 i *= 2;
926 cidToGID = (Gushort *)grealloc(cidToGID, i * sizeof(Gushort));
927 }
928 cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2);
929 }
930 } else if (!obj1.isName("Identity") && !obj1.isNull()) {
931 error(-1, "Invalid CIDToGIDMap entry in CID font");
932 }
933 obj1.free();
934 }
935
936 //----- character metrics -----
937
938 // default char width
939 if (desFontDict->lookup("DW", &obj1)->isInt()) {
940 widths.defWidth = obj1.getInt() * 0.001;
941 }
942 obj1.free();
943
944 // char width exceptions
945 if (desFontDict->lookup("W", &obj1)->isArray()) {
946 excepsSize = 0;
947 i = 0;
948 while (i + 1 < obj1.arrayGetLength()) {
949 obj1.arrayGet(i, &obj2);
950 obj1.arrayGet(i + 1, &obj3);
951 if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) {
952 if (obj1.arrayGet(i + 2, &obj4)->isNum()) {
953 if (widths.nExceps == excepsSize) {
954 excepsSize += 16;
955 widths.exceps = (GfxFontCIDWidthExcep *)
956 grealloc(widths.exceps,
957 excepsSize * sizeof(GfxFontCIDWidthExcep));
958 }
959 widths.exceps[widths.nExceps].first = obj2.getInt();
960 widths.exceps[widths.nExceps].last = obj3.getInt();
961 widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
962 ++widths.nExceps;
963 } else {
964 error(-1, "Bad widths array in Type 0 font");
965 }
966 obj4.free();
967 i += 3;
968 } else if (obj2.isInt() && obj3.isArray()) {
969 if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
970 excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15;
971 widths.exceps = (GfxFontCIDWidthExcep *)
972 grealloc(widths.exceps,
973 excepsSize * sizeof(GfxFontCIDWidthExcep));
974 }
975 j = obj2.getInt();
976 for (k = 0; k < obj3.arrayGetLength(); ++k) {
977 if (obj3.arrayGet(k, &obj4)->isNum()) {
978 widths.exceps[widths.nExceps].first = j;
979 widths.exceps[widths.nExceps].last = j;
980 widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
981 ++j;
982 ++widths.nExceps;
983 } else {
984 error(-1, "Bad widths array in Type 0 font");
985 }
986 obj4.free();
987 }
988 i += 2;
989 } else {
990 error(-1, "Bad widths array in Type 0 font");
991 ++i;
992 }
993 obj3.free();
994 obj2.free();
995 }
996 qsort(widths.exceps, widths.nExceps, sizeof(GfxFontCIDWidthExcep),
997 &cmpWidthExcep);
998 }
999 obj1.free();
1000
1001 // default metrics for vertical font
1002 if (desFontDict->lookup("DW2", &obj1)->isArray() &&
1003 obj1.arrayGetLength() == 2) {
1004 if (obj1.arrayGet(0, &obj2)->isNum()) {
1005 widths.defVY = obj1.getNum() * 0.001;
1006 }
1007 obj2.free();
1008 if (obj1.arrayGet(1, &obj2)->isNum()) {
1009 widths.defHeight = obj1.getNum() * 0.001;
1010 }
1011 obj2.free();
1012 }
1013 obj1.free();
1014
1015 // char metric exceptions for vertical font
1016 if (desFontDict->lookup("W2", &obj1)->isArray()) {
1017 excepsSize = 0;
1018 i = 0;
1019 while (i + 1 < obj1.arrayGetLength()) {
1020 obj1.arrayGet(0, &obj2);
1021 obj2.arrayGet(0, &obj3);
1022 if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) {
1023 if (obj1.arrayGet(i + 2, &obj4)->isNum() &&
1024 obj1.arrayGet(i + 3, &obj5)->isNum() &&
1025 obj1.arrayGet(i + 4, &obj6)->isNum()) {
1026 if (widths.nExcepsV == excepsSize) {
1027 excepsSize += 16;
1028 widths.excepsV = (GfxFontCIDWidthExcepV *)
1029 grealloc(widths.excepsV,
1030 excepsSize * sizeof(GfxFontCIDWidthExcepV));
1031 }
1032 widths.excepsV[widths.nExcepsV].first = obj2.getInt();
1033 widths.excepsV[widths.nExcepsV].last = obj3.getInt();
1034 widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
1035 widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001;
1036 widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001;
1037 ++widths.nExcepsV;
1038 } else {
1039 error(-1, "Bad widths (W2) array in Type 0 font");
1040 }
1041 obj6.free();
1042 obj5.free();
1043 obj4.free();
1044 i += 5;
1045 } else if (obj2.isInt() && obj3.isArray()) {
1046 if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) {
1047 excepsSize =
1048 (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15;
1049 widths.excepsV = (GfxFontCIDWidthExcepV *)
1050 grealloc(widths.excepsV,
1051 excepsSize * sizeof(GfxFontCIDWidthExcepV));
1052 }
1053 j = obj2.getInt();
1054 for (k = 0; k < obj3.arrayGetLength(); ++k) {
1055 if (obj3.arrayGet(k, &obj4)->isNum() &&
1056 obj3.arrayGet(k, &obj5)->isNum() &&
1057 obj3.arrayGet(k, &obj6)->isNum()) {
1058 widths.excepsV[widths.nExceps].first = j;
1059 widths.excepsV[widths.nExceps].last = j;
1060 widths.excepsV[widths.nExceps].height = obj4.getNum() * 0.001;
1061 widths.excepsV[widths.nExceps].vx = obj5.getNum() * 0.001;
1062 widths.excepsV[widths.nExceps].vy = obj6.getNum() * 0.001;
1063 ++j;
1064 ++widths.nExcepsV;
1065 } else {
1066 error(-1, "Bad widths (W2) array in Type 0 font");
1067 }
1068 obj6.free();
1069 obj5.free();
1070 obj4.free();
1071 }
1072 i += 2;
1073 } else {
1074 error(-1, "Bad widths (W2) array in Type 0 font");
1075 ++i;
1076 }
1077 obj3.free();
1078 obj2.free();
1079 }
1080 qsort(widths.excepsV, widths.nExcepsV, sizeof(GfxFontCIDWidthExcepV),
1081 &cmpWidthExcepV);
1082 }
1083 obj1.free();
1084
1085 desFontDictObj.free();
1086 ok = gTrue;
1087 return;
1088
1089 err4:
1090 obj3.free();
1091 obj2.free();
1092 err3:
1093 obj1.free();
1094 err2:
1095 desFontDictObj.free();
1096 err1:;
1097}
1098
1099GfxCIDFont::~GfxCIDFont() {
1100 if (cMap) {
1101 cMap->decRefCnt();
1102 }
1103 if (ctu) {
1104 ctu->decRefCnt();
1105 }
1106 gfree(widths.exceps);
1107 gfree(widths.excepsV);
1108 if (cidToGID) {
1109 gfree(cidToGID);
1110 }
1111}
1112
1113int GfxCIDFont::getNextChar(char *s, int len, CharCode *code,
1114 Unicode *u, int uSize, int *uLen,
1115 fouble *dx, fouble *dy, fouble *ox, fouble *oy) {
1116 CID cid;
1117 fouble w, h, vx, vy;
1118 int n, a, b, m;
1119
1120 if (!cMap) {
1121 *code = 0;
1122 *uLen = 0;
1123 *dx = *dy = 0;
1124 return 1;
1125 }
1126
1127 *code = (CharCode)(cid = cMap->getCID(s, len, &n));
1128 if (ctu) {
1129 *uLen = ctu->mapToUnicode(cid, u, uSize);
1130 } else {
1131 *uLen = 0;
1132 }
1133
1134 // horizontal
1135 if (cMap->getWMode() == 0) {
1136 w = widths.defWidth;
1137 h = vx = vy = 0;
1138 if (widths.nExceps > 0 && cid >= widths.exceps[0].first) {
1139 a = 0;
1140 b = widths.nExceps;
1141 // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first
1142 while (b - a > 1) {
1143 m = (a + b) / 2;
1144 if (widths.exceps[m].first <= cid) {
1145 a = m;
1146 } else {
1147 b = m;
1148 }
1149 }
1150 if (cid <= widths.exceps[a].last) {
1151 w = widths.exceps[a].width;
1152 }
1153 }
1154
1155 // vertical
1156 } else {
1157 w = 0;
1158 h = widths.defHeight;
1159 vx = widths.defWidth / 2;
1160 vy = widths.defVY;
1161 if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) {
1162 a = 0;
1163 b = widths.nExcepsV;
1164 // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first
1165 while (b - a > 1) {
1166 m = (a + b) / 2;
1167 if (widths.excepsV[m].last <= cid) {
1168 a = m;
1169 } else {
1170 b = m;
1171 }
1172 }
1173 if (cid <= widths.excepsV[a].last) {
1174 h = widths.excepsV[a].height;
1175 vx = widths.excepsV[a].vx;
1176 vy = widths.excepsV[a].vy;
1177 }
1178 }
1179 }
1180
1181 *dx = w;
1182 *dy = h;
1183 *ox = vx;
1184 *oy = vy;
1185
1186 return n;
1187}
1188
1189CharCodeToUnicode *GfxCIDFont::getToUnicode() {
1190 ctu->incRefCnt();
1191 return ctu;
1192}
1193
1194GString *GfxCIDFont::getCollection() {
1195 return cMap ? cMap->getCollection() : (GString *)NULL;
1196}
1197
1198//------------------------------------------------------------------------
1199// GfxFontDict
1200//------------------------------------------------------------------------
1201
1202GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) {
1203 int i;
1204 Object obj1, obj2;
1205
1206 numFonts = fontDict->getLength();
1207 fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *));
1208 for (i = 0; i < numFonts; ++i) {
1209 fontDict->getValNF(i, &obj1);
1210 obj1.fetch(xref, &obj2);
1211 if (obj1.isRef() && obj2.isDict()) {
1212 fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i),
1213 obj1.getRef(), obj2.getDict());
1214 if (fonts[i] && !fonts[i]->isOk()) {
1215 delete fonts[i];
1216 fonts[i] = NULL;
1217 }
1218 } else {
1219 error(-1, "font resource is not a dictionary");
1220 fonts[i] = NULL;
1221 }
1222 obj1.free();
1223 obj2.free();
1224 }
1225}
1226
1227GfxFontDict::~GfxFontDict() {
1228 int i;
1229
1230 for (i = 0; i < numFonts; ++i) {
1231 if (fonts[i]) {
1232 delete fonts[i];
1233 }
1234 }
1235 gfree(fonts);
1236}
1237
1238GfxFont *GfxFontDict::lookup(char *tag) {
1239 int i;
1240
1241 for (i = 0; i < numFonts; ++i) {
1242 if (fonts[i] && fonts[i]->matches(tag)) {
1243 return fonts[i];
1244 }
1245 }
1246 return NULL;
1247}