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/Array.cc b/poppler/Array.cc index cb22432..3a9471c 100644 --- a/poppler/Array.cc +++ b/poppler/Array.cc @@ -77,7 +77,7 @@ void Array::remove(int i) { memmove( elems + i, elems + i + 1, sizeof(elems[0]) * (length - i) ); } -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 +85,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..e82bf94 100644 --- a/poppler/Array.h +++ b/poppler/Array.h @@ -59,7 +59,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); 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..9d12086 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() { @@ -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 0f33d4e..51351d1 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 (xrefA != 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/Dict.cc b/poppler/Dict.cc index c4f667b..467a604 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,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(); + Object obj; + obj.initDict(dict->copy(xrefA)); + dictA->entries[i].val.free(); + dictA->entries[i].val = obj; + obj.free(); + } + } + return dictA; +} + Dict::~Dict() { int i; @@ -97,9 +126,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 +164,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) { sorted = gTrue; + lockDict; std::sort(entries, entries+length, cmpDictEntries); + unlockDict; } if (sorted) { @@ -147,6 +197,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 +210,10 @@ void Dict::remove(const char *key) { int i; bool found = false; DictEntry tmp; - if(length == 0) return; + if(length == 0) { + unlockDict; + return; + } for(i=0; i 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 99c326e..5267c37 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 + resDict = resDictA->copy(xref); fonts = NULL; resDict->lookupNF("Font", &obj1); if (obj1.isRef()) { @@ -364,6 +365,7 @@ GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) : } else { fonts = NULL; + resDict = NULL; xObjDict.initNull(); colorSpaceDict.initNull(); patternDict.initNull(); @@ -385,6 +387,7 @@ GfxResources::~GfxResources() { shadingDict.free(); gStateDict.free(); propertiesDict.free(); + delete resDict; } GfxFont *GfxResources::lookupFont(char *name) { @@ -534,7 +537,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 copyXRef) #ifdef USE_CMS : iccColorSpaceCache(5) #endif @@ -542,7 +545,8 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, int i; doc = docA; - xref = doc->getXRef(); + xref = (copyXRef) ? doc->getXRef()->copy() : doc->getXRef(); + xrefOwner = copyXRef; catalog = doc->getCatalog(); subPage = gFalse; printCommands = globalParams->getPrintCommands(); @@ -561,7 +565,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 copyXRef) #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 = (copyXRef) ? doc->getXRef()->copy() : doc->getXRef(); + xrefOwner = copyXRef; catalog = doc->getCatalog(); subPage = gTrue; printCommands = globalParams->getPrintCommands(); @@ -657,6 +662,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 7c42f14..5609105 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 copyXRef = 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 copyXRef = gFalse); ~Gfx(); + XRef *getXRef() { return xref; } + // Interpret a stream or array of streams. void display(Object *obj, GBool topLevel = gTrue); @@ -225,6 +228,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/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 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..7939199 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 } @@ -455,7 +475,7 @@ void PDFDoc::displayPage(OutputDev *out, int page, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { + void *annotDisplayDecideCbkData, GBool copyXRef) { if (globalParams->getPrintCommands()) { printf("***** page %d *****\n", page); } @@ -464,7 +484,7 @@ void PDFDoc::displayPage(OutputDev *out, int page, getPage(page)->display(out, hDPI, vDPI, rotate, useMediaBox, crop, printing, abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); + annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef); } @@ -491,14 +511,14 @@ void PDFDoc::displayPageSlice(OutputDev *out, int page, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { + void *annotDisplayDecideCbkData, GBool copyXRef) { if (getPage(page)) getPage(page)->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); + annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef); } Links *PDFDoc::getLinks(int page) { @@ -610,15 +630,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() ); @@ -826,11 +846,13 @@ int PDFDoc::saveWithoutChangesAs(GooString *name) { int PDFDoc::saveWithoutChangesAs(OutStream *outStr) { int c; - str->reset(); - while ((c = str->getChar()) != EOF) { + BaseStream *copyStr = str->copy(); + copyStr->reset(); + while ((c = copyStr->getChar()) != EOF) { outStr->put(c); } - str->close(); + copyStr->close(); + delete copyStr; return errNone; } @@ -840,11 +862,13 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) XRef *uxref; int c; //copy the original file - str->reset(); - while ((c = str->getChar()) != EOF) { + BaseStream *copyStr = str->copy(); + copyStr->reset(); + while ((c = copyStr->getChar()) != EOF) { outStr->put(c); } - str->close(); + copyStr->close(); + delete copyStr; Guchar *fileKey; CryptAlgorithm encAlgorithm; @@ -853,6 +877,7 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) uxref = new XRef(); uxref->add(0, 65535, 0, gFalse); + xref->lock(); for(int i=0; igetNumObjects(); i++) { if ((xref->getEntry(i)->type == xrefEntryFree) && (xref->getEntry(i)->gen == 0)) //we skip the irrelevant free objects @@ -864,7 +889,7 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen; if (xref->getEntry(i)->type != xrefEntryFree) { Object obj1; - xref->fetch(ref.num, ref.gen, &obj1); + xref->fetch(ref.num, ref.gen, &obj1, 1); Guint offset = writeObjectHeader(&ref, outStr); writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); writeObjectFooter(outStr); @@ -875,6 +900,7 @@ void PDFDoc::saveIncrementalUpdate (OutStream* outStr) } } } + xref->unlock(); if (uxref->getNumObjects() == 0) { //we have nothing to update delete uxref; return; @@ -922,6 +948,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) outStr->printf("%%PDF-%d.%d\r\n",pdfMajorVersion,pdfMinorVersion); XRef *uxref = new XRef(); uxref->add(0, 65535, 0, gFalse); + xref->lock(); for(int i=0; igetNumObjects(); i++) { Object obj1; Ref ref; @@ -941,7 +968,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) } else if (type == xrefEntryUncompressed){ ref.num = i; ref.gen = xref->getEntry(i)->gen; - xref->fetch(ref.num, ref.gen, &obj1); + xref->fetch(ref.num, ref.gen, &obj1, 1); Guint offset = writeObjectHeader(&ref, outStr); // Write unencrypted objects in unencrypted form if (xref->getEntry(i)->getFlag(XRefEntry::Unencrypted)) { @@ -955,7 +982,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) } else if (type == xrefEntryCompressed) { ref.num = i; ref.gen = 0; //compressed entries have gen == 0 - xref->fetch(ref.num, ref.gen, &obj1); + xref->fetch(ref.num, ref.gen, &obj1, 1); Guint offset = writeObjectHeader(&ref, outStr); writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); writeObjectFooter(outStr); @@ -963,6 +990,7 @@ void PDFDoc::saveCompleteRewrite (OutStream* outStr) obj1.free(); } } + xref->unlock(); Guint uxrefOffset = outStr->getPos(); writeXRefTableTrailer(uxrefOffset, uxref, gTrue /* write all entries */, uxref->getNumObjects(), outStr, gFalse /* complete rewrite */); @@ -1529,10 +1557,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 +1571,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 +1588,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 +1745,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 +1762,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 f3e9f68..bdc73ea 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..1e33924 100644 --- a/poppler/PSOutputDev.cc +++ b/poppler/PSOutputDev.cc @@ -2622,7 +2622,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; @@ -3011,7 +3011,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; @@ -3062,7 +3062,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; } @@ -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 @@ -3147,7 +3147,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(); @@ -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); @@ -4185,7 +4185,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", @@ -4258,7 +4258,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; @@ -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, 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..98f812c 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,9 @@ Page::~Page() { trans.free(); thumb.free(); actions.free(); +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif } Annots *Page::getAnnots() { @@ -363,6 +376,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 +406,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 +430,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 +446,7 @@ void Page::removeAnnot(Annot *annot) { annArray.free(); annot->removeReferencedObjects(); // Note: Might recurse in removeAnnot again annot->setPage(0, gFalse); + unlockPage; } Links *Page::getLinks() { @@ -445,10 +463,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 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 +474,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 copyXRef) { PDFRectangle *mediaBox, *cropBox; PDFRectangle box; Gfx *gfx; @@ -483,7 +501,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, copyXRef); return gfx; } @@ -495,7 +513,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 copyXRef) { Gfx *gfx; Object obj; Annots *annotList; @@ -512,9 +530,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, copyXRef); - contents.fetch(xref, &obj); + contents.fetch(gfx->getXRef(), &obj); if (!obj.isNull()) { gfx->saveState(); gfx->display(&obj); @@ -573,9 +591,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 +678,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..9aa1a7b 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 copyXRef = 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 copyXRef = 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 copyXRef = 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 de09f49..572b355 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, @@ -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, 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 842f0c6..911c8a9 100644 --- a/poppler/Stream.cc +++ b/poppler/Stream.cc @@ -85,15 +85,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() { @@ -138,34 +165,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); @@ -182,7 +209,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 +231,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 +264,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 +305,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 +317,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 +337,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 +752,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 +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 UniqueFileStream(f, fileName, startA, limitedA, lengthA, dictA); } void FileStream::reset() { @@ -869,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) { @@ -964,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; @@ -1038,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 2be0b42..da33025 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 81e939a..cbfd10b 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,58 @@ XRef::~XRef() { if (objStrs) { delete objStrs; } + if (strOwner) { + delete str; + } +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif +} + +XRef *XRef::copy() { + lockXRef; + 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]; + } + + 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) @@ -1036,6 +1100,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 +1109,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 +1190,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 +1211,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 +1281,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 +1307,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 +1355,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 +1368,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 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