SkPDF: move all pdf sources into src/pdf

also, consolidate XPS backend into src/xps

remove from include/ almost always a good thing.
TBR=reed@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1781773002
CQ_EXTRA_TRYBOTS=client.skia.compile:Build-Ubuntu-GCC-x86_64-Release-CMake-Trybot,Build-Mac-Clang-x86_64-Release-CMake-Trybot

Review URL: https://codereview.chromium.org/1781773002
diff --git a/src/pdf/SkDocument_PDF_None.cpp b/src/pdf/SkDocument_PDF_None.cpp
new file mode 100644
index 0000000..f146cba
--- /dev/null
+++ b/src/pdf/SkDocument_PDF_None.cpp
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2015 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"
+SkDocument* SkDocument::CreatePDF(SkWStream*, SkScalar) { return  nullptr; }
+SkDocument* SkDocument::CreatePDF(const char path[], SkScalar) { return nullptr; }
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
new file mode 100644
index 0000000..bacd9ec
--- /dev/null
+++ b/src/pdf/SkPDFDocument.cpp
@@ -0,0 +1,404 @@
+/*
+ * 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 "SkPDFCanon.h"
+#include "SkPDFDevice.h"
+#include "SkPDFDocument.h"
+#include "SkPDFFont.h"
+#include "SkPDFMetadata.h"
+#include "SkPDFStream.h"
+#include "SkPDFTypes.h"
+#include "SkPDFUtils.h"
+#include "SkStream.h"
+
+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 SkPDFDocument : public SkDocument {
+public:
+    SkPDFDocument(SkWStream* stream,
+                   void (*doneProc)(SkWStream*, bool),
+                   SkScalar rasterDpi,
+                   SkPixelSerializer* jpegEncoder)
+        : SkDocument(stream, doneProc)
+        , fRasterDpi(rasterDpi) {
+        fCanon.setPixelSerializer(SkSafeRef(jpegEncoder));
+    }
+
+    virtual ~SkPDFDocument() {
+        // 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
+///////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream,
+                                    void (*proc)(SkWStream*, bool),
+                                    SkScalar dpi,
+                                    SkPixelSerializer* jpeg) {
+    return stream ? sk_make_sp<SkPDFDocument>(stream, proc, dpi, jpeg) : nullptr;
+}
+
+SkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) {
+    return SkPDFMakeDocument(stream, nullptr, dpi, nullptr).release();
+}
+
+SkDocument* SkDocument::CreatePDF(SkWStream* stream,
+                                  SkScalar dpi,
+                                  SkPixelSerializer* jpegEncoder) {
+    return SkPDFMakeDocument(stream, nullptr, dpi, jpegEncoder).release();
+}
+
+SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) {
+    auto delete_wstream = [](SkWStream* stream, bool) { delete stream; };
+    SkAutoTDelete<SkFILEWStream> stream(new SkFILEWStream(path));
+    return stream->isValid()
+        ? SkPDFMakeDocument(stream.detach(), delete_wstream, dpi, nullptr).release()
+        : nullptr;
+}
diff --git a/src/pdf/SkPDFDocument.h b/src/pdf/SkPDFDocument.h
new file mode 100644
index 0000000..8ed7677
--- /dev/null
+++ b/src/pdf/SkPDFDocument.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SkPDFDocument_DEFINED
+#define SkPDFDocument_DEFINED
+
+#include "SkDocument.h"
+
+sk_sp<SkDocument> SkPDFMakeDocument(
+        SkWStream* stream,
+        void (*doneProc)(SkWStream*, bool),
+        SkScalar rasterDpi,
+        SkPixelSerializer* jpegEncoder);
+
+#endif  // SkPDFDocument_DEFINED