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 eb86147..22e0993 100644 --- a/poppler/Annot.cc +++ b/poppler/Annot.cc @@ -6569,7 +6569,8 @@ Annot *Annots::createAnnot(Dict* dict, Object *obj) { FormWidget *widget = form->findWidgetByRef(obj->getRef()); if (widget) { annot = widget->getWidgetAnnotation(); - annot->incRefCnt(); + if (annot) + annot->incRefCnt(); } } } 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..0f9495a 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 @@ -643,9 +651,9 @@ _render_type3_glyph (cairo_scaled_font_t *scaled_font, box.y1 = mat[1]; box.x2 = mat[2]; box.y2 = mat[3]; - gfx = new Gfx(info->doc, output_dev, resDict, &box, NULL); + gfx = new Gfx(info->doc, output_dev, resDict, &box, NULL, NULL, NULL, gTrue); 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() { @@ -767,12 +779,13 @@ CairoFontEngine::~CairoFontEngine() { } 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 +795,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 +814,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 d8f78d7..5c3ca03 100644 --- a/poppler/CairoOutputDev.cc +++ b/poppler/CairoOutputDev.cc @@ -162,6 +162,7 @@ CairoOutputDev::CairoOutputDev() { stroke_adjust = globalParams->getStrokeAdjust(); align_stroke_coords = gFalse; adjusted_stroke_width = gFalse; + xref = NULL; } CairoOutputDev::~CairoOutputDev() { @@ -234,9 +235,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); @@ -246,6 +248,9 @@ void CairoOutputDev::startPage(int pageNum, GfxState *state) { if (text) text->startPage(state); + if (xref != NULL) { + xref = xrefA; + } } void CairoOutputDev::endPage() { @@ -599,7 +604,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; @@ -843,7 +848,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, gTrue); gfx->display(str); delete gfx; strokePathClip = strokePathTmp; diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h index df76975..4ba7dc5 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 0f42356..b039216 100644 --- a/poppler/Catalog.cc +++ b/poppler/Catalog.cc @@ -54,6 +54,13 @@ #include "ViewerPreferences.h" #include "FileSpec.h" +#if MULTITHREADED +# define lockCatalog gLockMutex(&mutex) +# define unlockCatalog gUnlockMutex(&mutex) +#else +# define lockCatalog +# define unlockCatalog +#endif //------------------------------------------------------------------------ // Catalog //------------------------------------------------------------------------ @@ -63,9 +70,12 @@ Catalog::Catalog(PDFDoc *docA) { Object obj, obj2; Object optContentProps; +#if MULTITHREADED + gInitMutex(&mutex); +#endif ok = gTrue; doc = docA; - xref = doc->getXRef(); + xref = doc->getXRef()->copy(); pages = NULL; pageRefs = NULL; numPages = -1; @@ -169,6 +179,7 @@ Catalog::~Catalog() { outline.free(); acroForm.free(); viewerPreferences.free(); + delete xref; } GooString *Catalog::readMetadata() { @@ -179,6 +190,7 @@ GooString *Catalog::readMetadata() { if (metadata.isNone()) { Object catDict; + lockCatalog; xref->getCatalog(&catDict); if (catDict.isDict()) { catDict.dictLookup("Metadata", &metadata); @@ -187,11 +199,13 @@ GooString *Catalog::readMetadata() { metadata.initNull(); } catDict.free(); + unlockCatalog; } if (!metadata.isStream()) { return NULL; } + lockCatalog; dict = metadata.streamGetDict(); if (!dict->lookup("Subtype", &obj)->isName("XML")) { error(errSyntaxWarning, -1, "Unknown Metadata type: '{0:s}'", @@ -201,6 +215,7 @@ GooString *Catalog::readMetadata() { s = new GooString(); metadata.getStream()->fillGooString(s); metadata.streamClose(); + unlockCatalog; return s; } @@ -209,7 +224,10 @@ Page *Catalog::getPage(int i) if (i < 1) return NULL; if (i > lastCachedPage) { - if (cachePageTree(i) == gFalse) return NULL; + lockCatalog; + GBool cached = cachePageTree(i); + unlockCatalog; + if ( cached == gFalse) return NULL; } return pages[i-1]; } @@ -219,7 +237,10 @@ Ref *Catalog::getPageRef(int i) if (i < 1) return NULL; if (i > lastCachedPage) { - if (cachePageTree(i) == gFalse) return NULL; + lockCatalog; + GBool cached = cachePageTree(i); + unlockCatalog; + if ( cached == gFalse) return NULL; } return &pageRefs[i-1]; } @@ -413,6 +434,7 @@ LinkDest *Catalog::findDest(GooString *name) { Object obj1, obj2; GBool found; + lockCatalog; // try named destination dictionary then name tree found = gFalse; if (getDests()->isDict()) { @@ -427,8 +449,10 @@ LinkDest *Catalog::findDest(GooString *name) { else obj1.free(); } - if (!found) + if (!found) { + unlockCatalog; return NULL; + } // construct LinkDest dest = NULL; @@ -448,6 +472,7 @@ LinkDest *Catalog::findDest(GooString *name) { delete dest; dest = NULL; } + unlockCatalog; return dest; } @@ -456,6 +481,7 @@ FileSpec *Catalog::embeddedFile(int i) { Object efDict; Object obj; + lockCatalog; obj = getEmbeddedFileNameTree()->getValue(i); FileSpec *embeddedFile = 0; if (obj.isRef()) { @@ -468,6 +494,7 @@ FileSpec *Catalog::embeddedFile(int i) Object null; embeddedFile = new FileSpec(&null); } + unlockCatalog; return embeddedFile; } @@ -476,10 +503,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; @@ -491,6 +520,7 @@ GooString *Catalog::getJS(int i) if (strcmp(obj2.getName(), "JavaScript")) { obj2.free(); obj.free(); + unlockCatalog; return 0; } obj2.free(); @@ -506,6 +536,7 @@ GooString *Catalog::getJS(int i) } obj2.free(); obj.free(); + unlockCatalog; return js; } @@ -517,10 +548,12 @@ Catalog::PageMode Catalog::getPageMode() { pageMode = pageModeNone; + lockCatalog; xref->getCatalog(&catDict); if (!catDict.isDict()) { error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName()); catDict.free(); + unlockCatalog; return pageMode; } @@ -538,6 +571,7 @@ Catalog::PageMode Catalog::getPageMode() { else if (obj.isName("UseAttachments")) pageMode = pageModeAttach; } + unlockCatalog; obj.free(); catDict.free(); } @@ -552,10 +586,12 @@ Catalog::PageLayout Catalog::getPageLayout() { pageLayout = pageLayoutNone; + lockCatalog; xref->getCatalog(&catDict); if (!catDict.isDict()) { error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName()); catDict.free(); + unlockCatalog; return pageLayout; } @@ -574,6 +610,7 @@ Catalog::PageLayout Catalog::getPageLayout() { if (obj.isName("TwoPageRight")) pageLayout = pageLayoutTwoPageRight; } + unlockCatalog; obj.free(); catDict.free(); } @@ -749,10 +786,12 @@ int Catalog::getNumPages() { Object catDict, pagesDict, obj; + lockCatalog; xref->getCatalog(&catDict); if (!catDict.isDict()) { error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName()); catDict.free(); + unlockCatalog; return 0; } catDict.dictLookup("Pages", &pagesDict); @@ -764,6 +803,7 @@ int Catalog::getNumPages() error(errSyntaxError, -1, "Top-level pages object is wrong type ({0:s})", pagesDict.getTypeName()); pagesDict.free(); + unlockCatalog; return 0; } @@ -777,6 +817,7 @@ int Catalog::getNumPages() numPages = (int)obj.getNum(); } + unlockCatalog; obj.free(); pagesDict.free(); } @@ -790,16 +831,19 @@ PageLabelInfo *Catalog::getPageLabelInfo() Object catDict; Object obj; + lockCatalog; xref->getCatalog(&catDict); 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()); } + unlockCatalog; obj.free(); catDict.free(); } @@ -813,6 +857,7 @@ Object *Catalog::getStructTreeRoot() { Object catDict; + lockCatalog; xref->getCatalog(&catDict); if (catDict.isDict()) { catDict.dictLookup("StructTreeRoot", &structTreeRoot); @@ -820,6 +865,7 @@ Object *Catalog::getStructTreeRoot() error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName()); structTreeRoot.initNull(); } + unlockCatalog; catDict.free(); } @@ -832,6 +878,7 @@ Object *Catalog::getOutline() { Object catDict; + lockCatalog; xref->getCatalog(&catDict); if (catDict.isDict()) { catDict.dictLookup("Outlines", &outline); @@ -839,6 +886,7 @@ Object *Catalog::getOutline() error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName()); outline.initNull(); } + unlockCatalog; catDict.free(); } @@ -851,6 +899,7 @@ Object *Catalog::getDests() { Object catDict; + lockCatalog; xref->getCatalog(&catDict); if (catDict.isDict()) { catDict.dictLookup("Dests", &dests); @@ -858,6 +907,7 @@ Object *Catalog::getDests() error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName()); dests.initNull(); } + unlockCatalog; catDict.free(); } @@ -868,9 +918,11 @@ Form *Catalog::getForm() { if (!form) { if (acroForm.isDict()) { + lockCatalog; form = new Form(doc, &acroForm); // perform form-related loading after all widgets have been loaded form->postWidgetsLoad(); + unlockCatalog; } } @@ -894,6 +946,7 @@ Object *Catalog::getNames() { Object catDict; + lockCatalog; xref->getCatalog(&catDict); if (catDict.isDict()) { catDict.dictLookup("Names", &names); @@ -901,6 +954,7 @@ Object *Catalog::getNames() error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName()); names.initNull(); } + unlockCatalog; catDict.free(); } diff --git a/poppler/Catalog.h b/poppler/Catalog.h index cdb1f13..6fa3328 100644 --- a/poppler/Catalog.h +++ b/poppler/Catalog.h @@ -34,6 +34,7 @@ #endif #include "Object.h" +#include "goo/GooMutex.h" #include @@ -223,6 +224,10 @@ private: NameTree *getDestNameTree(); NameTree *getEmbeddedFileNameTree(); NameTree *getJSNameTree(); +#if MULTITHREADED + GooMutex mutex; +#endif + Dict *catDict; }; diff --git a/poppler/Dict.cc b/poppler/Dict.cc index c4f667b..f76fee1 100644 --- a/poppler/Dict.cc +++ b/poppler/Dict.cc @@ -89,6 +89,22 @@ Dict::Dict(Dict* dictA) { } } +Dict *Dict::copy(XRef *xrefA) { + Dict *dictA = new Dict(this); + dictA->xref = xrefA; + for (int i=0; ientries[i].val.getType() == objDict) { + Dict *dict = dictA->entries[i].val.getDict(); + dict->decRef(); + Object obj; + obj.initDict(dict->copy(xrefA)); + dictA->entries[i].val = *obj.copy(&obj); + obj.free(); + } + } + return dictA; +} + Dict::~Dict() { int i; diff --git a/poppler/Dict.h b/poppler/Dict.h index 897f221..e2a11be 100644 --- a/poppler/Dict.h +++ b/poppler/Dict.h @@ -48,6 +48,7 @@ public: // Constructor. Dict(XRef *xrefA); Dict(Dict* dictA); + Dict *copy(XRef *xrefA); // Destructor. ~Dict(); diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index 4e663b4..7ca9963 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -321,14 +321,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 + resDict = resDictA->copy(xref); fonts = NULL; resDict->lookupNF("Font", &obj1); if (obj1.isRef()) { @@ -363,6 +364,7 @@ GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) : } else { fonts = NULL; + resDict = NULL; xObjDict.initNull(); colorSpaceDict.initNull(); patternDict.initNull(); @@ -384,6 +386,7 @@ GfxResources::~GfxResources() { shadingDict.free(); gStateDict.free(); propertiesDict.free(); + delete resDict; } GfxFont *GfxResources::lookupFont(char *name) { @@ -533,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, GBool fCopy) #ifdef USE_CMS : iccColorSpaceCache(5) #endif @@ -541,7 +544,8 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, int i; doc = docA; - xref = doc->getXRef(); + xref = (fCopy) ? doc->getXRef()->copy() : doc->getXRef(); + xrefOwner = fCopy; catalog = doc->getCatalog(); subPage = gFalse; printCommands = globalParams->getPrintCommands(); @@ -560,7 +564,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 +593,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, GBool fCopy) #ifdef USE_CMS : iccColorSpaceCache(5) #endif @@ -597,7 +601,8 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, int i; doc = docA; - xref = doc->getXRef(); + xref = (fCopy) ? doc->getXRef()->copy() : doc->getXRef(); + xrefOwner = fCopy; catalog = doc->getCatalog(); subPage = gTrue; printCommands = globalParams->getPrintCommands(); @@ -658,6 +663,8 @@ Gfx::~Gfx() { while (mcStack) { popMarkedContent(); } + if (xrefOwner) + delete xref; } void Gfx::display(Object *obj, GBool topLevel) { diff --git a/poppler/Gfx.h b/poppler/Gfx.h index 37022e0..a41fe87 100644 --- a/poppler/Gfx.h +++ b/poppler/Gfx.h @@ -134,6 +134,7 @@ private: PopplerObjectCache gStateCache; Object propertiesDict; GfxResources *next; + Dict *resDict; }; //------------------------------------------------------------------------ @@ -148,16 +149,18 @@ public: double hDPI, double vDPI, PDFRectangle *box, PDFRectangle *cropBox, int rotate, GBool (*abortCheckCbkA)(void *data) = NULL, - void *abortCheckCbkDataA = NULL); + void *abortCheckCbkDataA = NULL, GBool fCopy = gFalse); // 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, GBool fCopy = gFalse); ~Gfx(); + XRef *getXRef() { return xref; } + // Interpret a stream or array of streams. void display(Object *obj, GBool topLevel = gTrue); @@ -228,6 +231,7 @@ private: MarkedContentStack *mcStack; // current BMC/EMC stack Parser *parser; // parser for page content stream(s) + GBool xrefOwner; // true if xref is owned by the instance #ifdef USE_CMS PopplerCache iccColorSpaceCache; diff --git a/poppler/GlobalParamsWin.cc b/poppler/GlobalParamsWin.cc index 527f08e..20d83ab 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/Outline.cc b/poppler/Outline.cc index bd4e6d0..32aff5f 100644 --- a/poppler/Outline.cc +++ b/poppler/Outline.cc @@ -38,16 +38,21 @@ //------------------------------------------------------------------------ -Outline::Outline(Object *outlineObj, XRef *xref) { +Outline::Outline(Object *outlineObj, XRef *xrefA) { Object first, last; items = NULL; if (!outlineObj->isDict()) { + xref = NULL; return; } - items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first), - outlineObj->dictLookupNF("Last", &last), + xref = xrefA->copy(); + Object outline; + outline.initDict(outlineObj->getDict()->copy(xref)); + items = OutlineItem::readItemList(outline.dictLookupNF("First", &first), + outline.dictLookupNF("Last", &last), xref); + outline.free(); first.free(); last.free(); } @@ -56,6 +61,7 @@ Outline::~Outline() { if (items) { deleteGooList(items, OutlineItem); } + delete xref; } //------------------------------------------------------------------------ diff --git a/poppler/Outline.h b/poppler/Outline.h index 90190e6..44ae9dc 100644 --- a/poppler/Outline.h +++ b/poppler/Outline.h @@ -40,7 +40,7 @@ class LinkAction; class Outline { public: - Outline(Object *outlineObj, XRef *xref); + Outline(Object *outlineObj, XRef *xrefA); ~Outline(); GooList *getItems() { return items; } @@ -49,6 +49,7 @@ private: GooList *items; // NULL if document has no outline, // otherwise, a list of OutlineItem + XRef *xref; }; //------------------------------------------------------------------------ diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h index 15af90a..9144418 100644 --- a/poppler/OutputDev.h +++ b/poppler/OutputDev.h @@ -132,7 +132,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 f52d498..2bdb88f 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; } @@ -455,7 +472,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 fMT) { if (globalParams->getPrintCommands()) { printf("***** page %d *****\n", page); } @@ -464,7 +481,7 @@ void PDFDoc::displayPage(OutputDev *out, int page, getPage(page)->display(out, hDPI, vDPI, rotate, useMediaBox, crop, printing, abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); + annotDisplayDecideCbk, annotDisplayDecideCbkData, fMT); } @@ -491,14 +508,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 fMT) { if (getPage(page)) getPage(page)->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); + annotDisplayDecideCbk, annotDisplayDecideCbkData, fMT); } Links *PDFDoc::getLinks(int page) { @@ -522,6 +539,16 @@ Linearization *PDFDoc::getLinearization() return linearization; } +// thread safe version of getDocInfo +Object *PDFDoc::getDocInfo(Object *info, XRef *xrefThread) { + Object *obj = xref->getDocInfo(info); + if (obj->isDict()) { + Dict *infoDict = obj->getDict(); + return info->initDict(infoDict->copy(xrefThread)); + } + return obj; +} + GBool PDFDoc::isLinearized() { if ((str->getLength()) && (getLinearization()->getLength() == str->getLength())) @@ -610,15 +637,15 @@ int PDFDoc::savePageAs(GooString *name, int pageNo) OutStream *outStr; XRef *yRef, *countRef; int rootNum = getXRef()->getNumObjects() + 1; - - // Make sure that special flags are set, because we are going to read - // all objects, including Unencrypted ones. - xref->scanSpecialFlags(); - - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); + + // Make sure that special flags are set, because we are going to read + // all objects, including Unencrypted ones. + xref->scanSpecialFlags(); + + Guchar *fileKey; + CryptAlgorithm encAlgorithm; + int keyLength; + xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); if (pageNo < 1 || pageNo > getNumPages()) { error(errInternal, -1, "Illegal pageNo: {0:d}({1:d})", pageNo, getNumPages() ); @@ -1529,10 +1556,10 @@ void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint n Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset) { Guint objectsCount = 0; //count the number of objects in the XRef(s) - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xRef->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); + Guchar *fileKey; + CryptAlgorithm encAlgorithm; + int keyLength; + xRef->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); for (int n = numOffset; n < xRef->getNumObjects(); n++) { if (xRef->getEntry(n)->type != xrefEntryFree) { @@ -1543,11 +1570,11 @@ Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset) objectsCount++; getXRef()->fetch(ref.num - numOffset, ref.gen, &obj); Guint offset = writeObjectHeader(&ref, outStr); - if (xRef->getEntry(n)->getFlag(XRefEntry::Unencrypted)) { - writeObject(&obj, outStr, NULL, cryptRC4, 0, 0, 0); - } else { - writeObject(&obj, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); - } + if (xRef->getEntry(n)->getFlag(XRefEntry::Unencrypted)) { + writeObject(&obj, outStr, NULL, cryptRC4, 0, 0, 0); + } else { + writeObject(&obj, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); + } writeObjectFooter(outStr); xRef->add(ref.num, ref.gen, offset, gTrue); obj.free(); @@ -1560,8 +1587,10 @@ Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset) Outline *PDFDoc::getOutline() { if (!outline) { + lockPDFDoc; // read outline outline = new Outline(catalog->getOutline(), xref); + unlockPDFDoc; } return outline; @@ -1715,7 +1744,11 @@ Page *PDFDoc::parsePage(int page) Page *PDFDoc::getPage(int page) { - if ((page < 1) || page > getNumPages()) return NULL; + lockPDFDoc; + if ((page < 1) || page > getNumPages()) { + unlockPDFDoc; + return NULL; + } if (isLinearized()) { if (!pageCache) { @@ -1728,11 +1761,14 @@ Page *PDFDoc::getPage(int page) pageCache[page-1] = parsePage(page); } if (pageCache[page-1]) { + unlockPDFDoc; return pageCache[page-1]; } else { error(errSyntaxWarning, -1, "Failed parsing page {0:d} using hint tables", page); } } - return catalog->getPage(page); + Page *pageObj = catalog->getPage(page); + unlockPDFDoc; + return pageObj; } diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index 328b0c7..39ebf46 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -43,6 +43,7 @@ #include "Page.h" #include "Annot.h" #include "OptionalContent.h" +#include "goo/GooMutex.h" class GooString; class BaseStream; @@ -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 fMT = 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 fMT = gFalse); // Find a page, given its object ID. Returns page number, or 0 if // not found. @@ -217,6 +218,7 @@ public: // Return the document's Info dictionary (if any). Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); } Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); } + Object *getDocInfo(Object *obj, XRef *xref); // Return the PDF version specified by the file. int getPDFMajorVersion() { return pdfMajorVersion; } @@ -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 93b078a..fd0a12a 100644 --- a/poppler/PSOutputDev.cc +++ b/poppler/PSOutputDev.cc @@ -2620,7 +2620,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, GooString *psName, box.y1 = m[1]; box.x2 = m[2]; box.y2 = m[3]; - gfx = new Gfx(doc, this, resDict, &box, NULL); + gfx = new Gfx(doc, this, resDict, &box, NULL, NULL, NULL, gTrue); inType3Char = gTrue; for (i = 0; i < charProcs->getLength(); ++i) { t3FillColorOnly = gFalse; @@ -3009,7 +3009,7 @@ void PSOutputDev::setupForm(Ref id, Object *strObj) { box.y1 = bbox[1]; box.x2 = bbox[2]; box.y2 = bbox[3]; - gfx = new Gfx(doc, this, resDict, &box, &box); + gfx = new Gfx(doc, this, resDict, &box, &box, NULL, NULL, gTrue); gfx->display(strObj); delete gfx; @@ -3060,7 +3060,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); + annotDisplayDecideCbk, annotDisplayDecideCbkData, gTrue); rasterize = scan->usesTransparency() || scan->usesPatternImageMask(); delete scan; } @@ -3083,7 +3083,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 @@ -3145,7 +3145,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, (360 - page->getRotate()) % 360, useMediaBox, crop, sliceX, stripeY, sliceW, stripeH, printing, abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); + annotDisplayDecideCbk, annotDisplayDecideCbkData, gTrue); // draw the rasterized image bitmap = splashOut->getBitmap(); @@ -3469,14 +3469,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); @@ -4183,7 +4183,7 @@ GBool PSOutputDev::tilingPatternFillL1(GfxState *state, Catalog *cat, Object *st 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, gTrue); writePS("/x {\n"); if (paintType == 2) { writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n", @@ -4256,7 +4256,7 @@ GBool PSOutputDev::tilingPatternFillL2(GfxState *state, Catalog *cat, Object *st 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, gTrue); inType3Char = gTrue; if (paintType == 2) { inUncoloredPattern = gTrue; @@ -4301,7 +4301,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, gTrue); 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 809f058..7ee6b1d 100644 --- a/poppler/PSOutputDev.h +++ b/poppler/PSOutputDev.h @@ -85,7 +85,7 @@ enum PSOutCustomCodeLocation { typedef void (*PSOutputFunc)(void *stream, const char *data, int len); typedef GooString *(*PSOutCustomCodeCbk)(PSOutputDev *psOut, - PSOutCustomCodeLocation loc, int n, + PSOutCustomCodeLocation loc, int n, void *data); class PSOutputDev: public OutputDev { @@ -184,7 +184,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(); @@ -417,7 +417,7 @@ private: void (*overlayCbk)(PSOutputDev *psOut, void *data); void *overlayCbkData; GooString *(*customCodeCbk)(PSOutputDev *psOut, - PSOutCustomCodeLocation loc, int n, + PSOutCustomCodeLocation loc, int n, void *data); void *customCodeCbkData; diff --git a/poppler/Page.cc b/poppler/Page.cc index 87bc3a4..9fb4ae8 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(); @@ -347,9 +357,11 @@ Page::~Page() { Annots *Page::getAnnots() { if (!annots) { + lockPage; Object obj; annots = new Annots(doc, num, getAnnots(&obj)); obj.free(); + unlockPage; } return annots; @@ -445,10 +457,10 @@ 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 fMT) { displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, printing, abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); + annotDisplayDecideCbk, annotDisplayDecideCbkData, fMT); } Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI, @@ -456,7 +468,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, GBool fMT) { PDFRectangle *mediaBox, *cropBox; PDFRectangle box; Gfx *gfx; @@ -483,7 +495,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, fMT); return gfx; } @@ -495,7 +507,7 @@ 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 fMT) { Gfx *gfx; Object obj; Annots *annotList; @@ -512,9 +524,9 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, - abortCheckCbk, abortCheckCbkData); + abortCheckCbk, abortCheckCbkData, fMT); - contents.fetch(xref, &obj); + contents.fetch(gfx->getXRef(), &obj); if (!obj.isNull()) { gfx->saveState(); gfx->display(&obj); @@ -573,9 +585,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; } @@ -658,6 +672,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 78cedc4..216b87b 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; @@ -208,7 +209,7 @@ public: int sliceX, int sliceY, int sliceW, int sliceH, GBool printing, GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData); + void *abortCheckCbkData, GBool fMT = gFalse); // Display a page. void display(OutputDev *out, double hDPI, double vDPI, @@ -217,7 +218,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 fMT = gFalse); // Display part of a page. void displaySlice(OutputDev *out, double hDPI, double vDPI, @@ -227,7 +228,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 fMT = gFalse); void display(Gfx *gfx); @@ -258,6 +259,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 5b80293..11f6d4a 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 a915f68..cb1a1b0 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; @@ -3377,7 +3379,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, @@ -4199,7 +4201,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, gTrue); // 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..f059d7b 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 c034cff..1f9f04a 100644 --- a/poppler/Stream.cc +++ b/poppler/Stream.cc @@ -138,25 +138,25 @@ 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); @@ -165,7 +165,7 @@ Stream *Stream::addFilters(Object *dict) { 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); @@ -182,7 +182,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; @@ -204,23 +204,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(); @@ -237,37 +237,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(); } @@ -278,7 +278,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(); @@ -290,19 +290,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(); @@ -310,7 +310,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(); @@ -725,13 +725,30 @@ 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"); + reset(); +} + +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; @@ -745,9 +762,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 UniqueFileStream(f, fileName, startA, limitedA, lengthA, dictA); } void FileStream::reset() { @@ -869,6 +890,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) { @@ -964,6 +990,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; @@ -1038,6 +1068,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..5ba350f 100644 --- a/poppler/Stream.h +++ b/poppler/Stream.h @@ -218,13 +218,13 @@ 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 }; @@ -299,6 +299,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 +317,6 @@ public: protected: Guint length; - -private: - Object dict; }; @@ -439,9 +437,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 +485,10 @@ private: return n; } +protected: FILE *f; + char *fileName; +private: Guint start; GBool limited; char buf[fileStreamBufSize]; @@ -497,6 +499,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 +519,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 +562,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 +611,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 452a5ac..a3924d2 100644 --- a/poppler/TextOutputDev.cc +++ b/poppler/TextOutputDev.cc @@ -4265,7 +4265,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); @@ -5310,7 +5310,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 c8a93b9..848a0cb 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; @@ -271,6 +282,7 @@ void XRef::init() { encrypted = gFalse; permFlags = defPermFlags; ownerPasswordOk = gFalse; + strOwner = gFalse; } XRef::XRef() { @@ -374,6 +386,53 @@ XRef::~XRef() { if (objStrs) { delete objStrs; } + if (strOwner) + delete str; +} + +XRef *XRef::copy() { + lockXRef; + XRef *xref = new XRef(); + xref->init(); + xref->str = str->copy(); + xref->strOwner = gTrue; + xref->encrypted = encrypted; + xref->permFlags = permFlags; + xref->ownerPasswordOk = ownerPasswordOk; + + xref->start = start; + xref->prevXRefOffset = prevXRefOffset; + xref->mainXRefEntriesOffset = mainXRefEntriesOffset; + xref->xRefStream = xRefStream; + xref->trailerDict.initDict(trailerDict.getDict()); + 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]; + } + + xref->reserve(size); + 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]; + } + } + unlockXRef; + return xref; } int XRef::reserve(int newSize) @@ -1035,6 +1094,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; @@ -1043,9 +1103,11 @@ 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; } - + switch (e->type) { case xrefEntryUncompressed: @@ -1123,7 +1185,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; @@ -1144,9 +1206,11 @@ 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(); } @@ -1204,6 +1268,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)); @@ -1229,21 +1294,26 @@ 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) { int entryIndexToUse = -1; + lockXRef; for (int i = 1; entryIndexToUse == -1 && i < size; ++i) { XRefEntry *e = getEntry(i, false /* complainIfMissing */); if (e->type == xrefEntryFree && e->gen != 65535) { @@ -1269,12 +1339,15 @@ Ref XRef::addIndirectObject (Object* o) { Ref r; r.num = entryIndexToUse; r.gen = e->gen; + unlockXRef; return r; } 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); @@ -1284,6 +1357,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 2defc6c..703eb44 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -34,8 +34,10 @@ #pragma interface #endif -#include "goo/gtypes.h" -#include "Object.h" +#include +#include "goo/gtypes.h" +#include "Object.h" +#include "goo/GooMutex.h" #include @@ -99,6 +101,9 @@ public: // Destructor. ~XRef(); + // Copy xref but with new base stream! + XRef *copy(); + // Is xref table valid? GBool isOk() { return ok; } @@ -208,6 +213,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 550e706..439736d 100644 --- a/qt4/src/poppler-document.cc +++ b/qt4/src/poppler-document.cc @@ -95,6 +95,7 @@ namespace Poppler { Document::Document(DocumentData *dataA) { + refCnt = 1; m_doc = dataA; } @@ -103,6 +104,22 @@ namespace Poppler { delete m_doc; } + void Document::incRefCnt() + { + ++refCnt; + } + + bool Document::decRefCnt() + { + GBool done; + + done = --refCnt == 0; + if (done) { + delete this; + } + return done; + } + Page *Document::page(int index) const { Page *page = new Page(m_doc, index); @@ -237,8 +254,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()) { @@ -251,6 +270,7 @@ namespace Poppler { strObj.streamClose(); } strObj.free(); + delete xref; } return result; } @@ -263,14 +283,17 @@ namespace Poppler { if ( m_doc->locked ) return QString(); - m_doc->doc->getDocInfo( &info ); - if ( !info.isDict() ) + XRef *xref = m_doc->doc->getXRef()->copy(); + Object *infoObj = m_doc->doc->getDocInfo( &info, xref); + 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() ) { @@ -278,10 +301,12 @@ namespace Poppler { result = UnicodeParsedString(s1); obj.free(); info.free(); + delete xref; return result; } obj.free(); info.free(); + delete xref; return QString(); } @@ -293,17 +318,19 @@ namespace Poppler { if ( m_doc->locked ) return QStringList(); - m_doc->doc->getDocInfo( &info ); - if ( !info.isDict() ) + XRef *xref = m_doc->doc->getXRef()->copy(); + Object *infoObj = m_doc->doc->getDocInfo( &info, xref); + 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; } @@ -315,14 +342,15 @@ namespace Poppler { return QDateTime(); Object info; - m_doc->doc->getDocInfo( &info ); - if ( !info.isDict() ) { + XRef *xref = m_doc->doc->getXRef()->copy(); + Object *infoObj = m_doc->doc->getDocInfo( &info, xref); + 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() ) @@ -332,6 +360,7 @@ namespace Poppler { } obj.free(); info.free(); + delete xref; return result; } @@ -523,14 +552,6 @@ namespace Poppler { m_doc->m_hints |= hint; else m_doc->m_hints &= ~(int)hint; - - // the only way to set antialiasing for Splash is on creation - if ( m_doc->m_backend == Document::SplashBackend && - ( hint & ( Document::Antialiasing || Document::TextAntialiasing || Document::TextHinting ) ) ) - { - 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 349a1bb..72e3ce8 100644 --- a/qt4/src/poppler-page.cc +++ b/qt4/src/poppler-page.cc @@ -251,10 +251,24 @@ 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; + 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(splashModeXBGR8, 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(); @@ -281,8 +295,8 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, // construct a qimage SHARING the raw bitmap data in memory 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; } @@ -371,7 +385,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(); @@ -472,7 +487,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 6d2ef2a..2e46704 100644 --- a/qt4/src/poppler-private.h +++ b/qt4/src/poppler-private.h @@ -111,63 +111,12 @@ 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; - bgColor[0] = paperColor.blue(); - bgColor[1] = paperColor.green(); - bgColor[2] = paperColor.red(); - GBool AA = m_hints & Document::TextAntialiasing ? gTrue : gFalse; - SplashOutputDev * splashOutputDev = new SplashOutputDev(splashModeXBGR8, 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; - if ( m_outputDev == NULL ) - return; - - switch ( m_backend ) - { - case Document::SplashBackend: - { -#if defined(HAVE_SPLASH) - SplashOutputDev *splash_output = static_cast( m_outputDev ); - SplashColor bgColor; - bgColor[0] = paperColor.blue(); - bgColor[1] = paperColor.green(); - bgColor[2] = paperColor.red(); - splash_output->setPaperColor(bgColor); -#endif - break; - } - default: ; - } } void fillMembers() @@ -191,7 +140,6 @@ namespace Poppler { bool locked; FontIterator *m_fontInfoIterator; Document::RenderBackend m_backend; - OutputDev *m_outputDev; QList m_embeddedFiles; QPointer m_optContentModel; QColor paperColor; diff --git a/qt4/src/poppler-ps-converter.cc b/qt4/src/poppler-ps-converter.cc index 63fb7b4..5793119 100644 --- a/qt4/src/poppler-ps-converter.cc +++ b/qt4/src/poppler-ps-converter.cc @@ -253,7 +253,7 @@ bool PSConverter::convert() NULL, NULL, annotDisplayDecideCbk, - &showAnnotations); + &showAnnotations, gTrue); if (d->pageConvertedCallback) (*d->pageConvertedCallback)(page, d->pageConvertedPayload); } diff --git a/qt4/src/poppler-qt4.h b/qt4/src/poppler-qt4.h index 425b1e0..a0ed82b 100644 --- a/qt4/src/poppler-qt4.h +++ b/qt4/src/poppler-qt4.h @@ -41,8 +41,11 @@ #include #include #include +#include #include "poppler-export.h" +#define POPPLER_QT_THREADSAFE 1 + class EmbFile; class Sound; class AnnotMovie; @@ -990,6 +993,20 @@ delete it; bool isLocked() const; /** + safely delete the document + + \since 0.22 + */ + bool decRefCnt(); + + /** + protect document against deletion + + \since 0.22 + */ + void incRefCnt(); + + /** The date associated with the document You would use this method with something like: @@ -1372,6 +1389,8 @@ QString subject = m_doc->info("Subject"); DocumentData *m_doc; Document(DocumentData *dataA); + + int refCnt; }; class BaseConverterPrivate; 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 e4bd0b1..f05ce9b 100644 --- a/utils/HtmlOutputDev.cc +++ b/utils/HtmlOutputDev.cc @@ -1224,7 +1224,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