resubmit https://code.google.com/p/skia/source/detail?r=7883 (in the meantime we
added capability to collect minidump and callstack if buildbot fails with heap
coruption in windows, and a NPE bug was fixed in SkPDFDocument, when document was destroyed without ever beeing used and a field was NULL + a few minor conflicts have been resolved)
git-svn-id: http://skia.googlecode.com/svn/trunk@8487 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index 7ee2778..062263d 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -14,21 +14,13 @@
#include "SkPDFPage.h"
#include "SkPDFTypes.h"
#include "SkStream.h"
+#include "SkTSet.h"
-// Add the resources, starting at firstIndex to the catalog, removing any dupes.
-// A hash table would be really nice here.
-static void addResourcesToCatalog(int firstIndex, bool firstPage,
- SkTDArray<SkPDFObject*>* resourceList,
- SkPDFCatalog* catalog) {
- for (int i = firstIndex; i < resourceList->count(); i++) {
- int index = resourceList->find((*resourceList)[i]);
- if (index != i) {
- (*resourceList)[i]->unref();
- resourceList->removeShuffle(i);
- i--;
- } else {
- catalog->addObject((*resourceList)[i], firstPage);
- }
+static void addResourcesToCatalog(bool firstPage,
+ SkTSet<SkPDFObject*>* resourceSet,
+ SkPDFCatalog* catalog) {
+ for (int i = 0; i < resourceSet->count(); i++) {
+ catalog->addObject((*resourceSet)[i], firstPage);
}
}
@@ -57,11 +49,12 @@
SkPDFDocument::SkPDFDocument(Flags flags)
: fXRefFileOffset(0),
- fSecondPageFirstResourceIndex(0),
fTrailerDict(NULL) {
fCatalog.reset(new SkPDFCatalog(flags));
fDocCatalog = SkNEW_ARGS(SkPDFDict, ("Catalog"));
fCatalog->addObject(fDocCatalog, true);
+ fFirstPageResources = NULL;
+ fOtherPageResources = NULL;
}
SkPDFDocument::~SkPDFDocument() {
@@ -73,11 +66,20 @@
fPageTree[i]->clear();
}
fPageTree.safeUnrefAll();
- fPageResources.safeUnrefAll();
+
+ if (fFirstPageResources) {
+ fFirstPageResources->safeUnrefAll();
+ }
+ if (fOtherPageResources) {
+ fOtherPageResources->safeUnrefAll();
+ }
+
fSubstitutes.safeUnrefAll();
fDocCatalog->unref();
SkSafeUnref(fTrailerDict);
+ SkDELETE(fFirstPageResources);
+ SkDELETE(fOtherPageResources);
}
bool SkPDFDocument::emitPDF(SkWStream* stream) {
@@ -90,6 +92,9 @@
}
}
+ fFirstPageResources = SkNEW(SkTSet<SkPDFObject*>);
+ fOtherPageResources = SkNEW(SkTSet<SkPDFObject*>);
+
// We haven't emitted the document before if fPageTree is empty.
if (fPageTree.isEmpty()) {
SkPDFDict* pageTreeRoot;
@@ -109,19 +114,41 @@
SkPDFDict* dests = SkNEW(SkPDFDict); // fPageResources owns reference
fCatalog->addObject(dests, true /* onFirstPage */);
- fPageResources.push(dests);
+ fFirstPageResources->add(dests);
bool firstPage = true;
+ /* The references returned in newResources are transfered to
+ * fFirstPageResources or fOtherPageResources depending on firstPage and
+ * knownResources doesn't have a reference but just relies on the other
+ * two sets to maintain a reference.
+ */
+ SkTSet<SkPDFObject*> knownResources;
+
+ // mergeInto returns the number of duplicates.
+ // If there are duplicates, there is a bug and we mess ref counting.
+ SkDEBUGCODE(int duplicates =) knownResources.mergeInto(*fFirstPageResources);
+ SkASSERT(duplicates == 0);
+
for (int i = 0; i < fPages.count(); i++) {
- int resourceCount = fPageResources.count();
- fPages[i]->finalizePage(fCatalog.get(), firstPage, &fPageResources);
- addResourcesToCatalog(resourceCount, firstPage, &fPageResources,
- fCatalog.get());
- fPages[i]->appendDestinations(dests);
- if (i == 0) {
+ if (i == 1) {
firstPage = false;
- fSecondPageFirstResourceIndex = fPageResources.count();
+ SkDEBUGCODE(duplicates =) knownResources.mergeInto(*fOtherPageResources);
}
+ SkTSet<SkPDFObject*> newResources;
+ fPages[i]->finalizePage(
+ fCatalog.get(), firstPage, knownResources, &newResources);
+ addResourcesToCatalog(firstPage, &newResources, fCatalog.get());
+ if (firstPage) {
+ SkDEBUGCODE(duplicates =) fFirstPageResources->mergeInto(newResources);
+ } else {
+ SkDEBUGCODE(duplicates =) fOtherPageResources->mergeInto(newResources);
+ }
+ SkASSERT(duplicates == 0);
+
+ SkDEBUGCODE(duplicates =) knownResources.mergeInto(newResources);
+ SkASSERT(duplicates == 0);
+
+ fPages[i]->appendDestinations(dests);
}
fDocCatalog->insert("Dests", SkNEW_ARGS(SkPDFObjRef, (dests)))->unref();
@@ -135,8 +162,8 @@
fileOffset += fCatalog->setFileOffset(fPages[0], fileOffset);
fileOffset += fPages[0]->getPageSize(fCatalog.get(),
(size_t) fileOffset);
- for (int i = 0; i < fSecondPageFirstResourceIndex; i++) {
- fileOffset += fCatalog->setFileOffset(fPageResources[i],
+ for (int i = 0; i < fFirstPageResources->count(); i++) {
+ fileOffset += fCatalog->setFileOffset((*fFirstPageResources)[i],
fileOffset);
}
// Add the size of resources of substitute objects used on page 1.
@@ -154,11 +181,9 @@
fileOffset += fPages[i]->getPageSize(fCatalog.get(), fileOffset);
}
- for (int i = fSecondPageFirstResourceIndex;
- i < fPageResources.count();
- i++) {
- fileOffset += fCatalog->setFileOffset(fPageResources[i],
- fileOffset);
+ for (int i = 0; i < fOtherPageResources->count(); i++) {
+ fileOffset += fCatalog->setFileOffset(
+ (*fOtherPageResources)[i], fileOffset);
}
fileOffset += fCatalog->setSubstituteResourcesOffsets(fileOffset,
@@ -170,8 +195,8 @@
fDocCatalog->emitObject(stream, fCatalog.get(), true);
fPages[0]->emitObject(stream, fCatalog.get(), true);
fPages[0]->emitPage(stream, fCatalog.get());
- for (int i = 0; i < fSecondPageFirstResourceIndex; i++) {
- fPageResources[i]->emit(stream, fCatalog.get(), true);
+ for (int i = 0; i < fFirstPageResources->count(); i++) {
+ (*fFirstPageResources)[i]->emit(stream, fCatalog.get(), true);
}
fCatalog->emitSubstituteResources(stream, true);
// TODO(vandebo): Support linearized format
@@ -188,10 +213,8 @@
fPages[i]->emitPage(stream, fCatalog.get());
}
- for (int i = fSecondPageFirstResourceIndex;
- i < fPageResources.count();
- i++) {
- fPageResources[i]->emit(stream, fCatalog.get(), true);
+ for (int i = 0; i < fOtherPageResources->count(); i++) {
+ (*fOtherPageResources)[i]->emit(stream, fCatalog.get(), true);
}
fCatalog->emitSubstituteResources(stream, false);