]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/XOutputDev.cc
Reused eog HIG dialog in GPdf.
[evince.git] / pdf / xpdf / XOutputDev.cc
index 6f207d8e45e0fe976c16bbb384bf1fef68fe709d..2100355af0338a8194e38861452d41f8dffe1e7a 100644 (file)
@@ -2,15 +2,16 @@
 //
 // XOutputDev.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
 #pragma implementation
 #endif
 
-#include <aconf.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
@@ -95,6 +96,12 @@ static XOutFontSubst xOutSubstFonts[16] = {
   {"Symbol",                0.576}
 };
 
+//------------------------------------------------------------------------
+
+static void outputToFile(void *stream, char *data, int len) {
+  fwrite(data, 1, len, (FILE *)stream);
+}
+
 //------------------------------------------------------------------------
 // XOutputFont
 //------------------------------------------------------------------------
@@ -581,18 +588,30 @@ void XOutputServer16BitFont::drawChar(GfxState *state, Pixmap pixmap,
 #if HAVE_T1LIB_H
 XOutputT1FontFile::~XOutputT1FontFile() {
   delete fontFile;
+  if (tmpFileName) {
+    unlink(tmpFileName->getCString());
+    delete tmpFileName;
+  }
 }
 #endif
 
 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
 XOutputFTFontFile::~XOutputFTFontFile() {
   delete fontFile;
+  if (tmpFileName) {
+    unlink(tmpFileName->getCString());
+    delete tmpFileName;
+  }
 }
 #endif
 
 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
 XOutputTTFontFile::~XOutputTTFontFile() {
   delete fontFile;
+  if (tmpFileName) {
+    unlink(tmpFileName->getCString());
+    delete tmpFileName;
+  }
 }
 #endif
 
@@ -626,8 +645,8 @@ XOutputFontCache::~XOutputFontCache() {
   delFonts();
 }
 
-void XOutputFontCache::startDoc(int screenNum, Colormap colormap,
-                               GBool trueColor,
+void XOutputFontCache::startDoc(int screenNum, Visual *visual,
+                               Colormap colormap, GBool trueColor,
                                int rMul, int gMul, int bMul,
                                int rShift, int gShift, int bShift,
                                Gulong *colors, int numColors) {
@@ -636,8 +655,7 @@ void XOutputFontCache::startDoc(int screenNum, Colormap colormap,
 
 #if HAVE_T1LIB_H
   if (t1libControl != fontRastNone) {
-    t1Engine = new T1FontEngine(display, DefaultVisual(display, screenNum),
-                               depth, colormap,
+    t1Engine = new T1FontEngine(display, visual, depth, colormap,
                                t1libControl == fontRastAALow ||
                                  t1libControl == fontRastAAHigh,
                                t1libControl == fontRastAAHigh);
@@ -656,8 +674,7 @@ void XOutputFontCache::startDoc(int screenNum, Colormap colormap,
 
 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
   if (freetypeControl != fontRastNone) {
-    ftEngine = new FTFontEngine(display, DefaultVisual(display, screenNum),
-                               depth, colormap,
+    ftEngine = new FTFontEngine(display, visual, depth, colormap,
                                freetypeControl == fontRastAALow ||
                                  freetypeControl == fontRastAAHigh);
     if (ftEngine->isOk()) {
@@ -675,8 +692,7 @@ void XOutputFontCache::startDoc(int screenNum, Colormap colormap,
 
 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
   if (freetypeControl != fontRastNone) {
-    ttEngine = new TTFontEngine(display, DefaultVisual(display, screenNum),
-                               depth, colormap,
+    ttEngine = new TTFontEngine(display, visual, depth, colormap,
                                freetypeControl == fontRastAALow ||
                                  freetypeControl == fontRastAAHigh);
     if (ttEngine->isOk()) {
@@ -812,6 +828,7 @@ XOutputFont *XOutputFontCache::getFont(XRef *xref, GfxFont *gfxFont,
     }
 #endif
     break;
+  case fontCIDType0:
   case fontCIDType0C:
 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
     if (freetypeControl != fontRastNone) {
@@ -977,8 +994,8 @@ XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp,
 
   case displayFontT1:
 #if HAVE_T1LIB_H
-    if (t1libControl != fontRastNone) {
-      font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gfxFont,
+    if (t1libControl != fontRastNone && !gfxFont->isCIDFont()) {
+      font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
                                  m11Orig, m12Orig, m21Orig, m22Orig,
                                  m11, m12, m21, m22, subst);
     }
@@ -986,9 +1003,9 @@ XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp,
 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
     if (!font) {
       if (freetypeControl != fontRastNone) {
-       font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gfxFont,
+       font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
                                    m11Orig, m12Orig, m21Orig, m22Orig,
-                                   m11, m12, m21, m22, subst);
+                                   m11, m12, m21, m22, gFalse, subst);
       }
     }
 #endif
@@ -1001,14 +1018,14 @@ XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp,
   case displayFontTT:
 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
     if (freetypeControl != fontRastNone) {
-      font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gfxFont,
+      font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
                                  m11Orig, m12Orig, m21Orig, m22Orig,
-                                 m11, m12, m21, m22, subst);
+                                 m11, m12, m21, m22, gFalse, subst);
     }
 #endif
 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
     if (freetypeControl != fontRastNone) {
-      font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gfxFont,
+      font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
                                  m11Orig, m12Orig, m21Orig, m22Orig,
                                  m11, m12, m21, m22, subst);
     }
@@ -1074,7 +1091,12 @@ XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref,
        return NULL;
       }
       ff = new Type1CFontFile(fontBuf, fontLen);
-      ff->convertToType1(f);
+      if (!ff->isOk()) {
+       delete ff;
+       gfree(fontBuf);
+       return NULL;
+      }
+      ff->convertToType1(outputToFile, f);
       delete ff;
       gfree(fontBuf);
     } else { // fontType1
@@ -1091,17 +1113,19 @@ XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref,
     fclose(f);
 
     // create the Font
-    font = tryGetT1FontFromFile(xref, fileName, gfxFont,
+    font = tryGetT1FontFromFile(xref, fileName, gTrue, gfxFont,
                                m11, m12, m21, m22,
                                m11, m12, m21, m22, gFalse);
 
-    // remove the temporary file
+    // on systems with Unix hard link semantics, this will remove the
+    // last link to the temp file
     unlink(fileName->getCString());
+
     delete fileName;
 
   // check for an external font file
   } else if ((fileName = gfxFont->getExtFontFile())) {
-    font = tryGetT1FontFromFile(xref, fileName, gfxFont,
+    font = tryGetT1FontFromFile(xref, fileName, gFalse, gfxFont,
                                m11, m12, m21, m22,
                                m11, m12, m21, m22, gFalse);
 
@@ -1114,6 +1138,7 @@ XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref,
 
 XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref,
                                                    GString *fileName,
+                                                   GBool deleteFile,
                                                    GfxFont *gfxFont,
                                                    double m11Orig,
                                                    double m12Orig,
@@ -1134,13 +1159,18 @@ XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref,
     error(-1, "Couldn't create t1lib font from '%s'",
          fileName->getCString());
     delete fontFile;
+    if (deleteFile) {
+      unlink(fileName->getCString());
+    }
     return NULL;
   }
 
   // add to list
   id = gfxFont->getID();
   t1FontFiles->append(new XOutputT1FontFile(id->num, id->gen,
-                                           subst, fontFile));
+                                           subst, fontFile,
+                                           deleteFile ? fileName->copy()
+                                                      : (GString *)NULL));
 
   // create the Font
   font = new XOutputT1Font(gfxFont->getID(), fontFile,
@@ -1236,19 +1266,21 @@ XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref,
     fclose(f);
 
     // create the Font
-    font = tryGetFTFontFromFile(xref, fileName, gfxFont,
+    font = tryGetFTFontFromFile(xref, fileName, gTrue, gfxFont,
                                m11, m12, m21, m22,
-                               m11, m12, m21, m22, gFalse);
+                               m11, m12, m21, m22, gTrue, gFalse);
 
-    // remove the temporary file
+    // on systems with Unix hard link semantics, this will remove the
+    // last link to the temp file
     unlink(fileName->getCString());
+
     delete fileName;
 
   // check for an external font file
   } else if ((fileName = gfxFont->getExtFontFile())) {
-    font = tryGetFTFontFromFile(xref, fileName, gfxFont,
+    font = tryGetFTFontFromFile(xref, fileName, gFalse, gfxFont,
                                m11, m12, m21, m22,
-                               m11, m12, m21, m22, gFalse);
+                               m11, m12, m21, m22, gFalse, gFalse);
 
   } else {
     font = NULL;
@@ -1259,6 +1291,7 @@ XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref,
 
 XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
                                                    GString *fileName,
+                                                   GBool deleteFile,
                                                    GfxFont *gfxFont,
                                                    double m11Orig,
                                                    double m12Orig,
@@ -1266,6 +1299,7 @@ XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
                                                    double m22Orig,
                                                    double m11, double m12,
                                                    double m21, double m22,
+                                                   GBool embedded,
                                                    GBool subst) {
   Ref *id;
   FTFontFile *fontFile;
@@ -1276,26 +1310,33 @@ XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
     if (gfxFont->getType() == fontCIDType2) {
       fontFile = new FTFontFile(ftEngine, fileName->getCString(),
                                ((GfxCIDFont *)gfxFont)->getCIDToGID(),
-                               ((GfxCIDFont *)gfxFont)->getCIDToGIDLen());
-    } else { // fontCIDType0C
-      fontFile = new FTFontFile(ftEngine, fileName->getCString());
+                               ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(),
+                               embedded);
+    } else { // fontCIDType0, fontCIDType0C
+      fontFile = new FTFontFile(ftEngine, fileName->getCString(), embedded);
     }
   } else {
     fontFile = new FTFontFile(ftEngine, fileName->getCString(),
                              ((Gfx8BitFont *)gfxFont)->getEncoding(),
-                             ((Gfx8BitFont *)gfxFont)->getHasEncoding());
+                             ((Gfx8BitFont *)gfxFont)->getHasEncoding(),
+                             ((Gfx8BitFont *)gfxFont)->isSymbolic());
   }
   if (!fontFile->isOk()) {
     error(-1, "Couldn't create FreeType font from '%s'",
          fileName->getCString());
     delete fontFile;
+    if (deleteFile) {
+      unlink(fileName->getCString());
+    }
     return NULL;
   }
 
   // add to list
   id = gfxFont->getID();
   ftFontFiles->append(new XOutputFTFontFile(id->num, id->gen,
-                                           subst, fontFile));
+                                           subst, fontFile,
+                                           deleteFile ? fileName->copy()
+                                                      : (GString *)NULL));
 
   // create the Font
   font = new XOutputFTFont(gfxFont->getID(), fontFile,
@@ -1363,16 +1404,18 @@ XOutputFont *XOutputFontCache::tryGetTTFont(XRef *xref,
     fclose(f);
 
     // create the Font
-    font = tryGetTTFontFromFile(xref, fileName, gfxFont,
+    font = tryGetTTFontFromFile(xref, fileName, gTrue, gfxFont,
                                m11, m12, m21, m22,
                                m11, m12, m21, m22, gFalse);
 
-    // remove the temporary file
+    // on systems with Unix hard link semantics, this will remove the
+    // last link to the temp file
     unlink(fileName->getCString());
+
     delete fileName;
 
   } else if ((fileName = gfxFont->getExtFontFile())) {
-    font = tryGetTTFontFromFile(xref, fileName, gfxFont,
+    font = tryGetTTFontFromFile(xref, fileName, gFalse, gfxFont,
                                m11, m12, m21, m22,
                                m11, m12, m21, m22, gFalse);
 
@@ -1385,6 +1428,7 @@ XOutputFont *XOutputFontCache::tryGetTTFont(XRef *xref,
 
 XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref,
                                                    GString *fileName,
+                                                   GBool deleteFile,
                                                    GfxFont *gfxFont,
                                                    double m11Orig,
                                                    double m12Orig,
@@ -1412,13 +1456,18 @@ XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref,
     error(-1, "Couldn't create FreeType font from '%s'",
          fileName->getCString());
     delete fontFile;
+    if (deleteFile) {
+      unlink(fileName->getCString());
+    }
     return NULL;
   }
 
   // add to list
   id = gfxFont->getID();
   ttFontFiles->append(new XOutputTTFontFile(id->num, id->gen,
-                                           subst, fontFile));
+                                           subst, fontFile,
+                                           deleteFile ? fileName->copy()
+                                                      : (GString *)NULL));
 
   // create the Font
   font = new XOutputTTFont(gfxFont->getID(), fontFile,
@@ -1570,6 +1619,7 @@ struct T3GlyphStack {
   GC origStrokeGC;
   GC origFillGC;
   Region origClipRegion;
+  double origCTM4, origCTM5;
   double wx, wy;               // untransformed glyph metrics
   T3GlyphStack *next;
 };
@@ -1578,53 +1628,63 @@ struct T3GlyphStack {
 // XOutputDev
 //------------------------------------------------------------------------
 
-XOutputDev::XOutputDev(Display *displayA, Pixmap pixmapA, Guint depthA,
-                      Colormap colormapA, GBool reverseVideoA,
-                      unsigned long paperColor, GBool installCmap,
-                      int rgbCubeSize) {
+XOutputDev::XOutputDev(Display *displayA, int screenNumA,
+                      Visual *visualA, Colormap colormapA,
+                      GBool reverseVideoA, unsigned long paperColorA,
+                      GBool installCmap, int rgbCubeSize,
+                      int forceDepth) {
   XVisualInfo visualTempl;
   XVisualInfo *visualList;
   int nVisuals;
   Gulong mask;
-  XGCValues gcValues;
   XColor xcolor;
   XColor *xcolors;
-  int r, g, b, n, m, i;
+  int r, g, b, n, m;
   GBool ok;
 
+  // no document yet
   xref = NULL;
 
-  // get display/pixmap info
+  // display / screen / visual / colormap
   display = displayA;
-  screenNum = DefaultScreen(display);
-  pixmap = pixmapA;
-  depth = depthA;
+  screenNum = screenNumA;
+  visual = visualA;
   colormap = colormapA;
 
+  // no pixmap yet
+  pixmapW = pixmapH = 0;
+
   // check for TrueColor visual
-  trueColor = gFalse;
-  if (depth == 0) {
-    depth = DefaultDepth(display, screenNum);
-    visualList = XGetVisualInfo(display, 0, &visualTempl, &nVisuals);
-    for (i = 0; i < nVisuals; ++i) {
-      if (visualList[i].visual == DefaultVisual(display, screenNum)) {
-       if (visualList[i].c_class == TrueColor) {
-         trueColor = gTrue;
-         for (mask = visualList[i].red_mask, rShift = 0;
-              mask && !(mask & 1);
-              mask >>= 1, ++rShift) ;
-         rMul = (int)mask;
-         for (mask = visualList[i].green_mask, gShift = 0;
-              mask && !(mask & 1);
-              mask >>= 1, ++gShift) ;
-         gMul = (int)mask;
-         for (mask = visualList[i].blue_mask, bShift = 0;
-              mask && !(mask & 1);
-              mask >>= 1, ++bShift) ;
-         bMul = (int)mask;
-       }
-       break;
-      }
+  if (forceDepth != 0) {
+    depth = forceDepth;
+    trueColor = depth >= 16;
+  } else {
+    visualTempl.visualid = XVisualIDFromVisual(visual);
+    visualList = XGetVisualInfo(display, VisualIDMask,
+                               &visualTempl, &nVisuals);
+    if (nVisuals < 1) {
+      // this shouldn't happen
+      XFree((XPointer)visualList);
+      visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl,
+                                 &nVisuals);
+    }
+    depth = visualList->depth;
+    if (visualList->c_class == TrueColor) {
+      trueColor = gTrue;
+      for (mask = visualList->red_mask, rShift = 0;
+          mask && !(mask & 1);
+          mask >>= 1, ++rShift) ;
+      rMul = (int)mask;
+      for (mask = visualList->green_mask, gShift = 0;
+          mask && !(mask & 1);
+          mask >>= 1, ++gShift) ;
+      gMul = (int)mask;
+      for (mask = visualList->blue_mask, bShift = 0;
+          mask && !(mask & 1);
+          mask >>= 1, ++bShift) ;
+      bMul = (int)mask;
+    } else {
+      trueColor = gFalse;
     }
     XFree((XPointer)visualList);
   }
@@ -1710,31 +1770,14 @@ XOutputDev::XOutputDev(Display *displayA, Pixmap pixmapA, Guint depthA,
     }
   }
 
-  // reverse video mode
+  // misc parameters
   reverseVideo = reverseVideoA;
-
-  // allocate GCs
-  gcValues.foreground = BlackPixel(display, screenNum);
-  gcValues.background = WhitePixel(display, screenNum);
-  gcValues.line_width = 0;
-  gcValues.line_style = LineSolid;
-  strokeGC = XCreateGC(display, pixmap,
-                      GCForeground | GCBackground | GCLineWidth | GCLineStyle,
-                       &gcValues);
-  fillGC = XCreateGC(display, pixmap,
-                    GCForeground | GCBackground | GCLineWidth | GCLineStyle,
-                    &gcValues);
-  gcValues.foreground = paperColor;
-  paperGC = XCreateGC(display, pixmap,
-                     GCForeground | GCBackground | GCLineWidth | GCLineStyle,
-                     &gcValues);
-
-  // no clip region yet
-  clipRegion = NULL;
+  paperColor = paperColorA;
 
   // set up the font cache and fonts
   gfxFont = NULL;
   font = NULL;
+  needFontUpdate = gFalse;
   fontCache = new XOutputFontCache(display, depth, this,
                                   globalParams->getT1libControl(),
                                   globalParams->getFreeTypeControl());
@@ -1755,12 +1798,6 @@ XOutputDev::~XOutputDev() {
   for (i = 0; i < nT3Fonts; ++i) {
     delete t3FontCache[i];
   }
-  XFreeGC(display, strokeGC);
-  XFreeGC(display, fillGC);
-  XFreeGC(display, paperGC);
-  if (clipRegion) {
-    XDestroyRegion(clipRegion);
-  }
   delete text;
 }
 
@@ -1768,7 +1805,7 @@ void XOutputDev::startDoc(XRef *xrefA) {
   int i;
 
   xref = xrefA;
-  fontCache->startDoc(screenNum, colormap, trueColor, rMul, gMul, bMul,
+  fontCache->startDoc(screenNum, visual, colormap, trueColor, rMul, gMul, bMul,
                      rShift, gShift, bShift, colors, numColors);
   for (i = 0; i < nT3Fonts; ++i) {
     delete t3FontCache[i];
@@ -1777,39 +1814,29 @@ void XOutputDev::startDoc(XRef *xrefA) {
 }
 
 void XOutputDev::startPage(int pageNum, GfxState *state) {
-  XOutputState *s;
   XGCValues gcValues;
   XRectangle rect;
 
-  // clear state stack
-  while (save) {
-    s = save;
-    save = save->next;
-    XFreeGC(display, s->strokeGC);
-    XFreeGC(display, s->fillGC);
-    XDestroyRegion(s->clipRegion);
-    delete s;
-  }
-  save = NULL;
-
   // default line flatness
   flatness = 0;
 
-  // reset GCs
+  // allocate GCs
   gcValues.foreground = BlackPixel(display, screenNum);
   gcValues.background = WhitePixel(display, screenNum);
   gcValues.line_width = 0;
   gcValues.line_style = LineSolid;
-  XChangeGC(display, strokeGC,
-           GCForeground | GCBackground | GCLineWidth | GCLineStyle,
-           &gcValues);
-  XChangeGC(display, fillGC,
-           GCForeground | GCBackground | GCLineWidth | GCLineStyle,
-           &gcValues);
-
-  // clear clipping region
-  if (clipRegion)
-    XDestroyRegion(clipRegion);
+  strokeGC = XCreateGC(display, pixmap,
+                      GCForeground | GCBackground | GCLineWidth | GCLineStyle,
+                       &gcValues);
+  fillGC = XCreateGC(display, pixmap,
+                    GCForeground | GCBackground | GCLineWidth | GCLineStyle,
+                    &gcValues);
+  gcValues.foreground = paperColor;
+  paperGC = XCreateGC(display, pixmap,
+                     GCForeground | GCBackground | GCLineWidth | GCLineStyle,
+                     &gcValues);
+
+  // initialize clip region
   clipRegion = XCreateRegion();
   rect.x = rect.y = 0;
   rect.width = pixmapW;
@@ -1826,11 +1853,27 @@ void XOutputDev::startPage(int pageNum, GfxState *state) {
   XFillRectangle(display, pixmap, paperGC, 0, 0, pixmapW, pixmapH);
 
   // clear text object
-  text->clear();
+  text->startPage(state);
 }
 
 void XOutputDev::endPage() {
-  text->coalesce();
+  XOutputState *s;
+
+  text->coalesce(gTrue);
+
+  // clear state stack, free all GCs, free the clip region
+  while (save) {
+    s = save;
+    save = save->next;
+    XFreeGC(display, s->strokeGC);
+    XFreeGC(display, s->fillGC);
+    XDestroyRegion(s->clipRegion);
+    delete s;
+  }
+  XFreeGC(display, strokeGC);
+  XFreeGC(display, fillGC);
+  XFreeGC(display, paperGC);
+  XDestroyRegion(clipRegion);
 }
 
 void XOutputDev::drawLink(Link *link, Catalog *catalog) {
@@ -1909,6 +1952,9 @@ void XOutputDev::restoreState(GfxState *state) {
     s = save;
     save = save->next;
     delete s;
+
+    // we'll need to restore the font
+    needFontUpdate = gTrue;
   }
 }
 
@@ -1918,7 +1964,7 @@ void XOutputDev::updateAll(GfxState *state) {
   updateMiterLimit(state);
   updateFillColor(state);
   updateStrokeColor(state);
-  updateFont(state);
+  needFontUpdate = gTrue;
 }
 
 void XOutputDev::updateCTM(GfxState *state, double m11, double m12,
@@ -2026,6 +2072,10 @@ void XOutputDev::updateStrokeColor(GfxState *state) {
 void XOutputDev::updateFont(GfxState *state) {
   double m11, m12, m21, m22;
 
+  needFontUpdate = gFalse;
+
+  text->updateFont(state);
+
   if (!(gfxFont = state->getFont())) {
     font = NULL;
     return;
@@ -2042,8 +2092,6 @@ void XOutputDev::updateFont(GfxState *state) {
     font->updateGC(fillGC);
     font->updateGC(strokeGC);
   }
-
-  text->updateFont(state);
 }
 
 void XOutputDev::stroke(GfxState *state) {
@@ -2450,11 +2498,11 @@ void XOutputDev::addPoint(XPoint **points, int *size, int *k, int x, int y) {
 }
 
 void XOutputDev::beginString(GfxState *state, GString *s) {
-  text->beginString(state);
+  text->beginWord(state, state->getCurX(), state->getCurY());
 }
 
 void XOutputDev::endString(GfxState *state) {
-  text->endString();
+  text->endWord();
 }
 
 void XOutputDev::drawChar(GfxState *state, double x, double y,
@@ -2468,7 +2516,11 @@ void XOutputDev::drawChar(GfxState *state, double x, double y,
   double *ctm;
   double saveCTM[6];
 
-  text->addChar(state, x, y, dx, dy, u, uLen);
+  if (needFontUpdate) {
+    updateFont(state);
+  }
+
+  text->addChar(state, x, y, dx, dy, code, u, uLen);
 
   if (!font) {
     return;
@@ -2542,6 +2594,9 @@ GBool XOutputDev::beginType3Char(GfxState *state,
   double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
   int i, j;
 
+  if (needFontUpdate) {
+    updateFont(state);
+  }
   if (!gfxFont) {
     return gFalse;
   }
@@ -2625,9 +2680,7 @@ GBool XOutputDev::beginType3Char(GfxState *state,
                                       (int)floor(yMin - yt),
                                       (int)ceil(xMax) - (int)floor(xMin) + 3,
                                       (int)ceil(yMax) - (int)floor(yMin) + 3,
-                                      display,
-                                      DefaultVisual(display, screenNum),
-                                      depth, pixmap);
+                                      display, visual, depth, pixmap);
     }
   }
   t3Font = t3FontCache[0];
@@ -2645,7 +2698,7 @@ GBool XOutputDev::beginType3Char(GfxState *state,
       }
       text->addChar(state, 0, 0,
                    t3Font->cacheTags[i+j].wx, t3Font->cacheTags[i+j].wy,
-                   u, uLen);
+                   code, u, uLen);
       drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
                     t3Font->cacheData + (i+j) * t3Font->glyphSize,
                     xt, yt, &color);
@@ -2676,6 +2729,7 @@ void XOutputDev::endType3Char(GfxState *state) {
   Gulong pixel;
   double alpha;
   T3GlyphStack *t3gs;
+  double *ctm;
 
   if (t3GlyphStack->cacheable) {
     image = t3GlyphStack->cache->image;
@@ -2716,9 +2770,14 @@ void XOutputDev::endType3Char(GfxState *state) {
     drawType3Glyph(t3GlyphStack->cache,
                   t3GlyphStack->cacheTag, t3GlyphStack->cacheData,
                   t3GlyphStack->x, t3GlyphStack->y, &t3GlyphStack->color);
+    // the CTM must be restored here in order for TextPage::addChar to
+    // work correctly
+    ctm = state->getCTM();
+    state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
+                 t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
   }
   text->addChar(state, 0, 0, t3GlyphStack->wx, t3GlyphStack->wy,
-               t3GlyphStack->u, t3GlyphStack->uLen);
+               t3GlyphStack->code, t3GlyphStack->u, t3GlyphStack->uLen);
   t3gs = t3GlyphStack;
   t3GlyphStack = t3gs->next;
   delete t3gs;
@@ -2813,11 +2872,61 @@ void XOutputDev::type3D1(GfxState *state, double wx, double wy,
   XRectangle rect;
   double *ctm;
   T3FontCache *t3Font;
+  double xt, yt, xMin, xMax, yMin, yMax, x1, y1;
   int i, j;
 
+  t3Font = t3GlyphStack->cache;
+  t3GlyphStack->wx = wx;
+  t3GlyphStack->wy = wy;
+
+  // check for a valid bbox
+  state->transform(0, 0, &xt, &yt);
+  state->transform(llx, lly, &x1, &y1);
+  xMin = xMax = x1;
+  yMin = yMax = y1;
+  state->transform(llx, ury, &x1, &y1);
+  if (x1 < xMin) {
+    xMin = x1;
+  } else if (x1 > xMax) {
+    xMax = x1;
+  }
+  if (y1 < yMin) {
+    yMin = y1;
+  } else if (y1 > yMax) {
+    yMax = y1;
+  }
+  state->transform(urx, lly, &x1, &y1);
+  if (x1 < xMin) {
+    xMin = x1;
+  } else if (x1 > xMax) {
+    xMax = x1;
+  }
+  if (y1 < yMin) {
+    yMin = y1;
+  } else if (y1 > yMax) {
+    yMax = y1;
+  }
+  state->transform(urx, ury, &x1, &y1);
+  if (x1 < xMin) {
+    xMin = x1;
+  } else if (x1 > xMax) {
+    xMax = x1;
+  }
+  if (y1 < yMin) {
+    yMin = y1;
+  } else if (y1 > yMax) {
+    yMax = y1;
+  }
+  if (xMin - xt < t3Font->glyphX ||
+      yMin - yt < t3Font->glyphY ||
+      xMax - xt > t3Font->glyphX + t3Font->glyphW ||
+      yMax - yt > t3Font->glyphY + t3Font->glyphH) {
+    error(-1, "Bad bounding box in Type 3 glyph");
+    return;
+  }
+
   // allocate a cache entry
   t3GlyphStack->cacheable = gTrue;
-  t3Font = t3GlyphStack->cache;
   i = t3GlyphStack->cacheIdx;
   for (j = 0; j < t3Font->cacheAssoc; ++j) {
     if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) {
@@ -2829,8 +2938,6 @@ void XOutputDev::type3D1(GfxState *state, double wx, double wy,
       ++t3Font->cacheTags[i+j].mru;
     }
   }
-  t3GlyphStack->wx = wx;
-  t3GlyphStack->wy = wy;
   t3GlyphStack->cacheTag->wx = wx;
   t3GlyphStack->cacheTag->wy = wy;
 
@@ -2878,6 +2985,8 @@ void XOutputDev::type3D1(GfxState *state, double wx, double wy,
   XSetRegion(display, strokeGC, clipRegion);
   XSetRegion(display, fillGC, clipRegion);
   ctm = state->getCTM();
+  t3GlyphStack->origCTM4 = ctm[4];
+  t3GlyphStack->origCTM5 = ctm[5];
   state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], 
                -t3GlyphStack->cache->glyphX, -t3GlyphStack->cache->glyphY);
 }
@@ -3118,8 +3227,7 @@ void XOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
   pixBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
 
   // allocate XImage and read from page pixmap
-  image = XCreateImage(display, DefaultVisual(display, screenNum),
-                      depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
+  image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
   image->data = (char *)gmalloc(bh * image->bytes_per_line);
   XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap,
               image, cx1, cy1);
@@ -3167,13 +3275,13 @@ void XOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
     if (n > 0) {
       p = pixBuf;
       for (i = 0; i < n; ++i) {
-       for (j = 0; j < width; ++j) {
-         imgStr->getPixel(p);
-         if (invert) {
-           *p ^= 1;
+       memcpy(p, imgStr->getLine(), width);
+       if (invert) {
+         for (j = 0; j < width; ++j) {
+           p[j] ^= 1;
          }
-         ++p;
        }
+       p += width;
       }
     }
     lastYStep = yStep;
@@ -3279,7 +3387,7 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   double r0, g0, b0, alpha, mul;
   Gulong pix;
   GfxRGB *p;
-  Guchar *q;
+  Guchar *q, *p2;
   GBool oneBitMode;
   GfxRGB oneBitRGB[2];
   int x, y, x1, y1, x2, y2;
@@ -3321,6 +3429,14 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   }
   tx = xoutRound(ctm[2] + ctm[4]);
   ty = xoutRound(ctm[3] + ctm[5]);
+  if (xScale < 0) {
+    // this is the right edge which needs to be (left + width - 1)
+    --tx;
+  }
+  if (yScale < 0) {
+    // this is the bottom edge which needs to be (top + height - 1)
+    --ty;
+  }
   // use ceil() to avoid gaps between "striped" images
   scaledWidth = (int)ceil(fabs(xScale));
   xSign = (xScale < 0) ? -1 : 1;
@@ -3425,8 +3541,7 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   }
 
   // allocate XImage
-  image = XCreateImage(display, DefaultVisual(display, screenNum),
-                      depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
+  image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
   image->data = (char *)gmalloc(bh * image->bytes_per_line);
 
   // if the transform is anything other than a 0/90/180/270 degree
@@ -3484,26 +3599,27 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
       p = pixBuf;
       q = alphaBuf;
       for (i = 0; i < n; ++i) {
-       for (j = 0; j < width; ++j) {
-         imgStr->getPixel(pixBuf2);
-         if (oneBitMode) {
-           *p++ = oneBitRGB[pixBuf2[0]];
-         } else {
-           colorMap->getRGB(pixBuf2, p);
-           ++p;
-         }
-         if (q) {
-           *q = 1;
-           for (k = 0; k < nComps; ++k) {
-             if (pixBuf2[k] < maskColors[2*k] ||
-                 pixBuf2[k] > maskColors[2*k]) {
-               *q = 0;
-               break;
-             }
-           }
-           ++q;
-         }
-       }
+        p2 = imgStr->getLine();
+        for (j = 0; j < width; ++j) {
+          if (oneBitMode) {
+            *p = oneBitRGB[*p2];
+          } else {
+            colorMap->getRGB(p2, p);
+          }
+          ++p;
+          if (q) {
+            *q = 1;
+            for (k = 0; k < nComps; ++k) {
+              if (p2[k] < maskColors[2*k] ||
+                  p2[k] > maskColors[2*k]) {
+                *q = 0;
+                break;
+              }
+            }
+            ++q;
+          }
+          p2 += nComps;
+        }
       }
     }
     lastYStep = yStep;