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

Unified Diff: src/doc/SkDocument_PDF.cpp

Issue 1781773002: SkPDF: move all pdf sources into src/pdf (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2016-03-10 (Thursday) 15:59:02 EST Created 4 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
« no previous file with comments | « src/doc/SkDocument.cpp ('k') | src/doc/SkDocument_PDF_None.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/doc/SkDocument_PDF.cpp
diff --git a/src/doc/SkDocument_PDF.cpp b/src/doc/SkDocument_PDF.cpp
deleted file mode 100644
index c866648ae7fecae8cbc020cfd0b997aac4c289fa..0000000000000000000000000000000000000000
--- a/src/doc/SkDocument_PDF.cpp
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkDocument.h"
-#include "SkPDFCanon.h"
-#include "SkPDFDevice.h"
-#include "SkPDFFont.h"
-#include "SkPDFStream.h"
-#include "SkPDFTypes.h"
-#include "SkPDFUtils.h"
-#include "SkStream.h"
-#include "SkPDFMetadata.h"
-
-class SkPDFDict;
-
-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");
-}
-
-static void emit_pdf_footer(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes,
- SkPDFObject* docCatalog,
- int64_t objCount,
- int32_t xRefFileOffset,
- sk_sp<SkPDFObject> info,
- sk_sp<SkPDFObject> id) {
- SkPDFDict trailerDict;
- // TODO(http://crbug.com/80908): Linearized format will take a
- // Prev entry too.
- trailerDict.insertInt("Size", int(objCount));
- trailerDict.insertObjRef("Root", sk_ref_sp(docCatalog));
- SkASSERT(info);
- trailerDict.insertObjRef("Info", std::move(info));
- if (id) {
- trailerDict.insertObject("ID", std::move(id));
- }
- stream->writeText("trailer\n");
- trailerDict.emitObject(stream, objNumMap, substitutes);
- stream->writeText("\nstartxref\n");
- stream->writeBigDecAsText(xRefFileOffset);
- stream->writeText("\n%%EOF");
-}
-
-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(
- const SkTDArray<SkPDFDict*>& pages,
- SkTDArray<SkPDFDict*>* pageTree) {
- // 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
- // the number of leaves below the node as "Count." The leaves are passed
- // into the method, have type "Page" and need a parent pointer. This method
- // builds the tree bottom up, skipping internal nodes that would have only
- // one child.
- 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]);
- }
-
- // nextRoundNodes passes its references to nodes on to curNodes.
- SkTDArray<SkPDFDict*> nextRoundNodes;
- nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize);
-
- int treeCapacity = kNodeSize;
- do {
- for (int i = 0; i < curNodes.count(); ) {
- if (i > 0 && i + 1 == curNodes.count()) {
- nextRoundNodes.push(curNodes[i]);
- break;
- }
-
- auto newNode = sk_make_sp<SkPDFDict>("Pages");
- auto kids = sk_make_sp<SkPDFArray>();
- kids->reserve(kNodeSize);
-
- int count = 0;
- for (; i < curNodes.count() && count < kNodeSize; i++, count++) {
- 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]);
- }
- }
-
- // treeCapacity is the number of leaf nodes possible for the
- // current set of subtrees being generated. (i.e. 8, 64, 512, ...).
- // It is hard to count the number of leaf nodes in the current
- // subtree. However, by construction, we know that unless it's the
- // last subtree for the current depth, the leaf count will be
- // treeCapacity, otherwise it's what ever is left over after
- // consuming treeCapacity chunks.
- int pageCount = treeCapacity;
- if (i == curNodes.count()) {
- pageCount = ((pages.count() - 1) % treeCapacity) + 1;
- }
- newNode->insertInt("Count", pageCount);
- newNode->insertObject("Kids", std::move(kids));
- nextRoundNodes.push(newNode.release()); // Transfer reference.
- }
-
- curNodes = nextRoundNodes;
- nextRoundNodes.rewind();
- treeCapacity *= kNodeSize;
- } while (curNodes.count() > 1);
-
- pageTree->push(curNodes[0]); // Transfer reference.
- return sk_ref_sp(curNodes[0]);
-}
-
-static bool emit_pdf_document(const SkTArray<sk_sp<const SkPDFDevice>>& pageDevices,
- const SkPDFMetadata& metadata,
- SkWStream* stream) {
- if (pageDevices.empty()) {
- return false;
- }
-
- SkTDArray<SkPDFDict*> pages; // TODO: SkTArray<sk_sp<SkPDFDict>>
- auto dests = sk_make_sp<SkPDFDict>();
-
- for (const sk_sp<const SkPDFDevice>& pageDevice : pageDevices) {
- SkASSERT(pageDevice);
- SkASSERT(pageDevices[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> infoDict(metadata.createDocumentInformationDict());
-
- sk_sp<SkPDFObject> id, xmp;
-#ifdef SK_PDF_GENERATE_PDFA
- SkPDFMetadata::UUID uuid = metadata.uuid();
- // We use the same UUID for Document ID and Instance ID since this
- // is the first revision of this document (and Skia does not
- // support revising existing PDF documents).
- // If we are not in PDF/A mode, don't use a UUID since testing
- // works best with reproducible outputs.
- id.reset(SkPDFMetadata::CreatePdfId(uuid, uuid));
- xmp.reset(metadata.createXMPObject(uuid, uuid));
- docCatalog->insertObjRef("Metadata", std::move(xmp));
-
- // sRGB is specified by HTML, CSS, and SVG.
- auto outputIntent = sk_make_sp<SkPDFDict>("OutputIntent");
- outputIntent->insertName("S", "GTS_PDFA1");
- outputIntent->insertString("RegistryName", "http://www.color.org");
- outputIntent->insertString("OutputConditionIdentifier",
- "sRGB IEC61966-2.1");
- auto intentArray = sk_make_sp<SkPDFArray>();
- intentArray->appendObject(std::move(outputIntent));
- // Don't specify OutputIntents if we are not in PDF/A mode since
- // no one has ever asked for this feature.
- docCatalog->insertObject("OutputIntents", std::move(intentArray));
-#endif
-
- SkTDArray<SkPDFDict*> pageTree;
- docCatalog->insertObjRef("Pages", generate_page_tree(pages, &pageTree));
-
- if (dests->size() > 0) {
- docCatalog->insertObjRef("Dests", std::move(dests));
- }
-
- // Build font subsetting info before proceeding.
- SkPDFSubstituteMap substitutes;
- perform_font_subsetting(pageDevices, &substitutes);
-
- SkPDFObjNumMap objNumMap;
- objNumMap.addObjectRecursively(infoDict.get(), substitutes);
- objNumMap.addObjectRecursively(docCatalog.get(), substitutes);
- size_t baseOffset = stream->bytesWritten();
- emit_pdf_header(stream);
- SkTDArray<int32_t> offsets;
- for (int i = 0; i < objNumMap.objects().count(); ++i) {
- SkPDFObject* object = objNumMap.objects()[i];
- size_t offset = stream->bytesWritten();
- // This assert checks that size(pdf_header) > 0 and that
- // the output stream correctly reports bytesWritten().
- SkASSERT(offset > baseOffset);
- offsets.push(SkToS32(offset - baseOffset));
- SkASSERT(object == substitutes.getSubstitute(object));
- SkASSERT(objNumMap.getObjectNumber(object) == i + 1);
- stream->writeDecAsText(i + 1);
- stream->writeText(" 0 obj\n"); // Generation number is always 0.
- object->emitObject(stream, objNumMap, substitutes);
- stream->writeText("\nendobj\n");
- }
- int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset);
-
- // Include the zeroth object in the count.
- int32_t objCount = SkToS32(offsets.count() + 1);
-
- stream->writeText("xref\n0 ");
- stream->writeDecAsText(objCount);
- stream->writeText("\n0000000000 65535 f \n");
- for (int i = 0; i < offsets.count(); i++) {
- SkASSERT(offsets[i] > 0);
- stream->writeBigDecAsText(offsets[i], 10);
- stream->writeText(" 00000 n \n");
- }
- emit_pdf_footer(stream, objNumMap, substitutes, docCatalog.get(), objCount,
- xRefFileOffset, std::move(infoDict), std::move(id));
-
- // 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();
- return true;
-}
-
-#if 0
-// TODO(halcanary): expose notEmbeddableCount in SkDocument
-void GetCountOfFontTypes(
- const SkTDArray<SkPDFDevice*>& pageDevices,
- int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1],
- int* notSubsettableCount,
- int* notEmbeddableCount) {
- sk_bzero(counts, sizeof(int) *
- (SkAdvancedTypefaceMetrics::kOther_Font + 1));
- SkTDArray<SkFontID> seenFonts;
- int notSubsettable = 0;
- int notEmbeddable = 0;
-
- for (int pageNumber = 0; pageNumber < pageDevices.count(); pageNumber++) {
- const SkTDArray<SkPDFFont*>& fontResources =
- pageDevices[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]->canSubset()) {
- notSubsettable++;
- }
- if (!fontResources[font]->canEmbed()) {
- notEmbeddable++;
- }
- }
- }
- }
- if (notSubsettableCount) {
- *notSubsettableCount = notSubsettable;
-
- }
- if (notEmbeddableCount) {
- *notEmbeddableCount = notEmbeddable;
- }
-}
-#endif
-
-template <typename T> static T* clone(const T* o) { return o ? new T(*o) : nullptr; }
-////////////////////////////////////////////////////////////////////////////////
-
-namespace {
-class SkDocument_PDF : public SkDocument {
-public:
- SkDocument_PDF(SkWStream* stream,
- void (*doneProc)(SkWStream*, bool),
- SkScalar rasterDpi,
- SkPixelSerializer* jpegEncoder)
- : SkDocument(stream, doneProc)
- , fRasterDpi(rasterDpi) {
- fCanon.setPixelSerializer(SkSafeRef(jpegEncoder));
- }
-
- virtual ~SkDocument_PDF() {
- // subclasses must call close() in their destructors
- this->close();
- }
-
-protected:
- SkCanvas* onBeginPage(SkScalar width, SkScalar height,
- const SkRect& trimBox) override {
- SkASSERT(!fCanvas.get());
-
- SkISize pageSize = SkISize::Make(
- SkScalarRoundToInt(width), SkScalarRoundToInt(height));
- sk_sp<SkPDFDevice> device(
- SkPDFDevice::Create(pageSize, fRasterDpi, &fCanon));
- fCanvas.reset(new SkCanvas(device.get()));
- fPageDevices.push_back(std::move(device));
- fCanvas->clipRect(trimBox);
- fCanvas->translate(trimBox.x(), trimBox.y());
- return fCanvas.get();
- }
-
- void onEndPage() override {
- SkASSERT(fCanvas.get());
- fCanvas->flush();
- fCanvas.reset(nullptr);
- }
-
- bool onClose(SkWStream* stream) override {
- SkASSERT(!fCanvas.get());
-
- bool success = emit_pdf_document(fPageDevices, fMetadata, stream);
- fPageDevices.reset();
- fCanon.reset();
- return success;
- }
-
- void onAbort() override {
- fPageDevices.reset();
- fCanon.reset();
- }
-
- void setMetadata(const SkDocument::Attribute info[],
- int infoCount,
- const SkTime::DateTime* creationDate,
- const SkTime::DateTime* modifiedDate) override {
- fMetadata.fInfo.reset(info, infoCount);
- fMetadata.fCreation.reset(clone(creationDate));
- fMetadata.fModified.reset(clone(modifiedDate));
- }
-
-private:
- SkPDFCanon fCanon;
- SkTArray<sk_sp<const SkPDFDevice>> fPageDevices;
- sk_sp<SkCanvas> fCanvas;
- SkScalar fRasterDpi;
- SkPDFMetadata fMetadata;
-};
-} // namespace
-///////////////////////////////////////////////////////////////////////////////
-
-SkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) {
- return stream ? new SkDocument_PDF(stream, nullptr, dpi, nullptr) : nullptr;
-}
-
-SkDocument* SkDocument::CreatePDF(SkWStream* stream,
- SkScalar dpi,
- SkPixelSerializer* jpegEncoder) {
- return stream
- ? new SkDocument_PDF(stream, nullptr, dpi, jpegEncoder)
- : nullptr;
-}
-
-SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) {
- SkFILEWStream* stream = new SkFILEWStream(path);
- if (!stream->isValid()) {
- delete stream;
- return nullptr;
- }
- auto delete_wstream = [](SkWStream* stream, bool) { delete stream; };
- return new SkDocument_PDF(stream, delete_wstream, dpi, nullptr);
-}
« no previous file with comments | « src/doc/SkDocument.cpp ('k') | src/doc/SkDocument_PDF_None.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698