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

Last change on this file since 27 was 27, checked in by Eugene Romanenko, 16 years ago

poppler updated to version 0.5.2, also needed changes to be compatible with new poppler

File size: 45.0 KB
Line 
1//========================================================================
2//
3// GfxFont.cc
4//
5// Copyright 1996-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9#include <config.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 "goo/gmem.h"
20#include "Error.h"
21#include "Object.h"
22#include "Dict.h"
23#include "GlobalParams.h"
24#include "CMap.h"
25#include "CharCodeToUnicode.h"
26#include "FontEncodingTables.h"
27#include "BuiltinFontTables.h"
28#include <fofi/FoFiType1.h>
29#include <fofi/FoFiType1C.h>
30#include <fofi/FoFiTrueType.h>
31#include "UGooString.h"
32#include "GfxFont.h"
33
34//------------------------------------------------------------------------
35
36struct StdFontMapEntry {
37  char *altName;
38  char *properName;
39};
40
41// Acrobat 4.0 and earlier substituted Base14-compatible fonts without
42// providing Widths and a FontDescriptor, so we munge the names into
43// the proper Base14 names.  This table is from implementation note 44
44// in the PDF 1.4 spec, with some additions based on empirical
45// evidence.
46static StdFontMapEntry stdFontMap[] = {
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,Bold",                 "Courier-Bold" },
59  { "Courier,BoldItalic",           "Courier-BoldOblique" },
60  { "Courier,Italic",               "Courier-Oblique" },
61  { "CourierNew",                   "Courier" },
62  { "CourierNew,Bold",              "Courier-Bold" },
63  { "CourierNew,BoldItalic",        "Courier-BoldOblique" },
64  { "CourierNew,Italic",            "Courier-Oblique" },
65  { "CourierNew-Bold",              "Courier-Bold" },
66  { "CourierNew-BoldItalic",        "Courier-BoldOblique" },
67  { "CourierNew-Italic",            "Courier-Oblique" },
68  { "CourierNewPS-BoldItalicMT",    "Courier-BoldOblique" },
69  { "CourierNewPS-BoldMT",          "Courier-Bold" },
70  { "CourierNewPS-ItalicMT",        "Courier-Oblique" },
71  { "CourierNewPSMT",               "Courier" },
72  { "Helvetica,Bold",               "Helvetica-Bold" },
73  { "Helvetica,BoldItalic",         "Helvetica-BoldOblique" },
74  { "Helvetica,Italic",             "Helvetica-Oblique" },
75  { "Helvetica-BoldItalic",         "Helvetica-BoldOblique" },
76  { "Helvetica-Italic",             "Helvetica-Oblique" },
77  { "Symbol,Bold",                  "Symbol" },
78  { "Symbol,BoldItalic",            "Symbol" },
79  { "Symbol,Italic",                "Symbol" },
80  { "TimesNewRoman",                "Times-Roman" },
81  { "TimesNewRoman,Bold",           "Times-Bold" },
82  { "TimesNewRoman,BoldItalic",     "Times-BoldItalic" },
83  { "TimesNewRoman,Italic",         "Times-Italic" },
84  { "TimesNewRoman-Bold",           "Times-Bold" },
85  { "TimesNewRoman-BoldItalic",     "Times-BoldItalic" },
86  { "TimesNewRoman-Italic",         "Times-Italic" },
87  { "TimesNewRomanPS",              "Times-Roman" },
88  { "TimesNewRomanPS-Bold",         "Times-Bold" },
89  { "TimesNewRomanPS-BoldItalic",   "Times-BoldItalic" },
90  { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" },
91  { "TimesNewRomanPS-BoldMT",       "Times-Bold" },
92  { "TimesNewRomanPS-Italic",       "Times-Italic" },
93  { "TimesNewRomanPS-ItalicMT",     "Times-Italic" },
94  { "TimesNewRomanPSMT",            "Times-Roman" },
95  { "TimesNewRomanPSMT,Bold",       "Times-Bold" },
96  { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" },
97  { "TimesNewRomanPSMT,Italic",     "Times-Italic" }
98};
99
100//------------------------------------------------------------------------
101// GfxFont
102//------------------------------------------------------------------------
103
104GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) {
105  GooString *nameA;
106  GfxFont *font;
107  Object obj1;
108
109  // get base font name
110  nameA = NULL;
111  fontDict->lookup("BaseFont", &obj1);
112  if (obj1.isName()) {
113    nameA = new GooString(obj1.getName());
114  }
115  obj1.free();
116
117  // get font type
118  font = NULL;
119  fontDict->lookup("Subtype", &obj1);
120  if (obj1.isName("Type1") || obj1.isName("MMType1")) {
121    font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict);
122  } else if (obj1.isName("Type1C")) {
123    font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict);
124  } else if (obj1.isName("Type3")) {
125    font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict);
126  } else if (obj1.isName("TrueType")) {
127    font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict);
128  } else if (obj1.isName("Type0")) {
129    font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict);
130  } else {
131    error(-1, "Unknown font type: '%s'",
132          obj1.isName() ? obj1.getName() : "???");
133    font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict);
134  }
135  obj1.free();
136
137  return font;
138}
139
140GfxFont::GfxFont(char *tagA, Ref idA, GooString *nameA) {
141  ok = gFalse;
142  tag = new GooString(tagA);
143  id = idA;
144  name = nameA;
145  origName = nameA;
146  embFontName = NULL;
147  extFontFile = NULL;
148  family = NULL;
149  stretch = StretchNotDefined;
150  weight = WeightNotDefined;
151  refCnt = 1;
152}
153
154GfxFont::~GfxFont() {
155  delete tag;
156  delete family;
157  if (origName && origName != name) {
158    delete origName;
159  }
160  if (name) {
161    delete name;
162  }
163  if (embFontName) {
164    delete embFontName;
165  }
166  if (extFontFile) {
167    delete extFontFile;
168  }
169}
170
171void GfxFont::incRefCnt() {
172  refCnt++;
173}
174
175void GfxFont::decRefCnt() {
176  if (--refCnt == 0)
177    delete this;
178}
179
180void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
181  Object obj1, obj2, obj3, obj4;
182  double t;
183  int i;
184
185  // assume Times-Roman by default (for substitution purposes)
186  flags = fontSerif;
187
188  embFontID.num = -1;
189  embFontID.gen = -1;
190  missingWidth = 0;
191
192  if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
193
194    // get flags
195    if (obj1.dictLookup("Flags", &obj2)->isInt()) {
196      flags = obj2.getInt();
197    }
198    obj2.free();
199
200    // get name
201    obj1.dictLookup("FontName", &obj2);
202    if (obj2.isName()) {
203      embFontName = new GooString(obj2.getName());
204    }
205    obj2.free();
206
207    // get family
208    obj1.dictLookup("FontFamily", &obj2);
209    if (obj2.isString()) family = new GooString(obj2.getString());
210    obj2.free();
211
212    // get stretch
213    obj1.dictLookup("FontStretch", &obj2);
214    if (obj2.isName()) {
215      if (strcmp(obj2.getName(), "UltraCondensed") == 0) stretch = UltraCondensed;
216      else if (strcmp(obj2.getName(), "ExtraCondensed") == 0) stretch = ExtraCondensed;
217      else if (strcmp(obj2.getName(), "Condensed") == 0) stretch = Condensed;
218      else if (strcmp(obj2.getName(), "SemiCondensed") == 0) stretch = SemiCondensed;
219      else if (strcmp(obj2.getName(), "Normal") == 0) stretch = Normal;
220      else if (strcmp(obj2.getName(), "SemiExpanded") == 0) stretch = SemiExpanded;
221      else if (strcmp(obj2.getName(), "Expanded") == 0) stretch = Expanded;
222      else if (strcmp(obj2.getName(), "ExtraExpanded") == 0) stretch = ExtraExpanded;
223      else if (strcmp(obj2.getName(), "UltraExpanded") == 0) stretch = UltraExpanded;
224      else error(-1, "Invalid Font Stretch");
225    }
226    obj2.free();
227   
228    // get weight
229    obj1.dictLookup("FontWeight", &obj2);
230    if (obj2.isNum()) {
231      if (obj2.getNum() == 100) weight = W100;
232      else if (obj2.getNum() == 200) weight = W200;
233      else if (obj2.getNum() == 300) weight = W300;
234      else if (obj2.getNum() == 400) weight = W400;
235      else if (obj2.getNum() == 500) weight = W500;
236      else if (obj2.getNum() == 600) weight = W600;
237      else if (obj2.getNum() == 700) weight = W700;
238      else if (obj2.getNum() == 800) weight = W800;
239      else if (obj2.getNum() == 900) weight = W900;
240      else error(-1, "Invalid Font Weight");
241    }
242    obj2.free();
243
244    // look for embedded font file
245    if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) {
246      embFontID = obj2.getRef();
247      if (type != fontType1) {
248        error(-1, "Mismatch between font type and embedded font file");
249        type = fontType1;
250      }
251    }
252    obj2.free();
253    if (embFontID.num == -1 &&
254        obj1.dictLookupNF("FontFile2", &obj2)->isRef()) {
255      embFontID = obj2.getRef();
256      if (type != fontTrueType && type != fontCIDType2) {
257        error(-1, "Mismatch between font type and embedded font file");
258        type = type == fontCIDType0 ? fontCIDType2 : fontTrueType;
259      }
260    }
261    obj2.free();
262    if (embFontID.num == -1 &&
263        obj1.dictLookupNF("FontFile3", &obj2)->isRef()) {
264      if (obj2.fetch(xref, &obj3)->isStream()) {
265        obj3.streamGetDict()->lookup("Subtype", &obj4);
266        if (obj4.isName("Type1")) {
267            embFontID = obj2.getRef();
268          if (type != fontType1) {
269            error(-1, "Mismatch between font type and embedded font file");
270            type = fontType1;
271          }
272        } else if (obj4.isName("Type1C")) {
273            embFontID = obj2.getRef();
274          if (type != fontType1 && type != fontType1C) {
275            error(-1, "Mismatch between font type and embedded font file");
276          }
277          type = fontType1C;
278        } else if (obj4.isName("TrueType")) {
279            embFontID = obj2.getRef();
280          if (type != fontTrueType) {
281            error(-1, "Mismatch between font type and embedded font file");
282            type = fontTrueType;
283          }
284        } else if (obj4.isName("CIDFontType0C")) {
285            embFontID = obj2.getRef();
286          if (type != fontCIDType0) {
287            error(-1, "Mismatch between font type and embedded font file");
288          }
289          type = fontCIDType0C;
290        } else {
291          error(-1, "Unknown embedded font type '%s'",
292                obj4.isName() ? obj4.getName() : "???");
293        }
294        obj4.free();
295      }
296      obj3.free();
297    }
298    obj2.free();
299
300    // look for MissingWidth
301    obj1.dictLookup("MissingWidth", &obj2);
302    if (obj2.isNum()) {
303      missingWidth = obj2.getNum();
304    }
305    obj2.free();
306
307    // get Ascent and Descent
308    obj1.dictLookup("Ascent", &obj2);
309    if (obj2.isNum()) {
310      t = 0.001 * obj2.getNum();
311      // some broken font descriptors set ascent and descent to 0
312      if (t != 0) {
313        ascent = t;
314      }
315    }
316    obj2.free();
317    obj1.dictLookup("Descent", &obj2);
318    if (obj2.isNum()) {
319      t = 0.001 * obj2.getNum();
320      // some broken font descriptors set ascent and descent to 0
321      if (t != 0) {
322        descent = t;
323      }
324      // some broken font descriptors specify a positive descent
325      if (descent > 0) {
326        descent = -descent;
327      }
328    }
329    obj2.free();
330
331    // font FontBBox
332    if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
333      for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
334        if (obj2.arrayGet(i, &obj3)->isNum()) {
335          fontBBox[i] = 0.001 * obj3.getNum();
336        }
337        obj3.free();
338      }
339    }
340    obj2.free();
341
342  }
343  obj1.free();
344}
345
346CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
347                                              CharCodeToUnicode *ctu) {
348  GooString *buf;
349  Object obj1;
350  int c;
351
352  if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) {
353    obj1.free();
354    return NULL;
355  }
356  buf = new GooString();
357  obj1.streamReset();
358  while ((c = obj1.streamGetChar()) != EOF) {
359    buf->append(c);
360  }
361  obj1.streamClose();
362  obj1.free();
363  if (ctu) {
364    ctu->mergeCMap(buf, nBits);
365  } else {
366    ctu = CharCodeToUnicode::parseCMap(buf, nBits);
367  }
368  delete buf;
369  return ctu;
370}
371
372void GfxFont::findExtFontFile() {
373  static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL };
374  static char *ttExts[] = { ".ttf", ".ttc", NULL };
375
376  if (name) {
377    if (type == fontType1) {
378      extFontFile = globalParams->findFontFile(name, type1Exts);
379    } else if (type == fontTrueType) {
380      extFontFile = globalParams->findFontFile(name, ttExts);
381    }
382  }
383}
384
385char *GfxFont::readExtFontFile(int *len) {
386  FILE *f;
387  char *buf;
388
389  if (!(f = fopen(extFontFile->getCString(), "rb"))) {
390    error(-1, "External font file '%s' vanished", extFontFile->getCString());
391    return NULL;
392  }
393  fseek(f, 0, SEEK_END);
394  *len = (int)ftell(f);
395  fseek(f, 0, SEEK_SET);
396  buf = (char *)gmalloc(*len);
397  if ((int)fread(buf, 1, *len, f) != *len) {
398    error(-1, "Error reading external font file '%s'",
399          extFontFile->getCString());
400  }
401  fclose(f);
402  return buf;
403}
404
405char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
406  char *buf;
407  Object obj1, obj2;
408  Stream *str;
409  int c;
410  int size, i;
411
412  obj1.initRef(embFontID.num, embFontID.gen);
413  obj1.fetch(xref, &obj2);
414  if (!obj2.isStream()) {
415    error(-1, "Embedded font file is not a stream");
416    obj2.free();
417    obj1.free();
418    embFontID.num = -1;
419    return NULL;
420  }
421  str = obj2.getStream();
422
423  buf = NULL;
424  i = size = 0;
425  str->reset();
426  while ((c = str->getChar()) != EOF) {
427    if (i == size) {
428      size += 4096;
429      buf = (char *)grealloc(buf, size);
430    }
431    buf[i++] = c;
432  }
433  *len = i;
434  str->close();
435
436  obj2.free();
437  obj1.free();
438
439  return buf;
440}
441
442//------------------------------------------------------------------------
443// Gfx8BitFont
444//------------------------------------------------------------------------
445
446Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GooString *nameA,
447                         GfxFontType typeA, Dict *fontDict):
448  GfxFont(tagA, idA, nameA)
449{
450  GooString *name2;
451  BuiltinFont *builtinFont;
452  char **baseEnc;
453  GBool baseEncFromFontFile;
454  char *buf;
455  int len;
456  FoFiType1 *ffT1;
457  FoFiType1C *ffT1C;
458  int code, code2;
459  char *charName;
460  GBool missing, hex;
461  Unicode toUnicode[256];
462  CharCodeToUnicode *utu, *ctu2;
463  Unicode uBuf[8];
464  double mul;
465  int firstChar, lastChar;
466  Gushort w;
467  Object obj1, obj2, obj3;
468  int n, i, a, b, m;
469
470  refCnt = 1;
471  type = typeA;
472  ctu = NULL;
473
474  // do font name substitution for various aliases of the Base 14 font
475  // names
476  if (name) {
477    name2 = name->copy();
478    i = 0;
479    while (i < name2->getLength()) {
480      if (name2->getChar(i) == ' ') {
481        name2->del(i);
482      } else {
483        ++i;
484      }
485    }
486    a = 0;
487    b = sizeof(stdFontMap) / sizeof(StdFontMapEntry);
488    // invariant: stdFontMap[a].altName <= name2 < stdFontMap[b].altName
489    while (b - a > 1) {
490      m = (a + b) / 2;
491      if (name2->cmp(stdFontMap[m].altName) >= 0) {
492        a = m;
493      } else {
494        b = m;
495      }
496    }
497    if (!name2->cmp(stdFontMap[a].altName)) {
498      name = new GooString(stdFontMap[a].properName);
499    }
500    delete name2;
501  }
502
503  // is it a built-in font?
504  builtinFont = NULL;
505  if (name) {
506    for (i = 0; i < nBuiltinFonts; ++i) {
507      if (!name->cmp(builtinFonts[i].name)) {
508        builtinFont = &builtinFonts[i];
509        break;
510      }
511    }
512  }
513
514  // default ascent/descent values
515  if (builtinFont) {
516    ascent = 0.001 * builtinFont->ascent;
517    descent = 0.001 * builtinFont->descent;
518    fontBBox[0] = 0.001 * builtinFont->bbox[0];
519    fontBBox[1] = 0.001 * builtinFont->bbox[1];
520    fontBBox[2] = 0.001 * builtinFont->bbox[2];
521    fontBBox[3] = 0.001 * builtinFont->bbox[3];
522  } else {
523    ascent = 0.95;
524    descent = -0.35;
525    fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
526  }
527
528  // get info from font descriptor
529  readFontDescriptor(xref, fontDict);
530
531  // for non-embedded fonts, don't trust the ascent/descent/bbox
532  // values from the font descriptor
533  if (builtinFont && embFontID.num < 0) {
534    ascent = 0.001 * builtinFont->ascent;
535    descent = 0.001 * builtinFont->descent;
536    fontBBox[0] = 0.001 * builtinFont->bbox[0];
537    fontBBox[1] = 0.001 * builtinFont->bbox[1];
538    fontBBox[2] = 0.001 * builtinFont->bbox[2];
539    fontBBox[3] = 0.001 * builtinFont->bbox[3];
540  }
541
542  // look for an external font file
543  findExtFontFile();
544
545  // get font matrix
546  fontMat[0] = fontMat[3] = 1;
547  fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
548  if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
549    for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
550      if (obj1.arrayGet(i, &obj2)->isNum()) {
551        fontMat[i] = obj2.getNum();
552      }
553      obj2.free();
554    }
555  }
556  obj1.free();
557
558  // get Type 3 bounding box, font definition, and resources
559  if (type == fontType3) {
560    if (fontDict->lookup("FontBBox", &obj1)->isArray()) {
561      for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) {
562        if (obj1.arrayGet(i, &obj2)->isNum()) {
563          fontBBox[i] = obj2.getNum();
564        }
565        obj2.free();
566      }
567    }
568    obj1.free();
569    if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) {
570      error(-1, "Missing or invalid CharProcs dictionary in Type 3 font");
571      charProcs.free();
572    }
573    if (!fontDict->lookup("Resources", &resources)->isDict()) {
574      resources.free();
575    }
576  }
577
578  //----- build the font encoding -----
579
580  // Encodings start with a base encoding, which can come from
581  // (in order of priority):
582  //   1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
583  //        - MacRoman / MacExpert / WinAnsi / Standard
584  //   2. embedded or external font file
585  //   3. default:
586  //        - builtin --> builtin encoding
587  //        - TrueType --> WinAnsiEncoding
588  //        - others --> StandardEncoding
589  // and then add a list of differences (if any) from
590  // FontDict.Encoding.Differences.
591
592  // check FontDict for base encoding
593  hasEncoding = gFalse;
594  usesMacRomanEnc = gFalse;
595  baseEnc = NULL;
596  baseEncFromFontFile = gFalse;
597  fontDict->lookup("Encoding", &obj1);
598  if (obj1.isDict()) {
599    obj1.dictLookup("BaseEncoding", &obj2);
600    if (obj2.isName("MacRomanEncoding")) {
601      hasEncoding = gTrue;
602      usesMacRomanEnc = gTrue;
603      baseEnc = macRomanEncoding;
604    } else if (obj2.isName("MacExpertEncoding")) {
605      hasEncoding = gTrue;
606      baseEnc = macExpertEncoding;
607    } else if (obj2.isName("WinAnsiEncoding")) {
608      hasEncoding = gTrue;
609      baseEnc = winAnsiEncoding;
610    }
611    obj2.free();
612  } else if (obj1.isName("MacRomanEncoding")) {
613    hasEncoding = gTrue;
614    usesMacRomanEnc = gTrue;
615    baseEnc = macRomanEncoding;
616  } else if (obj1.isName("MacExpertEncoding")) {
617    hasEncoding = gTrue;
618    baseEnc = macExpertEncoding;
619  } else if (obj1.isName("WinAnsiEncoding")) {
620    hasEncoding = gTrue;
621    baseEnc = winAnsiEncoding;
622  }
623
624  // check embedded or external font file for base encoding
625  // (only for Type 1 fonts - trying to get an encoding out of a
626  // TrueType font is a losing proposition)
627  ffT1 = NULL;
628  ffT1C = NULL;
629  buf = NULL;
630  if (type == fontType1 && (extFontFile || embFontID.num >= 0)) {
631    if (extFontFile) {
632      ffT1 = FoFiType1::load(extFontFile->getCString());
633    } else {
634      buf = readEmbFontFile(xref, &len);
635      ffT1 = FoFiType1::make(buf, len);
636    }
637    if (ffT1) {
638      if (ffT1->getName()) {
639        if (embFontName) {
640          delete embFontName;
641        }
642        embFontName = new GooString(ffT1->getName());
643      }
644      if (!baseEnc) {
645        baseEnc = ffT1->getEncoding();
646        baseEncFromFontFile = gTrue;
647      }
648    }
649  } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) {
650    if (extFontFile) {
651      ffT1C = FoFiType1C::load(extFontFile->getCString());
652    } else {
653      buf = readEmbFontFile(xref, &len);
654      ffT1C = FoFiType1C::make(buf, len);
655    }
656    if (ffT1C) {
657      if (ffT1C->getName()) {
658        if (embFontName) {
659          delete embFontName;
660        }
661        embFontName = new GooString(ffT1C->getName());
662      }
663      if (!baseEnc) {
664        baseEnc = ffT1C->getEncoding();
665        baseEncFromFontFile = gTrue;
666      }
667    }
668  }
669  if (buf) {
670    gfree(buf);
671  }
672
673  // get default base encoding
674  if (!baseEnc) {
675    if (builtinFont && embFontID.num < 0) {
676      baseEnc = builtinFont->defaultBaseEnc;
677      hasEncoding = gTrue;
678    } else if (type == fontTrueType) {
679      baseEnc = winAnsiEncoding;
680    } else {
681      baseEnc = standardEncoding;
682    }
683  }
684
685  // copy the base encoding
686  for (i = 0; i < 256; ++i) {
687    enc[i] = baseEnc[i];
688    if ((encFree[i] = baseEncFromFontFile) && enc[i]) {
689      enc[i] = copyString(baseEnc[i]);
690    }
691  }
692
693  // some Type 1C font files have empty encodings, which can break the
694  // T1C->T1 conversion (since the 'seac' operator depends on having
695  // the accents in the encoding), so we fill in any gaps from
696  // StandardEncoding
697  if (type == fontType1C && (extFontFile || embFontID.num >= 0) &&
698      baseEncFromFontFile) {
699    for (i = 0; i < 256; ++i) {
700      if (!enc[i] && standardEncoding[i]) {
701        enc[i] = standardEncoding[i];
702        encFree[i] = gFalse;
703      }
704    }
705  }
706
707  // merge differences into encoding
708  if (obj1.isDict()) {
709    obj1.dictLookup("Differences", &obj2);
710    if (obj2.isArray()) {
711      hasEncoding = gTrue;
712      code = 0;
713      for (i = 0; i < obj2.arrayGetLength(); ++i) {
714        obj2.arrayGet(i, &obj3);
715        if (obj3.isInt()) {
716          code = obj3.getInt();
717        } else if (obj3.isName()) {
718          if (code >= 0 && code < 256) {
719            if (encFree[code]) {
720              gfree(enc[code]);
721            }
722            enc[code] = copyString(obj3.getName());
723            encFree[code] = gTrue;
724          }
725          ++code;
726        } else {
727          error(-1, "Wrong type in font encoding resource differences (%s)",
728                obj3.getTypeName());
729        }
730        obj3.free();
731      }
732    }
733    obj2.free();
734  }
735  obj1.free();
736  if (ffT1) {
737    delete ffT1;
738  }
739  if (ffT1C) {
740    delete ffT1C;
741  }
742
743  //----- build the mapping to Unicode -----
744
745  // pass 1: use the name-to-Unicode mapping table
746  missing = hex = gFalse;
747  for (code = 0; code < 256; ++code) {
748    if ((charName = enc[code])) {
749      if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) &&
750          strcmp(charName, ".notdef")) {
751        // if it wasn't in the name-to-Unicode table, check for a
752        // name that looks like 'Axx' or 'xx', where 'A' is any letter
753        // and 'xx' is two hex digits
754        if ((strlen(charName) == 3 &&
755             isalpha(charName[0]) &&
756             isxdigit(charName[1]) && isxdigit(charName[2]) &&
757             ((charName[1] >= 'a' && charName[1] <= 'f') ||
758              (charName[1] >= 'A' && charName[1] <= 'F') ||
759              (charName[2] >= 'a' && charName[2] <= 'f') ||
760              (charName[2] >= 'A' && charName[2] <= 'F'))) ||
761            (strlen(charName) == 2 &&
762             isxdigit(charName[0]) && isxdigit(charName[1]) &&
763             ((charName[0] >= 'a' && charName[0] <= 'f') ||
764              (charName[0] >= 'A' && charName[0] <= 'F') ||
765              (charName[1] >= 'a' && charName[1] <= 'f') ||
766              (charName[1] >= 'A' && charName[1] <= 'F')))) {
767          hex = gTrue;
768        }
769        missing = gTrue;
770      }
771    } else {
772      toUnicode[code] = 0;
773    }
774  }
775
776  // pass 2: try to fill in the missing chars, looking for names of
777  // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B'
778  // are any letters, 'xx' is two hex digits, and 'nn' is 2-4
779  // decimal digits
780  if (missing && globalParams->getMapNumericCharNames()) {
781    for (code = 0; code < 256; ++code) {
782      if ((charName = enc[code]) && !toUnicode[code] &&
783          strcmp(charName, ".notdef")) {
784        n = strlen(charName);
785        code2 = -1;
786        if (hex && n == 3 && isalpha(charName[0]) &&
787            isxdigit(charName[1]) && isxdigit(charName[2])) {
788          sscanf(charName+1, "%x", &code2);
789        } else if (hex && n == 2 &&
790                   isxdigit(charName[0]) && isxdigit(charName[1])) {
791          sscanf(charName, "%x", &code2);
792        } else if (!hex && n >= 2 && n <= 4 &&
793                   isdigit(charName[0]) && isdigit(charName[1])) {
794          code2 = atoi(charName);
795        } else if (n >= 3 && n <= 5 &&
796                   isdigit(charName[1]) && isdigit(charName[2])) {
797          code2 = atoi(charName+1);
798        } else if (n >= 4 && n <= 6 &&
799                   isdigit(charName[2]) && isdigit(charName[3])) {
800          code2 = atoi(charName+2);
801        }
802        if (code2 >= 0 && code2 <= 0xff) {
803          toUnicode[code] = (Unicode)code2;
804        }
805      }
806    }
807  }
808
809  // construct the char code -> Unicode mapping object
810  ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode);
811
812  // merge in a ToUnicode CMap, if there is one -- this overwrites
813  // existing entries in ctu, i.e., the ToUnicode CMap takes
814  // precedence, but the other encoding info is allowed to fill in any
815  // holes
816  readToUnicodeCMap(fontDict, 8, ctu);
817
818  // look for a Unicode-to-Unicode mapping
819  if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
820    for (i = 0; i < 256; ++i) {
821      toUnicode[i] = 0;
822    }
823    ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode);
824    for (i = 0; i < 256; ++i) {
825      n = ctu->mapToUnicode((CharCode)i, uBuf, 8);
826      if (n >= 1) {
827        n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
828        if (n >= 1) {
829          ctu2->setMapping((CharCode)i, uBuf, n);
830        }
831      }
832    }
833    utu->decRefCnt();
834    delete ctu;
835    ctu = ctu2;
836  }
837
838  //----- get the character widths -----
839
840  // initialize all widths
841  for (code = 0; code < 256; ++code) {
842    widths[code] = missingWidth * 0.001;
843  }
844
845  // use widths from font dict, if present
846  fontDict->lookup("FirstChar", &obj1);
847  firstChar = obj1.isInt() ? obj1.getInt() : 0;
848  obj1.free();
849  if (firstChar < 0 || firstChar > 255) {
850    firstChar = 0;
851  }
852  fontDict->lookup("LastChar", &obj1);
853  lastChar = obj1.isInt() ? obj1.getInt() : 255;
854  obj1.free();
855  if (lastChar < 0 || lastChar > 255) {
856    lastChar = 255;
857  }
858  mul = (type == fontType3) ? fontMat[0] : 0.001;
859  fontDict->lookup("Widths", &obj1);
860  if (obj1.isArray()) {
861    flags |= fontFixedWidth;
862    if (obj1.arrayGetLength() < lastChar - firstChar + 1) {
863      lastChar = firstChar + obj1.arrayGetLength() - 1;
864    }
865    for (code = firstChar; code <= lastChar; ++code) {
866      obj1.arrayGet(code - firstChar, &obj2);
867      if (obj2.isNum()) {
868        widths[code] = obj2.getNum() * mul;
869        if (widths[code] != widths[firstChar]) {
870          flags &= ~fontFixedWidth;
871        }
872      }
873      obj2.free();
874    }
875
876  // use widths from built-in font
877  } else if (builtinFont) {
878    // this is a kludge for broken PDF files that encode char 32
879    // as .notdef
880    if (builtinFont->widths->getWidth("space", &w)) {
881      widths[32] = 0.001 * w;
882    }
883    for (code = 0; code < 256; ++code) {
884      if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
885        widths[code] = 0.001 * w;
886      }
887    }
888
889  // couldn't find widths -- use defaults
890  } else {
891    // this is technically an error -- the Widths entry is required
892    // for all but the Base-14 fonts -- but certain PDF generators
893    // apparently don't include widths for Arial and TimesNewRoman
894    if (isFixedWidth()) {
895      i = 0;
896    } else if (isSerif()) {
897      i = 8;
898    } else {
899      i = 4;
900    }
901    if (isBold()) {
902      i += 2;
903    }
904    if (isItalic()) {
905      i += 1;
906    }
907    builtinFont = builtinFontSubst[i];
908    // this is a kludge for broken PDF files that encode char 32
909    // as .notdef
910    if (builtinFont->widths->getWidth("space", &w)) {
911      widths[32] = 0.001 * w;
912    }
913    for (code = 0; code < 256; ++code) {
914      if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
915        widths[code] = 0.001 * w;
916      }
917    }
918  }
919  obj1.free();
920
921  ok = gTrue;
922}
923
924Gfx8BitFont::~Gfx8BitFont() {
925  int i;
926
927  for (i = 0; i < 256; ++i) {
928    if (encFree[i] && enc[i]) {
929      gfree(enc[i]);
930    }
931  }
932  ctu->decRefCnt();
933  if (charProcs.isDict()) {
934    charProcs.free();
935  }
936  if (resources.isDict()) {
937    resources.free();
938  }
939}
940
941int Gfx8BitFont::getNextChar(char *s, int len, CharCode *code,
942                             Unicode *u, int uSize, int *uLen,
943                             double *dx, double *dy, double *ox, double *oy) {
944  CharCode c;
945
946  *code = c = (CharCode)(*s & 0xff);
947  *uLen = ctu->mapToUnicode(c, u, uSize);
948  *dx = widths[c];
949  *dy = *ox = *oy = 0;
950  return 1;
951}
952
953CharCodeToUnicode *Gfx8BitFont::getToUnicode() {
954  ctu->incRefCnt();
955  return ctu;
956}
957
958Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
959  Gushort *map;
960  int cmapPlatform, cmapEncoding;
961  int unicodeCmap, macRomanCmap, msSymbolCmap, cmap;
962  GBool useMacRoman, useUnicode;
963  char *charName;
964  Unicode u;
965  int code, i, n;
966
967  map = (Gushort *)gmallocn(256, sizeof(Gushort));
968  for (i = 0; i < 256; ++i) {
969    map[i] = 0;
970  }
971
972  // To match up with the Adobe-defined behaviour, we choose a cmap
973  // like this:
974  // 1. If the PDF font has an encoding:
975  //    1a. If the PDF font specified MacRomanEncoding and the
976  //        TrueType font has a Macintosh Roman cmap, use it, and
977  //        reverse map the char names through MacRomanEncoding to
978  //        get char codes.
979  //    1b. If the TrueType font has a Microsoft Unicode cmap or a
980  //        non-Microsoft Unicode cmap, use it, and use the Unicode
981  //        indexes, not the char codes.
982  //    1c. If the PDF font is symbolic and the TrueType font has a
983  //        Microsoft Symbol cmap, use it, and use char codes
984  //        directly (possibly with an offset of 0xf000).
985  //    1d. If the TrueType font has a Macintosh Roman cmap, use it,
986  //        as in case 1a.
987  // 2. If the PDF font does not have an encoding or the PDF font is
988  //    symbolic:
989  //    2a. If the TrueType font has a Macintosh Roman cmap, use it,
990  //        and use char codes directly (possibly with an offset of
991  //        0xf000).
992  //    2b. If the TrueType font has a Microsoft Symbol cmap, use it,
993  //        and use char codes directly (possible with an offset of
994  //        0xf000).
995  // 3. If none of these rules apply, use the first cmap and hope for
996  //    the best (this shouldn't happen).
997  unicodeCmap = macRomanCmap = msSymbolCmap = -1;
998  for (i = 0; i < ff->getNumCmaps(); ++i) {
999    cmapPlatform = ff->getCmapPlatform(i);
1000    cmapEncoding = ff->getCmapEncoding(i);
1001    if ((cmapPlatform == 3 && cmapEncoding == 1) ||
1002        cmapPlatform == 0) {
1003      unicodeCmap = i;
1004    } else if (cmapPlatform == 1 && cmapEncoding == 0) {
1005      macRomanCmap = i;
1006    } else if (cmapPlatform == 3 && cmapEncoding == 0) {
1007      msSymbolCmap = i;
1008    }
1009  }
1010  cmap = 0;
1011  useMacRoman = gFalse;
1012  useUnicode = gFalse;
1013  if (hasEncoding) {
1014    if (usesMacRomanEnc && macRomanCmap >= 0) {
1015      cmap = macRomanCmap;
1016      useMacRoman = gTrue;
1017    } else if (unicodeCmap >= 0) {
1018      cmap = unicodeCmap;
1019      useUnicode = gTrue;
1020    } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) {
1021      cmap = msSymbolCmap;
1022    } else if ((flags & fontSymbolic) && macRomanCmap >= 0) {
1023      cmap = macRomanCmap;
1024    } else if (macRomanCmap >= 0) {
1025      cmap = macRomanCmap;
1026      useMacRoman = gTrue;
1027    }
1028  } else {
1029    if (macRomanCmap >= 0) {
1030      cmap = macRomanCmap;
1031    } else if (msSymbolCmap >= 0) {
1032      cmap = msSymbolCmap;
1033    }
1034  }
1035
1036  // reverse map the char names through MacRomanEncoding, then map the
1037  // char codes through the cmap
1038  if (useMacRoman) {
1039    for (i = 0; i < 256; ++i) {
1040      if ((charName = enc[i])) {
1041        if ((code = globalParams->getMacRomanCharCode(charName))) {
1042          map[i] = ff->mapCodeToGID(cmap, code);
1043        }
1044      }
1045    }
1046
1047  // map Unicode through the cmap
1048  } else if (useUnicode) {
1049    for (i = 0; i < 256; ++i) {
1050      if (((charName = enc[i]) &&
1051           (u = globalParams->mapNameToUnicode(charName))) ||
1052          (n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
1053        map[i] = ff->mapCodeToGID(cmap, u);
1054      }
1055    }
1056
1057  // map the char codes through the cmap, possibly with an offset of
1058  // 0xf000
1059  } else {
1060    for (i = 0; i < 256; ++i) {
1061      if (!(map[i] = ff->mapCodeToGID(cmap, i))) {
1062        map[i] = ff->mapCodeToGID(cmap, 0xf000 + i);
1063      }
1064    }
1065  }
1066
1067  // try the TrueType 'post' table to handle any unmapped characters
1068  for (i = 0; i < 256; ++i) {
1069    if (!map[i] && (charName = enc[i])) {
1070      map[i] = (Gushort)(int)ff->mapNameToGID(charName);
1071    }
1072  }
1073
1074  return map;
1075}
1076
1077Dict *Gfx8BitFont::getCharProcs() {
1078  return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL;
1079}
1080
1081Object *Gfx8BitFont::getCharProc(int code, Object *proc) {
1082  if (enc[code] && charProcs.isDict()) {
1083    charProcs.dictLookup(enc[code], proc);
1084  } else {
1085    proc->initNull();
1086  }
1087  return proc;
1088}
1089
1090Dict *Gfx8BitFont::getResources() {
1091  return resources.isDict() ? resources.getDict() : (Dict *)NULL;
1092}
1093
1094//------------------------------------------------------------------------
1095// GfxCIDFont
1096//------------------------------------------------------------------------
1097
1098static int CDECL cmpWidthExcep(const void *w1, const void *w2) {
1099  return ((GfxFontCIDWidthExcep *)w1)->first -
1100         ((GfxFontCIDWidthExcep *)w2)->first;
1101}
1102
1103static int CDECL cmpWidthExcepV(const void *w1, const void *w2) {
1104  return ((GfxFontCIDWidthExcepV *)w1)->first -
1105         ((GfxFontCIDWidthExcepV *)w2)->first;
1106}
1107
1108GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GooString *nameA,
1109                       Dict *fontDict):
1110  GfxFont(tagA, idA, nameA)
1111{
1112  Dict *desFontDict;
1113  GooString *collection, *cMapName;
1114  Object desFontDictObj;
1115  Object obj1, obj2, obj3, obj4, obj5, obj6;
1116  CharCodeToUnicode *utu;
1117  CharCode c;
1118  Unicode uBuf[8];
1119  int c1, c2;
1120  int excepsSize, i, j, k, n;
1121
1122  refCnt = 1;
1123  ascent = 0.95;
1124  descent = -0.35;
1125  fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
1126  cMap = NULL;
1127  ctu = NULL;
1128  widths.defWidth = 1.0;
1129  widths.defHeight = -1.0;
1130  widths.defVY = 0.880;
1131  widths.exceps = NULL;
1132  widths.nExceps = 0;
1133  widths.excepsV = NULL;
1134  widths.nExcepsV = 0;
1135  cidToGID = NULL;
1136  cidToGIDLen = 0;
1137
1138  // get the descendant font
1139  if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
1140    error(-1, "Missing DescendantFonts entry in Type 0 font");
1141    obj1.free();
1142    goto err1;
1143  }
1144  if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
1145    error(-1, "Bad descendant font in Type 0 font");
1146    goto err3;
1147  }
1148  obj1.free();
1149  desFontDict = desFontDictObj.getDict();
1150
1151  // font type
1152  if (!desFontDict->lookup("Subtype", &obj1)) {
1153    error(-1, "Missing Subtype entry in Type 0 descendant font");
1154    goto err3;
1155  }
1156  if (obj1.isName("CIDFontType0")) {
1157    type = fontCIDType0;
1158  } else if (obj1.isName("CIDFontType2")) {
1159    type = fontCIDType2;
1160  } else {
1161    error(-1, "Unknown Type 0 descendant font type '%s'",
1162          obj1.isName() ? obj1.getName() : "???");
1163    goto err3;
1164  }
1165  obj1.free();
1166
1167  // get info from font descriptor
1168  readFontDescriptor(xref, desFontDict);
1169
1170  // look for an external font file
1171  findExtFontFile();
1172
1173  //----- encoding info -----
1174
1175  // char collection
1176  if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
1177    error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font");
1178    goto err3;
1179  }
1180  obj1.dictLookup("Registry", &obj2);
1181  obj1.dictLookup("Ordering", &obj3);
1182  if (!obj2.isString() || !obj3.isString()) {
1183    error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
1184    goto err4;
1185  }
1186  collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
1187  obj3.free();
1188  obj2.free();
1189  obj1.free();
1190
1191  // look for a ToUnicode CMap
1192  if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) {
1193
1194    // the "Adobe-Identity" and "Adobe-UCS" collections don't have
1195    // cidToUnicode files
1196    if (collection->cmp("Adobe-Identity") &&
1197        collection->cmp("Adobe-UCS")) {
1198
1199      // look for a user-supplied .cidToUnicode file
1200      if (!(ctu = globalParams->getCIDToUnicode(collection))) {
1201        error(-1, "Unknown character collection '%s'",
1202              collection->getCString());
1203        // fall-through, assuming the Identity mapping -- this appears
1204        // to match Adobe's behavior
1205      }
1206    }
1207  }
1208
1209  // look for a Unicode-to-Unicode mapping
1210  if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
1211    if (ctu) {
1212      for (c = 0; c < ctu->getLength(); ++c) {
1213        n = ctu->mapToUnicode(c, uBuf, 8);
1214        if (n >= 1) {
1215          n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
1216          if (n >= 1) {
1217            ctu->setMapping(c, uBuf, n);
1218      }
1219    }
1220  }
1221      utu->decRefCnt();
1222    } else {
1223      ctu = utu;
1224    }
1225  }
1226
1227  // encoding (i.e., CMap)
1228  //~ need to handle a CMap stream here
1229  //~ also need to deal with the UseCMap entry in the stream dict
1230  if (!fontDict->lookup("Encoding", &obj1)->isName()) {
1231    error(-1, "Missing or invalid Encoding entry in Type 0 font");
1232    delete collection;
1233    goto err3;
1234  }
1235  cMapName = new GooString(obj1.getName());
1236  obj1.free();
1237  if (!(cMap = globalParams->getCMap(collection, cMapName))) {
1238    error(-1, "Unknown CMap '%s' for character collection '%s'",
1239          cMapName->getCString(), collection->getCString());
1240    delete collection;
1241    delete cMapName;
1242    goto err2;
1243  }
1244  delete collection;
1245  delete cMapName;
1246
1247  // CIDToGIDMap (for embedded TrueType fonts)
1248  if (type == fontCIDType2) {
1249    desFontDict->lookup("CIDToGIDMap", &obj1);
1250    if (obj1.isStream()) {
1251      cidToGIDLen = 0;
1252      i = 64;
1253      cidToGID = (Gushort *)gmallocn(i, sizeof(Gushort));
1254      obj1.streamReset();
1255      while ((c1 = obj1.streamGetChar()) != EOF &&
1256             (c2 = obj1.streamGetChar()) != EOF) {
1257        if (cidToGIDLen == i) {
1258          i *= 2;
1259          cidToGID = (Gushort *)greallocn(cidToGID, i, sizeof(Gushort));
1260        }
1261        cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2);
1262      }
1263    } else if (!obj1.isName("Identity") && !obj1.isNull()) {
1264      error(-1, "Invalid CIDToGIDMap entry in CID font");
1265    }
1266    obj1.free();
1267  }
1268
1269  //----- character metrics -----
1270
1271  // default char width
1272  if (desFontDict->lookup("DW", &obj1)->isInt()) {
1273    widths.defWidth = obj1.getInt() * 0.001;
1274  }
1275  obj1.free();
1276
1277  // char width exceptions
1278  if (desFontDict->lookup("W", &obj1)->isArray()) {
1279    excepsSize = 0;
1280    i = 0;
1281    while (i + 1 < obj1.arrayGetLength()) {
1282      obj1.arrayGet(i, &obj2);
1283      obj1.arrayGet(i + 1, &obj3);
1284      if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) {
1285        if (obj1.arrayGet(i + 2, &obj4)->isNum()) {
1286          if (widths.nExceps == excepsSize) {
1287            excepsSize += 16;
1288            widths.exceps = (GfxFontCIDWidthExcep *)
1289              greallocn(widths.exceps,
1290                        excepsSize, sizeof(GfxFontCIDWidthExcep));
1291          }
1292          widths.exceps[widths.nExceps].first = obj2.getInt();
1293          widths.exceps[widths.nExceps].last = obj3.getInt();
1294          widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
1295          ++widths.nExceps;
1296        } else {
1297          error(-1, "Bad widths array in Type 0 font");
1298        }
1299        obj4.free();
1300        i += 3;
1301      } else if (obj2.isInt() && obj3.isArray()) {
1302        if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
1303          excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15;
1304          widths.exceps = (GfxFontCIDWidthExcep *)
1305            greallocn(widths.exceps,
1306                      excepsSize, sizeof(GfxFontCIDWidthExcep));
1307        }
1308        j = obj2.getInt();
1309        for (k = 0; k < obj3.arrayGetLength(); ++k) {
1310          if (obj3.arrayGet(k, &obj4)->isNum()) {
1311            widths.exceps[widths.nExceps].first = j;
1312            widths.exceps[widths.nExceps].last = j;
1313            widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
1314            ++j;
1315            ++widths.nExceps;
1316          } else {
1317            error(-1, "Bad widths array in Type 0 font");
1318          }
1319          obj4.free();
1320        }
1321        i += 2;
1322      } else {
1323        error(-1, "Bad widths array in Type 0 font");
1324        ++i;
1325      }
1326      obj3.free();
1327      obj2.free();
1328    }
1329    qsort(widths.exceps, widths.nExceps, sizeof(GfxFontCIDWidthExcep),
1330          &cmpWidthExcep);
1331  }
1332  obj1.free();
1333
1334  // default metrics for vertical font
1335  if (desFontDict->lookup("DW2", &obj1)->isArray() &&
1336      obj1.arrayGetLength() == 2) {
1337    if (obj1.arrayGet(0, &obj2)->isNum()) {
1338      widths.defVY = obj2.getNum() * 0.001;
1339    }
1340    obj2.free();
1341    if (obj1.arrayGet(1, &obj2)->isNum()) {
1342      widths.defHeight = obj2.getNum() * 0.001;
1343    }
1344    obj2.free();
1345  }
1346  obj1.free();
1347
1348  // char metric exceptions for vertical font
1349  if (desFontDict->lookup("W2", &obj1)->isArray()) {
1350    excepsSize = 0;
1351    i = 0;
1352    while (i + 1 < obj1.arrayGetLength()) {
1353      obj1.arrayGet(i, &obj2);
1354      obj1.arrayGet(i+ 1, &obj3);
1355      if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) {
1356        if (obj1.arrayGet(i + 2, &obj4)->isNum() &&
1357            obj1.arrayGet(i + 3, &obj5)->isNum() &&
1358            obj1.arrayGet(i + 4, &obj6)->isNum()) {
1359          if (widths.nExcepsV == excepsSize) {
1360            excepsSize += 16;
1361            widths.excepsV = (GfxFontCIDWidthExcepV *)
1362              greallocn(widths.excepsV,
1363                        excepsSize, sizeof(GfxFontCIDWidthExcepV));
1364          }
1365          widths.excepsV[widths.nExcepsV].first = obj2.getInt();
1366          widths.excepsV[widths.nExcepsV].last = obj3.getInt();
1367          widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
1368          widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001;
1369          widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001;
1370          ++widths.nExcepsV;
1371        } else {
1372          error(-1, "Bad widths (W2) array in Type 0 font");
1373        }
1374        obj6.free();
1375        obj5.free();
1376        obj4.free();
1377        i += 5;
1378      } else if (obj2.isInt() && obj3.isArray()) {
1379        if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) {
1380          excepsSize =
1381            (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15;
1382          widths.excepsV = (GfxFontCIDWidthExcepV *)
1383            greallocn(widths.excepsV,
1384                      excepsSize, sizeof(GfxFontCIDWidthExcepV));
1385        }
1386        j = obj2.getInt();
1387        for (k = 0; k < obj3.arrayGetLength(); k += 3) {
1388          if (obj3.arrayGet(k, &obj4)->isNum() &&
1389              obj3.arrayGet(k+1, &obj5)->isNum() &&
1390              obj3.arrayGet(k+2, &obj6)->isNum()) {
1391            widths.excepsV[widths.nExceps].first = j;
1392            widths.excepsV[widths.nExceps].last = j;
1393            widths.excepsV[widths.nExceps].height = obj4.getNum() * 0.001;
1394            widths.excepsV[widths.nExceps].vx = obj5.getNum() * 0.001;
1395            widths.excepsV[widths.nExceps].vy = obj6.getNum() * 0.001;
1396            ++j;
1397            ++widths.nExcepsV;
1398          } else {
1399            error(-1, "Bad widths (W2) array in Type 0 font");
1400          }
1401          obj6.free();
1402          obj5.free();
1403          obj4.free();
1404        }
1405        i += 2;
1406      } else {
1407        error(-1, "Bad widths (W2) array in Type 0 font");
1408        ++i;
1409      }
1410      obj3.free();
1411      obj2.free();
1412    }
1413    qsort(widths.excepsV, widths.nExcepsV, sizeof(GfxFontCIDWidthExcepV),
1414          &cmpWidthExcepV);
1415  }
1416  obj1.free();
1417
1418  desFontDictObj.free();
1419  ok = gTrue;
1420  return;
1421
1422 err4:
1423  obj3.free();
1424  obj2.free();
1425 err3:
1426  obj1.free();
1427 err2:
1428  desFontDictObj.free();
1429 err1:;
1430}
1431
1432GfxCIDFont::~GfxCIDFont() {
1433  if (cMap) {
1434    cMap->decRefCnt();
1435  }
1436  if (ctu) {
1437    ctu->decRefCnt();
1438  }
1439  gfree(widths.exceps);
1440  gfree(widths.excepsV);
1441  if (cidToGID) {
1442    gfree(cidToGID);
1443  }
1444}
1445
1446int GfxCIDFont::getNextChar(char *s, int len, CharCode *code,
1447                            Unicode *u, int uSize, int *uLen,
1448                            double *dx, double *dy, double *ox, double *oy) {
1449  CID cid;
1450  double w, h, vx, vy;
1451  int n, a, b, m;
1452
1453  if (!cMap) {
1454    *code = 0;
1455    *uLen = 0;
1456    *dx = *dy = 0;
1457    return 1;
1458  }
1459
1460  *code = (CharCode)(cid = cMap->getCID(s, len, &n));
1461  if (ctu) {
1462    *uLen = ctu->mapToUnicode(cid, u, uSize);
1463  } else {
1464    *uLen = 0;
1465  }
1466
1467  // horizontal
1468  if (cMap->getWMode() == 0) {
1469    w = widths.defWidth;
1470    h = vx = vy = 0;
1471    if (widths.nExceps > 0 && cid >= widths.exceps[0].first) {
1472      a = 0;
1473      b = widths.nExceps;
1474      // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first
1475      while (b - a > 1) {
1476        m = (a + b) / 2;
1477        if (widths.exceps[m].first <= cid) {
1478          a = m;
1479        } else {
1480          b = m;
1481        }
1482      }
1483      if (cid <= widths.exceps[a].last) {
1484        w = widths.exceps[a].width;
1485      }
1486    }
1487
1488  // vertical
1489  } else {
1490    w = 0;
1491    h = widths.defHeight;
1492    vx = widths.defWidth / 2;
1493    vy = widths.defVY;
1494    if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) {
1495      a = 0;
1496      b = widths.nExcepsV;
1497      // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first
1498      while (b - a > 1) {
1499        m = (a + b) / 2;
1500        if (widths.excepsV[m].last <= cid) {
1501          a = m;
1502        } else {
1503          b = m;
1504        }
1505      }
1506      if (cid <= widths.excepsV[a].last) {
1507        h = widths.excepsV[a].height;
1508        vx = widths.excepsV[a].vx;
1509        vy = widths.excepsV[a].vy;
1510      }
1511    }
1512  }
1513
1514  *dx = w;
1515  *dy = h;
1516  *ox = vx;
1517  *oy = vy;
1518
1519  return n;
1520}
1521
1522int GfxCIDFont::getWMode() {
1523  return cMap ? cMap->getWMode() : 0;
1524}
1525
1526CharCodeToUnicode *GfxCIDFont::getToUnicode() {
1527  if (ctu) {
1528    ctu->incRefCnt();
1529  }
1530  return ctu;
1531}
1532
1533GooString *GfxCIDFont::getCollection() {
1534  return cMap ? cMap->getCollection() : (GooString *)NULL;
1535}
1536
1537Gushort *GfxCIDFont::getCodeToGIDMap(FoFiTrueType *ff, int *mapsizep) {
1538  Gushort *map;
1539  int cmapPlatform, cmapEncoding;
1540  int unicodeCmap, macRomanCmap, msSymbolCmap, cmap;
1541  GBool useMacRoman, useUnicode;
1542  char *charName;
1543  Unicode u;
1544  int code, i;
1545  int mapsize;
1546  int cidlen;
1547
1548  *mapsizep = 0;
1549  if (!ctu) return NULL;
1550
1551  /* we use only unicode cmap */
1552  cmap = -1;
1553  for (i = 0; i < ff->getNumCmaps(); ++i) {
1554    cmapPlatform = ff->getCmapPlatform(i);
1555    cmapEncoding = ff->getCmapEncoding(i);
1556    if ((cmapPlatform == 3 && cmapEncoding == 1) || cmapPlatform == 0)
1557      cmap = i;
1558  }
1559  if (cmap < 0)
1560    return NULL;
1561
1562  cidlen = 0;
1563  mapsize = 64;
1564  map = (Gushort *)gmalloc(mapsize * sizeof(Gushort));
1565
1566  while (cidlen < ctu->getLength()) {
1567    int n;
1568    if ((n = ctu->mapToUnicode((CharCode)cidlen, &u, 1)) == 0) {
1569      cidlen++;
1570      continue;
1571    }
1572    if (cidlen >= mapsize) {
1573      while (cidlen >= mapsize)
1574        mapsize *= 2;
1575      map = (Gushort *)grealloc(map, mapsize * sizeof(Gushort));
1576    }
1577    map[cidlen] = ff->mapCodeToGID(cmap, u);
1578    cidlen++;
1579  }
1580
1581  *mapsizep = cidlen;
1582  return map;
1583}
1584
1585//------------------------------------------------------------------------
1586// GfxFontDict
1587//------------------------------------------------------------------------
1588
1589GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) {
1590  int i;
1591  Object obj1, obj2;
1592  Ref r;
1593
1594  numFonts = fontDict->getLength();
1595  fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *));
1596  for (i = 0; i < numFonts; ++i) {
1597    fontDict->getValNF(i, &obj1);
1598    obj1.fetch(xref, &obj2);
1599    if (obj2.isDict()) {
1600      if (obj1.isRef()) {
1601        r = obj1.getRef();
1602      } else {
1603        // no indirect reference for this font, so invent a unique one
1604        // (legal generation numbers are five digits, so any 6-digit
1605        // number would be safe)
1606        r.num = i;
1607        if (fontDictRef) {
1608          r.gen = 100000 + fontDictRef->num;
1609        } else {
1610          r.gen = 999999;
1611        }
1612      }
1613      char *aux = fontDict->getKey(i)->getCString();
1614      fonts[i] = GfxFont::makeFont(xref, aux,
1615                                   r, obj2.getDict());
1616      delete[] aux;
1617      if (fonts[i] && !fonts[i]->isOk()) {
1618        delete fonts[i];
1619        fonts[i] = NULL;
1620      }
1621    } else {
1622      error(-1, "font resource is not a dictionary");
1623      fonts[i] = NULL;
1624    }
1625    obj1.free();
1626    obj2.free();
1627  }
1628}
1629
1630GfxFontDict::~GfxFontDict() {
1631  int i;
1632
1633  for (i = 0; i < numFonts; ++i) {
1634    if (fonts[i]) {
1635      fonts[i]->decRefCnt();
1636    }
1637  }
1638  gfree(fonts);
1639}
1640
1641GfxFont *GfxFontDict::lookup(char *tag) {
1642  int i;
1643
1644  for (i = 0; i < numFonts; ++i) {
1645    if (fonts[i] && fonts[i]->matches(tag)) {
1646      return fonts[i];
1647    }
1648  }
1649  return NULL;
1650}
Note: See TracBrowser for help on using the repository browser.