SkPDFDocument.cpp revision a43b41538ad6af0f2b7742b4ade8265d344b9d64
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
899ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com#include "SkDocument.h"
9a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary#include "SkPDFCanon.h"
10a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#include "SkPDFCatalog.h"
115867736b08d3689356b49f505bcf748c2194a0bcreed#include "SkPDFDevice.h"
12a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#include "SkPDFFont.h"
13a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#include "SkPDFPage.h"
14a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#include "SkPDFTypes.h"
15a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#include "SkStream.h"
16a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
17a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanarystatic void emit_pdf_header(SkWStream* stream) {
18a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    stream->writeText("%PDF-1.4\n%");
19a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    // The PDF spec recommends including a comment with four bytes, all
20a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    // with their high bits set.  This is "Skia" with the high bits set.
21a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    stream->write32(0xD3EBE9E1);
22a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    stream->writeText("\n");
23a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
24a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
25a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanarystatic void emit_pdf_footer(SkWStream* stream,
26a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                            SkPDFCatalog* catalog,
27a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                            SkPDFObject* docCatalog,
28a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                            int64_t objCount,
29a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                            int32_t xRefFileOffset) {
30a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkPDFDict trailerDict;
31a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    // TODO(vandebo): Linearized format will take a Prev entry too.
32a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    // TODO(vandebo): PDF/A requires an ID entry.
33a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    trailerDict.insertInt("Size", int(objCount));
34a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    trailerDict.insert("Root", new SkPDFObjRef(docCatalog))->unref();
35a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
36a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    stream->writeText("trailer\n");
37a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    trailerDict.emitObject(stream, catalog);
38a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    stream->writeText("\nstartxref\n");
39a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    stream->writeBigDecAsText(xRefFileOffset);
40a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    stream->writeText("\n%%EOF");
41a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
42a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
43a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanarystatic void perform_font_subsetting(SkPDFCatalog* catalog,
44a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                                    const SkTDArray<SkPDFPage*>& pages) {
45a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkASSERT(catalog);
46a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
47a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkPDFGlyphSetMap usage;
48a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    for (int i = 0; i < pages.count(); ++i) {
49a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        usage.merge(pages[i]->getFontGlyphUsage());
50a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
51a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkPDFGlyphSetMap::F2BIter iterator(usage);
52a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    const SkPDFGlyphSetMap::FontGlyphSetPair* entry = iterator.next();
53a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    while (entry) {
54a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        SkAutoTUnref<SkPDFFont> subsetFont(
55a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                entry->fFont->getFontSubset(entry->fGlyphSet));
56a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        if (subsetFont) {
57a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary            catalog->setSubstitute(entry->fFont, subsetFont.get());
58a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        }
59a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        entry = iterator.next();
60a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
61a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
62a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
63a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanarystatic bool emit_pdf_document(const SkTDArray<const SkPDFDevice*>& pageDevices,
64a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                              SkWStream* stream) {
65a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    if (pageDevices.isEmpty()) {
66a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        return false;
67a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
68a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
69a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkTDArray<SkPDFPage*> pages;
70a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict));
71a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
72a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    for (int i = 0; i < pageDevices.count(); i++) {
73a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        SkASSERT(pageDevices[i]);
74a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        SkASSERT(i == 0 ||
75a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                 pageDevices[i - 1]->getCanon() == pageDevices[i]->getCanon());
76a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        // Reference from new passed to pages.
77a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        SkAutoTUnref<SkPDFPage> page(SkNEW_ARGS(SkPDFPage, (pageDevices[i])));
78a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        page->finalizePage();
79a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        page->appendDestinations(dests);
80a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        pages.push(page.detach());
81a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
82a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkPDFCatalog catalog;
83a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
84a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkTDArray<SkPDFDict*> pageTree;
85a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkAutoTUnref<SkPDFDict> docCatalog(SkNEW_ARGS(SkPDFDict, ("Catalog")));
86a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
87a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkPDFDict* pageTreeRoot;
88a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkPDFPage::GeneratePageTree(pages, &pageTree, &pageTreeRoot);
89a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
90a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    docCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref();
91a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
92a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    /* TODO(vandebo): output intent
93a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkAutoTUnref<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent");
94a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    outputIntent->insert("S", new SkPDFName("GTS_PDFA1"))->unref();
95a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    outputIntent->insert("OutputConditionIdentifier",
96a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                         new SkPDFString("sRGB"))->unref();
97a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkAutoTUnref<SkPDFArray> intentArray = new SkPDFArray;
98a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    intentArray->append(outputIntent.get());
99a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    docCatalog->insert("OutputIntent", intentArray.get());
100a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    */
101a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
102a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    if (dests->size() > 0) {
103a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        docCatalog->insert("Dests", SkNEW_ARGS(SkPDFObjRef, (dests.get())))
104a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                ->unref();
105a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
106a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
107a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    // Build font subsetting info before proceeding.
108a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    perform_font_subsetting(&catalog, pages);
109a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
110a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkTSet<SkPDFObject*> resourceSet;
111a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    if (resourceSet.add(docCatalog.get())) {
112a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        docCatalog->addResources(&resourceSet, &catalog);
113a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
114a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    for (int i = 0; i < resourceSet.count(); ++i) {
115a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        SkAssertResult(catalog.addObject(resourceSet[i]));
116a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
117a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
118a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    size_t baseOffset = SkToOffT(stream->bytesWritten());
119a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    emit_pdf_header(stream);
120a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkTDArray<int32_t> offsets;
121a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    for (int i = 0; i < resourceSet.count(); ++i) {
122a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        SkPDFObject* object = resourceSet[i];
123a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        offsets.push(SkToS32(stream->bytesWritten() - baseOffset));
124a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        SkASSERT(object == catalog.getSubstituteObject(object));
125a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        SkASSERT(catalog.getObjectNumber(object) == i + 1);
126a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        stream->writeDecAsText(i + 1);
127a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        stream->writeText(" 0 obj\n");  // Generation number is always 0.
128a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        object->emitObject(stream, &catalog);
129a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        stream->writeText("\nendobj\n");
130a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
131a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset);
132a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
133a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    int32_t objCount = SkToS32(offsets.count() + 1);
134a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
135a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    stream->writeText("xref\n0 ");
136a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    stream->writeDecAsText(objCount + 1);
137a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    stream->writeText("\n0000000000 65535 f \n");
138a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    for (int i = 0; i < offsets.count(); i++) {
139a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        SkASSERT(offsets[i] > 0);
140a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        stream->writeBigDecAsText(offsets[i], 10);
141a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        stream->writeText(" 00000 n \n");
142a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
143a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    emit_pdf_footer(stream, &catalog, docCatalog.get(), objCount,
144a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                    xRefFileOffset);
145a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
146a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    // The page tree has both child and parent pointers, so it creates a
147a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    // reference cycle.  We must clear that cycle to properly reclaim memory.
148a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    for (int i = 0; i < pageTree.count(); i++) {
149a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        pageTree[i]->clear();
150a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
151a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    pageTree.safeUnrefAll();
152a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    pages.unrefAll();
153a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    return true;
154a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
155a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
156a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#if 0
157a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary// TODO(halcanary): expose notEmbeddableCount in SkDocument
158a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanaryvoid GetCountOfFontTypes(
159a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        const SkTDArray<SkPDFDevice*>& pageDevices,
160a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1],
161a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        int* notSubsettableCount,
162a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        int* notEmbeddableCount) {
163a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    sk_bzero(counts, sizeof(int) *
164a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                     (SkAdvancedTypefaceMetrics::kOther_Font + 1));
165a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    SkTDArray<SkFontID> seenFonts;
166a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    int notSubsettable = 0;
167a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    int notEmbeddable = 0;
168a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
169a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    for (int pageNumber = 0; pageNumber < pageDevices.count(); pageNumber++) {
170a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        const SkTDArray<SkPDFFont*>& fontResources =
171a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                pageDevices[pageNumber]->getFontResources();
172a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        for (int font = 0; font < fontResources.count(); font++) {
173a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary            SkFontID fontID = fontResources[font]->typeface()->uniqueID();
174a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary            if (seenFonts.find(fontID) == -1) {
175a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                counts[fontResources[font]->getType()]++;
176a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                seenFonts.push(fontID);
177a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                if (!fontResources[font]->canSubset()) {
178a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                    notSubsettable++;
179a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                }
180a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                if (!fontResources[font]->canEmbed()) {
181a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                    notEmbeddable++;
182a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary                }
183a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary            }
184a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        }
185a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
186a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    if (notSubsettableCount) {
187a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        *notSubsettableCount = notSubsettable;
188a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary
189a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
190a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    if (notEmbeddableCount) {
191a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        *notEmbeddableCount = notEmbeddable;
192a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    }
193a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary}
194a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary#endif
195a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary////////////////////////////////////////////////////////////////////////////////
19699ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
1977a0118465a2dd1783d7b19b026bedd7e13afadf2halcanarynamespace {
19899ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.comclass SkDocument_PDF : public SkDocument {
19999ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.compublic:
2008c92dc1dc281649f9e6b0ff534c25bc89dded3eahalcanary    SkDocument_PDF(SkWStream* stream,
201792c80f5a7b66e75d42664ccb298f31962c6654chalcanary                   void (*doneProc)(SkWStream*, bool),
2028c294900f31d8d032b62182f011019276d27d5d0commit-bot@chromium.org                   SkScalar rasterDpi)
2038c92dc1dc281649f9e6b0ff534c25bc89dded3eahalcanary        : SkDocument(stream, doneProc)
2048c92dc1dc281649f9e6b0ff534c25bc89dded3eahalcanary        , fRasterDpi(rasterDpi) {}
2056319367bdcbf5e5050632ab97973f5035d0dd8faskia.committer@gmail.com
20699ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    virtual ~SkDocument_PDF() {
20799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com        // subclasses must call close() in their destructors
20899ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com        this->close();
20999ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    }
21099ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
21199ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.comprotected:
21299ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height,
2135e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                                  const SkRect& trimBox) SK_OVERRIDE {
214a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary        SkASSERT(!fCanvas.get());
21599ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
216a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary        SkISize pageSize = SkISize::Make(
217a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary                SkScalarRoundToInt(width), SkScalarRoundToInt(height));
2187a0118465a2dd1783d7b19b026bedd7e13afadf2halcanary        SkAutoTUnref<SkPDFDevice> device(
2197a0118465a2dd1783d7b19b026bedd7e13afadf2halcanary                SkPDFDevice::Create(pageSize, fRasterDpi, &fCanon));
2207a0118465a2dd1783d7b19b026bedd7e13afadf2halcanary        fCanvas.reset(SkNEW_ARGS(SkCanvas, (device.get())));
2217a0118465a2dd1783d7b19b026bedd7e13afadf2halcanary        fPageDevices.push(device.detach());
222be519ad718371cc40c432572173e47f851476486halcanary        fCanvas->clipRect(trimBox);
22393f816129356d6764a9402817cc36bffd8f991fbhalcanary        fCanvas->translate(trimBox.x(), trimBox.y());
224a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary        return fCanvas.get();
22599ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    }
22699ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
22772c9faab45124e08c85f70ca38536914862d947cmtklein    void onEndPage() SK_OVERRIDE {
228a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary        SkASSERT(fCanvas.get());
22999ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com        fCanvas->flush();
230a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary        fCanvas.reset(NULL);
23199ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    }
23299ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
23372c9faab45124e08c85f70ca38536914862d947cmtklein    bool onClose(SkWStream* stream) SK_OVERRIDE {
234a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary        SkASSERT(!fCanvas.get());
23599ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
236a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary        bool success = emit_pdf_document(fPageDevices, stream);
2377a0118465a2dd1783d7b19b026bedd7e13afadf2halcanary        fPageDevices.unrefAll();
2382e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanary        fCanon.reset();
239b5a6651f9f69570d964382134d64360915db9a29commit-bot@chromium.org        return success;
240b5a6651f9f69570d964382134d64360915db9a29commit-bot@chromium.org    }
241b5a6651f9f69570d964382134d64360915db9a29commit-bot@chromium.org
24272c9faab45124e08c85f70ca38536914862d947cmtklein    void onAbort() SK_OVERRIDE {
2437a0118465a2dd1783d7b19b026bedd7e13afadf2halcanary        fPageDevices.unrefAll();
2442e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanary        fCanon.reset();
24599ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    }
24699ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
24799ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.comprivate:
248a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary    SkPDFCanon fCanon;
2496d622703e578eddc64ab4e3340d0ab0033268799halcanary    SkTDArray<const SkPDFDevice*> fPageDevices;
250a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary    SkAutoTUnref<SkCanvas> fCanvas;
251a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary    SkScalar fRasterDpi;
25299ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com};
2537a0118465a2dd1783d7b19b026bedd7e13afadf2halcanary}  // namespace
25499ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com///////////////////////////////////////////////////////////////////////////////
25599ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
2568c92dc1dc281649f9e6b0ff534c25bc89dded3eahalcanarySkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) {
2578c92dc1dc281649f9e6b0ff534c25bc89dded3eahalcanary    return stream ? SkNEW_ARGS(SkDocument_PDF, (stream, NULL, dpi)) : NULL;
25899ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com}
25999ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com
2608c92dc1dc281649f9e6b0ff534c25bc89dded3eahalcanarySkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) {
26199ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    SkFILEWStream* stream = SkNEW_ARGS(SkFILEWStream, (path));
26299ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    if (!stream->isValid()) {
26399ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com        SkDELETE(stream);
26499ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com        return NULL;
26599ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com    }
266a43b41538ad6af0f2b7742b4ade8265d344b9d64halcanary    auto delete_wstream = [](SkWStream* stream, bool) { SkDELETE(stream); };
2678c92dc1dc281649f9e6b0ff534c25bc89dded3eahalcanary    return SkNEW_ARGS(SkDocument_PDF, (stream, delete_wstream, dpi));
26899ac02bb701c1e30b20f2174aac25ffbe487c0afreed@google.com}
269