[PDF] Add a concept of a substitute object to the SkPDFCatalog class.
Code by Arthur Hsu, original code review: http://codereview.appspot.com/4650060/
Review URL: http://codereview.appspot.com/4639102
git-svn-id: http://skia.googlecode.com/svn/trunk@1812 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pdf/SkPDFCatalog.cpp b/src/pdf/SkPDFCatalog.cpp
index afa9d9a..5e9d018 100644
--- a/src/pdf/SkPDFCatalog.cpp
+++ b/src/pdf/SkPDFCatalog.cpp
@@ -25,10 +25,15 @@
fNextFirstPageObjNum(0) {
}
-SkPDFCatalog::~SkPDFCatalog() {}
+SkPDFCatalog::~SkPDFCatalog() {
+ fSubstituteResourcesRemaining.safeUnrefAll();
+ fSubstituteResourcesFirstPage.safeUnrefAll();
+}
SkPDFObject* SkPDFCatalog::addObject(SkPDFObject* obj, bool onFirstPage) {
- SkASSERT(findObjectIndex(obj) == -1);
+ if (findObjectIndex(obj) != -1) { // object already added
+ return obj;
+ }
SkASSERT(fNextFirstPageObjNum == 0);
if (onFirstPage)
fFirstPageCount++;
@@ -63,6 +68,12 @@
if (fCatalog[i].fObject == obj)
return i;
}
+ // If it's not in the main array, check if it's a substitute object.
+ for (int i = 0; i < fSubstituteMap.count(); ++i) {
+ if (fSubstituteMap[i].fSubstitute == obj) {
+ return findObjectIndex(fSubstituteMap[i].fOriginal);
+ }
+ }
return -1;
}
@@ -126,3 +137,73 @@
return fCatalog.count() + 1;
}
+
+void SkPDFCatalog::setSubstitute(SkPDFObject* original,
+ SkPDFObject* substitute) {
+#if defined(SK_DEBUG)
+ // Sanity check: is the original already in substitute list?
+ for (int i = 0; i < fSubstituteMap.count(); ++i) {
+ if (original == fSubstituteMap[i].fSubstitute ||
+ original == fSubstituteMap[i].fOriginal) {
+ SkASSERT(false);
+ return;
+ }
+ }
+#endif
+ // Check if the original is on first page.
+ bool onFirstPage = false;
+ for (int i = 0; i < fCatalog.count(); ++i) {
+ if (fCatalog[i].fObject == original) {
+ onFirstPage = fCatalog[i].fOnFirstPage;
+ break;
+ }
+#if defined(SK_DEBUG)
+ if (i == fCatalog.count() - 1) {
+ SkASSERT(false); // original not in catalog
+ return;
+ }
+#endif
+ }
+
+ SubstituteMapping newMapping(original, substitute);
+ fSubstituteMap.append(1, &newMapping);
+
+ // Add resource objects of substitute object to catalog.
+ SkTDArray<SkPDFObject*>* targetList = getSubstituteList(onFirstPage);
+ int existingSize = targetList->count();
+ newMapping.fSubstitute->getResources(targetList);
+ for (int i = existingSize; i < targetList->count(); ++i) {
+ addObject((*targetList)[i], onFirstPage);
+ }
+}
+
+SkPDFObject* SkPDFCatalog::getSubstituteObject(SkPDFObject* object) {
+ for (int i = 0; i < fSubstituteMap.count(); ++i) {
+ if (object == fSubstituteMap[i].fOriginal) {
+ return fSubstituteMap[i].fSubstitute;
+ }
+ }
+ return object;
+}
+
+off_t SkPDFCatalog::setSubstituteResourcesOffsets(off_t fileOffset,
+ bool firstPage) {
+ SkTDArray<SkPDFObject*>* targetList = getSubstituteList(firstPage);
+ off_t offsetSum = fileOffset;
+ for (int i = 0; i < targetList->count(); ++i) {
+ offsetSum += setFileOffset((*targetList)[i], offsetSum);
+ }
+ return offsetSum;
+}
+
+void SkPDFCatalog::emitSubstituteResources(SkWStream *stream, bool firstPage) {
+ SkTDArray<SkPDFObject*>* targetList = getSubstituteList(firstPage);
+ for (int i = 0; i < targetList->count(); ++i) {
+ (*targetList)[i]->emit(stream, this, true);
+ }
+}
+
+SkTDArray<SkPDFObject*>* SkPDFCatalog::getSubstituteList(bool firstPage) {
+ return firstPage ? &fSubstituteResourcesFirstPage :
+ &fSubstituteResourcesRemaining;
+}
\ No newline at end of file
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index fce100b..faa9360 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -78,14 +78,14 @@
fDocCatalog->insert("OutputIntent", intentArray.get());
*/
- bool first_page = true;
+ bool firstPage = true;
for (int i = 0; i < fPages.count(); i++) {
int resourceCount = fPageResources.count();
- fPages[i]->finalizePage(&fCatalog, first_page, &fPageResources);
- addResourcesToCatalog(resourceCount, first_page, &fPageResources,
- &fCatalog);
+ fPages[i]->finalizePage(&fCatalog, firstPage, &fPageResources);
+ addResourcesToCatalog(resourceCount, firstPage, &fPageResources,
+ &fCatalog);
if (i == 0) {
- first_page = false;
+ firstPage = false;
fSecondPageFirstResourceIndex = fPageResources.count();
}
}
@@ -97,6 +97,8 @@
fileOffset += fPages[0]->getPageSize(&fCatalog, fileOffset);
for (int i = 0; i < fSecondPageFirstResourceIndex; i++)
fileOffset += fCatalog.setFileOffset(fPageResources[i], fileOffset);
+ // Add the size of resources of substitute objects used on page 1.
+ fileOffset += fCatalog.setSubstituteResourcesOffsets(fileOffset, true);
if (fPages.count() > 1) {
// TODO(vandebo) For linearized format, save the start of the
// first page xref table and calculate the size.
@@ -113,6 +115,7 @@
i++)
fileOffset += fCatalog.setFileOffset(fPageResources[i], fileOffset);
+ fileOffset += fCatalog.setSubstituteResourcesOffsets(fileOffset, false);
fXRefFileOffset = fileOffset;
}
@@ -121,7 +124,8 @@
fPages[0]->emitObject(stream, &fCatalog, true);
fPages[0]->emitPage(stream, &fCatalog);
for (int i = 0; i < fSecondPageFirstResourceIndex; i++)
- fPageResources[i]->emitObject(stream, &fCatalog, true);
+ fPageResources[i]->emit(stream, &fCatalog, true);
+ fCatalog.emitSubstituteResources(stream, true);
// TODO(vandebo) support linearized format
//if (fPages.size() > 1) {
// // TODO(vandebo) save the file offset for the first page xref table.
@@ -135,8 +139,9 @@
fPages[i]->emitPage(stream, &fCatalog);
for (int i = fSecondPageFirstResourceIndex; i < fPageResources.count(); i++)
- fPageResources[i]->emitObject(stream, &fCatalog, true);
+ fPageResources[i]->emit(stream, &fCatalog, true);
+ fCatalog.emitSubstituteResources(stream, false);
int64_t objCount = fCatalog.emitXrefTable(stream, fPages.count() > 1);
emitFooter(stream, objCount);
return true;
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index b9420eb..600145e 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -27,9 +27,15 @@
SkPDFObject::SkPDFObject() {}
SkPDFObject::~SkPDFObject() {}
+void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog,
+ bool indirect) {
+ SkPDFObject* realObject = catalog->getSubstituteObject(this);
+ return realObject->emitObject(stream, catalog, indirect);
+}
+
size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
SkDynamicMemoryWStream buffer;
- emitObject(&buffer, catalog, indirect);
+ emit(&buffer, catalog, indirect);
return buffer.getOffset();
}
@@ -38,7 +44,7 @@
void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) {
catalog->emitObjectNumber(stream, this);
stream->writeText(" obj\n");
- emitObject(stream, catalog, false);
+ emit(stream, catalog, false);
stream->writeText("\nendobj\n");
}
@@ -292,7 +298,7 @@
stream->writeText("[");
for (int i = 0; i < fValue.count(); i++) {
- fValue[i]->emitObject(stream, catalog, false);
+ fValue[i]->emit(stream, catalog, false);
if (i + 1 < fValue.count())
stream->writeText(" ");
}
@@ -350,7 +356,7 @@
for (int i = 0; i < fValue.count(); i++) {
fValue[i].key->emitObject(stream, catalog, false);
stream->writeText(" ");
- fValue[i].value->emitObject(stream, catalog, false);
+ fValue[i].value->emit(stream, catalog, false);
stream->writeText("\n");
}
stream->writeText(">>");