aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf/SkPDFDocument.cpp
diff options
context:
space:
mode:
authorGravatar halcanary <halcanary@google.com>2015-03-25 05:06:30 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-03-25 05:06:30 -0700
commit6adf849f4eedd19591ce35129a846209e7e6393b (patch)
treea2f3ad6fe59b01422c8fd57d1bf08e782454aa74 /src/pdf/SkPDFDocument.cpp
parentc7c91806e35da06b13394262d83c169a83f76b1d (diff)
SkPDF refactor skpdfdocument
Most fields removed, made local to emitPDF function (since we never emit twice). Variables made into stack variables or auto-unrefed. we hold devices, not pages. addResourcesToCatalog inlined unused setPage function removed. deprecated getCountOfFontTypes function removed private functions removed BUG=skia:3585 Review URL: https://codereview.chromium.org/1034583002
Diffstat (limited to 'src/pdf/SkPDFDocument.cpp')
-rw-r--r--src/pdf/SkPDFDocument.cpp329
1 files changed, 125 insertions, 204 deletions
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index 1807673edc..4009cef9b6 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -15,13 +15,6 @@
#include "SkPDFTypes.h"
#include "SkStream.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,
@@ -46,200 +39,160 @@ static void perform_font_subsetting(SkPDFCatalog* catalog,
}
}
-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();
+SkPDFDocument::~SkPDFDocument() { fPageDevices.unrefAll(); }
- // 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) {
- if (fPages.isEmpty()) {
+ // SkTDArray<SkPDFDevice*> fPageDevices;
+ if (fPageDevices.isEmpty()) {
return false;
}
- for (int i = 0; i < fPages.count(); i++) {
- if (fPages[i] == NULL) {
- return false;
+ SkTDArray<SkPDFPage*> pages;
+ for (int i = 0; i < fPageDevices.count(); i++) {
+ // Reference from new passed to pages.
+ pages.push(SkNEW_ARGS(SkPDFPage, (fPageDevices[i])));
+ }
+ SkPDFCatalog catalog;
+
+ SkTDArray<SkPDFDict*> pageTree;
+ SkAutoTUnref<SkPDFDict> docCatalog(SkNEW_ARGS(SkPDFDict, ("Catalog")));
+ SkTSet<SkPDFObject*> firstPageResources;
+ SkTSet<SkPDFObject*> otherPageResources;
+ SkTDArray<SkPDFObject*> substitutes;
+ catalog.addObject(docCatalog.get(), true);
+
+ SkPDFDict* pageTreeRoot;
+ SkPDFPage::GeneratePageTree(pages, &catalog, &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());
+ docCatalog->insert("OutputIntent", intentArray.get());
+ */
+
+ SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict));
+
+ bool firstPage = true;
+ /* The references returned in newResources are transfered to
+ * firstPageResources or otherPageResources 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(firstPageResources);
+ SkASSERT(duplicates == 0);
+
+ for (int i = 0; i < pages.count(); i++) {
+ if (i == 1) {
+ firstPage = false;
+ SkDEBUGCODE(duplicates = )
+ knownResources.mergeInto(otherPageResources);
+ }
+ SkTSet<SkPDFObject*> newResources;
+ pages[i]->finalizePage(&catalog, firstPage, knownResources,
+ &newResources);
+ for (int j = 0; j < newResources.count(); j++) {
+ catalog.addObject(newResources[i], firstPage);
+ }
+ if (firstPage) {
+ SkDEBUGCODE(duplicates = )
+ firstPageResources.mergeInto(newResources);
+ } else {
+ SkDEBUGCODE(duplicates = )
+ otherPageResources.mergeInto(newResources);
}
- }
-
- fFirstPageResources = SkNEW(SkTSet<SkPDFObject*>);
- fOtherPageResources = SkNEW(SkTSet<SkPDFObject*>);
-
- // 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();
-
- /* 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);
- }
+ SkDEBUGCODE(duplicates = ) knownResources.mergeInto(newResources);
+ SkASSERT(duplicates == 0);
- 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();
- }
+ pages[i]->appendDestinations(dests);
+ }
- // Build font subsetting info before proceeding.
- perform_font_subsetting(fCatalog.get(), fPages, &fSubstitutes);
+ if (dests->size() > 0) {
+ SkPDFDict* raw_dests = dests.get();
+ firstPageResources.add(dests.detach()); // Transfer ownership.
+ catalog.addObject(raw_dests, true /* onFirstPage */);
+ docCatalog->insert("Dests", SkNEW_ARGS(SkPDFObjRef, (raw_dests)))
+ ->unref();
}
+ // Build font subsetting info before proceeding.
+ perform_font_subsetting(&catalog, pages, &substitutes);
+
SkTSet<SkPDFObject*> resourceSet;
- if (resourceSet.add(fDocCatalog)) {
- fDocCatalog->addResources(&resourceSet, fCatalog);
+ if (resourceSet.add(docCatalog.get())) {
+ docCatalog->addResources(&resourceSet, &catalog);
}
- off_t baseOffset = SkToOffT(stream->bytesWritten());
- emitHeader(stream);
+ size_t baseOffset = SkToOffT(stream->bytesWritten());
+ emit_pdf_header(stream);
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));
+ catalog.setFileOffset(object,
+ SkToOffT(stream->bytesWritten() - baseOffset));
+ SkASSERT(object == catalog.getSubstituteObject(object));
+ stream->writeDecAsText(catalog.getObjectNumber(object));
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;
-}
-
-// TODO(halcanary): remove this method, since it is unused.
-bool SkPDFDocument::setPage(int pageNumber, SkPDFDevice* pdfDevice) {
- if (!fPageTree.isEmpty()) {
- return false;
- }
+ int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset);
+ int64_t objCount = catalog.emitXrefTable(stream, pages.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();
}
+ pageTree.safeUnrefAll();
+ pages.unrefAll();
- SkPDFPage* page = new SkPDFPage(pdfDevice);
- SkSafeUnref(fPages[pageNumber]);
- fPages[pageNumber] = page; // Reference from new passed to fPages.
- return true;
-}
-
-bool SkPDFDocument::appendPage(SkPDFDevice* pdfDevice) {
- if (!fPageTree.isEmpty()) {
- return false;
- }
+ firstPageResources.safeUnrefAll();
+ otherPageResources.safeUnrefAll();
- SkPDFPage* page = new SkPDFPage(pdfDevice);
- fPages.push(page); // Reference from new passed to fPages.
+ substitutes.unrefAll();
+ docCatalog.reset(NULL);
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(
int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1],
@@ -251,9 +204,9 @@ void SkPDFDocument::getCountOfFontTypes(
int notSubsettable = 0;
int notEmbeddable = 0;
- for (int pageNumber = 0; pageNumber < fPages.count(); pageNumber++) {
+ for (int pageNumber = 0; pageNumber < fPageDevices.count(); pageNumber++) {
const SkTDArray<SkPDFFont*>& fontResources =
- fPages[pageNumber]->getFontResources();
+ fPageDevices[pageNumber]->getFontResources();
for (int font = 0; font < fontResources.count(); font++) {
SkFontID fontID = fontResources[font]->typeface()->uniqueID();
if (seenFonts.find(fontID) == -1) {
@@ -276,35 +229,3 @@ void SkPDFDocument::getCountOfFontTypes(
*notEmbeddableCount = notEmbeddable;
}
}
-
-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");
-}