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..6b2c21e 100644 --- a/poppler/Annot.cc +++ b/poppler/Annot.cc @@ -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..8197eec 100644 --- a/poppler/Array.cc +++ b/poppler/Array.cc @@ -33,6 +33,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 +49,9 @@ Array::Array(XRef *xrefA) { elems = NULL; size = length = 0; ref = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif } Array::~Array() { @@ -50,9 +60,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 +102,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 +128,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..8bb3e3f 100644 --- a/poppler/Array.h +++ b/poppler/Array.h @@ -29,6 +29,7 @@ #endif #include "Object.h" +#include "goo/GooMutex.h" class XRef; @@ -46,12 +47,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 +63,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 +74,9 @@ private: int size; // size of 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..c0abf62 100644 --- a/poppler/ArthurOutputDev.cc +++ b/poppler/ArthurOutputDev.cc @@ -122,7 +122,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(state->getPageWidth()); diff --git a/poppler/ArthurOutputDev.h b/poppler/ArthurOutputDev.h index ed631a0..8eb6f16 100644 --- a/poppler/ArthurOutputDev.h +++ b/poppler/ArthurOutputDev.h @@ -86,7 +86,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..ac1be91 100644 --- a/poppler/CairoFontEngine.cc +++ b/poppler/CairoFontEngine.cc @@ -58,6 +58,13 @@ #pragma implementation #endif +#if MULTITHREADED +# define lockFontEngine gLockMutex(&mutex) +# define unlockFontEngine gUnlockMutex(&mutex) +#else +# define lockFontEngine +# define unlockFontEngine +#endif //------------------------------------------------------------------------ // CairoFont @@ -558,6 +565,7 @@ typedef struct _type3_font_info { PDFDoc *doc; CairoFontEngine *fontEngine; GBool printing; + XRef *xref; } type3_font_info_t; static void @@ -645,7 +653,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 +682,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 +705,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 +723,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 +731,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 +764,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 +776,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 +798,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 +817,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..1e99172 100644 --- a/poppler/CairoFontEngine.h +++ b/poppler/CairoFontEngine.h @@ -85,7 +85,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 +94,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 +113,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..44a17be 100644 --- a/poppler/CairoOutputDev.cc +++ b/poppler/CairoOutputDev.cc @@ -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..4482fdf 100644 --- a/poppler/CairoOutputDev.h +++ b/poppler/CairoOutputDev.h @@ -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..4c7d053 100644 --- a/poppler/Catalog.cc +++ b/poppler/Catalog.cc @@ -55,6 +55,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 +71,9 @@ Catalog::Catalog(PDFDoc *docA) { Object obj, obj2; Object optContentProps; +#if MULTITHREADED + gInitMutex(&mutex); +#endif ok = gTrue; doc = docA; xref = doc->getXRef(); @@ -170,6 +180,9 @@ Catalog::~Catalog() { outline.free(); acroForm.free(); viewerPreferences.free(); +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif } GooString *Catalog::readMetadata() { @@ -177,6 +190,7 @@ GooString *Catalog::readMetadata() { Dict *dict; Object obj; + lockCatalog; if (metadata.isNone()) { Object catDict; @@ -191,6 +205,7 @@ GooString *Catalog::readMetadata() { } if (!metadata.isStream()) { + unlockCatalog; return NULL; } dict = metadata.streamGetDict(); @@ -202,6 +217,7 @@ GooString *Catalog::readMetadata() { s = new GooString(); metadata.getStream()->fillGooString(s); metadata.streamClose(); + unlockCatalog; return s; } @@ -209,19 +225,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 +299,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 +426,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,13 +451,16 @@ LinkDest *Catalog::findDest(GooString *name) { obj1.free(); } if (!found) { + lockCatalog; if (getDestNameTree()->lookup(name, &obj1)) found = gTrue; else obj1.free(); + unlockCatalog; } - if (!found) + if (!found) { return NULL; + } // construct LinkDest dest = 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); @@ -892,18 +953,20 @@ Form *Catalog::getForm() form->postWidgetsLoad(); } } - + if (lock) unlockCatalog; return form; } ViewerPreferences *Catalog::getViewerPreferences() { + lockCatalog; if (!viewerPrefs) { if (viewerPreferences.isDict()) { viewerPrefs = new ViewerPreferences(viewerPreferences.getDict()); } } + unlockCatalog; return viewerPrefs; } @@ -983,3 +1046,4 @@ NameTree *Catalog::getJSNameTree() return jsNameTree; } + diff --git a/poppler/Catalog.h b/poppler/Catalog.h index ef469ec..41e5e78 100644 --- a/poppler/Catalog.h +++ b/poppler/Catalog.h @@ -35,6 +35,7 @@ #endif #include "Object.h" +#include "goo/GooMutex.h" #include @@ -104,13 +105,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 +125,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 is not a destination. @@ -162,7 +163,7 @@ public: }; FormType getFormType(); - Form* getForm(); + Form* getForm(GBool lock = gTrue); ViewerPreferences *getViewerPreferences(); @@ -225,6 +226,7 @@ private: PageMode pageMode; // page mode PageLayout pageLayout; // page layout + void createPages(); // create pages for caching GBool cachePageTree(int page); // Cache first pages. Object *findDestInTree(Object *tree, GooString *name, Object *obj); @@ -232,6 +234,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..14b42ea 100644 --- a/poppler/Dict.cc +++ b/poppler/Dict.cc @@ -39,6 +39,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 +81,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 +102,24 @@ Dict::Dict(Dict* dictA) { } } +Dict *Dict::copy(XRef *xrefA) { + lockDict; + Dict *dictA = new Dict(this); + dictA->xref = xrefA; + for (int i=0; ientries[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 +128,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 +166,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 +199,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 +212,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; ival.free(); e->val = *val; + unlockDict; } else { add (copyString(key), val); } diff --git a/poppler/Dict.h b/poppler/Dict.h index 897f221..05917f2 100644 --- a/poppler/Dict.h +++ b/poppler/Dict.h @@ -32,6 +32,7 @@ #endif #include "Object.h" +#include "goo/GooMutex.h" //------------------------------------------------------------------------ // Dict @@ -48,13 +49,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 +100,9 @@ private: int size; // size of 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..4d6e4a1 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -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..0059a87 100644 --- a/poppler/Gfx.h +++ b/poppler/Gfx.h @@ -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..5164653 100644 --- a/poppler/GlobalParamsWin.cc +++ b/poppler/GlobalParamsWin.cc @@ -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..92227da 100644 --- a/poppler/Object.h +++ b/poppler/Object.h @@ -207,7 +207,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 +278,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..8d5f1a7 100644 --- a/poppler/OutputDev.h +++ b/poppler/OutputDev.h @@ -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..fbee8f6 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -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 } @@ -454,17 +474,18 @@ void PDFDoc::displayPage(OutputDev *out, int page, GBool useMediaBox, GBool crop, GBool printing, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { + GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), + void *annotDisplayDecideCbkData, GBool copyXRef) { if (globalParams->getPrintCommands()) { printf("***** page %d *****\n", page); } - if (getPage(page)) + if (getPage(page)) { getPage(page)->display(out, hDPI, vDPI, rotate, useMediaBox, crop, printing, abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); + annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef); + } } @@ -473,8 +494,8 @@ void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, GBool useMediaBox, GBool crop, GBool printing, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { + GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), + void *annotDisplayDecideCbkData) { int page; for (page = firstPage; page <= lastPage; ++page) { @@ -490,15 +511,16 @@ void PDFDoc::displayPageSlice(OutputDev *out, int page, int sliceX, int sliceY, int sliceW, int sliceH, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { - if (getPage(page)) + GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), + 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 +848,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 +864,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 +879,7 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) uxref = new XRef(); uxref->add(0, 65535, 0, gFalse); + xref->lock(); for(int i=0; igetNumObjects(); i++) { if ((xref->getEntry(i)->type == xrefEntryFree) && (xref->getEntry(i)->gen == 0)) //we skip the irrelevant free objects @@ -864,7 +891,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 +902,7 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) } } } + xref->unlock(); if (uxref->getNumObjects() == 0) { //we have nothing to update delete uxref; return; @@ -922,6 +950,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; igetNumObjects(); i++) { Object obj1; Ref ref; @@ -941,7 +970,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 +984,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 +992,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 +1592,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 +1752,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..11f5d37 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -38,6 +38,7 @@ #endif #include +#include "goo/GooMutex.h" #include "XRef.h" #include "Catalog.h" #include "Page.h" @@ -146,7 +147,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 +166,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 +327,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..9644306 100644 --- a/poppler/PSOutputDev.cc +++ b/poppler/PSOutputDev.cc @@ -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..db84281 100644 --- a/poppler/PSOutputDev.h +++ b/poppler/PSOutputDev.h @@ -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..0af527b 100644 --- a/poppler/Page.cc +++ b/poppler/Page.cc @@ -57,6 +57,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 +264,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 +353,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 +403,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 +433,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 +457,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 +473,7 @@ void Page::removeAnnot(Annot *annot) { annArray.free(); annot->removeReferencedObjects(); // Note: Might recurse in removeAnnot again annot->setPage(0, gFalse); + unlockPage; } Links *Page::getLinks() { @@ -444,11 +489,12 @@ void Page::display(OutputDev *out, double hDPI, double vDPI, GBool printing, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { + GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), + 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 +502,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 +532,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; } @@ -497,8 +543,9 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, GBool printing, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { + GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), + void *annotDisplayDecideCbkData, + GBool copyXRef) { Gfx *gfx; Object obj; Annots *annotList; @@ -511,13 +558,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 +600,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 +633,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 +720,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..0d4abfd 100644 --- a/poppler/Page.h +++ b/poppler/Page.h @@ -35,6 +35,7 @@ #endif #include "Object.h" +#include "goo/GooMutex.h" class Dict; class PDFDoc; @@ -102,6 +103,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 +213,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, @@ -218,8 +221,9 @@ public: GBool printing, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL, - void *annotDisplayDecideCbkData = NULL); + GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL, + void *annotDisplayDecideCbkData = NULL, + GBool copyXRef = gFalse); // Display part of a page. void displaySlice(OutputDev *out, double hDPI, double vDPI, @@ -228,8 +232,9 @@ public: GBool printing, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL, - void *annotDisplayDecideCbkData = NULL); + GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL, + void *annotDisplayDecideCbkData = NULL, + GBool copyXRef = gFalse); void display(Gfx *gfx); @@ -245,6 +250,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 +267,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..84941d6 100644 --- a/poppler/Parser.cc +++ b/poppler/Parser.cc @@ -271,7 +271,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..2512cc7 100644 --- a/poppler/PreScanOutputDev.cc +++ b/poppler/PreScanOutputDev.cc @@ -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..6b9b6b2 100644 --- a/poppler/PreScanOutputDev.h +++ b/poppler/PreScanOutputDev.h @@ -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..ca1ae24 100644 --- a/poppler/SplashOutputDev.cc +++ b/poppler/SplashOutputDev.cc @@ -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..7f1daa0 100644 --- a/poppler/SplashOutputDev.h +++ b/poppler/SplashOutputDev.h @@ -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..2a3f6d0 100644 --- a/poppler/Stream.cc +++ b/poppler/Stream.cc @@ -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", ¶ms); + dict->dictLookup("DecodeParms", ¶ms, recursion); if (params.isNull()) { params.free(); dict->dictLookup("DP", ¶ms); } if (obj.isName()) { - str = makeFilter(obj.getName(), str, ¶ms); + str = makeFilter(obj.getName(), str, ¶ms, recursion); } else if (obj.isArray()) { for (i = 0; i < obj.arrayGetLength(); ++i) { obj.arrayGet(i, &obj2); if (params.isArray()) - params.arrayGet(i, ¶ms2); + params.arrayGet(i, ¶ms2, recursion); else params2.initNull(); if (obj2.isName()) { - str = makeFilter(obj2.getName(), str, ¶ms2); + str = makeFilter(obj2.getName(), str, ¶ms2, 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..b923b21 100644 --- a/poppler/Stream.h +++ b/poppler/Stream.h @@ -39,6 +39,7 @@ #include #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 . // 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 a2198df..2792b33 100644 --- a/poppler/TextOutputDev.cc +++ b/poppler/TextOutputDev.cc @@ -4266,7 +4266,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); @@ -5312,7 +5312,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..5153ff9 100644 --- a/poppler/TextOutputDev.h +++ b/poppler/TextOutputDev.h @@ -718,7 +718,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..a72498d 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -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 , // 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..2cbaca4 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -34,7 +34,9 @@ #pragma interface #endif +#include #include "goo/gtypes.h" +#include "goo/GooMutex.h" #include "Object.h" #include "Stream.h" @@ -100,6 +102,9 @@ public: // Destructor. ~XRef(); + // Copy xref but with new base stream! + XRef *copy(); + // Is xref table valid? GBool isOk() { return ok; } @@ -180,6 +185,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 +218,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..470617f 100644 --- a/qt4/src/poppler-document.cc +++ b/qt4/src/poppler-document.cc @@ -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,14 +268,17 @@ namespace Poppler { if ( m_doc->locked ) return QString(); - m_doc->doc->getDocInfo( &info ); - if ( !info.isDict() ) - return QString(); + XRef *xref = m_doc->doc->getXRef()->copy(); + Object *infoObj = xref->getDocInfo(&info); + if ( !infoObj->isDict() ) { + delete xref; + return QString(); + } QString result; Object obj; GooString *s1; - Dict *infoDict = info.getDict(); + Dict *infoDict = infoObj->getDict(); if ( infoDict->lookup( type.toLatin1().data(), &obj )->isString() ) { @@ -280,10 +286,12 @@ namespace Poppler { result = UnicodeParsedString(s1); obj.free(); info.free(); + delete xref; return result; } obj.free(); info.free(); + delete xref; return QString(); } @@ -295,17 +303,20 @@ namespace Poppler { if ( m_doc->locked ) return QStringList(); - m_doc->doc->getDocInfo( &info ); - if ( !info.isDict() ) - return QStringList(); + XRef *xref = m_doc->doc->getXRef()->copy(); + Object *infoObj = xref->getDocInfo(&info); + if ( !infoObj->isDict() ) { + return QStringList(); + } - Dict *infoDict = info.getDict(); + Dict *infoDict = infoObj->getDict(); // somehow iterate over keys in infoDict for( int i=0; i < infoDict->getLength(); ++i ) { keys.append( QString::fromAscii(infoDict->getKey(i)) ); } info.free(); + delete xref; return keys; } @@ -317,14 +328,15 @@ namespace Poppler { return QDateTime(); Object info; - m_doc->doc->getDocInfo( &info ); - if ( !info.isDict() ) { + XRef *xref = m_doc->doc->getXRef()->copy(); + Object *infoObj = xref->getDocInfo(&info); + if ( !infoObj->isDict() ) { info.free(); return QDateTime(); } Object obj; - Dict *infoDict = info.getDict(); + Dict *infoDict = infoObj->getDict(); QDateTime result; if ( infoDict->lookup( type.toLatin1().data(), &obj )->isString() ) @@ -334,6 +346,7 @@ namespace Poppler { } obj.free(); info.free(); + delete xref; return result; } @@ -521,7 +534,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 +545,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..00da5f5 100644 --- a/qt4/src/poppler-page.cc +++ b/qt4/src/poppler-page.cc @@ -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(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 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..2d63b3a 100644 --- a/qt4/src/poppler-private.cc +++ b/qt4/src/poppler-private.cc @@ -226,7 +226,6 @@ namespace Debug { qDeleteAll(m_embeddedFiles); delete (OptContentModel *)m_optContentModel; delete doc; - delete m_outputDev; delete m_fontInfoIterator; count --; @@ -241,7 +240,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..554435f 100644 --- a/qt4/src/poppler-private.h +++ b/qt4/src/poppler-private.h @@ -112,85 +112,14 @@ namespace Poppler { void init(); ~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() { m_fontInfoIterator = new FontIterator(0, this); @@ -212,7 +141,6 @@ namespace Poppler { bool locked; FontIterator *m_fontInfoIterator; Document::RenderBackend m_backend; - OutputDev *m_outputDev; QList m_embeddedFiles; QPointer m_optContentModel; QColor paperColor; @@ -308,4 +236,4 @@ namespace Poppler { } -#endif +#endif \ No newline at end of file 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..42a1c72 100644 --- a/utils/HtmlOutputDev.cc +++ b/utils/HtmlOutputDev.cc @@ -1229,7 +1229,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..d8d2870 100644 --- a/utils/HtmlOutputDev.h +++ b/utils/HtmlOutputDev.h @@ -279,7 +279,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..51e4645 100644 --- a/utils/ImageOutputDev.h +++ b/utils/ImageOutputDev.h @@ -78,7 +78,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