1 //========================================================================
2 //
3 // GfxFont.cc
4 //
5 // Copyright 1996-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <math.h>
20 #include <limits.h>
21 #if HAVE_STD_SORT
22 #include <algorithm>
23 #endif
24 #include "gmem.h"
25 #include "Error.h"
26 #include "Object.h"
27 #include "Dict.h"
28 #include "GlobalParams.h"
29 #include "CMap.h"
30 #include "CharCodeToUnicode.h"
31 #include "FontEncodingTables.h"
32 #include "BuiltinFontTables.h"
33 #include "FoFiIdentifier.h"
34 #include "FoFiType1.h"
35 #include "FoFiType1C.h"
36 #include "FoFiTrueType.h"
37 #include "GfxFont.h"
38
39 //------------------------------------------------------------------------
40
41 struct Base14FontMapEntry {
42 const char *altName;
43 const char *base14Name;
44 };
45
46 static Base14FontMapEntry base14FontMap[] = {
47 { "Arial", "Helvetica" },
48 { "Arial,Bold", "Helvetica-Bold" },
49 { "Arial,BoldItalic", "Helvetica-BoldOblique" },
50 { "Arial,Italic", "Helvetica-Oblique" },
51 { "Arial-Bold", "Helvetica-Bold" },
52 { "Arial-BoldItalic", "Helvetica-BoldOblique" },
53 { "Arial-BoldItalicMT", "Helvetica-BoldOblique" },
54 { "Arial-BoldMT", "Helvetica-Bold" },
55 { "Arial-Italic", "Helvetica-Oblique" },
56 { "Arial-ItalicMT", "Helvetica-Oblique" },
57 { "ArialMT", "Helvetica" },
58 { "Courier", "Courier" },
59 { "Courier,Bold", "Courier-Bold" },
60 { "Courier,BoldItalic", "Courier-BoldOblique" },
61 { "Courier,Italic", "Courier-Oblique" },
62 { "Courier-Bold", "Courier-Bold" },
63 { "Courier-BoldOblique", "Courier-BoldOblique" },
64 { "Courier-Oblique", "Courier-Oblique" },
65 { "CourierNew", "Courier" },
66 { "CourierNew,Bold", "Courier-Bold" },
67 { "CourierNew,BoldItalic", "Courier-BoldOblique" },
68 { "CourierNew,Italic", "Courier-Oblique" },
69 { "CourierNew-Bold", "Courier-Bold" },
70 { "CourierNew-BoldItalic", "Courier-BoldOblique" },
71 { "CourierNew-Italic", "Courier-Oblique" },
72 { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" },
73 { "CourierNewPS-BoldMT", "Courier-Bold" },
74 { "CourierNewPS-ItalicMT", "Courier-Oblique" },
75 { "CourierNewPSMT", "Courier" },
76 { "Helvetica", "Helvetica" },
77 { "Helvetica,Bold", "Helvetica-Bold" },
78 { "Helvetica,BoldItalic", "Helvetica-BoldOblique" },
79 { "Helvetica,Italic", "Helvetica-Oblique" },
80 { "Helvetica-Bold", "Helvetica-Bold" },
81 { "Helvetica-BoldItalic", "Helvetica-BoldOblique" },
82 { "Helvetica-BoldOblique", "Helvetica-BoldOblique" },
83 { "Helvetica-Italic", "Helvetica-Oblique" },
84 { "Helvetica-Oblique", "Helvetica-Oblique" },
85 { "Symbol", "Symbol" },
86 { "Symbol,Bold", "Symbol" },
87 { "Symbol,BoldItalic", "Symbol" },
88 { "Symbol,Italic", "Symbol" },
89 { "Times-Bold", "Times-Bold" },
90 { "Times-BoldItalic", "Times-BoldItalic" },
91 { "Times-Italic", "Times-Italic" },
92 { "Times-Roman", "Times-Roman" },
93 { "TimesNewRoman", "Times-Roman" },
94 { "TimesNewRoman,Bold", "Times-Bold" },
95 { "TimesNewRoman,BoldItalic", "Times-BoldItalic" },
96 { "TimesNewRoman,Italic", "Times-Italic" },
97 { "TimesNewRoman-Bold", "Times-Bold" },
98 { "TimesNewRoman-BoldItalic", "Times-BoldItalic" },
99 { "TimesNewRoman-Italic", "Times-Italic" },
100 { "TimesNewRomanPS", "Times-Roman" },
101 { "TimesNewRomanPS-Bold", "Times-Bold" },
102 { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" },
103 { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" },
104 { "TimesNewRomanPS-BoldMT", "Times-Bold" },
105 { "TimesNewRomanPS-Italic", "Times-Italic" },
106 { "TimesNewRomanPS-ItalicMT", "Times-Italic" },
107 { "TimesNewRomanPSMT", "Times-Roman" },
108 { "TimesNewRomanPSMT,Bold", "Times-Bold" },
109 { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" },
110 { "TimesNewRomanPSMT,Italic", "Times-Italic" },
111 { "ZapfDingbats", "ZapfDingbats" }
112 };
113
114 //------------------------------------------------------------------------
115
116 // index: {fixed:0, sans-serif:4, serif:8} + bold*2 + italic
117 // NB: must be in same order as psSubstFonts in PSOutputDev.cc
118 static const char *base14SubstFonts[14] = {
119 "Courier",
120 "Courier-Oblique",
121 "Courier-Bold",
122 "Courier-BoldOblique",
123 "Helvetica",
124 "Helvetica-Oblique",
125 "Helvetica-Bold",
126 "Helvetica-BoldOblique",
127 "Times-Roman",
128 "Times-Italic",
129 "Times-Bold",
130 "Times-BoldItalic",
131 // the last two are never used for substitution
132 "Symbol",
133 "ZapfDingbats"
134 };
135
136 //------------------------------------------------------------------------
137
readFromStream(void * data)138 static int readFromStream(void *data) {
139 return ((Stream *)data)->getChar();
140 }
141
142 //------------------------------------------------------------------------
143 // GfxFontLoc
144 //------------------------------------------------------------------------
145
GfxFontLoc()146 GfxFontLoc::GfxFontLoc() {
147 path = NULL;
148 fontNum = 0;
149 oblique = 0;
150 encoding = NULL;
151 substIdx = -1;
152 }
153
~GfxFontLoc()154 GfxFontLoc::~GfxFontLoc() {
155 if (path) {
156 delete path;
157 }
158 if (encoding) {
159 delete encoding;
160 }
161 }
162
163 //------------------------------------------------------------------------
164 // GfxFont
165 //------------------------------------------------------------------------
166
makeFont(XRef * xref,char * tagA,Ref idA,Dict * fontDict)167 GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) {
168 GString *nameA;
169 Ref embFontIDA;
170 GfxFontType typeA;
171 GfxFont *font;
172 Object obj1;
173
174 // get base font name
175 nameA = NULL;
176 fontDict->lookup("BaseFont", &obj1);
177 if (obj1.isName()) {
178 nameA = new GString(obj1.getName());
179 } else if (obj1.isString()) {
180 nameA = obj1.getString()->copy();
181 }
182 obj1.free();
183
184 // get embedded font ID and font type
185 typeA = getFontType(xref, fontDict, &embFontIDA);
186
187 // create the font object
188 font = NULL;
189 if (typeA < fontCIDType0) {
190 font = new Gfx8BitFont(xref, tagA, idA, nameA, typeA, embFontIDA,
191 fontDict);
192 } else {
193 font = new GfxCIDFont(xref, tagA, idA, nameA, typeA, embFontIDA,
194 fontDict);
195 }
196
197 return font;
198 }
199
GfxFont(char * tagA,Ref idA,GString * nameA,GfxFontType typeA,Ref embFontIDA)200 GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA,
201 GfxFontType typeA, Ref embFontIDA) {
202 ok = gFalse;
203 tag = new GString(tagA);
204 id = idA;
205 name = nameA;
206 type = typeA;
207 embFontID = embFontIDA;
208 embFontName = NULL;
209 }
210
~GfxFont()211 GfxFont::~GfxFont() {
212 delete tag;
213 if (name) {
214 delete name;
215 }
216 if (embFontName) {
217 delete embFontName;
218 }
219 }
220
221 // This function extracts three pieces of information:
222 // 1. the "expected" font type, i.e., the font type implied by
223 // Font.Subtype, DescendantFont.Subtype, and
224 // FontDescriptor.FontFile3.Subtype
225 // 2. the embedded font object ID
226 // 3. the actual font type - determined by examining the embedded font
227 // if there is one, otherwise equal to the expected font type
228 // If the expected and actual font types don't match, a warning
229 // message is printed. The expected font type is not used for
230 // anything else.
getFontType(XRef * xref,Dict * fontDict,Ref * embID)231 GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
232 GfxFontType t, expectedType;
233 FoFiIdentifierType fft;
234 Dict *fontDict2;
235 Object subtype, fontDesc, obj1, obj2, obj3, obj4;
236 GBool isType0, err;
237
238 t = fontUnknownType;
239 embID->num = embID->gen = -1;
240 err = gFalse;
241
242 fontDict->lookup("Subtype", &subtype);
243 expectedType = fontUnknownType;
244 isType0 = gFalse;
245 if (subtype.isName("Type1") || subtype.isName("MMType1")) {
246 expectedType = fontType1;
247 } else if (subtype.isName("Type1C")) {
248 expectedType = fontType1C;
249 } else if (subtype.isName("Type3")) {
250 expectedType = fontType3;
251 } else if (subtype.isName("TrueType")) {
252 expectedType = fontTrueType;
253 } else if (subtype.isName("Type0")) {
254 isType0 = gTrue;
255 } else {
256 error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'",
257 subtype.isName() ? subtype.getName() : "???");
258 }
259 subtype.free();
260
261 fontDict2 = fontDict;
262 if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
263 if (obj1.arrayGetLength() == 0) {
264 error(errSyntaxWarning, -1, "Empty DescendantFonts array in font");
265 obj2.initNull();
266 } else if (obj1.arrayGet(0, &obj2)->isDict()) {
267 if (!isType0) {
268 error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
269 }
270 fontDict2 = obj2.getDict();
271 fontDict2->lookup("Subtype", &subtype);
272 if (subtype.isName("CIDFontType0")) {
273 if (isType0) {
274 expectedType = fontCIDType0;
275 }
276 } else if (subtype.isName("CIDFontType2")) {
277 if (isType0) {
278 expectedType = fontCIDType2;
279 }
280 }
281 subtype.free();
282 }
283 } else {
284 obj2.initNull();
285 }
286
287 if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) {
288 if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) {
289 *embID = obj3.getRef();
290 if (expectedType != fontType1) {
291 err = gTrue;
292 }
293 }
294 obj3.free();
295 if (embID->num == -1 &&
296 fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) {
297 *embID = obj3.getRef();
298 if (isType0) {
299 expectedType = fontCIDType2;
300 } else if (expectedType != fontTrueType) {
301 err = gTrue;
302 }
303 }
304 obj3.free();
305 if (embID->num == -1 &&
306 fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) {
307 *embID = obj3.getRef();
308 if (obj3.fetch(xref, &obj4)->isStream()) {
309 obj4.streamGetDict()->lookup("Subtype", &subtype);
310 if (subtype.isName("Type1")) {
311 if (expectedType != fontType1) {
312 err = gTrue;
313 expectedType = isType0 ? fontCIDType0 : fontType1;
314 }
315 } else if (subtype.isName("Type1C")) {
316 if (expectedType == fontType1) {
317 expectedType = fontType1C;
318 } else if (expectedType != fontType1C) {
319 err = gTrue;
320 expectedType = isType0 ? fontCIDType0C : fontType1C;
321 }
322 } else if (subtype.isName("TrueType")) {
323 if (expectedType != fontTrueType) {
324 err = gTrue;
325 expectedType = isType0 ? fontCIDType2 : fontTrueType;
326 }
327 } else if (subtype.isName("CIDFontType0C")) {
328 if (expectedType == fontCIDType0) {
329 expectedType = fontCIDType0C;
330 } else {
331 err = gTrue;
332 expectedType = isType0 ? fontCIDType0C : fontType1C;
333 }
334 } else if (subtype.isName("OpenType")) {
335 if (expectedType == fontTrueType) {
336 expectedType = fontTrueTypeOT;
337 } else if (expectedType == fontType1) {
338 expectedType = fontType1COT;
339 } else if (expectedType == fontCIDType0) {
340 expectedType = fontCIDType0COT;
341 } else if (expectedType == fontCIDType2) {
342 expectedType = fontCIDType2OT;
343 } else {
344 err = gTrue;
345 }
346 } else {
347 error(errSyntaxError, -1, "Unknown font type '{0:s}'",
348 subtype.isName() ? subtype.getName() : "???");
349 }
350 subtype.free();
351 }
352 obj4.free();
353 }
354 obj3.free();
355 }
356 fontDesc.free();
357
358 t = fontUnknownType;
359 if (embID->num >= 0) {
360 obj3.initRef(embID->num, embID->gen);
361 obj3.fetch(xref, &obj4);
362 if (obj4.isStream()) {
363 obj4.streamReset();
364 fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream());
365 obj4.streamClose();
366 switch (fft) {
367 case fofiIdType1PFA:
368 case fofiIdType1PFB:
369 t = fontType1;
370 break;
371 case fofiIdCFF8Bit:
372 t = isType0 ? fontCIDType0C : fontType1C;
373 break;
374 case fofiIdCFFCID:
375 t = fontCIDType0C;
376 break;
377 case fofiIdTrueType:
378 case fofiIdTrueTypeCollection:
379 t = isType0 ? fontCIDType2 : fontTrueType;
380 break;
381 case fofiIdOpenTypeCFF8Bit:
382 t = isType0 ? fontCIDType0COT : fontType1COT;
383 break;
384 case fofiIdOpenTypeCFFCID:
385 t = fontCIDType0COT;
386 break;
387 default:
388 error(errSyntaxError, -1, "Embedded font file may be invalid");
389 break;
390 }
391 }
392 obj4.free();
393 obj3.free();
394 }
395
396 if (t == fontUnknownType) {
397 t = expectedType;
398 }
399
400 if (t != expectedType) {
401 err = gTrue;
402 }
403
404 if (err) {
405 error(errSyntaxWarning, -1,
406 "Mismatch between font type and embedded font file");
407 }
408
409 obj2.free();
410 obj1.free();
411
412 return t;
413 }
414
readFontDescriptor(XRef * xref,Dict * fontDict)415 void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
416 Object obj1, obj2, obj3, obj4;
417 double t;
418 int i;
419
420 // assume Times-Roman by default (for substitution purposes)
421 flags = fontSerif;
422
423 missingWidth = 0;
424
425 if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
426
427 // get flags
428 if (obj1.dictLookup("Flags", &obj2)->isInt()) {
429 flags = obj2.getInt();
430 }
431 obj2.free();
432
433 // get name
434 obj1.dictLookup("FontName", &obj2);
435 if (obj2.isName()) {
436 embFontName = new GString(obj2.getName());
437 }
438 obj2.free();
439
440 // look for MissingWidth
441 obj1.dictLookup("MissingWidth", &obj2);
442 if (obj2.isNum()) {
443 missingWidth = obj2.getNum();
444 }
445 obj2.free();
446
447 // get Ascent and Descent
448 obj1.dictLookup("Ascent", &obj2);
449 if (obj2.isNum()) {
450 t = 0.001 * obj2.getNum();
451 // some broken font descriptors specify a negative ascent
452 if (t < 0) {
453 t = -t;
454 }
455 // some broken font descriptors set ascent and descent to 0;
456 // others set it to ridiculous values (e.g., 32768)
457 if (t != 0 && t < 1.9) {
458 ascent = t;
459 }
460 }
461 obj2.free();
462 obj1.dictLookup("Descent", &obj2);
463 if (obj2.isNum()) {
464 t = 0.001 * obj2.getNum();
465 // some broken font descriptors specify a positive descent
466 if (t > 0) {
467 t = -t;
468 }
469 // some broken font descriptors set ascent and descent to 0
470 if (t != 0 && t > -1.9) {
471 descent = t;
472 }
473 }
474 obj2.free();
475
476 // font FontBBox
477 if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
478 for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
479 if (obj2.arrayGet(i, &obj3)->isNum()) {
480 fontBBox[i] = 0.001 * obj3.getNum();
481 }
482 obj3.free();
483 }
484 }
485 obj2.free();
486
487 }
488 obj1.free();
489 }
490
readToUnicodeCMap(Dict * fontDict,int nBits,CharCodeToUnicode * ctu)491 CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
492 CharCodeToUnicode *ctu) {
493 GString *buf;
494 Object obj1;
495 char buf2[4096];
496 int n;
497
498 if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) {
499 obj1.free();
500 return NULL;
501 }
502 buf = new GString();
503 obj1.streamReset();
504 while ((n = obj1.streamGetBlock(buf2, sizeof(buf2))) > 0) {
505 buf->append(buf2, n);
506 }
507 obj1.streamClose();
508 obj1.free();
509 if (ctu) {
510 ctu->mergeCMap(buf, nBits);
511 } else {
512 ctu = CharCodeToUnicode::parseCMap(buf, nBits);
513 }
514 delete buf;
515 return ctu;
516 }
517
locateFont(XRef * xref,GBool ps)518 GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) {
519 GfxFontLoc *fontLoc;
520 SysFontType sysFontType;
521 GString *path, *base14Name, *substName;
522 PSFontParam16 *psFont16;
523 Object refObj, embFontObj;
524 int substIdx, fontNum;
525 double oblique;
526 GBool embed;
527
528 if (type == fontType3) {
529 return NULL;
530 }
531
532 //----- embedded font
533 if (embFontID.num >= 0) {
534 embed = gTrue;
535 refObj.initRef(embFontID.num, embFontID.gen);
536 refObj.fetch(xref, &embFontObj);
537 if (!embFontObj.isStream()) {
538 error(errSyntaxError, -1, "Embedded font object is wrong type");
539 embed = gFalse;
540 }
541 embFontObj.free();
542 refObj.free();
543 if (embed) {
544 if (ps) {
545 switch (type) {
546 case fontType1:
547 case fontType1C:
548 case fontType1COT:
549 embed = globalParams->getPSEmbedType1();
550 break;
551 case fontTrueType:
552 case fontTrueTypeOT:
553 embed = globalParams->getPSEmbedTrueType();
554 break;
555 case fontCIDType0C:
556 case fontCIDType0COT:
557 embed = globalParams->getPSEmbedCIDPostScript();
558 break;
559 case fontCIDType2:
560 case fontCIDType2OT:
561 embed = globalParams->getPSEmbedCIDTrueType();
562 break;
563 default:
564 break;
565 }
566 }
567 if (embed) {
568 fontLoc = new GfxFontLoc();
569 fontLoc->locType = gfxFontLocEmbedded;
570 fontLoc->fontType = type;
571 fontLoc->embFontID = embFontID;
572 return fontLoc;
573 }
574 }
575 }
576
577 //----- PS passthrough
578 if (ps && name && !isCIDFont() && globalParams->getPSFontPassthrough()) {
579 fontLoc = new GfxFontLoc();
580 fontLoc->locType = gfxFontLocResident;
581 fontLoc->fontType = fontType1;
582 fontLoc->path = name->copy();
583 return fontLoc;
584 }
585
586 //----- external font file (fontFile, fontDir)
587 if (name && (path = globalParams->findFontFile(name))) {
588 if ((fontLoc = getExternalFont(path, 0, 0, isCIDFont()))) {
589 return fontLoc;
590 }
591 }
592
593 //----- PS resident Base-14 font
594 if (ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
595 fontLoc = new GfxFontLoc();
596 fontLoc->locType = gfxFontLocResident;
597 fontLoc->fontType = fontType1;
598 fontLoc->path = new GString(((Gfx8BitFont *)this)->base14->base14Name);
599 return fontLoc;
600 }
601
602 //----- external font file for Base-14 font
603 if (!ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
604 base14Name = new GString(((Gfx8BitFont *)this)->base14->base14Name);
605 path = globalParams->findBase14FontFile(base14Name, &fontNum, &oblique);
606 delete base14Name;
607 if (path && (fontLoc = getExternalFont(path, fontNum, oblique, gFalse))) {
608 return fontLoc;
609 }
610 }
611
612 //----- system font
613 if (name && (path = globalParams->findSystemFontFile(name, &sysFontType,
614 &fontNum))) {
615 if (isCIDFont()) {
616 if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
617 fontLoc = new GfxFontLoc();
618 fontLoc->locType = gfxFontLocExternal;
619 fontLoc->fontType = fontCIDType2;
620 fontLoc->path = path;
621 fontLoc->fontNum = fontNum;
622 return fontLoc;
623 }
624 } else {
625 if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
626 fontLoc = new GfxFontLoc();
627 fontLoc->locType = gfxFontLocExternal;
628 fontLoc->fontType = fontTrueType;
629 fontLoc->path = path;
630 fontLoc->fontNum = fontNum;
631 return fontLoc;
632 } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) {
633 fontLoc = new GfxFontLoc();
634 fontLoc->locType = gfxFontLocExternal;
635 fontLoc->fontType = fontType1;
636 fontLoc->path = path;
637 return fontLoc;
638 }
639 }
640 delete path;
641 }
642
643 if (!isCIDFont()) {
644
645 //----- 8-bit PS resident font
646 if (ps) {
647 if (name && (path = globalParams->getPSResidentFont(name))) {
648 fontLoc = new GfxFontLoc();
649 fontLoc->locType = gfxFontLocResident;
650 fontLoc->fontType = fontType1;
651 fontLoc->path = path;
652 return fontLoc;
653 }
654 }
655
656 //----- 8-bit font substitution
657 if (flags & fontFixedWidth) {
658 substIdx = 0;
659 } else if (flags & fontSerif) {
660 substIdx = 8;
661 } else {
662 substIdx = 4;
663 }
664 if (isBold()) {
665 substIdx += 2;
666 }
667 if (isItalic()) {
668 substIdx += 1;
669 }
670 substName = new GString(base14SubstFonts[substIdx]);
671 if (ps) {
672 error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
673 base14SubstFonts[substIdx], name);
674 fontLoc = new GfxFontLoc();
675 fontLoc->locType = gfxFontLocResident;
676 fontLoc->fontType = fontType1;
677 fontLoc->path = substName;
678 fontLoc->substIdx = substIdx;
679 return fontLoc;
680 } else {
681 path = globalParams->findBase14FontFile(substName, &fontNum, &oblique);
682 delete substName;
683 if (path) {
684 if ((fontLoc = getExternalFont(path, fontNum, oblique, gFalse))) {
685 error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
686 base14SubstFonts[substIdx], name);
687 fontLoc->substIdx = substIdx;
688 return fontLoc;
689 }
690 }
691 }
692
693 // failed to find a substitute font
694 return NULL;
695 }
696
697 //----- 16-bit PS resident font
698 if (ps && name && ((psFont16 = globalParams->getPSResidentFont16(
699 name,
700 ((GfxCIDFont *)this)->getWMode())))) {
701 fontLoc = new GfxFontLoc();
702 fontLoc->locType = gfxFontLocResident;
703 fontLoc->fontType = fontCIDType0; // this is not used
704 fontLoc->path = psFont16->psFontName->copy();
705 fontLoc->encoding = psFont16->encoding->copy();
706 fontLoc->wMode = psFont16->wMode;
707 return fontLoc;
708 }
709 if (ps && ((psFont16 = globalParams->getPSResidentFontCC(
710 ((GfxCIDFont *)this)->getCollection(),
711 ((GfxCIDFont *)this)->getWMode())))) {
712 error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
713 psFont16->psFontName, name);
714 fontLoc = new GfxFontLoc();
715 fontLoc->locType = gfxFontLocResident;
716 fontLoc->fontType = fontCIDType0; // this is not used
717 fontLoc->path = psFont16->psFontName->copy();
718 fontLoc->encoding = psFont16->encoding->copy();
719 fontLoc->wMode = psFont16->wMode;
720 return fontLoc;
721 }
722
723 //----- CID font substitution
724 if ((path = globalParams->findCCFontFile(
725 ((GfxCIDFont *)this)->getCollection()))) {
726 if ((fontLoc = getExternalFont(path, 0, 0, gTrue))) {
727 error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
728 fontLoc->path, name);
729 return fontLoc;
730 }
731 }
732
733 // failed to find a substitute font
734 return NULL;
735 }
736
locateBase14Font(GString * base14Name)737 GfxFontLoc *GfxFont::locateBase14Font(GString *base14Name) {
738 GString *path;
739 int fontNum;
740 double oblique;
741
742 path = globalParams->findBase14FontFile(base14Name, &fontNum, &oblique);
743 if (!path) {
744 return NULL;
745 }
746 return getExternalFont(path, fontNum, oblique, gFalse);
747 }
748
getExternalFont(GString * path,int fontNum,double oblique,GBool cid)749 GfxFontLoc *GfxFont::getExternalFont(GString *path, int fontNum,
750 double oblique, GBool cid) {
751 FoFiIdentifierType fft;
752 GfxFontType fontType;
753 GfxFontLoc *fontLoc;
754
755 fft = FoFiIdentifier::identifyFile(path->getCString());
756 switch (fft) {
757 case fofiIdType1PFA:
758 case fofiIdType1PFB:
759 fontType = fontType1;
760 break;
761 case fofiIdCFF8Bit:
762 fontType = fontType1C;
763 break;
764 case fofiIdCFFCID:
765 fontType = fontCIDType0C;
766 break;
767 case fofiIdTrueType:
768 case fofiIdTrueTypeCollection:
769 fontType = cid ? fontCIDType2 : fontTrueType;
770 break;
771 case fofiIdOpenTypeCFF8Bit:
772 fontType = fontType1COT;
773 break;
774 case fofiIdOpenTypeCFFCID:
775 fontType = fontCIDType0COT;
776 break;
777 case fofiIdDfont:
778 fontType = cid ? fontCIDType2 : fontTrueType;
779 break;
780 case fofiIdUnknown:
781 case fofiIdError:
782 default:
783 fontType = fontUnknownType;
784 break;
785 }
786 if (fontType == fontUnknownType ||
787 (cid ? (fontType < fontCIDType0)
788 : (fontType >= fontCIDType0))) {
789 delete path;
790 return NULL;
791 }
792 fontLoc = new GfxFontLoc();
793 fontLoc->locType = gfxFontLocExternal;
794 fontLoc->fontType = fontType;
795 fontLoc->path = path;
796 fontLoc->fontNum = fontNum;
797 fontLoc->oblique = oblique;
798 return fontLoc;
799 }
800
readEmbFontFile(XRef * xref,int * len)801 char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
802 char *buf;
803 Object obj1, obj2;
804 Stream *str;
805 int size, n;
806
807 obj1.initRef(embFontID.num, embFontID.gen);
808 obj1.fetch(xref, &obj2);
809 if (!obj2.isStream()) {
810 error(errSyntaxError, -1, "Embedded font file is not a stream");
811 obj2.free();
812 obj1.free();
813 embFontID.num = -1;
814 return NULL;
815 }
816 str = obj2.getStream();
817
818 size = 0;
819 buf = NULL;
820 str->reset();
821 do {
822 if (size > INT_MAX - 4096) {
823 error(errSyntaxError, -1, "Embedded font file is too large");
824 break;
825 }
826 buf = (char *)grealloc(buf, size + 4096);
827 n = str->getBlock(buf + size, 4096);
828 size += n;
829 } while (n == 4096);
830 *len = size;
831 str->close();
832
833 obj2.free();
834 obj1.free();
835
836 return buf;
837 }
838
839 //------------------------------------------------------------------------
840 // Gfx8BitFont
841 //------------------------------------------------------------------------
842
Gfx8BitFont(XRef * xref,char * tagA,Ref idA,GString * nameA,GfxFontType typeA,Ref embFontIDA,Dict * fontDict)843 Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
844 GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
845 GfxFont(tagA, idA, nameA, typeA, embFontIDA)
846 {
847 GString *name2;
848 BuiltinFont *builtinFont;
849 const char **baseEnc;
850 GBool baseEncFromFontFile;
851 char *buf;
852 int len;
853 FoFiType1 *ffT1;
854 FoFiType1C *ffT1C;
855 int code, code2;
856 char *charName;
857 GBool missing, hex;
858 Unicode toUnicode[256];
859 CharCodeToUnicode *utu, *ctu2;
860 Unicode uBuf[8];
861 double mul;
862 int firstChar, lastChar;
863 Gushort w;
864 Object obj1, obj2, obj3;
865 int n, i, a, b, m;
866
867 ctu = NULL;
868
869 // do font name substitution for various aliases of the Base 14 font
870 // names
871 base14 = NULL;
872 if (name) {
873 name2 = name->copy();
874 i = 0;
875 while (i < name2->getLength()) {
876 if (name2->getChar(i) == ' ') {
877 name2->del(i);
878 } else {
879 ++i;
880 }
881 }
882 a = 0;
883 b = sizeof(base14FontMap) / sizeof(Base14FontMapEntry);
884 // invariant: base14FontMap[a].altName <= name2 < base14FontMap[b].altName
885 while (b - a > 1) {
886 m = (a + b) / 2;
887 if (name2->cmp(base14FontMap[m].altName) >= 0) {
888 a = m;
889 } else {
890 b = m;
891 }
892 }
893 if (!name2->cmp(base14FontMap[a].altName)) {
894 base14 = &base14FontMap[a];
895 }
896 delete name2;
897 }
898
899 // is it a built-in font?
900 builtinFont = NULL;
901 if (base14) {
902 for (i = 0; i < nBuiltinFonts; ++i) {
903 if (!strcmp(base14->base14Name, builtinFonts[i].name)) {
904 builtinFont = &builtinFonts[i];
905 break;
906 }
907 }
908 }
909
910 // default ascent/descent values
911 if (builtinFont) {
912 ascent = 0.001 * builtinFont->ascent;
913 descent = 0.001 * builtinFont->descent;
914 fontBBox[0] = 0.001 * builtinFont->bbox[0];
915 fontBBox[1] = 0.001 * builtinFont->bbox[1];
916 fontBBox[2] = 0.001 * builtinFont->bbox[2];
917 fontBBox[3] = 0.001 * builtinFont->bbox[3];
918 } else {
919 ascent = 0.75;
920 descent = -0.25;
921 fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
922 }
923
924 // get info from font descriptor
925 readFontDescriptor(xref, fontDict);
926
927 // for non-embedded fonts, don't trust the ascent/descent/bbox
928 // values from the font descriptor
929 if (builtinFont && embFontID.num < 0) {
930 ascent = 0.001 * builtinFont->ascent;
931 descent = 0.001 * builtinFont->descent;
932 fontBBox[0] = 0.001 * builtinFont->bbox[0];
933 fontBBox[1] = 0.001 * builtinFont->bbox[1];
934 fontBBox[2] = 0.001 * builtinFont->bbox[2];
935 fontBBox[3] = 0.001 * builtinFont->bbox[3];
936 }
937
938 // get font matrix
939 fontMat[0] = fontMat[3] = 1;
940 fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
941 if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
942 for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
943 if (obj1.arrayGet(i, &obj2)->isNum()) {
944 fontMat[i] = obj2.getNum();
945 }
946 obj2.free();
947 }
948 }
949 obj1.free();
950
951 // get Type 3 bounding box, font definition, and resources
952 if (type == fontType3) {
953 if (fontDict->lookup("FontBBox", &obj1)->isArray()) {
954 for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) {
955 if (obj1.arrayGet(i, &obj2)->isNum()) {
956 fontBBox[i] = obj2.getNum();
957 }
958 obj2.free();
959 }
960 }
961 obj1.free();
962 if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) {
963 error(errSyntaxError, -1,
964 "Missing or invalid CharProcs dictionary in Type 3 font");
965 charProcs.free();
966 }
967 if (!fontDict->lookup("Resources", &resources)->isDict()) {
968 resources.free();
969 }
970 }
971
972 //----- build the font encoding -----
973
974 // Encodings start with a base encoding, which can come from
975 // (in order of priority):
976 // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
977 // - MacRoman / MacExpert / WinAnsi / Standard
978 // 2. embedded or external font file
979 // 3. default:
980 // - builtin --> builtin encoding
981 // - TrueType --> WinAnsiEncoding
982 // - others --> StandardEncoding
983 // and then add a list of differences (if any) from
984 // FontDict.Encoding.Differences.
985
986 // check FontDict for base encoding
987 hasEncoding = gFalse;
988 usesMacRomanEnc = gFalse;
989 baseEnc = NULL;
990 baseEncFromFontFile = gFalse;
991 fontDict->lookup("Encoding", &obj1);
992 if (obj1.isDict()) {
993 obj1.dictLookup("BaseEncoding", &obj2);
994 if (obj2.isName("MacRomanEncoding")) {
995 hasEncoding = gTrue;
996 usesMacRomanEnc = gTrue;
997 baseEnc = macRomanEncoding;
998 } else if (obj2.isName("MacExpertEncoding")) {
999 hasEncoding = gTrue;
1000 baseEnc = macExpertEncoding;
1001 } else if (obj2.isName("WinAnsiEncoding")) {
1002 hasEncoding = gTrue;
1003 baseEnc = winAnsiEncoding;
1004 }
1005 obj2.free();
1006 } else if (obj1.isName("MacRomanEncoding")) {
1007 hasEncoding = gTrue;
1008 usesMacRomanEnc = gTrue;
1009 baseEnc = macRomanEncoding;
1010 } else if (obj1.isName("MacExpertEncoding")) {
1011 hasEncoding = gTrue;
1012 baseEnc = macExpertEncoding;
1013 } else if (obj1.isName("WinAnsiEncoding")) {
1014 hasEncoding = gTrue;
1015 baseEnc = winAnsiEncoding;
1016 }
1017
1018 // check embedded font file for base encoding
1019 // (only for Type 1 fonts - trying to get an encoding out of a
1020 // TrueType font is a losing proposition)
1021 ffT1 = NULL;
1022 ffT1C = NULL;
1023 buf = NULL;
1024 if (type == fontType1 && embFontID.num >= 0) {
1025 if ((buf = readEmbFontFile(xref, &len))) {
1026 if ((ffT1 = FoFiType1::make(buf, len))) {
1027 if (ffT1->getName()) {
1028 if (embFontName) {
1029 delete embFontName;
1030 }
1031 embFontName = new GString(ffT1->getName());
1032 }
1033 if (!baseEnc) {
1034 baseEnc = (const char **)ffT1->getEncoding();
1035 baseEncFromFontFile = gTrue;
1036 }
1037 }
1038 gfree(buf);
1039 }
1040 } else if (type == fontType1C && embFontID.num >= 0) {
1041 if ((buf = readEmbFontFile(xref, &len))) {
1042 if ((ffT1C = FoFiType1C::make(buf, len))) {
1043 if (ffT1C->getName()) {
1044 if (embFontName) {
1045 delete embFontName;
1046 }
1047 embFontName = new GString(ffT1C->getName());
1048 }
1049 if (!baseEnc) {
1050 baseEnc = (const char **)ffT1C->getEncoding();
1051 baseEncFromFontFile = gTrue;
1052 }
1053 }
1054 gfree(buf);
1055 }
1056 }
1057
1058 // get default base encoding
1059 if (!baseEnc) {
1060 if (builtinFont && embFontID.num < 0) {
1061 baseEnc = builtinFont->defaultBaseEnc;
1062 hasEncoding = gTrue;
1063 } else if (type == fontTrueType) {
1064 baseEnc = winAnsiEncoding;
1065 } else {
1066 baseEnc = standardEncoding;
1067 }
1068 }
1069
1070 // copy the base encoding
1071 for (i = 0; i < 256; ++i) {
1072 enc[i] = (char *)baseEnc[i];
1073 if ((encFree[i] = baseEncFromFontFile) && enc[i]) {
1074 enc[i] = copyString(baseEnc[i]);
1075 }
1076 }
1077
1078 // some Type 1C font files have empty encodings, which can break the
1079 // T1C->T1 conversion (since the 'seac' operator depends on having
1080 // the accents in the encoding), so we fill in any gaps from
1081 // StandardEncoding
1082 if (type == fontType1C && embFontID.num >= 0 && baseEncFromFontFile) {
1083 for (i = 0; i < 256; ++i) {
1084 if (!enc[i] && standardEncoding[i]) {
1085 enc[i] = (char *)standardEncoding[i];
1086 encFree[i] = gFalse;
1087 }
1088 }
1089 }
1090
1091 // merge differences into encoding
1092 if (obj1.isDict()) {
1093 obj1.dictLookup("Differences", &obj2);
1094 if (obj2.isArray()) {
1095 hasEncoding = gTrue;
1096 code = 0;
1097 for (i = 0; i < obj2.arrayGetLength(); ++i) {
1098 obj2.arrayGet(i, &obj3);
1099 if (obj3.isInt()) {
1100 code = obj3.getInt();
1101 } else if (obj3.isName()) {
1102 if (code >= 0 && code < 256) {
1103 if (encFree[code]) {
1104 gfree(enc[code]);
1105 }
1106 enc[code] = copyString(obj3.getName());
1107 encFree[code] = gTrue;
1108 }
1109 ++code;
1110 } else {
1111 error(errSyntaxError, -1,
1112 "Wrong type in font encoding resource differences ({0:s})",
1113 obj3.getTypeName());
1114 }
1115 obj3.free();
1116 }
1117 }
1118 obj2.free();
1119 }
1120 obj1.free();
1121 if (ffT1) {
1122 delete ffT1;
1123 }
1124 if (ffT1C) {
1125 delete ffT1C;
1126 }
1127
1128 //----- build the mapping to Unicode -----
1129
1130 // pass 1: use the name-to-Unicode mapping table
1131 missing = hex = gFalse;
1132 for (code = 0; code < 256; ++code) {
1133 if ((charName = enc[code])) {
1134 if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) &&
1135 strcmp(charName, ".notdef")) {
1136 // if it wasn't in the name-to-Unicode table, check for a
1137 // name that looks like 'Axx' or 'xx', where 'A' is any letter
1138 // and 'xx' is two hex digits
1139 if ((strlen(charName) == 3 &&
1140 isalpha(charName[0]) &&
1141 isxdigit(charName[1]) && isxdigit(charName[2]) &&
1142 ((charName[1] >= 'a' && charName[1] <= 'f') ||
1143 (charName[1] >= 'A' && charName[1] <= 'F') ||
1144 (charName[2] >= 'a' && charName[2] <= 'f') ||
1145 (charName[2] >= 'A' && charName[2] <= 'F'))) ||
1146 (strlen(charName) == 2 &&
1147 isxdigit(charName[0]) && isxdigit(charName[1]) &&
1148 ((charName[0] >= 'a' && charName[0] <= 'f') ||
1149 (charName[0] >= 'A' && charName[0] <= 'F') ||
1150 (charName[1] >= 'a' && charName[1] <= 'f') ||
1151 (charName[1] >= 'A' && charName[1] <= 'F')))) {
1152 hex = gTrue;
1153 }
1154 missing = gTrue;
1155 }
1156 } else {
1157 toUnicode[code] = 0;
1158 }
1159 }
1160
1161 // pass 2: try to fill in the missing chars, looking for names of
1162 // any of the following forms:
1163 // - 'xx'
1164 // - 'Axx'
1165 // - 'nn'
1166 // - 'Ann'
1167 // - 'ABnn'
1168 // - 'unixxxx' (possibly followed by garbage - some Arabic files
1169 // use 'uni0628.medi', etc.)
1170 // where 'A' and 'B' are any letters, 'xx' is two hex digits, 'xxxx'
1171 // is four hex digits, and 'nn' is 2-4 decimal digits
1172 if (missing && globalParams->getMapNumericCharNames()) {
1173 for (code = 0; code < 256; ++code) {
1174 if ((charName = enc[code]) && !toUnicode[code] &&
1175 strcmp(charName, ".notdef")) {
1176 n = (int)strlen(charName);
1177 code2 = -1;
1178 if (hex && n == 3 && isalpha(charName[0]) &&
1179 isxdigit(charName[1]) && isxdigit(charName[2])) {
1180 sscanf(charName+1, "%x", &code2);
1181 } else if (hex && n == 2 &&
1182 isxdigit(charName[0]) && isxdigit(charName[1])) {
1183 sscanf(charName, "%x", &code2);
1184 } else if (!hex && n >= 2 && n <= 4 &&
1185 isdigit(charName[0]) && isdigit(charName[1])) {
1186 code2 = atoi(charName);
1187 } else if (n >= 3 && n <= 5 &&
1188 isdigit(charName[1]) && isdigit(charName[2])) {
1189 code2 = atoi(charName+1);
1190 } else if (n >= 4 && n <= 6 &&
1191 isdigit(charName[2]) && isdigit(charName[3])) {
1192 code2 = atoi(charName+2);
1193 } else if (n >= 7 && charName[0] == 'u' && charName[1] == 'n' &&
1194 charName[2] == 'i' &&
1195 isxdigit(charName[3]) && isxdigit(charName[4]) &&
1196 isxdigit(charName[5]) && isxdigit(charName[6])) {
1197 sscanf(charName + 3, "%x", &code2);
1198 }
1199 if (code2 >= 0 && code2 <= 0xffff) {
1200 toUnicode[code] = (Unicode)code2;
1201 }
1202 }
1203 }
1204
1205 // if the 'mapUnknownCharNames' flag is set, do a simple pass-through
1206 // mapping for unknown character names
1207 } else if (missing && globalParams->getMapUnknownCharNames()) {
1208 for (code = 0; code < 256; ++code) {
1209 if (!toUnicode[code]) {
1210 toUnicode[code] = code;
1211 }
1212 }
1213 }
1214
1215 // construct the char code -> Unicode mapping object
1216 ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode);
1217
1218 // merge in a ToUnicode CMap, if there is one -- this overwrites
1219 // existing entries in ctu, i.e., the ToUnicode CMap takes
1220 // precedence, but the other encoding info is allowed to fill in any
1221 // holes
1222 readToUnicodeCMap(fontDict, 8, ctu);
1223
1224 // look for a Unicode-to-Unicode mapping
1225 if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
1226 for (i = 0; i < 256; ++i) {
1227 toUnicode[i] = 0;
1228 }
1229 ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode);
1230 for (i = 0; i < 256; ++i) {
1231 n = ctu->mapToUnicode((CharCode)i, uBuf, 8);
1232 if (n >= 1) {
1233 n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
1234 if (n >= 1) {
1235 ctu2->setMapping((CharCode)i, uBuf, n);
1236 }
1237 }
1238 }
1239 utu->decRefCnt();
1240 delete ctu;
1241 ctu = ctu2;
1242 }
1243
1244 //----- get the character widths -----
1245
1246 // initialize all widths
1247 for (code = 0; code < 256; ++code) {
1248 widths[code] = missingWidth * 0.001;
1249 }
1250
1251 // use widths from font dict, if present
1252 fontDict->lookup("FirstChar", &obj1);
1253 firstChar = obj1.isInt() ? obj1.getInt() : 0;
1254 obj1.free();
1255 if (firstChar < 0 || firstChar > 255) {
1256 firstChar = 0;
1257 }
1258 fontDict->lookup("LastChar", &obj1);
1259 lastChar = obj1.isInt() ? obj1.getInt() : 255;
1260 obj1.free();
1261 if (lastChar < 0 || lastChar > 255) {
1262 lastChar = 255;
1263 }
1264 mul = (type == fontType3) ? fontMat[0] : 0.001;
1265 fontDict->lookup("Widths", &obj1);
1266 if (obj1.isArray()) {
1267 flags |= fontFixedWidth;
1268 if (obj1.arrayGetLength() < lastChar - firstChar + 1) {
1269 lastChar = firstChar + obj1.arrayGetLength() - 1;
1270 }
1271 for (code = firstChar; code <= lastChar; ++code) {
1272 obj1.arrayGet(code - firstChar, &obj2);
1273 if (obj2.isNum()) {
1274 widths[code] = obj2.getNum() * mul;
1275 if (fabs(widths[code] - widths[firstChar]) > 0.00001) {
1276 flags &= ~fontFixedWidth;
1277 }
1278 }
1279 obj2.free();
1280 }
1281
1282 // use widths from built-in font
1283 } else if (builtinFont) {
1284 // this is a kludge for broken PDF files that encode char 32
1285 // as .notdef
1286 if (builtinFont->widths->getWidth("space", &w)) {
1287 widths[32] = 0.001 * w;
1288 }
1289 for (code = 0; code < 256; ++code) {
1290 if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
1291 widths[code] = 0.001 * w;
1292 }
1293 }
1294
1295 // couldn't find widths -- use defaults
1296 } else {
1297 // this is technically an error -- the Widths entry is required
1298 // for all but the Base-14 fonts -- but certain PDF generators
1299 // apparently don't include widths for Arial and TimesNewRoman
1300 if (isFixedWidth()) {
1301 i = 0;
1302 } else if (isSerif()) {
1303 i = 8;
1304 } else {
1305 i = 4;
1306 }
1307 if (isBold()) {
1308 i += 2;
1309 }
1310 if (isItalic()) {
1311 i += 1;
1312 }
1313 builtinFont = builtinFontSubst[i];
1314 // this is a kludge for broken PDF files that encode char 32
1315 // as .notdef
1316 if (builtinFont->widths->getWidth("space", &w)) {
1317 widths[32] = 0.001 * w;
1318 }
1319 for (code = 0; code < 256; ++code) {
1320 if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
1321 widths[code] = 0.001 * w;
1322 }
1323 }
1324 }
1325 obj1.free();
1326
1327 ok = gTrue;
1328 }
1329
~Gfx8BitFont()1330 Gfx8BitFont::~Gfx8BitFont() {
1331 int i;
1332
1333 for (i = 0; i < 256; ++i) {
1334 if (encFree[i] && enc[i]) {
1335 gfree(enc[i]);
1336 }
1337 }
1338 ctu->decRefCnt();
1339 if (charProcs.isDict()) {
1340 charProcs.free();
1341 }
1342 if (resources.isDict()) {
1343 resources.free();
1344 }
1345 }
1346
getNextChar(char * s,int len,CharCode * code,Unicode * u,int uSize,int * uLen,double * dx,double * dy,double * ox,double * oy)1347 int Gfx8BitFont::getNextChar(char *s, int len, CharCode *code,
1348 Unicode *u, int uSize, int *uLen,
1349 double *dx, double *dy, double *ox, double *oy) {
1350 CharCode c;
1351
1352 *code = c = (CharCode)(*s & 0xff);
1353 *uLen = ctu->mapToUnicode(c, u, uSize);
1354 *dx = widths[c];
1355 *dy = *ox = *oy = 0;
1356 return 1;
1357 }
1358
getToUnicode()1359 CharCodeToUnicode *Gfx8BitFont::getToUnicode() {
1360 ctu->incRefCnt();
1361 return ctu;
1362 }
1363
getCodeToGIDMap(FoFiTrueType * ff)1364 int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
1365 int *map;
1366 int cmapPlatform, cmapEncoding;
1367 int unicodeCmap, macRomanCmap, msSymbolCmap, cmap;
1368 GBool useMacRoman, useUnicode;
1369 char *charName;
1370 Unicode u;
1371 int code, i, n;
1372
1373 map = (int *)gmallocn(256, sizeof(int));
1374 for (i = 0; i < 256; ++i) {
1375 map[i] = 0;
1376 }
1377
1378 // To match up with the Adobe-defined behaviour, we choose a cmap
1379 // like this:
1380 // 1. If the PDF font has an encoding:
1381 // 1a. If the PDF font specified MacRomanEncoding and the
1382 // TrueType font has a Macintosh Roman cmap, use it, and
1383 // reverse map the char names through MacRomanEncoding to
1384 // get char codes.
1385 // 1b. If the PDF font is not symbolic or the PDF font is not
1386 // embedded, and the TrueType font has a Microsoft Unicode
1387 // cmap or a non-Microsoft Unicode cmap, use it, and use the
1388 // Unicode indexes, not the char codes.
1389 // 1c. If the PDF font is symbolic and the TrueType font has a
1390 // Microsoft Symbol cmap, use it, and use char codes
1391 // directly (possibly with an offset of 0xf000).
1392 // 1d. If the TrueType font has a Macintosh Roman cmap, use it,
1393 // as in case 1a.
1394 // 2. If the PDF font does not have an encoding or the PDF font is
1395 // symbolic:
1396 // 2a. If the TrueType font has a Macintosh Roman cmap, use it,
1397 // and use char codes directly (possibly with an offset of
1398 // 0xf000).
1399 // 2b. If the TrueType font has a Microsoft Symbol cmap, use it,
1400 // and use char codes directly (possible with an offset of
1401 // 0xf000).
1402 // 3. If none of these rules apply, use the first cmap and hope for
1403 // the best (this shouldn't happen).
1404 unicodeCmap = macRomanCmap = msSymbolCmap = -1;
1405 for (i = 0; i < ff->getNumCmaps(); ++i) {
1406 cmapPlatform = ff->getCmapPlatform(i);
1407 cmapEncoding = ff->getCmapEncoding(i);
1408 if ((cmapPlatform == 3 && cmapEncoding == 1) ||
1409 cmapPlatform == 0) {
1410 unicodeCmap = i;
1411 } else if (cmapPlatform == 1 && cmapEncoding == 0) {
1412 macRomanCmap = i;
1413 } else if (cmapPlatform == 3 && cmapEncoding == 0) {
1414 msSymbolCmap = i;
1415 }
1416 }
1417 cmap = 0;
1418 useMacRoman = gFalse;
1419 useUnicode = gFalse;
1420 if (hasEncoding) {
1421 if (usesMacRomanEnc && macRomanCmap >= 0) {
1422 cmap = macRomanCmap;
1423 useMacRoman = gTrue;
1424 } else if ((!(flags & fontSymbolic) || embFontID.num < 0) &&
1425 unicodeCmap >= 0) {
1426 cmap = unicodeCmap;
1427 useUnicode = gTrue;
1428 } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) {
1429 cmap = msSymbolCmap;
1430 } else if ((flags & fontSymbolic) && macRomanCmap >= 0) {
1431 cmap = macRomanCmap;
1432 } else if (macRomanCmap >= 0) {
1433 cmap = macRomanCmap;
1434 useMacRoman = gTrue;
1435 }
1436 } else {
1437 if (msSymbolCmap >= 0) {
1438 cmap = msSymbolCmap;
1439 } else if (macRomanCmap >= 0) {
1440 cmap = macRomanCmap;
1441 }
1442 }
1443
1444 // reverse map the char names through MacRomanEncoding, then map the
1445 // char codes through the cmap
1446 if (useMacRoman) {
1447 for (i = 0; i < 256; ++i) {
1448 if ((charName = enc[i])) {
1449 if ((code = globalParams->getMacRomanCharCode(charName))) {
1450 map[i] = ff->mapCodeToGID(cmap, code);
1451 }
1452 } else {
1453 map[i] = -1;
1454 }
1455 }
1456
1457 // map Unicode through the cmap
1458 } else if (useUnicode) {
1459 for (i = 0; i < 256; ++i) {
1460 if (((charName = enc[i]) &&
1461 (u = globalParams->mapNameToUnicode(charName))) ||
1462 (n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
1463 map[i] = ff->mapCodeToGID(cmap, u);
1464 } else {
1465 map[i] = -1;
1466 }
1467 }
1468
1469 // map the char codes through the cmap, possibly with an offset of
1470 // 0xf000
1471 } else {
1472 for (i = 0; i < 256; ++i) {
1473 if (!(map[i] = ff->mapCodeToGID(cmap, i))) {
1474 map[i] = ff->mapCodeToGID(cmap, 0xf000 + i);
1475 }
1476 }
1477 }
1478
1479 // try the TrueType 'post' table to handle any unmapped characters
1480 for (i = 0; i < 256; ++i) {
1481 if (map[i] <= 0 && (charName = enc[i])) {
1482 map[i] = ff->mapNameToGID(charName);
1483 }
1484 }
1485
1486 return map;
1487 }
1488
getCharProcs()1489 Dict *Gfx8BitFont::getCharProcs() {
1490 return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL;
1491 }
1492
getCharProc(int code,Object * proc)1493 Object *Gfx8BitFont::getCharProc(int code, Object *proc) {
1494 if (enc[code] && charProcs.isDict()) {
1495 charProcs.dictLookup(enc[code], proc);
1496 } else {
1497 proc->initNull();
1498 }
1499 return proc;
1500 }
1501
getCharProcNF(int code,Object * proc)1502 Object *Gfx8BitFont::getCharProcNF(int code, Object *proc) {
1503 if (enc[code] && charProcs.isDict()) {
1504 charProcs.dictLookupNF(enc[code], proc);
1505 } else {
1506 proc->initNull();
1507 }
1508 return proc;
1509 }
1510
getResources()1511 Dict *Gfx8BitFont::getResources() {
1512 return resources.isDict() ? resources.getDict() : (Dict *)NULL;
1513 }
1514
1515 //------------------------------------------------------------------------
1516 // GfxCIDFont
1517 //------------------------------------------------------------------------
1518
1519 #if HAVE_STD_SORT
1520
1521 struct cmpWidthExcepFunctor {
operator ()cmpWidthExcepFunctor1522 bool operator()(const GfxFontCIDWidthExcep &w1,
1523 const GfxFontCIDWidthExcep &w2) {
1524 return w1.first < w2.first;
1525 }
1526 };
1527
1528 struct cmpWidthExcepVFunctor {
operator ()cmpWidthExcepVFunctor1529 bool operator()(const GfxFontCIDWidthExcepV &w1,
1530 const GfxFontCIDWidthExcepV &w2) {
1531 return w1.first < w2.first;
1532 }
1533 };
1534
1535 #else // HAVE_STD_SORT
1536
cmpWidthExcep(const void * w1,const void * w2)1537 static int CDECL cmpWidthExcep(const void *w1, const void *w2) {
1538 return ((GfxFontCIDWidthExcep *)w1)->first -
1539 ((GfxFontCIDWidthExcep *)w2)->first;
1540 }
1541
cmpWidthExcepV(const void * w1,const void * w2)1542 static int CDECL cmpWidthExcepV(const void *w1, const void *w2) {
1543 return ((GfxFontCIDWidthExcepV *)w1)->first -
1544 ((GfxFontCIDWidthExcepV *)w2)->first;
1545 }
1546
1547 #endif
1548
GfxCIDFont(XRef * xref,char * tagA,Ref idA,GString * nameA,GfxFontType typeA,Ref embFontIDA,Dict * fontDict)1549 GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
1550 GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
1551 GfxFont(tagA, idA, nameA, typeA, embFontIDA)
1552 {
1553 Dict *desFontDict;
1554 Object desFontDictObj;
1555 Object obj1, obj2, obj3, obj4, obj5, obj6;
1556 CharCodeToUnicode *utu;
1557 CharCode c;
1558 Unicode uBuf[8];
1559 int c1, c2;
1560 int excepsSize, i, j, k, n;
1561
1562 ascent = 0.95;
1563 descent = -0.35;
1564 fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
1565 collection = NULL;
1566 cMap = NULL;
1567 ctu = NULL;
1568 ctuUsesCharCode = gTrue;
1569 widths.defWidth = 1.0;
1570 widths.defHeight = -1.0;
1571 widths.defVY = 0.880;
1572 widths.exceps = NULL;
1573 widths.nExceps = 0;
1574 widths.excepsV = NULL;
1575 widths.nExcepsV = 0;
1576 cidToGID = NULL;
1577 cidToGIDLen = 0;
1578
1579 // get the descendant font
1580 if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() ||
1581 obj1.arrayGetLength() == 0) {
1582 error(errSyntaxError, -1,
1583 "Missing or empty DescendantFonts entry in Type 0 font");
1584 obj1.free();
1585 goto err1;
1586 }
1587 if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
1588 error(errSyntaxError, -1, "Bad descendant font in Type 0 font");
1589 goto err2;
1590 }
1591 obj1.free();
1592 desFontDict = desFontDictObj.getDict();
1593
1594 // get info from font descriptor
1595 readFontDescriptor(xref, desFontDict);
1596
1597 //----- encoding info -----
1598
1599 // char collection
1600 if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
1601 error(errSyntaxError, -1,
1602 "Missing CIDSystemInfo dictionary in Type 0 descendant font");
1603 goto err2;
1604 }
1605 obj1.dictLookup("Registry", &obj2);
1606 obj1.dictLookup("Ordering", &obj3);
1607 if (!obj2.isString() || !obj3.isString()) {
1608 error(errSyntaxError, -1,
1609 "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
1610 goto err3;
1611 }
1612 collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
1613 obj3.free();
1614 obj2.free();
1615 obj1.free();
1616
1617 // look for a ToUnicode CMap
1618 if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) {
1619 ctuUsesCharCode = gFalse;
1620
1621 // use an identity mapping for the "Adobe-Identity" and
1622 // "Adobe-UCS" collections
1623 if (!collection->cmp("Adobe-Identity") ||
1624 !collection->cmp("Adobe-UCS")) {
1625 ctu = CharCodeToUnicode::makeIdentityMapping();
1626
1627 // look for a user-supplied .cidToUnicode file
1628 } else if (!(ctu = globalParams->getCIDToUnicode(collection))) {
1629 error(errSyntaxError, -1,
1630 "Unknown character collection '{0:t}'", collection);
1631 }
1632 }
1633
1634 // look for a Unicode-to-Unicode mapping
1635 if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
1636 if (ctu) {
1637 for (c = 0; c < ctu->getLength(); ++c) {
1638 n = ctu->mapToUnicode(c, uBuf, 8);
1639 if (n >= 1) {
1640 n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
1641 if (n >= 1) {
1642 ctu->setMapping(c, uBuf, n);
1643 }
1644 }
1645 }
1646 utu->decRefCnt();
1647 } else {
1648 ctu = utu;
1649 }
1650 }
1651
1652 // encoding (i.e., CMap)
1653 if (fontDict->lookup("Encoding", &obj1)->isNull()) {
1654 error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font");
1655 goto err2;
1656 }
1657 if (!(cMap = CMap::parse(NULL, collection, &obj1))) {
1658 goto err2;
1659 }
1660 obj1.free();
1661
1662 // CIDToGIDMap
1663 // (the PDF spec only allows these for TrueType fonts, but Acrobat
1664 // apparently also allows them for OpenType CFF fonts)
1665 if (type == fontCIDType2 || type == fontCIDType0COT) {
1666 desFontDict->lookup("CIDToGIDMap", &obj1);
1667 if (obj1.isStream()) {
1668 cidToGIDLen = 0;
1669 i = 64;
1670 cidToGID = (int *)gmallocn(i, sizeof(int));
1671 obj1.streamReset();
1672 while ((c1 = obj1.streamGetChar()) != EOF &&
1673 (c2 = obj1.streamGetChar()) != EOF) {
1674 if (cidToGIDLen == i) {
1675 i *= 2;
1676 cidToGID = (int *)greallocn(cidToGID, i, sizeof(int));
1677 }
1678 cidToGID[cidToGIDLen++] = (c1 << 8) + c2;
1679 }
1680 obj1.streamClose();
1681 } else if (!obj1.isName("Identity") && !obj1.isNull()) {
1682 error(errSyntaxError, -1, "Invalid CIDToGIDMap entry in CID font");
1683 }
1684 obj1.free();
1685 }
1686
1687 //----- character metrics -----
1688
1689 // default char width
1690 if (desFontDict->lookup("DW", &obj1)->isInt()) {
1691 widths.defWidth = obj1.getInt() * 0.001;
1692 }
1693 obj1.free();
1694
1695 // char width exceptions
1696 if (desFontDict->lookup("W", &obj1)->isArray()) {
1697 excepsSize = 0;
1698 i = 0;
1699 while (i + 1 < obj1.arrayGetLength()) {
1700 obj1.arrayGet(i, &obj2);
1701 obj1.arrayGet(i + 1, &obj3);
1702 if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) {
1703 if (obj1.arrayGet(i + 2, &obj4)->isNum()) {
1704 if (widths.nExceps == excepsSize) {
1705 excepsSize += 16;
1706 widths.exceps = (GfxFontCIDWidthExcep *)
1707 greallocn(widths.exceps,
1708 excepsSize, sizeof(GfxFontCIDWidthExcep));
1709 }
1710 widths.exceps[widths.nExceps].first = obj2.getInt();
1711 widths.exceps[widths.nExceps].last = obj3.getInt();
1712 widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
1713 ++widths.nExceps;
1714 } else {
1715 error(errSyntaxError, -1, "Bad widths array in Type 0 font");
1716 }
1717 obj4.free();
1718 i += 3;
1719 } else if (obj2.isInt() && obj3.isArray()) {
1720 if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
1721 excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15;
1722 widths.exceps = (GfxFontCIDWidthExcep *)
1723 greallocn(widths.exceps,
1724 excepsSize, sizeof(GfxFontCIDWidthExcep));
1725 }
1726 j = obj2.getInt();
1727 for (k = 0; k < obj3.arrayGetLength(); ++k) {
1728 if (obj3.arrayGet(k, &obj4)->isNum()) {
1729 widths.exceps[widths.nExceps].first = j;
1730 widths.exceps[widths.nExceps].last = j;
1731 widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
1732 ++j;
1733 ++widths.nExceps;
1734 } else {
1735 error(errSyntaxError, -1, "Bad widths array in Type 0 font");
1736 }
1737 obj4.free();
1738 }
1739 i += 2;
1740 } else {
1741 error(errSyntaxError, -1, "Bad widths array in Type 0 font");
1742 ++i;
1743 }
1744 obj3.free();
1745 obj2.free();
1746 }
1747 #if HAVE_STD_SORT
1748 std::sort(widths.exceps, widths.exceps + widths.nExceps,
1749 cmpWidthExcepFunctor());
1750 #else
1751 qsort(widths.exceps, widths.nExceps, sizeof(GfxFontCIDWidthExcep),
1752 &cmpWidthExcep);
1753 #endif
1754 }
1755 obj1.free();
1756
1757 // default metrics for vertical font
1758 if (desFontDict->lookup("DW2", &obj1)->isArray() &&
1759 obj1.arrayGetLength() == 2) {
1760 if (obj1.arrayGet(0, &obj2)->isNum()) {
1761 widths.defVY = obj2.getNum() * 0.001;
1762 }
1763 obj2.free();
1764 if (obj1.arrayGet(1, &obj2)->isNum()) {
1765 widths.defHeight = obj2.getNum() * 0.001;
1766 }
1767 obj2.free();
1768 }
1769 obj1.free();
1770
1771 // char metric exceptions for vertical font
1772 if (desFontDict->lookup("W2", &obj1)->isArray()) {
1773 excepsSize = 0;
1774 i = 0;
1775 while (i + 1 < obj1.arrayGetLength()) {
1776 obj1.arrayGet(i, &obj2);
1777 obj1.arrayGet(i+ 1, &obj3);
1778 if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) {
1779 if (obj1.arrayGet(i + 2, &obj4)->isNum() &&
1780 obj1.arrayGet(i + 3, &obj5)->isNum() &&
1781 obj1.arrayGet(i + 4, &obj6)->isNum()) {
1782 if (widths.nExcepsV == excepsSize) {
1783 excepsSize += 16;
1784 widths.excepsV = (GfxFontCIDWidthExcepV *)
1785 greallocn(widths.excepsV,
1786 excepsSize, sizeof(GfxFontCIDWidthExcepV));
1787 }
1788 widths.excepsV[widths.nExcepsV].first = obj2.getInt();
1789 widths.excepsV[widths.nExcepsV].last = obj3.getInt();
1790 widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
1791 widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001;
1792 widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001;
1793 ++widths.nExcepsV;
1794 } else {
1795 error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
1796 }
1797 obj6.free();
1798 obj5.free();
1799 obj4.free();
1800 i += 5;
1801 } else if (obj2.isInt() && obj3.isArray()) {
1802 if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) {
1803 excepsSize =
1804 (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15;
1805 widths.excepsV = (GfxFontCIDWidthExcepV *)
1806 greallocn(widths.excepsV,
1807 excepsSize, sizeof(GfxFontCIDWidthExcepV));
1808 }
1809 j = obj2.getInt();
1810 for (k = 0; k < obj3.arrayGetLength(); k += 3) {
1811 if (obj3.arrayGet(k, &obj4)->isNum() &&
1812 obj3.arrayGet(k+1, &obj5)->isNum() &&
1813 obj3.arrayGet(k+2, &obj6)->isNum()) {
1814 widths.excepsV[widths.nExcepsV].first = j;
1815 widths.excepsV[widths.nExcepsV].last = j;
1816 widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
1817 widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001;
1818 widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001;
1819 ++j;
1820 ++widths.nExcepsV;
1821 } else {
1822 error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
1823 }
1824 obj6.free();
1825 obj5.free();
1826 obj4.free();
1827 }
1828 i += 2;
1829 } else {
1830 error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
1831 ++i;
1832 }
1833 obj3.free();
1834 obj2.free();
1835 }
1836 #if HAVE_STD_SORT
1837 std::sort(widths.excepsV, widths.excepsV + widths.nExcepsV,
1838 cmpWidthExcepVFunctor());
1839 #else
1840 qsort(widths.excepsV, widths.nExcepsV, sizeof(GfxFontCIDWidthExcepV),
1841 &cmpWidthExcepV);
1842 #endif
1843 }
1844 obj1.free();
1845
1846 desFontDictObj.free();
1847 ok = gTrue;
1848 return;
1849
1850 err3:
1851 obj3.free();
1852 obj2.free();
1853 err2:
1854 obj1.free();
1855 desFontDictObj.free();
1856 err1:
1857 error(errSyntaxError, -1, "Failed to parse font object for '{0:t}'", name);
1858 }
1859
~GfxCIDFont()1860 GfxCIDFont::~GfxCIDFont() {
1861 if (collection) {
1862 delete collection;
1863 }
1864 if (cMap) {
1865 cMap->decRefCnt();
1866 }
1867 if (ctu) {
1868 ctu->decRefCnt();
1869 }
1870 gfree(widths.exceps);
1871 gfree(widths.excepsV);
1872 if (cidToGID) {
1873 gfree(cidToGID);
1874 }
1875 }
1876
getNextChar(char * s,int len,CharCode * code,Unicode * u,int uSize,int * uLen,double * dx,double * dy,double * ox,double * oy)1877 int GfxCIDFont::getNextChar(char *s, int len, CharCode *code,
1878 Unicode *u, int uSize, int *uLen,
1879 double *dx, double *dy, double *ox, double *oy) {
1880 CID cid;
1881 CharCode c;
1882 double w, h, vx, vy;
1883 int n, a, b, m;
1884
1885 if (!cMap) {
1886 *code = 0;
1887 *uLen = 0;
1888 *dx = *dy = 0;
1889 return 1;
1890 }
1891
1892 *code = (CharCode)(cid = cMap->getCID(s, len, &c, &n));
1893 if (ctu) {
1894 *uLen = ctu->mapToUnicode(ctuUsesCharCode ? c : cid, u, uSize);
1895 } else {
1896 *uLen = 0;
1897 }
1898 if (!*uLen && uSize >= 1 && globalParams->getMapUnknownCharNames()) {
1899 u[0] = *code;
1900 *uLen = 1;
1901 }
1902
1903 // horizontal
1904 if (cMap->getWMode() == 0) {
1905 w = widths.defWidth;
1906 h = vx = vy = 0;
1907 if (widths.nExceps > 0 && cid >= widths.exceps[0].first) {
1908 a = 0;
1909 b = widths.nExceps;
1910 // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first
1911 while (b - a > 1) {
1912 m = (a + b) / 2;
1913 if (widths.exceps[m].first <= cid) {
1914 a = m;
1915 } else {
1916 b = m;
1917 }
1918 }
1919 if (cid <= widths.exceps[a].last) {
1920 w = widths.exceps[a].width;
1921 }
1922 }
1923
1924 // vertical
1925 } else {
1926 w = 0;
1927 h = widths.defHeight;
1928 vx = widths.defWidth / 2;
1929 vy = widths.defVY;
1930 if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) {
1931 a = 0;
1932 b = widths.nExcepsV;
1933 // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first
1934 while (b - a > 1) {
1935 m = (a + b) / 2;
1936 if (widths.excepsV[m].last <= cid) {
1937 a = m;
1938 } else {
1939 b = m;
1940 }
1941 }
1942 if (cid <= widths.excepsV[a].last) {
1943 h = widths.excepsV[a].height;
1944 vx = widths.excepsV[a].vx;
1945 vy = widths.excepsV[a].vy;
1946 }
1947 }
1948 }
1949
1950 *dx = w;
1951 *dy = h;
1952 *ox = vx;
1953 *oy = vy;
1954
1955 return n;
1956 }
1957
getWMode()1958 int GfxCIDFont::getWMode() {
1959 return cMap ? cMap->getWMode() : 0;
1960 }
1961
getToUnicode()1962 CharCodeToUnicode *GfxCIDFont::getToUnicode() {
1963 if (ctu) {
1964 ctu->incRefCnt();
1965 }
1966 return ctu;
1967 }
1968
getCollection()1969 GString *GfxCIDFont::getCollection() {
1970 return cMap ? cMap->getCollection() : (GString *)NULL;
1971 }
1972
1973 //------------------------------------------------------------------------
1974 // GfxFontDict
1975 //------------------------------------------------------------------------
1976
GfxFontDict(XRef * xref,Ref * fontDictRef,Dict * fontDict)1977 GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) {
1978 int i;
1979 Object obj1, obj2;
1980 Ref r;
1981
1982 numFonts = fontDict->getLength();
1983 fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *));
1984 for (i = 0; i < numFonts; ++i) {
1985 fontDict->getValNF(i, &obj1);
1986 obj1.fetch(xref, &obj2);
1987 if (obj2.isDict()) {
1988 if (obj1.isRef()) {
1989 r = obj1.getRef();
1990 } else {
1991 // no indirect reference for this font, so invent a unique one
1992 // (legal generation numbers are five digits, so any 6-digit
1993 // number would be safe)
1994 r.num = i;
1995 if (fontDictRef) {
1996 r.gen = 100000 + fontDictRef->num;
1997 } else {
1998 r.gen = 999999;
1999 }
2000 }
2001 fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i),
2002 r, obj2.getDict());
2003 if (fonts[i] && !fonts[i]->isOk()) {
2004 delete fonts[i];
2005 fonts[i] = NULL;
2006 }
2007 } else {
2008 error(errSyntaxError, -1, "font resource is not a dictionary");
2009 fonts[i] = NULL;
2010 }
2011 obj1.free();
2012 obj2.free();
2013 }
2014 }
2015
~GfxFontDict()2016 GfxFontDict::~GfxFontDict() {
2017 int i;
2018
2019 for (i = 0; i < numFonts; ++i) {
2020 if (fonts[i]) {
2021 delete fonts[i];
2022 }
2023 }
2024 gfree(fonts);
2025 }
2026
lookup(char * tag)2027 GfxFont *GfxFontDict::lookup(char *tag) {
2028 int i;
2029
2030 for (i = 0; i < numFonts; ++i) {
2031 if (fonts[i] && fonts[i]->matches(tag)) {
2032 return fonts[i];
2033 }
2034 }
2035 return NULL;
2036 }
2037
lookupByRef(Ref ref)2038 GfxFont *GfxFontDict::lookupByRef(Ref ref) {
2039 int i;
2040
2041 for (i = 0; i < numFonts; ++i) {
2042 if (fonts[i] &&
2043 fonts[i]->getID()->num == ref.num &&
2044 fonts[i]->getID()->gen == ref.gen) {
2045 return fonts[i];
2046 }
2047 }
2048 return NULL;
2049 }
2050