Index: src/pdf/SkPDFDocument.cpp |
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp |
index 66635a98fb43a02a2ae845acc586f3e0c2a6a52a..8e884d5e834f20e5859a57ea0a3963168be92733 100644 |
--- a/src/pdf/SkPDFDocument.cpp |
+++ b/src/pdf/SkPDFDocument.cpp |
@@ -93,45 +93,9 @@ int32_t SkPDFObjectSerializer::offset(SkWStream* wStream) { |
return SkToS32(offset - fBaseOffset); |
} |
-static void perform_font_subsetting( |
- const SkTArray<sk_sp<const SkPDFDevice>>& pageDevices, |
- SkPDFSubstituteMap* substituteMap) { |
- SkASSERT(substituteMap); |
- |
- SkPDFGlyphSetMap usage; |
- for (const sk_sp<const SkPDFDevice>& pageDevice : pageDevices) { |
- usage.merge(pageDevice->getFontGlyphUsage()); |
- } |
- SkPDFGlyphSetMap::F2BIter iterator(usage); |
- const SkPDFGlyphSetMap::FontGlyphSetPair* entry = iterator.next(); |
- while (entry) { |
- sk_sp<SkPDFFont> subsetFont( |
- entry->fFont->getFontSubset(entry->fGlyphSet)); |
- if (subsetFont) { |
- substituteMap->setSubstitute(entry->fFont, subsetFont.get()); |
- } |
- entry = iterator.next(); |
- } |
-} |
- |
-static sk_sp<SkPDFDict> create_pdf_page(const SkPDFDevice* pageDevice) { |
- auto page = sk_make_sp<SkPDFDict>("Page"); |
- page->insertObject("Resources", pageDevice->makeResourceDict()); |
- page->insertObject("MediaBox", pageDevice->copyMediaBox()); |
- auto annotations = sk_make_sp<SkPDFArray>(); |
- pageDevice->appendAnnotations(annotations.get()); |
- if (annotations->size() > 0) { |
- page->insertObject("Annots", std::move(annotations)); |
- } |
- auto content = pageDevice->content(); |
- page->insertObjRef("Contents", sk_make_sp<SkPDFStream>(content.get())); |
- return page; |
-} |
// return root node. |
-static sk_sp<SkPDFDict> generate_page_tree( |
- SkTDArray<SkPDFDict*>& pages, |
- SkTDArray<SkPDFDict*>* pageTree) { |
+static sk_sp<SkPDFDict> generate_page_tree(SkTArray<sk_sp<SkPDFDict>>* pages) { |
// PDF wants a tree describing all the pages in the document. We arbitrary |
// choose 8 (kNodeSize) as the number of allowed children. The internal |
// nodes have type "Pages" with an array of children, a parent pointer, and |
@@ -142,22 +106,18 @@ static sk_sp<SkPDFDict> generate_page_tree( |
static const int kNodeSize = 8; |
// curNodes takes a reference to its items, which it passes to pageTree. |
- SkTDArray<SkPDFDict*> curNodes; |
- curNodes.setReserve(pages.count()); |
- for (int i = 0; i < pages.count(); i++) { |
- SkSafeRef(pages[i]); |
- curNodes.push(pages[i]); |
- } |
+ int totalPageCount = pages->count(); |
+ SkTArray<sk_sp<SkPDFDict>> curNodes; |
+ curNodes.swap(pages); |
// nextRoundNodes passes its references to nodes on to curNodes. |
- SkTDArray<SkPDFDict*> nextRoundNodes; |
- nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize); |
- |
int treeCapacity = kNodeSize; |
do { |
+ SkTArray<sk_sp<SkPDFDict>> nextRoundNodes; |
for (int i = 0; i < curNodes.count(); ) { |
if (i > 0 && i + 1 == curNodes.count()) { |
- nextRoundNodes.push(curNodes[i]); |
+ SkASSERT(curNodes[i]); |
+ nextRoundNodes.emplace_back(std::move(curNodes[i])); |
break; |
} |
@@ -167,16 +127,9 @@ static sk_sp<SkPDFDict> generate_page_tree( |
int count = 0; |
for (; i < curNodes.count() && count < kNodeSize; i++, count++) { |
+ SkASSERT(curNodes[i]); |
curNodes[i]->insertObjRef("Parent", newNode); |
- kids->appendObjRef(sk_ref_sp(curNodes[i])); |
- |
- // TODO(vandebo): put the objects in strict access order. |
- // Probably doesn't matter because they are so small. |
- if (curNodes[i] != pages[0]) { |
- pageTree->push(curNodes[i]); // Transfer reference. |
- } else { |
- SkSafeUnref(curNodes[i]); |
- } |
+ kids->appendObjRef(std::move(curNodes[i])); |
} |
// treeCapacity is the number of leaf nodes possible for the |
@@ -188,20 +141,19 @@ static sk_sp<SkPDFDict> generate_page_tree( |
// consuming treeCapacity chunks. |
int pageCount = treeCapacity; |
if (i == curNodes.count()) { |
- pageCount = ((pages.count() - 1) % treeCapacity) + 1; |
+ pageCount = ((totalPageCount - 1) % treeCapacity) + 1; |
} |
newNode->insertInt("Count", pageCount); |
newNode->insertObject("Kids", std::move(kids)); |
- nextRoundNodes.push(newNode.release()); // Transfer reference. |
+ nextRoundNodes.emplace_back(std::move(newNode)); |
} |
+ SkDEBUGCODE( for (const auto& n : curNodes) { SkASSERT(!n); } ); |
- curNodes = nextRoundNodes; |
- nextRoundNodes.rewind(); |
+ curNodes.swap(&nextRoundNodes); |
+ nextRoundNodes.reset(); |
treeCapacity *= kNodeSize; |
} while (curNodes.count() > 1); |
- |
- pageTree->push(curNodes[0]); // Transfer reference. |
- return sk_ref_sp(curNodes[0]); |
+ return std::move(curNodes[0]); |
} |
#if 0 |
@@ -269,16 +221,16 @@ void SkPDFDocument::serialize(const sk_sp<SkPDFObject>& object) { |
SkCanvas* SkPDFDocument::onBeginPage(SkScalar width, SkScalar height, |
const SkRect& trimBox) { |
SkASSERT(!fCanvas.get()); // endPage() was called before this. |
- if (fPageDevices.empty()) { |
+ if (fPages.empty()) { |
// if this is the first page if the document. |
fObjectSerializer.serializeHeader(this->getStream(), fMetadata); |
+ fDests = sk_make_sp<SkPDFDict>(); |
} |
SkISize pageSize = SkISize::Make( |
SkScalarRoundToInt(width), SkScalarRoundToInt(height)); |
- sk_sp<SkPDFDevice> device( |
+ fPageDevice.reset( |
SkPDFDevice::Create(pageSize, fRasterDpi, this)); |
- fCanvas = sk_make_sp<SkPDFCanvas>(device); |
- fPageDevices.push_back(std::move(device)); |
+ fCanvas = sk_make_sp<SkPDFCanvas>(fPageDevice); |
fCanvas->clipRect(trimBox); |
fCanvas->translate(trimBox.x(), trimBox.y()); |
return fCanvas.get(); |
@@ -288,11 +240,28 @@ void SkPDFDocument::onEndPage() { |
SkASSERT(fCanvas.get()); |
fCanvas->flush(); |
fCanvas.reset(nullptr); |
+ SkASSERT(fPageDevice); |
+ fGlyphUsage.merge(fPageDevice->getFontGlyphUsage()); |
+ auto page = sk_make_sp<SkPDFDict>("Page"); |
+ page->insertObject("Resources", fPageDevice->makeResourceDict()); |
+ page->insertObject("MediaBox", fPageDevice->copyMediaBox()); |
+ auto annotations = sk_make_sp<SkPDFArray>(); |
+ fPageDevice->appendAnnotations(annotations.get()); |
+ if (annotations->size() > 0) { |
+ page->insertObject("Annots", std::move(annotations)); |
+ } |
+ auto contentData = fPageDevice->content(); |
+ auto contentObject = sk_make_sp<SkPDFStream>(contentData.get()); |
+ this->serialize(contentObject); |
+ page->insertObjRef("Contents", std::move(contentObject)); |
+ fPageDevice->appendDestinations(fDests.get(), page.get()); |
+ fPages.emplace_back(std::move(page)); |
+ fPageDevice.reset(nullptr); |
} |
void SkPDFDocument::onAbort() { |
fCanvas.reset(nullptr); |
- fPageDevices.reset(); |
+ fPages.reset(); |
fCanon.reset(); |
renew(&fObjectSerializer); |
} |
@@ -308,25 +277,13 @@ void SkPDFDocument::setMetadata(const SkDocument::Attribute info[], |
bool SkPDFDocument::onClose(SkWStream* stream) { |
SkASSERT(!fCanvas.get()); |
- if (fPageDevices.empty()) { |
- fPageDevices.reset(); |
+ if (fPages.empty()) { |
+ fPages.reset(); |
fCanon.reset(); |
renew(&fObjectSerializer); |
return false; |
} |
- SkTDArray<SkPDFDict*> pages; // TODO: SkTArray<sk_sp<SkPDFDict>> |
- auto dests = sk_make_sp<SkPDFDict>(); |
- |
- for (const sk_sp<const SkPDFDevice>& pageDevice : fPageDevices) { |
- SkASSERT(pageDevice); |
- SkASSERT(fPageDevices[0]->getCanon() == pageDevice->getCanon()); |
- sk_sp<SkPDFDict> page(create_pdf_page(pageDevice.get())); |
- pageDevice->appendDestinations(dests.get(), page.get()); |
- pages.push(page.release()); |
- } |
- |
auto docCatalog = sk_make_sp<SkPDFDict>("Catalog"); |
- |
sk_sp<SkPDFObject> id, xmp; |
#ifdef SK_PDF_GENERATE_PDFA |
SkPDFMetadata::UUID uuid = metadata.uuid(); |
@@ -352,24 +309,28 @@ bool SkPDFDocument::onClose(SkWStream* stream) { |
docCatalog->insertObject("OutputIntents", std::move(intentArray)); |
#endif |
- SkTDArray<SkPDFDict*> pageTree; |
- docCatalog->insertObjRef("Pages", generate_page_tree(pages, &pageTree)); |
+ docCatalog->insertObjRef("Pages", generate_page_tree(&fPages)); |
- if (dests->size() > 0) { |
- docCatalog->insertObjRef("Dests", std::move(dests)); |
+ if (fDests->size() > 0) { |
+ docCatalog->insertObjRef("Dests", std::move(fDests)); |
} |
// Build font subsetting info before calling addObjectRecursively(). |
- perform_font_subsetting(fPageDevices, &fObjectSerializer.fSubstituteMap); |
+ for (const auto& entry : fGlyphUsage) { |
+ sk_sp<SkPDFFont> subsetFont( |
+ entry.fFont->getFontSubset(entry.fGlyphSet)); |
+ if (subsetFont) { |
+ fObjectSerializer.fSubstituteMap.setSubstitute( |
+ entry.fFont, subsetFont.get()); |
+ } |
+ } |
fObjectSerializer.addObjectRecursively(docCatalog); |
fObjectSerializer.serializeObjects(this->getStream()); |
fObjectSerializer.serializeFooter( |
this->getStream(), docCatalog, std::move(id)); |
- pageTree.unrefAll(); // TODO(halcanary): make this unnecesary by |
- // refactoring generate_page_tree(). |
- pages.unrefAll(); |
- fPageDevices.reset(); |
+ |
+ SkASSERT(fPages.count() == 0); |
fCanon.reset(); |
renew(&fObjectSerializer); |
return true; |