Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(224)

Unified Diff: src/pdf/SkPDFDocument.cpp

Issue 1033543002: SKPDF: refactor pdfcatalog and pdfdocument (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2015-03-23 (Monday) 19:02:27 EDT Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/pdf/SkPDFDocument.cpp
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index 8280551f8aabdcb5bfd283a1fd0613d514178b11..b71697163847d42f8035523cad94da8152a5415e 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -16,20 +16,9 @@
#include "SkStream.h"
#include "SkTSet.h"
-static void addResourcesToCatalog(bool firstPage,
- SkTSet<SkPDFObject*>* resourceSet,
- SkPDFCatalog* catalog) {
- for (int i = 0; i < resourceSet->count(); i++) {
- catalog->addObject((*resourceSet)[i], firstPage);
- }
-}
-
-static void perform_font_subsetting(SkPDFCatalog* catalog,
- const SkTDArray<SkPDFPage*>& pages,
- SkTDArray<SkPDFObject*>* substitutes) {
+static void perform_font_subsetting(const SkTDArray<SkPDFPage*>& pages,
+ SkPDFCatalog* catalog) {
SkASSERT(catalog);
- SkASSERT(substitutes);
-
SkPDFGlyphSetMap usage;
for (int i = 0; i < pages.count(); ++i) {
usage.merge(pages[i]->getFontGlyphUsage());
@@ -37,49 +26,45 @@ static void perform_font_subsetting(SkPDFCatalog* catalog,
SkPDFGlyphSetMap::F2BIter iterator(usage);
const SkPDFGlyphSetMap::FontGlyphSetPair* entry = iterator.next();
while (entry) {
- SkPDFFont* subsetFont =
- entry->fFont->getFontSubset(entry->fGlyphSet);
+ SkAutoTUnref<SkPDFFont> subsetFont(
+ entry->fFont->getFontSubset(entry->fGlyphSet));
if (subsetFont) {
catalog->setSubstitute(entry->fFont, subsetFont);
- substitutes->push(subsetFont); // Transfer ownership to substitutes
}
entry = iterator.next();
}
}
-SkPDFDocument::SkPDFDocument()
- : fXRefFileOffset(0),
- fTrailerDict(NULL) {
- fCatalog.reset(SkNEW(SkPDFCatalog));
- fDocCatalog = SkNEW_ARGS(SkPDFDict, ("Catalog"));
- fCatalog->addObject(fDocCatalog, true);
- fFirstPageResources = NULL;
- fOtherPageResources = NULL;
-}
+SkPDFDocument::SkPDFDocument() {}
SkPDFDocument::~SkPDFDocument() {
fPages.safeUnrefAll();
+}
- // The page tree has both child and parent pointers, so it creates a
- // reference cycle. We must clear that cycle to properly reclaim memory.
- for (int i = 0; i < fPageTree.count(); i++) {
- fPageTree[i]->clear();
- }
- fPageTree.safeUnrefAll();
-
- if (fFirstPageResources) {
- fFirstPageResources->safeUnrefAll();
- }
- if (fOtherPageResources) {
- fOtherPageResources->safeUnrefAll();
- }
+static void emit_pdf_header(SkWStream* stream) {
+ stream->writeText("%PDF-1.4\n%");
+ // The PDF spec recommends including a comment with four bytes, all
+ // with their high bits set. This is "Skia" with the high bits set.
+ stream->write32(0xD3EBE9E1);
+ stream->writeText("\n");
+}
- fSubstitutes.safeUnrefAll();
+static void emit_pdf_footer(SkWStream* stream,
+ SkPDFCatalog* catalog,
+ SkPDFObject* docCatalog,
+ int64_t objCount,
+ int32_t xRefFileOffset) {
+ SkPDFDict trailerDict;
+ // TODO(vandebo): Linearized format will take a Prev entry too.
+ // TODO(vandebo): PDF/A requires an ID entry.
+ trailerDict.insertInt("Size", int(objCount));
+ trailerDict.insert("Root", new SkPDFObjRef(docCatalog))->unref();
- fDocCatalog->unref();
- SkSafeUnref(fTrailerDict);
- SkDELETE(fFirstPageResources);
- SkDELETE(fOtherPageResources);
+ stream->writeText("trailer\n");
+ trailerDict.emitObject(stream, catalog);
+ stream->writeText("\nstartxref\n");
+ stream->writeBigDecAsText(xRefFileOffset);
+ stream->writeText("\n%%EOF");
}
bool SkPDFDocument::emitPDF(SkWStream* stream) {
@@ -92,154 +77,95 @@ bool SkPDFDocument::emitPDF(SkWStream* stream) {
}
}
- fFirstPageResources = SkNEW(SkTSet<SkPDFObject*>);
- fOtherPageResources = SkNEW(SkTSet<SkPDFObject*>);
+ SkPDFCatalog catalog;
+ SkTDArray<SkPDFDict*> pageTree;
+ SkAutoTUnref<SkPDFDict> docCatalog(SkNEW(SkPDFDict));
+ SkTDArray<SkPDFObject*> substitutes;
+ SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict));
- // We haven't emitted the document before if fPageTree is empty.
- if (fPageTree.isEmpty()) {
- SkPDFDict* pageTreeRoot;
- SkPDFPage::GeneratePageTree(fPages, fCatalog.get(), &fPageTree,
- &pageTreeRoot);
- fDocCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref();
+ SkPDFDict* pageTreeRoot;
+ SkPDFPage::GeneratePageTree(fPages, &pageTree, &pageTreeRoot);
+ docCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref();
- /* TODO(vandebo): output intent
- SkAutoTUnref<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent");
- outputIntent->insert("S", new SkPDFName("GTS_PDFA1"))->unref();
- outputIntent->insert("OutputConditionIdentifier",
- new SkPDFString("sRGB"))->unref();
- SkAutoTUnref<SkPDFArray> intentArray = new SkPDFArray;
- intentArray->append(outputIntent.get());
- fDocCatalog->insert("OutputIntent", intentArray.get());
- */
+ /* TODO(vandebo): output intent
+ SkAutoTUnref<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent");
+ outputIntent->insert("S", new SkPDFName("GTS_PDFA1"))->unref();
+ outputIntent->insert("OutputConditionIdentifier",
+ new SkPDFString("sRGB"))->unref();
+ SkAutoTUnref<SkPDFArray> intentArray = new SkPDFArray;
+ intentArray->append(outputIntent.get());
+ fDocCatalog->insert("OutputIntent", intentArray.get());
+ */
- SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict));
-
- 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++) {
- if (i == 1) {
- firstPage = false;
- 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);
- }
+ SkTSet<SkPDFObject*> knownResources;
+ for (int i = 0; i < fPages.count(); i++) {
+ SkTSet<SkPDFObject*> newResources;
+ fPages[i]->finalizePage();
+ fPages[i]->appendDestinations(dests);
+ }
- if (dests->size() > 0) {
- SkPDFDict* raw_dests = dests.get();
- fFirstPageResources->add(dests.detach()); // Transfer ownership.
- fCatalog->addObject(raw_dests, true /* onFirstPage */);
- fDocCatalog->insert("Dests", SkNEW_ARGS(SkPDFObjRef, (raw_dests)))->unref();
- }
+ // Build font subsetting info before proceeding.
+ perform_font_subsetting(fPages, &catalog);
- // Build font subsetting info before proceeding.
- perform_font_subsetting(fCatalog.get(), fPages, &fSubstitutes);
+ if (dests->size() > 0) {
+ docCatalog->insert("Dests", SkNEW_ARGS(SkPDFObjRef, (dests.get())))
+ ->unref();
}
SkTSet<SkPDFObject*> resourceSet;
- if (resourceSet.add(fDocCatalog)) {
- fDocCatalog->addResources(&resourceSet, fCatalog);
+ if (resourceSet.add(docCatalog)) {
+ docCatalog->addResources(&resourceSet, &catalog);
}
- off_t baseOffset = SkToOffT(stream->bytesWritten());
- emitHeader(stream);
+ for (int i = 0; i < resourceSet.count(); ++i) {
+ catalog.addObject(resourceSet[i]);
+ }
+
+ size_t baseOffset = stream->bytesWritten();
+ emit_pdf_header(stream);
+
+ SkTDArray<int32_t> objectOffsets;
+
for (int i = 0; i < resourceSet.count(); ++i) {
SkPDFObject* object = resourceSet[i];
- fCatalog->setFileOffset(object,
- SkToOffT(stream->bytesWritten()) - baseOffset);
- SkASSERT(object == fCatalog->getSubstituteObject(object));
- stream->writeDecAsText(fCatalog->getObjectNumber(object));
+ int32_t offset = SkToS32(stream->bytesWritten() - baseOffset);
+ objectOffsets.push(offset);
+ int32_t objectNumber = catalog.getObjectNumber(object);
+ SkASSERT(object == catalog.getSubstituteObject(object));
+ stream->writeDecAsText(objectNumber);
stream->writeText(" 0 obj\n"); // Generation number is always 0.
- object->emitObject(stream, fCatalog);
+ object->emitObject(stream, &catalog);
stream->writeText("\nendobj\n");
}
- fXRefFileOffset = SkToOffT(stream->bytesWritten()) - baseOffset;
- int64_t objCount = fCatalog->emitXrefTable(stream, fPages.count() > 1);
- emitFooter(stream, objCount);
- return true;
-}
+ int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset);
-// TODO(halcanary): remove this method, since it is unused.
-bool SkPDFDocument::setPage(int pageNumber, SkPDFDevice* pdfDevice) {
- if (!fPageTree.isEmpty()) {
- return false;
+ stream->writeText("xref\n0 ");
+ stream->writeDecAsText(objectOffsets.count() + 1);
+ stream->writeText("\n0000000000 65535 f \n");
+ for (int i = 0; i < objectOffsets.count(); i++) {
+ SkASSERT(objectOffsets[i] > 0);
+ stream->writeBigDecAsText(objectOffsets[i], 10);
+ stream->writeText(" 00000 n \n");
}
+ int64_t objCount = objectOffsets.count() + 1;
- pageNumber--;
- SkASSERT(pageNumber >= 0);
+ emit_pdf_footer(stream, &catalog, docCatalog.get(), objCount,
+ xRefFileOffset);
- if (pageNumber >= fPages.count()) {
- int oldSize = fPages.count();
- fPages.setCount(pageNumber + 1);
- for (int i = oldSize; i <= pageNumber; i++) {
- fPages[i] = NULL;
- }
+ // The page tree has both child and parent pointers, so it creates a
+ // reference cycle. We must clear that cycle to properly reclaim memory.
+ for (int i = 0; i < pageTree.count(); i++) {
+ pageTree[i]->clear();
}
-
- SkPDFPage* page = new SkPDFPage(pdfDevice);
- SkSafeUnref(fPages[pageNumber]);
- fPages[pageNumber] = page; // Reference from new passed to fPages.
+ pageTree.safeUnrefAll();
return true;
}
bool SkPDFDocument::appendPage(SkPDFDevice* pdfDevice) {
- if (!fPageTree.isEmpty()) {
- return false;
- }
-
- SkPDFPage* page = new SkPDFPage(pdfDevice);
- fPages.push(page); // Reference from new passed to fPages.
+ fPages.push(
+ new SkPDFPage(pdfDevice)); // Reference from new passed to fPages.
return true;
}
-// Deprecated.
-// TODO(halcanary): remove
-void SkPDFDocument::getCountOfFontTypes(
- int counts[SkAdvancedTypefaceMetrics::kOther_Font + 2]) const {
- sk_bzero(counts, sizeof(int) *
- (SkAdvancedTypefaceMetrics::kOther_Font + 2));
- SkTDArray<SkFontID> seenFonts;
- int notEmbeddable = 0;
-
- for (int pageNumber = 0; pageNumber < fPages.count(); pageNumber++) {
- const SkTDArray<SkPDFFont*>& fontResources =
- fPages[pageNumber]->getFontResources();
- for (int font = 0; font < fontResources.count(); font++) {
- SkFontID fontID = fontResources[font]->typeface()->uniqueID();
- if (seenFonts.find(fontID) == -1) {
- counts[fontResources[font]->getType()]++;
- seenFonts.push(fontID);
- if (!fontResources[font]->canEmbed()) {
- notEmbeddable++;
- }
- }
- }
- }
- counts[SkAdvancedTypefaceMetrics::kOther_Font + 1] = notEmbeddable;
-}
// TODO(halcanary): expose notEmbeddableCount in SkDocument
void SkPDFDocument::getCountOfFontTypes(
@@ -278,34 +204,3 @@ void SkPDFDocument::getCountOfFontTypes(
}
}
-void SkPDFDocument::emitHeader(SkWStream* stream) {
- stream->writeText("%PDF-1.4\n%");
- // The PDF spec recommends including a comment with four bytes, all
- // with their high bits set. This is "Skia" with the high bits set.
- stream->write32(0xD3EBE9E1);
- stream->writeText("\n");
-}
-
-//TODO(halcanary): remove this function
-size_t SkPDFDocument::headerSize() {
- SkDynamicMemoryWStream buffer;
- emitHeader(&buffer);
- return buffer.getOffset();
-}
-
-void SkPDFDocument::emitFooter(SkWStream* stream, int64_t objCount) {
- if (NULL == fTrailerDict) {
- fTrailerDict = SkNEW(SkPDFDict);
-
- // TODO(vandebo): Linearized format will take a Prev entry too.
- // TODO(vandebo): PDF/A requires an ID entry.
- fTrailerDict->insertInt("Size", int(objCount));
- fTrailerDict->insert("Root", new SkPDFObjRef(fDocCatalog))->unref();
- }
-
- stream->writeText("trailer\n");
- fTrailerDict->emitObject(stream, fCatalog.get());
- stream->writeText("\nstartxref\n");
- stream->writeBigDecAsText(fXRefFileOffset);
- stream->writeText("\n%%EOF");
-}
« src/pdf/SkPDFCatalog.cpp ('K') | « src/pdf/SkPDFDocument.h ('k') | src/pdf/SkPDFPage.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698