]> git.ipfire.org Git - thirdparty/cups.git/blob - pdftops/GfxFont.cxx
Import cups.org releases
[thirdparty/cups.git] / pdftops / GfxFont.cxx
1 //========================================================================
2 //
3 // GfxFont.cc
4 //
5 // Copyright 1996 Derek B. Noonburg
6 //
7 //========================================================================
8
9 #ifdef __GNUC__
10 #pragma implementation
11 #endif
12
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include "GString.h"
19 #include "gmem.h"
20 #include "gfile.h"
21 #include "config.h"
22 #include "Object.h"
23 #include "Array.h"
24 #include "Dict.h"
25 #include "Error.h"
26 #include "Params.h"
27 #include "FontFile.h"
28 #include "GfxFont.h"
29
30 #include "FontInfo.h"
31 #if JAPANESE_SUPPORT
32 #include "Japan12CMapInfo.h"
33 #endif
34 #if CHINESE_GB_SUPPORT
35 #include "GB12CMapInfo.h"
36 #endif
37 #if CHINESE_CNS_SUPPORT
38 #include "CNS13CMapInfo.h"
39 #endif
40
41 //------------------------------------------------------------------------
42
43 extern "C" {
44 static int CDECL cmpWidthExcep(const void *w1, const void *w2);
45 static int CDECL cmpWidthExcepV(const void *w1, const void *w2);
46 }
47
48 //------------------------------------------------------------------------
49
50 static Gushort *defCharWidths[12] = {
51 courierWidths,
52 courierObliqueWidths,
53 courierBoldWidths,
54 courierBoldObliqueWidths,
55 helveticaWidths,
56 helveticaObliqueWidths,
57 helveticaBoldWidths,
58 helveticaBoldObliqueWidths,
59 timesRomanWidths,
60 timesItalicWidths,
61 timesBoldWidths,
62 timesBoldItalicWidths
63 };
64
65 //------------------------------------------------------------------------
66 // GfxFont
67 //------------------------------------------------------------------------
68
69 GfxFont::GfxFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) {
70 BuiltinFont *builtinFont;
71 Object obj1, obj2, obj3, obj4;
72 int missingWidth;
73 char *name2, *p;
74 int i;
75
76 // get font tag and ID
77 tag = new GString(tagA);
78 id = idA;
79
80 // get font type
81 type = fontUnknownType;
82 fontDict->lookup("Subtype", &obj1);
83 if (obj1.isName("Type1"))
84 type = fontType1;
85 else if (obj1.isName("Type1C"))
86 type = fontType1C;
87 else if (obj1.isName("Type3"))
88 type = fontType3;
89 else if (obj1.isName("TrueType"))
90 type = fontTrueType;
91 else if (obj1.isName("Type0"))
92 type = fontType0;
93 obj1.free();
94 is16 = gFalse;
95
96 // get base font name
97 name = NULL;
98 fontDict->lookup("BaseFont", &obj1);
99 if (obj1.isName())
100 name = new GString(obj1.getName());
101 obj1.free();
102
103 // Newer Adobe tools are using Base14-compatible TrueType fonts
104 // without embedding them, so munge the names into the equivalent
105 // PostScript names. This is a kludge -- it would be nice if Adobe
106 // followed their own spec.
107 if (type == fontTrueType && name) {
108 p = name->getCString();
109 name2 = NULL;
110 if (!strncmp(p, "Arial", 5)) {
111 if (!strcmp(p+5, ",Bold")) {
112 name2 = "Helvetica-Bold";
113 } else if (!strcmp(p+5, ",Italic")) {
114 name2 = "Helvetica-Oblique";
115 } else if (!strcmp(p+5, ",BoldItalic")) {
116 name2 = "Helvetica-BoldOblique";
117 } else {
118 name2 = "Helvetica";
119 }
120 } else if (!strncmp(p, "TimesNewRoman", 13)) {
121 if (!strcmp(p+13, ",Bold")) {
122 name2 = "Times-Bold";
123 } else if (!strcmp(p+13, ",Italic")) {
124 name2 = "Times-Italic";
125 } else if (!strcmp(p+13, ",BoldItalic")) {
126 name2 = "Times-BoldItalic";
127 } else {
128 name2 = "Times-Roman";
129 }
130 } else if (!strncmp(p, "CourierNew", 10)) {
131 if (!strcmp(p+10, ",Bold")) {
132 name2 = "Courier-Bold";
133 } else if (!strcmp(p+10, ",Italic")) {
134 name2 = "Courier-Oblique";
135 } else if (!strcmp(p+10, ",BoldItalic")) {
136 name2 = "Courier-BoldOblique";
137 } else {
138 name2 = "Courier";
139 }
140 }
141 if (name2) {
142 delete name;
143 name = new GString(name2);
144 }
145 }
146
147 // is it a built-in font?
148 builtinFont = NULL;
149 if (name) {
150 for (i = 0; i < numBuiltinFonts; ++i) {
151 if (!strcmp(builtinFonts[i].name, name->getCString())) {
152 builtinFont = &builtinFonts[i];
153 break;
154 }
155 }
156 }
157
158 // assume Times-Roman by default (for substitution purposes)
159 flags = fontSerif;
160
161 // default ascent/descent values
162 if (builtinFont) {
163 ascent = 0.001 * builtinFont->ascent;
164 descent = 0.001 * builtinFont->descent;
165 } else {
166 ascent = 0.95;
167 descent = -0.35;
168 }
169
170 // get info from font descriptor
171 embFontName = NULL;
172 embFontID.num = -1;
173 embFontID.gen = -1;
174 missingWidth = 0;
175 if (type == fontType0) {
176 fontDict->lookup("DescendantFonts", &obj2);
177 if (obj2.isArray()) {
178 obj2.arrayGet(0, &obj3);
179 if (obj3.isDict()) {
180 obj3.dictLookup("FontDescriptor", &obj1);
181 } else {
182 error(-1, "Bad descendant font in Type 0 font");
183 obj1.initNull();
184 }
185 obj3.free();
186 } else {
187 error(-1, "Missing DescendantFonts entry in Type 0 font");
188 obj1.initNull();
189 }
190 obj2.free();
191 } else {
192 fontDict->lookup("FontDescriptor", &obj1);
193 }
194 if (obj1.isDict()) {
195
196 // get flags
197 obj1.dictLookup("Flags", &obj2);
198 if (obj2.isInt())
199 flags = obj2.getInt();
200 obj2.free();
201
202 // get name
203 obj1.dictLookup("FontName", &obj2);
204 if (obj2.isName())
205 embFontName = new GString(obj2.getName());
206 obj2.free();
207
208 // look for embedded font file
209 if (type == fontType1) {
210 obj1.dictLookupNF("FontFile", &obj2);
211 if (obj2.isRef())
212 embFontID = obj2.getRef();
213 obj2.free();
214 }
215 if (embFontID.num == -1 && type == fontTrueType) {
216 obj1.dictLookupNF("FontFile2", &obj2);
217 if (obj2.isRef())
218 embFontID = obj2.getRef();
219 obj2.free();
220 }
221 if (embFontID.num == -1) {
222 obj1.dictLookupNF("FontFile3", &obj2);
223 if (obj2.isRef()) {
224 embFontID = obj2.getRef();
225 obj2.fetch(xref, &obj3);
226 if (obj3.isStream()) {
227 obj3.streamGetDict()->lookup("Subtype", &obj4);
228 if (obj4.isName("Type1"))
229 type = fontType1;
230 else if (obj4.isName("Type1C"))
231 type = fontType1C;
232 else if (obj4.isName("Type3"))
233 type = fontType3;
234 else if (obj4.isName("TrueType"))
235 type = fontTrueType;
236 else if (obj4.isName("Type0"))
237 type = fontType0;
238 obj4.free();
239 }
240 obj3.free();
241 }
242 obj2.free();
243 }
244
245 // look for MissingWidth
246 obj1.dictLookup("MissingWidth", &obj2);
247 if (obj2.isInt()) {
248 missingWidth = obj2.getInt();
249 }
250 obj2.free();
251
252 // get Ascent and Descent
253 obj1.dictLookup("Ascent", &obj2);
254 if (obj2.isNum()) {
255 ascent = 0.001 * obj2.getNum();
256 }
257 obj2.free();
258 obj1.dictLookup("Descent", &obj2);
259 if (obj2.isNum()) {
260 descent = 0.001 * obj2.getNum();
261 }
262 obj2.free();
263
264 // font FontBBox
265 fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
266 if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
267 for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
268 if (obj2.arrayGet(i, &obj3)->isNum()) {
269 fontBBox[i] = obj3.getNum();
270 }
271 obj3.free();
272 }
273 }
274 obj2.free();
275 }
276 obj1.free();
277
278 // get Type3 font definition
279 if (type == fontType3) {
280 fontDict->lookup("CharProcs", &charProcs);
281 if (!charProcs.isDict()) {
282 error(-1, "Missing or invalid CharProcs dictionary in Type 3 font");
283 charProcs.free();
284 }
285 }
286
287 // look for an external font file
288 extFontFile = NULL;
289 if (type == fontType1 && name)
290 findExtFontFile();
291
292 // get font matrix
293 fontMat[0] = fontMat[3] = 1;
294 fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
295 if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
296 for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
297 if (obj1.arrayGet(i, &obj2)->isNum())
298 fontMat[i] = obj2.getNum();
299 obj2.free();
300 }
301 }
302 obj1.free();
303
304 // get encoding and character widths
305 if (type == fontType0) {
306 getType0EncAndWidths(fontDict);
307 } else {
308 getEncAndWidths(xref, fontDict, builtinFont, missingWidth);
309 }
310 }
311
312 GfxFont::~GfxFont() {
313 delete tag;
314 if (name) {
315 delete name;
316 }
317 if (!is16 && encoding) {
318 delete encoding;
319 }
320 if (embFontName) {
321 delete embFontName;
322 }
323 if (extFontFile) {
324 delete extFontFile;
325 }
326 if (charProcs.isDict()) {
327 charProcs.free();
328 }
329 if (is16) {
330 gfree(widths16.exceps);
331 gfree(widths16.excepsV);
332 }
333 }
334
335 double GfxFont::getWidth(GString *s) {
336 double w;
337 int i;
338
339 w = 0;
340 for (i = 0; i < s->getLength(); ++i)
341 w += widths[s->getChar(i) & 0xff];
342 return w;
343 }
344
345 double GfxFont::getWidth16(int c) {
346 double w;
347 int a, b, m;
348
349 w = widths16.defWidth;
350 a = -1;
351 b = widths16.numExceps;
352 // invariant: widths16.exceps[a].last < c < widths16.exceps[b].first
353 while (b - a > 1) {
354 m = (a + b) / 2;
355 if (widths16.exceps[m].last < c) {
356 a = m;
357 } else if (c < widths16.exceps[m].first) {
358 b = m;
359 } else {
360 w = widths16.exceps[m].width;
361 break;
362 }
363 }
364 return w;
365 }
366
367 double GfxFont::getHeight16(int c) {
368 double h;
369 int a, b, m;
370
371 h = widths16.defHeight;
372 a = -1;
373 b = widths16.numExcepsV;
374 // invariant: widths16.excepsV[a].last < c < widths16.excepsV[b].first
375 while (b - a > 1) {
376 m = (a + b) / 2;
377 if (widths16.excepsV[m].last < c) {
378 a = m;
379 } else if (c < widths16.excepsV[m].first) {
380 b = m;
381 } else {
382 h = widths16.excepsV[m].height;
383 break;
384 }
385 }
386 return h;
387 }
388
389 double GfxFont::getOriginX16(int c) {
390 double vx;
391 int a, b, m;
392
393 vx = widths16.defWidth / 2;
394 a = -1;
395 b = widths16.numExcepsV;
396 // invariant: widths16.excepsV[a].last < c < widths16.excepsV[b].first
397 while (b - a > 1) {
398 m = (a + b) / 2;
399 if (widths16.excepsV[m].last < c) {
400 a = m;
401 } else if (c < widths16.excepsV[m].first) {
402 b = m;
403 } else {
404 vx = widths16.excepsV[m].vx;
405 break;
406 }
407 }
408 return vx;
409 }
410
411 double GfxFont::getOriginY16(int c) {
412 double vy;
413 int a, b, m;
414
415 vy = widths16.defVY;
416 a = -1;
417 b = widths16.numExcepsV;
418 // invariant: widths16.excepsV[a].last < c < widths16.excepsV[b].first
419 while (b - a > 1) {
420 m = (a + b) / 2;
421 if (widths16.excepsV[m].last < c) {
422 a = m;
423 } else if (c < widths16.excepsV[m].first) {
424 b = m;
425 } else {
426 vy = widths16.excepsV[m].vy;
427 break;
428 }
429 }
430 return vy;
431 }
432
433 Object *GfxFont::getCharProc(int code, Object *proc) {
434 if (charProcs.isDict()) {
435 charProcs.dictLookup(encoding->getCharName(code), proc);
436 } else {
437 proc->initNull();
438 }
439 return proc;
440 }
441
442 void GfxFont::getEncAndWidths(XRef *xref, Dict *fontDict,
443 BuiltinFont *builtinFont, int missingWidth) {
444 Object obj1, obj2, obj3;
445 char *buf;
446 int len;
447 FontFile *fontFile;
448 int code, i;
449
450 // Encodings start with a base encoding, which can come from
451 // (in order of priority):
452 // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
453 // - MacRoman / WinAnsi / Standard
454 // 2. embedded font file
455 // 3. default:
456 // - builtin --> builtin encoding
457 // - TrueType --> MacRomanEncoding
458 // - others --> StandardEncoding
459 // and then add a list of differences from
460 // FontDict.Encoding.Differences.
461
462 // check FontDict for base encoding
463 encoding = NULL;
464 fontDict->lookup("Encoding", &obj1);
465 if (obj1.isDict()) {
466 obj1.dictLookup("BaseEncoding", &obj2);
467 if (obj2.isName("MacRomanEncoding")) {
468 encoding = macRomanEncoding.copy();
469 } else if (obj2.isName("WinAnsiEncoding")) {
470 encoding = winAnsiEncoding.copy();
471 } else if (obj2.isName("StandardEncoding")) {
472 encoding = standardEncoding.copy();
473 }
474 obj2.free();
475 } else if (obj1.isName("MacRomanEncoding")) {
476 encoding = macRomanEncoding.copy();
477 } else if (obj1.isName("WinAnsiEncoding")) {
478 encoding = winAnsiEncoding.copy();
479 } else if (obj1.isName("StandardEncoding")) {
480 encoding = standardEncoding.copy();
481 }
482 obj1.free();
483
484 // check embedded or external font file for base encoding
485 if ((type == fontType1 || type == fontType1C || type == fontTrueType) &&
486 (extFontFile || embFontID.num >= 0)) {
487 if (extFontFile) {
488 buf = readExtFontFile(&len);
489 } else {
490 buf = readEmbFontFile(xref, &len);
491 }
492 if (buf) {
493 if (type == fontType1) {
494 fontFile = new Type1FontFile(buf, len);
495 } else if (type == fontType1C) {
496 fontFile = new Type1CFontFile(buf, len);
497 } else {
498 fontFile = new TrueTypeFontFile(buf, len);
499 }
500 if (fontFile->getName()) {
501 if (embFontName)
502 delete embFontName;
503 embFontName = new GString(fontFile->getName());
504 }
505 if (!encoding) {
506 encoding = fontFile->getEncoding(gTrue);
507 }
508 delete fontFile;
509 gfree(buf);
510 }
511 }
512
513 // get default base encoding
514 if (!encoding) {
515 if (builtinFont)
516 encoding = builtinFont->encoding->copy();
517 else if (type == fontTrueType)
518 encoding = macRomanEncoding.copy();
519 else
520 encoding = standardEncoding.copy();
521 }
522
523 // merge differences into encoding
524 fontDict->lookup("Encoding", &obj1);
525 if (obj1.isDict()) {
526 obj1.dictLookup("Differences", &obj2);
527 if (obj2.isArray()) {
528 code = 0;
529 for (i = 0; i < obj2.arrayGetLength(); ++i) {
530 obj2.arrayGet(i, &obj3);
531 if (obj3.isInt()) {
532 code = obj3.getInt();
533 } else if (obj3.isName()) {
534 if (code < 256)
535 encoding->addChar(code, copyString(obj3.getName()));
536 ++code;
537 } else {
538 error(-1, "Wrong type in font encoding resource differences (%s)",
539 obj3.getTypeName());
540 }
541 obj3.free();
542 }
543 }
544 obj2.free();
545 }
546 obj1.free();
547
548 // get character widths
549 if (builtinFont)
550 makeWidths(fontDict, builtinFont->encoding, builtinFont->widths,
551 missingWidth);
552 else
553 makeWidths(fontDict, NULL, NULL, missingWidth);
554 }
555
556 void GfxFont::findExtFontFile() {
557 char **path;
558 FILE *f;
559
560 for (path = fontPath; *path; ++path) {
561 extFontFile = appendToPath(new GString(*path), name->getCString());
562 f = fopen(extFontFile->getCString(), "rb");
563 if (!f) {
564 extFontFile->append(".pfb");
565 f = fopen(extFontFile->getCString(), "rb");
566 }
567 if (!f) {
568 extFontFile->del(extFontFile->getLength() - 4, 4);
569 extFontFile->append(".pfa");
570 f = fopen(extFontFile->getCString(), "rb");
571 }
572 if (f) {
573 fclose(f);
574 break;
575 }
576 delete extFontFile;
577 extFontFile = NULL;
578 }
579 }
580
581 char *GfxFont::readExtFontFile(int *len) {
582 FILE *f;
583 char *buf;
584
585 if (!(f = fopen(extFontFile->getCString(), "rb"))) {
586 error(-1, "Internal: external font file '%s' vanished", extFontFile);
587 return NULL;
588 }
589 fseek(f, 0, SEEK_END);
590 *len = (int)ftell(f);
591 fseek(f, 0, SEEK_SET);
592 buf = (char *)gmalloc(*len);
593 if ((int)fread(buf, 1, *len, f) != *len)
594 error(-1, "Error reading external font file '%s'", extFontFile);
595 fclose(f);
596 return buf;
597 }
598
599 char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
600 char *buf;
601 Object obj1, obj2;
602 Stream *str;
603 int c;
604 int size, i;
605
606 obj1.initRef(embFontID.num, embFontID.gen);
607 obj1.fetch(xref, &obj2);
608 if (!obj2.isStream()) {
609 error(-1, "Embedded font file is not a stream");
610 obj2.free();
611 obj1.free();
612 embFontID.num = -1;
613 return NULL;
614 }
615 str = obj2.getStream();
616
617 buf = NULL;
618 i = size = 0;
619 str->reset();
620 while ((c = str->getChar()) != EOF) {
621 if (i == size) {
622 size += 4096;
623 buf = (char *)grealloc(buf, size);
624 }
625 buf[i++] = c;
626 }
627 *len = i;
628 str->close();
629
630 obj2.free();
631 obj1.free();
632
633 return buf;
634 }
635
636 void GfxFont::makeWidths(Dict *fontDict, FontEncoding *builtinEncoding,
637 Gushort *builtinWidths, int missingWidth) {
638 Object obj1, obj2;
639 int firstChar, lastChar;
640 int code, code2;
641 char *charName;
642 Gushort *defWidths;
643 int index;
644 double mult;
645
646 // initialize all widths
647 for (code = 0; code < 256; ++code) {
648 widths[code] = missingWidth * 0.001;
649 }
650
651 // use widths from font dict, if present
652 fontDict->lookup("FirstChar", &obj1);
653 firstChar = obj1.isInt() ? obj1.getInt() : 0;
654 obj1.free();
655 fontDict->lookup("LastChar", &obj1);
656 lastChar = obj1.isInt() ? obj1.getInt() : 255;
657 obj1.free();
658 if (type == fontType3)
659 mult = fontMat[0];
660 else
661 mult = 0.001;
662 fontDict->lookup("Widths", &obj1);
663 if (obj1.isArray()) {
664 for (code = firstChar; code <= lastChar; ++code) {
665 obj1.arrayGet(code - firstChar, &obj2);
666 if (obj2.isNum())
667 widths[code] = obj2.getNum() * mult;
668 obj2.free();
669 }
670
671 // use widths from built-in font
672 } else if (builtinEncoding) {
673 code2 = 0; // to make gcc happy
674 for (code = 0; code < 256; ++code) {
675 if ((charName = encoding->getCharName(code)) &&
676 (code2 = builtinEncoding->getCharCode(charName)) >= 0) {
677 widths[code] = builtinWidths[code2] * 0.001;
678 } else if (code == 32) {
679 // this is a kludge for broken PDF files that encode char 32
680 // as .notdef
681 widths[code] = builtinWidths[' '] * 0.001;
682 }
683 }
684
685 // couldn't find widths -- use defaults
686 } else {
687 #if 0 //~
688 //~ certain PDF generators apparently don't include widths
689 //~ for Arial and TimesNewRoman -- and this error message
690 //~ is a nuisance
691 error(-1, "No character widths resource for non-builtin font");
692 #endif
693 if (isFixedWidth())
694 index = 0;
695 else if (isSerif())
696 index = 8;
697 else
698 index = 4;
699 if (isBold())
700 index += 2;
701 if (isItalic())
702 index += 1;
703 defWidths = defCharWidths[index];
704 code2 = 0; // to make gcc happy
705 for (code = 0; code < 256; ++code) {
706 if ((charName = encoding->getCharName(code)) &&
707 (code2 = standardEncoding.getCharCode(charName)) >= 0)
708 widths[code] = defWidths[code2] * 0.001;
709 }
710 }
711 obj1.free();
712 }
713
714 void GfxFont::getType0EncAndWidths(Dict *fontDict) {
715 Object obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8;
716 int excepsSize;
717 int i, j, k, n;
718
719 widths16.exceps = NULL;
720 widths16.excepsV = NULL;
721
722 // get the CIDFont
723 fontDict->lookup("DescendantFonts", &obj1);
724 if (!obj1.isArray() || obj1.arrayGetLength() != 1) {
725 error(-1, "Bad DescendantFonts entry for Type 0 font");
726 goto err1;
727 }
728 obj1.arrayGet(0, &obj2);
729 if (!obj2.isDict()) {
730 error(-1, "Bad descendant font of Type 0 font");
731 goto err2;
732 }
733
734 // get font info
735 obj2.dictLookup("CIDSystemInfo", &obj3);
736 if (!obj3.isDict()) {
737 error(-1, "Bad CIDSystemInfo in Type 0 font descendant");
738 goto err3;
739 }
740 obj3.dictLookup("Registry", &obj4);
741 obj3.dictLookup("Ordering", &obj5);
742 if (obj4.isString() && obj5.isString()) {
743 if (obj4.getString()->cmp("Adobe") == 0 &&
744 obj5.getString()->cmp("Japan1") == 0) {
745 #if JAPANESE_SUPPORT
746 is16 = gTrue;
747 enc16.charSet = font16AdobeJapan12;
748 #else
749 error(-1, "Xpdf was compiled without Japanese font support");
750 goto err4;
751 #endif
752 } else if (obj4.getString()->cmp("Adobe") == 0 &&
753 obj5.getString()->cmp("GB1") == 0) {
754 #if CHINESE_GB_SUPPORT
755 is16 = gTrue;
756 enc16.charSet = font16AdobeGB12;
757 #else
758 error(-1, "Xpdf was compiled without Chinese GB font support");
759 goto err4;
760 #endif
761 } else if (obj4.getString()->cmp("Adobe") == 0 &&
762 obj5.getString()->cmp("CNS1") == 0) {
763 #if CHINESE_CNS_SUPPORT
764 is16 = gTrue;
765 enc16.charSet = font16AdobeCNS13;
766 #else
767 error(-1, "Xpdf was compiled without Chinese CNS font support");
768 goto err4;
769 #endif
770 } else {
771 error(-1, "Unknown Type 0 character set: %s-%s",
772 obj4.getString()->getCString(), obj5.getString()->getCString());
773 goto err4;
774 }
775 } else {
776 error(-1, "Unknown Type 0 character set");
777 goto err4;
778 }
779 obj5.free();
780 obj4.free();
781 obj3.free();
782
783 // get default char width
784 obj2.dictLookup("DW", &obj3);
785 if (obj3.isInt())
786 widths16.defWidth = obj3.getInt() * 0.001;
787 else
788 widths16.defWidth = 1.0;
789 obj3.free();
790
791 // get default char metrics for vertical font
792 obj2.dictLookup("DW2", &obj3);
793 widths16.defVY = 0.880;
794 widths16.defHeight = -1;
795 if (obj3.isArray() && obj3.arrayGetLength() == 2) {
796 obj3.arrayGet(0, &obj4);
797 if (obj4.isInt()) {
798 widths16.defVY = obj4.getInt() * 0.001;
799 }
800 obj4.free();
801 obj3.arrayGet(1, &obj4);
802 if (obj4.isInt()) {
803 widths16.defHeight = obj4.getInt() * 0.001;
804 }
805 obj4.free();
806 }
807 obj3.free();
808
809 // get char width exceptions
810 widths16.exceps = NULL;
811 widths16.numExceps = 0;
812 obj2.dictLookup("W", &obj3);
813 if (obj3.isArray()) {
814 excepsSize = 0;
815 k = 0;
816 i = 0;
817 while (i+1 < obj3.arrayGetLength()) {
818 obj3.arrayGet(i, &obj4);
819 obj3.arrayGet(i+1, &obj5);
820 if (obj4.isInt() && obj5.isInt()) {
821 obj3.arrayGet(i+2, &obj6);
822 if (!obj6.isNum()) {
823 error(-1, "Bad widths array in Type 0 font");
824 obj6.free();
825 obj5.free();
826 obj4.free();
827 break;
828 }
829 if (k == excepsSize) {
830 excepsSize += 16;
831 widths16.exceps = (GfxFontWidthExcep *)
832 grealloc(widths16.exceps,
833 excepsSize * sizeof(GfxFontWidthExcep));
834 }
835 widths16.exceps[k].first = obj4.getInt();
836 widths16.exceps[k].last = obj5.getInt();
837 widths16.exceps[k].width = obj6.getNum() * 0.001;
838 obj6.free();
839 ++k;
840 i += 3;
841 } else if (obj4.isInt() && obj5.isArray()) {
842 if (k + obj5.arrayGetLength() >= excepsSize) {
843 excepsSize = (k + obj5.arrayGetLength() + 15) & ~15;
844 widths16.exceps = (GfxFontWidthExcep *)
845 grealloc(widths16.exceps,
846 excepsSize * sizeof(GfxFontWidthExcep));
847 }
848 n = obj4.getInt();
849 for (j = 0; j < obj5.arrayGetLength(); ++j) {
850 obj5.arrayGet(j, &obj6);
851 if (!obj6.isNum()) {
852 error(-1, "Bad widths array in Type 0 font");
853 obj6.free();
854 break;
855 }
856 widths16.exceps[k].first = widths16.exceps[k].last = n++;
857 widths16.exceps[k].width = obj6.getNum() * 0.001;
858 obj6.free();
859 ++k;
860 }
861 i += 2;
862 } else {
863 error(-1, "Bad widths array in Type 0 font");
864 obj6.free();
865 obj5.free();
866 obj4.free();
867 break;
868 }
869 obj5.free();
870 obj4.free();
871 }
872 widths16.numExceps = k;
873 if (k > 0)
874 qsort(widths16.exceps, k, sizeof(GfxFontWidthExcep), &cmpWidthExcep);
875 }
876 obj3.free();
877
878 // get char metric exceptions for vertical font
879 widths16.excepsV = NULL;
880 widths16.numExcepsV = 0;
881 obj2.dictLookup("W2", &obj3);
882 if (obj3.isArray()) {
883 excepsSize = 0;
884 k = 0;
885 i = 0;
886 while (i+1 < obj3.arrayGetLength()) {
887 obj3.arrayGet(i, &obj4);
888 obj3.arrayGet(i+1, &obj5);
889 if (obj4.isInt() && obj5.isInt()) {
890 obj3.arrayGet(i+2, &obj6);
891 obj3.arrayGet(i+3, &obj7);
892 obj3.arrayGet(i+4, &obj8);
893 if (!obj6.isNum() || !obj7.isNum() || !obj8.isNum()) {
894 error(-1, "Bad widths (W2) array in Type 0 font");
895 obj8.free();
896 obj7.free();
897 obj6.free();
898 obj5.free();
899 obj4.free();
900 break;
901 }
902 if (k == excepsSize) {
903 excepsSize += 16;
904 widths16.excepsV = (GfxFontWidthExcepV *)
905 grealloc(widths16.excepsV,
906 excepsSize * sizeof(GfxFontWidthExcepV));
907 }
908 widths16.excepsV[k].first = obj4.getInt();
909 widths16.excepsV[k].last = obj5.getInt();
910 widths16.excepsV[k].height = obj6.getNum() * 0.001;
911 widths16.excepsV[k].vx = obj7.getNum() * 0.001;
912 widths16.excepsV[k].vy = obj8.getNum() * 0.001;
913 obj8.free();
914 obj7.free();
915 obj6.free();
916 ++k;
917 i += 5;
918 } else if (obj4.isInt() && obj5.isArray()) {
919 if (k + obj5.arrayGetLength() / 3 >= excepsSize) {
920 excepsSize = (k + obj5.arrayGetLength() / 3 + 15) & ~15;
921 widths16.excepsV = (GfxFontWidthExcepV *)
922 grealloc(widths16.excepsV,
923 excepsSize * sizeof(GfxFontWidthExcepV));
924 }
925 n = obj4.getInt();
926 for (j = 0; j < obj5.arrayGetLength(); j += 3) {
927 obj5.arrayGet(j, &obj6);
928 obj5.arrayGet(j+1, &obj7);
929 obj5.arrayGet(j+1, &obj8);
930 if (!obj6.isNum() || !obj7.isNum() || !obj8.isNum()) {
931 error(-1, "Bad widths (W2) array in Type 0 font");
932 obj6.free();
933 break;
934 }
935 widths16.excepsV[k].first = widths16.exceps[k].last = n++;
936 widths16.excepsV[k].height = obj6.getNum() * 0.001;
937 widths16.excepsV[k].vx = obj7.getNum() * 0.001;
938 widths16.excepsV[k].vy = obj8.getNum() * 0.001;
939 obj8.free();
940 obj7.free();
941 obj6.free();
942 ++k;
943 }
944 i += 2;
945 } else {
946 error(-1, "Bad widths array in Type 0 font");
947 obj5.free();
948 obj4.free();
949 break;
950 }
951 obj5.free();
952 obj4.free();
953 }
954 widths16.numExcepsV = k;
955 if (k > 0) {
956 qsort(widths16.excepsV, k, sizeof(GfxFontWidthExcepV), &cmpWidthExcepV);
957 }
958 }
959 obj3.free();
960
961 obj2.free();
962 obj1.free();
963
964 // get encoding (CMap)
965 fontDict->lookup("Encoding", &obj1);
966 if (!obj1.isName()) {
967 error(-1, "Bad encoding for Type 0 font");
968 goto err1;
969 }
970 #if JAPANESE_SUPPORT
971 if (enc16.charSet == font16AdobeJapan12) {
972 for (i = 0; gfxJapan12Tab[i].name; ++i) {
973 if (!strcmp(obj1.getName(), gfxJapan12Tab[i].name))
974 break;
975 }
976 if (!gfxJapan12Tab[i].name) {
977 error(-1, "Unknown encoding '%s' for Adobe-Japan1-2 font",
978 obj1.getName());
979 goto err1;
980 }
981 enc16.enc = gfxJapan12Tab[i].enc;
982 }
983 #endif
984 #if CHINESE_GB_SUPPORT
985 if (enc16.charSet == font16AdobeGB12) {
986 for (i = 0; gfxGB12Tab[i].name; ++i) {
987 if (!strcmp(obj1.getName(), gfxGB12Tab[i].name))
988 break;
989 }
990 if (!gfxGB12Tab[i].name) {
991 error(-1, "Unknown encoding '%s' for Adobe-GB1-2 font",
992 obj1.getName());
993 goto err1;
994 }
995 enc16.enc = gfxGB12Tab[i].enc;
996 }
997 #endif
998 #if CHINESE_CNS_SUPPORT
999 if (enc16.charSet == font16AdobeCNS13) {
1000 for (i = 0; gfxCNS13Tab[i].name; ++i) {
1001 if (!strcmp(obj1.getName(), gfxCNS13Tab[i].name))
1002 break;
1003 }
1004 if (!gfxCNS13Tab[i].name) {
1005 error(-1, "Unknown encoding '%s' for Adobe-CNS1-3 font",
1006 obj1.getName());
1007 goto err1;
1008 }
1009 enc16.enc = gfxCNS13Tab[i].enc;
1010 }
1011 #endif
1012 obj1.free();
1013
1014 return;
1015
1016 err4:
1017 obj5.free();
1018 obj4.free();
1019 err3:
1020 obj3.free();
1021 err2:
1022 obj2.free();
1023 err1:
1024 obj1.free();
1025 //~ fix this --> add 16-bit font support to FontFile
1026 encoding = new FontEncoding();
1027 makeWidths(fontDict, NULL, NULL, 0);
1028 }
1029
1030 extern "C" {
1031 static int CDECL cmpWidthExcep(const void *w1, const void *w2) {
1032 return ((GfxFontWidthExcep *)w1)->first - ((GfxFontWidthExcep *)w2)->first;
1033 }
1034
1035 static int CDECL cmpWidthExcepV(const void *w1, const void *w2) {
1036 return ((GfxFontWidthExcepV *)w1)->first - ((GfxFontWidthExcepV *)w2)->first;
1037 }
1038 }
1039
1040 //------------------------------------------------------------------------
1041 // GfxFontDict
1042 //------------------------------------------------------------------------
1043
1044 GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) {
1045 int i;
1046 Object obj1, obj2;
1047
1048 numFonts = fontDict->getLength();
1049 fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *));
1050 for (i = 0; i < numFonts; ++i) {
1051 fontDict->getValNF(i, &obj1);
1052 obj1.fetch(xref, &obj2);
1053 if (obj1.isRef() && obj2.isDict()) {
1054 fonts[i] = new GfxFont(xref, fontDict->getKey(i),
1055 obj1.getRef(), obj2.getDict());
1056 } else {
1057 error(-1, "font resource is not a dictionary");
1058 fonts[i] = NULL;
1059 }
1060 obj1.free();
1061 obj2.free();
1062 }
1063 }
1064
1065 GfxFontDict::~GfxFontDict() {
1066 int i;
1067
1068 for (i = 0; i < numFonts; ++i)
1069 delete fonts[i];
1070 gfree(fonts);
1071 }
1072
1073 GfxFont *GfxFontDict::lookup(char *tag) {
1074 int i;
1075
1076 for (i = 0; i < numFonts; ++i) {
1077 if (fonts[i]->matches(tag))
1078 return fonts[i];
1079 }
1080 return NULL;
1081 }