source: trunk/poppler/mypoppler/poppler/GfxFont.cc @ 257

Last change on this file since 257 was 257, checked in by Eugene Romanenko, 13 years ago

PDF plugin: Poppler library updated to version 0.10.0

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