SkPDFDocument.cpp revision cc77c12293d1685f5e83d768b30ca9157af1576d
199ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com/*
2a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary * Copyright 2011 Google Inc.
399ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com *
499ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com * Use of this source code is governed by a BSD-style license that can be
599ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com * found in the LICENSE file.
699ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com */
799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
8a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary#include "SkPDFCanon.h"
966be626f7f3ddda243e51aa8f36398b26769a9b4halcanary#include "SkPDFCanvas.h"
105867736b08d3689356b49f505bcf748c2194a0bcreed#include "SkPDFDevice.h"
1123f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary#include "SkPDFDocument.h"
12a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#include "SkPDFFont.h"
132f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary#include "SkPDFStream.h"
14f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanary#include "SkPDFUtils.h"
15a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#include "SkStream.h"
16f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanary
1750e82e61766d22da5238905916a8abc3e6664060halcanary
1850e82e61766d22da5238905916a8abc3e6664060halcanarySkPDFObjectSerializer::SkPDFObjectSerializer() : fBaseOffset(0), fNextToBeSerialized(0) {}
1950e82e61766d22da5238905916a8abc3e6664060halcanary
2050e82e61766d22da5238905916a8abc3e6664060halcanarytemplate <class T> static void renew(T* t) { t->~T(); new (t) T; }
2150e82e61766d22da5238905916a8abc3e6664060halcanary
2250e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFObjectSerializer::addObjectRecursively(const sk_sp<SkPDFObject>& object) {
2350e82e61766d22da5238905916a8abc3e6664060halcanary    fObjNumMap.addObjectRecursively(object.get(), fSubstituteMap);
24a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
25a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
2650e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFObjectSerializer::serializeHeader(SkWStream* wStream, const SkPDFMetadata& md) {
2750e82e61766d22da5238905916a8abc3e6664060halcanary    fBaseOffset = wStream->bytesWritten();
2850e82e61766d22da5238905916a8abc3e6664060halcanary    static const char kHeader[] = "%PDF-1.4\n%\xE1\xE9\xEB\xD3\n";
2950e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->write(kHeader, strlen(kHeader));
3050e82e61766d22da5238905916a8abc3e6664060halcanary    // The PDF spec recommends including a comment with four
3150e82e61766d22da5238905916a8abc3e6664060halcanary    // bytes, all with their high bits set.  "\xD3\xEB\xE9\xE1" is
3250e82e61766d22da5238905916a8abc3e6664060halcanary    // "Skia" with the high bits set.
3350e82e61766d22da5238905916a8abc3e6664060halcanary    fInfoDict.reset(md.createDocumentInformationDict());
3450e82e61766d22da5238905916a8abc3e6664060halcanary    this->addObjectRecursively(fInfoDict);
3550e82e61766d22da5238905916a8abc3e6664060halcanary    this->serializeObjects(wStream);
3650e82e61766d22da5238905916a8abc3e6664060halcanary}
3750e82e61766d22da5238905916a8abc3e6664060halcanary
3850e82e61766d22da5238905916a8abc3e6664060halcanary// Serialize all objects in the fObjNumMap that have not yet been serialized;
3950e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFObjectSerializer::serializeObjects(SkWStream* wStream) {
4050e82e61766d22da5238905916a8abc3e6664060halcanary    const SkTArray<sk_sp<SkPDFObject>>& objects = fObjNumMap.objects();
4150e82e61766d22da5238905916a8abc3e6664060halcanary    while (fNextToBeSerialized < objects.count()) {
4250e82e61766d22da5238905916a8abc3e6664060halcanary        SkPDFObject* object = objects[fNextToBeSerialized].get();
4350e82e61766d22da5238905916a8abc3e6664060halcanary        int32_t index = fNextToBeSerialized + 1;  // Skip object 0.
4450e82e61766d22da5238905916a8abc3e6664060halcanary        // "The first entry in the [XREF] table (object number 0) is
4550e82e61766d22da5238905916a8abc3e6664060halcanary        // always free and has a generation number of 65,535; it is
4650e82e61766d22da5238905916a8abc3e6664060halcanary        // the head of the linked list of free objects."
4750e82e61766d22da5238905916a8abc3e6664060halcanary        SkASSERT(fOffsets.count() == fNextToBeSerialized);
4850e82e61766d22da5238905916a8abc3e6664060halcanary        fOffsets.push(this->offset(wStream));
4950e82e61766d22da5238905916a8abc3e6664060halcanary        SkASSERT(object == fSubstituteMap.getSubstitute(object));
5050e82e61766d22da5238905916a8abc3e6664060halcanary        wStream->writeDecAsText(index);
5150e82e61766d22da5238905916a8abc3e6664060halcanary        wStream->writeText(" 0 obj\n");  // Generation number is always 0.
5250e82e61766d22da5238905916a8abc3e6664060halcanary        object->emitObject(wStream, fObjNumMap, fSubstituteMap);
5350e82e61766d22da5238905916a8abc3e6664060halcanary        wStream->writeText("\nendobj\n");
5450e82e61766d22da5238905916a8abc3e6664060halcanary        object->drop();
5550e82e61766d22da5238905916a8abc3e6664060halcanary        ++fNextToBeSerialized;
5650e82e61766d22da5238905916a8abc3e6664060halcanary    }
5750e82e61766d22da5238905916a8abc3e6664060halcanary}
5850e82e61766d22da5238905916a8abc3e6664060halcanary
5950e82e61766d22da5238905916a8abc3e6664060halcanary// Xref table and footer
6050e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFObjectSerializer::serializeFooter(SkWStream* wStream,
6150e82e61766d22da5238905916a8abc3e6664060halcanary                                            const sk_sp<SkPDFObject> docCatalog,
6250e82e61766d22da5238905916a8abc3e6664060halcanary                                            sk_sp<SkPDFObject> id) {
6350e82e61766d22da5238905916a8abc3e6664060halcanary    this->serializeObjects(wStream);
6450e82e61766d22da5238905916a8abc3e6664060halcanary    int32_t xRefFileOffset = this->offset(wStream);
6550e82e61766d22da5238905916a8abc3e6664060halcanary    // Include the special zeroth object in the count.
6650e82e61766d22da5238905916a8abc3e6664060halcanary    int32_t objCount = SkToS32(fOffsets.count() + 1);
6750e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeText("xref\n0 ");
6850e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeDecAsText(objCount);
6950e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeText("\n0000000000 65535 f \n");
7050e82e61766d22da5238905916a8abc3e6664060halcanary    for (int i = 0; i < fOffsets.count(); i++) {
7150e82e61766d22da5238905916a8abc3e6664060halcanary        wStream->writeBigDecAsText(fOffsets[i], 10);
7250e82e61766d22da5238905916a8abc3e6664060halcanary        wStream->writeText(" 00000 n \n");
7350e82e61766d22da5238905916a8abc3e6664060halcanary    }
74a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkPDFDict trailerDict;
7550e82e61766d22da5238905916a8abc3e6664060halcanary    trailerDict.insertInt("Size", objCount);
7650e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(docCatalog);
7750e82e61766d22da5238905916a8abc3e6664060halcanary    trailerDict.insertObjRef("Root", docCatalog);
7850e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(fInfoDict);
7950e82e61766d22da5238905916a8abc3e6664060halcanary    trailerDict.insertObjRef("Info", std::move(fInfoDict));
8034422610ac22adceeabb66023120f27b96cae953halcanary    if (id) {
818103a34300c5de2e85793a96c4738a33fc6eb46dhalcanary        trailerDict.insertObject("ID", std::move(id));
8234422610ac22adceeabb66023120f27b96cae953halcanary    }
8350e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeText("trailer\n");
8450e82e61766d22da5238905916a8abc3e6664060halcanary    trailerDict.emitObject(wStream, fObjNumMap, fSubstituteMap);
8550e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeText("\nstartxref\n");
8650e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeBigDecAsText(xRefFileOffset);
8750e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeText("\n%%EOF");
8850e82e61766d22da5238905916a8abc3e6664060halcanary}
8950e82e61766d22da5238905916a8abc3e6664060halcanary
9050e82e61766d22da5238905916a8abc3e6664060halcanaryint32_t SkPDFObjectSerializer::offset(SkWStream* wStream) {
9150e82e61766d22da5238905916a8abc3e6664060halcanary    size_t offset = wStream->bytesWritten();
9250e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(offset > fBaseOffset);
9350e82e61766d22da5238905916a8abc3e6664060halcanary    return SkToS32(offset - fBaseOffset);
94a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
95a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
962f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
978103a34300c5de2e85793a96c4738a33fc6eb46dhalcanary// return root node.
98cc77c12293d1685f5e83d768b30ca9157af1576dhalcanarystatic sk_sp<SkPDFDict> generate_page_tree(SkTArray<sk_sp<SkPDFDict>>* pages) {
992f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // PDF wants a tree describing all the pages in the document.  We arbitrary
1002f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // choose 8 (kNodeSize) as the number of allowed children.  The internal
1012f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // nodes have type "Pages" with an array of children, a parent pointer, and
1022f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // the number of leaves below the node as "Count."  The leaves are passed
1032f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // into the method, have type "Page" and need a parent pointer. This method
1042f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // builds the tree bottom up, skipping internal nodes that would have only
1052f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // one child.
1062f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    static const int kNodeSize = 8;
1072f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
1082f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // curNodes takes a reference to its items, which it passes to pageTree.
109cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    int totalPageCount = pages->count();
110cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    SkTArray<sk_sp<SkPDFDict>> curNodes;
111cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    curNodes.swap(pages);
1122f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
1132f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // nextRoundNodes passes its references to nodes on to curNodes.
1142f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    int treeCapacity = kNodeSize;
1152f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    do {
116cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        SkTArray<sk_sp<SkPDFDict>> nextRoundNodes;
1172f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary        for (int i = 0; i < curNodes.count(); ) {
1182f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            if (i > 0 && i + 1 == curNodes.count()) {
119cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                SkASSERT(curNodes[i]);
120cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                nextRoundNodes.emplace_back(std::move(curNodes[i]));
1212f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary                break;
1222f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            }
1232f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
124ece83924384b2e9e8cd422324c44797deb99ec90halcanary            auto newNode = sk_make_sp<SkPDFDict>("Pages");
125ece83924384b2e9e8cd422324c44797deb99ec90halcanary            auto kids = sk_make_sp<SkPDFArray>();
1262f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            kids->reserve(kNodeSize);
1272f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
1282f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            int count = 0;
1292f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            for (; i < curNodes.count() && count < kNodeSize; i++, count++) {
130cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                SkASSERT(curNodes[i]);
1318103a34300c5de2e85793a96c4738a33fc6eb46dhalcanary                curNodes[i]->insertObjRef("Parent", newNode);
132cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                kids->appendObjRef(std::move(curNodes[i]));
1332f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            }
1342f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
1352f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // treeCapacity is the number of leaf nodes possible for the
1362f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // current set of subtrees being generated. (i.e. 8, 64, 512, ...).
1372f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // It is hard to count the number of leaf nodes in the current
1382f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // subtree. However, by construction, we know that unless it's the
1392f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // last subtree for the current depth, the leaf count will be
1402f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // treeCapacity, otherwise it's what ever is left over after
1412f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // consuming treeCapacity chunks.
1422f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            int pageCount = treeCapacity;
1432f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            if (i == curNodes.count()) {
144cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                pageCount = ((totalPageCount - 1) % treeCapacity) + 1;
1452f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            }
14672266fd1fe9bfe078239a9d9e85f479faee30281halcanary            newNode->insertInt("Count", pageCount);
1478103a34300c5de2e85793a96c4738a33fc6eb46dhalcanary            newNode->insertObject("Kids", std::move(kids));
148cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary            nextRoundNodes.emplace_back(std::move(newNode));
1492f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary        }
150cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        SkDEBUGCODE( for (const auto& n : curNodes) { SkASSERT(!n); } );
1512f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
152cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        curNodes.swap(&nextRoundNodes);
153cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        nextRoundNodes.reset();
1542f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary        treeCapacity *= kNodeSize;
1552f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    } while (curNodes.count() > 1);
156cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    return std::move(curNodes[0]);
1572f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary}
1582f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
159a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#if 0
160a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary// TODO(halcanary): expose notEmbeddableCount in SkDocument
161a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanaryvoid GetCountOfFontTypes(
162a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        const SkTDArray<SkPDFDevice*>& pageDevices,
163a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1],
164a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        int* notSubsettableCount,
165a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        int* notEmbeddableCount) {
166a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    sk_bzero(counts, sizeof(int) *
167a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                     (SkAdvancedTypefaceMetrics::kOther_Font + 1));
168a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkTDArray<SkFontID> seenFonts;
169a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    int notSubsettable = 0;
170a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    int notEmbeddable = 0;
171a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
172a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    for (int pageNumber = 0; pageNumber < pageDevices.count(); pageNumber++) {
173a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        const SkTDArray<SkPDFFont*>& fontResources =
174a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                pageDevices[pageNumber]->getFontResources();
175a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        for (int font = 0; font < fontResources.count(); font++) {
176a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary            SkFontID fontID = fontResources[font]->typeface()->uniqueID();
177a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary            if (seenFonts.find(fontID) == -1) {
178a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                counts[fontResources[font]->getType()]++;
179a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                seenFonts.push(fontID);
180a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                if (!fontResources[font]->canSubset()) {
181a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                    notSubsettable++;
182a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                }
183a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                if (!fontResources[font]->canEmbed()) {
184a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                    notEmbeddable++;
185a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                }
186a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary            }
187a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        }
188a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
189a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    if (notSubsettableCount) {
190a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        *notSubsettableCount = notSubsettable;
191a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
192a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
193a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    if (notEmbeddableCount) {
194a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        *notEmbeddableCount = notEmbeddable;
195a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
196a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
197a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#endif
198f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanary
199f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanarytemplate <typename T> static T* clone(const T* o) { return o ? new T(*o) : nullptr; }
200a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary////////////////////////////////////////////////////////////////////////////////
20199ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
20250e82e61766d22da5238905916a8abc3e6664060halcanarySkPDFDocument::SkPDFDocument(SkWStream* stream,
20350e82e61766d22da5238905916a8abc3e6664060halcanary                             void (*doneProc)(SkWStream*, bool),
20450e82e61766d22da5238905916a8abc3e6664060halcanary                             SkScalar rasterDpi,
20550e82e61766d22da5238905916a8abc3e6664060halcanary                             SkPixelSerializer* jpegEncoder)
20650e82e61766d22da5238905916a8abc3e6664060halcanary    : SkDocument(stream, doneProc)
20750e82e61766d22da5238905916a8abc3e6664060halcanary    , fRasterDpi(rasterDpi) {
20850e82e61766d22da5238905916a8abc3e6664060halcanary    fCanon.setPixelSerializer(SkSafeRef(jpegEncoder));
20950e82e61766d22da5238905916a8abc3e6664060halcanary}
2106319367bdcbf5e5050632ab97973f5035d0dd8faskia.committer@gmail.com
21150e82e61766d22da5238905916a8abc3e6664060halcanarySkPDFDocument::~SkPDFDocument() {
21250e82e61766d22da5238905916a8abc3e6664060halcanary    // subclasses of SkDocument must call close() in their destructors.
21350e82e61766d22da5238905916a8abc3e6664060halcanary    this->close();
21450e82e61766d22da5238905916a8abc3e6664060halcanary}
21599ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
21650e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFDocument::serialize(const sk_sp<SkPDFObject>& object) {
21750e82e61766d22da5238905916a8abc3e6664060halcanary    fObjectSerializer.addObjectRecursively(object);
21850e82e61766d22da5238905916a8abc3e6664060halcanary    fObjectSerializer.serializeObjects(this->getStream());
21950e82e61766d22da5238905916a8abc3e6664060halcanary}
22099ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
22150e82e61766d22da5238905916a8abc3e6664060halcanarySkCanvas* SkPDFDocument::onBeginPage(SkScalar width, SkScalar height,
22250e82e61766d22da5238905916a8abc3e6664060halcanary                                     const SkRect& trimBox) {
22350e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(!fCanvas.get());  // endPage() was called before this.
224cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    if (fPages.empty()) {
22550e82e61766d22da5238905916a8abc3e6664060halcanary        // if this is the first page if the document.
22650e82e61766d22da5238905916a8abc3e6664060halcanary        fObjectSerializer.serializeHeader(this->getStream(), fMetadata);
227cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        fDests = sk_make_sp<SkPDFDict>();
22899ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    }
22950e82e61766d22da5238905916a8abc3e6664060halcanary    SkISize pageSize = SkISize::Make(
23050e82e61766d22da5238905916a8abc3e6664060halcanary            SkScalarRoundToInt(width), SkScalarRoundToInt(height));
231cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPageDevice.reset(
232989da4a32cd6823359f31c971c3b3f31425e905ehalcanary            SkPDFDevice::Create(pageSize, fRasterDpi, this));
233cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fCanvas = sk_make_sp<SkPDFCanvas>(fPageDevice);
23450e82e61766d22da5238905916a8abc3e6664060halcanary    fCanvas->clipRect(trimBox);
23550e82e61766d22da5238905916a8abc3e6664060halcanary    fCanvas->translate(trimBox.x(), trimBox.y());
23650e82e61766d22da5238905916a8abc3e6664060halcanary    return fCanvas.get();
23750e82e61766d22da5238905916a8abc3e6664060halcanary}
23850e82e61766d22da5238905916a8abc3e6664060halcanary
23950e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFDocument::onEndPage() {
24050e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(fCanvas.get());
24150e82e61766d22da5238905916a8abc3e6664060halcanary    fCanvas->flush();
24250e82e61766d22da5238905916a8abc3e6664060halcanary    fCanvas.reset(nullptr);
243cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    SkASSERT(fPageDevice);
244cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fGlyphUsage.merge(fPageDevice->getFontGlyphUsage());
245cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    auto page = sk_make_sp<SkPDFDict>("Page");
246cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    page->insertObject("Resources", fPageDevice->makeResourceDict());
247cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    page->insertObject("MediaBox", fPageDevice->copyMediaBox());
248cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    auto annotations = sk_make_sp<SkPDFArray>();
249cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPageDevice->appendAnnotations(annotations.get());
250cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    if (annotations->size() > 0) {
251cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        page->insertObject("Annots", std::move(annotations));
252cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    }
253cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    auto contentData = fPageDevice->content();
254cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    auto contentObject = sk_make_sp<SkPDFStream>(contentData.get());
255cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    this->serialize(contentObject);
256cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    page->insertObjRef("Contents", std::move(contentObject));
257cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPageDevice->appendDestinations(fDests.get(), page.get());
258cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPages.emplace_back(std::move(page));
259cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPageDevice.reset(nullptr);
26050e82e61766d22da5238905916a8abc3e6664060halcanary}
26150e82e61766d22da5238905916a8abc3e6664060halcanary
26250e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFDocument::onAbort() {
26350e82e61766d22da5238905916a8abc3e6664060halcanary    fCanvas.reset(nullptr);
264cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPages.reset();
26550e82e61766d22da5238905916a8abc3e6664060halcanary    fCanon.reset();
26650e82e61766d22da5238905916a8abc3e6664060halcanary    renew(&fObjectSerializer);
26750e82e61766d22da5238905916a8abc3e6664060halcanary}
26899ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
26950e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFDocument::setMetadata(const SkDocument::Attribute info[],
27050e82e61766d22da5238905916a8abc3e6664060halcanary                                int infoCount,
27150e82e61766d22da5238905916a8abc3e6664060halcanary                                const SkTime::DateTime* creationDate,
27250e82e61766d22da5238905916a8abc3e6664060halcanary                                const SkTime::DateTime* modifiedDate) {
27350e82e61766d22da5238905916a8abc3e6664060halcanary    fMetadata.fInfo.reset(info, infoCount);
27450e82e61766d22da5238905916a8abc3e6664060halcanary    fMetadata.fCreation.reset(clone(creationDate));
27550e82e61766d22da5238905916a8abc3e6664060halcanary    fMetadata.fModified.reset(clone(modifiedDate));
27650e82e61766d22da5238905916a8abc3e6664060halcanary}
27799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
27850e82e61766d22da5238905916a8abc3e6664060halcanarybool SkPDFDocument::onClose(SkWStream* stream) {
27950e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(!fCanvas.get());
280cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    if (fPages.empty()) {
281cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        fPages.reset();
2822e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanary        fCanon.reset();
28350e82e61766d22da5238905916a8abc3e6664060halcanary        renew(&fObjectSerializer);
28450e82e61766d22da5238905916a8abc3e6664060halcanary        return false;
285b5a6651f9f69570d964382134d64360915db9a29commit-bot@chromium.org    }
28650e82e61766d22da5238905916a8abc3e6664060halcanary    auto docCatalog = sk_make_sp<SkPDFDict>("Catalog");
28750e82e61766d22da5238905916a8abc3e6664060halcanary    sk_sp<SkPDFObject> id, xmp;
28850e82e61766d22da5238905916a8abc3e6664060halcanary    #ifdef SK_PDF_GENERATE_PDFA
28950e82e61766d22da5238905916a8abc3e6664060halcanary        SkPDFMetadata::UUID uuid = metadata.uuid();
29050e82e61766d22da5238905916a8abc3e6664060halcanary        // We use the same UUID for Document ID and Instance ID since this
29150e82e61766d22da5238905916a8abc3e6664060halcanary        // is the first revision of this document (and Skia does not
29250e82e61766d22da5238905916a8abc3e6664060halcanary        // support revising existing PDF documents).
29350e82e61766d22da5238905916a8abc3e6664060halcanary        // If we are not in PDF/A mode, don't use a UUID since testing
29450e82e61766d22da5238905916a8abc3e6664060halcanary        // works best with reproducible outputs.
29550e82e61766d22da5238905916a8abc3e6664060halcanary        id.reset(SkPDFMetadata::CreatePdfId(uuid, uuid));
29650e82e61766d22da5238905916a8abc3e6664060halcanary        xmp.reset(metadata.createXMPObject(uuid, uuid));
29750e82e61766d22da5238905916a8abc3e6664060halcanary        docCatalog->insertObjRef("Metadata", std::move(xmp));
29850e82e61766d22da5238905916a8abc3e6664060halcanary
29950e82e61766d22da5238905916a8abc3e6664060halcanary        // sRGB is specified by HTML, CSS, and SVG.
30050e82e61766d22da5238905916a8abc3e6664060halcanary        auto outputIntent = sk_make_sp<SkPDFDict>("OutputIntent");
30150e82e61766d22da5238905916a8abc3e6664060halcanary        outputIntent->insertName("S", "GTS_PDFA1");
30250e82e61766d22da5238905916a8abc3e6664060halcanary        outputIntent->insertString("RegistryName", "http://www.color.org");
30350e82e61766d22da5238905916a8abc3e6664060halcanary        outputIntent->insertString("OutputConditionIdentifier",
30450e82e61766d22da5238905916a8abc3e6664060halcanary                                   "sRGB IEC61966-2.1");
30550e82e61766d22da5238905916a8abc3e6664060halcanary        auto intentArray = sk_make_sp<SkPDFArray>();
30650e82e61766d22da5238905916a8abc3e6664060halcanary        intentArray->appendObject(std::move(outputIntent));
30750e82e61766d22da5238905916a8abc3e6664060halcanary        // Don't specify OutputIntents if we are not in PDF/A mode since
30850e82e61766d22da5238905916a8abc3e6664060halcanary        // no one has ever asked for this feature.
30950e82e61766d22da5238905916a8abc3e6664060halcanary        docCatalog->insertObject("OutputIntents", std::move(intentArray));
31050e82e61766d22da5238905916a8abc3e6664060halcanary    #endif
31150e82e61766d22da5238905916a8abc3e6664060halcanary
312cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    docCatalog->insertObjRef("Pages", generate_page_tree(&fPages));
31350e82e61766d22da5238905916a8abc3e6664060halcanary
314cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    if (fDests->size() > 0) {
315cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        docCatalog->insertObjRef("Dests", std::move(fDests));
316f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanary    }
317f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanary
31850e82e61766d22da5238905916a8abc3e6664060halcanary    // Build font subsetting info before calling addObjectRecursively().
319cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    for (const auto& entry : fGlyphUsage) {
320cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        sk_sp<SkPDFFont> subsetFont(
321cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                entry.fFont->getFontSubset(entry.fGlyphSet));
322cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        if (subsetFont) {
323cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary            fObjectSerializer.fSubstituteMap.setSubstitute(
324cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                    entry.fFont, subsetFont.get());
325cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        }
326cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    }
32750e82e61766d22da5238905916a8abc3e6664060halcanary
32850e82e61766d22da5238905916a8abc3e6664060halcanary    fObjectSerializer.addObjectRecursively(docCatalog);
32950e82e61766d22da5238905916a8abc3e6664060halcanary    fObjectSerializer.serializeObjects(this->getStream());
33050e82e61766d22da5238905916a8abc3e6664060halcanary    fObjectSerializer.serializeFooter(
33150e82e61766d22da5238905916a8abc3e6664060halcanary            this->getStream(), docCatalog, std::move(id));
332cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary
333cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    SkASSERT(fPages.count() == 0);
33450e82e61766d22da5238905916a8abc3e6664060halcanary    fCanon.reset();
33550e82e61766d22da5238905916a8abc3e6664060halcanary    renew(&fObjectSerializer);
33650e82e61766d22da5238905916a8abc3e6664060halcanary    return true;
33750e82e61766d22da5238905916a8abc3e6664060halcanary}
33850e82e61766d22da5238905916a8abc3e6664060halcanary
33999ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com///////////////////////////////////////////////////////////////////////////////
34099ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
34123f4d4d1b9151bb89cdced9986be7ec9b006d458halcanarysk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream,
34223f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary                                    void (*proc)(SkWStream*, bool),
34323f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary                                    SkScalar dpi,
34423f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary                                    SkPixelSerializer* jpeg) {
34523f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary    return stream ? sk_make_sp<SkPDFDocument>(stream, proc, dpi, jpeg) : nullptr;
34623f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary}
34723f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary
3488c92dc1dc281649f9e6b0ff534c25bc89dded3eahalcanarySkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) {
34923f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary    return SkPDFMakeDocument(stream, nullptr, dpi, nullptr).release();
350712fdf7603c62820b21174da9b0a2071c174936bhalcanary}
351712fdf7603c62820b21174da9b0a2071c174936bhalcanary
352712fdf7603c62820b21174da9b0a2071c174936bhalcanarySkDocument* SkDocument::CreatePDF(SkWStream* stream,
353712fdf7603c62820b21174da9b0a2071c174936bhalcanary                                  SkScalar dpi,
354712fdf7603c62820b21174da9b0a2071c174936bhalcanary                                  SkPixelSerializer* jpegEncoder) {
35523f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary    return SkPDFMakeDocument(stream, nullptr, dpi, jpegEncoder).release();
35699ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com}
35799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
3588c92dc1dc281649f9e6b0ff534c25bc89dded3eahalcanarySkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) {
359385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    auto delete_wstream = [](SkWStream* stream, bool) { delete stream; };
36023f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary    SkAutoTDelete<SkFILEWStream> stream(new SkFILEWStream(path));
36123f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary    return stream->isValid()
36218300a3aa7cb6eb55d21bb0450dffa58b6fc062cmtklein        ? SkPDFMakeDocument(stream.release(), delete_wstream, dpi, nullptr).release()
36323f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary        : nullptr;
36499ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com}
365