[poppler] Branch 'xpdf303merge' - poppler/Annot.cc poppler/ArthurOutputDev.cc poppler/CairoFontEngine.cc poppler/CharCodeToUnicode.h poppler/CMap.cc poppler/CMap.h poppler/FontInfo.cc poppler/Gfx.cc poppler/GfxFont.cc poppler/GfxFont.h poppler/GfxState.cc poppler/GfxState.h poppler/GlobalParams.cc poppler/GlobalParams.h poppler/GlobalParamsWin.cc poppler/PreScanOutputDev.cc poppler/PSOutputDev.cc poppler/PSOutputDev.h poppler/SplashOutputDev.cc poppler/XRef.cc

Albert Astals Cid aacid at kemper.freedesktop.org
Wed Feb 1 13:55:48 PST 2012


 poppler/Annot.cc            |    6 
 poppler/ArthurOutputDev.cc  |   47 --
 poppler/CMap.cc             |  153 ++++++++
 poppler/CMap.h              |   16 
 poppler/CairoFontEngine.cc  |   43 --
 poppler/CharCodeToUnicode.h |    1 
 poppler/FontInfo.cc         |    8 
 poppler/Gfx.cc              |  363 +++++++++++--------
 poppler/GfxFont.cc          |  831 +++++++++++++++++++++++++++++---------------
 poppler/GfxFont.h           |   34 -
 poppler/GfxState.cc         |   81 ++--
 poppler/GfxState.h          |    2 
 poppler/GlobalParams.cc     |  738 ++++++++++++++++++++++-----------------
 poppler/GlobalParams.h      |  112 ++---
 poppler/GlobalParamsWin.cc  |  180 +++++++--
 poppler/PSOutputDev.cc      |  591 +++++++++++++++----------------
 poppler/PSOutputDev.h       |   12 
 poppler/PreScanOutputDev.cc |   10 
 poppler/SplashOutputDev.cc  |   59 +--
 poppler/XRef.cc             |   16 
 20 files changed, 2008 insertions(+), 1295 deletions(-)

New commits:
commit 4fcd42cfa4424992cd4b36af38bc6230ce0706c9
Author: Albert Astals Cid <aacid at kde.org>
Date:   Wed Feb 1 22:53:03 2012 +0100

    [xpdf303] More merges from Thomas (with minor fixes from me)
    
    Basically fonts related and some other small stuff

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 235120c..9f07b2f 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -3082,10 +3082,10 @@ void AnnotWidget::drawText(GooString *text, GooString *da, GfxResources *resourc
           // We are forcing ZaDb but the font does not exist
           // so create a fake one
           Ref r; // dummy Ref, it's not used at all in this codepath
-          r.num = 0;
-          r.gen = 0;
+          r.num = -1;
+          r.gen = -1;
           Dict *d = new Dict(xref);
-          font = new Gfx8BitFont(xref, "ZaDb", r, new GooString("ZapfDingbats"), fontType1, d);
+          font = new Gfx8BitFont(xref, "ZaDb", r, new GooString("ZapfDingbats"), fontType1, r, d);
           delete d;
           freeFont = gTrue;
           addDingbatsResource = gTrue;
diff --git a/poppler/ArthurOutputDev.cc b/poppler/ArthurOutputDev.cc
index f0c3090..92bc84f 100644
--- a/poppler/ArthurOutputDev.cc
+++ b/poppler/ArthurOutputDev.cc
@@ -270,18 +270,17 @@ void ArthurOutputDev::updateFont(GfxState *state)
 {
 #ifdef HAVE_SPLASH
   GfxFont *gfxFont;
+  GfxFontLoc *fontLoc;
   GfxFontType fontType;
   SplashOutFontFileID *id;
   SplashFontFile *fontFile;
   SplashFontSrc *fontsrc = NULL;
   FoFiTrueType *ff;
-  Ref embRef;
   Object refObj, strObj;
   GooString *fileName;
   char *tmpBuf;
   int tmpBufLen;
   int *codeToGID;
-  DisplayFontParam *dfp;
   double *textMat;
   double m11, m12, m21, m22, fontSize;
   SplashCoord mat[4];
@@ -309,36 +308,24 @@ void ArthurOutputDev::updateFont(GfxState *state)
 
   } else {
 
-    // if there is an embedded font, write it to disk
-    if (gfxFont->getEmbeddedFontID(&embRef)) {
+    if (!(fontLoc = gfxFont->locateFont(xref, gFalse))) {
+      error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
+	    gfxFont->getName() ? gfxFont->getName()->getCString()
+	                       : "(unnamed)");
+      goto err2;
+    }
+
+    // embedded font
+    if (fontLoc->locType == gfxFontLocEmbedded) {
+      // if there is an embedded font, read it to memory
       tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
       if (! tmpBuf)
 	goto err2;
-    // if there is an external font file, use it
-    } else if (!(fileName = gfxFont->getExtFontFile())) {
 
-      // look for a display font mapping or a substitute font
-      dfp = NULL;
-      if (gfxFont->getName()) {
-        dfp = globalParams->getDisplayFont(gfxFont);
-      }
-      if (!dfp) {
-	error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
-	      gfxFont->getName() ? gfxFont->getName()->getCString()
-	                         : "(unnamed)");
-	goto err2;
-      }
-      switch (dfp->kind) {
-      case displayFontT1:
-	fileName = dfp->t1.fileName;
-	fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
-	break;
-      case displayFontTT:
-	fileName = dfp->tt.fileName;
-	fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
-	faceIndex = dfp->tt.faceIndex;
-	break;
-      }
+    // external font
+    } else { // gfxFontLocExternal
+      fileName = fontLoc->path;
+      fontType = fontLoc->fontType;
     }
 
     fontsrc = new SplashFontSrc;
@@ -346,7 +333,7 @@ void ArthurOutputDev::updateFont(GfxState *state)
       fontsrc->setFile(fileName, gFalse);
     else
       fontsrc->setBuf(tmpBuf, tmpBufLen, gTrue);
-
+    
     // load the font file
     switch (fontType) {
     case fontType1:
@@ -497,12 +484,14 @@ void ArthurOutputDev::updateFont(GfxState *state)
   mat[2] = m21;  mat[3] = -m22;
   m_font = m_fontEngine->getFont(fontFile, mat, matrix);
 
+  delete fontLoc;
   if (fontsrc && !fontsrc->isFile)
       fontsrc->unref();
   return;
 
  err2:
   delete id;
+  delete fontLoc;
  err1:
   if (fontsrc && !fontsrc->isFile)
       fontsrc->unref();
diff --git a/poppler/CMap.cc b/poppler/CMap.cc
index e26849b..13f293a 100644
--- a/poppler/CMap.cc
+++ b/poppler/CMap.cc
@@ -62,6 +62,75 @@ static int getCharFromStream(void *data) {
 
 //------------------------------------------------------------------------
 
+CMap *CMap::parse(CMapCache *cache, GooString *collectionA, Object *obj) {
+  CMap *cMap;
+  GooString *cMapNameA;
+
+  if (obj->isName()) {
+    cMapNameA = new GooString(obj->getName());
+    if (!(cMap = globalParams->getCMap(collectionA, cMapNameA))) {
+      error(errSyntaxError, -1,
+	    "Unknown CMap '{0:t}' for character collection '{1:t}'",
+	    cMapNameA, collectionA);
+    }
+    delete cMapNameA;
+  } else if (obj->isStream()) {
+    if (!(cMap = CMap::parse(NULL, collectionA, obj->getStream()))) {
+      error(errSyntaxError, -1, "Invalid CMap in Type 0 font");
+    }
+  } else {
+    error(errSyntaxError, -1, "Invalid Encoding in Type 0 font");
+    return NULL;
+  }
+  return cMap;
+}
+
+CMap *CMap::parse(CMapCache *cache, GooString *collectionA,
+		  GooString *cMapNameA) {
+  FILE *f;
+  CMap *cMap;
+
+  if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
+
+    // Check for an identity CMap.
+    if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
+      return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
+    }
+    if (!cMapNameA->cmp("Identity-V")) {
+      return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
+    }
+
+    error(errSyntaxError, -1,
+	  "Couldn't find '{0:t}' CMap file for '{1:t}' collection",
+	  cMapNameA, collectionA);
+    return NULL;
+  }
+
+  cMap = new CMap(collectionA->copy(), cMapNameA->copy());
+  cMap->parse2(cache, &getCharFromFile, f);
+
+  fclose(f);
+
+  return cMap;
+}
+
+CMap *CMap::parse(CMapCache *cache, GooString *collectionA, Stream *str) {
+  Object obj1;
+  CMap *cMap;
+
+  cMap = new CMap(collectionA->copy(), NULL);
+
+  if (!str->getDict()->lookup("UseCMap", &obj1)->isNull()) {
+    cMap->useCMap(cache, &obj1);
+  }
+  obj1.free();
+
+  str->reset();
+  cMap->parse2(cache, &getCharFromStream, str);
+  str->close();
+  return cMap;
+}
+
 CMap *CMap::parse(CMapCache *cache, GooString *collectionA,
 		  GooString *cMapNameA, Stream *stream) {
   FILE *f = NULL;
@@ -163,6 +232,76 @@ CMap *CMap::parse(CMapCache *cache, GooString *collectionA,
   return cmap;
 }
 
+void CMap::parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data) {
+  PSTokenizer *pst;
+  char tok1[256], tok2[256], tok3[256];
+  int n1, n2, n3;
+  Guint start, end, code;
+
+  pst = new PSTokenizer(getCharFunc, data);
+  pst->getToken(tok1, sizeof(tok1), &n1);
+  while (pst->getToken(tok2, sizeof(tok2), &n2)) {
+    if (!strcmp(tok2, "usecmap")) {
+      if (tok1[0] == '/') {
+	useCMap(cache, tok1 + 1);
+      }
+      pst->getToken(tok1, sizeof(tok1), &n1);
+    } else if (!strcmp(tok1, "/WMode")) {
+      wMode = atoi(tok2);
+      pst->getToken(tok1, sizeof(tok1), &n1);
+    } else if (!strcmp(tok2, "begincidchar")) {
+      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+	if (!strcmp(tok1, "endcidchar")) {
+	  break;
+	}
+	if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+	    !strcmp(tok2, "endcidchar")) {
+	  error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
+	  break;
+	}
+	if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+	      n1 >= 4 && (n1 & 1) == 0)) {
+	  error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
+	  continue;
+	}
+	tok1[n1 - 1] = '\0';
+	if (sscanf(tok1 + 1, "%x", &code) != 1) {
+	  error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
+	  continue;
+	}
+	n1 = (n1 - 2) / 2;
+	addCIDs(code, code, n1, (CID)atoi(tok2));
+      }
+      pst->getToken(tok1, sizeof(tok1), &n1);
+    } else if (!strcmp(tok2, "begincidrange")) {
+      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+	if (!strcmp(tok1, "endcidrange")) {
+	  break;
+	}
+	if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+	    !strcmp(tok2, "endcidrange") ||
+	    !pst->getToken(tok3, sizeof(tok3), &n3) ||
+	    !strcmp(tok3, "endcidrange")) {
+	  error(errSyntaxError, -1, "Illegal entry in cidrange block in CMap");
+	  break;
+	}
+	if (tok1[0] == '<' && tok2[0] == '<' &&
+	    n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
+	  tok1[n1 - 1] = tok2[n1 - 1] = '\0';
+	  sscanf(tok1 + 1, "%x", &start);
+	  sscanf(tok2 + 1, "%x", &end);
+	  n1 = (n1 - 2) / 2;
+	  addCIDs(start, end, n1, (CID)atoi(tok3));
+	}
+      }
+      pst->getToken(tok1, sizeof(tok1), &n1);
+    } else {
+      strcpy(tok1, tok2);
+    }
+  }
+  delete pst;
+}
+
 CMap::CMap(GooString *collectionA, GooString *cMapNameA) {
   int i;
 
@@ -218,6 +357,20 @@ void CMap::useCMap(CMapCache *cache, char *useName) {
   subCMap->decRefCnt();
 }
 
+void CMap::useCMap(CMapCache *cache, Object *obj) {
+  CMap *subCMap;
+
+  subCMap = CMap::parse(cache, collection, obj);
+  if (!subCMap) {
+    return;
+  }
+  isIdent = subCMap->isIdent;
+  if (subCMap->vector) {
+    copyVector(vector, subCMap->vector);
+  }
+  subCMap->decRefCnt();
+}
+
 void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
   int i, j;
 
diff --git a/poppler/CMap.h b/poppler/CMap.h
index f2e61f1..3f7085d 100644
--- a/poppler/CMap.h
+++ b/poppler/CMap.h
@@ -37,6 +37,7 @@
 #endif
 
 class GooString;
+class Object;
 struct CMapVectorEntry;
 class CMapCache;
 class Stream;
@@ -46,6 +47,19 @@ class Stream;
 class CMap {
 public:
 
+  // Parse a CMap from <obj>, which can be a name or a stream.  Sets
+  // the initial reference count to 1.  Returns NULL on failure.
+  static CMap *parse(CMapCache *cache, GooString *collectionA, Object *obj);
+
+  // Create the CMap specified by <collection> and <cMapName>.  Sets
+  // the initial reference count to 1.  Returns NULL on failure.
+  static CMap *parse(CMapCache *cache, GooString *collectionA,
+		     GooString *cMapNameA);
+
+  // Parse a CMap from <str>.  Sets the initial reference count to 1.
+  // Returns NULL on failure.
+  static CMap *parse(CMapCache *cache, GooString *collectionA, Stream *str);
+
   // Create the CMap specified by <collection> and <cMapName>.  Sets
   // the initial reference count to 1.
   // Stream is a stream containing the CMap, can be NULL and 
@@ -78,9 +92,11 @@ public:
 
 private:
 
+  void parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data);
   CMap(GooString *collectionA, GooString *cMapNameA);
   CMap(GooString *collectionA, GooString *cMapNameA, int wModeA);
   void useCMap(CMapCache *cache, char *useName);
+  void useCMap(CMapCache *cache, Object *obj);
   void copyVector(CMapVectorEntry *dest, CMapVectorEntry *src);
   void addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID);
   void freeCMapVector(CMapVectorEntry *vec);
diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index 889b073..2b02523 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -381,15 +381,14 @@ CairoFreeTypeFont::~CairoFreeTypeFont() { }
 
 CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
 					     FT_Library lib, GBool useCIDs) {
-  Ref embRef;
   Object refObj, strObj;
   GooString *fileName;
   char *fileNameC;
   char *font_data;
   int font_data_len;
-  DisplayFontParam *dfp;
   int i, n;
   GfxFontType fontType;
+  GfxFontLoc *fontLoc;
   char **enc;
   char *name;
   FoFiTrueType *ff;
@@ -401,7 +400,6 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
   int *codeToGID;
   Guint codeToGIDLen;
   
-  dfp = NULL;
   codeToGID = NULL;
   codeToGIDLen = 0;
   font_data = NULL;
@@ -414,32 +412,23 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
   ref = *gfxFont->getID();
   fontType = gfxFont->getType();
 
-  if (gfxFont->getEmbeddedFontID(&embRef)) {
+  if (!(fontLoc = gfxFont->locateFont(xref, gFalse))) {
+    error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
+    	gfxFont->getName() ? gfxFont->getName()->getCString()
+	                       : "(unnamed)");
+    goto err2;
+  }
+
+  // embedded font
+  if (fontLoc->locType == gfxFontLocEmbedded) {
     font_data = gfxFont->readEmbFontFile(xref, &font_data_len);
     if (NULL == font_data)
       goto err2;
-  } else if (!(fileName = gfxFont->getExtFontFile())) {
-    // look for a display font mapping or a substitute font
-    dfp = NULL;
-    if (gfxFont->getName()) {
-      dfp = globalParams->getDisplayFont(gfxFont);
-    }
-    if (!dfp) {
-      error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
-	    gfxFont->getName() ? gfxFont->getName()->getCString()
-	    : "(unnamed)");
-      goto err2;
-    }
-    switch (dfp->kind) {
-    case displayFontT1:
-      fileName = dfp->t1.fileName;
-      fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
-      break;
-    case displayFontTT:
-      fileName = dfp->tt.fileName;
-      fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
-      break;
-    }
+
+  // external font
+  } else { // gfxFontLocExternal
+    fileName = fontLoc->path;
+    fontType = fontLoc->fontType;
     substitute = gTrue;
   }
 
@@ -546,6 +535,7 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
     break;
   }
 
+  delete fontLoc;
   return new CairoFreeTypeFont(ref,
 		       font_face,
 		       codeToGID, codeToGIDLen,
@@ -553,6 +543,7 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
 
  err2:
   /* hmm? */
+  delete fontLoc;
   fprintf (stderr, "some font thing failed\n");
   return NULL;
 }
diff --git a/poppler/CharCodeToUnicode.h b/poppler/CharCodeToUnicode.h
index edc53f2..66417a1 100644
--- a/poppler/CharCodeToUnicode.h
+++ b/poppler/CharCodeToUnicode.h
@@ -89,6 +89,7 @@ public:
   // Map a CharCode to Unicode.
   int mapToUnicode(CharCode c, Unicode **u);
 
+  // Map a Unicode to CharCode.
   int mapToCharCode(Unicode* u, CharCode *c, int usize);
 
   // Return the mapping's length, i.e., one more than the max char
diff --git a/poppler/FontInfo.cc b/poppler/FontInfo.cc
index 9c6a97e..4847937 100644
--- a/poppler/FontInfo.cc
+++ b/poppler/FontInfo.cc
@@ -191,12 +191,8 @@ FontInfo::FontInfo(GfxFont *font, PDFDoc *doc) {
 
   if (!emb)
   {
-    DisplayFontParam *dfp = globalParams->getDisplayFont(font);
-    if (dfp)
-    {
-      if (dfp->kind == displayFontT1) file = dfp->t1.fileName->copy();
-      else file = dfp->tt.fileName->copy();
-    }
+    GooString *fontFile = globalParams->findFontFile(font->getName());
+    if (fontFile != NULL) file = fontFile->copy();
     else file = NULL;
   }
   else file = NULL;
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index fc49da7..4fa9431 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -689,7 +689,8 @@ void Gfx::go(GBool topLevel) {
 
   // scan a sequence of objects
   pushStateGuard();
-  updateLevel = lastAbortCheck = 0;
+  updateLevel = 1; // make sure even empty pages trigger a call to dump()
+  lastAbortCheck = 0;
   numArgs = 0;
   parser->getObj(&obj);
   while (!obj.isEOF()) {
@@ -858,6 +859,7 @@ Operator *Gfx::findOp(char *name) {
 
   a = -1;
   b = numOps;
+  cmp = 0; // make gcc happy
   // invariant: opTab[a] < name < opTab[b]
   while (b - a > 1) {
     m = (a + b) / 2;
@@ -964,6 +966,7 @@ void Gfx::opSetLineWidth(Object args[], int numArgs) {
 
 void Gfx::opSetExtGState(Object args[], int numArgs) {
   Object obj1, obj2, obj3, obj4, obj5;
+  Object args2[2];
   GfxBlendMode mode;
   GBool haveFillOP;
   Function *funcs[4];
@@ -971,6 +974,7 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
   GBool haveBackdropColor;
   GfxColorSpace *blendingColorSpace;
   GBool alpha, isolated, knockout;
+  double opac;
   int i;
 
   if (!res->lookupGState(args[0].getName(), &obj1)) {
@@ -987,6 +991,53 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
     printf("\n");
   }
 
+  // parameters that are also set by individual PDF operators
+  if (obj1.dictLookup("LW", &obj2)->isNum()) {
+    opSetLineWidth(&obj2, 1);
+  }
+  obj2.free();
+  if (obj1.dictLookup("LC", &obj2)->isInt()) {
+    opSetLineCap(&obj2, 1);
+  }
+  obj2.free();
+  if (obj1.dictLookup("LJ", &obj2)->isInt()) {
+    opSetLineJoin(&obj2, 1);
+  }
+  obj2.free();
+  if (obj1.dictLookup("ML", &obj2)->isNum()) {
+    opSetMiterLimit(&obj2, 1);
+  }
+  obj2.free();
+  if (obj1.dictLookup("D", &obj2)->isArray() &&
+      obj2.arrayGetLength() == 2) {
+    obj2.arrayGet(0, &args2[0]);
+    obj2.arrayGet(1, &args2[1]);
+    if (args2[0].isArray() && args2[1].isNum()) {
+      opSetDash(args2, 2);
+    }
+    args2[0].free();
+    args2[1].free();
+  }
+  obj2.free();
+#if 0 //~ need to add a new version of GfxResources::lookupFont() that
+      //~ takes an indirect ref instead of a name
+  if (obj1.dictLookup("Font", &obj2)->isArray() &&
+      obj2.arrayGetLength() == 2) {
+    obj2.arrayGet(0, &args2[0]);
+    obj2.arrayGet(1, &args2[1]);
+    if (args2[0].isDict() && args2[1].isNum()) {
+      opSetFont(args2, 2);
+    }
+    args2[0].free();
+    args2[1].free();
+  }
+  obj2.free();
+#endif
+  if (obj1.dictLookup("FL", &obj2)->isNum()) {
+    opSetFlat(&obj2, 1);
+  }
+  obj2.free();
+
   // transparency support: blend mode, fill/stroke opacity
   if (!obj1.dictLookup("BM", &obj2)->isNull()) {
     if (state->parseBlendMode(&obj2, &mode)) {
@@ -998,17 +1049,19 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
   }
   obj2.free();
   if (obj1.dictLookup("ca", &obj2)->isNum()) {
-    state->setFillOpacity(obj2.getNum());
+    opac = obj2.getNum();
+    state->setFillOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
     out->updateFillOpacity(state);
   }
   obj2.free();
   if (obj1.dictLookup("CA", &obj2)->isNum()) {
-    state->setStrokeOpacity(obj2.getNum());
+    opac = obj2.getNum();
+    state->setStrokeOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
     out->updateStrokeOpacity(state);
   }
   obj2.free();
 
-  // fill/stroke overprint
+  // fill/stroke overprint, overprint mode
   if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) {
     state->setFillOverprint(obj2.getBool());
     out->updateFillOverprint(state);
@@ -1097,13 +1150,18 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
       obj3.free();
       funcs[0] = NULL;
       if (!obj2.dictLookup("TR", &obj3)->isNull()) {
-	funcs[0] = Function::parse(&obj3);
-	if (funcs[0]->getInputSize() != 1 ||
-	    funcs[0]->getOutputSize() != 1) {
-	  error(errSyntaxError, getPos(),
-		"Invalid transfer function in soft mask in ExtGState");
-	  delete funcs[0];
+	if (obj3.isName("Default") ||
+	    obj3.isName("Identity")) {
 	  funcs[0] = NULL;
+	} else {
+	  funcs[0] = Function::parse(&obj3);
+	  if (funcs[0]->getInputSize() != 1 ||
+	      funcs[0]->getOutputSize() != 1) {
+	    error(errSyntaxError, getPos(),
+		  "Invalid transfer function in soft mask in ExtGState");
+	    delete funcs[0];
+	    funcs[0] = NULL;
+	  }
 	}
       }
       obj3.free();
@@ -1723,11 +1781,13 @@ void Gfx::opStroke(Object args[], int numArgs) {
     //error(errSyntaxError, getPos(), "No path in stroke");
     return;
   }
-  if (state->isPath() && !contentIsHidden()) {
-    if (state->getStrokeColorSpace()->getMode() == csPattern) {
-      doPatternStroke();
-    } else {
-      out->stroke(state);
+  if (state->isPath()) {
+    if (ocState) {
+      if (state->getStrokeColorSpace()->getMode() == csPattern) {
+	doPatternStroke();
+      } else {
+	out->stroke(state);
+      }
     }
   }
   doEndPath();
@@ -1738,12 +1798,14 @@ void Gfx::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) {
     //error(errSyntaxError, getPos(), "No path in closepath/stroke");
     return;
   }
-  state->closePath();
-  if (state->isPath() && !contentIsHidden()) {
-    if (state->getStrokeColorSpace()->getMode() == csPattern) {
-      doPatternStroke();
-    } else {
-      out->stroke(state);
+  if (state->isPath()) {
+    state->closePath();
+    if (ocState) {
+      if (state->getStrokeColorSpace()->getMode() == csPattern) {
+	doPatternStroke();
+      } else {
+	out->stroke(state);
+      }
     }
   }
   doEndPath();
@@ -1754,11 +1816,13 @@ void Gfx::opFill(Object args[], int numArgs) {
     //error(errSyntaxError, getPos(), "No path in fill");
     return;
   }
-  if (state->isPath() && !contentIsHidden()) {
-    if (state->getFillColorSpace()->getMode() == csPattern) {
-      doPatternFill(gFalse);
-    } else {
-      out->fill(state);
+  if (state->isPath()) {
+    if (ocState) {
+      if (state->getFillColorSpace()->getMode() == csPattern) {
+	doPatternFill(gFalse);
+      } else {
+	out->fill(state);
+      }
     }
   }
   doEndPath();
@@ -1769,11 +1833,13 @@ void Gfx::opEOFill(Object args[], int numArgs) {
     //error(errSyntaxError, getPos(), "No path in eofill");
     return;
   }
-  if (state->isPath() && !contentIsHidden()) {
-    if (state->getFillColorSpace()->getMode() == csPattern) {
-      doPatternFill(gTrue);
-    } else {
-      out->eoFill(state);
+  if (state->isPath()) {
+    if (ocState) {
+      if (state->getFillColorSpace()->getMode() == csPattern) {
+	doPatternFill(gTrue);
+      } else {
+	out->eoFill(state);
+      }
     }
   }
   doEndPath();
@@ -1784,16 +1850,18 @@ void Gfx::opFillStroke(Object args[], int numArgs) {
     //error(errSyntaxError, getPos(), "No path in fill/stroke");
     return;
   }
-  if (state->isPath() && !contentIsHidden()) {
-    if (state->getFillColorSpace()->getMode() == csPattern) {
-      doPatternFill(gFalse);
-    } else {
-      out->fill(state);
-    }
-    if (state->getStrokeColorSpace()->getMode() == csPattern) {
-      doPatternStroke();
-    } else {
-      out->stroke(state);
+  if (state->isPath()) {
+    if (ocState) {
+      if (state->getFillColorSpace()->getMode() == csPattern) {
+	doPatternFill(gFalse);
+      } else {
+	out->fill(state);
+      }
+      if (state->getStrokeColorSpace()->getMode() == csPattern) {
+	doPatternStroke();
+      } else {
+	out->stroke(state);
+      }
     }
   }
   doEndPath();
@@ -1804,17 +1872,19 @@ void Gfx::opCloseFillStroke(Object args[], int numArgs) {
     //error(errSyntaxError, getPos(), "No path in closepath/fill/stroke");
     return;
   }
-  if (state->isPath() && !contentIsHidden()) {
+  if (state->isPath()) {
     state->closePath();
-    if (state->getFillColorSpace()->getMode() == csPattern) {
-      doPatternFill(gFalse);
-    } else {
-      out->fill(state);
-    }
-    if (state->getStrokeColorSpace()->getMode() == csPattern) {
-      doPatternStroke();
-    } else {
-      out->stroke(state);
+    if (ocState) {
+      if (state->getFillColorSpace()->getMode() == csPattern) {
+	doPatternFill(gFalse);
+      } else {
+	out->fill(state);
+      }
+      if (state->getStrokeColorSpace()->getMode() == csPattern) {
+	doPatternStroke();
+      } else {
+	out->stroke(state);
+      }
     }
   }
   doEndPath();
@@ -1825,16 +1895,18 @@ void Gfx::opEOFillStroke(Object args[], int numArgs) {
     //error(errSyntaxError, getPos(), "No path in eofill/stroke");
     return;
   }
-  if (state->isPath() && !contentIsHidden()) {
-    if (state->getFillColorSpace()->getMode() == csPattern) {
-      doPatternFill(gTrue);
-    } else {
-      out->eoFill(state);
-    }
-    if (state->getStrokeColorSpace()->getMode() == csPattern) {
-      doPatternStroke();
-    } else {
-      out->stroke(state);
+  if (state->isPath()) {
+    if (ocState) {
+      if (state->getFillColorSpace()->getMode() == csPattern) {
+	doPatternFill(gTrue);
+      } else {
+	out->eoFill(state);
+      }
+      if (state->getStrokeColorSpace()->getMode() == csPattern) {
+	doPatternStroke();
+      } else {
+	out->stroke(state);
+      }
     }
   }
   doEndPath();
@@ -1845,17 +1917,19 @@ void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
     //error(errSyntaxError, getPos(), "No path in closepath/eofill/stroke");
     return;
   }
-  if (state->isPath() && !contentIsHidden()) {
+  if (state->isPath()) {
     state->closePath();
-    if (state->getFillColorSpace()->getMode() == csPattern) {
-      doPatternFill(gTrue);
-    } else {
-      out->eoFill(state);
-    }
-    if (state->getStrokeColorSpace()->getMode() == csPattern) {
-      doPatternStroke();
-    } else {
-      out->stroke(state);
+    if (ocState) {
+      if (state->getFillColorSpace()->getMode() == csPattern) {
+	doPatternFill(gTrue);
+      } else {
+	out->eoFill(state);
+      }
+      if (state->getStrokeColorSpace()->getMode() == csPattern) {
+	doPatternStroke();
+      } else {
+	out->stroke(state);
+      }
     }
   }
   doEndPath();
@@ -2123,25 +2197,23 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
   for (i = 0; i < 4; ++i) {
     m1[i] = m[i];
   }
-  if (!contentIsHidden()) {
-    m1[4] = m[4];
-    m1[5] = m[5];
-    if (out->useTilingPatternFill() &&
-    	out->tilingPatternFill(state, this, catalog, tPat->getContentStream(),
-			       tPat->getMatrix(), tPat->getPaintType(), tPat->getTilingType(),
-			       tPat->getResDict(), m1, tPat->getBBox(),
-			       xi0, yi0, xi1, yi1, xstep, ystep)) {
-	    goto restore;
-    } else {
-      for (yi = yi0; yi < yi1; ++yi) {
-        for (xi = xi0; xi < xi1; ++xi) {
-	  x = xi * xstep;
-	  y = yi * ystep;
-	  m1[4] = x * m[0] + y * m[2] + m[4];
-	  m1[5] = x * m[1] + y * m[3] + m[5];
-	  drawForm(tPat->getContentStream(), tPat->getResDict(),
-		  m1, tPat->getBBox());
-	}
+  m1[4] = m[4];
+  m1[5] = m[5];
+  if (out->useTilingPatternFill() &&
+	out->tilingPatternFill(state, this, catalog, tPat->getContentStream(),
+		       tPat->getMatrix(), tPat->getPaintType(), tPat->getTilingType(),
+		       tPat->getResDict(), m1, tPat->getBBox(),
+		       xi0, yi0, xi1, yi1, xstep, ystep)) {
+    goto restore;
+  } else {
+    for (yi = yi0; yi < yi1; ++yi) {
+      for (xi = xi0; xi < xi1; ++xi) {
+        x = xi * xstep;
+        y = yi * ystep;
+        m1[4] = x * m[0] + y * m[2] + m[4];
+        m1[5] = x * m[1] + y * m[3] + m[5];
+        drawForm(tPat->getContentStream(), tPat->getResDict(),
+        	  m1, tPat->getBBox());
       }
     }
   }
@@ -2420,8 +2492,7 @@ void Gfx::doFunctionShFill1(GfxFunctionShading *shading,
     state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4],
 		  x0 * matrix[1] + y1 * matrix[3] + matrix[5]);
     state->closePath();
-    if (!contentIsHidden())
-      out->fill(state);
+    out->fill(state);
     state->clearPath();
 
   // the four corner colors are not close enough -- subdivide the
@@ -2741,8 +2812,7 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
     }
 
     if (!out->useFillColorStop()) {
-      if (!contentIsHidden())
-        out->fill(state);
+      out->fill(state);
       state->clearPath();
     }
 
@@ -2763,8 +2833,7 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
       state->lineTo(xMax, yMin);
       state->closePath();
     }
-    if (!contentIsHidden())
-      out->fill(state);
+    out->fill(state);
     state->clearPath();
   }
 }
@@ -3098,8 +3167,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
 
     if (!out->useFillColorStop()) {
       // fill the path
-      if (!contentIsHidden())
-        out->fill(state);
+      out->fill(state);
       state->clearPath();
     }
 
@@ -3125,8 +3193,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
     state->lineTo(xMax, yMin);
     state->closePath();
 
-    if (!contentIsHidden())
-      out->fill(state);
+    out->fill(state);
     state->clearPath();
   }
 
@@ -3157,8 +3224,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
 	state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
       }
       state->closePath();
-      if (!contentIsHidden())
-        out->fill(state);
+      out->fill(state);
       state->clearPath();
     }
 
@@ -3190,8 +3256,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
 	state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
       }
       state->closePath();
-      if (!contentIsHidden())
-        out->fill(state);
+      out->fill(state);
       state->clearPath();
     }
   }
@@ -3201,7 +3266,7 @@ void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
   double x0, y0, x1, y1, x2, y2;
   int i;
 
-  if (out->useShadedFills( shading->getType()) && !contentIsHidden()) {
+  if (out->useShadedFills( shading->getType())) {
     if (out->gouraudTriangleShadedFill( state, shading))
       return;
   }
@@ -3264,14 +3329,13 @@ void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
     state->setFillColor(color0);
     out->updateFillColor(state);
 
-    path->reset();                         assert(!path->isEnd()); 
-    path->setCoord(x0,y0);  path->next();  assert(!path->isEnd()); 
-    path->setCoord(x1,y1);  path->next();  assert(!path->isEnd()); 
-    path->setCoord(x2,y2);  path->next();  assert(!path->isEnd()); 
-    path->setCoord(x0,y0);  path->next();  assert( path->isEnd()); 
+    path->reset();                         assert(!path->isEnd());
+    path->setCoord(x0,y0);  path->next();  assert(!path->isEnd());
+    path->setCoord(x1,y1);  path->next();  assert(!path->isEnd());
+    path->setCoord(x2,y2);  path->next();  assert(!path->isEnd());
+    path->setCoord(x0,y0);  path->next();  assert( path->isEnd());
+    out->fill(state);
 
-    if (!contentIsHidden())
-      out->fill(state);
   } else {
     x01 = 0.5 * (x0 + x1);
     y01 = 0.5 * (y0 + y1);
@@ -3312,14 +3376,13 @@ void Gfx::gouraudFillTriangle(double x0, double y0, double color0,
     state->setFillColor(&color);
     out->updateFillColor(state);
 
-    path->reset();                         assert(!path->isEnd()); 
-    path->setCoord(x0,y0);  path->next();  assert(!path->isEnd()); 
-    path->setCoord(x1,y1);  path->next();  assert(!path->isEnd()); 
-    path->setCoord(x2,y2);  path->next();  assert(!path->isEnd()); 
-    path->setCoord(x0,y0);  path->next();  assert( path->isEnd()); 
+    path->reset();                         assert(!path->isEnd());
+    path->setCoord(x0,y0);  path->next();  assert(!path->isEnd());
+    path->setCoord(x1,y1);  path->next();  assert(!path->isEnd());
+    path->setCoord(x2,y2);  path->next();  assert(!path->isEnd());
+    path->setCoord(x0,y0);  path->next();  assert( path->isEnd());
+    out->fill(state);
 
-    if (!contentIsHidden())
-      out->fill(state);
   } else {
     const double x01 = 0.5 * (x0 + x1);
     const double y01 = 0.5 * (y0 + y1);
@@ -3353,7 +3416,7 @@ void Gfx::gouraudFillTriangle(double x0, double y0, double color0,
 void Gfx::doPatchMeshShFill(GfxPatchMeshShading *shading) {
   int start, i;
 
-  if (out->useShadedFills( shading->getType()) && !contentIsHidden()) {
+  if (out->useShadedFills( shading->getType())) {
     if (out->patchMeshShadedFill( state, shading))
       return;
   }
@@ -3444,8 +3507,7 @@ void Gfx::fillPatch(GfxPatch *patch, int colorComps, int patchColorComps, double
 		   patch->x[1][0], patch->y[1][0],
 		   patch->x[0][0], patch->y[0][0]);
     state->closePath();
-    if (!contentIsHidden())
-      out->fill(state);
+    out->fill(state);
     state->clearPath();
   } else {
     for (i = 0; i < 4; ++i) {
@@ -3616,7 +3678,6 @@ void Gfx::opSetTextLeading(Object args[], int numArgs) {
 }
 
 void Gfx::opSetTextRender(Object args[], int numArgs) {
-  int rm = state->getRender();
   state->setRender(args[0].getInt());
   out->updateRender(state);
 }
@@ -3953,15 +4014,12 @@ void Gfx::doShowText(GooString *s) {
       originX *= state->getFontSize();
       originY *= state->getFontSize();
       state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
-      if (!contentIsHidden()) {
-        out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
+      out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
 		      tdx, tdy, tOriginX, tOriginY, code, n, u, uLen);
-      }
       state->shift(tdx, tdy);
       p += n;
       len -= n;
     }
-
   } else {
     dx = dy = 0;
     p = s->getCString();
@@ -3993,8 +4051,7 @@ void Gfx::doShowText(GooString *s) {
       dy *= state->getFontSize();
     }
     state->textTransformDelta(dx, dy, &tdx, &tdy);
-    if (!contentIsHidden())
-      out->drawString(state, s);
+    out->drawString(state, s);
     state->shift(tdx, tdy);
   }
 
@@ -4130,7 +4187,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
   GBool maskInterpolate;
   Stream *maskStr;
   Object obj1, obj2;
-  int i;
+  int i, n;
 
   // get info from the stream
   bits = 0;
@@ -4246,8 +4303,17 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
     }
     obj1.free();
 
+    // if drawing is disabled, skip over inline image data
+    if (!ocState) {
+      str->reset();
+      n = height * ((width + 7) / 8);
+      for (i = 0; i < n; ++i) {
+	str->getChar();
+      }
+      str->close();
+
     // draw it
-    if (!contentIsHidden()) {
+    } else {
       if (state->getFillColorSpace()->getMode() == csPattern) {
 	doPatternImageMask(ref, str, width, height, invert, inlineImg);
       } else {
@@ -4492,19 +4558,29 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
       haveExplicitMask = gTrue;
     }
 
+    // if drawing is disabled, skip over inline image data
+    if (!ocState) {
+      str->reset();
+      n = height * ((width * colorMap->getNumPixelComps() *
+		     colorMap->getBits() + 7) / 8);
+      for (i = 0; i < n; ++i) {
+	str->getChar();
+      }
+      str->close();
+
     // draw it
-    if (haveSoftMask) {
-      if (!contentIsHidden()) {
-        out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, interpolate,
+    } else {
+      if (haveSoftMask) {
+	out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, interpolate,
 				 maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate);
+	delete maskColorMap;
+      } else if (haveExplicitMask) {
+	out->drawMaskedImage(state, ref, str, width, height, colorMap, interpolate,
+			     maskStr, maskWidth, maskHeight, maskInvert, maskInterpolate);
+      } else {
+	out->drawImage(state, ref, str, width, height, colorMap, interpolate,
+		       haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
       }
-      delete maskColorMap;
-    } else if (haveExplicitMask && !contentIsHidden ()) {
-      out->drawMaskedImage(state, ref, str, width, height, colorMap, interpolate,
-			   maskStr, maskWidth, maskHeight, maskInvert, maskInterpolate);
-    } else if (!contentIsHidden()) {
-      out->drawImage(state, ref, str, width, height, colorMap, interpolate,
-		     haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
     }
     delete colorMap;
 
@@ -4757,6 +4833,9 @@ void Gfx::opBeginImage(Object args[], int numArgs) {
   Stream *str;
   int c1, c2;
 
+  // NB: this function is run even if ocState is false -- doImage() is
+  // responsible for skipping over the inline image data
+
   // build dict/stream
   str = buildImageStream();
 
@@ -4937,6 +5016,7 @@ void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
     printf("\n");
     fflush(stdout);
   }
+  ocState = !contentIsHidden();
 }
 
 void Gfx::opEndMarkedContent(Object args[], int numArgs) {
@@ -4953,6 +5033,7 @@ void Gfx::opEndMarkedContent(Object args[], int numArgs) {
 
   if (mcKind == gfxMCActualText)
     out->endActualText(state);
+  ocState = !contentIsHidden();
 }
 
 void Gfx::opMarkPoint(Object args[], int numArgs) {
diff --git a/poppler/GfxFont.cc b/poppler/GfxFont.cc
index a5006f0..c839ad4 100644
--- a/poppler/GfxFont.cc
+++ b/poppler/GfxFont.cc
@@ -43,6 +43,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <math.h>
+#include <limits.h>
 #include <algorithm>
 #include "goo/gmem.h"
 #include "Error.h"
@@ -53,6 +55,7 @@
 #include "CharCodeToUnicode.h"
 #include "FontEncodingTables.h"
 #include "BuiltinFontTables.h"
+#include <fofi/FoFiIdentifier.h>
 #include <fofi/FoFiType1.h>
 #include <fofi/FoFiType1C.h>
 #include <fofi/FoFiTrueType.h>
@@ -162,6 +165,12 @@ static int parseCharName(char *charName, Unicode *uBuf, int uLen,
 			 GBool numeric, GBool hex, GBool variants);
 
 //------------------------------------------------------------------------
+
+static int readFromStream(void *data) {
+  return ((Stream *)data)->getChar();
+}
+
+//------------------------------------------------------------------------
 // GfxFontLoc
 //------------------------------------------------------------------------
 
@@ -182,17 +191,13 @@ GfxFontLoc::~GfxFontLoc() {
 }
 
 //------------------------------------------------------------------------
-
-static int readFromStream(void *data) {
-  return ((Stream *)data)->getChar();
-}
-
-//------------------------------------------------------------------------
 // GfxFont
 //------------------------------------------------------------------------
 
 GfxFont *GfxFont::makeFont(XRef *xref, const char *tagA, Ref idA, Dict *fontDict) {
   GooString *nameA;
+  Ref embFontIDA;
+  GfxFontType typeA;
   GfxFont *font;
   Object obj1;
 
@@ -204,41 +209,35 @@ GfxFont *GfxFont::makeFont(XRef *xref, const char *tagA, Ref idA, Dict *fontDict
   }
   obj1.free();
 
-  // get font type
+  // get embedded font ID and font type
+  typeA = getFontType(xref, fontDict, &embFontIDA);
+
+  // create the font object
   font = NULL;
-  fontDict->lookup("Subtype", &obj1);
-  if (obj1.isName("Type1") || obj1.isName("MMType1")) {
-    font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict);
-  } else if (obj1.isName("Type1C")) {
-    font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict);
-  } else if (obj1.isName("Type3")) {
-    font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict);
-  } else if (obj1.isName("TrueType")) {
-    font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict);
-  } else if (obj1.isName("Type0")) {
-    font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict);
+  if (typeA < fontCIDType0) {
+    font = new Gfx8BitFont(xref, tagA, idA, nameA, typeA, embFontIDA,
+			   fontDict);
   } else {
-    error(errSyntaxError, -1, "Unknown font type: '{0:s}'",
-	  obj1.isName() ? obj1.getName() : "???");
-    font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict);
+    font = new GfxCIDFont(xref, tagA, idA, nameA, typeA, embFontIDA,
+			  fontDict);
   }
-  obj1.free();
 
   return font;
 }
 
-GfxFont::GfxFont(const char *tagA, Ref idA, GooString *nameA) {
+GfxFont::GfxFont(const char *tagA, Ref idA, GooString *nameA,
+		 GfxFontType typeA, Ref embFontIDA) {
   ok = gFalse;
   tag = new GooString(tagA);
   id = idA;
   name = nameA;
+  type = typeA;
+  embFontID = embFontIDA;
   embFontName = NULL;
-  extFontFile = NULL;
   family = NULL;
   stretch = StretchNotDefined;
   weight = WeightNotDefined;
   refCnt = 1;
-  dfp = NULL;
   hasToUnicode = gFalse;
 }
 
@@ -251,10 +250,6 @@ GfxFont::~GfxFont() {
   if (embFontName) {
     delete embFontName;
   }
-  if (extFontFile) {
-    delete extFontFile;
-  }
-  delete dfp;
 }
 
 void GfxFont::incRefCnt() {
@@ -266,6 +261,200 @@ void GfxFont::decRefCnt() {
     delete this;
 }
 
+// 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;
+  Object subtype, fontDesc, obj1, obj2, obj3, obj4;
+  GBool isType0, err;
+
+  t = fontUnknownType;
+  embID->num = embID->gen = -1;
+  err = gFalse;
+
+  fontDict->lookup("Subtype", &subtype);
+  expectedType = fontUnknownType;
+  isType0 = gFalse;
+  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")) {
+    isType0 = gTrue;
+  } else {
+    error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'",
+	  subtype.isName() ? subtype.getName() : "???");
+  }
+  subtype.free();
+
+  fontDict2 = fontDict;
+  if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
+    if (obj1.arrayGetLength() == 0) {
+      error(errSyntaxWarning, -1, "Empty DescendantFonts array in font");
+      obj2.initNull();
+    } else if (obj1.arrayGet(0, &obj2)->isDict()) {
+      if (!isType0) {
+	error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
+      }
+      fontDict2 = obj2.getDict();
+      fontDict2->lookup("Subtype", &subtype);
+      if (subtype.isName("CIDFontType0")) {
+	if (isType0) {
+	  expectedType = fontCIDType0;
+	}
+      } else if (subtype.isName("CIDFontType2")) {
+	if (isType0) {
+	  expectedType = fontCIDType2;
+	}
+      }
+      subtype.free();
+    }
+  } else {
+    obj2.initNull();
+  }
+
+  if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) {
+    if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) {
+      *embID = obj3.getRef();
+      if (expectedType != fontType1) {
+	err = gTrue;
+      }
+    }
+    obj3.free();
+    if (embID->num == -1 &&
+	fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) {
+      *embID = obj3.getRef();
+      if (isType0) {
+	expectedType = fontCIDType2;
+      } else if (expectedType != fontTrueType) {
+	err = gTrue;
+      }
+    }
+    obj3.free();
+    if (embID->num == -1 &&
+	fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) {
+      *embID = obj3.getRef();
+      if (obj3.fetch(xref, &obj4)->isStream()) {
+	obj4.streamGetDict()->lookup("Subtype", &subtype);
+	if (subtype.isName("Type1")) {
+	  if (expectedType != fontType1) {
+	    err = gTrue;
+	    expectedType = isType0 ? fontCIDType0 : fontType1;
+	  }
+	} else if (subtype.isName("Type1C")) {
+	  if (expectedType == fontType1) {
+	    expectedType = fontType1C;
+	  } else if (expectedType != fontType1C) {
+	    err = gTrue;
+	    expectedType = isType0 ? fontCIDType0C : fontType1C;
+	  }
+	} else if (subtype.isName("TrueType")) {
+	  if (expectedType != fontTrueType) {
+	    err = gTrue;
+	    expectedType = isType0 ? fontCIDType2 : fontTrueType;
+	  }
+	} else if (subtype.isName("CIDFontType0C")) {
+	  if (expectedType == fontCIDType0) {
+	    expectedType = fontCIDType0C;
+	  } else {
+	    err = gTrue;
+	    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 {
+	    err = gTrue;
+	  }
+	} else {
+	  error(errSyntaxError, -1, "Unknown font type '{0:s}'",
+		subtype.isName() ? subtype.getName() : "???");
+	}
+	subtype.free();
+      }
+      obj4.free();
+    }
+    obj3.free();
+  }
+  fontDesc.free();
+
+  t = fontUnknownType;
+  if (embID->num >= 0) {
+    obj3.initRef(embID->num, embID->gen);
+    obj3.fetch(xref, &obj4);
+    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;
+      }
+    }
+    obj4.free();
+    obj3.free();
+  }
+
+  if (t == fontUnknownType) {
+    t = expectedType;
+  }
+
+  if (t != expectedType) {
+    err = gTrue;
+  }
+
+  if (err) {
+    error(errSyntaxWarning, -1,
+	  "Mismatch between font type and embedded font file");
+  }
+
+  obj2.free();
+  obj1.free();
+
+  return t;
+}
+
 void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
   Object obj1, obj2, obj3, obj4;
   double t;
@@ -274,8 +463,6 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
   // assume Times-Roman by default (for substitution purposes)
   flags = fontSerif;
 
-  embFontID.num = -1;
-  embFontID.gen = -1;
   missingWidth = 0;
 
   if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
@@ -339,100 +526,6 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
     }
     obj2.free();
 
-    // look for embedded font file
-    if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) {
-      embFontID = obj2.getRef();
-      if (type != fontType1) {
-	error(errSyntaxError, -1, "Mismatch between font type and embedded font file");
-	if (isCIDFont()) {
-	  error(errSyntaxError, -1, "CID font has FontFile attribute; assuming CIDType0");
-	  type = fontCIDType0;
-	} else {
-	  type = fontType1;
-	}
-      }
-    }
-    obj2.free();
-    if (embFontID.num == -1 &&
-	obj1.dictLookupNF("FontFile2", &obj2)->isRef()) {
-      embFontID = obj2.getRef();
-      if (type != fontTrueType && type != fontCIDType2) {
-	error(errSyntaxError, -1, "Mismatch between font type and embedded font file");
-	type = isCIDFont() ? fontCIDType2 : fontTrueType;
-      }
-    }
-    obj2.free();
-    if (embFontID.num == -1 &&
-	obj1.dictLookupNF("FontFile3", &obj2)->isRef()) {
-      if (obj2.fetch(xref, &obj3)->isStream()) {
-	obj3.streamGetDict()->lookup("Subtype", &obj4);
-	if (obj4.isName("Type1")) {
-	  embFontID = obj2.getRef();
-	  if (type != fontType1) {
-	    error(errSyntaxError, -1, "Mismatch between font type and embedded font file");
-	    if (isCIDFont()) {
-	      error(errSyntaxError, -1, "Embedded CID font has type Type1; assuming CIDType0");
-	      type = fontCIDType0;
-	    } else {
-	      type = fontType1;
-	    }
-	  }
-	} else if (obj4.isName("Type1C")) {
-	  embFontID = obj2.getRef();
-	  if (type != fontType1 && type != fontType1C) {
-	    error(errSyntaxError, -1, "Mismatch between font type and embedded font file");
-	  }
-	  if (isCIDFont()) {
-	    error(errSyntaxError, -1, "Embedded CID font has type Type1C; assuming CIDType0C");
-	    type = fontCIDType0C;
-	  } else {
-	    type = fontType1C;
-	  }
-	} else if (obj4.isName("TrueType")) {
-	  embFontID = obj2.getRef();
-	  if (type != fontTrueType) {
-	    error(errSyntaxError, -1, "Mismatch between font type and embedded font file");
-	    if (isCIDFont()) {
-	      error(errSyntaxError, -1, "Embedded CID font has type TrueType; assuming CIDType2");
-	      type = fontCIDType2;
-	    } else {
-	      type = fontTrueType;
-	    }
-	  }
-	} else if (obj4.isName("CIDFontType0C")) {
-	  embFontID = obj2.getRef();
-	  if (type != fontCIDType0) {
-	    error(errSyntaxError, -1, "Mismatch between font type and embedded font file");
-	  }
-	  if (isCIDFont()) {
-	    type = fontCIDType0C;
-	  } else {
-	    error(errSyntaxError, -1, "Embedded non-CID font has type CIDFontType0c; assuming Type1C");
-	    type = fontType1C;
-	  }
-	} else if (obj4.isName("OpenType")) {
-	  embFontID = obj2.getRef();
-	  if (type == fontTrueType) {
-	    type = fontTrueTypeOT;
-	  } else if (type == fontType1) {
-	    type = fontType1COT;
-	  } else if (type == fontCIDType0) {
-	    type = fontCIDType0COT;
-	  } else if (type == fontCIDType2) {
-	    type = fontCIDType2OT;
-	  } else {
-	    error(errSyntaxError, -1, "Mismatch between font type and embedded font file");
-	  }
-	} else {
-	  error(errSyntaxError, -1, "Unknown embedded font type '{0:s}'",
-		obj4.isName() ? obj4.getName() : "???");
-	}
-	obj4.free();
-      }
-      obj3.free();
-    }
-    obj2.free();
-
     // look for MissingWidth
     obj1.dictLookup("MissingWidth", &obj2);
     if (obj2.isNum()) {
@@ -444,8 +537,13 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
     obj1.dictLookup("Ascent", &obj2);
     if (obj2.isNum()) {
       t = 0.001 * obj2.getNum();
-      // some broken font descriptors set ascent and descent to 0
-      if (t != 0) {
+      // 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) {
 	ascent = t;
       }
     }
@@ -453,14 +551,14 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
     obj1.dictLookup("Descent", &obj2);
     if (obj2.isNum()) {
       t = 0.001 * obj2.getNum();
+      // some broken font descriptors specify a positive descent
+      if (t > 0) {
+	t = -t;
+      }
       // some broken font descriptors set ascent and descent to 0
-      if (t != 0) {
+      if (t != 0 && t > -3) {
 	descent = t;
       }
-      // some broken font descriptors specify a positive descent
-      if (descent > 0) {
-	descent = -descent;
-      }
     }
     obj2.free();
 
@@ -502,45 +600,281 @@ CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
   return ctu;
 }
 
-void GfxFont::findExtFontFile() {
-  static const char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL };
-  static const char *ttExts[] = { ".ttf", ".ttc", NULL };
+GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) {
+  GfxFontLoc *fontLoc;
+  SysFontType sysFontType;
+  GooString *path, *base14Name, *substName;
+  PSFontParam16 *psFont16;
+  Object refObj, embFontObj;
+  int substIdx, fontNum;
+  GBool embed;
 
-  if (name) {
-    if (type == fontType1) {
-      extFontFile = globalParams->findFontFile(name, type1Exts);
-    } else if (type == fontTrueType) {
-      extFontFile = globalParams->findFontFile(name, ttExts);
+  if (type == fontType3) {
+    return NULL;
+  }
+
+  //----- embedded font
+  if (embFontID.num >= 0) {
+    embed = gTrue;
+    refObj.initRef(embFontID.num, embFontID.gen);
+    refObj.fetch(xref, &embFontObj);
+    if (!embFontObj.isStream()) {
+      error(errSyntaxError, -1, "Embedded font object is wrong type");
+      embed = gFalse;
+    }
+    embFontObj.free();
+    refObj.free();
+    if (embed) {
+      if (ps) {
+	switch (type) {
+	case fontType1:
+	case fontType1C:
+	case fontType1COT:
+	  embed = globalParams->getPSEmbedType1();
+	  break;
+	case fontTrueType:
+	case fontTrueTypeOT:
+	  embed = globalParams->getPSEmbedTrueType();
+	  break;
+	case fontCIDType0C:
+	case fontCIDType0COT:
+	  embed = globalParams->getPSEmbedCIDPostScript();
+	  break;
+	case fontCIDType2:
+	case fontCIDType2OT:
+	  embed = globalParams->getPSEmbedCIDTrueType();
+	  break;
+	default:
+	  break;
+	}
+      }
+      if (embed) {
+	fontLoc = new GfxFontLoc();
+	fontLoc->locType = gfxFontLocEmbedded;
+	fontLoc->fontType = type;
+	fontLoc->embFontID = embFontID;
+	return fontLoc;
+      }
     }
   }
-}
 
-char *GfxFont::readExtFontFile(int *len) {
-  FILE *f;
-  char *buf;
+  //----- PS passthrough
+  if (ps && !isCIDFont() && globalParams->getPSFontPassthrough()) {
+    fontLoc = new GfxFontLoc();
+    fontLoc->locType = gfxFontLocResident;
+    fontLoc->fontType = fontType1;
+    fontLoc->path = name->copy();
+    return fontLoc;
+  }
 
-  if (!(f = fopen(extFontFile->getCString(), "rb"))) {
-    error(errIO, -1, "External font file '{0:t}' vanished", extFontFile);
-    return NULL;
+  //----- 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);
+    if ((path = globalParams->findFontFile(base14Name))) {
+      if ((fontLoc = getExternalFont(path, gFalse))) {
+	delete base14Name;
+	return fontLoc;
+      }
+    }
+    delete base14Name;
   }
-  if (fseek(f, 0, SEEK_END) != 0) {
-    error(errIO, -1, "Cannot seek to end of '{0:t}'", extFontFile);
-    fclose(f);
+
+  //----- 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;
+  }
+
+  if (!isCIDFont()) {
+
+    //----- 8-bit PS resident font
+    if (ps) {
+      if ((path = globalParams->getPSResidentFont(name))) {
+	fontLoc = new GfxFontLoc();
+	fontLoc->locType = gfxFontLocResident;
+	fontLoc->fontType = fontType1;
+	fontLoc->path = path;
+	return fontLoc;
+      }
+    }
+
+    //----- 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) {
+      error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
+	    base14SubstFonts[substIdx], name);
+      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) {
+	if ((fontLoc = getExternalFont(path, gFalse))) {
+	  error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
+		  base14SubstFonts[substIdx], (name == NULL) ? new GooString("") : name);
+	  name = new GooString(base14SubstFonts[substIdx]);
+	  fontLoc->substIdx = substIdx;
+	  return fontLoc;
+	}
+      }
+    }
+
+    // failed to find a substitute font
     return NULL;
   }
-  *len = (int)ftell(f);
-  if (fseek(f, 0, SEEK_SET) != 0) {
-    error(errIO, -1, "Cannot seek to start of '{0:t}'", extFontFile);
-    fclose(f);
+
+  //----- 16-bit PS resident font
+  if (ps && ((psFont16 = globalParams->getPSResidentFont16(
+					 name,
+					 ((GfxCIDFont *)this)->getWMode())))) {
+    fontLoc = new GfxFontLoc();
+    fontLoc->locType = gfxFontLocResident;
+    fontLoc->fontType = fontCIDType0; // this is not used
+    fontLoc->path = psFont16->psFontName->copy();
+    fontLoc->encoding = psFont16->encoding->copy();
+    fontLoc->wMode = psFont16->wMode;
+    return fontLoc;
+  }
+  if (ps && ((psFont16 = globalParams->getPSResidentFontCC(
+				 ((GfxCIDFont *)this)->getCollection(),
+				 ((GfxCIDFont *)this)->getWMode())))) {
+    error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
+	  psFont16->psFontName, name);
+    fontLoc = new GfxFontLoc();
+    fontLoc->locType = gfxFontLocResident;
+    fontLoc->fontType = fontCIDType0; // this is not used
+    fontLoc->path = psFont16->psFontName->copy();
+    fontLoc->encoding = psFont16->encoding->copy();
+    fontLoc->wMode = psFont16->wMode;
+    return fontLoc;
+  }
+
+  //----- CID font substitution
+  if ((path = globalParams->findCCFontFile(
+				((GfxCIDFont *)this)->getCollection()))) {
+    if ((fontLoc = getExternalFont(path, gTrue))) {
+      error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
+	    fontLoc->path, name);
+      return fontLoc;
+    }
+  }
+
+  // failed to find a substitute font
+  return NULL;
+}
+
+GfxFontLoc *GfxFont::locateBase14Font(GooString *base14Name) {
+  GooString *path;
+
+  path = globalParams->findFontFile(base14Name);
+  if (!path) {
     return NULL;
   }
-  buf = (char *)gmalloc(*len);
-  if ((int)fread(buf, 1, *len, f) != *len) {
-    error(errIO, -1, "Error reading external font file '{0:t}'",
-	  extFontFile);
+  return getExternalFont(path, gFalse);
+}
+
+GfxFontLoc *GfxFont::getExternalFont(GooString *path, GBool cid) {
+  FoFiIdentifierType fft;
+  GfxFontType fontType;
+  GfxFontLoc *fontLoc;
+
+  fft = FoFiIdentifier::identifyFile(path->getCString());
+  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;
+    return NULL;
   }
-  fclose(f);
-  return buf;
+  fontLoc = new GfxFontLoc();
+  fontLoc->locType = gfxFontLocExternal;
+  fontLoc->fontType = fontType;
+  fontLoc->path = path;
+  return fontLoc;
 }
 
 char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
@@ -574,9 +908,8 @@ char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
 //------------------------------------------------------------------------
 
 Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
-			 GfxFontType typeA, Dict *fontDict):
-  GfxFont(tagA, idA, nameA)
-{
+			 GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
+  GfxFont(tagA, idA, nameA, typeA, embFontIDA) {
   GooString *name2;
   BuiltinFont *builtinFont;
   const char **baseEnc;
@@ -598,7 +931,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
   int n, i, a, b, m;
 
   refCnt = 1;
-  type = typeA;
   ctu = NULL;
 
   // do font name substitution for various aliases of the Base 14 font
@@ -670,9 +1002,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
     fontBBox[3] = 0.001 * builtinFont->bbox[3];
   }
 
-  // look for an external font file
-  findExtFontFile();
-
   // get font matrix
   fontMat[0] = fontMat[3] = 1;
   fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
@@ -753,54 +1082,45 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
     baseEnc = winAnsiEncoding;
   }
 
-  // check embedded or external font file for base encoding
+  // check embedded font file for base encoding
   // (only for Type 1 fonts - trying to get an encoding out of a
   // TrueType font is a losing proposition)
   ffT1 = NULL;
   ffT1C = NULL;
   buf = NULL;
-  if (type == fontType1 && (extFontFile || embFontID.num >= 0)) {
-    if (extFontFile) {
-      ffT1 = FoFiType1::load(extFontFile->getCString());
-    } else {
-      buf = readEmbFontFile(xref, &len);
-      ffT1 = FoFiType1::make(buf, len);
-    }
-    if (ffT1) {
-      if (ffT1->getName()) {
-	if (embFontName) {
-	  delete embFontName;
+  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());
 	}
-	embFontName = new GooString(ffT1->getName());
-      }
-      if (!baseEnc) {
-	baseEnc = (const char **)ffT1->getEncoding();
-	baseEncFromFontFile = gTrue;
-      }
-    }
-  } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) {
-    if (extFontFile) {
-      ffT1C = FoFiType1C::load(extFontFile->getCString());
-    } else {
-      buf = readEmbFontFile(xref, &len);
-      ffT1C = FoFiType1C::make(buf, len);
-    }
-    if (ffT1C) {
-      if (ffT1C->getName()) {
-	if (embFontName) {
-	  delete embFontName;
+	if (!baseEnc) {
+	  baseEnc = (const char **)ffT1->getEncoding();
+	  baseEncFromFontFile = gTrue;
 	}
-	embFontName = new GooString(ffT1C->getName());
       }
-      if (!baseEnc) {
-	baseEnc = (const char **)ffT1C->getEncoding();
-	baseEncFromFontFile = gTrue;
+      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();
+	  baseEncFromFontFile = gTrue;
+	}
       }
+      gfree(buf);
     }
   }
-  if (buf) {
-    gfree(buf);
-  }
 
   // get default base encoding
   if (!baseEnc) {
@@ -826,8 +1146,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
   // T1C->T1 conversion (since the 'seac' operator depends on having
   // the accents in the encoding), so we fill in any gaps from
   // StandardEncoding
-  if (type == fontType1C && (extFontFile || embFontID.num >= 0) &&
-      baseEncFromFontFile) {
+  if (type == fontType1C && embFontID.num >= 0 && baseEncFromFontFile) {
     for (i = 0; i < 256; ++i) {
       if (!enc[i] && standardEncoding[i]) {
 	enc[i] = (char *)standardEncoding[i];
@@ -997,7 +1316,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
       obj1.arrayGet(code - firstChar, &obj2);
       if (obj2.isNum()) {
 	widths[code] = obj2.getNum() * mul;
-	if (widths[code] != widths[firstChar]) {
+	if (fabs(widths[code] - widths[firstChar]) > 0.00001) {
 	  flags &= ~fontFixedWidth;
 	}
       }
@@ -1243,9 +1562,10 @@ int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
   //        TrueType font has a Macintosh Roman cmap, use it, and
   //        reverse map the char names through MacRomanEncoding to
   //        get char codes.
-  //    1b. If the TrueType font has a Microsoft Unicode cmap or a
-  //        non-Microsoft Unicode cmap, use it, and use the Unicode
-  //        indexes, not the char codes.
+  //    1b. If the PDF font is not symbolic or the PDF font is not
+  //        embedded, and the TrueType font has a Microsoft Unicode
+  //        cmap or a non-Microsoft Unicode cmap, use it, and use the
+  //        Unicode indexes, not the char codes.
   //    1c. If the PDF font is symbolic and the TrueType font has a
   //        Microsoft Symbol cmap, use it, and use char codes
   //        directly (possibly with an offset of 0xf000).
@@ -1281,7 +1601,8 @@ int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
     if (usesMacRomanEnc && macRomanCmap >= 0) {
       cmap = macRomanCmap;
       useMacRoman = gTrue;
-    } else if (unicodeCmap >= 0) {
+    } else if ((!(flags & fontSymbolic) || embFontID.num < 0) &&
+	       unicodeCmap >= 0) {
       cmap = unicodeCmap;
       useUnicode = gTrue;
     } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) {
@@ -1308,6 +1629,8 @@ int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
 	if ((code = globalParams->getMacRomanCharCode(charName))) {
 	  map[i] = ff->mapCodeToGID(cmap, code);
 	}
+      } else {
+	map[i] = -1;
       }
     }
 
@@ -1321,6 +1644,7 @@ int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
       {
 	n = ctu->mapToUnicode((CharCode)i, &uAux);
 	if (n > 0) map[i] = ff->mapCodeToGID(cmap, uAux[0]);
+	else map[i] = -1;
       }
     }
 
@@ -1336,7 +1660,7 @@ int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
 
   // try the TrueType 'post' table to handle any unmapped characters
   for (i = 0; i < 256; ++i) {
-    if (!map[i] && (charName = enc[i])) {
+    if (map[i] <= 0 && (charName = enc[i])) {
       map[i] = ff->mapNameToGID(charName);
     }
   }
@@ -1380,11 +1704,10 @@ struct cmpWidthExcepVFunctor {
 };
 
 GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
-		       Dict *fontDict):
-  GfxFont(tagA, idA, nameA)
+		       GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
+  GfxFont(tagA, idA, nameA, typeA, embFontIDA)
 {
   Dict *desFontDict;
-  GooString *collection, *cMapName;
   Object desFontDictObj;
   Object obj1, obj2, obj3, obj4, obj5, obj6;
   CharCodeToUnicode *utu;
@@ -1397,9 +1720,10 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
   ascent = 0.95;
   descent = -0.35;
   fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
+  collection = NULL;
   cMap = NULL;
-  cMapName = NULL;
   ctu = NULL;
+  ctuUsesCharCode = gTrue;
   widths.defWidth = 1.0;
   widths.defHeight = -1.0;
   widths.defVY = 0.880;
@@ -1411,8 +1735,9 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
   cidToGIDLen = 0;
 
   // get the descendant font
-  if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
-    error(errSyntaxError, -1, "Missing DescendantFonts entry in Type 0 font");
+  if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() ||
+      obj1.arrayGetLength() == 0) {
+    error(errSyntaxError, -1, "Missing or empty DescendantFonts entry in Type 0 font");
     obj1.free();
     goto err1;
   }
@@ -1423,28 +1748,9 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
   obj1.free();
   desFontDict = desFontDictObj.getDict();
 
-  // font type
-  if (!desFontDict->lookup("Subtype", &obj1)) {
-    error(errSyntaxError, -1, "Missing Subtype entry in Type 0 descendant font");
-    goto err3;
-  }
-  if (obj1.isName("CIDFontType0")) {
-    type = fontCIDType0;
-  } else if (obj1.isName("CIDFontType2")) {
-    type = fontCIDType2;
-  } else {
-    error(errSyntaxError, -1, "Unknown Type 0 descendant font type '{0:s}'",
-	  obj1.isName() ? obj1.getName() : "???");
-    goto err3;
-  }
-  obj1.free();
-
   // get info from font descriptor
   readFontDescriptor(xref, desFontDict);
 
-  // look for an external font file
-  findExtFontFile();
-
   //----- encoding info -----
 
   // char collection
@@ -1456,7 +1762,7 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
   obj1.dictLookup("Ordering", &obj3);
   if (!obj2.isString() || !obj3.isString()) {
     error(errSyntaxError, -1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
-    goto err4;
+    goto err3;
   }
   collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
   obj3.free();
@@ -1465,6 +1771,7 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
 
   // look for a ToUnicode CMap
   if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) {
+    ctuUsesCharCode = gFalse;
 
     // the "Adobe-Identity" and "Adobe-UCS" collections don't have
     // cidToUnicode files
@@ -1488,7 +1795,6 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
 	for (size_t i = 0; i < sizeof(knownCollections)/sizeof(knownCollections[0]); i++) {
 	  if (collection->cmp(knownCollections[i]) == 0) {
 	    error(errSyntaxError, -1, "Missing language pack for '{0:t}' mapping", collection);
-	    delete collection;
 	    goto err2;
 	  }
 	}
@@ -1519,40 +1825,13 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
   }
 
   // encoding (i.e., CMap)
-  //~ also need to deal with the UseCMap entry in the stream dict
-  if (!fontDict->lookup("Encoding", &obj1)->isName()) {
-    GBool success = gFalse;
-    if (obj1.isStream()) {
-      Object objName;
-      Stream *s = obj1.getStream();
-      s->getDict()->lookup("CMapName", &objName);
-      if (objName.isName())
-      {
-        cMapName = new GooString(objName.getName());
-        cMap = globalParams->getCMap(collection, cMapName, s);
-        success = gTrue;
-      }
-      objName.free();
-    }
-    
-    if (!success) {
-      error(errSyntaxError, -1, "Missing or invalid Encoding entry in Type 0 font");
-      delete collection;
-      goto err3;
-    }
-  } else {
-    cMapName = new GooString(obj1.getName());
-    cMap = globalParams->getCMap(collection, cMapName);
+  if (fontDict->lookup("Encoding", &obj1)->isNull()) {
+    error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font");
+    goto err2;
+  }
+  if (!(cMap = CMap::parse(NULL, collection, &obj1))) {
+    goto err2;
   }
-  if (!cMap) {
-      error(errSyntaxError, -1, "Unknown CMap '{0:t}' for character collection '{1:t}'",
-	    cMapName, collection);
-      delete collection;
-      delete cMapName;
-      goto err2;
-    }
-  delete collection;
-  delete cMapName;
   obj1.free();
 
   // CIDToGIDMap (for embedded TrueType fonts)
@@ -1730,17 +2009,19 @@ GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
   ok = gTrue;
   return;
 
- err4:
+ err3:
   obj3.free();
   obj2.free();
- err3:
-  obj1.free();
  err2:
+  obj1.free();
   desFontDictObj.free();
  err1:;
 }
 
 GfxCIDFont::~GfxCIDFont() {
+  if (collection) {
+    delete collection;
+  }
   if (cMap) {
     cMap->decRefCnt();
   }
diff --git a/poppler/GfxFont.h b/poppler/GfxFont.h
index 2207b9f..0c32e0f 100644
--- a/poppler/GfxFont.h
+++ b/poppler/GfxFont.h
@@ -43,7 +43,6 @@ class Dict;
 class CMap;
 class CharCodeToUnicode;
 class FoFiTrueType;
-class DisplayFontParam;
 struct GfxFontCIDWidths;
 struct Base14FontMapEntry;
 
@@ -171,7 +170,8 @@ public:
   // Build a GfxFont object.
   static GfxFont *makeFont(XRef *xref, const char *tagA, Ref idA, Dict *fontDict);
 
-  GfxFont(const char *tagA, Ref idA, GooString *nameA);
+  GfxFont(const char *tagA, Ref idA, GooString *nameA,
+	  GfxFontType typeA, Ref embFontIDA);
 
   GBool isOk() { return ok; }
 
@@ -213,10 +213,6 @@ public:
   // NULL if there is no embedded font.
   GooString *getEmbeddedFontName() { return embFontName; }
 
-  // Get the name of the external font file.  Returns NULL if there
-  // is no external font file.
-  GooString *getExtFontFile() { return extFontFile; }
-
   // Get font descriptor flags.
   int getFlags() { return flags; }
   GBool isFixedWidth() { return flags & fontFixedWidth; }
@@ -241,8 +237,14 @@ public:
   // Return the writing mode (0=horizontal, 1=vertical).
   virtual int getWMode() { return 0; }
 
+  // Locate the font file for this font.  If <ps> is true, includes PS
+  // printer-resident fonts.  Returns NULL on failure.
+  GfxFontLoc *locateFont(XRef *xref, GBool ps);
+
+  // Locate a Base-14 font file for a specified font name.
+  static GfxFontLoc *locateBase14Font(GooString *base14Name);
+
   // Read an external or embedded font file into a buffer.
-  char *readExtFontFile(int *len);
   char *readEmbFontFile(XRef *xref, int *len);
 
   // Get the next char from a string <s> of <len> bytes, returning the
@@ -258,19 +260,15 @@ public:
   // Does this font have a toUnicode map?
   GBool hasToUnicodeCMap() { return hasToUnicode; }
 
-  /* XXX: dfp shouldn't be public, however the font finding code is currently in
-   * GlobalParams. Instead it should be inside the GfxFont class. However,
-   * getDisplayFont currently uses FCcfg so moving it is not as simple. */
-  /* XXX: related to this is the fact that all of the extFontFile stuff is dead */
-  DisplayFontParam *dfp;
 protected:
 
   virtual ~GfxFont();
 
+  static GfxFontType getFontType(XRef *xref, Dict *fontDict, Ref *embID);
   void readFontDescriptor(XRef *xref, Dict *fontDict);
   CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits,
 				       CharCodeToUnicode *ctu);
-  void findExtFontFile();
+  static GfxFontLoc *getExternalFont(GooString *path, GBool cid);
 
   GooString *tag;			// PDF font tag
   Ref id;			// reference (used as unique ID)
@@ -282,7 +280,6 @@ protected:
   int flags;			// font descriptor flags
   GooString *embFontName;		// name of embedded font
   Ref embFontID;		// ref to embedded font file stream
-  GooString *extFontFile;		// external font file name
   double fontMat[6];		// font matrix (Type 3 only)
   double fontBBox[4];		// font bounding box (Type 3 only)
   double missingWidth;		// "default" width
@@ -301,7 +298,7 @@ class Gfx8BitFont: public GfxFont {
 public:
 
   Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
-	      GfxFontType typeA, Dict *fontDict);
+	      GfxFontType typeA, Ref embFontIDA, Dict *fontDict);
 
   virtual int getNextChar(char *s, int len, CharCode *code,
 			  Unicode **u, int *uLen,
@@ -351,6 +348,8 @@ private:
   double widths[256];		// character widths
   Object charProcs;		// Type 3 CharProcs dictionary
   Object resources;		// Type 3 Resources dictionary
+
+  friend class GfxFont;
 };
 
 //------------------------------------------------------------------------
@@ -361,7 +360,7 @@ class GfxCIDFont: public GfxFont {
 public:
 
   GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
-	     Dict *fontDict);
+	     GfxFontType typeA, Ref embFontIDA, Dict *fontDict);
 
   virtual GBool isCIDFont() { return gTrue; }
 
@@ -393,8 +392,11 @@ private:
   int mapCodeToGID(FoFiTrueType *ff, int cmapi,
     Unicode unicode, GBool wmode);
 
+  GooString *collection;		// collection name
   CMap *cMap;			// char code --> CID
   CharCodeToUnicode *ctu;	// CID --> Unicode
+  GBool ctuUsesCharCode;	// true: ctu maps char code to Unicode;
+				//   false: ctu maps CID to Unicode
   GfxFontCIDWidths widths;	// character widths
   int *cidToGID;		// CID --> GID mapping (for embedded
 				//   TrueType fonts)
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index de6f17b..4ea9d93 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -1568,10 +1568,11 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, Gfx *gfx, int recursion)
   }
   nCompsA = obj2.getInt();
   obj2.free();
-  if (nCompsA > gfxColorMaxComps) {
-    error(errSyntaxWarning, -1, "ICCBased color space with too many ({0:d} > {1:d}) components",
-	  nCompsA, gfxColorMaxComps);
-    nCompsA = gfxColorMaxComps;
+  if (nCompsA > 4) {
+    error(errSyntaxError, -1,
+	  "ICCBased color space with too many ({0:d} > 4) components",
+	  nCompsA);
+    nCompsA = 4;
   }
   if (dict->lookup("Alternate", &obj2)->isNull() ||
       !(altA = GfxColorSpace::parse(&obj2, gfx, recursion + 1))) {
@@ -2286,13 +2287,6 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, Gfx *gfx, int recursion)
   }
   obj1.free();
   cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA);
-  cs->nonMarking = gTrue;
-  for (i = 0; i < nCompsA; ++i) {
-    cs->names[i] = namesA[i];
-    if (namesA[i]->cmp("None")) {
-      cs->nonMarking = gFalse;
-    }
-  }
   return cs;
 
  err4:
@@ -4767,7 +4761,7 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
   GfxIndexedColorSpace *indexedCS;
   GfxSeparationColorSpace *sepCS;
   int maxPixel, indexHigh;
-  Guchar *lookup2;
+  Guchar *indexedLookup;
   Function *sepFunc;
   Object obj;
   double x[gfxColorMaxComps];
@@ -4791,7 +4785,7 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
 
   // initialize
   for (k = 0; k < gfxColorMaxComps; ++k) {
-    lookup[k] = NULL;
+    lookup2[k] = NULL;
   }
   byte_lookup = NULL;
 
@@ -4829,10 +4823,18 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
   // Construct a lookup table -- this stores pre-computed decoded
   // values for each component, i.e., the result of applying the
   // decode mapping to each possible image pixel component value.
-  //
+  for (k = 0; k < nComps; ++k) {
+    lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+					 sizeof(GfxColorComp));
+    for (i = 0; i <= maxPixel; ++i) {
+      lookup[k][i] = dblToCol(decodeLow[k] +
+			      (i * decodeRange[k]) / maxPixel);
+    }
+  }
+
   // Optimization: for Indexed and Separation color spaces (which have
-  // only one component), we store color values in the lookup table
-  // rather than component values.
+  // only one component), we pre-compute a second lookup table with
+  // color values
   colorSpace2 = NULL;
   nComps2 = 0;
   useByteLookup = gFalse;
@@ -4845,14 +4847,14 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
     colorSpace2 = indexedCS->getBase();
     indexHigh = indexedCS->getIndexHigh();
     nComps2 = colorSpace2->getNComps();
-    lookup2 = indexedCS->getLookup();
+    indexedLookup = indexedCS->getLookup();
     colorSpace2->getDefaultRanges(x, y, indexHigh);
     if (colorSpace2->useGetGrayLine() || colorSpace2->useGetRGBLine()) {
       byte_lookup = (Guchar *)gmallocn ((maxPixel + 1), nComps2);
       useByteLookup = gTrue;
     }
     for (k = 0; k < nComps2; ++k) {
-      lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+      lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
 					   sizeof(GfxColorComp));
       for (i = 0; i <= maxPixel; ++i) {
 	j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
@@ -4862,8 +4864,8 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
 	  j = indexHigh;
 	}
 
-	mapped = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k];
-	lookup[k][i] = dblToCol(mapped);
+	mapped = x[k] + (indexedLookup[j*nComps2 + k] / 255.0) * y[k];
+	lookup2[k][i] = dblToCol(mapped);
 	if (useByteLookup)
 	  byte_lookup[i * nComps2 + k] = (Guchar) (mapped * 255);
       }
@@ -4879,12 +4881,12 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
       useByteLookup = gTrue;
     }
     for (k = 0; k < nComps2; ++k) {
-      lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+      lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
 					   sizeof(GfxColorComp));
       for (i = 0; i <= maxPixel; ++i) {
 	x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
 	sepFunc->transform(x, y);
-	lookup[k][i] = dblToCol(y[k]);
+	lookup2[k][i] = dblToCol(y[k]);
 	if (useByteLookup)
 	  byte_lookup[i*nComps2 + k] = (Guchar) (y[k] * 255);
       }
@@ -4896,11 +4898,11 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
       useByteLookup = gTrue;
     }
     for (k = 0; k < nComps; ++k) {
-      lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+      lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
 					   sizeof(GfxColorComp));
       for (i = 0; i <= maxPixel; ++i) {
 	mapped = decodeLow[k] + (i * decodeRange[k]) / maxPixel;
-	lookup[k][i] = dblToCol(mapped);
+	lookup2[k][i] = dblToCol(mapped);
 	if (useByteLookup) {
 	  int byte;
 
@@ -4971,7 +4973,7 @@ GfxImageColorMap::~GfxImageColorMap() {
 
   delete colorSpace;
   for (i = 0; i < gfxColorMaxComps; ++i) {
-    gfree(lookup[i]);
+    gfree(lookup2[i]);
   }
   gfree(byte_lookup);
 }
@@ -4982,12 +4984,12 @@ void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) {
 
   if (colorSpace2) {
     for (i = 0; i < nComps2; ++i) {
-      color.c[i] = lookup[i][x[0]];
+      color.c[i] = lookup2[i][x[0]];
     }
     colorSpace2->getGray(&color, gray);
   } else {
     for (i = 0; i < nComps; ++i) {
-      color.c[i] = lookup[i][x[i]];
+      color.c[i] = lookup2[i][x[i]];
     }
     colorSpace->getGray(&color, gray);
   }
@@ -4999,12 +5001,12 @@ void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
 
   if (colorSpace2) {
     for (i = 0; i < nComps2; ++i) {
-      color.c[i] = lookup[i][x[0]];
+      color.c[i] = lookup2[i][x[0]];
     }
     colorSpace2->getRGB(&color, rgb);
   } else {
     for (i = 0; i < nComps; ++i) {
-      color.c[i] = lookup[i][x[i]];
+      color.c[i] = lookup2[i][x[i]];
     }
     colorSpace->getRGB(&color, rgb);
   }
@@ -5334,13 +5336,18 @@ void GfxPath::moveTo(double x, double y) {
 }
 
 void GfxPath::lineTo(double x, double y) {
-  if (justMoved) {
+  if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
     if (n >= size) {
       size *= 2;
       subpaths = (GfxSubpath **)
 	           greallocn(subpaths, size, sizeof(GfxSubpath *));
     }
-    subpaths[n] = new GfxSubpath(firstX, firstY);
+    if (justMoved) {
+      subpaths[n] = new GfxSubpath(firstX, firstY);
+    } else {
+      subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
+				   subpaths[n-1]->getLastY());
+    }
     ++n;
     justMoved = gFalse;
   }
@@ -5349,13 +5356,18 @@ void GfxPath::lineTo(double x, double y) {
 
 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
 	     double x3, double y3) {
-  if (justMoved) {
+  if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
     if (n >= size) {
       size *= 2;
       subpaths = (GfxSubpath **) 
  	         greallocn(subpaths, size, sizeof(GfxSubpath *));
     }
-    subpaths[n] = new GfxSubpath(firstX, firstY);
+    if (justMoved) {
+      subpaths[n] = new GfxSubpath(firstX, firstY);
+    } else {
+      subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
+				   subpaths[n-1]->getLastY());
+    }
     ++n;
     justMoved = gFalse;
   }
@@ -5571,9 +5583,6 @@ GfxState::~GfxState() {
     // this gets set to NULL by restore()
     delete path;
   }
-  if (saved) {
-    delete saved;
-  }
   if (font) {
     font->decRefCnt();
   }
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 6edab64..856ec3f 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -1120,6 +1120,8 @@ private:
   int nComps2;			// number of components in colorSpace2
   GfxColorComp *		// lookup table
     lookup[gfxColorMaxComps];
+  GfxColorComp *		// optimized case lookup table
+    lookup2[gfxColorMaxComps];
   Guchar *byte_lookup;
   double			// minimum values for each component
     decodeLow[gfxColorMaxComps];
diff --git a/poppler/GlobalParams.cc b/poppler/GlobalParams.cc
index d2c007f..ab399db 100644
--- a/poppler/GlobalParams.cc
+++ b/poppler/GlobalParams.cc
@@ -122,37 +122,21 @@ extern XpdfPluginVecTable xpdfPluginVecTable;
 GlobalParams *globalParams = NULL;
 
 //------------------------------------------------------------------------
-// DisplayFontParam
+// PSFontParam16
 //------------------------------------------------------------------------
 
-DisplayFontParam::DisplayFontParam(GooString *nameA,
-				   DisplayFontParamKind kindA) {
+PSFontParam16::PSFontParam16(GooString *nameA, int wModeA,
+			     GooString *psFontNameA, GooString *encodingA) {
   name = nameA;
-  kind = kindA;
-  switch (kind) {
-  case displayFontT1:
-    t1.fileName = NULL;
-    break;
-  case displayFontTT:
-    tt.fileName = NULL;
-    break;
-  }
+  wMode = wModeA;
+  psFontName = psFontNameA;
+  encoding = encodingA;
 }
 
-DisplayFontParam::~DisplayFontParam() {
+PSFontParam16::~PSFontParam16() {
   delete name;
-  switch (kind) {
-  case displayFontT1:
-    if (t1.fileName) {
-      delete t1.fileName;
-    }
-    break;
-  case displayFontTT:
-    if (tt.fileName) {
-      delete tt.fileName;
-    }
-    break;
-  }
+  delete psFontName;
+  delete encoding;
 }
 
 #if ENABLE_RELOCATABLE && defined(_WIN32)
@@ -211,182 +195,123 @@ get_poppler_datadir (void)
 
 #endif
 
-#ifdef _WIN32
-
 //------------------------------------------------------------------------
-// WinFontInfo
+// SysFontInfo
 //------------------------------------------------------------------------
 
-class WinFontInfo: public DisplayFontParam {
+class SysFontInfo {
 public:
 
-  GBool bold, italic;
-
-  static WinFontInfo *make(GooString *nameA, GBool boldA, GBool italicA,
-			   HKEY regKey, char *winFontDir);
-  WinFontInfo(GooString *nameA, GBool boldA, GBool italicA,
-	      GooString *fileNameA);
-  virtual ~WinFontInfo();
-  GBool equals(WinFontInfo *fi);
+  GooString *name;
+  GBool bold;
+  GBool italic;
+  GooString *path;
+  SysFontType type;
+  int fontNum;			// for TrueType collections
+
+  SysFontInfo(GooString *nameA, GBool boldA, GBool italicA,
+	      GooString *pathA, SysFontType typeA, int fontNumA);
+  ~SysFontInfo();
+  GBool match(SysFontInfo *fi);
+  GBool match(GooString *nameA, GBool boldA, GBool italicA);
 };
 
-WinFontInfo *WinFontInfo::make(GooString *nameA, GBool boldA, GBool italicA,
-			       HKEY regKey, char *winFontDir) {
-  GooString *regName;
-  GooString *fileNameA;
-  char buf[MAX_PATH];
-  DWORD n;
-  char c;
-  int i;
-
-  //----- find the font file
-  fileNameA = NULL;
-  regName = nameA->copy();
-  if (boldA) {
-    regName->append(" Bold");
-  }
-  if (italicA) {
-    regName->append(" Italic");
-  }
-  regName->append(" (TrueType)");
-  n = sizeof(buf);
-  if (RegQueryValueEx(regKey, regName->getCString(), NULL, NULL,
-		      (LPBYTE)buf, &n) == ERROR_SUCCESS) {
-    fileNameA = new GooString(winFontDir);
-    fileNameA->append('\\')->append(buf);
-  }
-  delete regName;
-  if (!fileNameA) {
-    delete nameA;
-    return NULL;
-  }
-
-  //----- normalize the font name
-  i = 0;
-  while (i < nameA->getLength()) {
-    c = nameA->getChar(i);
-    if (c == ' ' || c == ',' || c == '-') {
-      nameA->del(i);
-    } else {
-      ++i;
-    }
-  }
-
-  return new WinFontInfo(nameA, boldA, italicA, fileNameA);
-}
-
-WinFontInfo::WinFontInfo(GooString *nameA, GBool boldA, GBool italicA,
-			 GooString *fileNameA):
-  DisplayFontParam(nameA, displayFontTT)
-{
+SysFontInfo::SysFontInfo(GooString *nameA, GBool boldA, GBool italicA,
+			 GooString *pathA, SysFontType typeA, int fontNumA) {
+  name = nameA;
   bold = boldA;
   italic = italicA;
-  tt.fileName = fileNameA;
+  path = pathA;
+  type = typeA;
+  fontNum = fontNumA;
 }
 
-WinFontInfo::~WinFontInfo() {
+SysFontInfo::~SysFontInfo() {
+  delete name;
+  delete path;
 }
 
-GBool WinFontInfo::equals(WinFontInfo *fi) {
-  return !name->cmp(fi->name) && bold == fi->bold && italic == fi->italic;
+GBool SysFontInfo::match(SysFontInfo *fi) {
+  return !strcasecmp(name->getCString(), fi->name->getCString()) &&
+         bold == fi->bold && italic == fi->italic;
+}
+
+GBool SysFontInfo::match(GooString *nameA, GBool boldA, GBool italicA) {
+  return !strcasecmp(name->getCString(), nameA->getCString()) &&
+         bold == boldA && italic == italicA;
 }
 
 //------------------------------------------------------------------------
-// WinFontList
+// SysFontList
 //------------------------------------------------------------------------
 
-class WinFontList {
+class SysFontList {
 public:
 
-  WinFontList(char *winFontDirA);
-  ~WinFontList();
-  WinFontInfo *find(GooString *font);
+  SysFontList();
+  ~SysFontList();
+  SysFontInfo *find(GooString *name, GBool exact);
 
+#ifdef WIN32
+  void scanWindowsFonts(GooString *winFontDir);
+#endif
+#ifdef WITH_FONTCONFIGURATION_FONTCONFIG
+  void addFcFont(SysFontInfo *si) {fonts->append(si);}
+#endif
 private:
 
-  void add(WinFontInfo *fi);
-  static int CALLBACK enumFunc1(CONST LOGFONT *font,
-				CONST TEXTMETRIC *metrics,
-				DWORD type, LPARAM data);
-  static int CALLBACK enumFunc2(CONST LOGFONT *font,
-				CONST TEXTMETRIC *metrics,
-				DWORD type, LPARAM data);
-
-  GooList *fonts;			// [WinFontInfo]
-  HDC dc;			// (only used during enumeration)
-  HKEY regKey;			// (only used during enumeration)
-  char *winFontDir;		// (only used during enumeration)
-};
+#ifdef WIN32
+  SysFontInfo *makeWindowsFont(char *name, int fontNum,
+			       char *path);
+#endif
 
-WinFontList::WinFontList(char *winFontDirA) {
-  OSVERSIONINFO version;
-  char *path;
+  GooList *fonts;			// [SysFontInfo]
+};
 
+SysFontList::SysFontList() {
   fonts = new GooList();
-  dc = GetDC(NULL);
-  winFontDir = winFontDirA;
-  version.dwOSVersionInfoSize = sizeof(version);
-  GetVersionEx(&version);
-  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-    path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
-  } else {
-    path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
-  }
-  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0,
-		   KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
-		   &regKey) == ERROR_SUCCESS) {
-    EnumFonts(dc, NULL, &WinFontList::enumFunc1, (LPARAM)this);
-    RegCloseKey(regKey);
-  }
-  ReleaseDC(NULL, dc);
 }
 
-WinFontList::~WinFontList() {
-  deleteGooList(fonts, WinFontInfo);
+SysFontList::~SysFontList() {
+  deleteGooList(fonts, SysFontInfo);
 }
 
-void WinFontList::add(WinFontInfo *fi) {
-  int i;
-
-  for (i = 0; i < fonts->getLength(); ++i) {
-    if (((WinFontInfo *)fonts->get(i))->equals(fi)) {
-      delete fi;
-      return;
-    }
-  }
-  fonts->append(fi);
-}
-
-WinFontInfo *WinFontList::find(GooString *font) {
-  GooString *name;
+SysFontInfo *SysFontList::find(GooString *name, GBool exact) {
+  GooString *name2;
   GBool bold, italic;
-  WinFontInfo *fi;
+  SysFontInfo *fi;
   char c;
   int n, i;
 
-  name = font->copy();
+  name2 = name->copy();
 
   // remove space, comma, dash chars
   i = 0;
-  while (i < name->getLength()) {
-    c = name->getChar(i);
+  while (i < name2->getLength()) {
+    c = name2->getChar(i);
     if (c == ' ' || c == ',' || c == '-') {
-      name->del(i);
+      name2->del(i);
     } else {
       ++i;
     }
   }
-  n = name->getLength();
+  n = name2->getLength();
 
   // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.)
-  if (!strcmp(name->getCString() + n - 2, "MT")) {
-    name->del(n - 2, 2);
+  if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) {
+    name2->del(n - 2, 2);
     n -= 2;
   }
 
+  // look for "Regular"
+  if (n > 7 && !strcmp(name2->getCString() + n - 7, "Regular")) {
+    name2->del(n - 7, 7);
+    n -= 7;
+  }
+
   // look for "Italic"
-  if (!strcmp(name->getCString() + n - 6, "Italic")) {
-    name->del(n - 6, 6);
+  if (n > 6 && !strcmp(name2->getCString() + n - 6, "Italic")) {
+    name2->del(n - 6, 6);
     italic = gTrue;
     n -= 6;
   } else {
@@ -394,8 +319,8 @@ WinFontInfo *WinFontList::find(GooString *font) {
   }
 
   // look for "Bold"
-  if (!strcmp(name->getCString() + n - 4, "Bold")) {
-    name->del(n - 4, 4);
+  if (n > 4 && !strcmp(name2->getCString() + n - 4, "Bold")) {
+    name2->del(n - 4, 4);
     bold = gTrue;
     n -= 4;
   } else {
@@ -403,78 +328,57 @@ WinFontInfo *WinFontList::find(GooString *font) {
   }
 
   // remove trailing "MT" (FooMT-Bold, etc.)
-  if (!strcmp(name->getCString() + n - 2, "MT")) {
-    name->del(n - 2, 2);
+  if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) {
+    name2->del(n - 2, 2);
     n -= 2;
   }
 
   // remove trailing "PS"
-  if (!strcmp(name->getCString() + n - 2, "PS")) {
-    name->del(n - 2, 2);
+  if (n > 2 && !strcmp(name2->getCString() + n - 2, "PS")) {
+    name2->del(n - 2, 2);
     n -= 2;
   }
 
+  // remove trailing "IdentityH"
+  if (n > 9 && !strcmp(name2->getCString() + n - 9, "IdentityH")) {
+    name2->del(n - 9, 9);
+    n -= 9;
+  }
+
   // search for the font
   fi = NULL;
   for (i = 0; i < fonts->getLength(); ++i) {
-    fi = (WinFontInfo *)fonts->get(i);
-    if (!fi->name->cmp(name) && fi->bold == bold && fi->italic == italic) {
+    fi = (SysFontInfo *)fonts->get(i);
+    if (fi->match(name2, bold, italic)) {
       break;
     }
     fi = NULL;
   }
-
-  delete name;
-  return fi;
-}
-
-int CALLBACK WinFontList::enumFunc1(CONST LOGFONT *font,
-				    CONST TEXTMETRIC *metrics,
-				    DWORD type, LPARAM data) {
-  WinFontList *fl = (WinFontList *)data;
-
-  EnumFonts(fl->dc, font->lfFaceName, &WinFontList::enumFunc2, (LPARAM)fl);
-  return 1;
-}
-
-int CALLBACK WinFontList::enumFunc2(CONST LOGFONT *font,
-				    CONST TEXTMETRIC *metrics,
-				    DWORD type, LPARAM data) {
-  WinFontList *fl = (WinFontList *)data;
-  WinFontInfo *fi;
-
-  if (type & TRUETYPE_FONTTYPE) {
-    if ((fi = WinFontInfo::make(new GooString(font->lfFaceName),
-				font->lfWeight >= 600,
-				font->lfItalic ? gTrue : gFalse,
-				fl->regKey, fl->winFontDir))) {
-      fl->add(fi);
+  if (!fi && !exact && bold) {
+    // try ignoring the bold flag
+    for (i = 0; i < fonts->getLength(); ++i) {
+      fi = (SysFontInfo *)fonts->get(i);
+      if (fi->match(name2, gFalse, italic)) {
+	break;
+      }
+      fi = NULL;
+    }
+  }
+  if (!fi && !exact && (bold || italic)) {
+    // try ignoring the bold and italic flags
+    for (i = 0; i < fonts->getLength(); ++i) {
+      fi = (SysFontInfo *)fonts->get(i);
+      if (fi->match(name2, gFalse, gFalse)) {
+	break;
+      }
+      fi = NULL;
     }
   }
-  return 1;
-}
-
-#endif // _WIN32
-
-//------------------------------------------------------------------------
-// PSFontParam
-//------------------------------------------------------------------------
 
-PSFontParam::PSFontParam(GooString *pdfFontNameA, int wModeA,
-			 GooString *psFontNameA, GooString *encodingA) {
-  pdfFontName = pdfFontNameA;
-  wMode = wModeA;
-  psFontName = psFontNameA;
-  encoding = encodingA;
+  delete name2;
+  return fi;
 }
 
-PSFontParam::~PSFontParam() {
-  delete pdfFontName;
-  delete psFontName;
-  if (encoding) {
-    delete encoding;
-  }
-}
 
 #ifdef ENABLE_PLUGINS
 //------------------------------------------------------------------------
@@ -656,18 +560,23 @@ GlobalParams::GlobalParams(const char *customPopplerDataDir)
   unicodeMaps = new GooHash(gTrue);
   cMapDirs = new GooHash(gTrue);
   toUnicodeDirs = new GooList();
-  displayFonts = new GooHash();
+  fontFiles = new GooHash(gTrue);
+  fontDirs = new GooList();
+  ccFontFiles = new GooHash(gTrue);
+  sysFonts = new SysFontList();
   psExpandSmaller = gFalse;
   psShrinkLarger = gTrue;
   psCenter = gTrue;
   psLevel = psLevel2;
-  psFonts = new GooHash();
-  psNamedFonts16 = new GooList();
-  psFonts16 = new GooList();
+  psFile = NULL;
+  psResidentFonts = new GooHash(gTrue);
+  psResidentFonts16 = new GooList();
+  psResidentFontsCC = new GooList();
   psEmbedType1 = gTrue;
   psEmbedTrueType = gTrue;
   psEmbedCIDPostScript = gTrue;
   psEmbedCIDTrueType = gTrue;
+  psFontPassthrough = gFalse;
   psSubstFonts = gTrue;
   psPreload = gFalse;
   psOPI = gFalse;
@@ -683,7 +592,6 @@ GlobalParams::GlobalParams(const char *customPopplerDataDir)
 #endif
   textPageBreaks = gTrue;
   textKeepTinyChars = gFalse;
-  fontDirs = new GooList();
   enableFreeType = gTrue;
   disableFreeTypeHinting = gFalse;
   antialias = gTrue;
@@ -712,9 +620,7 @@ GlobalParams::GlobalParams(const char *customPopplerDataDir)
 
 #ifdef _WIN32
   baseFontsInitialized = gFalse;
-  winFontList = NULL;
 #endif
-
 #ifdef ENABLE_PLUGINS
   plugins = new GooList();
   securityHandlers = new GooList();
@@ -875,15 +781,17 @@ GlobalParams::~GlobalParams() {
   deleteGooHash(residentUnicodeMaps, UnicodeMap);
   deleteGooHash(unicodeMaps, GooString);
   deleteGooList(toUnicodeDirs, GooString);
-  deleteGooHash(displayFonts, DisplayFontParam);
-#ifdef _WIN32
-  delete winFontList;
-#endif
-  deleteGooHash(psFonts, PSFontParam);
-  deleteGooList(psNamedFonts16, PSFontParam);
-  deleteGooList(psFonts16, PSFontParam);
-  delete textEncoding;
+  deleteGooHash(fontFiles, GooString);
   deleteGooList(fontDirs, GooString);
+  deleteGooHash(ccFontFiles, GooString);
+  delete sysFonts;
+  if (psFile) {
+    delete psFile;
+  }
+  deleteGooHash(psResidentFonts, GooString);
+  deleteGooList(psResidentFonts16, PSFontParam16);
+  deleteGooList(psResidentFontsCC, PSFontParam16);
+  delete textEncoding;
 
   GooHashIter *iter;
   GooString *key;
@@ -1187,21 +1095,71 @@ static FcPattern *buildFcPattern(GfxFont *font)
 }
 #endif
 
+GooString *GlobalParams::findFontFile(GooString *fontName) {
+  static const char *exts[] = { ".pfa", ".pfb", ".ttf", ".ttc" };
+  GooString *path, *dir;
+#ifdef WIN32
+  GooString *fontNameU;
+#endif
+  const char *ext;
+  FILE *f;
+  int i, j;
+
+  lockGlobalParams;
+  setupBaseFonts(NULL);
+  if ((path = (GooString *)fontFiles->lookup(fontName))) {
+    path = path->copy();
+    unlockGlobalParams;
+    return path;
+  }
+  for (i = 0; i < fontDirs->getLength(); ++i) {
+    dir = (GooString *)fontDirs->get(i);
+    for (j = 0; j < (int)(sizeof(exts) / sizeof(exts[0])); ++j) {
+      ext = exts[j];
+#ifdef WIN32
+      fontNameU = fileNameToUTF8(fontName->getCString());
+      path = appendToPath(dir->copy(), fontNameU->getCString());
+      delete fontNameU;
+#else
+      path = appendToPath(dir->copy(), fontName->getCString());
+#endif
+      path->append(ext);
+      if ((f = openFile(path->getCString(), "rb"))) {
+	fclose(f);
+	unlockGlobalParams;
+	return path;
+      }
+      delete path;
+    }
+  }
+  unlockGlobalParams;
+  return NULL;
+}
+
 /* if you can't or don't want to use Fontconfig, you need to implement
    this function for your platform. For Windows, it's in GlobalParamsWin.cc
 */
 #if WITH_FONTCONFIGURATION_FONTCONFIG
-DisplayFontParam *GlobalParams::getDisplayFont(GfxFont *font) {
-  DisplayFontParam *dfp;
-  FcPattern *p=0;
+// not needed for fontconfig
+void GlobalParams::setupBaseFonts(char *dir) {
+}
 
+GooString *GlobalParams::findSystemFontFile(GfxFont *font,
+					  SysFontType *type,
+					  int *fontNum) {
+  SysFontInfo *fi = NULL;
+  FcPattern *p=0;
+  GooString *path = NULL;
   GooString *fontName = font->getName();
   if (!fontName) return NULL;
-  
+  fontName = fontName->copy();
   lockGlobalParams;
-  dfp = font->dfp;
-  if (!dfp)
-  {
+
+  if ((fi = sysFonts->find(fontName, gTrue))) {
+    path = fi->path->copy();
+    *type = fi->type;
+    *fontNum = fi->fontNum;
+  } else {
     FcChar8* s;
     char * ext;
     FcResult res;
@@ -1230,38 +1188,70 @@ DisplayFontParam *GlobalParams::getDisplayFont(GfxFont *font) {
       first: fonts support the language
       second: all fonts (fall back)
     */
-    while (dfp == NULL)
+    while (fi == NULL)
     {
       for (i = 0; i < set->nfont; ++i)
       {
-        res = FcPatternGetString(set->fonts[i], FC_FILE, 0, &s);
-        if (res != FcResultMatch || !s)
-          continue;
-        if (lb != NULL) {
-          FcLangSet *l;
-          res = FcPatternGetLangSet(set->fonts[i], FC_LANG, 0, &l);
-          if (res != FcResultMatch || !FcLangSetContains(l,lb)) {
-            continue;
-          }
-        }
-        ext = strrchr((char*)s,'.');
-        if (!ext)
-          continue;
-        if (!strncasecmp(ext,".ttf",4) || !strncasecmp(ext, ".ttc", 4))
-        {
-          dfp = new DisplayFontParam(fontName->copy(), displayFontTT);  
-          dfp->tt.fileName = new GooString((char*)s);
-          FcPatternGetInteger(set->fonts[i], FC_INDEX, 0, &(dfp->tt.faceIndex));
-        }
-        else if (!strncasecmp(ext,".pfa",4) || !strncasecmp(ext,".pfb",4)) 
-        {
-          dfp = new DisplayFontParam(fontName->copy(), displayFontT1);  
-          dfp->t1.fileName = new GooString((char*)s);
-        }
-        else
-          continue;
-        font->dfp = dfp;
-        break;
+	res = FcPatternGetString(set->fonts[i], FC_FILE, 0, &s);
+	if (res != FcResultMatch || !s)
+	  continue;
+	if (lb != NULL) {
+	  FcLangSet *l;
+	  res = FcPatternGetLangSet(set->fonts[i], FC_LANG, 0, &l);
+	  if (res != FcResultMatch || !FcLangSetContains(l,lb)) {
+	    continue;
+	  }
+	}
+	ext = strrchr((char*)s,'.');
+	if (!ext)
+	  continue;
+	if (!strncasecmp(ext,".ttf",4) || !strncasecmp(ext, ".ttc", 4))
+	{
+	  int weight, slant;
+	  GBool bold = font->isBold();
+	  GBool italic = font->isItalic();
+	  FcPatternGetInteger(set->fonts[i], FC_WEIGHT, 0, &weight);
+	  FcPatternGetInteger(set->fonts[i], FC_SLANT, 0, &slant);
+	  if (weight == FC_WEIGHT_DEMIBOLD || weight == FC_WEIGHT_BOLD 
+	      || weight == FC_WEIGHT_EXTRABOLD || weight == FC_WEIGHT_BLACK)
+	  {
+	    bold = gTrue;
+	  }
+	  if (slant == FC_SLANT_ITALIC)
+	    italic = gTrue;
+	  *fontNum = 0;
+	  *type = (!strncasecmp(ext,".ttf",4)) ? sysFontTTF : sysFontTTC;
+	  FcPatternGetInteger(set->fonts[i], FC_INDEX, 0, fontNum);
+	  fi = new SysFontInfo(fontName->copy(), bold, italic,
+			       new GooString((char*)s), *type, *fontNum);
+	  sysFonts->addFcFont(fi);
+	  path = new GooString((char*)s);
+	}
+	else if (!strncasecmp(ext,".pfa",4) || !strncasecmp(ext,".pfb",4)) 
+	{
+	  int weight, slant;
+	  GBool bold = font->isBold();
+	  GBool italic = font->isItalic();
+	  FcPatternGetInteger(set->fonts[i], FC_WEIGHT, 0, &weight);
+	  FcPatternGetInteger(set->fonts[i], FC_SLANT, 0, &slant);
+	  if (weight == FC_WEIGHT_DEMIBOLD || weight == FC_WEIGHT_BOLD 
+	      || weight == FC_WEIGHT_EXTRABOLD || weight == FC_WEIGHT_BLACK)
+	  {
+		bold = gTrue;
+	  }
+	  if (slant == FC_SLANT_ITALIC)
+	    italic = gTrue;
+	  *fontNum = 0;
+	  *type = (!strncasecmp(ext,".pfa",4)) ? sysFontPFA : sysFontPFB;
+	  FcPatternGetInteger(set->fonts[i], FC_INDEX, 0, fontNum);
+	  fi = new SysFontInfo(fontName->copy(), bold, italic,
+			       new GooString((char*)s), *type, *fontNum);
+	  sysFonts->addFcFont(fi);
+	  path = new GooString((char*)s);
+	}
+	else
+	  continue;
+	break;
       }
       if (lb != NULL) {
         FcLangSetDestroy(lb);
@@ -1273,18 +1263,124 @@ DisplayFontParam *GlobalParams::getDisplayFont(GfxFont *font) {
     }
     FcFontSetDestroy(set);
   }
+  if (path == NULL && (fi = sysFonts->find(fontName, gFalse))) {
+    path = fi->path->copy();
+    *type = fi->type;
+    *fontNum = fi->fontNum;
+  }
 fin:
   if (p)
     FcPatternDestroy(p);
-
   unlockGlobalParams;
-  return dfp;
+  return path;
 }
-#endif
-#if WITH_FONTCONFIGURATION_WIN32
+
+#elif WITH_FONTCONFIGURATION_WIN32
 #include "GlobalParamsWin.cc"
+#else
+static struct {
+  const char *name;
+  const char *t1FileName;
+  const char *ttFileName;
+} displayFontTab[] = {
+  {"Courier",               "n022003l.pfb", "cour.ttf"},
+  {"Courier-Bold",          "n022004l.pfb", "courbd.ttf"},
+  {"Courier-BoldOblique",   "n022024l.pfb", "courbi.ttf"},
+  {"Courier-Oblique",       "n022023l.pfb", "couri.ttf"},
+  {"Helvetica",             "n019003l.pfb", "arial.ttf"},
+  {"Helvetica-Bold",        "n019004l.pfb", "arialbd.ttf"},
+  {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf"},
+  {"Helvetica-Oblique",     "n019023l.pfb", "ariali.ttf"},
+  {"Symbol",                "s050000l.pfb", NULL},
+  {"Times-Bold",            "n021004l.pfb", "timesbd.ttf"},
+  {"Times-BoldItalic",      "n021024l.pfb", "timesbi.ttf"},
+  {"Times-Italic",          "n021023l.pfb", "timesi.ttf"},
+  {"Times-Roman",           "n021003l.pfb", "times.ttf"},
+  {"ZapfDingbats",          "d050000l.pfb", NULL},
+  {NULL}
+};
+
+static const char *displayFontDirs[] = {
+  "/usr/share/ghostscript/fonts",
+  "/usr/local/share/ghostscript/fonts",
+  "/usr/share/fonts/default/Type1",
+  "/usr/share/fonts/default/ghostscript",
+  "/usr/share/fonts/type1/gsfonts",
+  NULL
+};
+
+void GlobalParams::setupBaseFonts(char *dir) {
+  GooString *fontName;
+  GooString *fileName;
+  FILE *f;
+  int i, j;
+
+  for (i = 0; displayFontTab[i].name; ++i) {
+    if (fontFiles->lookup(displayFontTab[i].name)) {
+      continue;
+    }
+    fontName = new GooString(displayFontTab[i].name);
+    fileName = NULL;
+    if (dir) {
+      fileName = appendToPath(new GooString(dir), displayFontTab[i].t1FileName);
+      if ((f = fopen(fileName->getCString(), "rb"))) {
+	      fclose(f);
+      } else {
+	      delete fileName;
+	      fileName = NULL;
+      }
+    }
+    for (j = 0; !fileName && displayFontDirs[j]; ++j) {
+      fileName = appendToPath(new GooString(displayFontDirs[j]),
+			      displayFontTab[i].t1FileName);
+      if ((f = fopen(fileName->getCString(), "rb"))) {
+	      fclose(f);
+      } else {
+	      delete fileName;
+	      fileName = NULL;
+      }
+    }
+    if (!fileName) {
+      error(errConfig, -1, "No display font for '{0:s}'",
+	    displayFontTab[i].name);
+      delete fontName;
+      continue;
+    }
+    addFontFile(fontName, fileName);
+  }
+
+}
+
+GooString *GlobalParams::findSystemFontFile(GfxFont *font,
+					  SysFontType *type,
+					  int *fontNum) {
+  SysFontInfo *fi;
+  GooString *path;
+
+  path = NULL;
+  lockGlobalParams;
+  if ((fi = sysFonts->find(font->getName(), gFalse))) {
+    path = fi->path->copy();
+    *type = fi->type;
+    *fontNum = fi->fontNum;
+  }
+  unlockGlobalParams;
+  return path;
+}
 #endif
 
+GooString *GlobalParams::findCCFontFile(GooString *collection) {
+  GooString *path;
+
+  lockGlobalParams;
+  if ((path = (GooString *)ccFontFiles->lookup(collection))) {
+    path = path->copy();
+  }
+  unlockGlobalParams;
+  return path;
+}
+
+
 GBool GlobalParams::getPSExpandSmaller() {
   GBool f;
 
@@ -1321,41 +1417,62 @@ PSLevel GlobalParams::getPSLevel() {
   return level;
 }
 
-PSFontParam *GlobalParams::getPSFont(GooString *fontName) {
-  PSFontParam *p;
+GooString *GlobalParams::getPSResidentFont(GooString *fontName) {
+  GooString *psName;
 
   lockGlobalParams;
-  p = (PSFontParam *)psFonts->lookup(fontName);
+  psName = (GooString *)psResidentFonts->lookup(fontName);
   unlockGlobalParams;
-  return p;
+  return psName;
 }
 
-PSFontParam *GlobalParams::getPSFont16(GooString *fontName,
-				       GooString *collection, int wMode) {
-  PSFontParam *p;
+GooList *GlobalParams::getPSResidentFonts() {
+  GooList *names;
+  GooHashIter *iter;
+  GooString *name;
+  GooString *psName;
+
+  names = new GooList();
+  lockGlobalParams;
+  psResidentFonts->startIter(&iter);
+  while (psResidentFonts->getNext(&iter, &name, (void **)&psName)) {
+    names->append(psName->copy());
+  }
+  unlockGlobalParams;
+  return names;
+}
+
+PSFontParam16 *GlobalParams::getPSResidentFont16(GooString *fontName,
+						 int wMode) {
+  PSFontParam16 *p;
   int i;
 
   lockGlobalParams;
   p = NULL;
-  if (fontName) {
-    for (i = 0; i < psNamedFonts16->getLength(); ++i) {
-      p = (PSFontParam *)psNamedFonts16->get(i);
-      if (!p->pdfFontName->cmp(fontName) &&
-	  p->wMode == wMode) {
-	break;
-      }
-      p = NULL;
+  for (i = 0; i < psResidentFonts16->getLength(); ++i) {
+    p = (PSFontParam16 *)psResidentFonts16->get(i);
+    if (!(p->name->cmp(fontName)) && p->wMode == wMode) {
+      break;
     }
+    p = NULL;
   }
-  if (!p && collection) {
-    for (i = 0; i < psFonts16->getLength(); ++i) {
-      p = (PSFontParam *)psFonts16->get(i);
-      if (!p->pdfFontName->cmp(collection) &&
-	  p->wMode == wMode) {
-	break;
-      }
-      p = NULL;
+  unlockGlobalParams;
+  return p;
+}
+
+PSFontParam16 *GlobalParams::getPSResidentFontCC(GooString *collection,
+						 int wMode) {
+  PSFontParam16 *p;
+  int i;
+
+  lockGlobalParams;
+  p = NULL;
+  for (i = 0; i < psResidentFontsCC->getLength(); ++i) {
+    p = (PSFontParam16 *)psResidentFontsCC->get(i);
+    if (!(p->name->cmp(collection)) && p->wMode == wMode) {
+      break;
     }
+    p = NULL;
   }
   unlockGlobalParams;
   return p;
@@ -1397,11 +1514,11 @@ GBool GlobalParams::getPSEmbedCIDTrueType() {
   return e;
 }
 
-GBool GlobalParams::getPSSubstFonts() {
+GBool GlobalParams::getPSFontPassthrough() {
   GBool e;
 
   lockGlobalParams;
-  e = psSubstFonts;
+  e = psFontPassthrough;
   unlockGlobalParams;
   return e;
 }
@@ -1478,30 +1595,6 @@ GBool GlobalParams::getTextKeepTinyChars() {
   return tiny;
 }
 
-GooString *GlobalParams::findFontFile(GooString *fontName, const char **exts) {
-  GooString *dir, *fileName;
-  const char **ext;
-  FILE *f;
-  int i;
-
-  lockGlobalParams;
-  for (i = 0; i < fontDirs->getLength(); ++i) {
-    dir = (GooString *)fontDirs->get(i);
-    for (ext = exts; *ext; ++ext) {
-      fileName = appendToPath(dir->copy(), fontName->getCString());
-      fileName->append(*ext);
-      if ((f = openFile(fileName->getCString(), "rb"))) {
-	fclose(f);
-	unlockGlobalParams;
-	return fileName;
-      }
-      delete fileName;
-    }
-  }
-  unlockGlobalParams;
-  return NULL;
-}
-
 GBool GlobalParams::getEnableFreeType() {
   GBool f;
 
@@ -1752,6 +1845,21 @@ GooList *GlobalParams::getEncodingNames()
 // functions to set parameters
 //------------------------------------------------------------------------
 
+void GlobalParams::addFontFile(GooString *fontName, GooString *path) {
+  lockGlobalParams;
+  fontFiles->add(fontName, path);
+  unlockGlobalParams;
+}
+
+void GlobalParams::setPSFile(char *file) {
+  lockGlobalParams;
+  if (psFile) {
+    delete psFile;
+  }
+  psFile = new GooString(file);
+  unlockGlobalParams;
+}
+
 void GlobalParams::setPSExpandSmaller(GBool expand) {
   lockGlobalParams;
   psExpandSmaller = expand;
@@ -1806,6 +1914,12 @@ void GlobalParams::setPSSubstFonts(GBool substFonts) {
   unlockGlobalParams;
 }
 
+void GlobalParams::setPSFontPassthrough(GBool passthrough) {
+  lockGlobalParams;
+  psFontPassthrough = passthrough;
+  unlockGlobalParams;
+}
+
 void GlobalParams::setPSPreload(GBool preload) {
   lockGlobalParams;
   psPreload = preload;
diff --git a/poppler/GlobalParams.h b/poppler/GlobalParams.h
index bcaeda3..35f4473 100644
--- a/poppler/GlobalParams.h
+++ b/poppler/GlobalParams.h
@@ -60,9 +60,7 @@ struct XpdfSecurityHandler;
 class GlobalParams;
 class GfxFont;
 class Stream;
-#ifdef _WIN32
-class WinFontList;
-#endif
+class SysFontList;
 
 //------------------------------------------------------------------------
 
@@ -71,60 +69,27 @@ extern GlobalParams *globalParams;
 
 //------------------------------------------------------------------------
 
-enum DisplayFontParamKind {
-  displayFontT1,
-  displayFontTT
-};
-
-struct DisplayFontParamT1 {
-  GooString *fileName;
-};
-
-struct DisplayFontParamTT {
-  GooString *fileName;
-  int faceIndex;
-};
-
-class DisplayFontParam {
-public:
-
-  GooString *name;		// font name for 8-bit fonts and named
-				//   CID fonts; collection name for
-				//   generic CID fonts
-  DisplayFontParamKind kind;
-  union {
-    DisplayFontParamT1 t1;
-    DisplayFontParamTT tt;
-  };
-
-  DisplayFontParam(GooString *nameA, DisplayFontParamKind kindA);
-  void setFileName(GooString *fileNameA) {
-    if (displayFontT1 == kind)
-        t1.fileName = fileNameA;
-    else {
-        assert(displayFontTT == kind);
-        tt.fileName = fileNameA;
-    }
-  }  
-  virtual ~DisplayFontParam();
+enum SysFontType {
+  sysFontPFA,
+  sysFontPFB,
+  sysFontTTF,
+  sysFontTTC
 };
 
 //------------------------------------------------------------------------
 
-class PSFontParam {
+class PSFontParam16 {
 public:
 
-  GooString *pdfFontName;		// PDF font name for 8-bit fonts and
-				//   named 16-bit fonts; char collection
-				//   name for generic 16-bit fonts
-  int wMode;			// writing mode (0=horiz, 1=vert) for
-				//   16-bit fonts
+  GooString *name;		// PDF font name for psResidentFont16;
+				//   char collection name for psResidentFontCC
+  int wMode;			// writing mode (0=horiz, 1=vert)
   GooString *psFontName;		// PostScript font name
-  GooString *encoding;		// encoding, for 16-bit fonts only
+  GooString *encoding;		// encoding
 
-  PSFontParam(GooString *pdfFontNameA, int wModeA,
-	      GooString *psFontNameA, GooString *encodingA);
-  ~PSFontParam();
+  PSFontParam16(GooString *nameA, int wModeA,
+		GooString *psFontNameA, GooString *encodingA);
+  ~PSFontParam16();
 };
 
 //------------------------------------------------------------------------
@@ -167,10 +132,7 @@ public:
   ~GlobalParams();
 
   void setBaseDir(const char *dir);
-
-#if WITH_FONTCONFIGURATION_WIN32
   void setupBaseFonts(char *dir);
-#endif
 
   //----- accessors
 
@@ -182,18 +144,23 @@ public:
   FILE *getUnicodeMapFile(GooString *encodingName);
   FILE *findCMapFile(GooString *collection, GooString *cMapName);
   FILE *findToUnicodeFile(GooString *name);
-  DisplayFontParam *getDisplayFont(GfxFont *font);
+  GooString *findFontFile(GooString *fontName);
+  GooString *findSystemFontFile(GfxFont *font, SysFontType *type,
+			      int *fontNum);
+  GooString *findCCFontFile(GooString *collection);
   GBool getPSExpandSmaller();
   GBool getPSShrinkLarger();
   GBool getPSCenter();
   PSLevel getPSLevel();
-  PSFontParam *getPSFont(GooString *fontName);
-  PSFontParam *getPSFont16(GooString *fontName, GooString *collection, int wMode);
+  GooString *getPSResidentFont(GooString *fontName);
+  GooList *getPSResidentFonts();
+  PSFontParam16 *getPSResidentFont16(GooString *fontName, int wMode);
+  PSFontParam16 *getPSResidentFontCC(GooString *collection, int wMode);
   GBool getPSEmbedType1();
   GBool getPSEmbedTrueType();
   GBool getPSEmbedCIDPostScript();
   GBool getPSEmbedCIDTrueType();
-  GBool getPSSubstFonts();
+  GBool getPSFontPassthrough();
   GBool getPSPreload();
   GBool getPSOPI();
   GBool getPSASCIIHex();
@@ -202,7 +169,6 @@ public:
   EndOfLineKind getTextEOL();
   GBool getTextPageBreaks();
   GBool getTextKeepTinyChars();
-  GooString *findFontFile(GooString *fontName, const char **exts);
   GBool getEnableFreeType();
   GBool getDisableFreeTypeHinting();
   GBool getAntialias();
@@ -235,6 +201,8 @@ public:
   GooList *getEncodingNames();
 
   //----- functions to set parameters
+  void addFontFile(GooString *fontName, GooString *path);
+  void setPSFile(char *file);
   void setPSExpandSmaller(GBool expand);
   void setPSShrinkLarger(GBool shrink);
   void setPSCenter(GBool center);
@@ -244,6 +212,7 @@ public:
   void setPSEmbedCIDPostScript(GBool embed);
   void setPSEmbedCIDTrueType(GBool embed);
   void setPSSubstFonts(GBool substFonts);
+  void setPSFontPassthrough(GBool passthrough);
   void setPSPreload(GBool preload);
   void setPSOPI(GBool opi);
   void setPSASCIIHex(GBool hex);
@@ -310,25 +279,35 @@ private:
   GooHash *cMapDirs;		// list of CMap dirs, indexed by collection
 				//   name [GooList[GooString]]
   GooList *toUnicodeDirs;		// list of ToUnicode CMap dirs [GooString]
-  GooHash *displayFonts;		// display font info, indexed by font name
-				//   [DisplayFontParam]
 #ifdef _WIN32
   GBool baseFontsInitialized;
-  WinFontList *winFontList;	// system TrueType fonts
 #endif
+  GooHash *fontFiles;		// font files: font name mapped to path
+				//   [GString]
+  GooList *fontDirs;		// list of font dirs [GString]
+  GooHash *ccFontFiles;	// character collection font files:
+				//   collection name  mapped to path [GString]
+  SysFontList *sysFonts;	// system fonts
+  GooString *psFile;		// PostScript file or command (for xpdf)
   GBool psExpandSmaller;	// expand smaller pages to fill paper
   GBool psShrinkLarger;		// shrink larger pages to fit paper
   GBool psCenter;		// center pages on the paper
   PSLevel psLevel;		// PostScript level to generate
-  GooHash *psFonts;		// PostScript font info, indexed by PDF
-				//   font name [PSFontParam]
-  GooList *psNamedFonts16;	// named 16-bit fonts [PSFontParam]
-  GooList *psFonts16;		// generic 16-bit fonts [PSFontParam]
+  GooHash *psResidentFonts;	// 8-bit fonts resident in printer:
+				//   PDF font name mapped to PS font name
+				//   [GString]
+  GooList *psResidentFonts16;	// 16-bit fonts resident in printer:
+				//   PDF font name mapped to font info
+				//   [PSFontParam16]
+  GooList *psResidentFontsCC;	// 16-bit character collection fonts
+				//   resident in printer: collection name
+				//   mapped to font info [PSFontParam16]
   GBool psEmbedType1;		// embed Type 1 fonts?
   GBool psEmbedTrueType;	// embed TrueType fonts?
   GBool psEmbedCIDPostScript;	// embed CID PostScript fonts?
   GBool psEmbedCIDTrueType;	// embed CID TrueType fonts?
   GBool psSubstFonts;		// substitute missing fonts?
+  GBool psFontPassthrough;	// pass all fonts through as-is?
   GBool psPreload;		// preload PostScript images and forms into
 				//   memory
   GBool psOPI;			// generate PostScript OPI comments?
@@ -340,7 +319,6 @@ private:
 				//   output
   GBool textPageBreaks;		// insert end-of-page markers?
   GBool textKeepTinyChars;	// keep all characters in text output
-  GooList *fontDirs;		// list of font dirs [GooString]
   GBool enableFreeType;		// FreeType enable flag
   GBool disableFreeTypeHinting;	// FreeType disable hinting flag
   GBool antialias;		// anti-aliasing enable flag
@@ -367,8 +345,8 @@ private:
   CMapCache *cMapCache;
   
 #ifdef ENABLE_PLUGINS
-  GList *plugins;		// list of plugins [Plugin]
-  GList *securityHandlers;	// list of loaded security handlers
+  GooList *plugins;		// list of plugins [Plugin]
+  GooList *securityHandlers;	// list of loaded security handlers
 				//   [XpdfSecurityHandler]
 #endif
 
diff --git a/poppler/GlobalParamsWin.cc b/poppler/GlobalParamsWin.cc
index 5af717a..54ce4f7 100644
--- a/poppler/GlobalParamsWin.cc
+++ b/poppler/GlobalParamsWin.cc
@@ -60,9 +60,9 @@ description for all fonts available in Windows. That's how MuPDF works.
 #define DEFAULT_SUBSTITUTE_FONT "Helvetica"
 
 static struct {
-    const char *name;
-    const char *t1FileName;
-    const char *ttFileName;
+    char *name;
+    char *t1FileName;
+    char *ttFileName;
 } displayFontTab[] = {
     {"Courier",               "n022003l.pfb", "cour.ttf"},
     {"Courier-Bold",          "n022004l.pfb", "courbd.ttf"},
@@ -218,11 +218,124 @@ static bool FileExists(const char *path)
     return false;
 }
 
-static void AddFont(GooHash *displayFonts, char *fontName, GooString *fontPath, DisplayFontParamKind kind)
-{
-    DisplayFontParam *dfp = new DisplayFontParam(new GooString(fontName), kind);
-    dfp->setFileName(fontPath);
-    displayFonts->add(dfp->name, dfp);
+void SysFontList::scanWindowsFonts(GooString *winFontDir) {
+  OSVERSIONINFO version;
+  char *path;
+  DWORD idx, valNameLen, dataLen, type;
+  HKEY regKey;
+  char valName[1024], data[1024];
+  int n, fontNum;
+  char *p0, *p1;
+  GooString *fontPath;
+
+  version.dwOSVersionInfoSize = sizeof(version);
+  GetVersionEx(&version);
+  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+    path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
+  } else {
+    path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
+  }
+  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0,
+		   KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+		   &regKey) == ERROR_SUCCESS) {
+    idx = 0;
+    while (1) {
+      valNameLen = sizeof(valName) - 1;
+      dataLen = sizeof(data) - 1;
+      if (RegEnumValue(regKey, idx, valName, &valNameLen, NULL,
+		       &type, (LPBYTE)data, &dataLen) != ERROR_SUCCESS) {
+	break;
+      }
+      if (type == REG_SZ &&
+	  valNameLen > 0 && valNameLen < sizeof(valName) &&
+	  dataLen > 0 && dataLen < sizeof(data)) {
+	valName[valNameLen] = '\0';
+	data[dataLen] = '\0';
+	n = strlen(data);
+	if (!strcasecmp(data + n - 4, ".ttf") ||
+	    !strcasecmp(data + n - 4, ".ttc")) {
+	  fontPath = new GooString(data);
+	  if (!(dataLen >= 3 && data[1] == ':' && data[2] == '\\')) {
+	    fontPath->insert(0, '\\');
+	    fontPath->insert(0, winFontDir);
+		fontPath->append('\0');
+	  }
+	  p0 = valName;
+	  fontNum = 0;
+	  while (*p0) {
+	    p1 = strstr(p0, " & ");
+	    if (p1) {
+	      *p1 = '\0';
+	      p1 = p1 + 3;
+	    } else {
+	      p1 = p0 + strlen(p0);
+	    }
+	    fonts->append(makeWindowsFont(p0, fontNum,
+					  fontPath->getCString()));
+	    p0 = p1;
+	    ++fontNum;
+	  }
+	  delete fontPath;
+	}
+      }
+      ++idx;
+    }
+    RegCloseKey(regKey);
+  }
+}
+
+SysFontInfo *SysFontList::makeWindowsFont(char *name, int fontNum,
+					  char *path) {
+  int n;
+  GBool bold, italic;
+  GooString *s;
+  char c;
+  int i;
+  SysFontType type;
+
+  n = strlen(name);
+  bold = italic = gFalse;
+
+  // remove trailing ' (TrueType)'
+  if (n > 11 && !strncmp(name + n - 11, " (TrueType)", 11)) {
+    n -= 11;
+  }
+
+  // remove trailing ' Italic'
+  if (n > 7 && !strncmp(name + n - 7, " Italic", 7)) {
+    n -= 7;
+    italic = gTrue;
+  }
+
+  // remove trailing ' Bold'
+  if (n > 5 && !strncmp(name + n - 5, " Bold", 5)) {
+    n -= 5;
+    bold = gTrue;
+  }
+
+  // remove trailing ' Regular'
+  if (n > 5 && !strncmp(name + n - 8, " Regular", 8)) {
+    n -= 8;
+  }
+
+  //----- normalize the font name
+  s = new GooString(name, n);
+  i = 0;
+  while (i < s->getLength()) {
+    c = s->getChar(i);
+    if (c == ' ' || c == ',' || c == '-') {
+      s->del(i);
+    } else {
+      ++i;
+    }
+  }
+
+  if (!strcasecmp(path + strlen(path) - 4, ".ttc")) {
+    type = sysFontTTC;
+  } else {
+    type = sysFontTTF;
+  }
+  return new SysFontInfo(s, bold, italic, new GooString(path), type, fontNum);
 }
 
 void GlobalParams::setupBaseFonts(char * dir)
@@ -235,14 +348,14 @@ void GlobalParams::setupBaseFonts(char * dir)
     GetWindowsFontDir(winFontDir, sizeof(winFontDir));
 
     for (int i = 0; displayFontTab[i].name; ++i) {
-        char *fontName = (char *) displayFontTab[i].name;
-        if (displayFonts->lookup(fontName))
+        GooString  *fontName = new GooString(displayFontTab[i].name);
+        if (fontFiles->lookup(fontName))
             continue;
 
         if (dir) {
             GooString *fontPath = appendToPath(new GooString(dir), displayFontTab[i].t1FileName);
             if (FileExists(fontPath->getCString())) {
-                AddFont(displayFonts, fontName, fontPath, displayFontT1);
+                addFontFile(fontName, fontPath);
                 continue;
             }
             delete fontPath;
@@ -251,7 +364,7 @@ void GlobalParams::setupBaseFonts(char * dir)
         if (winFontDir[0] && displayFontTab[i].ttFileName) {
             GooString *fontPath = appendToPath(new GooString(winFontDir), displayFontTab[i].ttFileName);
             if (FileExists(fontPath->getCString())) {
-                AddFont(displayFonts, fontName, fontPath, displayFontTT);
+                addFontFile(fontName, fontPath);
                 continue;
             }
             delete fontPath;
@@ -259,6 +372,9 @@ void GlobalParams::setupBaseFonts(char * dir)
 
         error(errSyntaxError, -1, "No display font for '{0:s}'", fontName);
     }
+    if (winFontDir[0]) {
+      sysFonts->scanWindowsFonts(new GooString(winFontDir));
+    }
 }
 
 static char *findSubstituteName(const char *origName)
@@ -270,22 +386,28 @@ static char *findSubstituteName(const char *origName)
 }
 
 /* Windows implementation of external font matching code */
-DisplayFontParam *GlobalParams::getDisplayFont(GfxFont *font) {
-    DisplayFontParam *  dfp;
-    GooString *         fontName = font->getName();
-    char *              substFontName = NULL;
-
-    if (!fontName) return NULL;
-    lockGlobalParams;
-    setupBaseFonts(NULL);
-    dfp = (DisplayFontParam *)displayFonts->lookup(fontName);
-    if (!dfp) {
-        substFontName = findSubstituteName(fontName->getCString());
-        error(errSyntaxError, -1, "Couldn't find a font for '{0:t}', subst is '{0:s}'", fontName, substFontName);
-        dfp = (DisplayFontParam *)displayFonts->lookup(substFontName);
-        assert(dfp);
+GooString *GlobalParams::findSystemFontFile(GfxFont *font,
+					  SysFontType *type,
+					  int *fontNum) {
+  SysFontInfo *fi;
+  GooString *path = NULL;
+  GooString *fontName = font->getName();
+  if (!fontName) return NULL;
+  lockGlobalParams;
+  setupBaseFonts(NULL);
+  if ((fi = sysFonts->find(fontName, gFalse))) {
+    path = fi->path->copy();
+    *type = fi->type;
+    *fontNum = fi->fontNum;
+  } else {
+    GooString *substFontName = new GooString(findSubstituteName(fontName->getCString()));
+    error(errSyntaxError, -1, "Couldn't find a font for '{0:t}', subst is '{0:s}'", fontName, substFontName);
+    if ((fi = sysFonts->find(substFontName, gFalse))) {
+      path = fi->path->copy();
+      *type = fi->type;
+      *fontNum = fi->fontNum;
     }
-    unlockGlobalParams;
-    return dfp;
+  }      
+  unlockGlobalParams;
+  return path;
 }
-
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 4a6537d..cf385be 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -46,6 +46,7 @@
 #include <limits.h>
 #include "goo/GooString.h"
 #include "goo/GooList.h"
+#include "goo/GooHash.h"
 #include "poppler-config.h"
 #include "GlobalParams.h"
 #include "Object.h"
@@ -64,6 +65,7 @@
 #include "XRef.h"
 #include "PreScanOutputDev.h"
 #include "FileSpec.h"
+#include "CharCodeToUnicode.h"
 #if HAVE_SPLASH
 #  include "splash/Splash.h"
 #  include "splash/SplashBitmap.h"
@@ -805,25 +807,12 @@ struct PSSubstFont {
   double mWidth;		// width of 'm' character
 };
 
-static const char *psFonts[] = {
-  "Courier",
-  "Courier-Bold",
-  "Courier-Oblique",
-  "Courier-BoldOblique",
-  "Helvetica",
-  "Helvetica-Bold",
-  "Helvetica-Oblique",
-  "Helvetica-BoldOblique",
-  "Symbol",
-  "Times-Roman",
-  "Times-Bold",
-  "Times-Italic",
-  "Times-BoldItalic",
-  "ZapfDingbats",
-  NULL
-};
-
-static const PSSubstFont psSubstFonts[] = {
+// NB: must be in same order as base14SubstFonts in GfxFont.cc
+static PSSubstFont psBase14SubstFonts[14] = {
+  {"Courier",               0.600},
+  {"Courier-Oblique",       0.600},
+  {"Courier-Bold",          0.600},
+  {"Courier-BoldOblique",   0.600},
   {"Helvetica",             0.833},
   {"Helvetica-Oblique",     0.833},
   {"Helvetica-Bold",        0.889},
@@ -832,10 +821,16 @@ static const PSSubstFont psSubstFonts[] = {
   {"Times-Italic",          0.722},
   {"Times-Bold",            0.833},
   {"Times-BoldItalic",      0.778},
-  {"Courier",               0.600},
-  {"Courier-Oblique",       0.600},
-  {"Courier-Bold",          0.600},
-  {"Courier-BoldOblique",   0.600}
+  // the last two are never used for substitution
+  {"Symbol",                0},
+  {"ZapfDingbats",          0}
+};
+
+// Mapping from Type 1/1C font file to PS font name.
+struct PST1FontName {
+  Ref fontFileID;
+  GooString *psName;		// PostScript font name used for this
+				//   embedded font file
 };
 
 // Info for 8-bit fonts
@@ -1010,6 +1005,7 @@ PSOutputDev::PSOutputDev(const char *fileName, PDFDoc *doc,
   overlayCbkData = NULL;
 
   fontIDs = NULL;
+  fontNames = new GooHash(gTrue);
   fontFileIDs = NULL;
   fontFileNames = NULL;
   font8Info = NULL;
@@ -1073,6 +1069,7 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
   overlayCbkData = NULL;
 
   fontIDs = NULL;
+  fontNames = new GooHash(gTrue);
   fontFileIDs = NULL;
   fontFileNames = NULL;
   font8Info = NULL;
@@ -1130,7 +1127,6 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
       paperHeight = 1;
     }
   }
-  substFonts = globalParams->getPSSubstFonts();
   preload = globalParams->getPSPreload();
   if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
     imgLLX = imgLLY = 0;
@@ -1256,6 +1252,7 @@ PSOutputDev::~PSOutputDev() {
   if (fontIDs) {
     gfree(fontIDs);
   }
+  delete fontNames;
   if (fontFileIDs) {
     gfree(fontFileIDs);
   }
@@ -1656,9 +1653,7 @@ void PSOutputDev::setupFonts(Dict *resDict) {
 }
 
 void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
-  Ref fontFileID;
-  GooString *name;
-  PSFontParam *fontParam;
+  GfxFontLoc *fontLoc;
   GooString *psName;
   char buf[16];
   GBool subst;
@@ -1667,9 +1662,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
   double xs, ys;
   int code;
   double w1, w2;
-  double *fm;
   int i, j;
-  DisplayFontParam *dfp;
 
   // check if font is already set up
   for (i = 0; i < fontIDLen; ++i) {
@@ -1686,205 +1679,162 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
   }
   fontIDs[fontIDLen++] = *font->getID();
 
+  psName = NULL;
   xs = ys = 1;
   subst = gFalse;
 
-  // check for resident 8-bit font
-  if (font->getName() &&
-      (fontParam = globalParams->getPSFont(font->getName()))) {
-    psName = new GooString(fontParam->psFontName->getCString());
-
-  // check for embedded Type 1 font
-  } else if (globalParams->getPSEmbedType1() &&
-	     font->getType() == fontType1 &&
-	     font->getEmbeddedFontID(&fontFileID) &&
-	     font->getEmbeddedFontName()) {
-    psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
-    setupEmbeddedType1Font(&fontFileID, psName);
-
-  // check for embedded Type 1C font
-  } else if (globalParams->getPSEmbedType1() &&
-	     font->getType() == fontType1C &&
-	     font->getEmbeddedFontID(&fontFileID) &&
-	     font->getName()) {
-    // use the PDF font name because the embedded font name might
-    // not include the subset prefix
-    psName = font->getName()->sanitizedName(gTrue /* ps mode */);
-    setupEmbeddedType1CFont(font, &fontFileID, psName);
-
-  // check for embedded OpenType - Type 1C font
-  } else if (globalParams->getPSEmbedType1() &&
-	     font->getType() == fontType1COT &&
-	     font->getEmbeddedFontID(&fontFileID) &&
-	     font->getName()) {
-    // use the PDF font name because the embedded font name might
-    // not include the subset prefix
-    psName = font->getName()->sanitizedName(gTrue /* ps mode */);
-    setupEmbeddedOpenTypeT1CFont(font, &fontFileID, psName);
-
-  // check for external Type 1 font file
-  } else if (globalParams->getPSEmbedType1() &&
-	     font->getType() == fontType1 &&
-	     font->getExtFontFile() &&
-	     font->getName()) {
-    // this assumes that the PS font name matches the PDF font name
-    psName = font->getName()->copy();
-    setupExternalType1Font(font->getExtFontFile(), psName);
-
-  // check for embedded TrueType font
-  } else if (globalParams->getPSEmbedTrueType() &&
-	     (font->getType() == fontTrueType ||
-	      font->getType() == fontTrueTypeOT) &&
-	     font->getEmbeddedFontID(&fontFileID) &&
-	     font->getEmbeddedFontName()) {
-    psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
-    setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
-
-  // check for external TrueType font file
-  } else if (globalParams->getPSEmbedTrueType() &&
-	     font->getType() == fontTrueType &&
-	     font->getExtFontFile()) {
-    psName = setupExternalTrueTypeFont(font);
-
-  // check for embedded CID PostScript font
-  } else if (globalParams->getPSEmbedCIDPostScript() &&
-	     font->getType() == fontCIDType0C &&
-	     font->getEmbeddedFontID(&fontFileID) &&
-	     font->getEmbeddedFontName()) {
-    psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
-    setupEmbeddedCIDType0Font(font, &fontFileID, psName);
-
-  // check for embedded CID TrueType font
-  } else if (globalParams->getPSEmbedCIDTrueType() &&
-	     (font->getType() == fontCIDType2 ||
-	      font->getType() == fontCIDType2OT) &&
-	     font->getEmbeddedFontID(&fontFileID) &&
-	     font->getEmbeddedFontName()) {
-    psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
-    setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue);
-
-  // check for embedded OpenType - CID CFF font
-  } else if (globalParams->getPSEmbedCIDPostScript() &&
-	     font->getType() == fontCIDType0COT &&
-	     font->getEmbeddedFontID(&fontFileID) &&
-	     font->getEmbeddedFontName()) {
-    psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
-    setupEmbeddedOpenTypeCFFFont(font, &fontFileID, psName);
-
-  // check for Type 3 font
-  } else if (font->getType() == fontType3) {
+  if (font->getType() == fontType3) {
     psName = GooString::format("T3_{0:d}_{1:d}",
 			     font->getID()->num, font->getID()->gen);
     setupType3Font(font, psName, parentResDict);
-
-  // check for external CID TrueType font file
-  } else if (globalParams->getPSEmbedCIDTrueType() &&
-	     font->getType() == fontCIDType2 &&
-	     font->getExtFontFile()) {
-    psName = setupExternalCIDTrueTypeFont(font, font->getExtFontFile());
-
-  // do 8-bit font substitution
-  } else if (!font->isCIDFont()) {
-    subst = gTrue;
-    name = font->getName();
-    psName = NULL;
-    if (name) {
-      for (i = 0; psFonts[i]; ++i) {
-	if (name->cmp(psFonts[i]) == 0) {
-	  psName = new GooString(psFonts[i]);
-	  break;
+  } else {
+    fontLoc = font->locateFont(xref, gTrue);
+    switch (fontLoc->locType) {
+    case gfxFontLocEmbedded:
+      switch (fontLoc->fontType) {
+      case fontType1:
+	// this assumes that the PS font name matches the PDF font name
+	psName = font->getEmbeddedFontName()->copy();
+	setupEmbeddedType1Font(&fontLoc->embFontID, psName);
+	break;
+      case fontType1C:
+	psName = makePSFontName(font, &fontLoc->embFontID);
+	setupEmbeddedType1CFont(font, &fontLoc->embFontID, psName);
+	break;
+      case fontType1COT:
+	psName = makePSFontName(font, &fontLoc->embFontID);
+	setupEmbeddedOpenTypeT1CFont(font, &fontLoc->embFontID, psName);
+	break;
+      case fontTrueType:
+      case fontTrueTypeOT:
+	psName = makePSFontName(font, font->getID());
+	setupEmbeddedTrueTypeFont(font, &fontLoc->embFontID, psName);
+	break;
+      case fontCIDType0C:
+	psName = makePSFontName(font, &fontLoc->embFontID);
+	setupEmbeddedCIDType0Font(font, &fontLoc->embFontID, psName);
+	break;
+      case fontCIDType2:
+      case fontCIDType2OT:
+	psName = makePSFontName(font, font->getID());
+	//~ should check to see if font actually uses vertical mode
+	setupEmbeddedCIDTrueTypeFont(font, &fontLoc->embFontID, psName, gTrue);
+	break;
+      case fontCIDType0COT:
+	psName = makePSFontName(font, &fontLoc->embFontID);
+	setupEmbeddedOpenTypeCFFFont(font, &fontLoc->embFontID, psName);
+	break;
+      default:
+	break;
+      }
+      break;
+    case gfxFontLocExternal:
+      //~ add cases for external 16-bit fonts
+      switch (fontLoc->fontType) {
+      case fontType1:
+	if (font->getName()) {
+	  // this assumes that the PS font name matches the PDF font name
+	  psName = font->getName()->copy();
+	} else {
+	  //~ this won't work -- the PS font name won't match
+	  psName = makePSFontName(font, font->getID());
 	}
+	setupExternalType1Font(fontLoc->path, psName);
+	break;
+      case fontTrueType:
+      case fontTrueTypeOT:
+	psName = makePSFontName(font, font->getID());
+	setupExternalTrueTypeFont(font, fontLoc->path, psName);
+	break;
+      case fontCIDType2:
+      case fontCIDType2OT:
+	psName = makePSFontName(font, font->getID());
+	//~ should check to see if font actually uses vertical mode
+	setupExternalCIDTrueTypeFont(font, fontLoc->path, psName, gTrue);
+	break;
+      default:
+	break;
       }
+      break;
+    case gfxFontLocResident:
+      psName = fontLoc->path->copy();
+      break;
     }
+
     if (!psName) {
-      if (substFonts) {
-	if (font->isFixedWidth()) {
-	  i = 8;
-	} else if (font->isSerif()) {
-	  i = 4;
-	} else {
-	  i = 0;
-	}
-	if (font->isBold()) {
-	  i += 2;
-	}
-	if (font->isItalic()) {
-	  i += 1;
-	}
-	psName = new GooString(psSubstFonts[i].psName);
-	for (code = 0; code < 256; ++code) {
-	  if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
-	      charName[0] == 'm' && charName[1] == '\0') {
-	    break;
-	  }
-	}
-	if (code < 256) {
-	  w1 = ((Gfx8BitFont *)font)->getWidth(code);
-	} else {
-	  w1 = 0;
-	}
-	w2 = psSubstFonts[i].mWidth;
-	xs = w1 / w2;
-	if (xs < 0.1) {
-	  xs = 1;
+      if (font->isCIDFont()) {
+	error(errSyntaxError, -1,
+	      "Couldn't find a font to substitute for '{0:s}' ('{1:s}' character collection)",
+	      font->getName() ? font->getName()->getCString()
+	                      : "(unnamed)",
+	      ((GfxCIDFont *)font)->getCollection()
+	          ? ((GfxCIDFont *)font)->getCollection()->getCString()
+	          : "(unknown)");
+	if (font16EncLen >= font16EncSize) {
+	  font16EncSize += 16;
+	  font16Enc = (PSFont16Enc *)greallocn(font16Enc,
+					       font16EncSize,
+					       sizeof(PSFont16Enc));
 	}
+	font16Enc[font16EncLen].fontID = *font->getID();
+	font16Enc[font16EncLen].enc = NULL;
+	++font16EncLen;
       } else {
-	psName = new GooString(name);
-	xs = 1;
+	error(errSyntaxError, -1,
+	      "Couldn't find a font to substitute for '{0:s}'",
+	      font->getName() ? font->getName()->getCString()
+	                      : "(unnamed)");
       }
-      if (font->getType() == fontType3) {
-	// This is a hack which makes it possible to substitute for some
-	// Type 3 fonts.  The problem is that it's impossible to know what
-	// the base coordinate system used in the font is without actually
-	// rendering the font.
-	ys = xs;
-	fm = font->getFontMatrix();
-	if (fm[0] != 0) {
-	  ys *= fm[3] / fm[0];
+      delete fontLoc;
+      return;
+    }
+
+    // scale substituted 8-bit fonts
+    if (fontLoc->locType == gfxFontLocResident &&
+	fontLoc->substIdx >= 0) {
+      subst = gTrue;
+      for (code = 0; code < 256; ++code) {
+	if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
+	    charName[0] == 'm' && charName[1] == '\0') {
+	  break;
 	}
+      }
+      if (code < 256) {
+	w1 = ((Gfx8BitFont *)font)->getWidth(code);
       } else {
-	ys = 1;
+	w1 = 0;
+      }
+      w2 = psBase14SubstFonts[fontLoc->substIdx].mWidth;
+      xs = w1 / w2;
+      if (xs < 0.1) {
+	xs = 1;
       }
     }
 
-  // do 16-bit font substitution
-  } else if ((fontParam = globalParams->
-	        getPSFont16(font->getName(),
-			    ((GfxCIDFont *)font)->getCollection(),
-			    font->getWMode()))) {
-    subst = gTrue;
-    psName = fontParam->psFontName->copy();
-    if (font16EncLen >= font16EncSize) {
-      font16EncSize += 16;
-      font16Enc = (PSFont16Enc *)greallocn(font16Enc,
-					   font16EncSize, sizeof(PSFont16Enc));
-    }
-    font16Enc[font16EncLen].fontID = *font->getID();
-    font16Enc[font16EncLen].enc = fontParam->encoding->copy();
-    if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
-      uMap->decRefCnt();
+    // handle encodings for substituted CID fonts
+    if (fontLoc->locType == gfxFontLocResident &&
+	fontLoc->fontType >= fontCIDType0) {
+      subst = gTrue;
+      if (font16EncLen >= font16EncSize) {
+	font16EncSize += 16;
+	font16Enc = (PSFont16Enc *)greallocn(font16Enc,
+					     font16EncSize,
+					     sizeof(PSFont16Enc));
+      }
+      font16Enc[font16EncLen].fontID = *font->getID();
+      if ((uMap = globalParams->getUnicodeMap(fontLoc->encoding))) {
+	font16Enc[font16EncLen].enc = fontLoc->encoding->copy();
+	uMap->decRefCnt();
+      } else {
+	error(errSyntaxError, -1,
+	      "Couldn't find Unicode map for 16-bit font encoding '{0:t}'",
+	      fontLoc->encoding);
+	font16Enc[font16EncLen].enc = NULL;
+      }
       ++font16EncLen;
-    } else {
-      error(errSyntaxError, -1, "Couldn't find Unicode map for 16-bit font encoding '{0:t}'",
-	    font16Enc[font16EncLen].enc);
     }
 
-    // try the display font for embedding
-  } else if (globalParams->getPSEmbedCIDTrueType() &&
-	     ((GfxCIDFont *)font)->getCollection() &&
-	     (dfp = globalParams->
-	      getDisplayFont(font)) &&
-	     dfp->kind == displayFontTT) {
-    psName = setupExternalCIDTrueTypeFont(font, dfp->tt.fileName, dfp->tt.faceIndex);
-
-  // give up - can't do anything with this font
-  } else {
-    error(errSyntaxError, -1, "Couldn't find a font to substitute for '{0:s}' ('{1:s}' character collection)",
-	  font->getName() ? font->getName()->getCString() : "(unnamed)",
-	  ((GfxCIDFont *)font)->getCollection()
-	    ? ((GfxCIDFont *)font)->getCollection()->getCString()
-	    : "(unknown)");
-    return;
+    delete fontLoc;
   }
 
   // generate PostScript code to set up the font
@@ -1911,11 +1861,6 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
 	  charName = buf;
 	} else {
 	  charName = ((Gfx8BitFont *)font)->getCharName(i+j);
-	  // this is a kludge for broken PDF files that encode char 32
-	  // as .notdef
-	  if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
-	    charName = "space";
-	  }
 	}
 	writePS("/");
 	writePSName(charName ? charName : (char *)".notdef");
@@ -2279,39 +2224,10 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
   writePS("%%EndResource\n");
 }
 
-GooString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) {
-  GooString *fileName;
-  char *fontBuf;
-  int fontLen;
+void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GooString *fileName,
+					    GooString *psName) {
   FoFiTrueType *ffTT;
   int *codeToGID;
-  GooString *psName;
-  int i;
-
-  // check if font is already embedded
-  fileName = font->getExtFontFile();
-  for (i = 0; i < fontFileNameLen; ++i) {
-    if (!fontFileNames[i]->cmp(fileName)) {
-      return psFileNames[i]->copy();
-    }
-  }
-
-  psName = font->getName()->sanitizedName(gTrue /* ps mode */);
-  // add entry to fontFileNames list
-  if (i == fontFileNameLen) {
-    if (fontFileNameLen >= fontFileNameSize) {
-      fontFileNameSize += 64;
-      fontFileNames =
-	(GooString **)greallocn(fontFileNames,
-			      fontFileNameSize, sizeof(GooString *));
-      psFileNames =
-	(GooString **)greallocn(psFileNames,
-			     fontFileNameSize, sizeof(GooString *));
-    }
-    fontFileNames[fontFileNameLen] = fileName->copy();
-    psFileNames[fontFileNameLen] = psName->copy();
-    fontFileNameLen++;
-  }
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2320,8 +2236,7 @@ GooString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) {
   embFontList->append("\n");
 
   // convert it to a Type 42 font
-  fontBuf = font->readExtFontFile(&fontLen);
-  if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+  if ((ffTT = FoFiTrueType::load(fileName->getCString()))) {
     codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
     ffTT->convertToType42(psName->getCString(),
 			  ((Gfx8BitFont *)font)->getHasEncoding()
@@ -2341,50 +2256,21 @@ GooString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) {
     }
     delete ffTT;
   }
-  gfree(fontBuf);
 
   // ending comment
   writePS("%%EndResource\n");
-  return psName;
 }
 
-GooString *PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GooString *fileName, int faceIndex) {
+void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font,
+					       GooString *fileName,
+					       GooString *psName,
+					       GBool needVerticalMetrics) {
   FoFiTrueType *ffTT;
   int *codeToGID;
-  GooString *psName;
-  int i;
-  GooString *myFileName;
-
-  myFileName = fileName->copy();
-  if (faceIndex > 0) {
-    char tmp[32];
-    sprintf(tmp, ",%d", faceIndex);
-    myFileName->append(tmp);
-  }
-  // check if font is already embedded
-  for (i = 0; i < fontFileNameLen; ++i) {
-    if (!fontFileNames[i]->cmp(myFileName)) {
-      delete myFileName;
-      return psFileNames[i]->copy();
-    }
-  }
-
-  psName = font->getName()->sanitizedName(gTrue /* ps mode */);
-  // add entry to fontFileNames list
-  if (i == fontFileNameLen) {
-    if (fontFileNameLen >= fontFileNameSize) {
-      fontFileNameSize += 64;
-      fontFileNames =
-	(GooString **)grealloc(fontFileNames,
-			     fontFileNameSize * sizeof(GooString *));
-      psFileNames =
-	(GooString **)grealloc(psFileNames,
-			     fontFileNameSize * sizeof(GooString *));
-    }
-  }
-  fontFileNames[fontFileNameLen] = myFileName;
-  psFileNames[fontFileNameLen] = psName->copy();
-  fontFileNameLen++;
+  int codeToGIDLen;
+  CharCodeToUnicode *ctu;
+  Unicode *uBuf;
+  int cmap, code;
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2392,33 +2278,66 @@ GooString *PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GooString *f
   embFontList->append(psName->getCString());
   embFontList->append("\n");
 
-  // convert it to a CID type2 font
-  if ((ffTT = FoFiTrueType::load(fileName->getCString(), faceIndex))) {
-      int n = ((GfxCIDFont *)font)->getCIDToGIDLen();
-      if (n) {
-	codeToGID = (int *)gmallocn(n, sizeof(int));
-	memcpy(codeToGID, ((GfxCIDFont *)font)->getCIDToGID(), n * sizeof(int));
-      } else {
-	codeToGID = ((GfxCIDFont *)font)->getCodeToGIDMap(ffTT, &n);
-      }
-      if (globalParams->getPSLevel() >= psLevel3) {
-	// Level 3: use a CID font
-	ffTT->convertToCIDType2(psName->getCString(),
-				codeToGID, n, gTrue,
-				outputFunc, outputStream);
+  // convert it to a Type 0 font
+  //~ this should use fontNum to load the correct font
+  if ((ffTT = FoFiTrueType::load(fileName->getCString()))) {
+
+    // check for embedding permission
+    if (ffTT->getEmbeddingRights() >= 1) {
+
+      // create a CID-to-GID mapping, via Unicode
+      if ((ctu = ((GfxCIDFont *)font)->getToUnicode())) {
+	// look for a Unicode cmap
+	for (cmap = 0; cmap < ffTT->getNumCmaps(); ++cmap) {
+	  if ((ffTT->getCmapPlatform(cmap) == 3 &&
+	       ffTT->getCmapEncoding(cmap) == 1) ||
+	      ffTT->getCmapPlatform(cmap) == 0) {
+	    break;
+	  }
+	}
+	if (cmap < ffTT->getNumCmaps()) {
+	  // map CID -> Unicode -> GID
+	  codeToGIDLen = ctu->getLength();
+	  codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int));
+	  for (code = 0; code < codeToGIDLen; ++code) {
+	    if (ctu->mapToUnicode(code, &uBuf) > 0) {
+	      codeToGID[code] = ffTT->mapCodeToGID(cmap, uBuf[0]);
+	    } else {
+	      codeToGID[code] = 0;
+	    }
+	  }
+	  if (globalParams->getPSLevel() >= psLevel3) {
+	    // Level 3: use a CID font
+	    ffTT->convertToCIDType2(psName->getCString(),
+				    codeToGID, codeToGIDLen,
+				    needVerticalMetrics,
+				    outputFunc, outputStream);
+	  } else {
+	    // otherwise: use a non-CID composite font
+	    ffTT->convertToType0(psName->getCString(),
+				 codeToGID, codeToGIDLen,
+				 needVerticalMetrics,
+				 outputFunc, outputStream);
+	  }
+	  gfree(codeToGID);
+	}
+	ctu->decRefCnt();
       } else {
-	// otherwise: use a non-CID composite font
-	ffTT->convertToType0(psName->getCString(),
-			     codeToGID, n, gTrue,
-			     outputFunc, outputStream);
+	error(errSyntaxError, -1,
+	      "Couldn't find a mapping to Unicode for font '{0:s}'",
+	      font->getName() ? font->getName()->getCString() : "(unnamed)");
       }
-      gfree(codeToGID);
-      delete ffTT;
+    } else {
+      error(errSyntaxError, -1,
+	    "TrueType font '%s' does not allow embedding",
+	    font->getName() ? font->getName()->getCString() : "(unnamed)");
+	    
+    }
+    delete ffTT;
   }
 
   // ending comment
   writePS("%%EndResource\n");
-  return psName;
 }
 
 void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
@@ -2670,6 +2589,41 @@ void PSOutputDev::setupType3Font(GfxFont *font, GooString *psName,
   writePS("%%EndResource\n");
 }
 
+// Make a unique PS font name, based on the names given in the PDF
+// font object, and an object ID (font file object for 
+GooString *PSOutputDev::makePSFontName(GfxFont *font, Ref *id) {
+  GooString *psName, *s;
+
+  if ((s = font->getEmbeddedFontName())) {
+    psName = filterPSName(s);
+    if (!fontNames->lookupInt(psName)) {
+      fontNames->add(psName->copy(), 1);
+      return psName;
+    }
+    delete psName;
+  }
+  if ((s = font->getName())) {
+    psName = filterPSName(s);
+    if (!fontNames->lookupInt(psName)) {
+      fontNames->add(psName->copy(), 1);
+      return psName;
+    }
+    delete psName;
+  }
+  psName = GooString::format("FF{0:d}_{1:d}", id->num, id->gen);
+  if ((s = font->getEmbeddedFontName())) {
+    s = filterPSName(s);
+    psName->append('_')->append(s);
+    delete s;
+  } else if ((s = font->getName())) {
+    s = filterPSName(s);
+    psName->append('_')->append(s);
+    delete s;
+  }
+  fontNames->add(psName->copy(), 1);
+  return psName;
+}
+
 void PSOutputDev::setupImages(Dict *resDict) {
   Object xObjDict, xObj, xObjRef, subtypeObj;
   int i;
@@ -6909,6 +6863,37 @@ void PSOutputDev::writePSName(const char *s) {
   }
 }
 
+GooString *PSOutputDev::filterPSName(GooString *name) {
+  GooString *name2;
+  char buf[8];
+  int i;
+  char c;
+
+  name2 = new GooString();
+
+  // ghostscript chokes on names that begin with out-of-limits
+  // numbers, e.g., 1e4foo is handled correctly (as a name), but
+  // 1e999foo generates a limitcheck error
+  c = name->getChar(0);
+  if (c >= '0' && c <= '9') {
+    name2->append('f');
+  }
+
+  for (i = 0; i < name->getLength(); ++i) {
+    c = name->getChar(i);
+    if (c <= (char)0x20 || c >= (char)0x7f ||
+	c == '(' || c == ')' || c == '<' || c == '>' ||
+	c == '[' || c == ']' || c == '{' || c == '}' ||
+	c == '/' || c == '%') {
+      sprintf(buf, "#%02x", c & 0xff);
+      name2->append(buf);
+    } else {
+      name2->append(c);
+    }
+  }
+  return name2;
+}
+
 // Convert GooString to GooString, with appropriate escaping
 // of things that can't appear in a label
 // This is heavily based on the writePSTextLine() method
diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h
index 69725d4..4666c06 100644
--- a/poppler/PSOutputDev.h
+++ b/poppler/PSOutputDev.h
@@ -297,13 +297,18 @@ private:
   void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GooString *psName);
   void setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GooString *psName);
   void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GooString *psName);
-  GooString *setupExternalTrueTypeFont(GfxFont *font);
+  void setupExternalTrueTypeFont(GfxFont *font, GooString *fileName,
+				 GooString *psName);
   void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GooString *psName);
   void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GooString *psName,
 				    GBool needVerticalMetrics);
+  void setupExternalCIDTrueTypeFont(GfxFont *font,
+				    GooString *fileName,
+				    GooString *psName,
+				    GBool needVerticalMetrics);
   void setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GooString *psName);
-  GooString *setupExternalCIDTrueTypeFont(GfxFont *font, GooString *fileName, int faceIndex = 0);
   void setupType3Font(GfxFont *font, GooString *psName, Dict *parentResDict);
+  GooString *makePSFontName(GfxFont *font, Ref *id);
   void setupImages(Dict *resDict);
   void setupImage(Ref id, Stream *str);
   void setupForms(Dict *resDict);
@@ -353,6 +358,7 @@ private:
 		    double *x1, double *y1);
 #endif
   void cvtFunction(Function *func);
+  GooString *filterPSName(GooString *name);
 
   // Write the document-level setup.
   void writeDocSetup(PDFDoc *doc, Catalog *catalog, int firstPage, int lastPage, GBool duplexA);
@@ -376,7 +382,6 @@ private:
                                 // (only psModePSOrigPageSizes output mode)
   int imgLLX, imgLLY,		// imageable area, in pts
       imgURX, imgURY;
-  GBool substFonts;		// substitute missing fonts
   GBool preload;		// load all images into memory, and
 				//   predefine forms
 
@@ -396,6 +401,7 @@ private:
   Ref *fontIDs;			// list of object IDs of all used fonts
   int fontIDLen;		// number of entries in fontIDs array
   int fontIDSize;		// size of fontIDs array
+  GooHash *fontNames;		// all used font names
   Ref *fontFileIDs;		// list of object IDs of all embedded fonts
   int fontFileIDLen;		// number of entries in fontFileIDs array
   int fontFileIDSize;		// size of fontFileIDs array
diff --git a/poppler/PreScanOutputDev.cc b/poppler/PreScanOutputDev.cc
index 7be6abb..d77bb5a 100644
--- a/poppler/PreScanOutputDev.cc
+++ b/poppler/PreScanOutputDev.cc
@@ -108,8 +108,6 @@ void PreScanOutputDev::beginStringOp(GfxState *state) {
   int render;
   GfxFont *font;
   double m11, m12, m21, m22;
-  Ref embRef;
-  DisplayFontParam *dfp;
   GBool simpleTTF;
 
   render = state->getRender();
@@ -124,18 +122,14 @@ void PreScanOutputDev::beginStringOp(GfxState *state) {
 
   font = state->getFont();
   state->getFontTransMat(&m11, &m12, &m21, &m22);
+  //~ this should check for external fonts that are non-TrueType
   simpleTTF = fabs(m11 + m22) < 0.01 &&
               m11 > 0 &&
               fabs(m12) < 0.01 &&
               fabs(m21) < 0.01 &&
               fabs(state->getHorizScaling() - 1) < 0.001 &&
               (font->getType() == fontTrueType ||
-	       font->getType() == fontTrueTypeOT) &&
-              (font->getEmbeddedFontID(&embRef) ||
-	       font->getExtFontFile() ||
-	       (font->getName() &&
-		(dfp = globalParams->getDisplayFont(font)) &&
-		dfp->kind == displayFontTT));
+	       font->getType() == fontTrueTypeOT);
   if (simpleTTF) {
     //~ need to create a FoFiTrueType object, and check for a Unicode cmap
   }
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index fe99fd4..825c7ad 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -837,7 +837,10 @@ static void setSat(Guchar rIn, Guchar gIn, Guchar bIn, int sat,
 
 static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest,
 			      SplashColorPtr blend, SplashColorMode cm) {
-  Guchar r0, g0, b0, r1, g1, b1;
+  Guchar r0, g0, b0;
+#ifdef SPLASH_CMYK
+  Guchar r1, g1, b1;
+#endif
 
   switch (cm) {
   case splashModeMono1:
@@ -872,7 +875,10 @@ static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest,
 static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest,
 				     SplashColorPtr blend,
 				     SplashColorMode cm) {
-  Guchar r0, g0, b0, r1, g1, b1;
+  Guchar r0, g0, b0;
+#ifdef SPLASH_CMYK
+  Guchar r1, g1, b1;
+#endif
 
   switch (cm) {
   case splashModeMono1:
@@ -1660,18 +1666,17 @@ void SplashOutputDev::updateFont(GfxState * /*state*/) {
 
 void SplashOutputDev::doUpdateFont(GfxState *state) {
   GfxFont *gfxFont;
+  GfxFontLoc *fontLoc;
   GfxFontType fontType;
   SplashOutFontFileID *id;
   SplashFontFile *fontFile;
   SplashFontSrc *fontsrc = NULL;
   FoFiTrueType *ff;
-  Ref embRef;
   Object refObj, strObj;
   GooString *fileName;
   char *tmpBuf;
   int tmpBufLen;
   int *codeToGID;
-  DisplayFontParam *dfp;
   double *textMat;
   double m11, m12, m21, m22, fontSize;
   int faceIndex = 0;
@@ -1684,7 +1689,7 @@ void SplashOutputDev::doUpdateFont(GfxState *state) {
   font = NULL;
   fileName = NULL;
   tmpBuf = NULL;
-  dfp = NULL;
+  fontLoc = NULL;
 
   if (!(gfxFont = state->getFont())) {
     goto err1;
@@ -1708,37 +1713,24 @@ void SplashOutputDev::doUpdateFont(GfxState *state) {
 
   } else {
 
-    // if there is an embedded font, write it to disk
-    if (gfxFont->getEmbeddedFontID(&embRef)) {
+    if (!(fontLoc = gfxFont->locateFont(doc->getXRef(), gFalse))) {
+      error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
+	    gfxFont->getName() ? gfxFont->getName()->getCString()
+	                       : "(unnamed)");
+      goto err2;
+    }
+
+    // embedded font
+    if (fontLoc->locType == gfxFontLocEmbedded) {
+      // if there is an embedded font, read it to memory
       tmpBuf = gfxFont->readEmbFontFile(doc->getXRef(), &tmpBufLen);
       if (! tmpBuf)
 	goto err2;
 
-    // if there is an external font file, use it
-    } else if (!(fileName = gfxFont->getExtFontFile())) {
-
-      // look for a display font mapping or a substitute font
-      dfp = NULL;
-      if (gfxFont->getName()) {
-        dfp = globalParams->getDisplayFont(gfxFont);
-      }
-      if (!dfp) {
-	error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
-	      gfxFont->getName() ? gfxFont->getName()->getCString()
-	                         : "(unnamed)");
-	goto err2;
-      }
-      switch (dfp->kind) {
-      case displayFontT1:
-	fileName = dfp->t1.fileName;
-	fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
-	break;
-      case displayFontTT:
-	fileName = dfp->tt.fileName;
-	fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
-	faceIndex = dfp->tt.faceIndex;
-	break;
-      }
+    // external font
+    } else { // gfxFontLocExternal
+      fileName = fontLoc->path;
+      fontType = fontLoc->fontType;
       doAdjustFontMatrix = gTrue;
     }
 
@@ -1940,12 +1932,14 @@ void SplashOutputDev::doUpdateFont(GfxState *state) {
     font = fontEngine->getFont(fontFile, mat, splash->getMatrix());
   }
 
+  delete fontLoc;
   if (fontsrc && !fontsrc->isFile)
       fontsrc->unref();
   return;
 
  err2:
   delete id;
+  delete fontLoc;
  err1:
   if (fontsrc && !fontsrc->isFile)
       fontsrc->unref();
@@ -2959,7 +2953,6 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
 #if SPLASH_CMYK
   GfxCMYK cmyk;
 #endif
-  GBool grayIndexed = gFalse;
   Guchar pix;
   int n, i;
 
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index bacd540..c455d6a 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -826,25 +826,25 @@ GBool XRef::constructXRef(GBool *wasReconstructed) {
         delete parser;
 
       // look for object
-      } else if (isdigit(*p)) {
+      } else if (*p > 0 && isdigit(*p)) {
         num = atoi(p);
         if (num > 0) {
 	  do {
 	    ++p;
-	  } while (*p && isdigit(*p));
-	  if (isspace(*p)) {
+	  } while (*p > 0 && isdigit(*p));
+	  if (*p > 0 && isspace(*p)) {
 	    do {
 	      ++p;
-	    } while (*p && isspace(*p));
-	    if (isdigit(*p)) {
+	    } while (*p > 0 && isspace(*p));
+	    if (*p > 0 && isdigit(*p)) {
 	      gen = atoi(p);
 	      do {
 	        ++p;
-	      } while (*p && isdigit(*p));
-	      if (isspace(*p)) {
+	      } while (*p > 0 && isdigit(*p));
+	      if (*p > 0 && isspace(*p)) {
 	        do {
 		  ++p;
-	        } while (*p && isspace(*p));
+	        } while (*p > 0 && isspace(*p));
 	        if (!strncmp(p, "obj", 3)) {
 		  if (num >= size) {
 		    newSize = (num + 1 + 255) & ~255;


More information about the poppler mailing list