1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
34 //------------------------------------------------------------------------
36 static int CDECL cmpWidthExcep(const void *w1, const void *w2);
38 //------------------------------------------------------------------------
40 static Gushort *defCharWidths[12] = {
44 courierBoldObliqueWidths,
46 helveticaObliqueWidths,
48 helveticaBoldObliqueWidths,
55 //------------------------------------------------------------------------
57 //------------------------------------------------------------------------
59 inline int GfxFontEncoding::hash(char *name) {
65 return h % gfxFontEncHashSize;
68 GfxFontEncoding::GfxFontEncoding() {
71 encoding = (char **)gmalloc(256 * sizeof(char *));
73 for (i = 0; i < 256; ++i)
75 for (i = 0; i < gfxFontEncHashSize; ++i)
79 GfxFontEncoding::GfxFontEncoding(char **encoding1, int encSize) {
84 for (i = 0; i < gfxFontEncHashSize; ++i)
86 for (i = 0; i < encSize; ++i) {
88 addChar1(i, encoding[i]);
92 void GfxFontEncoding::addChar(int code, char *name) {
95 // replace character associated with code
97 h = hash(encoding[code]);
98 for (i = 0; i < gfxFontEncHashSize; ++i) {
99 if (hashTab[h] == code) {
103 if (++h == gfxFontEncHashSize)
106 gfree(encoding[code]);
109 // associate name with code
110 encoding[code] = name;
112 // insert name in hash table
113 addChar1(code, name);
116 void GfxFontEncoding::addChar1(int code, char *name) {
119 // insert name in hash table
121 for (i = 0; i < gfxFontEncHashSize; ++i) {
126 } else if (encoding[code2] && !strcmp(encoding[code2], name)) {
127 // keep the highest code for each char -- this is needed because
128 // X won't display chars with codes < 32
133 if (++h == gfxFontEncHashSize)
138 GfxFontEncoding::~GfxFontEncoding() {
142 for (i = 0; i < 256; ++i) {
150 int GfxFontEncoding::getCharCode(char *name) {
154 for (i = 0; i < gfxFontEncHashSize; ++i) {
157 (code > 0 && encoding[code] && !strcmp(encoding[code], name)))
159 if (++h >= gfxFontEncHashSize)
165 //------------------------------------------------------------------------
167 //------------------------------------------------------------------------
169 GfxFont::GfxFont(char *tag1, Ref id1, Dict *fontDict) {
170 BuiltinFont *builtinFont;
172 Object obj1, obj2, obj3;
176 // get font tag and ID
177 tag = new GString(tag1);
180 // get base font name
182 fontDict->lookup("BaseFont", &obj1);
184 name = new GString(obj1.getName());
187 // is it a built-in font?
190 for (i = 0; i < numBuiltinFonts; ++i) {
191 if (!strcmp(builtinFonts[i].name, name->getCString())) {
192 builtinFont = &builtinFonts[i];
199 type = fontUnknownType;
200 fontDict->lookup("Subtype", &obj1);
201 if (obj1.isName("Type1"))
203 else if (obj1.isName("Type3"))
205 else if (obj1.isName("TrueType"))
207 else if (obj1.isName("Type0"))
212 // get info from font descriptor
213 // for flags: assume Times-Roman (or TimesNewRoman), but
214 // explicitly check for Arial and CourierNew -- certain PDF
215 // generators apparently don't include FontDescriptors for Arial,
216 // TimesNewRoman, and CourierNew
217 flags = fontSerif; // assume Times-Roman by default
218 if (type == fontTrueType && !name->cmp("Arial"))
220 else if (type == fontTrueType && !name->cmp("CourierNew"))
221 flags = fontFixedWidth;
226 fontDict->lookup("FontDescriptor", &obj1);
230 obj1.dictLookup("Flags", &obj2);
232 flags = obj2.getInt();
235 // embedded Type 1 font file and font name
236 if (type == fontType1) {
237 obj1.dictLookupNF("FontFile", &obj2);
239 embFontID = obj2.getRef();
241 // get font name from the font file itself since font subsets
242 // sometimes use the 'AAAAAA+foo' name and sometimes use just 'foo'
244 if (obj3.isStream()) {
246 for (i = 0; i < 64; ++i) {
247 obj3.streamGetLine(buf, sizeof(buf));
248 if (!strncmp(buf, "/FontName", 9)) {
249 if ((p1 = strchr(buf+9, '/'))) {
251 for (p2 = p1; *p2 && !isspace(*p2); ++p2) ;
252 embFontName = new GString(p1, p2 - p1);
261 // couldn't find font name so just use the one in the PDF font
264 obj1.dictLookup("FontName", &obj2);
266 embFontName = new GString(obj2.getName());
271 // embedded TrueType font file
272 } else if (type == fontTrueType) {
273 obj1.dictLookupNF("FontFile2", &obj2);
275 embFontID = obj2.getRef();
282 fontMat[0] = fontMat[3] = 1;
283 fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
284 if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
285 for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
286 if (obj1.arrayGet(i, &obj2)->isNum())
287 fontMat[i] = obj2.getNum();
293 // get encoding and character widths
294 if (type == fontType0) {
295 getType0EncAndWidths(fontDict);
296 } else if (builtinFont) {
297 makeEncoding(fontDict, builtinFont->encoding);
298 makeWidths(fontDict, builtinFont->encoding, builtinFont->widths);
300 makeEncoding(fontDict, NULL);
301 makeWidths(fontDict, NULL, NULL);
305 GfxFont::~GfxFont() {
309 if (!is16 && encoding)
316 gfree(widths16.exceps);
319 double GfxFont::getWidth(GString *s) {
324 for (i = 0; i < s->getLength(); ++i)
325 w += widths[s->getChar(i) & 0xff];
329 double GfxFont::getWidth16(int c) {
333 w = widths16.defWidth;
335 b = widths16.numExceps;
336 // invariant: widths16.exceps[a].last < c < widths16.exceps[b].first
339 if (widths16.exceps[m].last < c) {
341 } else if (c < widths16.exceps[m].first) {
344 w = widths16.exceps[m].width;
351 double GfxFont::getWidth16(GString *s) {
357 for (i = 0; i < s->getLength(); i += 2) {
358 c = (s->getChar(i) << 8) + s->getChar(i+1);
364 void GfxFont::makeEncoding(Dict *fontDict, GfxFontEncoding *builtinEncoding) {
365 GfxFontEncoding *baseEnc;
366 Object obj1, obj2, obj3;
370 // start with empty encoding
371 encoding = new GfxFontEncoding();
373 // get encoding from font dict
374 fontDict->lookup("Encoding", &obj1);
376 // encoding specified by dictionary
378 obj1.dictLookup("BaseEncoding", &obj2);
379 baseEnc = makeEncoding1(obj2, fontDict, builtinEncoding);
381 obj1.dictLookup("Differences", &obj2);
382 if (obj2.isArray()) {
384 for (i = 0; i < obj2.arrayGetLength(); ++i) {
385 obj2.arrayGet(i, &obj3);
387 code = obj3.getInt();
388 } else if (obj3.isName()) {
390 encoding->addChar(code, copyString(obj3.getName()));
393 error(-1, "Wrong type in font encoding resource differences (%s)",
401 // encoding specified by name or null
403 baseEnc = makeEncoding1(obj1, fontDict, builtinEncoding);
406 // free the font dict encoding
409 // merge base encoding and differences;
410 for (code = 0; code < 256; ++code) {
411 if (!encoding->getCharName(code)) {
412 if ((charName = baseEnc->getCharName(code)))
413 encoding->addChar(code, copyString(charName));
418 GfxFontEncoding *GfxFont::makeEncoding1(Object obj, Dict *fontDict,
419 GfxFontEncoding *builtinEncoding) {
420 GfxFontEncoding *enc;
427 // MacRoman, WinAnsi, or Standard encoding
428 if (obj.isName("MacRomanEncoding")) {
429 enc = &macRomanEncoding;
430 } else if (obj.isName("WinAnsiEncoding")) {
431 enc = &winAnsiEncoding;
432 } else if (obj.isName("StandardEncoding")) {
433 enc = &standardEncoding;
435 // use the built-in font encoding if possible
436 } else if (builtinEncoding) {
437 enc = builtinEncoding;
442 // Type 1 font: try to get encoding from font file
443 if (type == fontType1) {
445 // default to using standard encoding
446 enc = &standardEncoding;
448 // is there an external font file?
449 haveEncoding = gFalse;
451 for (path = fontPath; *path; ++path) {
452 extFontFile = appendToPath(new GString(*path), name->getCString());
453 f = fopen(extFontFile->getCString(), "rb");
455 extFontFile->append(".pfb");
456 f = fopen(extFontFile->getCString(), "rb");
459 extFontFile->del(extFontFile->getLength() - 4, 4);
460 extFontFile->append(".pfa");
461 f = fopen(extFontFile->getCString(), "rb");
465 str = new FileStream(f, 0, -1, &obj1);
466 getType1Encoding(str);
469 haveEncoding = gTrue;
477 // is there an embedded font file?
478 // (this has to be checked after the external font because
479 // XOutputDev needs the encoding from the external font)
480 if (!haveEncoding && embFontID.num >= 0) {
481 obj1.initRef(embFontID.num, embFontID.gen);
484 getType1Encoding(obj2.getStream());
489 // TrueType font: use Mac encoding
490 } else if (type == fontTrueType) {
491 enc = &macRomanEncoding;
493 // not Type 1 or TrueType: just use the standard encoding
495 enc = &standardEncoding;
502 void GfxFont::getType1Encoding(Stream *str) {
508 // look for encoding in font file
511 for (i = 0; i < 100; ++i) {
512 if (!str->getLine(buf, sizeof(buf)))
514 if (!strncmp(buf, "/Encoding StandardEncoding def", 30))
516 if (!strncmp(buf, "/Encoding 256 array", 19)) {
522 // found the encoding, grab it
524 for (i = 0; i < 300; ++i) {
525 if (!str->getLine(buf, sizeof(buf)))
527 p = strtok(buf, " \t");
528 if (p && !strcmp(p, "dup")) {
529 if ((p = strtok(NULL, " \t"))) {
531 if ((p = strtok(NULL, " \t"))) {
533 encoding->addChar(code, copyString(p+1));
538 //~ look for getinterval/putinterval junk
542 void GfxFont::makeWidths(Dict *fontDict, GfxFontEncoding *builtinEncoding,
543 Gushort *builtinWidths) {
545 int firstChar, lastChar;
552 // initialize all widths to zero
553 for (code = 0; code < 256; ++code)
556 // use widths from built-in font
557 if (builtinEncoding) {
558 code2 = 0; // to make gcc happy
559 for (code = 0; code < 256; ++code) {
560 if ((charName = encoding->getCharName(code)) &&
561 (code2 = builtinEncoding->getCharCode(charName)) >= 0)
562 widths[code] = builtinWidths[code2] * 0.001;
565 // get widths from font dict
567 fontDict->lookup("FirstChar", &obj1);
568 firstChar = obj1.isInt() ? obj1.getInt() : 0;
570 fontDict->lookup("LastChar", &obj1);
571 lastChar = obj1.isInt() ? obj1.getInt() : 255;
573 if (type == fontType3)
577 fontDict->lookup("Widths", &obj1);
578 if (obj1.isArray()) {
579 for (code = firstChar; code <= lastChar; ++code) {
580 obj1.arrayGet(code - firstChar, &obj2);
582 widths[code] = obj2.getNum() * mult;
587 // couldn't find widths -- use defaults
589 //~ certain PDF generators apparently don't include widths
590 //~ for Arial and TimesNewRoman -- and this error message
592 error(-1, "No character widths resource for non-builtin font");
604 defWidths = defCharWidths[index];
605 code2 = 0; // to make gcc happy
606 for (code = 0; code < 256; ++code) {
607 if ((charName = encoding->getCharName(code)) &&
608 (code2 = standardEncoding.getCharCode(charName)) >= 0)
609 widths[code] = defWidths[code2] * 0.001;
616 void GfxFont::getType0EncAndWidths(Dict *fontDict) {
617 Object obj1, obj2, obj3, obj4, obj5, obj6;
621 fontDict->lookup("DescendantFonts", &obj1);
622 if (!obj1.isArray() || obj1.arrayGetLength() != 1) {
623 error(-1, "Bad DescendantFonts entry for Type 0 font");
626 obj1.arrayGet(0, &obj2);
627 if (!obj2.isDict("Font")) {
628 error(-1, "Bad descendant font of Type 0 font");
632 obj2.dictLookup("CIDSystemInfo", &obj3);
633 if (!obj3.isDict()) {
634 error(-1, "Bad CIDSystemInfo in Type 0 font descendant");
637 obj3.dictLookup("Registry", &obj4);
638 obj3.dictLookup("Ordering", &obj5);
639 if (obj4.isString() && obj5.isString()) {
640 if (obj4.getString()->cmp("Adobe") == 0 &&
641 obj5.getString()->cmp("Japan1") == 0) {
644 enc16.charSet = font16AdobeJapan12;
646 error(-1, "Xpdf was compiled without Japanese font support");
650 error(-1, "Uknown Type 0 character set: %s-%s",
651 obj4.getString()->getCString(), obj5.getString()->getCString());
655 error(-1, "Unknown Type 0 character set");
662 obj2.dictLookup("DW", &obj3);
664 widths16.defWidth = obj3.getInt() * 0.001;
666 widths16.defWidth = 1.0;
669 widths16.exceps = NULL;
670 widths16.numExceps = 0;
671 obj2.dictLookup("W", &obj3);
672 if (obj3.isArray()) {
676 while (i+1 < obj3.arrayGetLength()) {
677 obj3.arrayGet(i, &obj4);
678 obj3.arrayGet(i+1, &obj5);
679 if (obj4.isInt() && obj5.isInt()) {
680 obj3.arrayGet(i+2, &obj6);
682 error(-1, "Bad widths array in Type 0 font");
688 if (k == excepsSize) {
690 widths16.exceps = (GfxFontWidthExcep *)
691 grealloc(widths16.exceps,
692 excepsSize * sizeof(GfxFontWidthExcep));
694 widths16.exceps[k].first = obj4.getInt();
695 widths16.exceps[k].last = obj5.getInt();
696 widths16.exceps[k].width = obj6.getNum() * 0.001;
700 } else if (obj4.isInt() && obj5.isArray()) {
701 if (k + obj5.arrayGetLength() >= excepsSize) {
702 excepsSize = (k + obj5.arrayGetLength() + 15) & ~15;
703 widths16.exceps = (GfxFontWidthExcep *)
704 grealloc(widths16.exceps,
705 excepsSize * sizeof(GfxFontWidthExcep));
708 for (j = 0; j < obj5.arrayGetLength(); ++j) {
709 obj5.arrayGet(j, &obj6);
711 error(-1, "Bad widths array in Type 0 font");
715 widths16.exceps[k].first = widths16.exceps[k].last = n++;
716 widths16.exceps[k].width = obj6.getNum() * 0.001;
722 error(-1, "Bad widths array in Type 0 font");
731 widths16.numExceps = k;
733 qsort(widths16.exceps, k, sizeof(GfxFontWidthExcep), &cmpWidthExcep);
740 fontDict->lookup("Encoding", &obj1);
741 if (!obj1.isName()) {
742 error(-1, "Bad encoding for Type 0 font");
746 if (enc16.charSet == font16AdobeJapan12) {
747 for (i = 0; gfxFontEnc16Tab[i].name; ++i) {
748 if (!strcmp(obj1.getName(), gfxFontEnc16Tab[i].name))
751 if (!gfxFontEnc16Tab[i].name) {
752 error(-1, "Unknown encoding '%s' for Adobe-Japan1-2 font",
756 enc16.enc = gfxFontEnc16Tab[i].enc;
772 makeEncoding(fontDict, NULL);
773 makeWidths(fontDict, NULL, NULL);
776 static int CDECL cmpWidthExcep(const void *w1, const void *w2) {
777 return ((GfxFontWidthExcep *)w1)->first - ((GfxFontWidthExcep *)w2)->first;
780 //------------------------------------------------------------------------
782 //------------------------------------------------------------------------
784 GfxFontDict::GfxFontDict(Dict *fontDict) {
788 numFonts = fontDict->getLength();
789 fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *));
790 for (i = 0; i < numFonts; ++i) {
791 fontDict->getValNF(i, &obj1);
793 if (obj1.isRef() && obj2.isDict("Font")) {
794 fonts[i] = new GfxFont(fontDict->getKey(i), obj1.getRef(),
797 error(-1, "font resource is not a dictionary");
805 GfxFontDict::~GfxFontDict() {
808 for (i = 0; i < numFonts; ++i)
813 GfxFont *GfxFontDict::lookup(char *tag) {
816 for (i = 0; i < numFonts; ++i) {
817 if (fonts[i]->matches(tag))