Coverage Report

Created: 2025-08-26 06:28

/src/xpdf-4.05/xpdf/GfxFont.cc
Line
Count
Source (jump to first uncovered line)
1
//========================================================================
2
//
3
// GfxFont.cc
4
//
5
// Copyright 1996-2003 Glyph & Cog, LLC
6
//
7
//========================================================================
8
9
#include <aconf.h>
10
11
#include <stdio.h>
12
#include <stdlib.h>
13
#include <string.h>
14
#include <ctype.h>
15
#include <math.h>
16
#include <limits.h>
17
#include "gmem.h"
18
#include "gmempp.h"
19
#include "GList.h"
20
#include "GHash.h"
21
#include "Error.h"
22
#include "Object.h"
23
#include "Dict.h"
24
#include "GlobalParams.h"
25
#include "CMap.h"
26
#include "CharCodeToUnicode.h"
27
#include "FontEncodingTables.h"
28
#include "BuiltinFontTables.h"
29
#include "FoFiIdentifier.h"
30
#include "FoFiType1.h"
31
#include "FoFiType1C.h"
32
#include "FoFiTrueType.h"
33
#include "GfxFont.h"
34
35
//------------------------------------------------------------------------
36
37
struct Base14FontMapEntry {
38
  const char *altName;
39
  const char *base14Name;
40
};
41
42
static Base14FontMapEntry base14FontMap[] = {
43
  { "Arial",                        "Helvetica" },
44
  { "Arial,Bold",                   "Helvetica-Bold" },
45
  { "Arial,BoldItalic",             "Helvetica-BoldOblique" },
46
  { "Arial,Italic",                 "Helvetica-Oblique" },
47
  { "Arial-Bold",                   "Helvetica-Bold" },
48
  { "Arial-BoldItalic",             "Helvetica-BoldOblique" },
49
  { "Arial-BoldItalicMT",           "Helvetica-BoldOblique" },
50
  { "Arial-BoldMT",                 "Helvetica-Bold" },
51
  { "Arial-Italic",                 "Helvetica-Oblique" },
52
  { "Arial-ItalicMT",               "Helvetica-Oblique" },
53
  { "ArialMT",                      "Helvetica" },
54
  { "Courier",                      "Courier" },
55
  { "Courier,Bold",                 "Courier-Bold" },
56
  { "Courier,BoldItalic",           "Courier-BoldOblique" },
57
  { "Courier,Italic",               "Courier-Oblique" },
58
  { "Courier-Bold",                 "Courier-Bold" },
59
  { "Courier-BoldOblique",          "Courier-BoldOblique" },
60
  { "Courier-Oblique",              "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",                    "Helvetica" },
73
  { "Helvetica,Bold",               "Helvetica-Bold" },
74
  { "Helvetica,BoldItalic",         "Helvetica-BoldOblique" },
75
  { "Helvetica,Italic",             "Helvetica-Oblique" },
76
  { "Helvetica-Bold",               "Helvetica-Bold" },
77
  { "Helvetica-BoldItalic",         "Helvetica-BoldOblique" },
78
  { "Helvetica-BoldOblique",        "Helvetica-BoldOblique" },
79
  { "Helvetica-Italic",             "Helvetica-Oblique" },
80
  { "Helvetica-Oblique",            "Helvetica-Oblique" },
81
  { "Symbol",                       "Symbol" },
82
  { "Symbol,Bold",                  "Symbol" },
83
  { "Symbol,BoldItalic",            "Symbol" },
84
  { "Symbol,Italic",                "Symbol" },
85
  { "Times-Bold",                   "Times-Bold" },
86
  { "Times-BoldItalic",             "Times-BoldItalic" },
87
  { "Times-Italic",                 "Times-Italic" },
88
  { "Times-Roman",                  "Times-Roman" },
89
  { "TimesNewRoman",                "Times-Roman" },
90
  { "TimesNewRoman,Bold",           "Times-Bold" },
91
  { "TimesNewRoman,BoldItalic",     "Times-BoldItalic" },
92
  { "TimesNewRoman,Italic",         "Times-Italic" },
93
  { "TimesNewRoman-Bold",           "Times-Bold" },
94
  { "TimesNewRoman-BoldItalic",     "Times-BoldItalic" },
95
  { "TimesNewRoman-Italic",         "Times-Italic" },
96
  { "TimesNewRomanPS",              "Times-Roman" },
97
  { "TimesNewRomanPS-Bold",         "Times-Bold" },
98
  { "TimesNewRomanPS-BoldItalic",   "Times-BoldItalic" },
99
  { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" },
100
  { "TimesNewRomanPS-BoldMT",       "Times-Bold" },
101
  { "TimesNewRomanPS-Italic",       "Times-Italic" },
102
  { "TimesNewRomanPS-ItalicMT",     "Times-Italic" },
103
  { "TimesNewRomanPSMT",            "Times-Roman" },
104
  { "TimesNewRomanPSMT,Bold",       "Times-Bold" },
105
  { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" },
106
  { "TimesNewRomanPSMT,Italic",     "Times-Italic" },
107
  { "ZapfDingbats",                 "ZapfDingbats" }
108
};
109
110
//------------------------------------------------------------------------
111
112
// index: {fixed:0, sans-serif:4, serif:8} + bold*2 + italic
113
// NB: must be in same order as psSubstFonts in PSOutputDev.cc
114
static const char *base14SubstFonts[14] = {
115
  "Courier",
116
  "Courier-Oblique",
117
  "Courier-Bold",
118
  "Courier-BoldOblique",
119
  "Helvetica",
120
  "Helvetica-Oblique",
121
  "Helvetica-Bold",
122
  "Helvetica-BoldOblique",
123
  "Times-Roman",
124
  "Times-Italic",
125
  "Times-Bold",
126
  "Times-BoldItalic",
127
  // the last two are never used for substitution
128
  "Symbol",
129
  "ZapfDingbats"
130
};
131
132
//------------------------------------------------------------------------
133
134
0
static int readFromStream(void *data) {
135
0
  return ((Stream *)data)->getChar();
136
0
}
137
138
//------------------------------------------------------------------------
139
// GfxFontLoc
140
//------------------------------------------------------------------------
141
142
0
GfxFontLoc::GfxFontLoc() {
143
0
  path = NULL;
144
0
  fontNum = 0;
145
0
  oblique = 0;
146
0
  encoding = NULL;
147
0
  substIdx = -1;
148
0
}
149
150
0
GfxFontLoc::~GfxFontLoc() {
151
0
  if (path) {
152
0
    delete path;
153
0
  }
154
0
  if (encoding) {
155
0
    delete encoding;
156
0
  }
157
0
}
158
159
//------------------------------------------------------------------------
160
// GfxFont
161
//------------------------------------------------------------------------
162
163
GfxFont *GfxFont::makeFont(XRef *xref, const char *tagA,
164
0
         Ref idA, Dict *fontDict) {
165
0
  GString *nameA;
166
0
  Ref embFontIDA;
167
0
  GfxFontType typeA;
168
0
  GfxFont *font;
169
0
  Object obj1;
170
171
  // get base font name
172
0
  nameA = NULL;
173
0
  fontDict->lookup("BaseFont", &obj1);
174
0
  if (obj1.isName()) {
175
0
    nameA = new GString(obj1.getName());
176
0
  } else if (obj1.isString()) {
177
0
    nameA = obj1.getString()->copy();
178
0
  }
179
0
  obj1.free();
180
181
  // get embedded font ID and font type
182
0
  typeA = getFontType(xref, fontDict, &embFontIDA);
183
184
  // create the font object
185
0
  font = NULL;
186
0
  if (typeA < fontCIDType0) {
187
0
    font = new Gfx8BitFont(xref, tagA, idA, nameA, typeA, embFontIDA,
188
0
         fontDict);
189
0
  } else {
190
0
    font = new GfxCIDFont(xref, tagA, idA, nameA, typeA, embFontIDA,
191
0
        fontDict);
192
0
  }
193
194
0
  return font;
195
0
}
196
197
0
GfxFont *GfxFont::makeDefaultFont(XRef *xref) {
198
0
  Object type, subtype, baseFont;
199
0
  type.initName("Font");
200
0
  subtype.initName("Type1");
201
0
  baseFont.initName("Helvetica");
202
0
  Object fontDict;
203
0
  fontDict.initDict(xref);
204
0
  fontDict.dictAdd(copyString("Type"), &type);
205
0
  fontDict.dictAdd(copyString("Subtype"), &subtype);
206
0
  fontDict.dictAdd(copyString("BaseFont"), &baseFont);
207
208
0
  Ref r;
209
0
  r.gen = 100000;
210
0
  r.num = GfxFontDict::hashFontObject(&fontDict);
211
212
0
  GfxFont *font = makeFont(xref, "undef", r, fontDict.getDict());
213
0
  fontDict.free();
214
215
0
  return font;
216
0
}
217
218
GfxFont::GfxFont(const char *tagA, Ref idA, GString *nameA,
219
0
     GfxFontType typeA, Ref embFontIDA) {
220
0
  ok = gFalse;
221
0
  tag = new GString(tagA);
222
0
  id = idA;
223
0
  name = nameA;
224
0
  type = typeA;
225
0
  embFontID = embFontIDA;
226
0
  embFontName = NULL;
227
0
  hasToUnicode = gFalse;
228
0
}
229
230
0
GfxFont::~GfxFont() {
231
0
  delete tag;
232
0
  if (name) {
233
0
    delete name;
234
0
  }
235
0
  if (embFontName) {
236
0
    delete embFontName;
237
0
  }
238
0
}
239
240
// This function extracts three pieces of information:
241
// 1. the "expected" font type, i.e., the font type implied by
242
//    Font.Subtype, DescendantFont.Subtype, and
243
//    FontDescriptor.FontFile3.Subtype
244
// 2. the embedded font object ID
245
// 3. the actual font type - determined by examining the embedded font
246
//    if there is one, otherwise equal to the expected font type
247
// If the expected and actual font types don't match, a warning
248
// message is printed.  The expected font type is not used for
249
// anything else.
250
0
GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
251
0
  GfxFontType t, expectedType;
252
0
  FoFiIdentifierType fft;
253
0
  Dict *fontDict2;
254
0
  Object subtype, fontDesc, obj1, obj2, obj3, obj4;
255
0
  GBool isType0, err;
256
257
0
  t = fontUnknownType;
258
0
  embID->num = embID->gen = -1;
259
0
  err = gFalse;
260
261
0
  fontDict->lookup("Subtype", &subtype);
262
0
  expectedType = fontUnknownType;
263
0
  isType0 = gFalse;
264
0
  if (subtype.isName("Type1") || subtype.isName("MMType1")) {
265
0
    expectedType = fontType1;
266
0
  } else if (subtype.isName("Type1C")) {
267
0
    expectedType = fontType1C;
268
0
  } else if (subtype.isName("Type3")) {
269
0
    expectedType = fontType3;
270
0
  } else if (subtype.isName("TrueType")) {
271
0
    expectedType = fontTrueType;
272
0
  } else if (subtype.isName("Type0")) {
273
0
    isType0 = gTrue;
274
0
  } else {
275
0
    error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'",
276
0
    subtype.isName() ? subtype.getName() : "???");
277
0
  }
278
0
  subtype.free();
279
280
0
  fontDict2 = fontDict;
281
0
  if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
282
0
    if (obj1.arrayGetLength() == 0) {
283
0
      error(errSyntaxWarning, -1, "Empty DescendantFonts array in font");
284
0
      obj2.initNull();
285
0
    } else if (obj1.arrayGet(0, &obj2)->isDict()) {
286
0
      if (!isType0) {
287
0
  error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
288
0
      }
289
0
      fontDict2 = obj2.getDict();
290
0
      fontDict2->lookup("Subtype", &subtype);
291
0
      if (subtype.isName("CIDFontType0")) {
292
0
  if (isType0) {
293
0
    expectedType = fontCIDType0;
294
0
  }
295
0
      } else if (subtype.isName("CIDFontType2")) {
296
0
  if (isType0) {
297
0
    expectedType = fontCIDType2;
298
0
  }
299
0
      }
300
0
      subtype.free();
301
0
    }
302
0
  } else {
303
0
    obj2.initNull();
304
0
  }
305
306
  // NB: the PDF spec doesn't say anything about precedence, but Adobe
307
  // uses FontFile3 over FontFile2 if both are present.
308
0
  if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) {
309
0
    if (fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) {
310
0
      *embID = obj3.getRef();
311
0
      if (obj3.fetch(xref, &obj4)->isStream()) {
312
0
  obj4.streamGetDict()->lookup("Subtype", &subtype);
313
0
  if (subtype.isName("Type1")) {
314
0
    if (expectedType != fontType1) {
315
0
      err = gTrue;
316
0
      expectedType = isType0 ? fontCIDType0 : fontType1;
317
0
    }
318
0
  } else if (subtype.isName("Type1C")) {
319
0
    if (expectedType == fontType1) {
320
0
      expectedType = fontType1C;
321
0
    } else if (expectedType != fontType1C) {
322
0
      err = gTrue;
323
0
      expectedType = isType0 ? fontCIDType0C : fontType1C;
324
0
    }
325
0
  } else if (subtype.isName("TrueType")) {
326
0
    if (expectedType != fontTrueType) {
327
0
      err = gTrue;
328
0
      expectedType = isType0 ? fontCIDType2 : fontTrueType;
329
0
    }
330
0
  } else if (subtype.isName("CIDFontType0C")) {
331
0
    if (expectedType == fontCIDType0) {
332
0
      expectedType = fontCIDType0C;
333
0
    } else {
334
0
      err = gTrue;
335
0
      expectedType = isType0 ? fontCIDType0C : fontType1C;
336
0
    }
337
0
  } else if (subtype.isName("OpenType")) {
338
0
    if (expectedType == fontTrueType) {
339
0
      expectedType = fontTrueTypeOT;
340
0
    } else if (expectedType == fontType1) {
341
0
      expectedType = fontType1COT;
342
0
    } else if (expectedType == fontCIDType0) {
343
0
      expectedType = fontCIDType0COT;
344
0
    } else if (expectedType == fontCIDType2) {
345
0
      expectedType = fontCIDType2OT;
346
0
    } else {
347
0
      err = gTrue;
348
0
    }
349
0
  } else {
350
0
    error(errSyntaxError, -1, "Unknown font type '{0:s}'",
351
0
    subtype.isName() ? subtype.getName() : "???");
352
0
  }
353
0
  subtype.free();
354
0
      }
355
0
      obj4.free();
356
0
    }
357
0
    obj3.free();
358
0
    if (embID->num == -1) {
359
0
      if (fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) {
360
0
  *embID = obj3.getRef();
361
0
  if (isType0) {
362
0
    expectedType = fontCIDType2;
363
0
  } else if (expectedType != fontTrueType) {
364
0
    err = gTrue;
365
0
  }
366
0
      }
367
0
      obj3.free();
368
0
    }
369
0
    if (embID->num == -1) {
370
0
      if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) {
371
0
  *embID = obj3.getRef();
372
0
  if (expectedType != fontType1) {
373
0
    err = gTrue;
374
0
  }
375
0
      }
376
0
      obj3.free();
377
0
    }
378
0
  }
379
0
  fontDesc.free();
380
381
0
  t = fontUnknownType;
382
0
  if (embID->num >= 0) {
383
0
    obj3.initRef(embID->num, embID->gen);
384
0
    obj3.fetch(xref, &obj4);
385
0
    if (obj4.isStream()) {
386
0
      obj4.streamReset();
387
0
      fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream());
388
0
      obj4.streamClose();
389
0
      switch (fft) {
390
0
      case fofiIdType1PFA:
391
0
      case fofiIdType1PFB:
392
0
  t = fontType1;
393
0
  break;
394
0
      case fofiIdCFF8Bit:
395
0
  t = isType0 ? fontCIDType0C : fontType1C;
396
0
  break;
397
0
      case fofiIdCFFCID:
398
0
  t = fontCIDType0C;
399
0
  break;
400
0
      case fofiIdTrueType:
401
0
      case fofiIdTrueTypeCollection:
402
0
  t = isType0 ? fontCIDType2 : fontTrueType;
403
0
  break;
404
0
      case fofiIdOpenTypeCFF8Bit:
405
0
  t = isType0 ? fontCIDType0COT : fontType1COT;
406
0
  break;
407
0
      case fofiIdOpenTypeCFFCID:
408
0
  t = fontCIDType0COT;
409
0
  break;
410
0
      default:
411
0
  error(errSyntaxError, -1, "Embedded font file may be invalid");
412
0
  break;
413
0
      }
414
0
    }
415
0
    obj4.free();
416
0
    obj3.free();
417
0
  }
418
419
0
  if (t == fontUnknownType) {
420
0
    t = expectedType;
421
0
  }
422
423
0
  if (t != expectedType) {
424
0
    err = gTrue;
425
0
  }
426
427
0
  if (err) {
428
0
    error(errSyntaxWarning, -1,
429
0
    "Mismatch between font type and embedded font file");
430
0
  }
431
432
0
  obj2.free();
433
0
  obj1.free();
434
435
0
  return t;
436
0
}
437
438
0
void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
439
0
  Object obj1, obj2, obj3, obj4;
440
0
  double t, t2;
441
0
  int i;
442
443
  // assume Times-Roman by default (for substitution purposes)
444
0
  flags = fontSerif;
445
446
0
  if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
447
448
    // get flags
449
0
    if (obj1.dictLookup("Flags", &obj2)->isInt()) {
450
0
      flags = obj2.getInt();
451
0
    }
452
0
    obj2.free();
453
454
    // get name
455
0
    obj1.dictLookup("FontName", &obj2);
456
0
    if (obj2.isName()) {
457
0
      embFontName = new GString(obj2.getName());
458
0
    }
459
0
    obj2.free();
460
461
    // look for MissingWidth
462
0
    obj1.dictLookup("MissingWidth", &obj2);
463
0
    if (obj2.isNum()) {
464
0
      missingWidth = obj2.getNum();
465
0
    }
466
0
    obj2.free();
467
468
    // get Ascent
469
    // (CapHeight is a little more reliable - so use it if present)
470
0
    obj1.dictLookup("Ascent", &obj2);
471
0
    obj1.dictLookup("CapHeight", &obj3);
472
0
    if (obj2.isNum() || obj3.isNum()) {
473
0
      if (obj2.isNum()) {
474
0
  t = 0.001 * obj2.getNum();
475
  // some broken font descriptors specify a negative ascent
476
0
  if (t < 0) {
477
0
    t = -t;
478
0
  }
479
0
      } else {
480
0
  t = 0;
481
0
      }
482
0
      if (obj3.isNum()) {
483
0
  t2 = 0.001 * obj3.getNum();
484
  // some broken font descriptors specify a negative ascent
485
0
  if (t2 < 0) {
486
0
    t2 = -t2;
487
0
  }
488
0
      } else {
489
0
  t2 = 0;
490
0
      }
491
0
      if (t != 0 && t < 1.9) {
492
0
  declaredAscent = t;
493
0
      }
494
      // if both Ascent and CapHeight are set, use the smaller one
495
      // (because the most common problem is that Ascent is too large)
496
0
      if (t2 != 0 && (t == 0 || t2 < t)) {
497
0
  t = t2;
498
0
      }
499
      // some broken font descriptors set ascent and descent to 0;
500
      // others set it to ridiculous values (e.g., 32768)
501
0
      if (t != 0 && t < 1.9) {
502
0
  ascent = t;
503
0
      }
504
0
    }
505
0
    obj2.free();
506
0
    obj3.free();
507
508
    // get Descent
509
0
    obj1.dictLookup("Descent", &obj2);
510
0
    if (obj2.isNum()) {
511
0
      t = 0.001 * obj2.getNum();
512
      // some broken font descriptors specify a positive descent
513
0
      if (t > 0) {
514
0
  t = -t;
515
0
      }
516
      // some broken font descriptors set ascent and descent to 0
517
0
      if (t != 0 && t > -1.9) {
518
0
  descent = t;
519
0
      }
520
0
    }
521
0
    obj2.free();
522
523
    // font FontBBox
524
0
    if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
525
0
      for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
526
0
  if (obj2.arrayGet(i, &obj3)->isNum()) {
527
0
    fontBBox[i] = 0.001 * obj3.getNum();
528
0
  }
529
0
  obj3.free();
530
0
      }
531
0
    }
532
0
    obj2.free();
533
534
0
  }
535
0
  obj1.free();
536
537
  // scan font name for bold/italic tags and update the flags
538
0
  if (name) {
539
0
    i = name->getLength();
540
0
    if (i > 2 && !strncmp(name->getCString() + i - 2, "MT", 2)) {
541
0
      i -= 2;
542
0
    }
543
0
    if (i > 6 && !strncmp(name->getCString() + i - 6, "Italic", 6)) {
544
0
      flags |= fontItalic;
545
0
      i -= 6;
546
0
    } else if (i > 2 && !strncmp(name->getCString() + i - 2, "It", 2)) {
547
0
      flags |= fontItalic;
548
0
      i -= 2;
549
0
    } else if (i > 7 && !strncmp(name->getCString() + i - 7, "Oblique", 7)) {
550
0
      flags |= fontItalic;
551
0
      i -= 7;
552
0
    }
553
0
    char c = name->getChar(i-1);
554
0
    if (!((c >= 'A' && c <= 'Z') ||
555
0
    (c >= 'a' && c <= 'z') ||
556
0
    (c >= '0' && c <= '9'))) {
557
0
      --i;
558
0
    }
559
0
    if (i > 4 && !strncmp(name->getCString() + i - 4, "Bold", 4)) {
560
0
      flags |= fontBold;
561
0
    }
562
0
  }
563
0
}
564
565
CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
566
0
                CharCodeToUnicode *ctu) {
567
0
  GString *buf;
568
0
  Object obj1;
569
0
  char buf2[4096];
570
0
  int n;
571
572
0
  if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) {
573
0
    obj1.free();
574
0
    return NULL;
575
0
  }
576
0
  buf = new GString();
577
0
  obj1.streamReset();
578
0
  while ((n = obj1.streamGetBlock(buf2, sizeof(buf2))) > 0) {
579
0
    buf->append(buf2, n);
580
0
  }
581
0
  obj1.streamClose();
582
0
  obj1.free();
583
0
  if (ctu) {
584
0
    ctu->mergeCMap(buf, nBits);
585
0
  } else {
586
0
    ctu = CharCodeToUnicode::parseCMap(buf, nBits);
587
0
  }
588
0
  delete buf;
589
0
  hasToUnicode = gTrue;
590
0
  return ctu;
591
0
}
592
593
0
GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) {
594
0
  GfxFontLoc *fontLoc;
595
0
  SysFontType sysFontType;
596
0
  FoFiIdentifierType fft;
597
0
  GString *path, *base14Name, *substName;
598
0
  PSFontParam16 *psFont16;
599
0
  Object refObj, embFontObj;
600
0
  int substIdx, fontNum;
601
0
  double oblique;
602
0
  GBool embed;
603
604
0
  if (type == fontType3) {
605
0
    return NULL;
606
0
  }
607
608
  //----- embedded font
609
0
  if (embFontID.num >= 0) {
610
0
    embed = gTrue;
611
0
    refObj.initRef(embFontID.num, embFontID.gen);
612
0
    refObj.fetch(xref, &embFontObj);
613
0
    if (!embFontObj.isStream()) {
614
0
      error(errSyntaxError, -1, "Embedded font object is wrong type");
615
0
      embed = gFalse;
616
0
    }
617
0
    embFontObj.free();
618
0
    refObj.free();
619
0
    if (embed) {
620
0
      if (ps) {
621
0
  switch (type) {
622
0
  case fontType1:
623
0
  case fontType1C:
624
0
  case fontType1COT:
625
0
    embed = globalParams->getPSEmbedType1();
626
0
    break;
627
0
  case fontTrueType:
628
0
  case fontTrueTypeOT:
629
0
    embed = globalParams->getPSEmbedTrueType();
630
0
    break;
631
0
  case fontCIDType0C:
632
0
  case fontCIDType0COT:
633
0
    embed = globalParams->getPSEmbedCIDPostScript();
634
0
    break;
635
0
  case fontCIDType2:
636
0
  case fontCIDType2OT:
637
0
    embed = globalParams->getPSEmbedCIDTrueType();
638
0
    break;
639
0
  default:
640
0
    break;
641
0
  }
642
0
      }
643
0
      if (embed) {
644
0
  fontLoc = new GfxFontLoc();
645
0
  fontLoc->locType = gfxFontLocEmbedded;
646
0
  fontLoc->fontType = type;
647
0
  fontLoc->embFontID = embFontID;
648
0
  return fontLoc;
649
0
      }
650
0
    }
651
0
  }
652
653
  //----- PS passthrough
654
0
  if (ps && name && !isCIDFont() && globalParams->getPSFontPassthrough()) {
655
0
    fontLoc = new GfxFontLoc();
656
0
    fontLoc->locType = gfxFontLocResident;
657
0
    fontLoc->fontType = fontType1;
658
0
    fontLoc->path = name->copy();
659
0
    return fontLoc;
660
0
  }
661
662
  //----- external font file (fontFile, fontDir)
663
0
  if (name && (path = globalParams->findFontFile(name))) {
664
0
    if ((fontLoc = getExternalFont(path, 0, 0, isCIDFont()))) {
665
0
      return fontLoc;
666
0
    }
667
0
  }
668
669
  //----- PS resident Base-14 font
670
0
  if (ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
671
0
    fontLoc = new GfxFontLoc();
672
0
    fontLoc->locType = gfxFontLocResident;
673
0
    fontLoc->fontType = fontType1;
674
0
    fontLoc->path = new GString(((Gfx8BitFont *)this)->base14->base14Name);
675
0
    return fontLoc;
676
0
  }
677
678
  //----- external font file for Base-14 font
679
0
  if (!ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
680
0
    base14Name = new GString(((Gfx8BitFont *)this)->base14->base14Name);
681
0
    path = globalParams->findBase14FontFile(base14Name, &fontNum, &oblique);
682
0
    delete base14Name;
683
0
    if (path && (fontLoc = getExternalFont(path, fontNum, oblique, gFalse))) {
684
0
      return fontLoc;
685
0
    }
686
0
  }
687
688
  //----- system font
689
0
  if (name && (path = globalParams->findSystemFontFile(name, &sysFontType,
690
0
                   &fontNum))) {
691
0
    fontLoc = new GfxFontLoc();
692
0
    fontLoc->locType = gfxFontLocExternal;
693
0
    fontLoc->path = path;
694
0
    fontLoc->fontNum = fontNum;
695
0
    if (isCIDFont()) {
696
0
      if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
697
0
  fontLoc->fontType = fontCIDType2;
698
0
  return fontLoc;
699
0
      } else if (sysFontType == sysFontOTF) {
700
0
  fft = FoFiIdentifier::identifyFile(fontLoc->path->getCString());
701
0
  if (fft == fofiIdOpenTypeCFFCID) {
702
0
    fontLoc->fontType = fontCIDType0COT;
703
0
    return fontLoc;
704
0
  } else if (fft == fofiIdTrueType) {
705
0
    fontLoc->fontType = fontCIDType2;
706
0
    return fontLoc;
707
0
  }
708
0
      }
709
0
    } else {
710
0
      if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
711
0
  fontLoc->fontType = fontTrueType;
712
0
  return fontLoc;
713
0
      } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) {
714
0
  fontLoc->fontType = fontType1;
715
0
  return fontLoc;
716
0
      } else if (sysFontType == sysFontOTF) {
717
0
  fft = FoFiIdentifier::identifyFile(fontLoc->path->getCString());
718
0
  if (fft == fofiIdOpenTypeCFF8Bit) {
719
0
    fontLoc->fontType = fontType1COT;
720
0
    return fontLoc;
721
0
  } else if (fft == fofiIdTrueType) {
722
0
    fontLoc->fontType = fontTrueTypeOT;
723
0
    return fontLoc;
724
0
  }
725
0
      }
726
0
    }
727
0
    delete fontLoc;
728
0
  }
729
730
0
  if (!isCIDFont()) {
731
732
    //----- 8-bit PS resident font
733
0
    if (ps) {
734
0
      if (name && (path = globalParams->getPSResidentFont(name))) {
735
0
  fontLoc = new GfxFontLoc();
736
0
  fontLoc->locType = gfxFontLocResident;
737
0
  fontLoc->fontType = fontType1;
738
0
  fontLoc->path = path;
739
0
  return fontLoc;
740
0
      }
741
0
    }
742
743
    //----- 8-bit font substitution
744
0
    if (flags & fontFixedWidth) {
745
0
      substIdx = 0;
746
0
    } else if (flags & fontSerif) {
747
0
      substIdx = 8;
748
0
    } else {
749
0
      substIdx = 4;
750
0
    }
751
0
    if (isBold()) {
752
0
      substIdx += 2;
753
0
    }
754
0
    if (isItalic()) {
755
0
      substIdx += 1;
756
0
    }
757
0
    substName = new GString(base14SubstFonts[substIdx]);
758
0
    if (ps) {
759
0
      error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
760
0
      base14SubstFonts[substIdx], name);
761
0
      fontLoc = new GfxFontLoc();
762
0
      fontLoc->locType = gfxFontLocResident;
763
0
      fontLoc->fontType = fontType1;
764
0
      fontLoc->path = substName;
765
0
      fontLoc->substIdx = substIdx;
766
0
      return fontLoc;
767
0
    } else {
768
0
      path = globalParams->findBase14FontFile(substName, &fontNum, &oblique);
769
0
      delete substName;
770
0
      if (path) {
771
0
  if ((fontLoc = getExternalFont(path, fontNum, oblique, gFalse))) {
772
0
    error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
773
0
    base14SubstFonts[substIdx], name);
774
0
    fontLoc->substIdx = substIdx;
775
0
    return fontLoc;
776
0
  }
777
0
      }
778
0
    }
779
780
    // failed to find a substitute font
781
0
    return NULL;
782
0
  }
783
784
  //----- 16-bit PS resident font
785
0
  if (ps && name && ((psFont16 = globalParams->getPSResidentFont16(
786
0
           name,
787
0
           ((GfxCIDFont *)this)->getWMode())))) {
788
0
    fontLoc = new GfxFontLoc();
789
0
    fontLoc->locType = gfxFontLocResident;
790
0
    fontLoc->fontType = fontCIDType0; // this is not used
791
0
    fontLoc->path = psFont16->psFontName->copy();
792
0
    fontLoc->encoding = psFont16->encoding->copy();
793
0
    fontLoc->wMode = psFont16->wMode;
794
0
    return fontLoc;
795
0
  }
796
0
  if (ps && ((psFont16 = globalParams->getPSResidentFontCC(
797
0
         ((GfxCIDFont *)this)->getCollection(),
798
0
         ((GfxCIDFont *)this)->getWMode())))) {
799
0
    error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
800
0
    psFont16->psFontName, name);
801
0
    fontLoc = new GfxFontLoc();
802
0
    fontLoc->locType = gfxFontLocResident;
803
0
    fontLoc->fontType = fontCIDType0; // this is not used
804
0
    fontLoc->path = psFont16->psFontName->copy();
805
0
    fontLoc->encoding = psFont16->encoding->copy();
806
0
    fontLoc->wMode = psFont16->wMode;
807
0
    return fontLoc;
808
0
  }
809
810
  //----- CID font substitution
811
0
  if ((path = globalParams->findCCFontFile(
812
0
        ((GfxCIDFont *)this)->getCollection()))) {
813
0
    if ((fontLoc = getExternalFont(path, 0, 0, gTrue))) {
814
0
      error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
815
0
      fontLoc->path, name);
816
0
      return fontLoc;
817
0
    }
818
0
  }
819
820
  // failed to find a substitute font
821
0
  return NULL;
822
0
}
823
824
0
GfxFontLoc *GfxFont::locateBase14Font(GString *base14Name) {
825
0
  GString *path;
826
0
  int fontNum;
827
0
  double oblique;
828
829
0
  path = globalParams->findBase14FontFile(base14Name, &fontNum, &oblique);
830
0
  if (!path) {
831
0
    return NULL;
832
0
  }
833
0
  return getExternalFont(path, fontNum, oblique, gFalse);
834
0
}
835
836
GfxFontLoc *GfxFont::getExternalFont(GString *path, int fontNum,
837
0
             double oblique, GBool cid) {
838
0
  FoFiIdentifierType fft;
839
0
  GfxFontType fontType;
840
0
  GfxFontLoc *fontLoc;
841
842
0
  fft = FoFiIdentifier::identifyFile(path->getCString());
843
0
  switch (fft) {
844
0
  case fofiIdType1PFA:
845
0
  case fofiIdType1PFB:
846
0
    fontType = fontType1;
847
0
    break;
848
0
  case fofiIdCFF8Bit:
849
0
    fontType = fontType1C;
850
0
    break;
851
0
  case fofiIdCFFCID:
852
0
    fontType = fontCIDType0C;
853
0
    break;
854
0
  case fofiIdTrueType:
855
0
  case fofiIdTrueTypeCollection:
856
0
    fontType = cid ? fontCIDType2 : fontTrueType;
857
0
    break;
858
0
  case fofiIdOpenTypeCFF8Bit:
859
0
    fontType = fontType1COT;
860
0
    break;
861
0
  case fofiIdOpenTypeCFFCID:
862
0
    fontType = fontCIDType0COT;
863
0
    break;
864
0
  case fofiIdDfont:
865
0
    fontType = cid ? fontCIDType2 : fontTrueType;
866
0
    break;
867
0
  case fofiIdUnknown:
868
0
  case fofiIdError:
869
0
  default:
870
0
    fontType = fontUnknownType;
871
0
    break;
872
0
  }
873
0
  if (fontType == fontUnknownType ||
874
0
      (cid ? (fontType < fontCIDType0)
875
0
           : (fontType >= fontCIDType0))) {
876
0
    delete path;
877
0
    return NULL;
878
0
  }
879
0
  fontLoc = new GfxFontLoc();
880
0
  fontLoc->locType = gfxFontLocExternal;
881
0
  fontLoc->fontType = fontType;
882
0
  fontLoc->path = path;
883
0
  fontLoc->fontNum = fontNum;
884
0
  fontLoc->oblique = oblique;
885
0
  return fontLoc;
886
0
}
887
888
0
char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
889
0
  char *buf;
890
0
  Object obj1, obj2;
891
0
  Stream *str;
892
0
  int size, n;
893
894
0
  obj1.initRef(embFontID.num, embFontID.gen);
895
0
  obj1.fetch(xref, &obj2);
896
0
  if (!obj2.isStream()) {
897
0
    error(errSyntaxError, -1, "Embedded font file is not a stream");
898
0
    obj2.free();
899
0
    obj1.free();
900
0
    embFontID.num = -1;
901
0
    return NULL;
902
0
  }
903
0
  str = obj2.getStream();
904
905
0
  size = 4096;
906
0
  buf = (char *)gmalloc(size);
907
0
  *len = 0;
908
0
  str->reset();
909
0
  do {
910
0
    if (*len > size - 4096) {
911
0
      if (size > INT_MAX / 2) {
912
0
  error(errSyntaxError, -1, "Embedded font file is too large");
913
0
  break;
914
0
      }
915
0
      size *= 2;
916
0
      buf = (char *)grealloc(buf, size);
917
0
    }
918
0
    n = str->getBlock(buf + *len, 4096);
919
0
    *len += n;
920
0
  } while (n == 4096);
921
0
  str->close();
922
923
0
  obj2.free();
924
0
  obj1.free();
925
926
0
  return buf;
927
0
}
928
929
//------------------------------------------------------------------------
930
// Gfx8BitFont
931
//------------------------------------------------------------------------
932
933
Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA,
934
       GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
935
0
  GfxFont(tagA, idA, nameA, typeA, embFontIDA)
936
0
{
937
0
  GString *name2;
938
0
  BuiltinFont *builtinFont;
939
0
  const char **baseEnc;
940
0
  char *buf;
941
0
  int len;
942
0
  FoFiType1 *ffT1;
943
0
  FoFiType1C *ffT1C;
944
0
  int code, code2;
945
0
  char *charName;
946
0
  GBool missing, hex;
947
0
  Unicode toUnicode[256];
948
0
  CharCodeToUnicode *utu, *ctu2;
949
0
  Unicode uBuf[8];
950
0
  double mul;
951
0
  int firstChar, lastChar;
952
0
  Gushort w;
953
0
  Object obj1, obj2, obj3;
954
0
  int n, i, a, b, m;
955
956
0
  ctu = NULL;
957
958
  // do font name substitution for various aliases of the Base 14 font
959
  // names
960
0
  base14 = NULL;
961
0
  if (name) {
962
0
    name2 = name->copy();
963
0
    i = 0;
964
0
    while (i < name2->getLength()) {
965
0
      if (name2->getChar(i) == ' ') {
966
0
  name2->del(i);
967
0
      } else {
968
0
  ++i;
969
0
      }
970
0
    }
971
0
    a = 0;
972
0
    b = sizeof(base14FontMap) / sizeof(Base14FontMapEntry);
973
    // invariant: base14FontMap[a].altName <= name2 < base14FontMap[b].altName
974
0
    while (b - a > 1) {
975
0
      m = (a + b) / 2;
976
0
      if (name2->cmp(base14FontMap[m].altName) >= 0) {
977
0
  a = m;
978
0
      } else {
979
0
  b = m;
980
0
      }
981
0
    }
982
0
    if (!name2->cmp(base14FontMap[a].altName)) {
983
0
      base14 = &base14FontMap[a];
984
0
    }
985
0
    delete name2;
986
0
  }
987
988
  // is it a built-in font?
989
0
  builtinFont = NULL;
990
0
  if (base14) {
991
0
    for (i = 0; i < nBuiltinFonts; ++i) {
992
0
      if (!strcmp(base14->base14Name, builtinFonts[i].name)) {
993
0
  builtinFont = &builtinFonts[i];
994
0
  break;
995
0
      }
996
0
    }
997
0
  }
998
999
  // default ascent/descent values
1000
0
  if (builtinFont) {
1001
0
    missingWidth = builtinFont->missingWidth;
1002
0
    ascent = 0.001 * builtinFont->ascent;
1003
0
    descent = 0.001 * builtinFont->descent;
1004
0
    declaredAscent = ascent;
1005
0
    fontBBox[0] = 0.001 * builtinFont->bbox[0];
1006
0
    fontBBox[1] = 0.001 * builtinFont->bbox[1];
1007
0
    fontBBox[2] = 0.001 * builtinFont->bbox[2];
1008
0
    fontBBox[3] = 0.001 * builtinFont->bbox[3];
1009
0
  } else {
1010
0
    missingWidth = 0;
1011
0
    ascent = 0.75;
1012
0
    descent = -0.25;
1013
0
    declaredAscent = ascent;
1014
0
    fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
1015
0
  }
1016
1017
  // get info from font descriptor
1018
0
  readFontDescriptor(xref, fontDict);
1019
1020
  // for Base-14 fonts (even if embedded), don't trust the
1021
  // ascent/descent/bbox values from the font descriptor
1022
0
  if (builtinFont) {
1023
0
    ascent = 0.001 * builtinFont->ascent;
1024
0
    descent = 0.001 * builtinFont->descent;
1025
0
    declaredAscent = ascent;
1026
0
    fontBBox[0] = 0.001 * builtinFont->bbox[0];
1027
0
    fontBBox[1] = 0.001 * builtinFont->bbox[1];
1028
0
    fontBBox[2] = 0.001 * builtinFont->bbox[2];
1029
0
    fontBBox[3] = 0.001 * builtinFont->bbox[3];
1030
0
  }
1031
1032
  // get font matrix
1033
0
  fontMat[0] = fontMat[3] = 1;
1034
0
  fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
1035
0
  if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
1036
0
    for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
1037
0
      if (obj1.arrayGet(i, &obj2)->isNum()) {
1038
0
  fontMat[i] = obj2.getNum();
1039
0
      }
1040
0
      obj2.free();
1041
0
    }
1042
0
  }
1043
0
  obj1.free();
1044
1045
  // get Type 3 bounding box, font definition, and resources
1046
0
  if (type == fontType3) {
1047
0
    if (fontDict->lookup("FontBBox", &obj1)->isArray()) {
1048
0
      for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) {
1049
0
  if (obj1.arrayGet(i, &obj2)->isNum()) {
1050
0
    fontBBox[i] = obj2.getNum();
1051
0
  }
1052
0
  obj2.free();
1053
0
      }
1054
0
    }
1055
0
    obj1.free();
1056
0
    if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) {
1057
0
      error(errSyntaxError, -1,
1058
0
      "Missing or invalid CharProcs dictionary in Type 3 font");
1059
0
      charProcs.free();
1060
0
    }
1061
0
    if (!fontDict->lookup("Resources", &resources)->isDict()) {
1062
0
      resources.free();
1063
0
    }
1064
0
  }
1065
1066
  //----- build the font encoding -----
1067
1068
  // Encodings start with a base encoding, which can come from
1069
  // (in order of priority):
1070
  //   1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
1071
  //        - MacRoman / MacExpert / WinAnsi / Standard
1072
  //   2. embedded or external font file
1073
  //   3. default:
1074
  //        - builtin --> builtin encoding
1075
  //        - TrueType --> WinAnsiEncoding
1076
  //        - others --> StandardEncoding
1077
  // and then add a list of differences (if any) from
1078
  // FontDict.Encoding.Differences.
1079
1080
  // check FontDict for base encoding
1081
0
  hasEncoding = gFalse;
1082
0
  usesMacRomanEnc = gFalse;
1083
0
  baseEnc = NULL;
1084
0
  baseEncFromFontFile = gFalse;
1085
0
  fontDict->lookup("Encoding", &obj1);
1086
0
  if (obj1.isDict()) {
1087
0
    obj1.dictLookup("BaseEncoding", &obj2);
1088
0
    if (obj2.isName("MacRomanEncoding")) {
1089
0
      hasEncoding = gTrue;
1090
0
      usesMacRomanEnc = gTrue;
1091
0
      baseEnc = macRomanEncoding;
1092
0
    } else if (obj2.isName("MacExpertEncoding")) {
1093
0
      hasEncoding = gTrue;
1094
0
      baseEnc = macExpertEncoding;
1095
0
    } else if (obj2.isName("WinAnsiEncoding")) {
1096
0
      hasEncoding = gTrue;
1097
0
      baseEnc = winAnsiEncoding;
1098
0
    }
1099
0
    obj2.free();
1100
0
  } else if (obj1.isName("MacRomanEncoding")) {
1101
0
    hasEncoding = gTrue;
1102
0
    usesMacRomanEnc = gTrue;
1103
0
    baseEnc = macRomanEncoding;
1104
0
  } else if (obj1.isName("MacExpertEncoding")) {
1105
0
    hasEncoding = gTrue;
1106
0
    baseEnc = macExpertEncoding;
1107
0
  } else if (obj1.isName("WinAnsiEncoding")) {
1108
0
    hasEncoding = gTrue;
1109
0
    baseEnc = winAnsiEncoding;
1110
0
  }
1111
1112
  // check embedded font file for base encoding
1113
  // (only for Type 1 fonts - trying to get an encoding out of a
1114
  // TrueType font is a losing proposition)
1115
0
  ffT1 = NULL;
1116
0
  ffT1C = NULL;
1117
0
  buf = NULL;
1118
0
  if (type == fontType1 && embFontID.num >= 0) {
1119
0
    if ((buf = readEmbFontFile(xref, &len))) {
1120
0
      if ((ffT1 = FoFiType1::make(buf, len))) {
1121
0
  if (ffT1->getName()) {
1122
0
    if (embFontName) {
1123
0
      delete embFontName;
1124
0
    }
1125
0
    embFontName = new GString(ffT1->getName());
1126
0
  }
1127
0
  if (!baseEnc) {
1128
0
    baseEnc = (const char **)ffT1->getEncoding();
1129
0
    baseEncFromFontFile = gTrue;
1130
0
  }
1131
0
      }
1132
0
      gfree(buf);
1133
0
    }
1134
0
  } else if (type == fontType1C && embFontID.num >= 0) {
1135
0
    if ((buf = readEmbFontFile(xref, &len))) {
1136
0
      if ((ffT1C = FoFiType1C::make(buf, len))) {
1137
0
  if (ffT1C->getName()) {
1138
0
    if (embFontName) {
1139
0
      delete embFontName;
1140
0
    }
1141
0
    embFontName = new GString(ffT1C->getName());
1142
0
  }
1143
0
  if (!baseEnc) {
1144
0
    baseEnc = (const char **)ffT1C->getEncoding();
1145
0
    baseEncFromFontFile = gTrue;
1146
0
  }
1147
0
      }
1148
0
      gfree(buf);
1149
0
    }
1150
0
  }
1151
1152
  // get default base encoding
1153
0
  if (!baseEnc) {
1154
0
    if (builtinFont && embFontID.num < 0) {
1155
0
      baseEnc = builtinFont->defaultBaseEnc;
1156
0
      hasEncoding = gTrue;
1157
0
    } else if (type == fontTrueType) {
1158
0
      baseEnc = winAnsiEncoding;
1159
0
    } else {
1160
0
      baseEnc = standardEncoding;
1161
0
    }
1162
0
  }
1163
1164
  // copy the base encoding
1165
0
  for (i = 0; i < 256; ++i) {
1166
0
    enc[i] = (char *)baseEnc[i];
1167
0
    if ((encFree[i] = (char)baseEncFromFontFile) && enc[i]) {
1168
0
      enc[i] = copyString(baseEnc[i]);
1169
0
    }
1170
0
  }
1171
1172
  // some Type 1C font files have empty encodings, which can break the
1173
  // T1C->T1 conversion (since the 'seac' operator depends on having
1174
  // the accents in the encoding), so we fill in any gaps from
1175
  // StandardEncoding
1176
0
  if (type == fontType1C && embFontID.num >= 0 && baseEncFromFontFile) {
1177
0
    for (i = 0; i < 256; ++i) {
1178
0
      if (!enc[i] && standardEncoding[i]) {
1179
0
  enc[i] = (char *)standardEncoding[i];
1180
0
  encFree[i] = gFalse;
1181
0
      }
1182
0
    }
1183
0
  }
1184
1185
  // merge differences into encoding
1186
0
  if (obj1.isDict()) {
1187
0
    obj1.dictLookup("Differences", &obj2);
1188
0
    if (obj2.isArray()) {
1189
0
      hasEncoding = gTrue;
1190
0
      code = 0;
1191
0
      for (i = 0; i < obj2.arrayGetLength(); ++i) {
1192
0
  obj2.arrayGet(i, &obj3);
1193
0
  if (obj3.isInt()) {
1194
0
    code = obj3.getInt();
1195
0
  } else if (obj3.isName()) {
1196
0
    if (code >= 0 && code < 256) {
1197
0
      if (encFree[code]) {
1198
0
        gfree(enc[code]);
1199
0
      }
1200
0
      enc[code] = copyString(obj3.getName());
1201
0
      encFree[code] = gTrue;
1202
0
    }
1203
0
    ++code;
1204
0
  } else {
1205
0
    error(errSyntaxError, -1,
1206
0
    "Wrong type in font encoding resource differences ({0:s})",
1207
0
    obj3.getTypeName());
1208
0
  }
1209
0
  obj3.free();
1210
0
      }
1211
0
    }
1212
0
    obj2.free();
1213
0
  }
1214
0
  obj1.free();
1215
0
  if (ffT1) {
1216
0
    delete ffT1;
1217
0
  }
1218
0
  if (ffT1C) {
1219
0
    delete ffT1C;
1220
0
  }
1221
1222
  //----- build the mapping to Unicode -----
1223
1224
  // pass 1: use the name-to-Unicode mapping table
1225
0
  missing = hex = gFalse;
1226
0
  for (code = 0; code < 256; ++code) {
1227
0
    if ((charName = enc[code])) {
1228
0
      if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) &&
1229
0
    strcmp(charName, ".notdef")) {
1230
  // if it wasn't in the name-to-Unicode table, check for a
1231
  // name that looks like 'Axx' or 'xx', where 'A' is any letter
1232
  // and 'xx' is two hex digits
1233
0
  if ((strlen(charName) == 3 &&
1234
0
       isalpha(charName[0] & 0xff) &&
1235
0
       isxdigit(charName[1] & 0xff) && isxdigit(charName[2] & 0xff) &&
1236
0
       ((charName[1] >= 'a' && charName[1] <= 'f') ||
1237
0
        (charName[1] >= 'A' && charName[1] <= 'F') ||
1238
0
        (charName[2] >= 'a' && charName[2] <= 'f') ||
1239
0
        (charName[2] >= 'A' && charName[2] <= 'F'))) ||
1240
0
      (strlen(charName) == 2 &&
1241
0
       isxdigit(charName[0] & 0xff) && isxdigit(charName[1] & 0xff) &&
1242
0
       ((charName[0] >= 'a' && charName[0] <= 'f') ||
1243
0
        (charName[0] >= 'A' && charName[0] <= 'F') ||
1244
0
        (charName[1] >= 'a' && charName[1] <= 'f') ||
1245
0
        (charName[1] >= 'A' && charName[1] <= 'F')))) {
1246
0
    hex = gTrue;
1247
0
  }
1248
0
  missing = gTrue;
1249
0
      }
1250
0
    } else {
1251
0
      toUnicode[code] = 0;
1252
0
    }
1253
0
  }
1254
1255
  // pass 2: try to fill in the missing chars, looking for names of
1256
  // any of the following forms:
1257
  // - 'xx'
1258
  // - 'Axx'
1259
  // - 'nn'
1260
  // - 'Ann'
1261
  // - 'ABnn'
1262
  // - 'unixxxx' (possibly followed by garbage - some Arabic files
1263
  //             use 'uni0628.medi', etc.)
1264
  // where 'A' and 'B' are any letters, 'xx' is two hex digits, 'xxxx'
1265
  // is four hex digits, and 'nn' is 2-4 decimal digits
1266
0
  usedNumericHeuristic = gFalse;
1267
0
  if (missing && globalParams->getMapNumericCharNames()) {
1268
0
    for (code = 0; code < 256; ++code) {
1269
0
      if ((charName = enc[code]) && !toUnicode[code] &&
1270
0
    strcmp(charName, ".notdef")) {
1271
0
  n = (int)strlen(charName);
1272
0
  code2 = -1;
1273
0
  if (hex && n == 3 && isalpha(charName[0] & 0xff) &&
1274
0
      isxdigit(charName[1] & 0xff) && isxdigit(charName[2] & 0xff)) {
1275
0
    sscanf(charName+1, "%x", &code2);
1276
0
  } else if (hex && n == 2 &&
1277
0
       isxdigit(charName[0] & 0xff) &&
1278
0
       isxdigit(charName[1] & 0xff)) {
1279
0
    sscanf(charName, "%x", &code2);
1280
0
  } else if (!hex && n >= 2 && n <= 4 &&
1281
0
       isdigit(charName[0] & 0xff) && isdigit(charName[1] & 0xff)) {
1282
0
    code2 = atoi(charName);
1283
0
  } else if (n >= 3 && n <= 5 &&
1284
0
       isdigit(charName[1] & 0xff) && isdigit(charName[2] & 0xff)) {
1285
0
    code2 = atoi(charName+1);
1286
0
  } else if (n >= 4 && n <= 6 &&
1287
0
       isdigit(charName[2] & 0xff) && isdigit(charName[3] & 0xff)) {
1288
0
    code2 = atoi(charName+2);
1289
0
  } else if (n >= 7 && charName[0] == 'u' && charName[1] == 'n' &&
1290
0
       charName[2] == 'i' &&
1291
0
       isxdigit(charName[3] & 0xff) &&
1292
0
       isxdigit(charName[4] & 0xff) &&
1293
0
       isxdigit(charName[5] & 0xff) &&
1294
0
       isxdigit(charName[6] & 0xff)) {
1295
0
    sscanf(charName + 3, "%x", &code2);
1296
0
  }
1297
0
  if (code2 >= 0 && code2 <= 0xffff) {
1298
0
    toUnicode[code] = (Unicode)code2;
1299
0
    usedNumericHeuristic = gTrue;
1300
0
  }
1301
0
      }
1302
0
    }
1303
1304
  // if the 'mapUnknownCharNames' flag is set, do a simple pass-through
1305
  // mapping for unknown character names
1306
0
  } else if (missing && globalParams->getMapUnknownCharNames()) {
1307
0
    for (code = 0; code < 256; ++code) {
1308
0
      if (!toUnicode[code]) {
1309
0
  toUnicode[code] = code;
1310
0
      }
1311
0
    }
1312
0
  }
1313
1314
  // construct the char code -> Unicode mapping object
1315
0
  ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode);
1316
1317
  // merge in a ToUnicode CMap, if there is one -- this overwrites
1318
  // existing entries in ctu, i.e., the ToUnicode CMap takes
1319
  // precedence, but the other encoding info is allowed to fill in any
1320
  // holes
1321
0
  readToUnicodeCMap(fontDict, 8, ctu);
1322
1323
  // look for a Unicode-to-Unicode mapping
1324
0
  if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
1325
0
    for (i = 0; i < 256; ++i) {
1326
0
      toUnicode[i] = 0;
1327
0
    }
1328
0
    ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode);
1329
0
    for (i = 0; i < 256; ++i) {
1330
0
      n = ctu->mapToUnicode((CharCode)i, uBuf, 8);
1331
0
      if (n >= 1) {
1332
0
  n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
1333
0
  if (n >= 1) {
1334
0
    ctu2->setMapping((CharCode)i, uBuf, n);
1335
0
  }
1336
0
      }
1337
0
    }
1338
0
    utu->decRefCnt();
1339
0
    delete ctu;
1340
0
    ctu = ctu2;
1341
0
  }
1342
1343
  //----- get the character widths -----
1344
1345
  // initialize all widths
1346
0
  for (code = 0; code < 256; ++code) {
1347
0
    widths[code] = missingWidth * 0.001;
1348
0
  }
1349
1350
  // use widths from font dict, if present
1351
0
  fontDict->lookup("FirstChar", &obj1);
1352
0
  firstChar = obj1.isInt() ? obj1.getInt() : 0;
1353
0
  obj1.free();
1354
0
  if (firstChar < 0 || firstChar > 255) {
1355
0
    firstChar = 0;
1356
0
  }
1357
0
  fontDict->lookup("LastChar", &obj1);
1358
0
  lastChar = obj1.isInt() ? obj1.getInt() : 255;
1359
0
  obj1.free();
1360
0
  if (lastChar < 0 || lastChar > 255) {
1361
0
    lastChar = 255;
1362
0
  }
1363
0
  mul = (type == fontType3) ? fontMat[0] : 0.001;
1364
0
  fontDict->lookup("Widths", &obj1);
1365
0
  if (obj1.isArray()) {
1366
0
    flags |= fontFixedWidth;
1367
0
    if (obj1.arrayGetLength() < lastChar - firstChar + 1) {
1368
0
      lastChar = firstChar + obj1.arrayGetLength() - 1;
1369
0
    }
1370
0
    for (code = firstChar; code <= lastChar; ++code) {
1371
0
      obj1.arrayGet(code - firstChar, &obj2);
1372
0
      if (obj2.isNum()) {
1373
0
  widths[code] = obj2.getNum() * mul;
1374
0
  if (fabs(widths[code] - widths[firstChar]) > 0.00001) {
1375
0
    flags &= ~fontFixedWidth;
1376
0
  }
1377
0
      }
1378
0
      obj2.free();
1379
0
    }
1380
1381
  // use widths from built-in font
1382
0
  } else if (builtinFont) {
1383
    // this is a kludge for broken PDF files that encode char 32
1384
    // as .notdef
1385
0
    if (builtinFont->widths->getWidth("space", &w)) {
1386
0
      widths[32] = 0.001 * w;
1387
0
    }
1388
0
    for (code = 0; code < 256; ++code) {
1389
0
      if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
1390
0
  widths[code] = 0.001 * w;
1391
0
      }
1392
0
    }
1393
1394
  // couldn't find widths -- use defaults 
1395
0
  } else {
1396
    // this is technically an error -- the Widths entry is required
1397
    // for all but the Base-14 fonts -- but certain PDF generators
1398
    // apparently don't include widths for Arial and TimesNewRoman
1399
0
    if (isFixedWidth()) {
1400
0
      i = 0;
1401
0
    } else if (isSerif()) {
1402
0
      i = 8;
1403
0
    } else {
1404
0
      i = 4;
1405
0
    }
1406
0
    if (isBold()) {
1407
0
      i += 2;
1408
0
    }
1409
0
    if (isItalic()) {
1410
0
      i += 1;
1411
0
    }
1412
0
    builtinFont = builtinFontSubst[i];
1413
    // this is a kludge for broken PDF files that encode char 32
1414
    // as .notdef
1415
0
    if (builtinFont->widths->getWidth("space", &w)) {
1416
0
      widths[32] = 0.001 * w;
1417
0
    }
1418
0
    for (code = 0; code < 256; ++code) {
1419
0
      if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
1420
0
  widths[code] = 0.001 * w;
1421
0
      }
1422
0
    }
1423
0
  }
1424
0
  obj1.free();
1425
1426
0
  ok = gTrue;
1427
0
}
1428
1429
0
Gfx8BitFont::~Gfx8BitFont() {
1430
0
  int i;
1431
1432
0
  for (i = 0; i < 256; ++i) {
1433
0
    if (encFree[i] && enc[i]) {
1434
0
      gfree(enc[i]);
1435
0
    }
1436
0
  }
1437
0
  ctu->decRefCnt();
1438
0
  if (charProcs.isDict()) {
1439
0
    charProcs.free();
1440
0
  }
1441
0
  if (resources.isDict()) {
1442
0
    resources.free();
1443
0
  }
1444
0
}
1445
1446
int Gfx8BitFont::getNextChar(char *s, int len, CharCode *code,
1447
           Unicode *u, int uSize, int *uLen,
1448
0
           double *dx, double *dy, double *ox, double *oy) {
1449
0
  CharCode c;
1450
1451
0
  *code = c = (CharCode)(*s & 0xff);
1452
0
  *uLen = ctu->mapToUnicode(c, u, uSize);
1453
0
  *dx = widths[c];
1454
0
  *dy = *ox = *oy = 0;
1455
0
  return 1;
1456
0
}
1457
1458
0
CharCodeToUnicode *Gfx8BitFont::getToUnicode() {
1459
0
  ctu->incRefCnt();
1460
0
  return ctu;
1461
0
}
1462
1463
0
int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
1464
0
  int *map;
1465
0
  int cmapPlatform, cmapEncoding;
1466
0
  int unicodeCmap, macRomanCmap, macUnicodeCmap, msSymbolCmap, cmap;
1467
0
  GBool nonsymbolic, useMacRoman, useUnicode;
1468
0
  char *charName;
1469
0
  Unicode u;
1470
0
  int code, i, n;
1471
1472
0
  map = (int *)gmallocn(256, sizeof(int));
1473
0
  for (i = 0; i < 256; ++i) {
1474
0
    map[i] = 0;
1475
0
  }
1476
1477
  // This is based on the cmap/encoding selection algorithm in the PDF
1478
  // 2.0 spec, but with some differences to match up with Adobe's
1479
  // behavior.
1480
0
  unicodeCmap = macRomanCmap = macUnicodeCmap = msSymbolCmap = -1;
1481
0
  for (i = 0; i < ff->getNumCmaps(); ++i) {
1482
0
    cmapPlatform = ff->getCmapPlatform(i);
1483
0
    cmapEncoding = ff->getCmapEncoding(i);
1484
0
    if (cmapPlatform == 3 && cmapEncoding == 1) {
1485
0
      unicodeCmap = i;
1486
0
    } else if (cmapPlatform == 1 && cmapEncoding == 0) {
1487
0
      macRomanCmap = i;
1488
0
    } else if (cmapPlatform == 0 && cmapEncoding <= 4) {
1489
0
      macUnicodeCmap = i;
1490
0
    } else if (cmapPlatform == 3 && cmapEncoding == 0) {
1491
0
      msSymbolCmap = i;
1492
0
    }
1493
0
  }
1494
0
  useMacRoman = gFalse;
1495
0
  useUnicode = gFalse;
1496
0
  nonsymbolic = !(flags & fontSymbolic);
1497
0
  if (embFontID.num < 0 && hasEncoding && unicodeCmap >= 0) { 
1498
0
    cmap = unicodeCmap;
1499
0
    useUnicode = gTrue;
1500
0
  } else if (!nonsymbolic && msSymbolCmap >= 0) {
1501
0
    cmap = msSymbolCmap;
1502
0
  } else if (unicodeCmap >= 0) {
1503
0
    cmap = unicodeCmap;
1504
0
    useUnicode = nonsymbolic;
1505
0
  } else if (usesMacRomanEnc && macRomanCmap >= 0) {
1506
    // MacRoman cmap has higher precedence than Mac Unicode only if
1507
    // the font uses the MacRoman encoding
1508
0
    cmap = macRomanCmap;
1509
0
    useMacRoman = gTrue;
1510
0
  } else if (macUnicodeCmap >= 0) {
1511
0
    cmap = macUnicodeCmap;
1512
0
    useUnicode = nonsymbolic;
1513
0
  } else if (macRomanCmap >= 0) {
1514
0
    cmap = macRomanCmap;
1515
0
    useMacRoman = nonsymbolic;
1516
0
  } else {
1517
0
    cmap = 0;
1518
0
  }
1519
1520
  // reverse map the char names through MacRomanEncoding, then map the
1521
  // char codes through the cmap; fall back on Unicode if that doesn't
1522
  // work
1523
0
  if (useMacRoman) {
1524
0
    for (i = 0; i < 256; ++i) {
1525
0
      if ((charName = enc[i])) {
1526
0
  if ((code = globalParams->getMacRomanCharCode(charName))) {
1527
0
    map[i] = ff->mapCodeToGID(cmap, code);
1528
0
  } else if (unicodeCmap >= 0 &&
1529
0
       (u = globalParams->mapNameToUnicode(charName))) {
1530
0
    map[i] = ff->mapCodeToGID(unicodeCmap, u);
1531
0
  }
1532
0
      } else if (unicodeCmap >= 0 &&
1533
0
     (n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
1534
0
  map[i] = ff->mapCodeToGID(cmap, u);
1535
0
      } else {
1536
0
  map[i] = -1;
1537
0
      }
1538
0
    }
1539
1540
  // map Unicode through the cmap
1541
0
  } else if (useUnicode) {
1542
0
    for (i = 0; i < 256; ++i) {
1543
0
      if (((charName = enc[i]) &&
1544
0
     (u = globalParams->mapNameToUnicode(charName))) ||
1545
0
    (n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
1546
0
  map[i] = ff->mapCodeToGID(cmap, u);
1547
0
      } else {
1548
0
  map[i] = -1;
1549
0
      }
1550
0
    }
1551
1552
  // map the char codes through the cmap, possibly with an offset of
1553
  // 0xf000
1554
0
  } else {
1555
0
    for (i = 0; i < 256; ++i) {
1556
0
      if (!(map[i] = ff->mapCodeToGID(cmap, i))) {
1557
0
  map[i] = ff->mapCodeToGID(cmap, 0xf000 + i);
1558
0
      }
1559
0
    }
1560
0
  }
1561
1562
  // try the TrueType 'post' table to handle any unmapped characters
1563
0
  for (i = 0; i < 256; ++i) {
1564
0
    if (map[i] <= 0 && (charName = enc[i])) {
1565
0
      map[i] = ff->mapNameToGID(charName);
1566
0
    }
1567
0
  }
1568
1569
0
  return map;
1570
0
}
1571
1572
0
int *Gfx8BitFont::getCodeToGIDMap(FoFiType1C *ff) {
1573
0
  int *map;
1574
0
  GHash *nameToGID;
1575
0
  int i, gid;
1576
1577
0
  map = (int *)gmallocn(256, sizeof(int));
1578
0
  for (i = 0; i < 256; ++i) {
1579
0
    map[i] = 0;
1580
0
  }
1581
1582
0
  nameToGID = ff->getNameToGIDMap();
1583
0
  for (i = 0; i < 256; ++i) {
1584
0
    if (!enc[i]) {
1585
0
      continue;
1586
0
    }
1587
0
    gid = nameToGID->lookupInt(enc[i]);
1588
0
    if (gid < 0 || gid >= 65536) {
1589
0
      continue;
1590
0
    }
1591
0
    map[i] = gid;
1592
0
  }
1593
1594
0
  delete nameToGID;
1595
1596
0
  return map;
1597
0
}
1598
1599
0
Dict *Gfx8BitFont::getCharProcs() {
1600
0
  return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL;
1601
0
}
1602
1603
0
Object *Gfx8BitFont::getCharProc(int code, Object *proc) {
1604
0
  if (enc[code] && charProcs.isDict()) {
1605
0
    charProcs.dictLookup(enc[code], proc);
1606
0
  } else {
1607
0
    proc->initNull();
1608
0
  }
1609
0
  return proc;
1610
0
}
1611
1612
0
Object *Gfx8BitFont::getCharProcNF(int code, Object *proc) {
1613
0
  if (enc[code] && charProcs.isDict()) {
1614
0
    charProcs.dictLookupNF(enc[code], proc);
1615
0
  } else {
1616
0
    proc->initNull();
1617
0
  }
1618
0
  return proc;
1619
0
}
1620
1621
0
Dict *Gfx8BitFont::getResources() {
1622
0
  return resources.isDict() ? resources.getDict() : (Dict *)NULL;
1623
0
}
1624
1625
0
GBool Gfx8BitFont::problematicForUnicode() {
1626
0
  GString *nameLC;
1627
0
  GBool symbolic;
1628
1629
  // potential inputs:
1630
  // - font is embedded (GfxFont.embFontID.num >= 0)
1631
  // - font name (GfxFont.name)
1632
  // - font type (GfxFont.type)
1633
  // - Base-14 font (Gfx8BitFont.base14 != NULL)
1634
  // - symbolic (GfxFont.flags & fontSymbolic)
1635
  // - has Encoding array (Gfx8BitFont.hasEncoding)
1636
  // - extracted base encoding from embedded font file
1637
  //   (Gfx8BitFont.baseEncFromFontFile)
1638
  // - has a ToUnicode map (GfxFont.hasToUnicode)
1639
  // - used the numeric glyph name heuristic
1640
  //   (Gfx8BitFont.usedNumericHeuristic)
1641
1642
0
  if (name) {
1643
0
    nameLC = name->copy();
1644
0
    nameLC->lowerCase();
1645
0
    symbolic = strstr(nameLC->getCString(), "dingbat") ||
1646
0
               strstr(nameLC->getCString(), "wingding") ||
1647
0
               strstr(nameLC->getCString(), "commpi");
1648
0
    delete nameLC;
1649
0
    if (symbolic) {
1650
0
      return gFalse;
1651
0
    }
1652
0
  }
1653
1654
0
  if (embFontID.num >= 0) {
1655
0
    switch (type) {
1656
0
    case fontType1:
1657
0
    case fontType1C:
1658
0
    case fontType1COT:
1659
0
      return !hasToUnicode && (!hasEncoding || usedNumericHeuristic);
1660
1661
0
    case fontType3:
1662
0
      return !hasToUnicode && !hasEncoding;
1663
1664
0
    case fontTrueType:
1665
0
    case fontTrueTypeOT:
1666
0
      return !hasToUnicode && !hasEncoding;
1667
1668
0
    default:
1669
0
      return !hasToUnicode;
1670
0
    }
1671
1672
0
  } else {
1673
    // NB: type will be fontTypeUnknown if the PDF specifies an
1674
    // invalid font type -- which is ok, if we have a ToUnicode map or
1675
    // an encoding
1676
0
    return !hasToUnicode && !hasEncoding;
1677
0
  }
1678
0
}
1679
1680
//------------------------------------------------------------------------
1681
// GfxCIDFont
1682
//------------------------------------------------------------------------
1683
1684
GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA,
1685
           GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
1686
0
  GfxFont(tagA, idA, nameA, typeA, embFontIDA)
1687
0
{
1688
0
  Dict *desFontDict;
1689
0
  Object desFontDictObj;
1690
0
  Object obj1, obj2, obj3, obj4, obj5, obj6;
1691
0
  CharCodeToUnicode *utu;
1692
0
  CharCode c;
1693
0
  Unicode uBuf[8];
1694
0
  int c1, c2;
1695
0
  int excepsSize, i, j, k, n;
1696
1697
0
  missingWidth = 0;
1698
0
  ascent = 0.95;
1699
0
  descent = -0.35;
1700
0
  declaredAscent = ascent;
1701
0
  fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
1702
0
  collection = NULL;
1703
0
  cMap = NULL;
1704
0
  ctu = NULL;
1705
0
  ctuUsesCharCode = gTrue;
1706
0
  widths.defWidth = 1.0;
1707
0
  widths.defHeight = -1.0;
1708
0
  widths.defVY = 0.880;
1709
0
  widths.exceps = NULL;
1710
0
  widths.nExceps = 0;
1711
0
  widths.excepsV = NULL;
1712
0
  widths.nExcepsV = 0;
1713
0
  cidToGID = NULL;
1714
0
  cidToGIDLen = 0;
1715
1716
  // get the descendant font
1717
0
  if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() ||
1718
0
      obj1.arrayGetLength() == 0) {
1719
0
    error(errSyntaxError, -1,
1720
0
    "Missing or empty DescendantFonts entry in Type 0 font");
1721
0
    obj1.free();
1722
0
    goto err1;
1723
0
  }
1724
0
  if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
1725
0
    error(errSyntaxError, -1, "Bad descendant font in Type 0 font");
1726
0
    goto err2;
1727
0
  }
1728
0
  obj1.free();
1729
0
  desFontDict = desFontDictObj.getDict();
1730
1731
  // get info from font descriptor
1732
0
  readFontDescriptor(xref, desFontDict);
1733
1734
  //----- encoding info -----
1735
1736
  // char collection
1737
0
  if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
1738
0
    error(errSyntaxError, -1,
1739
0
    "Missing CIDSystemInfo dictionary in Type 0 descendant font");
1740
0
    goto err2;
1741
0
  }
1742
0
  obj1.dictLookup("Registry", &obj2);
1743
0
  obj1.dictLookup("Ordering", &obj3);
1744
0
  if (!obj2.isString() || !obj3.isString()) {
1745
0
    error(errSyntaxError, -1,
1746
0
    "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
1747
0
    goto err3;
1748
0
  }
1749
0
  collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
1750
0
  obj3.free();
1751
0
  obj2.free();
1752
0
  obj1.free();
1753
1754
  // encoding (i.e., CMap)
1755
0
  if (fontDict->lookup("Encoding", &obj1)->isNull()) {
1756
0
    error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font");
1757
0
    goto err2;
1758
0
  }
1759
0
  if (!(cMap = CMap::parse(NULL, collection, &obj1))) {
1760
0
    goto err2;
1761
0
  }
1762
1763
  // check for fonts that use the Identity-H encoding (cmap), and the
1764
  // Adobe-Identity character collection
1765
0
  identityEnc = obj1.isName("Identity-H") &&
1766
0
                !collection->cmp("Adobe-Identity");
1767
1768
0
  obj1.free();
1769
1770
  // CIDToGIDMap
1771
  // (the PDF 1.7 spec only allows these for TrueType fonts, but
1772
  // Acrobat apparently also allows them for OpenType CFF fonts -- and
1773
  // the PDF 2.0 spec has removed the prohibition)
1774
0
  hasIdentityCIDToGID = gFalse;
1775
0
  desFontDict->lookup("CIDToGIDMap", &obj1);
1776
0
  if (obj1.isStream()) {
1777
0
    cidToGIDLen = 0;
1778
0
    i = 64;
1779
0
    cidToGID = (int *)gmallocn(i, sizeof(int));
1780
0
    obj1.streamReset();
1781
0
    while ((c1 = obj1.streamGetChar()) != EOF &&
1782
0
     (c2 = obj1.streamGetChar()) != EOF) {
1783
0
      if (cidToGIDLen == i) {
1784
0
  i *= 2;
1785
0
  cidToGID = (int *)greallocn(cidToGID, i, sizeof(int));
1786
0
      }
1787
0
      cidToGID[cidToGIDLen++] = (c1 << 8) + c2;
1788
0
    }
1789
0
    obj1.streamClose();
1790
0
    identityEnc = gFalse;
1791
0
  } else if (obj1.isName("Identity")) {
1792
0
    hasIdentityCIDToGID = gTrue;
1793
0
  } else if (!obj1.isNull()) {
1794
0
    error(errSyntaxError, -1, "Invalid CIDToGIDMap entry in CID font");
1795
0
  }
1796
0
  obj1.free();
1797
1798
  // look for a ToUnicode CMap
1799
0
  hasKnownCollection = gFalse;
1800
0
  if (globalParams->getUseTrueTypeUnicodeMapping()) {
1801
0
    readTrueTypeUnicodeMapping(xref);
1802
0
  }
1803
0
  if (!ctu) {
1804
0
    ctu = readToUnicodeCMap(fontDict, 16, NULL);
1805
0
  }
1806
0
  if (!ctu) {
1807
0
    ctuUsesCharCode = gFalse;
1808
1809
    // use an identity mapping for the "Adobe-Identity" and
1810
    // "Adobe-UCS" collections
1811
0
    if (!collection->cmp("Adobe-Identity") ||
1812
0
  !collection->cmp("Adobe-UCS")) {
1813
0
      ctu = CharCodeToUnicode::makeIdentityMapping();
1814
1815
    // look for a user-supplied .cidToUnicode file
1816
0
    } else if ((ctu = globalParams->getCIDToUnicode(collection))) {
1817
0
      hasKnownCollection = gTrue;
1818
1819
0
    } else {
1820
0
      error(errSyntaxError, -1,
1821
0
      "Unknown character collection '{0:t}'", collection);
1822
1823
      // fall back to an identity mapping
1824
0
      ctu = CharCodeToUnicode::makeIdentityMapping();
1825
0
    }
1826
0
  }
1827
1828
  // look for a Unicode-to-Unicode mapping
1829
0
  if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
1830
0
    if (ctu) {
1831
0
      if (ctu->isIdentity()) {
1832
0
  ctu->decRefCnt();
1833
0
  ctu = utu;
1834
0
      } else {
1835
0
  for (c = 0; c < ctu->getLength(); ++c) {
1836
0
    n = ctu->mapToUnicode(c, uBuf, 8);
1837
0
    if (n >= 1) {
1838
0
      n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
1839
0
      if (n >= 1) {
1840
0
        ctu->setMapping(c, uBuf, n);
1841
0
      }
1842
0
    }
1843
0
  }
1844
0
  utu->decRefCnt();
1845
0
      }
1846
0
    } else {
1847
0
      ctu = utu;
1848
0
    }
1849
0
  }
1850
1851
  //----- character metrics -----
1852
1853
  // default char width
1854
0
  if (desFontDict->lookup("DW", &obj1)->isNum()) {
1855
0
    widths.defWidth = obj1.getNum() * 0.001;
1856
0
  }
1857
0
  obj1.free();
1858
1859
  // char width exceptions
1860
0
  if (desFontDict->lookup("W", &obj1)->isArray()) {
1861
0
    excepsSize = 0;
1862
0
    i = 0;
1863
0
    while (i + 1 < obj1.arrayGetLength()) {
1864
0
      obj1.arrayGet(i, &obj2);
1865
0
      obj1.arrayGet(i + 1, &obj3);
1866
0
      if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) {
1867
0
  if (obj1.arrayGet(i + 2, &obj4)->isNum()) {
1868
0
    if (widths.nExceps == excepsSize) {
1869
0
      excepsSize += 16;
1870
0
      widths.exceps = (GfxFontCIDWidthExcep *)
1871
0
        greallocn(widths.exceps,
1872
0
      excepsSize, sizeof(GfxFontCIDWidthExcep));
1873
0
    }
1874
0
    widths.exceps[widths.nExceps].first = obj2.getInt();
1875
0
    widths.exceps[widths.nExceps].last = obj3.getInt();
1876
0
    widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
1877
0
    ++widths.nExceps;
1878
0
  } else {
1879
0
    error(errSyntaxError, -1, "Bad widths array in Type 0 font");
1880
0
  }
1881
0
  obj4.free();
1882
0
  i += 3;
1883
0
      } else if (obj2.isInt() && obj3.isArray()) {
1884
0
  if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
1885
0
    excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15;
1886
0
    widths.exceps = (GfxFontCIDWidthExcep *)
1887
0
      greallocn(widths.exceps,
1888
0
          excepsSize, sizeof(GfxFontCIDWidthExcep));
1889
0
  }
1890
0
  j = obj2.getInt();
1891
0
  for (k = 0; k < obj3.arrayGetLength(); ++k) {
1892
0
    if (obj3.arrayGet(k, &obj4)->isNum()) {
1893
0
      widths.exceps[widths.nExceps].first = j;
1894
0
      widths.exceps[widths.nExceps].last = j;
1895
0
      widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
1896
0
      ++j;
1897
0
      ++widths.nExceps;
1898
0
    } else {
1899
0
      error(errSyntaxError, -1, "Bad widths array in Type 0 font");
1900
0
    }
1901
0
    obj4.free();
1902
0
  }
1903
0
  i += 2;
1904
0
      } else {
1905
0
  error(errSyntaxError, -1, "Bad widths array in Type 0 font");
1906
0
  ++i;
1907
0
      }
1908
0
      obj3.free();
1909
0
      obj2.free();
1910
0
    }
1911
0
  }
1912
0
  obj1.free();
1913
1914
  // default metrics for vertical font
1915
0
  if (desFontDict->lookup("DW2", &obj1)->isArray() &&
1916
0
      obj1.arrayGetLength() == 2) {
1917
0
    if (obj1.arrayGet(0, &obj2)->isNum()) {
1918
0
      widths.defVY = obj2.getNum() * 0.001;
1919
0
    }
1920
0
    obj2.free();
1921
0
    if (obj1.arrayGet(1, &obj2)->isNum()) {
1922
0
      widths.defHeight = obj2.getNum() * 0.001;
1923
0
    }
1924
0
    obj2.free();
1925
0
  }
1926
0
  obj1.free();
1927
1928
  // char metric exceptions for vertical font
1929
0
  if (desFontDict->lookup("W2", &obj1)->isArray()) {
1930
0
    excepsSize = 0;
1931
0
    i = 0;
1932
0
    while (i + 1 < obj1.arrayGetLength()) {
1933
0
      obj1.arrayGet(i, &obj2);
1934
0
      obj1.arrayGet(i+ 1, &obj3);
1935
0
      if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) {
1936
0
  if (obj1.arrayGet(i + 2, &obj4)->isNum() &&
1937
0
      obj1.arrayGet(i + 3, &obj5)->isNum() &&
1938
0
      obj1.arrayGet(i + 4, &obj6)->isNum()) {
1939
0
    if (widths.nExcepsV == excepsSize) {
1940
0
      excepsSize += 16;
1941
0
      widths.excepsV = (GfxFontCIDWidthExcepV *)
1942
0
        greallocn(widths.excepsV,
1943
0
      excepsSize, sizeof(GfxFontCIDWidthExcepV));
1944
0
    }
1945
0
    widths.excepsV[widths.nExcepsV].first = obj2.getInt();
1946
0
    widths.excepsV[widths.nExcepsV].last = obj3.getInt();
1947
0
    widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
1948
0
    widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001;
1949
0
    widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001;
1950
0
    ++widths.nExcepsV;
1951
0
  } else {
1952
0
    error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
1953
0
  }
1954
0
  obj6.free();
1955
0
  obj5.free();
1956
0
  obj4.free();
1957
0
  i += 5;
1958
0
      } else if (obj2.isInt() && obj3.isArray()) {
1959
0
  if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) {
1960
0
    excepsSize =
1961
0
      (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15;
1962
0
    widths.excepsV = (GfxFontCIDWidthExcepV *)
1963
0
      greallocn(widths.excepsV,
1964
0
          excepsSize, sizeof(GfxFontCIDWidthExcepV));
1965
0
  }
1966
0
  j = obj2.getInt();
1967
0
  for (k = 0; k + 2 < obj3.arrayGetLength(); k += 3) {
1968
0
    if (obj3.arrayGet(k, &obj4)->isNum() &&
1969
0
        obj3.arrayGet(k+1, &obj5)->isNum() &&
1970
0
        obj3.arrayGet(k+2, &obj6)->isNum()) {
1971
0
      widths.excepsV[widths.nExcepsV].first = j;
1972
0
      widths.excepsV[widths.nExcepsV].last = j;
1973
0
      widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
1974
0
      widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001;
1975
0
      widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001;
1976
0
      ++j;
1977
0
      ++widths.nExcepsV;
1978
0
    } else {
1979
0
      error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
1980
0
    }
1981
0
    obj6.free();
1982
0
    obj5.free();
1983
0
    obj4.free();
1984
0
  }
1985
0
  i += 2;
1986
0
      } else {
1987
0
  error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font");
1988
0
  ++i;
1989
0
      }
1990
0
      obj3.free();
1991
0
      obj2.free();
1992
0
    }
1993
0
  }
1994
0
  obj1.free();
1995
1996
0
  desFontDictObj.free();
1997
0
  ok = gTrue;
1998
0
  return;
1999
2000
0
 err3:
2001
0
  obj3.free();
2002
0
  obj2.free();
2003
0
 err2:
2004
0
  obj1.free();
2005
0
  desFontDictObj.free();
2006
0
 err1:
2007
0
  error(errSyntaxError, -1, "Failed to parse font object for '{0:t}'", name);
2008
0
}
2009
2010
0
GfxCIDFont::~GfxCIDFont() {
2011
0
  if (collection) {
2012
0
    delete collection;
2013
0
  }
2014
0
  if (cMap) {
2015
0
    cMap->decRefCnt();
2016
0
  }
2017
0
  if (ctu) {
2018
0
    ctu->decRefCnt();
2019
0
  }
2020
0
  gfree(widths.exceps);
2021
0
  gfree(widths.excepsV);
2022
0
  if (cidToGID) {
2023
0
    gfree(cidToGID);
2024
0
  }
2025
0
}
2026
2027
// Construct a code-to-Unicode mapping, based on the TrueType Unicode
2028
// cmap (if present).  Constructs ctu if succesful; leaves ctu = null
2029
// otherwise.  Always leaves ctu = null for non-TrueType fonts.
2030
0
void GfxCIDFont::readTrueTypeUnicodeMapping(XRef *xref) {
2031
0
  char *buf;
2032
0
  FoFiTrueType *ff;
2033
0
  Unicode *gidToUnicode, *codeToUnicode;
2034
0
  Unicode u;
2035
0
  int bufLen, cmapPlatform, cmapEncoding, unicodeCmap;
2036
0
  int nGlyphs, nMappings, gid, i;
2037
2038
  // must be an embedded TrueType font, with an unknown char collection
2039
0
  if ((type != fontCIDType2 && type == fontCIDType2OT) ||
2040
0
      embFontID.num < 0 ||
2041
0
      hasKnownCollection) {
2042
0
    goto err0;
2043
0
  }
2044
2045
  // read the embedded font and construct a FoFiTrueType
2046
0
  if (!(buf = readEmbFontFile(xref, &bufLen))) {
2047
0
    goto err0;
2048
0
  }
2049
0
  if (!(ff = FoFiTrueType::make(buf, bufLen, 0))) {
2050
0
    goto err1;
2051
0
  }
2052
2053
  // find the TrueType Unicode cmap
2054
0
  unicodeCmap = -1;
2055
0
  for (i = 0; i < ff->getNumCmaps(); ++i) {
2056
0
    cmapPlatform = ff->getCmapPlatform(i);
2057
0
    cmapEncoding = ff->getCmapEncoding(i);
2058
0
    if ((cmapPlatform == 3 && cmapEncoding == 1) ||
2059
0
  (cmapPlatform == 0 && cmapEncoding <= 4)) {
2060
0
      unicodeCmap = i;
2061
0
      break;
2062
0
    }
2063
0
  }
2064
0
  if (unicodeCmap < 0) {
2065
0
    goto err2;
2066
0
  }
2067
2068
  // construct reverse GID-to-Unicode map
2069
0
  nGlyphs = ff->getNumGlyphs();
2070
0
  gidToUnicode = (Unicode *)gmallocn(nGlyphs, sizeof(Unicode));
2071
0
  memset(gidToUnicode, 0, nGlyphs * sizeof(Unicode));
2072
0
  nMappings = 0;
2073
0
  for (u = 1; u <= 0xffff; ++u) {
2074
0
    gid = ff->mapCodeToGID(unicodeCmap, (int)u);
2075
0
    if (gid > 0 && gid < nGlyphs) {
2076
0
      gidToUnicode[gid] = u;
2077
0
      ++nMappings;
2078
0
    }
2079
0
  }
2080
  // bail out if the Unicode cmap was completely empty
2081
0
  if (nMappings == 0) {
2082
0
    goto err3;
2083
0
  }
2084
2085
  // construct code-to-Unicode map
2086
0
  codeToUnicode = (Unicode *)gmallocn(65536, sizeof(Unicode));
2087
0
  memset(codeToUnicode, 0, 65536 * sizeof(Unicode));
2088
0
  for (i = 0; i <= 0xffff; ++i) {
2089
    // we've already checked for an identity encoding, so CID = i
2090
0
    if (cidToGID && i < cidToGIDLen) {
2091
0
      gid = cidToGID[i];
2092
0
    } else {
2093
0
      gid = i;
2094
0
    }
2095
0
    if (gid < nGlyphs && gidToUnicode[gid] > 0) {
2096
0
      codeToUnicode[i] = gidToUnicode[gid];
2097
0
    }
2098
0
  }
2099
0
  ctu = CharCodeToUnicode::make16BitToUnicode(codeToUnicode);
2100
2101
0
  gfree(codeToUnicode);
2102
0
 err3:
2103
0
  gfree(gidToUnicode);
2104
0
 err2:
2105
0
  delete ff;
2106
0
 err1:
2107
0
  gfree(buf);
2108
0
 err0:
2109
0
  return;
2110
0
}
2111
2112
int GfxCIDFont::getNextChar(char *s, int len, CharCode *code,
2113
          Unicode *u, int uSize, int *uLen,
2114
0
          double *dx, double *dy, double *ox, double *oy) {
2115
0
  CID cid;
2116
0
  CharCode c;
2117
0
  int n;
2118
2119
0
  if (!cMap) {
2120
0
    *code = 0;
2121
0
    *uLen = 0;
2122
0
    *dx = *dy = 0;
2123
0
    return 1;
2124
0
  }
2125
2126
0
  *code = (CharCode)(cid = cMap->getCID(s, len, &c, &n));
2127
0
  if (ctu) {
2128
0
    *uLen = ctu->mapToUnicode(ctuUsesCharCode ? c : cid, u, uSize);
2129
0
  } else {
2130
0
    *uLen = 0;
2131
0
  }
2132
0
  if (!*uLen && uSize >= 1 && globalParams->getMapUnknownCharNames()) {
2133
0
    u[0] = *code;
2134
0
    *uLen = 1;
2135
0
  }
2136
2137
  // horizontal
2138
0
  if (cMap->getWMode() == 0) {
2139
0
    getHorizontalMetrics(cid, dx);
2140
0
    *dy = *ox = *oy = 0;
2141
2142
  // vertical
2143
0
  } else {
2144
0
    getVerticalMetrics(cid, dy, ox, oy);
2145
0
    *dx = 0;
2146
0
  }
2147
2148
0
  return n;
2149
0
}
2150
2151
// NB: Section 9.7.4.3 in the PDF 2.0 spec says that, in the case of
2152
// duplicate entries in the metrics, the first entry should be used.
2153
// This means we need to leave the metrics in the original order and
2154
// perform a linear search.  (Or use a more complex data structure.)
2155
0
void GfxCIDFont::getHorizontalMetrics(CID cid, double *w) {
2156
0
  int i;
2157
0
  for (i = 0; i < widths.nExceps; ++i) {
2158
0
    if (widths.exceps[i].first <= cid && cid <= widths.exceps[i].last) {
2159
0
      *w = widths.exceps[i].width;
2160
0
      return;
2161
0
    }
2162
0
  }
2163
0
  *w = widths.defWidth;
2164
0
}
2165
2166
// NB: Section 9.7.4.3 in the PDF 2.0 spec says that, in the case of
2167
// duplicate entries in the metrics, the first entry should be used.
2168
// This means we need to leave the metrics in the original order and
2169
// perform a linear search.  (Or use a more complex data structure.)
2170
void GfxCIDFont::getVerticalMetrics(CID cid, double *h,
2171
0
            double *vx, double *vy) {
2172
0
  int i;
2173
0
  for (i = 0; i < widths.nExcepsV; ++i) {
2174
0
    if (widths.excepsV[i].first <= cid && cid <= widths.excepsV[i].last) {
2175
0
      *h = widths.excepsV[i].height;
2176
0
      *vx = widths.excepsV[i].vx;
2177
0
      *vy = widths.excepsV[i].vy;
2178
0
      return;
2179
0
    }
2180
0
  }
2181
0
  *h = widths.defHeight;
2182
0
  getHorizontalMetrics(cid, vx);
2183
0
  *vx /= 2;
2184
0
  *vy = widths.defVY;
2185
0
}
2186
2187
0
int GfxCIDFont::getWMode() {
2188
0
  return cMap ? cMap->getWMode() : 0;
2189
0
}
2190
2191
0
CharCodeToUnicode *GfxCIDFont::getToUnicode() {
2192
0
  if (ctu) {
2193
0
    ctu->incRefCnt();
2194
0
  }
2195
0
  return ctu;
2196
0
}
2197
2198
0
GString *GfxCIDFont::getCollection() {
2199
0
  return cMap ? cMap->getCollection() : (GString *)NULL;
2200
0
}
2201
2202
0
double GfxCIDFont::getWidth(CID cid) {
2203
0
  double w;
2204
2205
0
  getHorizontalMetrics(cid, &w);
2206
0
  return w;
2207
0
}
2208
2209
0
GBool GfxCIDFont::problematicForUnicode() {
2210
0
  GString *nameLC;
2211
0
  GBool symbolic;
2212
2213
  // potential inputs:
2214
  // - font is embedded (GfxFont.embFontID.num >= 0)
2215
  // - font name (GfxFont.name)
2216
  // - font type (GfxFont.type)
2217
  // - symbolic (GfxFont.flags & fontSymbolic)
2218
  // - has a ToUnicode map (GfxFont.hasToUnicode)
2219
  // - collection is Adobe-Identity or Adobe-UCS
2220
  //   (GfxCIDFont.collection - compare string)
2221
  // - collection is known AdobeCJK (GfxCIDFont.hasKnownCollection)
2222
  // - has non-Identity CIDToGIDMap (GfxCIDFont.cidToGID != NULL)
2223
  // - has Identity CIDToGIDMap (GfxCIDFont.hasIdentityCIDToGID)
2224
2225
0
  if (name) {
2226
0
    nameLC = name->copy();
2227
0
    nameLC->lowerCase();
2228
0
    symbolic = strstr(nameLC->getCString(), "dingbat") ||
2229
0
               strstr(nameLC->getCString(), "wingding") ||
2230
0
               strstr(nameLC->getCString(), "commpi");
2231
0
    delete nameLC;
2232
0
    if (symbolic) {
2233
0
      return gFalse;
2234
0
    }
2235
0
  }
2236
2237
0
  if (embFontID.num >= 0) {
2238
0
    switch (type) {
2239
0
    case fontCIDType0:
2240
0
    case fontCIDType0C:
2241
0
    case fontCIDType0COT:
2242
0
      return !hasToUnicode && !hasKnownCollection;
2243
2244
0
    case fontCIDType2:
2245
0
    case fontCIDType2OT:
2246
0
      return !hasToUnicode && !hasKnownCollection;
2247
2248
0
    default:
2249
0
      return !hasToUnicode;
2250
0
    }
2251
2252
0
  } else {
2253
0
    return !hasToUnicode;
2254
0
  }
2255
0
}
2256
2257
//------------------------------------------------------------------------
2258
// GfxFontDict
2259
//------------------------------------------------------------------------
2260
2261
class GfxFontDictEntry {
2262
public:
2263
2264
  GfxFontDictEntry(Ref refA, Object *fontObjA);
2265
  ~GfxFontDictEntry();
2266
  void load(GfxFont *fontA);
2267
2268
  GBool loaded;
2269
  Ref ref;
2270
  Object fontObj;   // valid if unloaded
2271
  GfxFont *font;    // valid if loaded
2272
};
2273
2274
0
GfxFontDictEntry::GfxFontDictEntry(Ref refA, Object *fontObjA) {
2275
0
  loaded = gFalse;
2276
0
  ref = refA;
2277
0
  fontObjA->copy(&fontObj);
2278
0
  font = NULL;
2279
0
}
2280
2281
0
GfxFontDictEntry::~GfxFontDictEntry() {
2282
  // NB: If the font has been loaded, font is non-NULL and is owned by
2283
  // GfxFontDict.uniqueFonts.
2284
0
  if (!loaded) {
2285
0
    fontObj.free();
2286
0
  }
2287
0
}
2288
2289
0
void GfxFontDictEntry::load(GfxFont *fontA) {
2290
0
  loaded = gTrue;
2291
0
  font = fontA;
2292
0
  fontObj.free();
2293
0
}
2294
2295
0
GfxFontDict::GfxFontDict(XRef *xrefA, Ref *fontDictRef, Dict *fontDict) {
2296
0
  xref = xrefA;
2297
0
  fonts = new GHash(gTrue);
2298
0
  uniqueFonts = new GList();
2299
2300
0
  for (int i = 0; i < fontDict->getLength(); ++i) {
2301
0
    char *tag = fontDict->getKey(i);
2302
0
    Object fontObj;
2303
0
    fontDict->getValNF(i, &fontObj);
2304
0
    Ref r;
2305
0
    if (fontObj.isRef()) {
2306
0
      r = fontObj.getRef();
2307
0
    } else if (fontDictRef) {
2308
      // legal generation numbers are five digits, so we use a
2309
      // 6-digit number here
2310
0
      r.gen = 100000 + fontDictRef->num;
2311
0
      r.num = i;
2312
0
    } else {
2313
      // no indirect reference for this font, or for the containing
2314
      // font dict, so hash the font and use that
2315
0
      r.gen = 100000;
2316
0
      r.num = hashFontObject(&fontObj);
2317
0
    }
2318
0
    fonts->add(new GString(tag), new GfxFontDictEntry(r, &fontObj));
2319
0
    fontObj.free();
2320
0
  }
2321
0
}
2322
2323
0
GfxFontDict::~GfxFontDict() {
2324
0
  deleteGList(uniqueFonts, GfxFont);
2325
0
  deleteGHash(fonts, GfxFontDictEntry);
2326
0
}
2327
2328
0
GfxFont *GfxFontDict::lookup(char *tag) {
2329
0
  GfxFontDictEntry *entry = (GfxFontDictEntry *)fonts->lookup(tag);
2330
0
  if (!entry) {
2331
0
    return NULL;
2332
0
  }
2333
0
  load(tag, entry);
2334
0
  return entry->font;
2335
0
}
2336
2337
0
GfxFont *GfxFontDict::lookupByRef(Ref ref) {
2338
0
  GHashIter *iter;
2339
0
  GString *tag;
2340
0
  GfxFontDictEntry *entry;
2341
0
  fonts->startIter(&iter);
2342
0
  while (fonts->getNext(&iter, &tag, (void **)&entry)) {
2343
0
    if (entry->ref.num == ref.num && entry->ref.gen == ref.gen) {
2344
0
      fonts->killIter(&iter);
2345
0
      load(tag->getCString(), entry);
2346
0
      return entry->font;
2347
0
    }
2348
0
  }
2349
0
  return NULL;
2350
0
}
2351
2352
0
int GfxFontDict::getNumFonts() {
2353
0
  loadAll();
2354
0
  return uniqueFonts->getLength();
2355
0
}
2356
2357
0
GfxFont *GfxFontDict::getFont(int i) {
2358
0
  return (GfxFont *)uniqueFonts->get(i);
2359
0
}
2360
2361
0
void GfxFontDict::loadAll() {
2362
0
  GHashIter *iter;
2363
0
  GString *tag;
2364
0
  GfxFontDictEntry *entry;
2365
0
  fonts->startIter(&iter);
2366
0
  while (fonts->getNext(&iter, &tag, (void **)&entry)) {
2367
0
    load(tag->getCString(), entry);
2368
0
  }
2369
0
}
2370
2371
0
void GfxFontDict::load(char *tag, GfxFontDictEntry *entry) {
2372
0
  if (entry->loaded) {
2373
0
    return;
2374
0
  }
2375
2376
  // check for a duplicate that has already been loaded
2377
  // (don't do this for "synthetic" refs)
2378
0
  if (entry->fontObj.isRef()) {
2379
0
    for (int i = 0; i < uniqueFonts->getLength(); ++i) {
2380
0
      GfxFont *font = (GfxFont *)uniqueFonts->get(i);
2381
0
      if (font->getID()->num == entry->ref.num &&
2382
0
    font->getID()->gen == entry->ref.gen) {
2383
0
  entry->load(font);
2384
0
  return;
2385
0
      }
2386
0
    }
2387
0
  }
2388
2389
0
  GfxFont *font = NULL;
2390
0
  Object obj;
2391
0
  entry->fontObj.fetch(xref, &obj);
2392
0
  if (obj.isDict()) {
2393
0
    font = GfxFont::makeFont(xref, tag, entry->ref, obj.getDict());
2394
0
    if (font->isOk()) {
2395
0
      uniqueFonts->append(font);
2396
0
    } else {
2397
0
      delete font;
2398
0
      font = NULL;
2399
0
    }
2400
0
  } else {
2401
0
    error(errSyntaxError, -1, "font resource is not a dictionary");
2402
0
  }
2403
0
  obj.free();
2404
0
  entry->load(font);
2405
0
}
2406
2407
// FNV-1a hash
2408
class FNVHash {
2409
public:
2410
2411
0
  FNVHash() {
2412
0
    h = 2166136261U;
2413
0
  }
2414
2415
0
  void hash(char c) {
2416
0
    h ^= c & 0xff;
2417
0
    h *= 16777619;
2418
0
  }
2419
2420
0
  void hash(char *p, int n) {
2421
0
    int i;
2422
0
    for (i = 0; i < n; ++i) {
2423
0
      hash(p[i]);
2424
0
    }
2425
0
  }
2426
2427
0
  int get31() {
2428
0
    return (h ^ (h >> 31)) & 0x7fffffff;
2429
0
  }
2430
2431
private:
2432
2433
  Guint h;
2434
};
2435
2436
0
int GfxFontDict::hashFontObject(Object *obj) {
2437
0
  FNVHash h;
2438
2439
0
  hashFontObject1(obj, &h);
2440
0
  return h.get31();
2441
0
}
2442
2443
0
void GfxFontDict::hashFontObject1(Object *obj, FNVHash *h) {
2444
0
  Object obj2;
2445
0
  GString *s;
2446
0
  char *p;
2447
0
  double r;
2448
0
  int n, i;
2449
2450
0
  switch (obj->getType()) {
2451
0
  case objBool:
2452
0
    h->hash('b');
2453
0
    h->hash(obj->getBool() ? 1 : 0);
2454
0
    break;
2455
0
  case objInt:
2456
0
    h->hash('i');
2457
0
    n = obj->getInt();
2458
0
    h->hash((char *)&n, sizeof(int));
2459
0
    break;
2460
0
  case objReal:
2461
0
    h->hash('r');
2462
0
    r = obj->getReal();
2463
0
    h->hash((char *)&r, sizeof(double));
2464
0
    break;
2465
0
  case objString:
2466
0
    h->hash('s');
2467
0
    s = obj->getString();
2468
0
    h->hash(s->getCString(), s->getLength());
2469
0
    break;
2470
0
  case objName:
2471
0
    h->hash('n');
2472
0
    p = obj->getName();
2473
0
    h->hash(p, (int)strlen(p));
2474
0
    break;
2475
0
  case objNull:
2476
0
    h->hash('z');
2477
0
    break;
2478
0
  case objArray:
2479
0
    h->hash('a');
2480
0
    n = obj->arrayGetLength();
2481
0
    h->hash((char *)&n, sizeof(int));
2482
0
    for (i = 0; i < n; ++i) {
2483
0
      obj->arrayGetNF(i, &obj2);
2484
0
      hashFontObject1(&obj2, h);
2485
0
      obj2.free();
2486
0
    }
2487
0
    break;
2488
0
  case objDict:
2489
0
    h->hash('d');
2490
0
    n = obj->dictGetLength();
2491
0
    h->hash((char *)&n, sizeof(int));
2492
0
    for (i = 0; i < n; ++i) {
2493
0
      p = obj->dictGetKey(i);
2494
0
      h->hash(p, (int)strlen(p));
2495
0
      obj->dictGetValNF(i, &obj2);
2496
0
      hashFontObject1(&obj2, h);
2497
0
      obj2.free();
2498
0
    }
2499
0
    break;
2500
0
  case objStream:
2501
    // this should never happen - streams must be indirect refs
2502
0
    break;
2503
0
  case objRef:
2504
0
    h->hash('f');
2505
0
    n = obj->getRefNum();
2506
0
    h->hash((char *)&n, sizeof(int));
2507
0
    n = obj->getRefGen();
2508
0
    h->hash((char *)&n, sizeof(int));
2509
0
    break;
2510
0
  default:
2511
0
    h->hash('u');
2512
0
    break;
2513
0
  }
2514
0
}