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