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

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

First import

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