[poppler] glib/poppler-input-stream.cc glib/poppler-input-stream.h poppler/Annot.cc poppler/Array.cc poppler/Array.h poppler/ArthurOutputDev.cc poppler/ArthurOutputDev.h poppler/CairoFontEngine.cc poppler/CairoFontEngine.h poppler/CairoOutputDev.cc poppler/CairoOutputDev.h poppler/Catalog.cc poppler/Catalog.h poppler/Dict.cc poppler/Dict.h poppler/Gfx.cc poppler/Gfx.h poppler/GlobalParamsWin.cc poppler/Object.h poppler/OutputDev.h poppler/Page.cc poppler/Page.h poppler/Parser.cc poppler/PDFDoc.cc poppler/PDFDoc.h poppler/PreScanOutputDev.cc poppler/PreScanOutputDev.h poppler/PSOutputDev.cc poppler/PSOutputDev.h poppler/SplashOutputDev.cc poppler/SplashOutputDev.h poppler/Stream.cc poppler/Stream.h poppler/TextOutputDev.cc poppler/TextOutputDev.h poppler/XRef.cc poppler/XRef.h qt4/src test/gtk-test.cc utils/HtmlOutputDev.cc utils/HtmlOutputDev.h utils/ImageOutputDev.h

Albert Astals Cid aacid at kemper.freedesktop.org
Sat Jan 19 08:44:34 PST 2013


 glib/poppler-input-stream.cc |    4 +
 glib/poppler-input-stream.h  |    1 
 poppler/Annot.cc             |   52 +++++++++----------
 poppler/Array.cc             |   48 ++++++++++++++++-
 poppler/Array.h              |   15 ++++-
 poppler/ArthurOutputDev.cc   |    3 -
 poppler/ArthurOutputDev.h    |    3 -
 poppler/CairoFontEngine.cc   |   33 +++++++++---
 poppler/CairoFontEngine.h    |   11 ++--
 poppler/CairoOutputDev.cc    |   15 +++--
 poppler/CairoOutputDev.h     |    5 +
 poppler/Catalog.cc           |   84 +++++++++++++++++++++++++++---
 poppler/Catalog.h            |   15 ++++-
 poppler/Dict.cc              |   67 +++++++++++++++++++++++-
 poppler/Dict.h               |   11 +++-
 poppler/Gfx.cc               |   18 +++---
 poppler/Gfx.h                |    8 +-
 poppler/GlobalParamsWin.cc   |    4 -
 poppler/Object.h             |    7 +-
 poppler/OutputDev.h          |    4 -
 poppler/PDFDoc.cc            |   66 ++++++++++++++++++------
 poppler/PDFDoc.h             |   11 ++--
 poppler/PSOutputDev.cc       |   12 ++--
 poppler/PSOutputDev.h        |    4 -
 poppler/Page.cc              |   75 ++++++++++++++++++++++++---
 poppler/Page.h               |   18 +++++-
 poppler/Parser.cc            |    3 -
 poppler/PreScanOutputDev.cc  |    4 -
 poppler/PreScanOutputDev.h   |    4 -
 poppler/SplashOutputDev.cc   |   16 +++--
 poppler/SplashOutputDev.h    |    5 +
 poppler/Stream.cc            |  117 ++++++++++++++++++++++++++++++++-----------
 poppler/Stream.h             |   35 +++++++++---
 poppler/TextOutputDev.cc     |    5 +
 poppler/TextOutputDev.h      |    3 -
 poppler/XRef.cc              |   99 +++++++++++++++++++++++++++++++++---
 poppler/XRef.h               |   16 +++++
 qt4/src/poppler-document.cc  |   23 ++++----
 qt4/src/poppler-page.cc      |   64 ++++++++++++++++++++---
 qt4/src/poppler-private.cc   |    3 -
 qt4/src/poppler-private.h    |   74 ---------------------------
 test/gtk-test.cc             |    2 
 utils/HtmlOutputDev.cc       |    3 -
 utils/HtmlOutputDev.h        |    3 -
 utils/ImageOutputDev.h       |    3 -
 45 files changed, 793 insertions(+), 283 deletions(-)

New commits:
commit 8eb489c355d734a72e140ce7e32470d048362499
Author: Thomas Freitag <Thomas.Freitag at alfa.de>
Date:   Sat Jan 19 17:43:08 2013 +0100

    Make rendering thread-safe
    
    Bug #50992

diff --git a/glib/poppler-input-stream.cc b/glib/poppler-input-stream.cc
index 99fcb6f..4ac3149 100644
--- a/glib/poppler-input-stream.cc
+++ b/glib/poppler-input-stream.cc
@@ -41,6 +41,10 @@ PopplerInputStream::~PopplerInputStream()
     g_object_unref(cancellable);
 }
 
+BaseStream *PopplerInputStream::copy() {
+  return new PopplerInputStream(inputStream, cancellable, start, limited, length, &dict);
+}
+
 Stream *PopplerInputStream::makeSubStream(Guint startA, GBool limitedA,
                                           Guint lengthA, Object *dictA)
 {
diff --git a/glib/poppler-input-stream.h b/glib/poppler-input-stream.h
index 0d795f4..639ea04 100644
--- a/glib/poppler-input-stream.h
+++ b/glib/poppler-input-stream.h
@@ -33,6 +33,7 @@ public:
   PopplerInputStream(GInputStream *inputStream, GCancellable *cancellableA,
                      Guint startA, GBool limitedA, Guint lengthA, Object *dictA);
   virtual ~PopplerInputStream();
+  virtual BaseStream *copy();
   virtual Stream *makeSubStream(Guint start, GBool limited,
                                 Guint lengthA, Object *dictA);
   virtual StreamKind getKind() { return strWeird; }
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index dae0f62..0b3c5e4 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -25,7 +25,7 @@
 // Copyright (C) 2009 Ilya Gorenbein <igorenbein at finjan.com>
 // Copyright (C) 2011 José Aliste <jaliste at src.gnome.org>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
-// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2012 Tobias Koenig <tokoe at kdab.com>
 //
 // To see a description of the changes please see the Changelog file that
@@ -1205,7 +1205,7 @@ void Annot::initialize(PDFDoc *docA, Dict *dict) {
   if (dict->lookupNF("P", &obj1)->isRef()) {
     Ref ref = obj1.getRef();
 
-    page = doc->getCatalog()->findPage (ref.num, ref.gen);
+    page = doc->getCatalog()->findPage (ref.num, ref.gen, gFalse);
   } else {
     page = 0;
   }
@@ -1748,7 +1748,7 @@ void Annot::draw(Gfx *gfx, GBool printing) {
     return;
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
       rect->x1, rect->y1, rect->x2, rect->y2);
   obj.free();
@@ -2412,7 +2412,7 @@ void AnnotText::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -2511,7 +2511,7 @@ void AnnotLink::draw(Gfx *gfx, GBool printing) {
     return;
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, border, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2);
   obj.free();
@@ -2944,7 +2944,7 @@ void AnnotFreeText::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                  rect->x1, rect->y1, rect->x2, rect->y2);
   obj.free();
@@ -3416,7 +3416,7 @@ void AnnotLine::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -3724,7 +3724,7 @@ void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -3770,7 +3770,7 @@ AnnotWidget::~AnnotWidget() {
 void AnnotWidget::initialize(PDFDoc *docA, Dict *dict) {
   Object obj1;
 
-  form = doc->getCatalog()->getForm();
+  form = doc->getCatalog()->getForm(gFalse);
 
   if(dict->lookup("H", &obj1)->isName()) {
     const char *modeName = obj1.getName();
@@ -4967,7 +4967,7 @@ void AnnotWidget::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   if (addDingbatsResource) {
     // We are forcing ZaDb but the font does not exist
     // so create a fake one
@@ -4976,19 +4976,19 @@ void AnnotWidget::draw(Gfx *gfx, GBool printing) {
     subtypeObj.initName("Type1");
 
     Object fontDictObj;
-    Dict *fontDict = new Dict(xref);
+    Dict *fontDict = new Dict(gfx->getXRef());
     fontDict->decRef();
     fontDict->add(copyString("BaseFont"), &baseFontObj);
     fontDict->add(copyString("Subtype"), &subtypeObj);
     fontDictObj.initDict(fontDict);
 
     Object fontsDictObj;
-    Dict *fontsDict = new Dict(xref);
+    Dict *fontsDict = new Dict(gfx->getXRef());
     fontsDict->decRef();
     fontsDict->add(copyString("ZaDb"), &fontDictObj);
     fontsDictObj.initDict(fontsDict);
 
-    Dict *dict = new Dict(xref);
+    Dict *dict = new Dict(gfx->getXRef());
     dict->add(copyString("Font"), &fontsDictObj);
     gfx->pushResources(dict);
     delete dict;
@@ -5084,25 +5084,25 @@ void AnnotMovie::draw(Gfx *gfx, GBool printing) {
       appearBuf->append ("Q\n");
 
       Object imgDict;
-      imgDict.initDict(xref);
+      imgDict.initDict(gfx->getXRef());
       imgDict.dictSet ("MImg", &poster);
 
       Object resDict;
-      resDict.initDict(xref);
+      resDict.initDict(gfx->getXRef());
       resDict.dictSet ("XObject", &imgDict);
 
       Object formDict, obj1, obj2;
-      formDict.initDict(xref);
+      formDict.initDict(gfx->getXRef());
       formDict.dictSet("Length", obj1.initInt(appearBuf->getLength()));
       formDict.dictSet("Subtype", obj1.initName("Form"));
       formDict.dictSet("Name", obj1.initName("FRM"));
-      obj1.initArray(xref);
+      obj1.initArray(gfx->getXRef());
       obj1.arrayAdd(obj2.initInt(0));
       obj1.arrayAdd(obj2.initInt(0));
       obj1.arrayAdd(obj2.initInt(width));
       obj1.arrayAdd(obj2.initInt(height));
       formDict.dictSet("BBox", &obj1);
-      obj1.initArray(xref);
+      obj1.initArray(gfx->getXRef());
       obj1.arrayAdd(obj2.initInt(1));
       obj1.arrayAdd(obj2.initInt(0));
       obj1.arrayAdd(obj2.initInt(0));
@@ -5120,10 +5120,10 @@ void AnnotMovie::draw(Gfx *gfx, GBool printing) {
       delete appearBuf;
 
       Object objDict;
-      objDict.initDict(xref);
+      objDict.initDict(gfx->getXRef());
       objDict.dictSet ("FRM", &aStream);
 
-      resDict.initDict(xref);
+      resDict.initDict(gfx->getXRef());
       resDict.dictSet ("XObject", &objDict);
 
       appearBuf = new GooString ();
@@ -5147,7 +5147,7 @@ void AnnotMovie::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2);
   obj.free();
@@ -5489,7 +5489,7 @@ void AnnotGeometry::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2);
   obj.free();
@@ -5773,7 +5773,7 @@ void AnnotPolygon::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -5985,7 +5985,7 @@ void AnnotInk::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
@@ -6206,7 +6206,7 @@ void AnnotFileAttachment::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, border, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2);
   obj.free();
@@ -6367,7 +6367,7 @@ void AnnotSound::draw(Gfx *gfx, GBool printing) {
   }
 
   // draw the appearance stream
-  appearance.fetch(xref, &obj);
+  appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, border, color,
 		 rect->x1, rect->y1, rect->x2, rect->y2);
   obj.free();
diff --git a/poppler/Array.cc b/poppler/Array.cc
index cb22432..d23ed5d 100644
--- a/poppler/Array.cc
+++ b/poppler/Array.cc
@@ -15,6 +15,7 @@
 //
 // Copyright (C) 2005 Kristian Høgsberg <krh at redhat.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -33,6 +34,13 @@
 #include "Object.h"
 #include "Array.h"
 
+#if MULTITHREADED
+#  define lockArray   gLockMutex(&mutex)
+#  define unlockArray gUnlockMutex(&mutex)
+#else
+#  define lockArray
+#  define unlockArray
+#endif
 //------------------------------------------------------------------------
 // Array
 //------------------------------------------------------------------------
@@ -42,6 +50,9 @@ Array::Array(XRef *xrefA) {
   elems = NULL;
   size = length = 0;
   ref = 1;
+#if MULTITHREADED
+  gInitMutex(&mutex);
+#endif
 }
 
 Array::~Array() {
@@ -50,9 +61,38 @@ Array::~Array() {
   for (i = 0; i < length; ++i)
     elems[i].free();
   gfree(elems);
+#if MULTITHREADED
+  gDestroyMutex(&mutex);
+#endif
+}
+
+Object *Array::copy(XRef *xrefA, Object *obj) {
+  lockArray;
+  obj->initArray(xrefA);
+  for (int i = 0; i < length; ++i) {
+    Object obj1;
+    obj->arrayAdd(elems[i].copy(&obj1));
+  }
+  unlockArray;
+  return obj;
+}
+
+int Array::incRef() {
+  lockArray;
+  ++ref;
+  unlockArray;
+  return ref;
+}
+
+int Array::decRef() {
+  lockArray;
+  --ref;
+  unlockArray;
+  return ref;
 }
 
 void Array::add(Object *elem) {
+  lockArray;
   if (length == size) {
     if (length == 0) {
       size = 8;
@@ -63,21 +103,25 @@ void Array::add(Object *elem) {
   }
   elems[length] = *elem;
   ++length;
+  unlockArray;
 }
 
 void Array::remove(int i) {
+  lockArray;
   if (i < 0 || i >= length) {
 #ifdef DEBUG_MEM
     abort();
 #else
+    unlockArray;
     return;
 #endif
   }
   --length;
   memmove( elems + i, elems + i + 1, sizeof(elems[0]) * (length - i) );
+  unlockArray;
 }
 
-Object *Array::get(int i, Object *obj) {
+Object *Array::get(int i, Object *obj, int recursion) {
   if (i < 0 || i >= length) {
 #ifdef DEBUG_MEM
     abort();
@@ -85,7 +129,7 @@ Object *Array::get(int i, Object *obj) {
     return obj->initNull();
 #endif
   }
-  return elems[i].fetch(xref, obj);
+  return elems[i].fetch(xref, obj, recursion);
 }
 
 Object *Array::getNF(int i, Object *obj) {
diff --git a/poppler/Array.h b/poppler/Array.h
index 666a409..e78e399 100644
--- a/poppler/Array.h
+++ b/poppler/Array.h
@@ -15,6 +15,7 @@
 //
 // Copyright (C) 2005 Kristian Høgsberg <krh at redhat.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -28,7 +29,9 @@
 #pragma interface
 #endif
 
+#include "poppler-config.h"
 #include "Object.h"
+#include "goo/GooMutex.h"
 
 class XRef;
 
@@ -46,12 +49,15 @@ public:
   ~Array();
 
   // Reference counting.
-  int incRef() { return ++ref; }
-  int decRef() { return --ref; }
+  int incRef();
+  int decRef();
 
   // Get number of elements.
   int getLength() { return length; }
 
+  // Copy array with new xref
+  Object *copy(XRef *xrefA, Object *obj);
+
   // Add an element.
   void add(Object *elem);
 
@@ -59,7 +65,7 @@ public:
   void remove(int i);
 
   // Accessors.
-  Object *get(int i, Object *obj);
+  Object *get(int i, Object *obj, int resursion = 0);
   Object *getNF(int i, Object *obj);
   GBool getString(int i, GooString *string);
 
@@ -70,6 +76,9 @@ private:
   int size;			// size of <elems> array
   int length;			// number of elements in array
   int ref;			// reference count
+#if MULTITHREADED
+  GooMutex mutex;
+#endif
 };
 
 #endif
diff --git a/poppler/ArthurOutputDev.cc b/poppler/ArthurOutputDev.cc
index a1cb89d..5d57e93 100644
--- a/poppler/ArthurOutputDev.cc
+++ b/poppler/ArthurOutputDev.cc
@@ -20,6 +20,7 @@
 // Copyright (C) 2009 Petr Gajdos <pgajdos at novell.com>
 // Copyright (C) 2010 Matthias Fauconneau <matthias.fauconneau at gmail.com>
 // Copyright (C) 2011 Andreas Hartmetz <ahartmetz at gmail.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -122,7 +123,7 @@ void ArthurOutputDev::startDoc(XRef *xrefA) {
 #endif
 }
 
-void ArthurOutputDev::startPage(int pageNum, GfxState *state)
+void ArthurOutputDev::startPage(int pageNum, GfxState *state, XRef *xref)
 {
   // fill page with white background.
   int w = static_cast<int>(state->getPageWidth());
diff --git a/poppler/ArthurOutputDev.h b/poppler/ArthurOutputDev.h
index ed631a0..9d5e867 100644
--- a/poppler/ArthurOutputDev.h
+++ b/poppler/ArthurOutputDev.h
@@ -18,6 +18,7 @@
 // Copyright (C) 2009, 2011 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2010 Pino Toscano <pino at kde.org>
 // Copyright (C) 2011 Andreas Hartmetz <ahartmetz at gmail.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -86,7 +87,7 @@ public:
   //----- initialization and control
 
   // Start a page.
-  virtual void startPage(int pageNum, GfxState *state);
+  virtual void startPage(int pageNum, GfxState *state, XRef *xref);
 
   // End a page.
   virtual void endPage();
diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index c4493e8..beb4e37 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -26,6 +26,7 @@
 // Copyright (C) 2010 Suzuki Toshiya <mpsuzuki at hiroshima-u.ac.jp>
 // Copyright (C) 2010 Jan Kümmel <jan+freedesktop at snorc.org>
 // Copyright (C) 2012 Hib Eris <hib at hiberis.nl>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -58,6 +59,13 @@
 #pragma implementation
 #endif
 
+#if MULTITHREADED
+#  define lockFontEngine   gLockMutex(&mutex)
+#  define unlockFontEngine gUnlockMutex(&mutex)
+#else
+#  define lockFontEngine
+#  define unlockFontEngine
+#endif
 
 //------------------------------------------------------------------------
 // CairoFont
@@ -558,6 +566,7 @@ typedef struct _type3_font_info {
   PDFDoc *doc;
   CairoFontEngine *fontEngine;
   GBool printing;
+  XRef *xref;
 } type3_font_info_t;
 
 static void
@@ -645,7 +654,7 @@ _render_type3_glyph (cairo_scaled_font_t  *scaled_font,
   box.y2 = mat[3];
   gfx = new Gfx(info->doc, output_dev, resDict, &box, NULL);
   output_dev->startDoc(info->doc, info->fontEngine);
-  output_dev->startPage (1, gfx->getState());
+  output_dev->startPage (1, gfx->getState(), gfx->getXRef());
   output_dev->setInType3Char(gTrue);
   gfx->display(charProcs->getVal(glyph, &charProc));
 
@@ -674,7 +683,7 @@ _render_type3_glyph (cairo_scaled_font_t  *scaled_font,
 
 CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, PDFDoc *doc,
 				       CairoFontEngine *fontEngine,
-				       GBool printing) {
+				       GBool printing, XRef *xref) {
   Object refObj, strObj;
   type3_font_info_t *info;
   cairo_font_face_t *font_face;
@@ -697,6 +706,7 @@ CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, PDFDoc *doc,
   info->doc = doc;
   info->fontEngine = fontEngine;
   info->printing = printing;
+  info->xref = xref;
 
   cairo_font_face_set_user_data (font_face, &type3_font_key, (void *) info, _free_type3_font_info);
 
@@ -714,7 +724,7 @@ CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, PDFDoc *doc,
     }
   }
 
-  return new CairoType3Font(ref, doc, font_face, codeToGID, codeToGIDLen, printing);
+  return new CairoType3Font(ref, doc, font_face, codeToGID, codeToGIDLen, printing, xref);
 }
 
 CairoType3Font::CairoType3Font(Ref ref,
@@ -722,7 +732,7 @@ CairoType3Font::CairoType3Font(Ref ref,
 			       cairo_font_face_t *cairo_font_face,
 			       int *codeToGID,
 			       Guint codeToGIDLen,
-			       GBool printing) : CairoFont(ref,
+			       GBool printing, XRef *xref) : CairoFont(ref,
 							   cairo_font_face,
 							   codeToGID,
 							   codeToGIDLen,
@@ -755,6 +765,9 @@ CairoFontEngine::CairoFontEngine(FT_Library libA) {
   FT_Library_Version(lib, &major, &minor, &patch);
   useCIDs = major > 2 ||
             (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
+#if MULTITHREADED
+  gInitMutex(&mutex);
+#endif
 }
 
 CairoFontEngine::~CairoFontEngine() {
@@ -764,15 +777,19 @@ CairoFontEngine::~CairoFontEngine() {
     if (fontCache[i])
       delete fontCache[i];
   }
+#if MULTITHREADED
+  gDestroyMutex(&mutex);
+#endif
 }
 
 CairoFont *
-CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing) {
+CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing, XRef *xref) {
   int i, j;
   Ref ref;
   CairoFont *font;
   GfxFontType fontType;
   
+  lockFontEngine;
   ref = *gfxFont->getID();
 
   for (i = 0; i < cairoFontCacheSize; ++i) {
@@ -782,15 +799,16 @@ CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing) {
 	fontCache[j] = fontCache[j-1];
       }
       fontCache[0] = font;
+      unlockFontEngine;
       return font;
     }
   }
   
   fontType = gfxFont->getType();
   if (fontType == fontType3)
-    font = CairoType3Font::create (gfxFont, doc, this, printing);
+    font = CairoType3Font::create (gfxFont, doc, this, printing, xref);
   else
-    font = CairoFreeTypeFont::create (gfxFont, doc->getXRef(), lib, useCIDs);
+    font = CairoFreeTypeFont::create (gfxFont, xref, lib, useCIDs);
 
   //XXX: if font is null should we still insert it into the cache?
   if (fontCache[cairoFontCacheSize - 1]) {
@@ -800,5 +818,6 @@ CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing) {
     fontCache[j] = fontCache[j-1];
   }
   fontCache[0] = font;
+  unlockFontEngine;
   return font;
 }
diff --git a/poppler/CairoFontEngine.h b/poppler/CairoFontEngine.h
index 6335348..8c0dba1 100644
--- a/poppler/CairoFontEngine.h
+++ b/poppler/CairoFontEngine.h
@@ -19,6 +19,7 @@
 // Copyright (C) 2006, 2007 Jeff Muizelaar <jeff at infidigm.net>
 // Copyright (C) 2006, 2010 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2008 Adrian Johnson <ajohnson at redneon.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -32,6 +33,7 @@
 #pragma interface
 #endif
 
+#include "poppler-config.h"
 #include "goo/gtypes.h"
 #include <cairo-ft.h>
 
@@ -85,7 +87,7 @@ class CairoType3Font : public CairoFont {
 public:
   static CairoType3Font *create(GfxFont *gfxFont, PDFDoc *doc,
 				CairoFontEngine *fontEngine,
-				GBool printing);
+				GBool printing, XRef *xref);
   virtual ~CairoType3Font();
 
   virtual GBool matches(Ref &other, GBool printing);
@@ -94,7 +96,7 @@ private:
   CairoType3Font(Ref ref, PDFDoc *doc,
 		 cairo_font_face_t *cairo_font_face,
 		 int *codeToGID, Guint codeToGIDLen,
-		 GBool printing);
+		 GBool printing, XRef *xref);
   PDFDoc *doc;
 };
 
@@ -113,12 +115,15 @@ public:
   CairoFontEngine(FT_Library libA);
   ~CairoFontEngine();
 
-  CairoFont *getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing);
+  CairoFont *getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing, XRef *xref);
 
 private:
   CairoFont *fontCache[cairoFontCacheSize];
   FT_Library lib;
   GBool useCIDs;
+#if MULTITHREADED
+  GooMutex mutex;
+#endif
 };
 
 #endif
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 441ca45..10df30c 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -25,7 +25,7 @@
 // Copyright (C) 2008, 2009 Chris Wilson <chris at chris-wilson.co.uk>
 // Copyright (C) 2008, 2012 Hib Eris <hib at hiberis.nl>
 // Copyright (C) 2009, 2010 David Benjamin <davidben at mit.edu>
-// Copyright (C) 2011, 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2011-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2012 Patrick Pfeifer <p2000 at mailinator.com>
 // Copyright (C) 2012 Jason Crain <jason at aquaticape.us>
 //
@@ -163,6 +163,7 @@ CairoOutputDev::CairoOutputDev() {
   stroke_adjust = globalParams->getStrokeAdjust();
   align_stroke_coords = gFalse;
   adjusted_stroke_width = gFalse;
+  xref = NULL;
 }
 
 CairoOutputDev::~CairoOutputDev() {
@@ -235,9 +236,10 @@ void CairoOutputDev::startDoc(PDFDoc *docA,
     fontEngine = new CairoFontEngine(ft_lib);
     fontEngine_owner = gTrue;
   }
+  xref = doc->getXRef();
 }
 
-void CairoOutputDev::startPage(int pageNum, GfxState *state) {
+void CairoOutputDev::startPage(int pageNum, GfxState *state, XRef *xrefA) {
   /* set up some per page defaults */
   cairo_pattern_destroy(fill_pattern);
   cairo_pattern_destroy(stroke_pattern);
@@ -249,6 +251,9 @@ void CairoOutputDev::startPage(int pageNum, GfxState *state) {
 
   if (text)
     text->startPage(state);
+  if (xrefA != NULL) {
+    xref = xrefA;
+  }
 }
 
 void CairoOutputDev::endPage() {
@@ -602,7 +607,7 @@ void CairoOutputDev::updateFont(GfxState *state) {
   if (text)
     text->updateFont(state);
   
-  currentFont = fontEngine->getFont (state->getFont(), doc, printing);
+  currentFont = fontEngine->getFont (state->getFont(), doc, printing, xref);
 
   if (!currentFont)
     return;
@@ -805,7 +810,7 @@ void CairoOutputDev::eoFill(GfxState *state) {
 
 }
 
-GBool CairoOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *cat, Object *str,
+GBool CairoOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *cat, Object *str,
 					double *pmat, int paintType, int /*tilingType*/, Dict *resDict,
 					double *mat, double *bbox,
 					int x0, int y0, int x1, int y1,
@@ -846,7 +851,7 @@ GBool CairoOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *cat
   box.x2 = bbox[2]; box.y2 = bbox[3];
   strokePathTmp = strokePathClip;
   strokePathClip = NULL;
-  gfx = new Gfx(doc, this, resDict, &box, NULL);
+  gfx = new Gfx(doc, this, resDict, &box, NULL, NULL, NULL, gfxA->getXRef());
   gfx->display(str);
   delete gfx;
   strokePathClip = strokePathTmp;
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index a699a7b..2ac1fd5 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -20,7 +20,7 @@
 // Copyright (C) 2006-2011 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2008, 2009, 2011, 2012 Adrian Johnson <ajohnson at redneon.com>
 // Copyright (C) 2008 Michael Vrable <mvrable at cs.ucsd.edu>
-// Copyright (C) 2010-2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2010-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -124,7 +124,7 @@ public:
   //----- initialization and control
 
   // Start a page.
-  virtual void startPage(int pageNum, GfxState *state);
+  virtual void startPage(int pageNum, GfxState *state, XRef *xref);
 
   // End a page.
   virtual void endPage();
@@ -284,6 +284,7 @@ protected:
   GBool adjusted_stroke_width;
   GBool align_stroke_coords;
   CairoFont *currentFont;
+  XRef *xref;
 
   struct StrokePathClip {
     GfxPath *path;
diff --git a/poppler/Catalog.cc b/poppler/Catalog.cc
index cf6dff0..b7f7ede 100644
--- a/poppler/Catalog.cc
+++ b/poppler/Catalog.cc
@@ -25,6 +25,7 @@
 // Copyright (C) 2009 Ilya Gorenbein <igorenbein at finjan.com>
 // Copyright (C) 2010 Hib Eris <hib at hiberis.nl>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -55,6 +56,13 @@
 #include "ViewerPreferences.h"
 #include "FileSpec.h"
 
+#if MULTITHREADED
+#  define lockCatalog   gLockMutex(&mutex)
+#  define unlockCatalog gUnlockMutex(&mutex)
+#else
+#  define lockCatalog
+#  define unlockCatalog
+#endif
 //------------------------------------------------------------------------
 // Catalog
 //------------------------------------------------------------------------
@@ -64,6 +72,9 @@ Catalog::Catalog(PDFDoc *docA) {
   Object obj, obj2;
   Object optContentProps;
 
+#if MULTITHREADED
+  gInitMutex(&mutex);
+#endif
   ok = gTrue;
   doc = docA;
   xref = doc->getXRef();
@@ -170,6 +181,9 @@ Catalog::~Catalog() {
   outline.free();
   acroForm.free();
   viewerPreferences.free();
+#if MULTITHREADED
+  gDestroyMutex(&mutex);
+#endif
 }
 
 GooString *Catalog::readMetadata() {
@@ -177,6 +191,7 @@ GooString *Catalog::readMetadata() {
   Dict *dict;
   Object obj;
 
+  lockCatalog;
   if (metadata.isNone()) {
     Object catDict;
 
@@ -191,6 +206,7 @@ GooString *Catalog::readMetadata() {
   }
 
   if (!metadata.isStream()) {
+    unlockCatalog;
     return NULL;
   }
   dict = metadata.streamGetDict();
@@ -202,6 +218,7 @@ GooString *Catalog::readMetadata() {
   s = new GooString();
   metadata.getStream()->fillGooString(s);
   metadata.streamClose();
+  unlockCatalog;
   return s;
 }
 
@@ -209,19 +226,31 @@ Page *Catalog::getPage(int i)
 {
   if (i < 1) return NULL;
 
+  lockCatalog;
   if (i > lastCachedPage) {
-     if (cachePageTree(i) == gFalse) return NULL;
+     GBool cached = cachePageTree(i);
+     if ( cached == gFalse) {
+       unlockCatalog;
+       return NULL;
+     }
   }
+  unlockCatalog;
   return pages[i-1];
 }
 
-Ref *Catalog::getPageRef(int i)
+Ref *Catalog::getPageRef(int i, GBool lock)
 {
   if (i < 1) return NULL;
 
+  if (lock) lockCatalog;
   if (i > lastCachedPage) {
-     if (cachePageTree(i) == gFalse) return NULL;
+     GBool cached = cachePageTree(i);
+     if ( cached == gFalse) {
+       if (lock) unlockCatalog;
+       return NULL;
+     }
   }
+  if (lock) unlockCatalog;
   return &pageRefs[i-1];
 }
 
@@ -271,7 +300,7 @@ GBool Catalog::cachePageTree(int page)
       return gFalse;
     }
 
-    pagesSize = getNumPages();
+    pagesSize = getNumPages(gFalse);
     pages = (Page **)gmallocn(pagesSize, sizeof(Page *));
     pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref));
     for (int i = 0; i < pagesSize; ++i) {
@@ -398,11 +427,11 @@ GBool Catalog::cachePageTree(int page)
   return gFalse;
 }
 
-int Catalog::findPage(int num, int gen) {
+int Catalog::findPage(int num, int gen, GBool lock) {
   int i;
 
-  for (i = 0; i < getNumPages(); ++i) {
-    Ref *ref = getPageRef(i+1);
+  for (i = 0; i < getNumPages(lock); ++i) {
+    Ref *ref = getPageRef(i+1, lock);
     if (ref != NULL && ref->num == num && ref->gen == gen)
       return i + 1;
   }
@@ -423,10 +452,12 @@ LinkDest *Catalog::findDest(GooString *name) {
       obj1.free();
   }
   if (!found) {
+    lockCatalog;
     if (getDestNameTree()->lookup(name, &obj1))
       found = gTrue;
     else
       obj1.free();
+    unlockCatalog;
   }
   if (!found)
     return NULL;
@@ -457,6 +488,7 @@ FileSpec *Catalog::embeddedFile(int i)
 {
     Object efDict;
     Object obj;
+    lockCatalog;
     obj = getEmbeddedFileNameTree()->getValue(i);
     FileSpec *embeddedFile = 0;
     if (obj.isRef()) {
@@ -469,6 +501,7 @@ FileSpec *Catalog::embeddedFile(int i)
       Object null;
       embeddedFile = new FileSpec(&null);
     }
+    unlockCatalog;
     return embeddedFile;
 }
 
@@ -477,10 +510,12 @@ GooString *Catalog::getJS(int i)
   Object obj;
   // getJSNameTree()->getValue(i) returns a shallow copy of the object so we
   // do not need to free it
+  lockCatalog;
   getJSNameTree()->getValue(i).fetch(xref, &obj);
 
   if (!obj.isDict()) {
     obj.free();
+    unlockCatalog;
     return 0;
   }
   Object obj2;
@@ -492,6 +527,7 @@ GooString *Catalog::getJS(int i)
   if (strcmp(obj2.getName(), "JavaScript")) {
     obj2.free();
     obj.free();
+    unlockCatalog;
     return 0;
   }
   obj2.free();
@@ -507,11 +543,13 @@ GooString *Catalog::getJS(int i)
   }
   obj2.free();
   obj.free();
+  unlockCatalog;
   return js;
 }
 
 Catalog::PageMode Catalog::getPageMode() {
 
+  lockCatalog;
   if (pageMode == pageModeNull) {
 
     Object catDict, obj;
@@ -522,6 +560,7 @@ Catalog::PageMode Catalog::getPageMode() {
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
       catDict.free();
+      unlockCatalog;
       return pageMode;
     }
 
@@ -542,11 +581,13 @@ Catalog::PageMode Catalog::getPageMode() {
     obj.free();
     catDict.free();
   }
+  unlockCatalog;
   return pageMode;
 }
 
 Catalog::PageLayout Catalog::getPageLayout() {
 
+  lockCatalog;
   if (pageLayout == pageLayoutNull) {
 
     Object catDict, obj;
@@ -557,6 +598,7 @@ Catalog::PageLayout Catalog::getPageLayout() {
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
       catDict.free();
+      unlockCatalog;
       return pageLayout;
     }
 
@@ -578,6 +620,7 @@ Catalog::PageLayout Catalog::getPageLayout() {
     obj.free();
     catDict.free();
   }
+  unlockCatalog;
   return pageLayout;
 }
 
@@ -744,8 +787,13 @@ GBool Catalog::indexToLabel(int index, GooString *label)
   }
 }
 
-int Catalog::getNumPages()
+int Catalog::getNumPages(GBool lock)
 {
+  GBool locked = gFalse;
+  if (lock && numPages == -1) {
+    locked = gTrue;
+    lockCatalog;
+  }
   if (numPages == -1)
   {
     Object catDict, pagesDict, obj;
@@ -754,6 +802,7 @@ int Catalog::getNumPages()
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
       catDict.free();
+      if (locked) unlockCatalog;
       return 0;
     }
     catDict.dictLookup("Pages", &pagesDict);
@@ -765,6 +814,7 @@ int Catalog::getNumPages()
       error(errSyntaxError, -1, "Top-level pages object is wrong type ({0:s})",
           pagesDict.getTypeName());
       pagesDict.free();
+      if (locked) unlockCatalog;
       return 0;
     }
 
@@ -782,11 +832,13 @@ int Catalog::getNumPages()
     pagesDict.free();
   }
 
+  if (locked) unlockCatalog;
   return numPages;
 }
 
 PageLabelInfo *Catalog::getPageLabelInfo()
 {
+  lockCatalog;
   if (!pageLabelInfo) {
     Object catDict;
     Object obj;
@@ -795,21 +847,24 @@ PageLabelInfo *Catalog::getPageLabelInfo()
     if (!catDict.isDict()) {
       error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
       catDict.free();
+      unlockCatalog;
       return NULL;
     }
 
     if (catDict.dictLookup("PageLabels", &obj)->isDict()) {
-      pageLabelInfo = new PageLabelInfo(&obj, getNumPages());
+      pageLabelInfo = new PageLabelInfo(&obj, getNumPages(gFalse));
     }
     obj.free();
     catDict.free();
   }
 
+  unlockCatalog;
   return pageLabelInfo;
 }
 
 Object *Catalog::getStructTreeRoot()
 {
+  lockCatalog;
   if (structTreeRoot.isNone())
   {
      Object catDict;
@@ -824,11 +879,13 @@ Object *Catalog::getStructTreeRoot()
      catDict.free();
   }
 
+  unlockCatalog;
   return &structTreeRoot;
 }
 
 Object *Catalog::getOutline()
 {
+  lockCatalog;
   if (outline.isNone())
   {
      Object catDict;
@@ -843,11 +900,13 @@ Object *Catalog::getOutline()
      catDict.free();
   }
 
+  unlockCatalog;
   return &outline;
 }
 
 Object *Catalog::getDests()
 {
+  lockCatalog;
   if (dests.isNone())
   {
      Object catDict;
@@ -862,6 +921,7 @@ Object *Catalog::getDests()
      catDict.free();
   }
 
+  unlockCatalog;
   return &dests;
 }
 
@@ -883,8 +943,9 @@ Catalog::FormType Catalog::getFormType()
   return res;
 }
 
-Form *Catalog::getForm()
+Form *Catalog::getForm(GBool lock)
 {
+  if (lock) lockCatalog;
   if (!form) {
     if (acroForm.isDict()) {
       form = new Form(doc, &acroForm);
@@ -893,17 +954,20 @@ Form *Catalog::getForm()
     }
   }
 
+  if (lock) unlockCatalog;
   return form;
 }
 
 ViewerPreferences *Catalog::getViewerPreferences()
 {
+  lockCatalog;
   if (!viewerPrefs) {
     if (viewerPreferences.isDict()) {
       viewerPrefs = new ViewerPreferences(viewerPreferences.getDict());
     }
   }
 
+  unlockCatalog;
   return viewerPrefs;
 }
 
diff --git a/poppler/Catalog.h b/poppler/Catalog.h
index ef469ec..ac7505f 100644
--- a/poppler/Catalog.h
+++ b/poppler/Catalog.h
@@ -21,6 +21,7 @@
 // Copyright (C) 2008, 2011 Pino Toscano <pino at kde.org>
 // Copyright (C) 2010 Hib Eris <hib at hiberis.nl>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -34,7 +35,9 @@
 #pragma interface
 #endif
 
+#include "poppler-config.h"
 #include "Object.h"
+#include "goo/GooMutex.h"
 
 #include <vector>
 
@@ -104,13 +107,13 @@ public:
   GBool isOk() { return ok; }
 
   // Get number of pages.
-  int getNumPages();
+  int getNumPages(GBool lock = gTrue);
 
   // Get a page.
   Page *getPage(int i);
 
   // Get the reference for a page object.
-  Ref *getPageRef(int i);
+  Ref *getPageRef(int i, GBool lock = gTrue);
 
   // Return base URI, or NULL if none.
   GooString *getBaseURI() { return baseURI; }
@@ -124,7 +127,7 @@ public:
 
   // Find a page, given its object ID.  Returns page number, or 0 if
   // not found.
-  int findPage(int num, int gen);
+  int findPage(int num, int gen, GBool lock = gTrue);
 
   // Find a named destination.  Returns the link destination, or
   // NULL if <name> is not a destination.
@@ -162,7 +165,7 @@ public:
   };
 
   FormType getFormType();
-  Form* getForm();
+  Form* getForm(GBool lock = gTrue);
 
   ViewerPreferences *getViewerPreferences();
 
@@ -225,6 +228,7 @@ private:
   PageMode pageMode;		// page mode
   PageLayout pageLayout;	// page layout
 
+  void createPages();       // create pages for caching
   GBool cachePageTree(int page); // Cache first <page> pages.
   Object *findDestInTree(Object *tree, GooString *name, Object *obj);
 
@@ -232,6 +236,9 @@ private:
   NameTree *getDestNameTree();
   NameTree *getEmbeddedFileNameTree();
   NameTree *getJSNameTree();
+#if MULTITHREADED
+  GooMutex mutex;
+#endif
 
 };
 
diff --git a/poppler/Dict.cc b/poppler/Dict.cc
index c4f667b..95ed585 100644
--- a/poppler/Dict.cc
+++ b/poppler/Dict.cc
@@ -19,6 +19,7 @@
 // Copyright (C) 2008, 2010 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha at gmail.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -39,6 +40,13 @@
 #include "XRef.h"
 #include "Dict.h"
 
+#if MULTITHREADED
+#  define lockDict   gLockMutex(&mutex)
+#  define unlockDict gUnlockMutex(&mutex)
+#else
+#  define lockDict
+#  define unlockDict
+#endif
 //------------------------------------------------------------------------
 // Dict
 //------------------------------------------------------------------------
@@ -74,12 +82,18 @@ Dict::Dict(XRef *xrefA) {
   size = length = 0;
   ref = 1;
   sorted = gFalse;
+#if MULTITHREADED
+  gInitMutex(&mutex);
+#endif
 }
 
 Dict::Dict(Dict* dictA) {
   xref = dictA->xref;
   size = length = dictA->length;
   ref = 1;
+#if MULTITHREADED
+  gInitMutex(&mutex);
+#endif
 
   sorted = dictA->sorted;
   entries = (DictEntry *)gmallocn(size, sizeof(DictEntry));
@@ -89,6 +103,24 @@ Dict::Dict(Dict* dictA) {
   }
 }
 
+Dict *Dict::copy(XRef *xrefA) {
+  lockDict;
+  Dict *dictA = new Dict(this);
+  dictA->xref = xrefA;
+  for (int i=0; i<length; i++) {
+    if (dictA->entries[i].val.getType() == objDict) {
+       Dict *dict = dictA->entries[i].val.getDict();
+       Object obj;
+       obj.initDict(dict->copy(xrefA));
+       dictA->entries[i].val.free();
+       dictA->entries[i].val = obj;
+       obj.free();
+    }
+  }
+  unlockDict;
+  return dictA;
+}
+
 Dict::~Dict() {
   int i;
 
@@ -97,9 +129,27 @@ Dict::~Dict() {
     entries[i].val.free();
   }
   gfree(entries);
+#if MULTITHREADED
+  gDestroyMutex(&mutex);
+#endif
+}
+
+int Dict::incRef() {
+  lockDict;
+  ++ref;
+  unlockDict;
+  return ref;
+}
+
+int Dict::decRef() {
+  lockDict;
+  --ref;
+  unlockDict;
+  return ref;
 }
 
 void Dict::add(char *key, Object *val) {
+  lockDict;
   if (sorted) {
     // We use add on very few occasions so
     // virtually this will never be hit
@@ -117,13 +167,16 @@ void Dict::add(char *key, Object *val) {
   entries[length].key = key;
   entries[length].val = *val;
   ++length;
+  unlockDict;
 }
 
 inline DictEntry *Dict::find(const char *key) {
   if (!sorted && length >= SORT_LENGTH_LOWER_LIMIT)
   {
+      lockDict;
       sorted = gTrue;
       std::sort(entries, entries+length, cmpDictEntries);
+      unlockDict;
   }
 
   if (sorted) {
@@ -147,6 +200,7 @@ GBool Dict::hasKey(const char *key) {
 }
 
 void Dict::remove(const char *key) {
+  lockDict;
   if (sorted) {
     const int pos = binarySearch(key, entries, length);
     if (pos != -1) {
@@ -159,7 +213,10 @@ void Dict::remove(const char *key) {
     int i; 
     bool found = false;
     DictEntry tmp;
-    if(length == 0) return;
+    if(length == 0) {
+      unlockDict;
+      return;
+    }
 
     for(i=0; i<length; i++) {
       if (!strcmp(key, entries[i].key)) {
@@ -167,13 +224,17 @@ void Dict::remove(const char *key) {
         break;
       }
     }
-    if(!found) return;
+    if(!found) {
+      unlockDict;
+      return;
+    }
     //replace the deleted entry with the last entry
     length -= 1;
     tmp = entries[length];
     if (i!=length) //don't copy the last entry if it is deleted 
       entries[i] = tmp;
   }
+  unlockDict;
 }
 
 void Dict::set(const char *key, Object *val) {
@@ -184,8 +245,10 @@ void Dict::set(const char *key, Object *val) {
   }
   e = find (key);
   if (e) {
+    lockDict;
     e->val.free();
     e->val = *val;
+    unlockDict;
   } else {
     add (copyString(key), val);
   }
diff --git a/poppler/Dict.h b/poppler/Dict.h
index 897f221..fba99ed 100644
--- a/poppler/Dict.h
+++ b/poppler/Dict.h
@@ -18,6 +18,7 @@
 // Copyright (C) 2007-2008 Julien Rebetez <julienr at svn.gnome.org>
 // Copyright (C) 2010 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha at gmail.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -31,7 +32,9 @@
 #pragma interface
 #endif
 
+#include "poppler-config.h"
 #include "Object.h"
+#include "goo/GooMutex.h"
 
 //------------------------------------------------------------------------
 // Dict
@@ -48,13 +51,14 @@ public:
   // Constructor.
   Dict(XRef *xrefA);
   Dict(Dict* dictA);
+  Dict *copy(XRef *xrefA);
 
   // Destructor.
   ~Dict();
 
   // Reference counting.
-  int incRef() { return ++ref; }
-  int decRef() { return --ref; }
+  int incRef();
+  int decRef();
 
   // Get number of entries.
   int getLength() { return length; }
@@ -98,6 +102,9 @@ private:
   int size;			// size of <entries> array
   int length;			// number of entries in dictionary
   int ref;			// reference count
+#if MULTITHREADED
+  GooMutex mutex;
+#endif
 
   DictEntry *find(const char *key);
 };
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 5c9ed35..454987e 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -28,7 +28,7 @@
 // Copyright (C) 2008 Michael Vrable <mvrable at cs.ucsd.edu>
 // Copyright (C) 2008 Hib Eris <hib at hiberis.nl>
 // Copyright (C) 2009 M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
-// Copyright (C) 2009-2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2009 William Bader <williambader at hotmail.com>
 // Copyright (C) 2009, 2010 David Benjamin <davidben at mit.edu>
 // Copyright (C) 2010 Nils Höglund <nils.hoglund at gmail.com>
@@ -322,14 +322,15 @@ static inline GBool isSameGfxColor(const GfxColor &colorA, const GfxColor &color
 // GfxResources
 //------------------------------------------------------------------------
 
-GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) :
+GfxResources::GfxResources(XRef *xref, Dict *resDictA, GfxResources *nextA) :
     gStateCache(2, xref) {
   Object obj1, obj2;
   Ref r;
 
-  if (resDict) {
+  if (resDictA) {
 
     // build font dictionary
+    Dict *resDict = resDictA->copy(xref);
     fonts = NULL;
     resDict->lookupNF("Font", &obj1);
     if (obj1.isRef()) {
@@ -362,6 +363,7 @@ GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) :
     // get properties dictionary
     resDict->lookup("Properties", &propertiesDict);
 
+    delete resDict;
   } else {
     fonts = NULL;
     xObjDict.initNull();
@@ -534,7 +536,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict,
 	 double hDPI, double vDPI, PDFRectangle *box,
 	 PDFRectangle *cropBox, int rotate,
 	 GBool (*abortCheckCbkA)(void *data),
-	 void *abortCheckCbkDataA)
+	 void *abortCheckCbkDataA, XRef *xrefA)
 #ifdef USE_CMS
  : iccColorSpaceCache(5)
 #endif
@@ -542,7 +544,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict,
   int i;
 
   doc = docA;
-  xref = doc->getXRef();
+  xref = (xrefA == NULL) ? doc->getXRef() : xrefA;
   catalog = doc->getCatalog();
   subPage = gFalse;
   printCommands = globalParams->getPrintCommands();
@@ -561,7 +563,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict,
   fontChanged = gFalse;
   clip = clipNone;
   ignoreUndef = 0;
-  out->startPage(pageNum, state);
+  out->startPage(pageNum, state, xref);
   out->setDefaultCTM(state->getCTM());
   out->updateAll(state);
   for (i = 0; i < 6; ++i) {
@@ -589,7 +591,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict,
 Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict,
 	 PDFRectangle *box, PDFRectangle *cropBox,
 	 GBool (*abortCheckCbkA)(void *data),
-	 void *abortCheckCbkDataA)
+	 void *abortCheckCbkDataA, XRef *xrefA)
  #ifdef USE_CMS
  : iccColorSpaceCache(5)
 #endif
@@ -597,7 +599,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict,
   int i;
 
   doc = docA;
-  xref = doc->getXRef();
+  xref = (xrefA == NULL) ? doc->getXRef() : xrefA;
   catalog = doc->getCatalog();
   subPage = gTrue;
   printCommands = globalParams->getPrintCommands();
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index 7c42f14..369bc4c 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -18,7 +18,7 @@
 // Copyright (C) 2008 Brad Hards <bradh at kde.org>
 // Copyright (C) 2008, 2010 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2009-2012 Albert Astals Cid <aacid at kde.org>
-// Copyright (C) 2009, 2010, 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2009, 2010, 2012, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2010 David Benjamin <davidben at mit.edu>
 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger at googlemail.com>
 //
@@ -148,16 +148,18 @@ public:
       double hDPI, double vDPI, PDFRectangle *box,
       PDFRectangle *cropBox, int rotate,
       GBool (*abortCheckCbkA)(void *data) = NULL,
-      void *abortCheckCbkDataA = NULL);
+      void *abortCheckCbkDataA = NULL, XRef *xrefA = NULL);
 
   // Constructor for a sub-page object.
   Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict,
       PDFRectangle *box, PDFRectangle *cropBox,
       GBool (*abortCheckCbkA)(void *data) = NULL,
-      void *abortCheckCbkDataA = NULL);
+      void *abortCheckCbkDataA = NULL, XRef *xrefA = NULL);
 
   ~Gfx();
 
+  XRef *getXRef() { return xref; }
+
   // Interpret a stream or array of streams.
   void display(Object *obj, GBool topLevel = gTrue);
 
diff --git a/poppler/GlobalParamsWin.cc b/poppler/GlobalParamsWin.cc
index b76e156..e83c079 100644
--- a/poppler/GlobalParamsWin.cc
+++ b/poppler/GlobalParamsWin.cc
@@ -2,7 +2,7 @@
    but mostly based on xpdf code.
    
    // Copyright (C) 2010, 2012 Hib Eris <hib at hiberis.nl>
-   // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+   // Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
    // Copyright (C) 2012 Suzuki Toshiya <mpsuzuki at hiroshima-u.ac.jp>
    // Copyright (C) 2012 Adrian Johnson <ajohnson at redneon.com>
    // Copyright (C) 2012 Mark Brand <mabrand at mabrand.nl>
@@ -470,7 +470,7 @@ void GlobalParams::setupBaseFonts(char * dir)
       obj1.initNull();
       parser = new Parser(NULL,
 	      new Lexer(NULL,
-	      new FileStream(file, 0, gFalse, size, &obj1)),
+	      new FileStream(file, fileName->getCString(), 0, gFalse, size, &obj1)),
 	      gTrue);
       obj1.free();
       parser->getObj(&obj1);
diff --git a/poppler/Object.h b/poppler/Object.h
index c885d73..09ac5dd 100644
--- a/poppler/Object.h
+++ b/poppler/Object.h
@@ -18,6 +18,7 @@
 // Copyright (C) 2008, 2010 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2009 Jakub Wilk <ubanus at users.sf.net>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -207,7 +208,7 @@ public:
   int arrayGetLength();
   void arrayAdd(Object *elem);
   void arrayRemove(int i);
-  Object *arrayGet(int i, Object *obj);
+  Object *arrayGet(int i, Object *obj, int recursion);
   Object *arrayGetNF(int i, Object *obj);
 
   // Dict accessors.
@@ -278,8 +279,8 @@ inline void Object::arrayAdd(Object *elem)
 inline void Object::arrayRemove(int i)
   { OBJECT_TYPE_CHECK(objArray); array->remove(i); }
 
-inline Object *Object::arrayGet(int i, Object *obj)
-  { OBJECT_TYPE_CHECK(objArray); return array->get(i, obj); }
+inline Object *Object::arrayGet(int i, Object *obj, int recursion = 0)
+  { OBJECT_TYPE_CHECK(objArray); return array->get(i, obj, recursion); }
 
 inline Object *Object::arrayGetNF(int i, Object *obj)
   { OBJECT_TYPE_CHECK(objArray); return array->getNF(i, obj); }
diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h
index f540d57..5cf87cc 100644
--- a/poppler/OutputDev.h
+++ b/poppler/OutputDev.h
@@ -17,7 +17,7 @@
 // Copyright (C) 2006 Thorkild Stray <thorkild at ifi.uio.no>
 // Copyright (C) 2007 Jeff Muizelaar <jeff at infidigm.net>
 // Copyright (C) 2007, 2011 Adrian Johnson <ajohnson at redneon.com>
-// Copyright (C) 2009-2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2009, 2011 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2009, 2012 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger at googlemail.com>
@@ -137,7 +137,7 @@ public:
     { return gTrue; }
 
   // Start a page.
-  virtual void startPage(int pageNum, GfxState *state) {}
+  virtual void startPage(int pageNum, GfxState *state, XRef *xref) {}
 
   // End a page.
   virtual void endPage() {}
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index 0d78588..7a3dc39 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -26,7 +26,7 @@
 // Copyright (C) 2010 Ilya Gorenbein <igorenbein at finjan.com>
 // Copyright (C) 2010 Srinivas Adicherla <srinivas.adicherla at geodesic.com>
 // Copyright (C) 2010 Philip Lorenz <lorenzph+freedesktop at gmail.com>
-// Copyright (C) 2011, 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2011-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
 //
 // To see a description of the changes please see the Changelog file that
@@ -75,6 +75,14 @@
 #include "PDFDoc.h"
 #include "Hints.h"
 
+#if MULTITHREADED
+#  define lockPDFDoc   gLockMutex(&mutex)
+#  define unlockPDFDoc gUnlockMutex(&mutex)
+#else
+#  define lockPDFDoc
+#  define unlockPDFDoc
+#endif
+
 //------------------------------------------------------------------------
 
 #define headerSearchSize 1024	// read this many bytes at beginning of
@@ -94,6 +102,9 @@
 
 void PDFDoc::init()
 {
+#if MULTITHREADED
+  gInitMutex(&mutex);
+#endif
   ok = gFalse;
   errCode = errNone;
   fileName = NULL;
@@ -160,7 +171,7 @@ PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword,
 
   // create stream
   obj.initNull();
-  str = new FileStream(file, 0, gFalse, size, &obj);
+  str = new FileStream(file, fileName->getCString(), 0, gFalse, size, &obj);
 
   ok = setup(ownerPassword, userPassword);
 }
@@ -211,7 +222,7 @@ PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword,
 
   // create stream
   obj.initNull();
-  str = new FileStream(file, 0, gFalse, size, &obj);
+  str = new FileStream(file, fileName->getCString(), 0, gFalse, size, &obj);
 
   ok = setup(ownerPassword, userPassword);
 }
@@ -246,10 +257,12 @@ PDFDoc::PDFDoc(BaseStream *strA, GooString *ownerPassword,
 }
 
 GBool PDFDoc::setup(GooString *ownerPassword, GooString *userPassword) {
+  lockPDFDoc;
   str->setPos(0, -1);
   if (str->getPos() < 0)
   {
     error(errSyntaxError, -1, "Document base stream is not seekable");
+    unlockPDFDoc;
     return gFalse;
   }
 
@@ -269,12 +282,14 @@ GBool PDFDoc::setup(GooString *ownerPassword, GooString *userPassword) {
   if (!xref->isOk()) {
     error(errSyntaxError, -1, "Couldn't read xref table");
     errCode = xref->getErrorCode();
+    unlockPDFDoc;
     return gFalse;
   }
 
   // check for encryption
   if (!checkEncryption(ownerPassword, userPassword)) {
     errCode = errEncrypted;
+    unlockPDFDoc;
     return gFalse;
   }
 
@@ -293,11 +308,13 @@ GBool PDFDoc::setup(GooString *ownerPassword, GooString *userPassword) {
     if (catalog && !catalog->isOk()) {
       error(errSyntaxError, -1, "Couldn't read page catalog");
       errCode = errBadCatalog;
+      unlockPDFDoc;
       return gFalse;
     }
   }
 
   // done
+  unlockPDFDoc;
   return gTrue;
 }
 
@@ -342,6 +359,9 @@ PDFDoc::~PDFDoc() {
     gfree(fileNameU);
   }
 #endif
+#if MULTITHREADED
+  gDestroyMutex(&mutex);
+#endif
 }
 
 
@@ -455,7 +475,7 @@ void PDFDoc::displayPage(OutputDev *out, int page,
 			 GBool (*abortCheckCbk)(void *data),
 			 void *abortCheckCbkData,
                          GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
-                         void *annotDisplayDecideCbkData) {
+                         void *annotDisplayDecideCbkData, GBool copyXRef) {
   if (globalParams->getPrintCommands()) {
     printf("***** page %d *****\n", page);
   }
@@ -464,7 +484,7 @@ void PDFDoc::displayPage(OutputDev *out, int page,
     getPage(page)->display(out, hDPI, vDPI,
 				    rotate, useMediaBox, crop, printing,
 				    abortCheckCbk, abortCheckCbkData,
-				    annotDisplayDecideCbk, annotDisplayDecideCbkData);
+				    annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef);
 
 }
 
@@ -491,14 +511,14 @@ void PDFDoc::displayPageSlice(OutputDev *out, int page,
 			      GBool (*abortCheckCbk)(void *data),
 			      void *abortCheckCbkData,
                               GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
-                              void *annotDisplayDecideCbkData) {
+                              void *annotDisplayDecideCbkData, GBool copyXRef) {
   if (getPage(page))
     getPage(page)->displaySlice(out, hDPI, vDPI,
 					 rotate, useMediaBox, crop,
 					 sliceX, sliceY, sliceW, sliceH,
 					 printing,
 					 abortCheckCbk, abortCheckCbkData,
-					 annotDisplayDecideCbk, annotDisplayDecideCbkData);
+					 annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef);
 }
 
 Links *PDFDoc::getLinks(int page) {
@@ -826,11 +846,13 @@ int PDFDoc::saveWithoutChangesAs(GooString *name) {
 int PDFDoc::saveWithoutChangesAs(OutStream *outStr) {
   int c;
   
-  str->reset();
-  while ((c = str->getChar()) != EOF) {
+  BaseStream *copyStr = str->copy();
+  copyStr->reset();
+  while ((c = copyStr->getChar()) != EOF) {
     outStr->put(c);
   }
-  str->close();
+  copyStr->close();
+  delete copyStr;
 
   return errNone;
 }
@@ -840,11 +862,13 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr)
   XRef *uxref;
   int c;
   //copy the original file
-  str->reset();
-  while ((c = str->getChar()) != EOF) {
+  BaseStream *copyStr = str->copy();
+  copyStr->reset();
+  while ((c = copyStr->getChar()) != EOF) {
     outStr->put(c);
   }
-  str->close();
+  copyStr->close();
+  delete copyStr;
 
   Guchar *fileKey;
   CryptAlgorithm encAlgorithm;
@@ -853,6 +877,7 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr)
 
   uxref = new XRef();
   uxref->add(0, 65535, 0, gFalse);
+  xref->lock();
   for(int i=0; i<xref->getNumObjects(); i++) {
     if ((xref->getEntry(i)->type == xrefEntryFree) && 
         (xref->getEntry(i)->gen == 0)) //we skip the irrelevant free objects
@@ -864,7 +889,7 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr)
       ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen;
       if (xref->getEntry(i)->type != xrefEntryFree) {
         Object obj1;
-        xref->fetch(ref.num, ref.gen, &obj1);
+        xref->fetch(ref.num, ref.gen, &obj1, 1);
         Guint offset = writeObjectHeader(&ref, outStr);
         writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
         writeObjectFooter(outStr);
@@ -875,6 +900,7 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr)
       }
     }
   }
+  xref->unlock();
   if (uxref->getNumObjects() == 0) { //we have nothing to update
     delete uxref;
     return;
@@ -922,6 +948,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr)
   outStr->printf("%%PDF-%d.%d\r\n",pdfMajorVersion,pdfMinorVersion);
   XRef *uxref = new XRef();
   uxref->add(0, 65535, 0, gFalse);
+  xref->lock();
   for(int i=0; i<xref->getNumObjects(); i++) {
     Object obj1;
     Ref ref;
@@ -941,7 +968,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr)
     } else if (type == xrefEntryUncompressed){ 
       ref.num = i;
       ref.gen = xref->getEntry(i)->gen;
-      xref->fetch(ref.num, ref.gen, &obj1);
+      xref->fetch(ref.num, ref.gen, &obj1, 1);
       Guint offset = writeObjectHeader(&ref, outStr);
       // Write unencrypted objects in unencrypted form
       if (xref->getEntry(i)->getFlag(XRefEntry::Unencrypted)) {
@@ -955,7 +982,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr)
     } else if (type == xrefEntryCompressed) {
       ref.num = i;
       ref.gen = 0; //compressed entries have gen == 0
-      xref->fetch(ref.num, ref.gen, &obj1);
+      xref->fetch(ref.num, ref.gen, &obj1, 1);
       Guint offset = writeObjectHeader(&ref, outStr);
       writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
       writeObjectFooter(outStr);
@@ -963,6 +990,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr)
       obj1.free();
     }
   }
+  xref->unlock();
   Guint uxrefOffset = outStr->getPos();
   writeXRefTableTrailer(uxrefOffset, uxref, gTrue /* write all entries */,
                         uxref->getNumObjects(), outStr, gFalse /* complete rewrite */);
@@ -1562,8 +1590,10 @@ Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, G
 Outline *PDFDoc::getOutline()
 {
   if (!outline) {
+    lockPDFDoc;
     // read outline
     outline = new Outline(catalog->getOutline(), xref);
+    unlockPDFDoc;
   }
 
   return outline;
@@ -1720,14 +1750,18 @@ Page *PDFDoc::getPage(int page)
   if ((page < 1) || page > getNumPages()) return NULL;
 
   if (isLinearized()) {
+    lockPDFDoc;
     if (!pageCache) {
       pageCache = (Page **) gmallocn(getNumPages(), sizeof(Page *));
       for (int i = 0; i < getNumPages(); i++) {
         pageCache[i] = NULL;
       }
     }
+    unlockPDFDoc;
     if (!pageCache[page-1]) {
+      lockPDFDoc;
       pageCache[page-1] = parsePage(page);
+      unlockPDFDoc;
     }
     if (pageCache[page-1]) {
        return pageCache[page-1];
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index 4562346..75d0c40 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -22,7 +22,7 @@
 // Copyright (C) 2009 Kovid Goyal <kovid at kovidgoyal.net>
 // Copyright (C) 2010 Hib Eris <hib at hiberis.nl>
 // Copyright (C) 2010 Srinivas Adicherla <srinivas.adicherla at geodesic.com>
-// Copyright (C) 2011, 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2011, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
 //
 // To see a description of the changes please see the Changelog file that
@@ -37,7 +37,9 @@
 #pragma interface
 #endif
 
+#include "poppler-config.h"
 #include <stdio.h>
+#include "goo/GooMutex.h"
 #include "XRef.h"
 #include "Catalog.h"
 #include "Page.h"
@@ -146,7 +148,7 @@ public:
 		   GBool (*abortCheckCbk)(void *data) = NULL,
 		   void *abortCheckCbkData = NULL,
                    GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
-                   void *annotDisplayDecideCbkData = NULL);
+                   void *annotDisplayDecideCbkData = NULL, GBool copyXRef = gFalse);
 
   // Display a range of pages.
   void displayPages(OutputDev *out, int firstPage, int lastPage,
@@ -165,7 +167,7 @@ public:
 			GBool (*abortCheckCbk)(void *data) = NULL,
 			void *abortCheckCbkData = NULL,
                         GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
-                        void *annotDisplayDecideCbkData = NULL);
+                        void *annotDisplayDecideCbkData = NULL, GBool copyXRef = gFalse);
 
   // Find a page, given its object ID.  Returns page number, or 0 if
   // not found.
@@ -326,6 +328,9 @@ private:
   int fopenErrno;
 
   Guint startXRefPos;		// offset of last xref table
+#if MULTITHREADED
+  GooMutex mutex;
+#endif
 };
 
 #endif
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 95be97f..9042297 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -20,7 +20,7 @@
 // Copyright (C) 2007, 2008 Brad Hards <bradh at kde.org>
 // Copyright (C) 2008, 2009 Koji Otani <sho at bbr.jp>
 // Copyright (C) 2008, 2010 Hib Eris <hib at hiberis.nl>
-// Copyright (C) 2009-2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2009 Till Kamppeter <till.kamppeter at gmail.com>
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2009, 2011, 2012 William Bader <williambader at hotmail.com>
@@ -3085,7 +3085,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
     rotateA += 360;
   }
   state = new GfxState(dpi, dpi, &box, rotateA, gFalse);
-  startPage(page->getNum(), state);
+  startPage(page->getNum(), state, xref);
   delete state;
 
   // set up the SplashOutputDev
@@ -3471,14 +3471,14 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
 #endif // HAVE_SPLASH
 }
 
-void PSOutputDev::startPage(int pageNum, GfxState *state) {
+void PSOutputDev::startPage(int pageNum, GfxState *state, XRef *xrefA) {
   Page *page;
   int x1, y1, x2, y2, width, height, t;
   int imgWidth, imgHeight, imgWidth2, imgHeight2;
   GBool landscape;
   GooString *s;
 
-
+  xref = xrefA;
   if (mode == psModePS || mode == psModePSOrigPageSizes) {
     GooString pageLabel;
     const GBool gotLabel = doc->getCatalog()->indexToLabel(pageNum -1, &pageLabel);
@@ -4284,7 +4284,7 @@ GBool PSOutputDev::tilingPatternFillL2(GfxState *state, Catalog *cat, Object *st
   return gTrue;
 }
 
-GBool PSOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str,
+GBool PSOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *cat, Object *str,
 				     double *pmat, int paintType, int tilingType, Dict *resDict,
 				     double *mat, double *bbox,
 				     int x0, int y0, int x1, int y1,
@@ -4303,7 +4303,7 @@ GBool PSOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Ob
     box.y1 = bbox[1];
     box.x2 = bbox[2];
     box.y2 = bbox[3];
-    gfx = new Gfx(doc, this, resDict, &box, NULL);
+    gfx = new Gfx(doc, this, resDict, &box, NULL, NULL, NULL, gfxA->getXRef());
     writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] cm\n", mat[0], mat[1], mat[2], mat[3], tx, ty);
     inType3Char = gTrue;
     gfx->display(str);
diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h
index 6f29096..58cbe46 100644
--- a/poppler/PSOutputDev.h
+++ b/poppler/PSOutputDev.h
@@ -17,7 +17,7 @@
 // Copyright (C) 2005 Kristian Høgsberg <krh at redhat.com>
 // Copyright (C) 2006-2008, 2012 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2007 Brad Hards <bradh at kde.org>
-// Copyright (C) 2009-2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2009 Till Kamppeter <till.kamppeter at gmail.com>
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2009, 2011 William Bader <williambader at hotmail.com>
@@ -186,7 +186,7 @@ public:
 			       void *annotDisplayDecideCbkData = NULL);
 
   // Start a page.
-  virtual void startPage(int pageNum, GfxState *state);
+  virtual void startPage(int pageNum, GfxState *state, XRef *xref);
 
   // End a page.
   virtual void endPage();
diff --git a/poppler/Page.cc b/poppler/Page.cc
index 8c2065b..fa6d2a9 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -25,6 +25,7 @@
 // Copyright (C) 2008 Brad Hards <bradh at kde.org>
 // Copyright (C) 2008 Ilya Gorenbein <igorenbein at finjan.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -57,6 +58,13 @@
 #include "Catalog.h"
 #include "Form.h"
 
+#if MULTITHREADED
+#  define lockPage   gLockMutex(&mutex)
+#  define unlockPage gUnlockMutex(&mutex)
+#else
+#  define lockPage
+#  define unlockPage
+#endif
 //------------------------------------------------------------------------
 // PDFRectangle
 //------------------------------------------------------------------------
@@ -257,6 +265,9 @@ GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) {
 Page::Page(PDFDoc *docA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form) {
   Object tmp;
 	
+#if MULTITHREADED
+  gInitMutex(&mutex);
+#endif
   ok = gTrue;
   doc = docA;
   xref = doc->getXRef();
@@ -343,6 +354,36 @@ Page::~Page() {
   trans.free();
   thumb.free();
   actions.free();
+#if MULTITHREADED
+  gDestroyMutex(&mutex);
+#endif
+}
+
+void Page::replaceXRef(XRef *xrefA) {
+  Object obj1;
+  Dict *pageDict = pageObj.getDict()->copy(xrefA);
+  xref = xrefA;
+  trans.free();
+  pageDict->lookupNF("Trans", &trans);
+  annotsObj.free();
+  pageDict->lookupNF("Annots", &annotsObj);
+  contents.free();
+  pageDict->lookupNF("Contents", &contents);
+  if (contents.isArray()) {
+    contents.free();
+    pageDict->lookupNF("Contents", &obj1)->getArray()->copy(xrefA, &contents);
+    obj1.free();
+  }
+  thumb.free();
+  pageDict->lookupNF("Thumb", &thumb);
+  actions.free();
+  pageDict->lookupNF("AA", &actions);
+  pageDict->lookup("Resources", &obj1);
+  if (obj1.isDict()) {
+    attrs->replaceResource(obj1);
+  }
+  obj1.free();
+  delete pageDict;
 }
 
 Annots *Page::getAnnots() {
@@ -363,6 +404,7 @@ void Page::addAnnot(Annot *annot) {
   // Make sure we have annots before adding the new one
   // even if it's an empty list so that we can safely
   // call annots->appendAnnot(annot)
+  lockPage;
   getAnnots();
 
   if (annotsObj.isNull()) {
@@ -392,12 +434,14 @@ void Page::addAnnot(Annot *annot) {
 
   annots->appendAnnot(annot);
   annot->setPage(num, gTrue);
+  unlockPage;
 }
 
 void Page::removeAnnot(Annot *annot) {
   Ref annotRef = annot->getRef();
   Object annArray;
 
+  lockPage;
   getAnnots(&annArray);
   if (annArray.isArray()) {
     int idx = -1;
@@ -414,6 +458,7 @@ void Page::removeAnnot(Annot *annot) {
     if (idx == -1) {
       error(errInternal, -1, "Annotation doesn't belong to this page");
       annArray.free();
+      unlockPage;
       return;
     }
     annots->removeAnnot(annot); // Gracefully fails on popup windows
@@ -429,6 +474,7 @@ void Page::removeAnnot(Annot *annot) {
   annArray.free();
   annot->removeReferencedObjects(); // Note: Might recurse in removeAnnot again
   annot->setPage(0, gFalse);
+  unlockPage;
 }
 
 Links *Page::getLinks() {
@@ -445,10 +491,11 @@ void Page::display(OutputDev *out, double hDPI, double vDPI,
 		   GBool (*abortCheckCbk)(void *data),
 		   void *abortCheckCbkData,
                    GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
-                   void *annotDisplayDecideCbkData) {
+                   void *annotDisplayDecideCbkData,
+                   GBool copyXRef) {
   displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, printing,
 	       abortCheckCbk, abortCheckCbkData,
-               annotDisplayDecideCbk, annotDisplayDecideCbkData);
+               annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef);
 }
 
 Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
@@ -456,7 +503,7 @@ Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
 		     int sliceX, int sliceY, int sliceW, int sliceH,
 		     GBool printing,
 		     GBool (*abortCheckCbk)(void *data),
-		     void *abortCheckCbkData) {
+		     void *abortCheckCbkData, XRef *xrefA) {
   PDFRectangle *mediaBox, *cropBox;
   PDFRectangle box;
   Gfx *gfx;
@@ -486,7 +533,7 @@ Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
   }
   gfx = new Gfx(doc, out, num, attrs->getResourceDict(),
 		hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL,
-		rotate, abortCheckCbk, abortCheckCbkData);
+		rotate, abortCheckCbk, abortCheckCbkData, xrefA);
 
   return gfx;
 }
@@ -498,7 +545,8 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
 			GBool (*abortCheckCbk)(void *data),
 			void *abortCheckCbkData,
                         GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
-                        void *annotDisplayDecideCbkData) {
+                        void *annotDisplayDecideCbkData,
+                        GBool copyXRef) {
   Gfx *gfx;
   Object obj;
   Annots *annotList;
@@ -511,13 +559,18 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
 			   annotDisplayDecideCbk, annotDisplayDecideCbkData)) {
     return;
   }
+  lockPage;
+  XRef *localXRef = (copyXRef) ? xref->copy() : xref;
+  if (copyXRef) {
+    replaceXRef(localXRef);
+  }
 
   gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop,
 		  sliceX, sliceY, sliceW, sliceH,
 		  printing,
-		  abortCheckCbk, abortCheckCbkData);
+		  abortCheckCbk, abortCheckCbkData, localXRef);
 
-  contents.fetch(xref, &obj);
+  contents.fetch(localXRef, &obj);
   if (!obj.isNull()) {
     gfx->saveState();
     gfx->display(&obj);
@@ -548,6 +601,11 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
   }
 
   delete gfx;
+  if (copyXRef) {
+    replaceXRef(doc->getXRef());
+    delete localXRef;
+  }
+  unlockPage;
 }
 
 void Page::display(Gfx *gfx) {
@@ -576,9 +634,11 @@ GBool Page::loadThumb(unsigned char **data_out,
   GfxImageColorMap *colorMap;
 
   /* Get stream dict */
+  lockPage;
   thumb.fetch(xref, &fetched_thumb);
   if (!fetched_thumb.isStream()) {
     fetched_thumb.free();
+    unlockPage;
     return gFalse;
   }
 
@@ -661,6 +721,7 @@ GBool Page::loadThumb(unsigned char **data_out,
 
   delete colorMap;
  fail1:
+  unlockPage;
   fetched_thumb.free();
 
   return success;
diff --git a/poppler/Page.h b/poppler/Page.h
index a6098ed..100731d 100644
--- a/poppler/Page.h
+++ b/poppler/Page.h
@@ -21,6 +21,7 @@
 // Copyright (C) 2008 Iñigo Martínez <inigomartinez at gmail.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
 // Copyright (C) 2012 Albert Astals Cid <aacid at kde.org>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -34,7 +35,9 @@
 #pragma interface
 #endif
 
+#include "poppler-config.h"
 #include "Object.h"
+#include "goo/GooMutex.h"
 
 class Dict;
 class PDFDoc;
@@ -102,6 +105,8 @@ public:
 	? separationInfo.getDict() : (Dict *)NULL; }
   Dict *getResourceDict()
     { return resources.isDict() ? resources.getDict() : (Dict *)NULL; }
+  void replaceResource(Object obj1) 
+  {  resources.free(); obj1.copy(&resources); }
 
   // Clip all other boxes to the MediaBox.
   void clipBoxes();
@@ -210,7 +215,7 @@ public:
 		 int sliceX, int sliceY, int sliceW, int sliceH,
 		 GBool printing,
 		 GBool (*abortCheckCbk)(void *data),
-		 void *abortCheckCbkData);
+		 void *abortCheckCbkData, XRef *xrefA = NULL);
 
   // Display a page.
   void display(OutputDev *out, double hDPI, double vDPI,
@@ -219,7 +224,8 @@ public:
 	       GBool (*abortCheckCbk)(void *data) = NULL,
 	       void *abortCheckCbkData = NULL,
                GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
-               void *annotDisplayDecideCbkData = NULL);
+               void *annotDisplayDecideCbkData = NULL,
+               GBool copyXRef = gFalse);
 
   // Display part of a page.
   void displaySlice(OutputDev *out, double hDPI, double vDPI,
@@ -229,7 +235,8 @@ public:
 		    GBool (*abortCheckCbk)(void *data) = NULL,
 		    void *abortCheckCbkData = NULL,
                     GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
-                    void *annotDisplayDecideCbkData = NULL);
+                    void *annotDisplayDecideCbkData = NULL,
+                    GBool copyXRef = gFalse);
 
   void display(Gfx *gfx);
 
@@ -245,6 +252,8 @@ public:
 		     int rotate, GBool useMediaBox, GBool upsideDown);
 
 private:
+  // replace xref
+  void replaceXRef(XRef *xrefA);
 
   PDFDoc *doc;
   XRef *xref;			// the xref table for this PDF file
@@ -260,6 +269,9 @@ private:
   Object actions;		// page addiction actions
   double duration;              // page duration
   GBool ok;			// true if page is valid
+#if MULTITHREADED
+  GooMutex mutex;
+#endif
 };
 
 #endif
diff --git a/poppler/Parser.cc b/poppler/Parser.cc
index 431a279..41c611d 100644
--- a/poppler/Parser.cc
+++ b/poppler/Parser.cc
@@ -17,6 +17,7 @@
 // Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk at gmail.com>
 // Copyright (C) 2009 Ilya Gorenbein <igorenbein at finjan.com>
 // Copyright (C) 2012 Hib Eris <hib at hiberis.nl>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -271,7 +272,7 @@ Stream *Parser::makeStream(Object *dict, Guchar *fileKey,
   }
 
   // get filters
-  str = str->addFilters(dict);
+  str = str->addFilters(dict, recursion);
 
   return str;
 }
diff --git a/poppler/PreScanOutputDev.cc b/poppler/PreScanOutputDev.cc
index 3a86d52..6a01126 100644
--- a/poppler/PreScanOutputDev.cc
+++ b/poppler/PreScanOutputDev.cc
@@ -16,7 +16,7 @@
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2010, 2011 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2011 William Bader <williambader at hotmail.com>
-// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2011, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2011 Adrian Johnson <ajohnson at redneon.com>
 //
 // To see a description of the changes please see the Changelog file that
@@ -52,7 +52,7 @@ PreScanOutputDev::PreScanOutputDev(PDFDoc *docA) {
 PreScanOutputDev::~PreScanOutputDev() {
 }
 
-void PreScanOutputDev::startPage(int /*pageNum*/, GfxState * /*state*/) {
+void PreScanOutputDev::startPage(int /*pageNum*/, GfxState * /*state*/, XRef * /*xref*/) {
 }
 
 void PreScanOutputDev::endPage() {
diff --git a/poppler/PreScanOutputDev.h b/poppler/PreScanOutputDev.h
index 5260a3b..0fc9d3e 100644
--- a/poppler/PreScanOutputDev.h
+++ b/poppler/PreScanOutputDev.h
@@ -16,7 +16,7 @@
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2010 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2011 William Bader <williambader at hotmail.com>
-// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2011, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2011 Adrian Johnson <ajohnson at redneon.com>
 //
 // To see a description of the changes please see the Changelog file that
@@ -76,7 +76,7 @@ public:
   //----- initialization and control
 
   // Start a page.
-  virtual void startPage(int pageNum, GfxState *state);
+  virtual void startPage(int pageNum, GfxState *state, XRef *xref);
 
   // End a page.
   virtual void endPage();
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 6f2d4d6..c55a2a2 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -20,7 +20,7 @@
 // Copyright (C) 2006 Scott Turner <scotty1024 at mac.com>
 // Copyright (C) 2007 Koji Otani <sho at bbr.jp>
 // Copyright (C) 2009 Petr Gajdos <pgajdos at novell.com>
-// Copyright (C) 2009-2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2009 William Bader <williambader at hotmail.com>
 // Copyright (C) 2010 Patrick Spendrin <ps_ml at gmx.de>
@@ -1250,6 +1250,7 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA,
   textClipPath = NULL;
   transpGroupStack = NULL;
   nestCount = 0;
+  xref = NULL;
 }
 
 void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) {
@@ -1345,12 +1346,13 @@ void SplashOutputDev::startDoc(PDFDoc *docA) {
   nT3Fonts = 0;
 }
 
-void SplashOutputDev::startPage(int pageNum, GfxState *state) {
+void SplashOutputDev::startPage(int pageNum, GfxState *state, XRef *xrefA) {
   int w, h;
   double *ctm;
   SplashCoord mat[6];
   SplashColor color;
 
+  xref = xrefA;
   if (state) {
     setupScreenParams(state->getHDPI(), state->getVDPI());
     w = (int)(state->getPageWidth() + 0.5);
@@ -1840,7 +1842,7 @@ void SplashOutputDev::doUpdateFont(GfxState *state) {
 
   } else {
 
-    if (!(fontLoc = gfxFont->locateFont(doc->getXRef(), gFalse))) {
+    if (!(fontLoc = gfxFont->locateFont((xref) ? xref : doc->getXRef(), gFalse))) {
       error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
 	    gfxFont->getName() ? gfxFont->getName()->getCString()
 	                       : "(unnamed)");
@@ -1850,7 +1852,7 @@ void SplashOutputDev::doUpdateFont(GfxState *state) {
     // embedded font
     if (fontLoc->locType == gfxFontLocEmbedded) {
       // if there is an embedded font, read it to memory
-      tmpBuf = gfxFont->readEmbFontFile(doc->getXRef(), &tmpBufLen);
+      tmpBuf = gfxFont->readEmbFontFile((xref) ? xref : doc->getXRef(), &tmpBufLen);
       if (! tmpBuf)
 	goto err2;
 
@@ -3385,7 +3387,7 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
   if (maskWidth > width || maskHeight > height) {
     decodeLow.initInt(maskInvert ? 0 : 1);
     decodeHigh.initInt(maskInvert ? 1 : 0);
-    maskDecode.initArray(doc->getXRef());
+    maskDecode.initArray((xref) ? xref : doc->getXRef());
     maskDecode.arrayAdd(&decodeLow);
     maskDecode.arrayAdd(&decodeHigh);
     maskColorMap = new GfxImageColorMap(1, &maskDecode,
@@ -4075,7 +4077,7 @@ void SplashOutputDev::setFreeTypeHinting(GBool enable, GBool enableSlightHinting
   enableSlightHinting = enableSlightHintingA;
 }
 
-GBool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *catalog, Object *str,
+GBool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *catalog, Object *str,
 					double *ptm, int paintType, int /*tilingType*/, Dict *resDict,
 					double *mat, double *bbox,
 					int x0, int y0, int x1, int y1,
@@ -4207,7 +4209,7 @@ GBool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *ca
 
   box.x1 = bbox[0]; box.y1 = bbox[1];
   box.x2 = bbox[2]; box.y2 = bbox[3];
-  gfx = new Gfx(doc, this, resDict, &box, NULL);
+  gfx = new Gfx(doc, this, resDict, &box, NULL, NULL, NULL, gfxA->getXRef());
   // set pattern transformation matrix
   gfx->getState()->setCTM(m1.m[0], m1.m[1], m1.m[2], m1.m[3], m1.m[4], m1.m[5]);
   updateCTM(gfx->getState(), m1.m[0], m1.m[1], m1.m[2], m1.m[3], m1.m[4], m1.m[5]);
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index de7934d..830356a 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -14,7 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2005 Takashi Iwai <tiwai at suse.de>
-// Copyright (C) 2009-2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger at googlemail.com>
 // Copyright (C) 2011 Andreas Hartmetz <ahartmetz at gmail.com>
@@ -195,7 +195,7 @@ public:
   //----- initialization and control
 
   // Start a page.
-  virtual void startPage(int pageNum, GfxState *state);
+  virtual void startPage(int pageNum, GfxState *state, XRef *xref);
 
   // End a page.
   virtual void endPage();
@@ -399,6 +399,7 @@ private:
   GBool skipRotatedText;
 
   PDFDoc *doc;			// the current document
+  XRef *xref;       // the xref of the current document
 
   SplashBitmap *bitmap;
   Splash *splash;
diff --git a/poppler/Stream.cc b/poppler/Stream.cc
index 4cb3326..482bcbf 100644
--- a/poppler/Stream.cc
+++ b/poppler/Stream.cc
@@ -23,7 +23,7 @@
 // Copyright (C) 2010 Hib Eris <hib at hiberis.nl>
 // Copyright (C) 2010 Tomas Hoger <thoger at redhat.com>
 // Copyright (C) 2011, 2012 William Bader <williambader at hotmail.com>
-// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2012 Oliver Sander <sander at mi.fu-berlin.de>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
 // Copyright (C) 2012 Even Rouault <even.rouault at mines-paris.org>
@@ -86,15 +86,42 @@ static GBool setDJSYSFLAGS = gFalse;
 #endif
 #endif
 
+#if MULTITHREADED
+#  define lockStream   gLockMutex(&mutex)
+#  define unlockStream gUnlockMutex(&mutex)
+#else
+#  define lockStream
+#  define unlockStream
+#endif
 //------------------------------------------------------------------------
 // Stream (base class)
 //------------------------------------------------------------------------
 
 Stream::Stream() {
   ref = 1;
+#if MULTITHREADED
+  gInitMutex(&mutex);
+#endif
 }
 
 Stream::~Stream() {
+#if MULTITHREADED
+  gDestroyMutex(&mutex);
+#endif
+}
+
+int Stream::incRef() {
+  lockStream;
+  ++ref;
+  unlockStream;
+  return ref;
+}
+
+int Stream::decRef() {
+  lockStream;
+  --ref;
+  unlockStream;
+  return ref;
 }
 
 void Stream::close() {
@@ -139,34 +166,34 @@ GooString *Stream::getPSFilter(int psLevel, const char *indent) {
   return new GooString();
 }
 
-Stream *Stream::addFilters(Object *dict) {
+Stream *Stream::addFilters(Object *dict, int recursion) {
   Object obj, obj2;
   Object params, params2;
   Stream *str;
   int i;
 
   str = this;
-  dict->dictLookup("Filter", &obj);
+  dict->dictLookup("Filter", &obj, recursion);
   if (obj.isNull()) {
     obj.free();
     dict->dictLookup("F", &obj);
   }
-  dict->dictLookup("DecodeParms", &params);
+  dict->dictLookup("DecodeParms", &params, recursion);
   if (params.isNull()) {
     params.free();
     dict->dictLookup("DP", &params);
   }
   if (obj.isName()) {
-    str = makeFilter(obj.getName(), str, &params);
+    str = makeFilter(obj.getName(), str, &params, recursion);
   } else if (obj.isArray()) {
     for (i = 0; i < obj.arrayGetLength(); ++i) {
       obj.arrayGet(i, &obj2);
       if (params.isArray())
-	params.arrayGet(i, &params2);
+	params.arrayGet(i, &params2, recursion);
       else
 	params2.initNull();
       if (obj2.isName()) {
-	str = makeFilter(obj2.getName(), str, &params2);
+	str = makeFilter(obj2.getName(), str, &params2, recursion);
       } else {
 	error(errSyntaxError, getPos(), "Bad filter name");
 	str = new EOFStream(str);
@@ -183,7 +210,7 @@ Stream *Stream::addFilters(Object *dict) {
   return str;
 }
 
-Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
+Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursion) {
   int pred;			// parameters
   int colors;
   int bits;
@@ -205,23 +232,23 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
     bits = 8;
     early = 1;
     if (params->isDict()) {
-      params->dictLookup("Predictor", &obj);
+      params->dictLookup("Predictor", &obj, recursion);
       if (obj.isInt())
 	pred = obj.getInt();
       obj.free();
-      params->dictLookup("Columns", &obj);
+      params->dictLookup("Columns", &obj, recursion);
       if (obj.isInt())
 	columns = obj.getInt();
       obj.free();
-      params->dictLookup("Colors", &obj);
+      params->dictLookup("Colors", &obj, recursion);
       if (obj.isInt())
 	colors = obj.getInt();
       obj.free();
-      params->dictLookup("BitsPerComponent", &obj);
+      params->dictLookup("BitsPerComponent", &obj, recursion);
       if (obj.isInt())
 	bits = obj.getInt();
       obj.free();
-      params->dictLookup("EarlyChange", &obj);
+      params->dictLookup("EarlyChange", &obj, recursion);
       if (obj.isInt())
 	early = obj.getInt();
       obj.free();
@@ -238,37 +265,37 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
     endOfBlock = gTrue;
     black = gFalse;
     if (params->isDict()) {
-      params->dictLookup("K", &obj);
+      params->dictLookup("K", &obj, recursion);
       if (obj.isInt()) {
 	encoding = obj.getInt();
       }
       obj.free();
-      params->dictLookup("EndOfLine", &obj);
+      params->dictLookup("EndOfLine", &obj, recursion);
       if (obj.isBool()) {
 	endOfLine = obj.getBool();
       }
       obj.free();
-      params->dictLookup("EncodedByteAlign", &obj);
+      params->dictLookup("EncodedByteAlign", &obj, recursion);
       if (obj.isBool()) {
 	byteAlign = obj.getBool();
       }
       obj.free();
-      params->dictLookup("Columns", &obj);
+      params->dictLookup("Columns", &obj, recursion);
       if (obj.isInt()) {
 	columns = obj.getInt();
       }
       obj.free();
-      params->dictLookup("Rows", &obj);
+      params->dictLookup("Rows", &obj, recursion);
       if (obj.isInt()) {
 	rows = obj.getInt();
       }
       obj.free();
-      params->dictLookup("EndOfBlock", &obj);
+      params->dictLookup("EndOfBlock", &obj, recursion);
       if (obj.isBool()) {
 	endOfBlock = obj.getBool();
       }
       obj.free();
-      params->dictLookup("BlackIs1", &obj);
+      params->dictLookup("BlackIs1", &obj, recursion);
       if (obj.isBool()) {
 	black = obj.getBool();
       }
@@ -279,7 +306,7 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
   } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) {
     colorXform = -1;
     if (params->isDict()) {
-      if (params->dictLookup("ColorTransform", &obj)->isInt()) {
+      if (params->dictLookup("ColorTransform", &obj, recursion)->isInt()) {
 	colorXform = obj.getInt();
       }
       obj.free();
@@ -291,19 +318,19 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
     colors = 1;
     bits = 8;
     if (params->isDict()) {
-      params->dictLookup("Predictor", &obj);
+      params->dictLookup("Predictor", &obj, recursion);
       if (obj.isInt())
 	pred = obj.getInt();
       obj.free();
-      params->dictLookup("Columns", &obj);
+      params->dictLookup("Columns", &obj, recursion);
       if (obj.isInt())
 	columns = obj.getInt();
       obj.free();
-      params->dictLookup("Colors", &obj);
+      params->dictLookup("Colors", &obj, recursion);
       if (obj.isInt())
 	colors = obj.getInt();
       obj.free();
-      params->dictLookup("BitsPerComponent", &obj);
+      params->dictLookup("BitsPerComponent", &obj, recursion);
       if (obj.isInt())
 	bits = obj.getInt();
       obj.free();
@@ -311,7 +338,7 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
     str = new FlateStream(str, pred, columns, colors, bits);
   } else if (!strcmp(name, "JBIG2Decode")) {
     if (params->isDict()) {
-      params->dictLookup("JBIG2Globals", &globals);
+      params->dictLookup("JBIG2Globals", &globals, recursion);
     }
     str = new JBIG2Stream(str, &globals);
     globals.free();
@@ -726,13 +753,29 @@ GBool StreamPredictor::getNextLine() {
 }
 
 //------------------------------------------------------------------------
+// UniqueFileStream
+//------------------------------------------------------------------------
+
+UniqueFileStream::UniqueFileStream(FILE *fA, char *fileNameA, Guint startA, GBool limitedA,
+		       Guint lengthA, Object *dictA):
+    FileStream(fA, fileNameA, startA, limitedA, lengthA, dictA) {
+  f = fopen(fileName, "rb");
+}
+
+UniqueFileStream::~UniqueFileStream() {
+  close();
+  fclose(f);
+}
+
+//------------------------------------------------------------------------
 // FileStream
 //------------------------------------------------------------------------
 
-FileStream::FileStream(FILE *fA, Guint startA, GBool limitedA,
+FileStream::FileStream(FILE *fA, char *fileNameA, Guint startA, GBool limitedA,
 		       Guint lengthA, Object *dictA):
     BaseStream(dictA, lengthA) {
   f = fA;
+  fileName = fileNameA;
   start = startA;
   limited = limitedA;
   length = lengthA;
@@ -746,9 +789,13 @@ FileStream::~FileStream() {
   close();
 }
 
+BaseStream *FileStream::copy() {
+  return new UniqueFileStream(f, fileName, start, limited, length, &dict);
+}
+
 Stream *FileStream::makeSubStream(Guint startA, GBool limitedA,
 				  Guint lengthA, Object *dictA) {
-  return new FileStream(f, startA, limitedA, lengthA, dictA);
+  return new FileStream(f, fileName, startA, limitedA, lengthA, dictA);
 }
 
 void FileStream::reset() {
@@ -870,6 +917,11 @@ CachedFileStream::~CachedFileStream()
   cc->decRefCnt();
 }
 
+BaseStream *CachedFileStream::copy() {
+  cc->incRefCnt();
+  return new CachedFileStream(cc, start, limited, length, &dict);
+}
+
 Stream *CachedFileStream::makeSubStream(Guint startA, GBool limitedA,
         Guint lengthA, Object *dictA)
 {
@@ -965,6 +1017,10 @@ MemStream::~MemStream() {
   }
 }
 
+BaseStream *MemStream::copy() {
+  return new MemStream(buf, start, length, &dict);
+}
+
 Stream *MemStream::makeSubStream(Guint startA, GBool limited,
 				 Guint lengthA, Object *dictA) {
   MemStream *subStr;
@@ -1039,6 +1095,11 @@ EmbedStream::EmbedStream(Stream *strA, Object *dictA,
 EmbedStream::~EmbedStream() {
 }
 
+BaseStream *EmbedStream::copy() {
+  error(errInternal, -1, "Called copy() on EmbedStream");
+  return NULL;
+}
+
 Stream *EmbedStream::makeSubStream(Guint start, GBool limitedA,
 				   Guint lengthA, Object *dictA) {
   error(errInternal, -1, "Called makeSubStream() on EmbedStream");
diff --git a/poppler/Stream.h b/poppler/Stream.h
index 20b5fd6..9dd5459 100644
--- a/poppler/Stream.h
+++ b/poppler/Stream.h
@@ -20,7 +20,7 @@
 // Copyright (C) 2009 Stefan Thomas <thomas at eload24.com>
 // Copyright (C) 2010 Hib Eris <hib at hiberis.nl>
 // Copyright (C) 2011, 2012 William Bader <williambader at hotmail.com>
-// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
 //
 // To see a description of the changes please see the Changelog file that
@@ -39,6 +39,7 @@
 #include <stdio.h>
 #include "goo/gtypes.h"
 #include "Object.h"
+#include "goo/GooMutex.h"
 
 class BaseStream;
 class CachedFile;
@@ -98,8 +99,8 @@ public:
   virtual ~Stream();
 
   // Reference counting.
-  int incRef() { return ++ref; }
-  int decRef() { return --ref; }
+  int incRef();
+  int decRef();
 
   // Get kind of stream.
   virtual StreamKind getKind() = 0;
@@ -218,15 +219,18 @@ public:
 
   // Add filters to this stream according to the parameters in <dict>.
   // Returns the new stream.
-  Stream *addFilters(Object *dict);
+  Stream *addFilters(Object *dict, int recursion = 0);
 
 private:
   virtual GBool hasGetChars() { return false; }
   virtual int getChars(int nChars, Guchar *buffer);
 
-  Stream *makeFilter(char *name, Stream *str, Object *params);
+  Stream *makeFilter(char *name, Stream *str, Object *params, int recursion = 0);
 
   int ref;			// reference count
+#if MULTITHREADED
+  GooMutex mutex;
+#endif
 };
 
 
@@ -299,6 +303,7 @@ public:
 
   BaseStream(Object *dictA, Guint lengthA);
   virtual ~BaseStream();
+  virtual BaseStream *copy() = 0;
   virtual Stream *makeSubStream(Guint start, GBool limited,
 				Guint length, Object *dict) = 0;
   virtual void setPos(Guint pos, int dir = 0) = 0;
@@ -316,9 +321,6 @@ public:
 protected:
 
   Guint length;
-
-private:
-
   Object dict;
 };
 
@@ -439,9 +441,10 @@ private:
 class FileStream: public BaseStream {
 public:
 
-  FileStream(FILE *fA, Guint startA, GBool limitedA,
+  FileStream(FILE *fA, char *fileName, Guint startA, GBool limitedA,
 	     Guint lengthA, Object *dictA);
   virtual ~FileStream();
+  virtual BaseStream *copy();
   virtual Stream *makeSubStream(Guint startA, GBool limitedA,
 				Guint lengthA, Object *dictA);
   virtual StreamKind getKind() { return strFile; }
@@ -486,7 +489,10 @@ private:
       return n;
     }
 
+protected:
   FILE *f;
+  char *fileName;
+private:
   Guint start;
   GBool limited;
   char buf[fileStreamBufSize];
@@ -497,6 +503,14 @@ private:
   GBool saved;
 };
 
+class UniqueFileStream: public FileStream {
+public:
+
+  UniqueFileStream(FILE *fA, char *fileNameA, Guint startA, GBool limitedA,
+	     Guint lengthA, Object *dictA);
+  virtual ~UniqueFileStream();
+};
+
 //------------------------------------------------------------------------
 // CachedFileStream
 //------------------------------------------------------------------------
@@ -509,6 +523,7 @@ public:
   CachedFileStream(CachedFile *ccA, Guint startA, GBool limitedA,
 	     Guint lengthA, Object *dictA);
   virtual ~CachedFileStream();
+  virtual BaseStream *copy();
   virtual Stream *makeSubStream(Guint startA, GBool limitedA,
 				Guint lengthA, Object *dictA);
   virtual StreamKind getKind() { return strCachedFile; }
@@ -551,6 +566,7 @@ public:
 
   MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA);
   virtual ~MemStream();
+  virtual BaseStream *copy();
   virtual Stream *makeSubStream(Guint start, GBool limited,
 				Guint lengthA, Object *dictA);
   virtual StreamKind getKind() { return strWeird; }
@@ -599,6 +615,7 @@ public:
 
   EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Guint lengthA);
   virtual ~EmbedStream();
+  virtual BaseStream *copy();
   virtual Stream *makeSubStream(Guint start, GBool limitedA,
 				Guint lengthA, Object *dictA);
   virtual StreamKind getKind() { return str->getKind(); }
diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc
index b0b53fc..3ff9b70 100644
--- a/poppler/TextOutputDev.cc
+++ b/poppler/TextOutputDev.cc
@@ -33,6 +33,7 @@
 // Copyright (C) 2012 Jason Crain <jason at aquaticape.us>
 // Copyright (C) 2012 Peter Breitenlohner <peb at mppmu.mpg.de>
 // Copyright (C) 2013 José Aliste <jaliste at src.gnome.org>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -4267,7 +4268,7 @@ TextSelectionPainter::TextSelectionPainter(TextPage *page,
 
   state = new GfxState(72 * scale, 72 * scale, &box, rotation, gFalse);
 
-  out->startPage (0, state);
+  out->startPage (0, state, NULL);
   out->setDefaultCTM (state->getCTM());
 
   state->setTextMat(1, 0, 0, -1, 0, 0);
@@ -5313,7 +5314,7 @@ TextOutputDev::~TextOutputDev() {
   delete actualText;
 }
 
-void TextOutputDev::startPage(int pageNum, GfxState *state) {
+void TextOutputDev::startPage(int pageNum, GfxState *state, XRef *xref) {
   text->startPage(state);
 }
 
diff --git a/poppler/TextOutputDev.h b/poppler/TextOutputDev.h
index 100f23e..38be378 100644
--- a/poppler/TextOutputDev.h
+++ b/poppler/TextOutputDev.h
@@ -20,6 +20,7 @@
 // Copyright (C) 2008, 2010 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2010 Brian Ewins <brian.ewins at gmail.com>
 // Copyright (C) 2012 Jason Crain <jason at aquaticape.us>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -718,7 +719,7 @@ public:
   //----- initialization and control
 
   // Start a page.
-  virtual void startPage(int pageNum, GfxState *state);
+  virtual void startPage(int pageNum, GfxState *state, XRef *xref);
 
   // End a page.
   virtual void endPage();
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index 81e939a..0ff17f0 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -20,7 +20,7 @@
 // Copyright (C) 2007 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2009, 2010 Ilya Gorenbein <igorenbein at finjan.com>
 // Copyright (C) 2010 Hib Eris <hib at hiberis.nl>
-// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag at kabelmail.de>
+// Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag at kabelmail.de>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
 //
 // To see a description of the changes please see the Changelog file that
@@ -65,6 +65,14 @@
 #define permHighResPrint  (1<<11) // bit 12
 #define defPermFlags 0xfffc
 
+#if MULTITHREADED
+#  define lockXRef   gLockMutex(&mutex)
+#  define unlockXRef gUnlockMutex(&mutex)
+#else
+#  define lockXRef
+#  define unlockXRef
+#endif
+
 //------------------------------------------------------------------------
 // ObjectStream
 //------------------------------------------------------------------------
@@ -74,7 +82,7 @@ public:
 
   // Create an object stream, using object number <objStrNum>,
   // generation 0.
-  ObjectStream(XRef *xref, int objStrNumA);
+  ObjectStream(XRef *xref, int objStrNumA, int recursion = 0);
 
   GBool isOk() { return ok; }
 
@@ -127,7 +135,7 @@ class ObjectStreamItem : public PopplerCacheItem
     ObjectStream *objStream;
 };
 
-ObjectStream::ObjectStream(XRef *xref, int objStrNumA) {
+ObjectStream::ObjectStream(XRef *xref, int objStrNumA, int recursion) {
   Stream *str;
   Parser *parser;
   int *offsets;
@@ -140,11 +148,11 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) {
   objNums = NULL;
   ok = gFalse;
 
-  if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) {
+  if (!xref->fetch(objStrNum, 0, &objStr, recursion)->isStream()) {
     goto err1;
   }
 
-  if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) {
+  if (!objStr.streamGetDict()->lookup("N", &obj1, recursion)->isInt()) {
     obj1.free();
     goto err1;
   }
@@ -154,7 +162,7 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) {
     goto err1;
   }
 
-  if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) {
+  if (!objStr.streamGetDict()->lookup("First", &obj1, recursion)->isInt()) {
     obj1.free();
     goto err1;
   }
@@ -257,6 +265,9 @@ Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) {
 //------------------------------------------------------------------------
 
 void XRef::init() {
+#if MULTITHREADED
+  gInitMutex(&mutex);
+#endif
   ok = gTrue;
   errCode = errNone;
   entries = NULL;
@@ -272,6 +283,7 @@ void XRef::init() {
   permFlags = defPermFlags;
   ownerPasswordOk = gFalse;
   rootNum = -1;
+  strOwner = gFalse;
 }
 
 XRef::XRef() {
@@ -375,6 +387,59 @@ XRef::~XRef() {
   if (objStrs) {
     delete objStrs;
   }
+  if (strOwner) {
+    delete str;
+  }
+#if MULTITHREADED
+  gDestroyMutex(&mutex);
+#endif
+}
+
+XRef *XRef::copy() {
+  XRef *xref = new XRef();
+  xref->str = str->copy();
+  xref->strOwner = gTrue;
+  xref->encrypted = encrypted;
+  xref->permFlags = permFlags;
+  xref->ownerPasswordOk = ownerPasswordOk;
+  xref->rootGen = rootGen;
+  xref->rootNum = rootNum;
+
+  xref->start = start;
+  xref->prevXRefOffset = prevXRefOffset;
+  xref->mainXRefEntriesOffset = mainXRefEntriesOffset;
+  xref->xRefStream = xRefStream;
+  trailerDict.copy(&xref->trailerDict);
+  xref->encAlgorithm = encAlgorithm;
+  xref->encRevision = encRevision;
+  xref->encVersion = encVersion;
+  xref->permFlags = permFlags;
+  xref->keyLength = keyLength;
+  xref->permFlags = permFlags;
+  for (int i = 0; i < 32; i++) {
+    xref->fileKey[i] = fileKey[i];
+  }
+
+  if (xref->reserve(size) == 0) {
+    error(errSyntaxError, -1, "unable to allocate {0:d} entries", size);
+    return NULL;
+  }
+  xref->size = size;
+  for (int i = 0; i < size; ++i) {
+    xref->entries[i].offset = entries[i].offset;
+    xref->entries[i].type = entries[i].type;
+    xref->entries[i].obj.initNull ();
+    xref->entries[i].flags = entries[i].flags;
+    xref->entries[i].gen = entries[i].gen;
+  }
+  xref->streamEndsLen = streamEndsLen;
+  if (streamEndsLen  != 0) {
+    xref->streamEnds = (Guint *)gmalloc(streamEndsLen * sizeof(Guint));
+    for (int i = 0; i < streamEndsLen; i++) {
+      xref->streamEnds[i] = streamEnds[i];
+    }
+  }
+  return xref;
 }
 
 int XRef::reserve(int newSize)
@@ -1036,6 +1101,7 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
   Parser *parser;
   Object obj1, obj2, obj3;
 
+  if (recursion == 0) lockXRef;
   // check for bogus ref - this can happen in corrupted PDF files
   if (num < 0 || num >= size) {
     goto err;
@@ -1044,6 +1110,7 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
   e = getEntry(num);
   if(!e->obj.isNull ()) { //check for updated object
     obj = e->obj.copy(obj);
+    if (recursion == 0) unlockXRef;
     return obj;
   }
 
@@ -1124,7 +1191,7 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
     }
 
     if (!objStr) {
-      objStr = new ObjectStream(this, e->offset);
+      objStr = new ObjectStream(this, e->offset, recursion + 1);
       if (!objStr->isOk()) {
 	delete objStr;
 	objStr = NULL;
@@ -1145,12 +1212,22 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
     goto err;
   }
   
+  if (recursion == 0) unlockXRef;
   return obj;
 
  err:
+  if (recursion == 0) unlockXRef;
   return obj->initNull();
 }
 
+void XRef::lock() {
+  lockXRef;
+}
+
+void XRef::unlock() {
+  unlockXRef;
+}
+
 Object *XRef::getDocInfo(Object *obj) {
   return trailerDict.dictLookup("Info", obj);
 }
@@ -1205,6 +1282,7 @@ int XRef::getNumEntry(Guint offset)
 }
 
 void XRef::add(int num, int gen, Guint offs, GBool used) {
+  lockXRef;
   if (num >= size) {
     if (num >= capacity) {
       entries = (XRefEntry *)greallocn(entries, num + 1, sizeof(XRefEntry));
@@ -1230,17 +1308,21 @@ void XRef::add(int num, int gen, Guint offs, GBool used) {
     e->type = xrefEntryFree;
     e->offset = 0;
   }
+  unlockXRef;
 }
 
 void XRef::setModifiedObject (Object* o, Ref r) {
+  lockXRef;
   if (r.num < 0 || r.num >= size) {
     error(errInternal, -1,"XRef::setModifiedObject on unknown ref: {0:d}, {1:d}\n", r.num, r.gen);
+    unlockXRef;
     return;
   }
   XRefEntry *e = getEntry(r.num);
   e->obj.free();
   o->copy(&(e->obj));
   e->setFlag(XRefEntry::Updated, gTrue);
+  unlockXRef;
 }
 
 Ref XRef::addIndirectObject (Object* o) {
@@ -1274,8 +1356,10 @@ Ref XRef::addIndirectObject (Object* o) {
 }
 
 void XRef::removeIndirectObject(Ref r) {
+  lockXRef;
   if (r.num < 0 || r.num >= size) {
     error(errInternal, -1,"XRef::removeIndirectObject on unknown ref: {0:d}, {1:d}\n", r.num, r.gen);
+    unlockXRef;
     return;
   }
   XRefEntry *e = getEntry(r.num);
@@ -1285,6 +1369,7 @@ void XRef::removeIndirectObject(Ref r) {
   e->type = xrefEntryFree;
   e->gen++;
   e->setFlag(XRefEntry::Updated, gTrue);
+  unlockXRef;
 }
 
 void XRef::writeXRef(XRef::XRefWriter *writer, GBool writeAllEntries) {
diff --git a/poppler/XRef.h b/poppler/XRef.h
index 9af4a13..cbef85b 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -19,7 +19,7 @@
 // Copyright (C) 2007 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2010 Ilya Gorenbein <igorenbein at finjan.com>
 // Copyright (C) 2010 Hib Eris <hib at hiberis.nl>
-// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag at kabelmail.de>
+// Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag at kabelmail.de>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
 //
 // To see a description of the changes please see the Changelog file that
@@ -34,7 +34,10 @@
 #pragma interface
 #endif
 
+#include <config.h>
+#include "poppler-config.h"
 #include "goo/gtypes.h"
+#include "goo/GooMutex.h"
 #include "Object.h"
 #include "Stream.h"
 
@@ -100,6 +103,9 @@ public:
   // Destructor.
   ~XRef();
 
+  // Copy xref but with new base stream!
+  XRef *copy();
+
   // Is xref table valid?
   GBool isOk() { return ok; }
 
@@ -180,6 +186,10 @@ public:
   // Output XRef stream contents to GooString and fill trailerDict fields accordingly
   void writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref);
 
+  // to be thread safe during write where changes are not allowed
+  void lock();
+  void unlock();
+
 private:
 
   BaseStream *str;		// input stream
@@ -209,6 +219,10 @@ private:
   GBool xRefStream;		// true if last XRef section is a stream
   Guint mainXRefOffset;		// position of the main XRef table/stream
   GBool scannedSpecialFlags;	// true if scanSpecialFlags has been called
+  GBool strOwner;     // true if str is owned by the instance
+#if MULTITHREADED
+  GooMutex mutex;
+#endif
 
   void init();
   int reserve(int newSize);
diff --git a/qt4/src/poppler-document.cc b/qt4/src/poppler-document.cc
index ee56ed6..7d13656 100644
--- a/qt4/src/poppler-document.cc
+++ b/qt4/src/poppler-document.cc
@@ -5,7 +5,7 @@
  * Copyright (C) 2006-2010, Pino Toscano <pino at kde.org>
  * Copyright (C) 2010, 2011 Hib Eris <hib at hiberis.nl>
  * Copyright (C) 2012 Koji Otani <sho at bbr.jp>
- * Copyright (C) 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+ * Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
  * Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -239,8 +239,10 @@ namespace Poppler {
 	if (fi.isEmbedded())
 	{
 		Object refObj, strObj;
+		XRef *xref = m_doc->doc->getXRef()->copy();
+
 		refObj.initRef(fi.m_data->embRef.num, fi.m_data->embRef.gen);
-		refObj.fetch(m_doc->doc->getXRef(), &strObj);
+		refObj.fetch(xref, &strObj);
 		refObj.free();
 		if (strObj.isStream())
 		{
@@ -253,6 +255,7 @@ namespace Poppler {
 			strObj.streamClose();
 		}
 		strObj.free();
+		delete xref;
 	}
 	return result;
     }
@@ -265,7 +268,8 @@ namespace Poppler {
 	if ( m_doc->locked )
 	    return QString();
 
-	m_doc->doc->getDocInfo( &info );
+	QScopedPointer<XRef> xref(m_doc->doc->getXRef()->copy());
+	xref->getDocInfo(&info);
 	if ( !info.isDict() )
 	    return QString();
 
@@ -295,7 +299,8 @@ namespace Poppler {
 	if ( m_doc->locked )
 	    return QStringList();
 
-	m_doc->doc->getDocInfo( &info );
+	QScopedPointer<XRef> xref(m_doc->doc->getXRef()->copy());
+	xref->getDocInfo(&info);
 	if ( !info.isDict() )
 	    return QStringList();
 
@@ -317,7 +322,8 @@ namespace Poppler {
 	    return QDateTime();
 
 	Object info;
-	m_doc->doc->getDocInfo( &info );
+	QScopedPointer<XRef> xref(m_doc->doc->getXRef()->copy());
+	xref->getDocInfo(&info);
 	if ( !info.isDict() ) {
 	    info.free();
 	    return QDateTime();
@@ -521,7 +527,6 @@ namespace Poppler {
 
     void Document::setRenderHint( Document::RenderHint hint, bool on )
     {
-        const bool touchesAntialias = hint & ( Document::Antialiasing | Document::TextAntialiasing | Document::TextHinting );
         const bool touchesOverprinting = hint & Document::OverprintPreview;
         
         int hintForOperation = hint;
@@ -533,12 +538,6 @@ namespace Poppler {
         else
             m_doc->m_hints &= ~hintForOperation;
 
-        // the only way to set antialiasing for Splash is on creation
-        if ( m_doc->m_backend == Document::SplashBackend && (touchesAntialias || touchesOverprinting) )
-        {
-            delete m_doc->m_outputDev;
-            m_doc->m_outputDev = NULL;
-        }
     }
 
     Document::RenderHints Document::renderHints() const
diff --git a/qt4/src/poppler-page.cc b/qt4/src/poppler-page.cc
index 5475614..f9ac443 100644
--- a/qt4/src/poppler-page.cc
+++ b/qt4/src/poppler-page.cc
@@ -13,7 +13,7 @@
  * Copyright (C) 2012 Tobias Koenig <tokoe at kdab.com>
  * Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
  * Copyright (C) 2012 Adam Reichold <adamreichold at myopera.com>
- * Copyright (C) 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+ * Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -258,10 +258,59 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
     case Poppler::Document::SplashBackend:
     {
 #if defined(HAVE_SPLASH)
-      SplashOutputDev *splash_output = static_cast<SplashOutputDev *>(m_page->parentDoc->getOutputDev());
+      SplashColor bgColor;
+#if defined(SPLASH_CMYK)
+      GBool overprint = m_page->parentDoc->m_hints & Document::OverprintPreview ? gTrue : gFalse;
+      globalParams->setOverprintPreview(overprint);
+      if (overprint)
+      {
+        Guchar c, m, y, k;
+
+        c = 255 - m_page->parentDoc->paperColor.blue();
+        m = 255 - m_page->parentDoc->paperColor.red();
+        y = 255 - m_page->parentDoc->paperColor.green();
+        k = c;
+        if (m < k) {
+          k = m;
+        }
+        if (y < k) {
+          k = y;
+        }
+        bgColor[0] = c - k;
+        bgColor[1] = m - k;
+        bgColor[2] = y - k;
+        bgColor[3] = k;
+        for (int i = 4; i < SPOT_NCOMPS + 4; i++) {
+          bgColor[i] = 0;
+        }
+      }
+      else
+#endif
+      {
+        bgColor[0] = m_page->parentDoc->paperColor.blue();
+        bgColor[1] = m_page->parentDoc->paperColor.green();
+        bgColor[2] = m_page->parentDoc->paperColor.red();
+      }
+ 
+      GBool AA = m_page->parentDoc->m_hints & Document::TextAntialiasing ? gTrue : gFalse;
+
+      SplashOutputDev * splash_output = new SplashOutputDev(
+#if defined(SPLASH_CMYK)
+                      (overprint) ? splashModeDeviceN8 : splashModeXBGR8,
+#else
+                      splashModeXBGR8,
+#endif 
+                      4, gFalse, bgColor, gTrue, AA);
+
+      splash_output->setVectorAntialias(m_page->parentDoc->m_hints & Document::Antialiasing ? gTrue : gFalse);
+      splash_output->setFreeTypeHinting(m_page->parentDoc->m_hints & Document::TextHinting ? gTrue : gFalse, 
+                                        m_page->parentDoc->m_hints & Document::TextSlightHinting ? gTrue : gFalse);
+
+      splash_output->startDoc(m_page->parentDoc->doc);      
 
       m_page->parentDoc->doc->displayPageSlice(splash_output, m_page->index + 1, xres, yres,
-						 rotation, false, true, false, x, y, w, h);
+                                               rotation, false, true, false, x, y, w, h,
+                                               NULL, NULL, NULL, NULL, gTrue);
 
       SplashBitmap *bitmap = splash_output->getBitmap();
       int bw = bitmap->getWidth();
@@ -291,8 +340,7 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
         QImage tmpimg( dataPtr, bw, bh, QImage::Format_ARGB32 );
         img = tmpimg.copy();
       }
-      // unload underlying xpdf bitmap
-      splash_output->startPage( 0, NULL );
+      delete splash_output;
 #endif
       break;
     }
@@ -381,7 +429,8 @@ QString Page::text(const QRectF &r, TextLayout textLayout) const
   const GBool rawOrder = textLayout == RawOrderLayout;
   output_dev = new TextOutputDev(0, gFalse, 0, rawOrder, gFalse);
   m_page->parentDoc->doc->displayPageSlice(output_dev, m_page->index + 1, 72, 72,
-      0, false, true, false, -1, -1, -1, -1);
+      0, false, true, false, -1, -1, -1, -1,
+      NULL, NULL, NULL, NULL, gTrue);
   if (r.isNull())
   {
     rect = m_page->page->getCropBox();
@@ -482,7 +531,8 @@ QList<TextBox*> Page::textList(Rotation rotate) const
   int rotation = (int)rotate * 90;
 
   m_page->parentDoc->doc->displayPageSlice(output_dev, m_page->index + 1, 72, 72,
-      rotation, false, false, false, -1, -1, -1, -1);
+      rotation, false, false, false, -1, -1, -1, -1,
+      NULL, NULL, NULL, NULL, gTrue);
 
   TextWordList *word_list = output_dev->makeWordList();
   
diff --git a/qt4/src/poppler-private.cc b/qt4/src/poppler-private.cc
index ffb5b92..7022147 100644
--- a/qt4/src/poppler-private.cc
+++ b/qt4/src/poppler-private.cc
@@ -2,6 +2,7 @@
  * Copyright (C) 2005, Net Integration Technologies, Inc.
  * Copyright (C) 2006, 2011 by Albert Astals Cid <aacid at kde.org>
  * Copyright (C) 2008, 2010, 2011 by Pino Toscano <pino at kde.org>
+ * Copyright (C) 2013 by Thomas Freitag <Thomas.Freitag at alfa.de>
  * Inspired on code by
  * Copyright (C) 2004 by Albert Astals Cid <tsdgeos at terra.es>
  * Copyright (C) 2004 by Enrico Ros <eros.kde at email.it>
@@ -226,7 +227,6 @@ namespace Debug {
         qDeleteAll(m_embeddedFiles);
         delete (OptContentModel *)m_optContentModel;
         delete doc;
-        delete m_outputDev;
         delete m_fontInfoIterator;
     
         count --;
@@ -241,7 +241,6 @@ namespace Debug {
     {
         m_fontInfoIterator = 0;
         m_backend = Document::SplashBackend;
-        m_outputDev = 0;
         paperColor = Qt::white;
         m_hints = 0;
         m_optContentModel = 0;
diff --git a/qt4/src/poppler-private.h b/qt4/src/poppler-private.h
index 5a9e1b8..5759a4e 100644
--- a/qt4/src/poppler-private.h
+++ b/qt4/src/poppler-private.h
@@ -5,7 +5,7 @@
  * Copyright (C) 2007-2009, 2011 by Pino Toscano <pino at kde.org>
  * Copyright (C) 2011 Andreas Hartmetz <ahartmetz at gmail.com>
  * Copyright (C) 2011 Hib Eris <hib at hiberis.nl>
- * Copyright (C) 2012 Thomas Freitag <Thomas.Freitag at alfa.de>
+ * Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
  * Inspired on code by
  * Copyright (C) 2004 by Albert Astals Cid <tsdgeos at terra.es>
  * Copyright (C) 2004 by Enrico Ros <eros.kde at email.it>
@@ -113,82 +113,11 @@ namespace Poppler {
 	
 	~DocumentData();
 	
-	OutputDev *getOutputDev()
-	{
-		if (!m_outputDev)
-		{
-			switch (m_backend)
-			{
-			case Document::ArthurBackend:
-			// create a splash backend even in case of the Arthur Backend
-			case Document::SplashBackend:
-			{
-#if defined(HAVE_SPLASH)
-			SplashColor bgColor;
-			GBool overprint = m_hints & Document::OverprintPreview ? gTrue : gFalse;
-			globalParams->setOverprintPreview(overprint);
-#if defined(SPLASH_CMYK)
-			if (overprint)
-			{
-				Guchar c, m, y, k;
-
-				c = 255 - paperColor.blue();
-				m = 255 - paperColor.red();
-				y = 255 - paperColor.green();
-				k = c;
-				if (m < k) {
-					k = m;
-				}
-				if (y < k) {
-					k = y;
-				}
-				bgColor[0] = c - k;
-				bgColor[1] = m - k;
-				bgColor[2] = y - k;
-				bgColor[3] = k;
-				for (int i = 4; i < SPOT_NCOMPS + 4; i++) {
-					bgColor[i] = 0;
-				}
-			}
-			else
-#endif
-			{
-				bgColor[0] = paperColor.blue();
-				bgColor[1] = paperColor.green();
-				bgColor[2] = paperColor.red();
-			}
-			GBool AA = m_hints & Document::TextAntialiasing ? gTrue : gFalse;
-			SplashOutputDev * splashOutputDev = new SplashOutputDev(
-#if defined(SPLASH_CMYK)
-				(overprint) ? splashModeDeviceN8 : splashModeXBGR8,
-#else
-				splashModeXBGR8,
-#endif 
-				4, gFalse, bgColor, gTrue, AA);
-			splashOutputDev->setVectorAntialias(m_hints & Document::Antialiasing ? gTrue : gFalse);
-			splashOutputDev->setFreeTypeHinting(m_hints & Document::TextHinting ? gTrue : gFalse, m_hints & Document::TextSlightHinting ? gTrue : gFalse);
-			splashOutputDev->startDoc(doc);
-			m_outputDev = splashOutputDev;
-#endif
-			break;
-			}
-			}
-		}
-		return m_outputDev;
-	}
-	
 	void addTocChildren( QDomDocument * docSyn, QDomNode * parent, GooList * items );
 	
 	void setPaperColor(const QColor &color)
 	{
-		if (color == paperColor)
-			return;
-
 		paperColor = color;
-		
-		// Make sure the new paper color will be picked up for the next rendering
-		delete m_outputDev;
-		m_outputDev = NULL;
 	}
 	
 	void fillMembers()
@@ -212,7 +141,6 @@ namespace Poppler {
 	bool locked;
 	FontIterator *m_fontInfoIterator;
 	Document::RenderBackend m_backend;
-	OutputDev *m_outputDev;
 	QList<EmbeddedFile*> m_embeddedFiles;
 	QPointer<OptContentModel> m_optContentModel;
 	QColor paperColor;
diff --git a/test/gtk-test.cc b/test/gtk-test.cc
index a5759d7..6deb401 100644
--- a/test/gtk-test.cc
+++ b/test/gtk-test.cc
@@ -116,7 +116,7 @@ GDKSplashOutputDev::~GDKSplashOutputDev() {
 
 void GDKSplashOutputDev::clear() {
   startDoc(NULL);
-  startPage(0, NULL);
+  startPage(0, NULL, NULL);
 }
 
 void GDKSplashOutputDev::endPage() {
diff --git a/utils/HtmlOutputDev.cc b/utils/HtmlOutputDev.cc
index a718380..8d0ffea 100644
--- a/utils/HtmlOutputDev.cc
+++ b/utils/HtmlOutputDev.cc
@@ -34,6 +34,7 @@
 // Copyright (C) 2012 Ihar Filipau <thephilips at gmail.com>
 // Copyright (C) 2012 Gerald Schmidt <solahcin at gmail.com>
 // Copyright (C) 2012 Pino Toscano <pino at kde.org>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -1229,7 +1230,7 @@ HtmlOutputDev::~HtmlOutputDev() {
       delete pages;
 }
 
-void HtmlOutputDev::startPage(int pageNum, GfxState *state) {
+void HtmlOutputDev::startPage(int pageNum, GfxState *state, XRef *xref) {
 #if 0
   if (mode&&!xml){
     if (write){
diff --git a/utils/HtmlOutputDev.h b/utils/HtmlOutputDev.h
index 12b16bf..c9fd28c 100644
--- a/utils/HtmlOutputDev.h
+++ b/utils/HtmlOutputDev.h
@@ -23,6 +23,7 @@
 // Copyright (C) 2011 Stephen Reichling <sreichling at chegg.com>
 // Copyright (C) 2012 Igor Slepchin <igor.redhat at gmail.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -279,7 +280,7 @@ public:
 
 
   // Start a page.
-  virtual void startPage(int pageNum, GfxState *state);
+  virtual void startPage(int pageNum, GfxState *state, XRef *xref);
 
   // End a page.
   virtual void endPage();
diff --git a/utils/ImageOutputDev.h b/utils/ImageOutputDev.h
index 6201a24..13911ed 100644
--- a/utils/ImageOutputDev.h
+++ b/utils/ImageOutputDev.h
@@ -18,6 +18,7 @@
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2010 Jakob Voss <jakob.voss at gbv.de>
 // Copyright (C) 2012 Adrian Johnson <ajohnson at redneon.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -78,7 +79,7 @@ public:
   virtual GBool needNonText() { return gTrue; }
 
   // Start a page
-  virtual void startPage(int pageNumA, GfxState *state) 
+  virtual void startPage(int pageNumA, GfxState *state, XRef *xref) 
 			{ pageNum = pageNumA; }
  
   //---- get info about output device


More information about the poppler mailing list