SkPDFDocument.cpp revision 3c35fb3310c22eb0141c8f39c5423f7bcd42adff
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
899e22fbe569ef3525d4de07eceaca2200a3d6e50halcanary#include "SkColorSpace_Base.h"
966be626f7f3ddda243e51aa8f36398b26769a9b4halcanary#include "SkPDFCanvas.h"
105867736b08d3689356b49f505bcf748c2194a0bcreed#include "SkPDFDevice.h"
1123f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary#include "SkPDFDocument.h"
122f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary#include "SkPDFStream.h"
13f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanary#include "SkPDFUtils.h"
14a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#include "SkStream.h"
15f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanary
1650e82e61766d22da5238905916a8abc3e6664060halcanarySkPDFObjectSerializer::SkPDFObjectSerializer() : fBaseOffset(0), fNextToBeSerialized(0) {}
1750e82e61766d22da5238905916a8abc3e6664060halcanary
1850e82e61766d22da5238905916a8abc3e6664060halcanarytemplate <class T> static void renew(T* t) { t->~T(); new (t) T; }
1950e82e61766d22da5238905916a8abc3e6664060halcanary
20a50151dcb5a0b8bfdef383e363e519c91d2d2c7ahalcanarySkPDFObjectSerializer::~SkPDFObjectSerializer() {
21a50151dcb5a0b8bfdef383e363e519c91d2d2c7ahalcanary    for (int i = 0; i < fObjNumMap.objects().count(); ++i) {
22a50151dcb5a0b8bfdef383e363e519c91d2d2c7ahalcanary        fObjNumMap.objects()[i]->drop();
23a50151dcb5a0b8bfdef383e363e519c91d2d2c7ahalcanary    }
24a50151dcb5a0b8bfdef383e363e519c91d2d2c7ahalcanary}
25a50151dcb5a0b8bfdef383e363e519c91d2d2c7ahalcanary
2650e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFObjectSerializer::addObjectRecursively(const sk_sp<SkPDFObject>& object) {
2750e82e61766d22da5238905916a8abc3e6664060halcanary    fObjNumMap.addObjectRecursively(object.get(), fSubstituteMap);
28a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
29a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
30ad5dcd17cd9996a99068601d11df1c27b3652b9ahalcanary#define SKPDF_MAGIC "\xD3\xEB\xE9\xE1"
31ad5dcd17cd9996a99068601d11df1c27b3652b9ahalcanary#ifndef SK_BUILD_FOR_WIN32
32ad5dcd17cd9996a99068601d11df1c27b3652b9ahalcanarystatic_assert((SKPDF_MAGIC[0] & 0x7F) == "Skia"[0], "");
33ad5dcd17cd9996a99068601d11df1c27b3652b9ahalcanarystatic_assert((SKPDF_MAGIC[1] & 0x7F) == "Skia"[1], "");
34ad5dcd17cd9996a99068601d11df1c27b3652b9ahalcanarystatic_assert((SKPDF_MAGIC[2] & 0x7F) == "Skia"[2], "");
35ad5dcd17cd9996a99068601d11df1c27b3652b9ahalcanarystatic_assert((SKPDF_MAGIC[3] & 0x7F) == "Skia"[3], "");
36ad5dcd17cd9996a99068601d11df1c27b3652b9ahalcanary#endif
374b6566644f704cf9e30c71fa547c9b5915752792halcanaryvoid SkPDFObjectSerializer::serializeHeader(SkWStream* wStream,
384b6566644f704cf9e30c71fa547c9b5915752792halcanary                                            const SkDocument::PDFMetadata& md) {
3950e82e61766d22da5238905916a8abc3e6664060halcanary    fBaseOffset = wStream->bytesWritten();
40ad5dcd17cd9996a99068601d11df1c27b3652b9ahalcanary    static const char kHeader[] = "%PDF-1.4\n%" SKPDF_MAGIC "\n";
4150e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->write(kHeader, strlen(kHeader));
4250e82e61766d22da5238905916a8abc3e6664060halcanary    // The PDF spec recommends including a comment with four
4350e82e61766d22da5238905916a8abc3e6664060halcanary    // bytes, all with their high bits set.  "\xD3\xEB\xE9\xE1" is
4450e82e61766d22da5238905916a8abc3e6664060halcanary    // "Skia" with the high bits set.
454b6566644f704cf9e30c71fa547c9b5915752792halcanary    fInfoDict = SkPDFMetadata::MakeDocumentInformationDict(md);
4650e82e61766d22da5238905916a8abc3e6664060halcanary    this->addObjectRecursively(fInfoDict);
4750e82e61766d22da5238905916a8abc3e6664060halcanary    this->serializeObjects(wStream);
4850e82e61766d22da5238905916a8abc3e6664060halcanary}
49ad5dcd17cd9996a99068601d11df1c27b3652b9ahalcanary#undef SKPDF_MAGIC
5050e82e61766d22da5238905916a8abc3e6664060halcanary
5150e82e61766d22da5238905916a8abc3e6664060halcanary// Serialize all objects in the fObjNumMap that have not yet been serialized;
5250e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFObjectSerializer::serializeObjects(SkWStream* wStream) {
5350e82e61766d22da5238905916a8abc3e6664060halcanary    const SkTArray<sk_sp<SkPDFObject>>& objects = fObjNumMap.objects();
5450e82e61766d22da5238905916a8abc3e6664060halcanary    while (fNextToBeSerialized < objects.count()) {
5550e82e61766d22da5238905916a8abc3e6664060halcanary        SkPDFObject* object = objects[fNextToBeSerialized].get();
5650e82e61766d22da5238905916a8abc3e6664060halcanary        int32_t index = fNextToBeSerialized + 1;  // Skip object 0.
5750e82e61766d22da5238905916a8abc3e6664060halcanary        // "The first entry in the [XREF] table (object number 0) is
5850e82e61766d22da5238905916a8abc3e6664060halcanary        // always free and has a generation number of 65,535; it is
5950e82e61766d22da5238905916a8abc3e6664060halcanary        // the head of the linked list of free objects."
6050e82e61766d22da5238905916a8abc3e6664060halcanary        SkASSERT(fOffsets.count() == fNextToBeSerialized);
6150e82e61766d22da5238905916a8abc3e6664060halcanary        fOffsets.push(this->offset(wStream));
6250e82e61766d22da5238905916a8abc3e6664060halcanary        SkASSERT(object == fSubstituteMap.getSubstitute(object));
6350e82e61766d22da5238905916a8abc3e6664060halcanary        wStream->writeDecAsText(index);
6450e82e61766d22da5238905916a8abc3e6664060halcanary        wStream->writeText(" 0 obj\n");  // Generation number is always 0.
6550e82e61766d22da5238905916a8abc3e6664060halcanary        object->emitObject(wStream, fObjNumMap, fSubstituteMap);
6650e82e61766d22da5238905916a8abc3e6664060halcanary        wStream->writeText("\nendobj\n");
6750e82e61766d22da5238905916a8abc3e6664060halcanary        object->drop();
6850e82e61766d22da5238905916a8abc3e6664060halcanary        ++fNextToBeSerialized;
6950e82e61766d22da5238905916a8abc3e6664060halcanary    }
7050e82e61766d22da5238905916a8abc3e6664060halcanary}
7150e82e61766d22da5238905916a8abc3e6664060halcanary
7250e82e61766d22da5238905916a8abc3e6664060halcanary// Xref table and footer
7350e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFObjectSerializer::serializeFooter(SkWStream* wStream,
7450e82e61766d22da5238905916a8abc3e6664060halcanary                                            const sk_sp<SkPDFObject> docCatalog,
7550e82e61766d22da5238905916a8abc3e6664060halcanary                                            sk_sp<SkPDFObject> id) {
7650e82e61766d22da5238905916a8abc3e6664060halcanary    this->serializeObjects(wStream);
7750e82e61766d22da5238905916a8abc3e6664060halcanary    int32_t xRefFileOffset = this->offset(wStream);
7850e82e61766d22da5238905916a8abc3e6664060halcanary    // Include the special zeroth object in the count.
7950e82e61766d22da5238905916a8abc3e6664060halcanary    int32_t objCount = SkToS32(fOffsets.count() + 1);
8050e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeText("xref\n0 ");
8150e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeDecAsText(objCount);
8250e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeText("\n0000000000 65535 f \n");
8350e82e61766d22da5238905916a8abc3e6664060halcanary    for (int i = 0; i < fOffsets.count(); i++) {
8450e82e61766d22da5238905916a8abc3e6664060halcanary        wStream->writeBigDecAsText(fOffsets[i], 10);
8550e82e61766d22da5238905916a8abc3e6664060halcanary        wStream->writeText(" 00000 n \n");
8650e82e61766d22da5238905916a8abc3e6664060halcanary    }
87a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkPDFDict trailerDict;
8850e82e61766d22da5238905916a8abc3e6664060halcanary    trailerDict.insertInt("Size", objCount);
8950e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(docCatalog);
9050e82e61766d22da5238905916a8abc3e6664060halcanary    trailerDict.insertObjRef("Root", docCatalog);
9150e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(fInfoDict);
9250e82e61766d22da5238905916a8abc3e6664060halcanary    trailerDict.insertObjRef("Info", std::move(fInfoDict));
9334422610ac22adceeabb66023120f27b96cae953halcanary    if (id) {
948103a34300c5de2e85793a96c4738a33fc6eb46dhalcanary        trailerDict.insertObject("ID", std::move(id));
9534422610ac22adceeabb66023120f27b96cae953halcanary    }
9650e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeText("trailer\n");
9750e82e61766d22da5238905916a8abc3e6664060halcanary    trailerDict.emitObject(wStream, fObjNumMap, fSubstituteMap);
9850e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeText("\nstartxref\n");
9950e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeBigDecAsText(xRefFileOffset);
10050e82e61766d22da5238905916a8abc3e6664060halcanary    wStream->writeText("\n%%EOF");
10150e82e61766d22da5238905916a8abc3e6664060halcanary}
10250e82e61766d22da5238905916a8abc3e6664060halcanary
10350e82e61766d22da5238905916a8abc3e6664060halcanaryint32_t SkPDFObjectSerializer::offset(SkWStream* wStream) {
10450e82e61766d22da5238905916a8abc3e6664060halcanary    size_t offset = wStream->bytesWritten();
10550e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(offset > fBaseOffset);
10650e82e61766d22da5238905916a8abc3e6664060halcanary    return SkToS32(offset - fBaseOffset);
107a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
108a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
1092f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
1108103a34300c5de2e85793a96c4738a33fc6eb46dhalcanary// return root node.
111cc77c12293d1685f5e83d768b30ca9157af1576dhalcanarystatic sk_sp<SkPDFDict> generate_page_tree(SkTArray<sk_sp<SkPDFDict>>* pages) {
1122f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // PDF wants a tree describing all the pages in the document.  We arbitrary
1132f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // choose 8 (kNodeSize) as the number of allowed children.  The internal
1142f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // nodes have type "Pages" with an array of children, a parent pointer, and
1152f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // the number of leaves below the node as "Count."  The leaves are passed
1162f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // into the method, have type "Page" and need a parent pointer. This method
1172f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // builds the tree bottom up, skipping internal nodes that would have only
1182f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // one child.
1192f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    static const int kNodeSize = 8;
1202f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
1212f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // curNodes takes a reference to its items, which it passes to pageTree.
122cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    int totalPageCount = pages->count();
123cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    SkTArray<sk_sp<SkPDFDict>> curNodes;
124cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    curNodes.swap(pages);
1252f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
1262f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    // nextRoundNodes passes its references to nodes on to curNodes.
1272f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    int treeCapacity = kNodeSize;
1282f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    do {
129cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        SkTArray<sk_sp<SkPDFDict>> nextRoundNodes;
1302f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary        for (int i = 0; i < curNodes.count(); ) {
1312f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            if (i > 0 && i + 1 == curNodes.count()) {
132cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                SkASSERT(curNodes[i]);
133cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                nextRoundNodes.emplace_back(std::move(curNodes[i]));
1342f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary                break;
1352f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            }
1362f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
137ece83924384b2e9e8cd422324c44797deb99ec90halcanary            auto newNode = sk_make_sp<SkPDFDict>("Pages");
138ece83924384b2e9e8cd422324c44797deb99ec90halcanary            auto kids = sk_make_sp<SkPDFArray>();
1392f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            kids->reserve(kNodeSize);
1402f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
1412f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            int count = 0;
1422f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            for (; i < curNodes.count() && count < kNodeSize; i++, count++) {
143cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                SkASSERT(curNodes[i]);
1448103a34300c5de2e85793a96c4738a33fc6eb46dhalcanary                curNodes[i]->insertObjRef("Parent", newNode);
145cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                kids->appendObjRef(std::move(curNodes[i]));
1462f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            }
1472f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
1482f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // treeCapacity is the number of leaf nodes possible for the
1492f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // current set of subtrees being generated. (i.e. 8, 64, 512, ...).
1502f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // It is hard to count the number of leaf nodes in the current
1512f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // subtree. However, by construction, we know that unless it's the
1522f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // last subtree for the current depth, the leaf count will be
1532f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // treeCapacity, otherwise it's what ever is left over after
1542f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            // consuming treeCapacity chunks.
1552f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            int pageCount = treeCapacity;
1562f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            if (i == curNodes.count()) {
157cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                pageCount = ((totalPageCount - 1) % treeCapacity) + 1;
1582f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary            }
15972266fd1fe9bfe078239a9d9e85f479faee30281halcanary            newNode->insertInt("Count", pageCount);
1608103a34300c5de2e85793a96c4738a33fc6eb46dhalcanary            newNode->insertObject("Kids", std::move(kids));
161cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary            nextRoundNodes.emplace_back(std::move(newNode));
1622f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary        }
163cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        SkDEBUGCODE( for (const auto& n : curNodes) { SkASSERT(!n); } );
1642f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
165cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        curNodes.swap(&nextRoundNodes);
166cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        nextRoundNodes.reset();
1672f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary        treeCapacity *= kNodeSize;
1682f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary    } while (curNodes.count() > 1);
169cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    return std::move(curNodes[0]);
1702f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary}
1712f7ebcb424cd1d1acf07478157f86b0a3eafd712halcanary
172a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#if 0
173a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary// TODO(halcanary): expose notEmbeddableCount in SkDocument
174a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanaryvoid GetCountOfFontTypes(
175a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        const SkTDArray<SkPDFDevice*>& pageDevices,
176a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1],
177a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        int* notSubsettableCount,
178a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        int* notEmbeddableCount) {
179a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    sk_bzero(counts, sizeof(int) *
180a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                     (SkAdvancedTypefaceMetrics::kOther_Font + 1));
181a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkTDArray<SkFontID> seenFonts;
182a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    int notSubsettable = 0;
183a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    int notEmbeddable = 0;
184a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
185a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    for (int pageNumber = 0; pageNumber < pageDevices.count(); pageNumber++) {
186a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        const SkTDArray<SkPDFFont*>& fontResources =
187a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                pageDevices[pageNumber]->getFontResources();
188a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        for (int font = 0; font < fontResources.count(); font++) {
189a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary            SkFontID fontID = fontResources[font]->typeface()->uniqueID();
190a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary            if (seenFonts.find(fontID) == -1) {
191a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                counts[fontResources[font]->getType()]++;
192a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                seenFonts.push(fontID);
193a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                if (!fontResources[font]->canSubset()) {
194a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                    notSubsettable++;
195a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                }
196a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                if (!fontResources[font]->canEmbed()) {
197a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                    notEmbeddable++;
198a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                }
199a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary            }
200a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        }
201a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
202a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    if (notSubsettableCount) {
203a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        *notSubsettableCount = notSubsettable;
204a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
205a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
206a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    if (notEmbeddableCount) {
207a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        *notEmbeddableCount = notEmbeddable;
208a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
209a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
210a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#endif
211f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanary
212f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanarytemplate <typename T> static T* clone(const T* o) { return o ? new T(*o) : nullptr; }
213a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary////////////////////////////////////////////////////////////////////////////////
21499ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
21550e82e61766d22da5238905916a8abc3e6664060halcanarySkPDFDocument::SkPDFDocument(SkWStream* stream,
21650e82e61766d22da5238905916a8abc3e6664060halcanary                             void (*doneProc)(SkWStream*, bool),
21750e82e61766d22da5238905916a8abc3e6664060halcanary                             SkScalar rasterDpi,
2184b6566644f704cf9e30c71fa547c9b5915752792halcanary                             const SkDocument::PDFMetadata& metadata,
2194b6566644f704cf9e30c71fa547c9b5915752792halcanary                             sk_sp<SkPixelSerializer> jpegEncoder,
220488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary                             bool pdfa)
22150e82e61766d22da5238905916a8abc3e6664060halcanary    : SkDocument(stream, doneProc)
222488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    , fRasterDpi(rasterDpi)
2234b6566644f704cf9e30c71fa547c9b5915752792halcanary    , fMetadata(metadata)
224488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    , fPDFA(pdfa) {
2254b6566644f704cf9e30c71fa547c9b5915752792halcanary    fCanon.setPixelSerializer(std::move(jpegEncoder));
22650e82e61766d22da5238905916a8abc3e6664060halcanary}
2276319367bdcbf5e5050632ab97973f5035d0dd8faskia.committer@gmail.com
22850e82e61766d22da5238905916a8abc3e6664060halcanarySkPDFDocument::~SkPDFDocument() {
22950e82e61766d22da5238905916a8abc3e6664060halcanary    // subclasses of SkDocument must call close() in their destructors.
23050e82e61766d22da5238905916a8abc3e6664060halcanary    this->close();
23150e82e61766d22da5238905916a8abc3e6664060halcanary}
23299ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
23350e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFDocument::serialize(const sk_sp<SkPDFObject>& object) {
23450e82e61766d22da5238905916a8abc3e6664060halcanary    fObjectSerializer.addObjectRecursively(object);
23550e82e61766d22da5238905916a8abc3e6664060halcanary    fObjectSerializer.serializeObjects(this->getStream());
23650e82e61766d22da5238905916a8abc3e6664060halcanary}
23799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
23850e82e61766d22da5238905916a8abc3e6664060halcanarySkCanvas* SkPDFDocument::onBeginPage(SkScalar width, SkScalar height,
23950e82e61766d22da5238905916a8abc3e6664060halcanary                                     const SkRect& trimBox) {
24050e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(!fCanvas.get());  // endPage() was called before this.
241cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    if (fPages.empty()) {
24250e82e61766d22da5238905916a8abc3e6664060halcanary        // if this is the first page if the document.
24350e82e61766d22da5238905916a8abc3e6664060halcanary        fObjectSerializer.serializeHeader(this->getStream(), fMetadata);
244cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        fDests = sk_make_sp<SkPDFDict>();
245488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary        if (fPDFA) {
2464b6566644f704cf9e30c71fa547c9b5915752792halcanary            SkPDFMetadata::UUID uuid = SkPDFMetadata::CreateUUID(fMetadata);
2478cd4a24236ffc26522d0372c0d0ab0d96e301b3bhalcanary            // We use the same UUID for Document ID and Instance ID since this
2488cd4a24236ffc26522d0372c0d0ab0d96e301b3bhalcanary            // is the first revision of this document (and Skia does not
2498cd4a24236ffc26522d0372c0d0ab0d96e301b3bhalcanary            // support revising existing PDF documents).
2508cd4a24236ffc26522d0372c0d0ab0d96e301b3bhalcanary            // If we are not in PDF/A mode, don't use a UUID since testing
2518cd4a24236ffc26522d0372c0d0ab0d96e301b3bhalcanary            // works best with reproducible outputs.
2524b6566644f704cf9e30c71fa547c9b5915752792halcanary            fID = SkPDFMetadata::MakePdfId(uuid, uuid);
2534b6566644f704cf9e30c71fa547c9b5915752792halcanary            fXMP = SkPDFMetadata::MakeXMPObject(fMetadata, uuid, uuid);
2548cd4a24236ffc26522d0372c0d0ab0d96e301b3bhalcanary            fObjectSerializer.addObjectRecursively(fXMP);
2558cd4a24236ffc26522d0372c0d0ab0d96e301b3bhalcanary            fObjectSerializer.serializeObjects(this->getStream());
256488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary        }
25799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    }
25850e82e61766d22da5238905916a8abc3e6664060halcanary    SkISize pageSize = SkISize::Make(
25950e82e61766d22da5238905916a8abc3e6664060halcanary            SkScalarRoundToInt(width), SkScalarRoundToInt(height));
260cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPageDevice.reset(
261989da4a32cd6823359f31c971c3b3f31425e905ehalcanary            SkPDFDevice::Create(pageSize, fRasterDpi, this));
262cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fCanvas = sk_make_sp<SkPDFCanvas>(fPageDevice);
26350e82e61766d22da5238905916a8abc3e6664060halcanary    fCanvas->clipRect(trimBox);
26450e82e61766d22da5238905916a8abc3e6664060halcanary    fCanvas->translate(trimBox.x(), trimBox.y());
26550e82e61766d22da5238905916a8abc3e6664060halcanary    return fCanvas.get();
26650e82e61766d22da5238905916a8abc3e6664060halcanary}
26750e82e61766d22da5238905916a8abc3e6664060halcanary
26850e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFDocument::onEndPage() {
26950e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(fCanvas.get());
27050e82e61766d22da5238905916a8abc3e6664060halcanary    fCanvas->flush();
27150e82e61766d22da5238905916a8abc3e6664060halcanary    fCanvas.reset(nullptr);
272cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    SkASSERT(fPageDevice);
273cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    auto page = sk_make_sp<SkPDFDict>("Page");
274cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    page->insertObject("Resources", fPageDevice->makeResourceDict());
275cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    page->insertObject("MediaBox", fPageDevice->copyMediaBox());
276cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    auto annotations = sk_make_sp<SkPDFArray>();
277cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPageDevice->appendAnnotations(annotations.get());
278cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    if (annotations->size() > 0) {
279cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        page->insertObject("Annots", std::move(annotations));
280cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    }
281cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    auto contentData = fPageDevice->content();
282cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    auto contentObject = sk_make_sp<SkPDFStream>(contentData.get());
283cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    this->serialize(contentObject);
284cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    page->insertObjRef("Contents", std::move(contentObject));
285cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPageDevice->appendDestinations(fDests.get(), page.get());
286cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPages.emplace_back(std::move(page));
287cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPageDevice.reset(nullptr);
28850e82e61766d22da5238905916a8abc3e6664060halcanary}
28950e82e61766d22da5238905916a8abc3e6664060halcanary
29050e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFDocument::onAbort() {
29150e82e61766d22da5238905916a8abc3e6664060halcanary    fCanvas.reset(nullptr);
292cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    fPages.reset();
29350e82e61766d22da5238905916a8abc3e6664060halcanary    fCanon.reset();
29450e82e61766d22da5238905916a8abc3e6664060halcanary    renew(&fObjectSerializer);
2953c35fb3310c22eb0141c8f39c5423f7bcd42adffhalcanary    renew(&fGlyphUsage);
29650e82e61766d22da5238905916a8abc3e6664060halcanary}
29799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
2984b6566644f704cf9e30c71fa547c9b5915752792halcanary#ifdef SK_SUPPORT_LEGACY_DOCUMENT_API
29950e82e61766d22da5238905916a8abc3e6664060halcanaryvoid SkPDFDocument::setMetadata(const SkDocument::Attribute info[],
30050e82e61766d22da5238905916a8abc3e6664060halcanary                                int infoCount,
30150e82e61766d22da5238905916a8abc3e6664060halcanary                                const SkTime::DateTime* creationDate,
30250e82e61766d22da5238905916a8abc3e6664060halcanary                                const SkTime::DateTime* modifiedDate) {
3034b6566644f704cf9e30c71fa547c9b5915752792halcanary    for (int i = 0; i < infoCount; ++i) {
3044b6566644f704cf9e30c71fa547c9b5915752792halcanary        const SkDocument::Attribute& kv = info[i];
3054b6566644f704cf9e30c71fa547c9b5915752792halcanary        SkPDFMetadata::SetMetadataByKey(kv.fKey, kv.fValue, &fMetadata);
3064b6566644f704cf9e30c71fa547c9b5915752792halcanary    }
3074b6566644f704cf9e30c71fa547c9b5915752792halcanary    if (creationDate) {
3084b6566644f704cf9e30c71fa547c9b5915752792halcanary        fMetadata.fCreation.fEnabled = true;
3094b6566644f704cf9e30c71fa547c9b5915752792halcanary        fMetadata.fCreation.fDateTime = *creationDate;
3104b6566644f704cf9e30c71fa547c9b5915752792halcanary    }
3114b6566644f704cf9e30c71fa547c9b5915752792halcanary    if (modifiedDate) {
3124b6566644f704cf9e30c71fa547c9b5915752792halcanary        fMetadata.fModified.fEnabled = true;
3134b6566644f704cf9e30c71fa547c9b5915752792halcanary        fMetadata.fModified.fDateTime = *modifiedDate;
3144b6566644f704cf9e30c71fa547c9b5915752792halcanary    }
31550e82e61766d22da5238905916a8abc3e6664060halcanary}
3164b6566644f704cf9e30c71fa547c9b5915752792halcanary#endif  // SK_SUPPORT_LEGACY_DOCUMENT_API
31799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
31878daeff1f9c1639d4921abb7acd9b76b77660802halcanarystatic sk_sp<SkData> SkSrgbIcm() {
31999e22fbe569ef3525d4de07eceaca2200a3d6e50halcanary    auto srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
32099e22fbe569ef3525d4de07eceaca2200a3d6e50halcanary    return as_CSB(srgb)->writeToICC();
32178daeff1f9c1639d4921abb7acd9b76b77660802halcanary}
32278daeff1f9c1639d4921abb7acd9b76b77660802halcanary
32378daeff1f9c1639d4921abb7acd9b76b77660802halcanarystatic sk_sp<SkPDFStream> make_srgb_color_profile() {
32478daeff1f9c1639d4921abb7acd9b76b77660802halcanary    sk_sp<SkData> profile = SkSrgbIcm();
32578daeff1f9c1639d4921abb7acd9b76b77660802halcanary    sk_sp<SkPDFStream> stream = sk_make_sp<SkPDFStream>(profile.get());
32678daeff1f9c1639d4921abb7acd9b76b77660802halcanary    stream->insertInt("N", 3);
32778daeff1f9c1639d4921abb7acd9b76b77660802halcanary    sk_sp<SkPDFArray> array = sk_make_sp<SkPDFArray>();
32878daeff1f9c1639d4921abb7acd9b76b77660802halcanary    array->appendScalar(0.0f);
32978daeff1f9c1639d4921abb7acd9b76b77660802halcanary    array->appendScalar(1.0f);
33078daeff1f9c1639d4921abb7acd9b76b77660802halcanary    array->appendScalar(0.0f);
33178daeff1f9c1639d4921abb7acd9b76b77660802halcanary    array->appendScalar(1.0f);
33278daeff1f9c1639d4921abb7acd9b76b77660802halcanary    array->appendScalar(0.0f);
33378daeff1f9c1639d4921abb7acd9b76b77660802halcanary    array->appendScalar(1.0f);
33478daeff1f9c1639d4921abb7acd9b76b77660802halcanary    stream->insertObject("Range", std::move(array));
33578daeff1f9c1639d4921abb7acd9b76b77660802halcanary    return stream;
33678daeff1f9c1639d4921abb7acd9b76b77660802halcanary}
337488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary
338488165e689baf0f215d5798c87d0031b58e4bc8dhalcanarystatic sk_sp<SkPDFArray> make_srgb_output_intents() {
339488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    // sRGB is specified by HTML, CSS, and SVG.
340488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    auto outputIntent = sk_make_sp<SkPDFDict>("OutputIntent");
341488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    outputIntent->insertName("S", "GTS_PDFA1");
342488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    outputIntent->insertString("RegistryName", "http://www.color.org");
343488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    outputIntent->insertString("OutputConditionIdentifier",
344488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary                               "Custom");
345488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    outputIntent->insertString("Info","sRGB IEC61966-2.1");
346488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    outputIntent->insertObjRef("DestOutputProfile",
347488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary                               make_srgb_color_profile());
348488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    auto intentArray = sk_make_sp<SkPDFArray>();
349488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    intentArray->appendObject(std::move(outputIntent));
350488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    return intentArray;
351488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary}
35278daeff1f9c1639d4921abb7acd9b76b77660802halcanary
35350e82e61766d22da5238905916a8abc3e6664060halcanarybool SkPDFDocument::onClose(SkWStream* stream) {
35450e82e61766d22da5238905916a8abc3e6664060halcanary    SkASSERT(!fCanvas.get());
355cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    if (fPages.empty()) {
356cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        fPages.reset();
3572e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanary        fCanon.reset();
35850e82e61766d22da5238905916a8abc3e6664060halcanary        renew(&fObjectSerializer);
3593c35fb3310c22eb0141c8f39c5423f7bcd42adffhalcanary        renew(&fGlyphUsage);
36050e82e61766d22da5238905916a8abc3e6664060halcanary        return false;
361b5a6651f9f69570d964382134d64360915db9a29commit-bot@chromium.org    }
36250e82e61766d22da5238905916a8abc3e6664060halcanary    auto docCatalog = sk_make_sp<SkPDFDict>("Catalog");
363488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    if (fPDFA) {
3648cd4a24236ffc26522d0372c0d0ab0d96e301b3bhalcanary        SkASSERT(fXMP);
3658cd4a24236ffc26522d0372c0d0ab0d96e301b3bhalcanary        docCatalog->insertObjRef("Metadata", fXMP);
36650e82e61766d22da5238905916a8abc3e6664060halcanary        // Don't specify OutputIntents if we are not in PDF/A mode since
36750e82e61766d22da5238905916a8abc3e6664060halcanary        // no one has ever asked for this feature.
368488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary        docCatalog->insertObject("OutputIntents", make_srgb_output_intents());
369488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    }
370488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    SkASSERT(!fPages.empty());
371cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    docCatalog->insertObjRef("Pages", generate_page_tree(&fPages));
372488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    SkASSERT(fPages.empty());
37350e82e61766d22da5238905916a8abc3e6664060halcanary
374cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    if (fDests->size() > 0) {
375cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        docCatalog->insertObjRef("Dests", std::move(fDests));
376f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanary    }
377f12a1673f024d30d30f06b9f88b5cc072b8a2d1ehalcanary
37850e82e61766d22da5238905916a8abc3e6664060halcanary    // Build font subsetting info before calling addObjectRecursively().
379cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    for (const auto& entry : fGlyphUsage) {
380cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        sk_sp<SkPDFFont> subsetFont(
3813c35fb3310c22eb0141c8f39c5423f7bcd42adffhalcanary                entry.fFont->getFontSubset(&entry.fGlyphSet));
382cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        if (subsetFont) {
383cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary            fObjectSerializer.fSubstituteMap.setSubstitute(
384cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary                    entry.fFont, subsetFont.get());
385cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary        }
386cc77c12293d1685f5e83d768b30ca9157af1576dhalcanary    }
38750e82e61766d22da5238905916a8abc3e6664060halcanary
38850e82e61766d22da5238905916a8abc3e6664060halcanary    fObjectSerializer.addObjectRecursively(docCatalog);
38950e82e61766d22da5238905916a8abc3e6664060halcanary    fObjectSerializer.serializeObjects(this->getStream());
390488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary    fObjectSerializer.serializeFooter(this->getStream(), docCatalog, fID);
39150e82e61766d22da5238905916a8abc3e6664060halcanary    fCanon.reset();
39250e82e61766d22da5238905916a8abc3e6664060halcanary    renew(&fObjectSerializer);
3933c35fb3310c22eb0141c8f39c5423f7bcd42adffhalcanary    renew(&fGlyphUsage);
39450e82e61766d22da5238905916a8abc3e6664060halcanary    return true;
39550e82e61766d22da5238905916a8abc3e6664060halcanary}
39650e82e61766d22da5238905916a8abc3e6664060halcanary
39799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com///////////////////////////////////////////////////////////////////////////////
39899ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
39923f4d4d1b9151bb89cdced9986be7ec9b006d458halcanarysk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream,
40023f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary                                    void (*proc)(SkWStream*, bool),
40123f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary                                    SkScalar dpi,
4024b6566644f704cf9e30c71fa547c9b5915752792halcanary                                    const SkDocument::PDFMetadata& metadata,
4034b6566644f704cf9e30c71fa547c9b5915752792halcanary                                    sk_sp<SkPixelSerializer> jpeg,
404488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary                                    bool pdfa) {
4054b6566644f704cf9e30c71fa547c9b5915752792halcanary    return stream ? sk_make_sp<SkPDFDocument>(stream, proc, dpi, metadata,
4064b6566644f704cf9e30c71fa547c9b5915752792halcanary                                              std::move(jpeg), pdfa)
407488165e689baf0f215d5798c87d0031b58e4bc8dhalcanary                  : nullptr;
40823f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary}
40923f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary
4104b6566644f704cf9e30c71fa547c9b5915752792halcanarysk_sp<SkDocument> SkDocument::MakePDF(const char path[], SkScalar dpi) {
411385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    auto delete_wstream = [](SkWStream* stream, bool) { delete stream; };
412b8fb9934a0707e8e5f9e725502974dc2d432a815halcanary    std::unique_ptr<SkFILEWStream> stream(new SkFILEWStream(path));
41323f4d4d1b9151bb89cdced9986be7ec9b006d458halcanary    return stream->isValid()
4144b6566644f704cf9e30c71fa547c9b5915752792halcanary                   ? SkPDFMakeDocument(stream.release(), delete_wstream, dpi,
4154b6566644f704cf9e30c71fa547c9b5915752792halcanary                                       SkDocument::PDFMetadata(), nullptr,
4164b6566644f704cf9e30c71fa547c9b5915752792halcanary                                       false)
4174b6566644f704cf9e30c71fa547c9b5915752792halcanary                   : nullptr;
4184b6566644f704cf9e30c71fa547c9b5915752792halcanary}
4194b6566644f704cf9e30c71fa547c9b5915752792halcanary
4204b6566644f704cf9e30c71fa547c9b5915752792halcanarysk_sp<SkDocument> SkDocument::MakePDF(SkWStream* stream,
4214b6566644f704cf9e30c71fa547c9b5915752792halcanary                                      SkScalar dpi,
4224b6566644f704cf9e30c71fa547c9b5915752792halcanary                                      const SkDocument::PDFMetadata& metadata,
4234b6566644f704cf9e30c71fa547c9b5915752792halcanary                                      sk_sp<SkPixelSerializer> jpegEncoder,
4244b6566644f704cf9e30c71fa547c9b5915752792halcanary                                      bool pdfa) {
4254b6566644f704cf9e30c71fa547c9b5915752792halcanary    return SkPDFMakeDocument(stream, nullptr, dpi, metadata,
4264b6566644f704cf9e30c71fa547c9b5915752792halcanary                             std::move(jpegEncoder), pdfa);
42799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com}
428