GfxFont.cc 71 KB
Newer Older
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1 2 3 4 5 6 7 8
//========================================================================
//
// GfxFont.cc
//
// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================

9 10 11 12
//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
13 14 15
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
16
// Copyright (C) 2005, 2006, 2008-2010, 2012, 2014, 2015, 2017, 2018 Albert Astals Cid <aacid@kde.org>
17 18 19 20 21 22 23 24
// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
// Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
// Copyright (C) 2007 Koji Otani <sho@bbr.jp>
// Copyright (C) 2007 Ed Catmur <ed@catmur.co.uk>
// Copyright (C) 2008 Jonathan Kew <jonathan_kew@sil.org>
// Copyright (C) 2008 Ed Avis <eda@waniasset.com>
Hib Eris's avatar
Hib Eris committed
25
// Copyright (C) 2008, 2010 Hib Eris <hib@hiberis.nl>
Peter Kerzum's avatar
Peter Kerzum committed
26
// Copyright (C) 2009 Peter Kerzum <kerzum@yandex-team.ru>
27
// Copyright (C) 2009, 2010 David Benjamin <davidben@mit.edu>
28
// Copyright (C) 2011 Axel Strübing <axel.struebing@freenet.de>
29
// Copyright (C) 2011, 2012, 2014 Adrian Johnson <ajohnson@redneon.com>
Albert Astals Cid's avatar
Albert Astals Cid committed
30
// Copyright (C) 2012 Yi Yang <ahyangyi@gmail.com>
suzuki toshiya's avatar
suzuki toshiya committed
31
// Copyright (C) 2012 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
Thomas Freitag's avatar
Thomas Freitag committed
32
// Copyright (C) 2012, 2017 Thomas Freitag <Thomas.Freitag@alfa.de>
Albert Astals Cid's avatar
Albert Astals Cid committed
33
// Copyright (C) 2013-2016, 2018 Jason Crain <jason@aquaticape.us>
34
// Copyright (C) 2014 Olly Betts <olly@survex.com>
35
// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
36
// Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
37 38 39 40 41 42
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

Kristian Høgsberg's avatar
Kristian Høgsberg committed
43 44 45 46 47 48
#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
49 50
#include <math.h>
#include <limits.h>
51
#include <algorithm>
Kristian Høgsberg's avatar
Kristian Høgsberg committed
52 53 54 55 56 57 58 59 60
#include "goo/gmem.h"
#include "Error.h"
#include "Object.h"
#include "Dict.h"
#include "GlobalParams.h"
#include "CMap.h"
#include "CharCodeToUnicode.h"
#include "FontEncodingTables.h"
#include "BuiltinFontTables.h"
61
#include "UnicodeTypeTable.h"
62
#include <fofi/FoFiIdentifier.h>
Kristian Høgsberg's avatar
Kristian Høgsberg committed
63 64 65 66
#include <fofi/FoFiType1.h>
#include <fofi/FoFiType1C.h>
#include <fofi/FoFiTrueType.h>
#include "GfxFont.h"
67
#include "PSOutputDev.h"
Kristian Høgsberg's avatar
Kristian Høgsberg committed
68 69 70

//------------------------------------------------------------------------

71
struct Base14FontMapEntry {
72
  const char *altName;
73
  const char *base14Name;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
74 75
};

76
static const Base14FontMapEntry base14FontMap[] = {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
77 78 79 80 81 82 83 84 85 86 87
  { "Arial",                        "Helvetica" },
  { "Arial,Bold",                   "Helvetica-Bold" },
  { "Arial,BoldItalic",             "Helvetica-BoldOblique" },
  { "Arial,Italic",                 "Helvetica-Oblique" },
  { "Arial-Bold",                   "Helvetica-Bold" },
  { "Arial-BoldItalic",             "Helvetica-BoldOblique" },
  { "Arial-BoldItalicMT",           "Helvetica-BoldOblique" },
  { "Arial-BoldMT",                 "Helvetica-Bold" },
  { "Arial-Italic",                 "Helvetica-Oblique" },
  { "Arial-ItalicMT",               "Helvetica-Oblique" },
  { "ArialMT",                      "Helvetica" },
88
  { "Courier",                      "Courier" },
Kristian Høgsberg's avatar
Kristian Høgsberg committed
89 90
  { "Courier,Bold",                 "Courier-Bold" },
  { "Courier,BoldItalic",           "Courier-BoldOblique" },
91
  { "Courier,Italic",               "Courier-Oblique" },
92 93 94
  { "Courier-Bold",                 "Courier-Bold" },
  { "Courier-BoldOblique",          "Courier-BoldOblique" },
  { "Courier-Oblique",              "Courier-Oblique" },
Kristian Høgsberg's avatar
Kristian Høgsberg committed
95 96 97 98 99 100 101 102 103 104 105
  { "CourierNew",                   "Courier" },
  { "CourierNew,Bold",              "Courier-Bold" },
  { "CourierNew,BoldItalic",        "Courier-BoldOblique" },
  { "CourierNew,Italic",            "Courier-Oblique" },
  { "CourierNew-Bold",              "Courier-Bold" },
  { "CourierNew-BoldItalic",        "Courier-BoldOblique" },
  { "CourierNew-Italic",            "Courier-Oblique" },
  { "CourierNewPS-BoldItalicMT",    "Courier-BoldOblique" },
  { "CourierNewPS-BoldMT",          "Courier-Bold" },
  { "CourierNewPS-ItalicMT",        "Courier-Oblique" },
  { "CourierNewPSMT",               "Courier" },
106
  { "Helvetica",                    "Helvetica" },
Kristian Høgsberg's avatar
Kristian Høgsberg committed
107 108 109
  { "Helvetica,Bold",               "Helvetica-Bold" },
  { "Helvetica,BoldItalic",         "Helvetica-BoldOblique" },
  { "Helvetica,Italic",             "Helvetica-Oblique" },
110
  { "Helvetica-Bold",               "Helvetica-Bold" },
Kristian Høgsberg's avatar
Kristian Høgsberg committed
111
  { "Helvetica-BoldItalic",         "Helvetica-BoldOblique" },
112
  { "Helvetica-BoldOblique",        "Helvetica-BoldOblique" },
Kristian Høgsberg's avatar
Kristian Høgsberg committed
113
  { "Helvetica-Italic",             "Helvetica-Oblique" },
114 115
  { "Helvetica-Oblique",            "Helvetica-Oblique" },
  { "Symbol",                       "Symbol" },
Kristian Høgsberg's avatar
Kristian Høgsberg committed
116 117 118
  { "Symbol,Bold",                  "Symbol" },
  { "Symbol,BoldItalic",            "Symbol" },
  { "Symbol,Italic",                "Symbol" },
119 120 121 122
  { "SymbolMT",                     "Symbol" },
  { "SymbolMT,Bold",                "Symbol" },
  { "SymbolMT,BoldItalic",          "Symbol" },
  { "SymbolMT,Italic",              "Symbol" },
123 124 125 126
  { "Times-Bold",                   "Times-Bold" },
  { "Times-BoldItalic",             "Times-BoldItalic" },
  { "Times-Italic",                 "Times-Italic" },
  { "Times-Roman",                  "Times-Roman" },
Kristian Høgsberg's avatar
Kristian Høgsberg committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
  { "TimesNewRoman",                "Times-Roman" },
  { "TimesNewRoman,Bold",           "Times-Bold" },
  { "TimesNewRoman,BoldItalic",     "Times-BoldItalic" },
  { "TimesNewRoman,Italic",         "Times-Italic" },
  { "TimesNewRoman-Bold",           "Times-Bold" },
  { "TimesNewRoman-BoldItalic",     "Times-BoldItalic" },
  { "TimesNewRoman-Italic",         "Times-Italic" },
  { "TimesNewRomanPS",              "Times-Roman" },
  { "TimesNewRomanPS-Bold",         "Times-Bold" },
  { "TimesNewRomanPS-BoldItalic",   "Times-BoldItalic" },
  { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" },
  { "TimesNewRomanPS-BoldMT",       "Times-Bold" },
  { "TimesNewRomanPS-Italic",       "Times-Italic" },
  { "TimesNewRomanPS-ItalicMT",     "Times-Italic" },
  { "TimesNewRomanPSMT",            "Times-Roman" },
  { "TimesNewRomanPSMT,Bold",       "Times-Bold" },
  { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" },
144 145
  { "TimesNewRomanPSMT,Italic",     "Times-Italic" },
  { "ZapfDingbats",                 "ZapfDingbats" }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
146 147
};

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
//------------------------------------------------------------------------

// index: {fixed:0, sans-serif:4, serif:8} + bold*2 + italic
// NB: must be in same order as psSubstFonts in PSOutputDev.cc
static const char *base14SubstFonts[14] = {
  "Courier",
  "Courier-Oblique",
  "Courier-Bold",
  "Courier-BoldOblique",
  "Helvetica",
  "Helvetica-Oblique",
  "Helvetica-Bold",
  "Helvetica-BoldOblique",
  "Times-Roman",
  "Times-Italic",
  "Times-Bold",
  "Times-BoldItalic",
  // the last two are never used for substitution
  "Symbol",
  "ZapfDingbats"
};

//------------------------------------------------------------------------

172
static int parseCharName(char *charName, Unicode *uBuf, int uLen,
173 174
			 bool names, bool ligatures, 
			 bool numeric, bool hex, bool variants);
175

176 177 178 179 180 181
//------------------------------------------------------------------------

static int readFromStream(void *data) {
  return ((Stream *)data)->getChar();
}

182 183 184 185 186
//------------------------------------------------------------------------
// GfxFontLoc
//------------------------------------------------------------------------

GfxFontLoc::GfxFontLoc() {
187
  path = nullptr;
188
  fontNum = 0;
189
  encoding = nullptr;
190 191 192 193 194 195 196 197 198 199 200 201
  substIdx = -1;
}

GfxFontLoc::~GfxFontLoc() {
  if (path) {
    delete path;
  }
  if (encoding) {
    delete encoding;
  }
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
202 203 204 205
//------------------------------------------------------------------------
// GfxFont
//------------------------------------------------------------------------

206
GfxFont *GfxFont::makeFont(XRef *xref, const char *tagA, Ref idA, Dict *fontDict) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
207
  GooString *nameA;
208 209
  Ref embFontIDA;
  GfxFontType typeA;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
210 211 212
  GfxFont *font;

  // get base font name
213
  nameA = nullptr;
Albert Astals Cid's avatar
Albert Astals Cid committed
214
  Object obj1 = fontDict->lookup("BaseFont");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
215 216 217 218
  if (obj1.isName()) {
    nameA = new GooString(obj1.getName());
  }

219 220 221 222
  // get embedded font ID and font type
  typeA = getFontType(xref, fontDict, &embFontIDA);

  // create the font object
223
  font = nullptr;
224 225 226
  if (typeA < fontCIDType0) {
    font = new Gfx8BitFont(xref, tagA, idA, nameA, typeA, embFontIDA,
			   fontDict);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
227
  } else {
228 229
    font = new GfxCIDFont(xref, tagA, idA, nameA, typeA, embFontIDA,
			  fontDict);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
230 231 232 233 234
  }

  return font;
}

235 236
GfxFont::GfxFont(const char *tagA, Ref idA, GooString *nameA,
		 GfxFontType typeA, Ref embFontIDA) {
237
  ok = false;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
238 239 240
  tag = new GooString(tagA);
  id = idA;
  name = nameA;
241 242
  type = typeA;
  embFontID = embFontIDA;
243 244
  embFontName = nullptr;
  family = nullptr;
245 246
  stretch = StretchNotDefined;
  weight = WeightNotDefined;
247
  refCnt = 1;
248
  encodingName = new GooString("");
249
  hasToUnicode = false;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
250 251 252 253
}

GfxFont::~GfxFont() {
  delete tag;
254
  delete family;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
255 256 257 258 259 260
  if (name) {
    delete name;
  }
  if (embFontName) {
    delete embFontName;
  }
261 262 263
  if (encodingName) {
    delete encodingName;
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
264 265
}

266 267 268 269 270 271 272 273 274
void GfxFont::incRefCnt() {
  refCnt++;
}

void GfxFont::decRefCnt() {
  if (--refCnt == 0)
    delete this;
}

275 276 277 278 279 280 281 282 283 284 285 286 287 288
// This function extracts three pieces of information:
// 1. the "expected" font type, i.e., the font type implied by
//    Font.Subtype, DescendantFont.Subtype, and
//    FontDescriptor.FontFile3.Subtype
// 2. the embedded font object ID
// 3. the actual font type - determined by examining the embedded font
//    if there is one, otherwise equal to the expected font type
// If the expected and actual font types don't match, a warning
// message is printed.  The expected font type is not used for
// anything else.
GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
  GfxFontType t, expectedType;
  FoFiIdentifierType fft;
  Dict *fontDict2;
289
  bool isType0, err;
290 291 292

  t = fontUnknownType;
  embID->num = embID->gen = -1;
293
  err = false;
294

Albert Astals Cid's avatar
Albert Astals Cid committed
295
  Object subtype = fontDict->lookup("Subtype");
296
  expectedType = fontUnknownType;
297
  isType0 = false;
298 299 300 301 302 303 304 305 306
  if (subtype.isName("Type1") || subtype.isName("MMType1")) {
    expectedType = fontType1;
  } else if (subtype.isName("Type1C")) {
    expectedType = fontType1C;
  } else if (subtype.isName("Type3")) {
    expectedType = fontType3;
  } else if (subtype.isName("TrueType")) {
    expectedType = fontTrueType;
  } else if (subtype.isName("Type0")) {
307
    isType0 = true;
308 309 310 311 312 313
  } else {
    error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'",
	  subtype.isName() ? subtype.getName() : "???");
  }

  fontDict2 = fontDict;
Albert Astals Cid's avatar
Albert Astals Cid committed
314 315 316 317
  Object obj1 = fontDict->lookup("DescendantFonts");
  Object obj2; // Do not move to inside the if
               // we need it around so that fontDict2 remains valid
  if (obj1.isArray()) {
318 319
    if (obj1.arrayGetLength() == 0) {
      error(errSyntaxWarning, -1, "Empty DescendantFonts array in font");
Albert Astals Cid's avatar
Albert Astals Cid committed
320 321 322 323 324
    } else {
      obj2 = obj1.arrayGet(0);
      if (obj2.isDict()) {
	if (!isType0) {
	  error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
325
	}
Albert Astals Cid's avatar
Albert Astals Cid committed
326 327 328 329 330 331 332 333 334 335
	fontDict2 = obj2.getDict();
	subtype = fontDict2->lookup("Subtype");
	if (subtype.isName("CIDFontType0")) {
	  if (isType0) {
	    expectedType = fontCIDType0;
	  }
	} else if (subtype.isName("CIDFontType2")) {
	  if (isType0) {
	    expectedType = fontCIDType2;
	  }
336 337 338 339 340
	}
      }
    }
  }

Albert Astals Cid's avatar
Albert Astals Cid committed
341 342 343 344
  Object fontDesc = fontDict2->lookup("FontDescriptor");
  if (fontDesc.isDict()) {
    Object obj3 = fontDesc.dictLookupNF("FontFile");
    if (obj3.isRef()) {
345 346
      *embID = obj3.getRef();
      if (expectedType != fontType1) {
347
	err = true;
348 349
      }
    }
Albert Astals Cid's avatar
Albert Astals Cid committed
350
    if (embID->num == -1 && (obj3 = fontDesc.dictLookupNF("FontFile2"), obj3.isRef())) {
351 352 353 354
      *embID = obj3.getRef();
      if (isType0) {
	expectedType = fontCIDType2;
      } else if (expectedType != fontTrueType) {
355
	err = true;
356 357
      }
    }
Albert Astals Cid's avatar
Albert Astals Cid committed
358
    if (embID->num == -1 && (obj3 = fontDesc.dictLookupNF("FontFile3"), obj3.isRef())) {
359
      *embID = obj3.getRef();
Albert Astals Cid's avatar
Albert Astals Cid committed
360 361 362
      Object obj4 = obj3.fetch(xref);
      if (obj4.isStream()) {
	subtype = obj4.streamGetDict()->lookup("Subtype");
363 364
	if (subtype.isName("Type1")) {
	  if (expectedType != fontType1) {
365
	    err = true;
366 367 368 369 370 371
	    expectedType = isType0 ? fontCIDType0 : fontType1;
	  }
	} else if (subtype.isName("Type1C")) {
	  if (expectedType == fontType1) {
	    expectedType = fontType1C;
	  } else if (expectedType != fontType1C) {
372
	    err = true;
373 374 375 376
	    expectedType = isType0 ? fontCIDType0C : fontType1C;
	  }
	} else if (subtype.isName("TrueType")) {
	  if (expectedType != fontTrueType) {
377
	    err = true;
378 379 380 381 382 383
	    expectedType = isType0 ? fontCIDType2 : fontTrueType;
	  }
	} else if (subtype.isName("CIDFontType0C")) {
	  if (expectedType == fontCIDType0) {
	    expectedType = fontCIDType0C;
	  } else {
384
	    err = true;
385 386 387 388 389 390 391 392 393 394 395 396
	    expectedType = isType0 ? fontCIDType0C : fontType1C;
	  }
	} else if (subtype.isName("OpenType")) {
	  if (expectedType == fontTrueType) {
	    expectedType = fontTrueTypeOT;
	  } else if (expectedType == fontType1) {
	    expectedType = fontType1COT;
	  } else if (expectedType == fontCIDType0) {
	    expectedType = fontCIDType0COT;
	  } else if (expectedType == fontCIDType2) {
	    expectedType = fontCIDType2OT;
	  } else {
397
	    err = true;
398 399 400 401 402 403 404 405 406 407 408
	  }
	} else {
	  error(errSyntaxError, -1, "Unknown font type '{0:s}'",
		subtype.isName() ? subtype.getName() : "???");
	}
      }
    }
  }

  t = fontUnknownType;
  if (embID->num >= 0) {
Albert Astals Cid's avatar
Albert Astals Cid committed
409 410
    Object obj3(embID->num, embID->gen);
    Object obj4 = obj3.fetch(xref);
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
    if (obj4.isStream()) {
      obj4.streamReset();
      fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream());
      obj4.streamClose();
      switch (fft) {
      case fofiIdType1PFA:
      case fofiIdType1PFB:
	t = fontType1;
	break;
      case fofiIdCFF8Bit:
	t = isType0 ? fontCIDType0C : fontType1C;
	break;
      case fofiIdCFFCID:
	t = fontCIDType0C;
	break;
      case fofiIdTrueType:
      case fofiIdTrueTypeCollection:
	t = isType0 ? fontCIDType2 : fontTrueType;
	break;
      case fofiIdOpenTypeCFF8Bit:
	t = expectedType; // hack: open type always == expected type? s. bug-poppler20605.pdf
	break;
      case fofiIdOpenTypeCFFCID:
	t = fontCIDType0COT;
	break;
      default:
	error(errSyntaxError, -1, "Embedded font file may be invalid");
	break;
      }
    }
  }

  if (t == fontUnknownType) {
    t = expectedType;
  }

  if (t != expectedType) {
448
    err = true;
449 450 451 452 453 454 455 456 457 458
  }

  if (err) {
    error(errSyntaxWarning, -1,
	  "Mismatch between font type and embedded font file");
  }

  return t;
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
459 460 461 462 463 464 465 466
void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
  double t;

  // assume Times-Roman by default (for substitution purposes)
  flags = fontSerif;

  missingWidth = 0;

Albert Astals Cid's avatar
Albert Astals Cid committed
467 468
  Object obj1 = fontDict->lookup("FontDescriptor");
  if (obj1.isDict()) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
469 470

    // get flags
Albert Astals Cid's avatar
Albert Astals Cid committed
471 472
    Object obj2 = obj1.dictLookup("Flags");
    if (obj2.isInt()) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
473 474 475 476
      flags = obj2.getInt();
    }

    // get name
Albert Astals Cid's avatar
Albert Astals Cid committed
477
    obj2 = obj1.dictLookup("FontName");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
478 479 480
    if (obj2.isName()) {
      embFontName = new GooString(obj2.getName());
    }
481
    if (embFontName == nullptr) {
482
      // get name with typo
Albert Astals Cid's avatar
Albert Astals Cid committed
483
      obj2 = obj1.dictLookup("Fontname");
484 485
      if (obj2.isName()) {
        embFontName = new GooString(obj2.getName());
486
        error(errSyntaxWarning, -1, "The file uses Fontname instead of FontName please notify the creator that the file is broken");
487 488
      }
    }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
489

490
    // get family
Albert Astals Cid's avatar
Albert Astals Cid committed
491
    obj2 = obj1.dictLookup("FontFamily");
492 493 494
    if (obj2.isString()) family = new GooString(obj2.getString());

    // get stretch
Albert Astals Cid's avatar
Albert Astals Cid committed
495
    obj2 = obj1.dictLookup("FontStretch");
496 497 498 499 500 501 502 503 504 505
    if (obj2.isName()) {
      if (strcmp(obj2.getName(), "UltraCondensed") == 0) stretch = UltraCondensed;
      else if (strcmp(obj2.getName(), "ExtraCondensed") == 0) stretch = ExtraCondensed;
      else if (strcmp(obj2.getName(), "Condensed") == 0) stretch = Condensed;
      else if (strcmp(obj2.getName(), "SemiCondensed") == 0) stretch = SemiCondensed;
      else if (strcmp(obj2.getName(), "Normal") == 0) stretch = Normal;
      else if (strcmp(obj2.getName(), "SemiExpanded") == 0) stretch = SemiExpanded;
      else if (strcmp(obj2.getName(), "Expanded") == 0) stretch = Expanded;
      else if (strcmp(obj2.getName(), "ExtraExpanded") == 0) stretch = ExtraExpanded;
      else if (strcmp(obj2.getName(), "UltraExpanded") == 0) stretch = UltraExpanded;
506
      else error(errSyntaxWarning, -1, "Invalid Font Stretch");
507 508 509
    }
    
    // get weight
Albert Astals Cid's avatar
Albert Astals Cid committed
510
    obj2 = obj1.dictLookup("FontWeight");
511 512 513 514 515 516 517 518 519 520
    if (obj2.isNum()) {
      if (obj2.getNum() == 100) weight = W100;
      else if (obj2.getNum() == 200) weight = W200;
      else if (obj2.getNum() == 300) weight = W300;
      else if (obj2.getNum() == 400) weight = W400;
      else if (obj2.getNum() == 500) weight = W500;
      else if (obj2.getNum() == 600) weight = W600;
      else if (obj2.getNum() == 700) weight = W700;
      else if (obj2.getNum() == 800) weight = W800;
      else if (obj2.getNum() == 900) weight = W900;
521
      else error(errSyntaxWarning, -1, "Invalid Font Weight");
522 523
    }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
524
    // look for MissingWidth
Albert Astals Cid's avatar
Albert Astals Cid committed
525
    obj2 = obj1.dictLookup("MissingWidth");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
526 527 528 529 530
    if (obj2.isNum()) {
      missingWidth = obj2.getNum();
    }

    // get Ascent and Descent
Albert Astals Cid's avatar
Albert Astals Cid committed
531
    obj2 = obj1.dictLookup("Ascent");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
532 533
    if (obj2.isNum()) {
      t = 0.001 * obj2.getNum();
534 535 536 537 538 539 540
      // some broken font descriptors specify a negative ascent
      if (t < 0) {
	t = -t;
      }
      // some broken font descriptors set ascent and descent to 0;
      // others set it to ridiculous values (e.g., 32768)
      if (t != 0 && t < 3) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
541 542 543
	ascent = t;
      }
    }
Albert Astals Cid's avatar
Albert Astals Cid committed
544
    obj2 = obj1.dictLookup("Descent");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
545 546
    if (obj2.isNum()) {
      t = 0.001 * obj2.getNum();
547 548 549 550
      // some broken font descriptors specify a positive descent
      if (t > 0) {
	t = -t;
      }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
551
      // some broken font descriptors set ascent and descent to 0
552
      if (t != 0 && t > -3) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
553 554 555 556 557
	descent = t;
      }
    }

    // font FontBBox
Albert Astals Cid's avatar
Albert Astals Cid committed
558 559 560 561 562
    obj2 = obj1.dictLookup("FontBBox");
    if (obj2.isArray()) {
      for (int i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
	Object obj3 = obj2.arrayGet(i);
	if (obj3.isNum()) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
563 564 565 566 567 568 569 570 571 572 573
	  fontBBox[i] = 0.001 * obj3.getNum();
	}
      }
    }
  }
}

CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
					      CharCodeToUnicode *ctu) {
  GooString *buf;

Albert Astals Cid's avatar
Albert Astals Cid committed
574 575
  Object obj1 = fontDict->lookup("ToUnicode");
  if (!obj1.isStream()) {
576
    return nullptr;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
577 578
  }
  buf = new GooString();
579
  obj1.getStream()->fillGooString(buf);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
580 581 582 583 584 585
  obj1.streamClose();
  if (ctu) {
    ctu->mergeCMap(buf, nBits);
  } else {
    ctu = CharCodeToUnicode::parseCMap(buf, nBits);
  }
586
  hasToUnicode = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
587 588 589 590
  delete buf;
  return ctu;
}

591
GfxFontLoc *GfxFont::locateFont(XRef *xref, PSOutputDev *ps) {
592 593 594 595
  GfxFontLoc *fontLoc;
  SysFontType sysFontType;
  GooString *path, *base14Name, *substName;
  int substIdx, fontNum;
596
  bool embed;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
597

598
  if (type == fontType3) {
599
    return nullptr;
600 601 602 603
  }

  //----- embedded font
  if (embFontID.num >= 0) {
604
    embed = true;
Albert Astals Cid's avatar
Albert Astals Cid committed
605 606
    Object refObj(embFontID.num, embFontID.gen);
    Object embFontObj = refObj.fetch(xref);
607 608
    if (!embFontObj.isStream()) {
      error(errSyntaxError, -1, "Embedded font object is wrong type");
609
      embed = false;
610 611 612 613 614 615 616
    }
    if (embed) {
      if (ps) {
	switch (type) {
	case fontType1:
	case fontType1C:
	case fontType1COT:
617
	  embed = ps->getEmbedType1();
618 619 620
	  break;
	case fontTrueType:
	case fontTrueTypeOT:
621
	  embed = ps->getEmbedTrueType();
622 623 624
	  break;
	case fontCIDType0C:
	case fontCIDType0COT:
625
	  embed = ps->getEmbedCIDPostScript();
626 627 628
	  break;
	case fontCIDType2:
	case fontCIDType2OT:
629
	  embed = ps->getEmbedCIDTrueType();
630 631 632 633 634 635 636 637 638 639 640 641
	  break;
	default:
	  break;
	}
      }
      if (embed) {
	fontLoc = new GfxFontLoc();
	fontLoc->locType = gfxFontLocEmbedded;
	fontLoc->fontType = type;
	fontLoc->embFontID = embFontID;
	return fontLoc;
      }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
642 643 644
    }
  }

645
  //----- PS passthrough
646
  if (ps && !isCIDFont() && ps->getFontPassthrough()) {
647 648 649 650 651 652
    fontLoc = new GfxFontLoc();
    fontLoc->locType = gfxFontLocResident;
    fontLoc->fontType = fontType1;
    fontLoc->path = name->copy();
    return fontLoc;
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
653

654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
  //----- PS resident Base-14 font
  if (ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
    fontLoc = new GfxFontLoc();
    fontLoc->locType = gfxFontLocResident;
    fontLoc->fontType = fontType1;
    fontLoc->path = new GooString(((Gfx8BitFont *)this)->base14->base14Name);
    return fontLoc;
  }

  //----- external font file (fontFile, fontDir)
  if (name && (path = globalParams->findFontFile(name))) {
    if ((fontLoc = getExternalFont(path, isCIDFont()))) {
      return fontLoc;
    }
  }

  //----- external font file for Base-14 font
  if (!ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
    base14Name = new GooString(((Gfx8BitFont *)this)->base14->base14Name);
673
    if ((path = globalParams->findBase14FontFile(base14Name, this))) {
674
      if ((fontLoc = getExternalFont(path, false))) {
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
	delete base14Name;
	return fontLoc;
      }
    }
    delete base14Name;
  }

  //----- system font
  if ((path = globalParams->findSystemFontFile(this, &sysFontType,
					       &fontNum))) {
    if (isCIDFont()) {
      if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
	fontLoc = new GfxFontLoc();
	fontLoc->locType = gfxFontLocExternal;
	fontLoc->fontType = fontCIDType2;
	fontLoc->path = path;
	fontLoc->fontNum = fontNum;
	return fontLoc;
      }
    } else {
      if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
	fontLoc = new GfxFontLoc();
	fontLoc->locType = gfxFontLocExternal;
	fontLoc->fontType = fontTrueType;
	fontLoc->path = path;
	return fontLoc;
      } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) {
	fontLoc = new GfxFontLoc();
	fontLoc->locType = gfxFontLocExternal;
	fontLoc->fontType = fontType1;
	fontLoc->path = path;
	fontLoc->fontNum = fontNum;
	return fontLoc;
      }
    }
    delete path;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
711
  }
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730

  if (!isCIDFont()) {

    //----- 8-bit font substitution
    if (flags & fontFixedWidth) {
      substIdx = 0;
    } else if (flags & fontSerif) {
      substIdx = 8;
    } else {
      substIdx = 4;
    }
    if (isBold()) {
      substIdx += 2;
    }
    if (isItalic()) {
      substIdx += 1;
    }
    substName = new GooString(base14SubstFonts[substIdx]);
    if (ps) {
Albert Astals Cid's avatar
Albert Astals Cid committed
731
      error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:s}'",
732
	    base14SubstFonts[substIdx], name ? name->c_str() : "null");
733 734 735 736 737 738 739 740 741 742
      fontLoc = new GfxFontLoc();
      fontLoc->locType = gfxFontLocResident;
      fontLoc->fontType = fontType1;
      fontLoc->path = substName;
      fontLoc->substIdx = substIdx;
      return fontLoc;
    } else {
      path = globalParams->findFontFile(substName);
      delete substName;
      if (path) {
743
	if ((fontLoc = getExternalFont(path, false))) {
Albert Astals Cid's avatar
Albert Astals Cid committed
744
	  error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:s}'",
745
		  base14SubstFonts[substIdx], name ? name->c_str() : "");
746 747 748 749 750 751 752 753
	  name = new GooString(base14SubstFonts[substIdx]);
	  fontLoc->substIdx = substIdx;
	  return fontLoc;
	}
      }
    }

    // failed to find a substitute font
754
    return nullptr;
Ed Avis's avatar
Ed Avis committed
755
  }
756 757

  // failed to find a substitute font
758
  return nullptr;
759 760 761 762 763 764 765
}

GfxFontLoc *GfxFont::locateBase14Font(GooString *base14Name) {
  GooString *path;

  path = globalParams->findFontFile(base14Name);
  if (!path) {
766
    return nullptr;
Ed Avis's avatar
Ed Avis committed
767
  }
768
  return getExternalFont(path, false);
769 770
}

771
GfxFontLoc *GfxFont::getExternalFont(GooString *path, bool cid) {
772 773 774 775
  FoFiIdentifierType fft;
  GfxFontType fontType;
  GfxFontLoc *fontLoc;

776
  fft = FoFiIdentifier::identifyFile(path->c_str());
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
  switch (fft) {
  case fofiIdType1PFA:
  case fofiIdType1PFB:
    fontType = fontType1;
    break;
  case fofiIdCFF8Bit:
    fontType = fontType1C;
    break;
  case fofiIdCFFCID:
    fontType = fontCIDType0C;
    break;
  case fofiIdTrueType:
  case fofiIdTrueTypeCollection:
    fontType = cid ? fontCIDType2 : fontTrueType;
    break;
  case fofiIdOpenTypeCFF8Bit:
    fontType = fontType1COT;
    break;
  case fofiIdOpenTypeCFFCID:
    fontType = fontCIDType0COT;
    break;
  case fofiIdUnknown:
  case fofiIdError:
  default:
    fontType = fontUnknownType;
    break;
  }
  if (fontType == fontUnknownType ||
      (cid ? (fontType < fontCIDType0)
           : (fontType >= fontCIDType0))) {
    delete path;
808
    return nullptr;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
809
  }
810 811 812 813 814
  fontLoc = new GfxFontLoc();
  fontLoc->locType = gfxFontLocExternal;
  fontLoc->fontType = fontType;
  fontLoc->path = path;
  return fontLoc;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
815 816 817 818 819 820
}

char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
  char *buf;
  Stream *str;

Albert Astals Cid's avatar
Albert Astals Cid committed
821 822
  Object obj1(embFontID.num, embFontID.gen);
  Object obj2 = obj1.fetch(xref);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
823
  if (!obj2.isStream()) {
824
    error(errSyntaxError, -1, "Embedded font file is not a stream");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
825
    embFontID.num = -1;
826
    *len = 0;
827
    return nullptr;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
828 829 830
  }
  str = obj2.getStream();

831
  buf = (char*)str->toUnsignedChars(len);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
832 833 834 835 836
  str->close();

  return buf;
}

837 838 839 840 841 842 843 844 845 846 847 848 849

struct AlternateNameMap {
  const char *name;
  const char *alt;
};

static const AlternateNameMap alternateNameMap[] =
{
  { "fi", "f_i" },
  { "fl", "f_l" },
  { "ff", "f_f" },
  { "ffi", "f_f_i" },
  { "ffl", "f_f_l" },
850
  { nullptr,    nullptr }
851 852 853 854 855 856 857 858 859 860
};

const char *GfxFont::getAlternateName(const char *name) {
  const AlternateNameMap *map = alternateNameMap;
  while (map->name) {
    if (strcmp(name, map->name) == 0) {
      return map->alt;
    }
    map++;
  }
861
  return nullptr;
862 863
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
864 865 866 867
//------------------------------------------------------------------------
// Gfx8BitFont
//------------------------------------------------------------------------

868 869 870
// Parse character names of the form 'Axx', 'xx', 'Ann', 'ABnn', or
// 'nn', where 'A' and 'B' are any letters, 'xx' is two hex digits,
// and 'nn' is decimal digits.
871
static bool parseNumericName(const char *s, bool hex, unsigned int *u) {
872 873 874 875 876 877 878 879 880 881 882 883 884 885
  char *endptr;

  // Strip leading alpha characters.
  if (hex) {
    int n = 0;

    // Get string length while ignoring junk at end.
    while (isalnum(s[n]))
      ++n;

    // Only 2 hex characters with optional leading alpha is allowed.
    if (n == 3 && isalpha(*s)) {
      ++s;
    } else if (n != 2) {
886
      return false;
887 888 889 890 891 892 893 894 895 896
    }
  } else {
    // Strip up to two alpha characters.
    for (int i = 0; i < 2 && isalpha(*s); ++i)
      ++s;
  }

  int v = strtol(s, &endptr, hex ? 16 : 10);

  if (endptr == s)
897
    return false;
898 899 900 901 902 903 904 905

  // Skip trailing junk characters.
  while (*endptr != '\0' && !isalnum(*endptr))
    ++endptr;

  if (*endptr == '\0') {
    if (u)
      *u = v;
906
    return true;
907
  }
908
  return false;
909 910
}

911
// Returns true if the font has character names like xx or Axx which
912
// should be parsed for hex or decimal values.
913 914
static bool testForNumericNames(Dict *fontDict, bool hex) {
  bool numeric = true;
915

Albert Astals Cid's avatar
Albert Astals Cid committed
916
  Object enc = fontDict->lookup("Encoding");
917
  if (!enc.isDict()) {
918
    return false;
919 920
  }

Albert Astals Cid's avatar
Albert Astals Cid committed
921
  Object diff = enc.dictLookup("Differences");
922
  if (!diff.isArray()) {
923
    return false;
924 925 926
  }

  for (int i = 0; i < diff.arrayGetLength() && numeric; ++i) {
Albert Astals Cid's avatar
Albert Astals Cid committed
927
    Object obj = diff.arrayGet(i);
928 929 930
    if (obj.isInt()) {
      // All sequences must start between character codes 0 and 5.
      if (obj.getInt() > 5)
931
	numeric = false;
932 933
    } else if (obj.isName()) {
      // All character names must sucessfully parse.
934
      if (!parseNumericName(obj.getName(), hex, nullptr))
935
	numeric = false;
936
    } else {
937
      numeric = false;
938 939 940 941 942 943
    }
  }

  return numeric;
}

944
Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
945 946
			 GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
  GfxFont(tagA, idA, nameA, typeA, embFontIDA) {
947
  GooString *name2;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
948
  BuiltinFont *builtinFont;
949
  const char **baseEnc;
950
  bool baseEncFromFontFile;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
951 952 953 954
  char *buf;
  int len;
  FoFiType1 *ffT1;
  FoFiType1C *ffT1C;
Albert Astals Cid's avatar
Albert Astals Cid committed
955
  int code;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
956
  char *charName;
957 958
  bool missing, hex;
  bool numeric;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
959 960 961 962
  Unicode toUnicode[256];
  Unicode uBuf[8];
  double mul;
  int firstChar, lastChar;
963
  unsigned short w;
Albert Astals Cid's avatar
Albert Astals Cid committed
964
  Object obj1;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
965 966
  int n, i, a, b, m;

967
  refCnt = 1;
968
  ctu = nullptr;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
969 970 971

  // do font name substitution for various aliases of the Base 14 font
  // names
972
  base14 = nullptr;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
973
  if (name) {
974 975 976 977 978 979 980 981 982
    name2 = name->copy();
    i = 0;
    while (i < name2->getLength()) {
      if (name2->getChar(i) == ' ') {
	name2->del(i);
      } else {
	++i;
      }
    }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
983
    a = 0;
984 985
    b = sizeof(base14FontMap) / sizeof(Base14FontMapEntry);
    // invariant: base14FontMap[a].altName <= name2 < base14FontMap[b].altName
Kristian Høgsberg's avatar
Kristian Høgsberg committed
986 987
    while (b - a > 1) {
      m = (a + b) / 2;
988
      if (name2->cmp(base14FontMap[m].altName) >= 0) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
989 990 991 992 993
	a = m;
      } else {
	b = m;
      }
    }
994 995
    if (!name2->cmp(base14FontMap[a].altName)) {
      base14 = &base14FontMap[a];
Kristian Høgsberg's avatar
Kristian Høgsberg committed
996
    }
997
    delete name2;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
998 999 1000
  }

  // is it a built-in font?
1001
  builtinFont = nullptr;
1002
  if (base14) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1003
    for (i = 0; i < nBuiltinFonts; ++i) {
1004
      if (!strcmp(base14->base14Name, builtinFonts[i].name)) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
	builtinFont = &builtinFonts[i];
	break;
      }
    }
  }

  // default ascent/descent values
  if (builtinFont) {
    ascent = 0.001 * builtinFont->ascent;
    descent = 0.001 * builtinFont->descent;
    fontBBox[0] = 0.001 * builtinFont->bbox[0];
    fontBBox[1] = 0.001 * builtinFont->bbox[1];
    fontBBox[2] = 0.001 * builtinFont->bbox[2];
    fontBBox[3] = 0.001 * builtinFont->bbox[3];
  } else {
    ascent = 0.95;
    descent = -0.35;
    fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
  }

  // get info from font descriptor
  readFontDescriptor(xref, fontDict);

1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
  // for non-embedded fonts, don't trust the ascent/descent/bbox
  // values from the font descriptor
  if (builtinFont && embFontID.num < 0) {
    ascent = 0.001 * builtinFont->ascent;
    descent = 0.001 * builtinFont->descent;
    fontBBox[0] = 0.001 * builtinFont->bbox[0];
    fontBBox[1] = 0.001 * builtinFont->bbox[1];
    fontBBox[2] = 0.001 * builtinFont->bbox[2];
    fontBBox[3] = 0.001 * builtinFont->bbox[3];
  }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
1039 1040 1041
  // get font matrix
  fontMat[0] = fontMat[3] = 1;
  fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
Albert Astals Cid's avatar
Albert Astals Cid committed
1042 1043
  obj1 = fontDict->lookup("FontMatrix");
  if (obj1.isArray()) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1044
    for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
Albert Astals Cid's avatar
Albert Astals Cid committed
1045 1046
      Object obj2 = obj1.arrayGet(i);
      if (obj2.isNum()) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1047 1048 1049 1050 1051 1052 1053
	fontMat[i] = obj2.getNum();
      }
    }
  }

  // get Type 3 bounding box, font definition, and resources
  if (type == fontType3) {
Albert Astals Cid's avatar
Albert Astals Cid committed
1054 1055
    obj1 = fontDict->lookup("FontBBox");
    if (obj1.isArray()) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1056
      for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) {
Albert Astals Cid's avatar
Albert Astals Cid committed
1057 1058
	Object obj2 = obj1.arrayGet(i);
	if (obj2.isNum()) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1059 1060 1061 1062
	  fontBBox[i] = obj2.getNum();
	}
      }
    }
Albert Astals Cid's avatar
Albert Astals Cid committed
1063 1064
    charProcs = fontDict->lookup("CharProcs");
    if (!charProcs.isDict()) {
1065 1066
      error(errSyntaxError, -1,
	    "Missing or invalid CharProcs dictionary in Type 3 font");
Albert Astals Cid's avatar
Albert Astals Cid committed
1067
      charProcs.setToNull();
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1068
    }
Albert Astals Cid's avatar
Albert Astals Cid committed
1069 1070 1071
    resources = fontDict->lookup("Resources");
    if (!resources.isDict()) {
      resources.setToNull();
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
    }
  }

  //----- build the font encoding -----

  // Encodings start with a base encoding, which can come from
  // (in order of priority):
  //   1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
  //        - MacRoman / MacExpert / WinAnsi / Standard
  //   2. embedded or external font file
  //   3. default:
  //        - builtin --> builtin encoding
1084
  //        - TrueType --> WinAnsiEncoding
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1085 1086 1087 1088 1089
  //        - others --> StandardEncoding
  // and then add a list of differences (if any) from
  // FontDict.Encoding.Differences.

  // check FontDict for base encoding
1090 1091
  hasEncoding = false;
  usesMacRomanEnc = false;
1092
  baseEnc = nullptr;
1093
  baseEncFromFontFile = false;
Albert Astals Cid's avatar
Albert Astals Cid committed
1094
  obj1 = fontDict->lookup("Encoding");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1095
  if (obj1.isDict()) {
Albert Astals Cid's avatar
Albert Astals Cid committed
1096
    Object obj2 = obj1.dictLookup("BaseEncoding");
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1097
    if (obj2.isName("MacRomanEncoding")) {
1098 1099
      hasEncoding = true;
      usesMacRomanEnc = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1100 1101
      baseEnc = macRomanEncoding;
    } else if (obj2.isName("MacExpertEncoding")) {
1102
      hasEncoding = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1103 1104
      baseEnc = macExpertEncoding;
    } else if (obj2.isName("WinAnsiEncoding")) {
1105
      hasEncoding = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1106 1107 1108
      baseEnc = winAnsiEncoding;
    }
  } else if (obj1.isName("MacRomanEncoding")) {
1109 1110
    hasEncoding = true;
    usesMacRomanEnc = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1111 1112
    baseEnc = macRomanEncoding;
  } else if (obj1.isName("MacExpertEncoding")) {
1113
    hasEncoding = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1114 1115
    baseEnc = macExpertEncoding;
  } else if (obj1.isName("WinAnsiEncoding")) {
1116
    hasEncoding = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1117 1118 1119
    baseEnc = winAnsiEncoding;
  }

1120
  // check embedded font file for base encoding
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1121 1122
  // (only for Type 1 fonts - trying to get an encoding out of a
  // TrueType font is a losing proposition)
1123 1124 1125
  ffT1 = nullptr;
  ffT1C = nullptr;
  buf = nullptr;
1126 1127 1128 1129 1130 1131 1132 1133
  if (type == fontType1 && embFontID.num >= 0) {
    if ((buf = readEmbFontFile(xref, &len))) {
      if ((ffT1 = FoFiType1::make(buf, len))) {
	if (ffT1->getName()) {
	  if (embFontName) {
	    delete embFontName;
	  }
	  embFontName = new GooString(ffT1->getName());
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1134
	}
1135 1136
	if (!baseEnc) {
	  baseEnc = (const char **)ffT1->getEncoding();
1137
	  baseEncFromFontFile = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1138 1139
	}
      }
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
      gfree(buf);
    }
  } else if (type == fontType1C && embFontID.num >= 0) {
    if ((buf = readEmbFontFile(xref, &len))) {
      if ((ffT1C = FoFiType1C::make(buf, len))) {
	if (ffT1C->getName()) {
	  if (embFontName) {
	    delete embFontName;
	  }
	  embFontName = new GooString(ffT1C->getName());
	}
	if (!baseEnc) {
	  baseEnc = (const char **)ffT1C->getEncoding();
1153
	  baseEncFromFontFile = true;
1154
	}
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1155
      }
1156
      gfree(buf);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1157 1158 1159 1160 1161
    }
  }

  // get default base encoding
  if (!baseEnc) {
1162
    if (builtinFont && embFontID.num < 0) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1163
      baseEnc = builtinFont->defaultBaseEnc;
1164
      hasEncoding = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1165 1166 1167 1168 1169 1170 1171
    } else if (type == fontTrueType) {
      baseEnc = winAnsiEncoding;
    } else {
      baseEnc = standardEncoding;
    }
  }

1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
  if (baseEncFromFontFile) {
    encodingName->Set("Builtin");
  } else if (baseEnc == winAnsiEncoding) {
    encodingName->Set("WinAnsi");
  } else if (baseEnc == macRomanEncoding) {
    encodingName->Set("MacRoman");
  } else if (baseEnc == macExpertEncoding) {
    encodingName->Set("MacExpert");
  } else if (baseEnc == symbolEncoding) {
    encodingName->Set("Symbol");
  } else if (baseEnc == zapfDingbatsEncoding) {
    encodingName->Set("ZapfDingbats");
  } else {
    encodingName->Set("Standard");
  }

Kristian Høgsberg's avatar
Kristian Høgsberg committed