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

Side by Side Diff: src/doc/SkDocument_PDF.cpp

Issue 1034793002: SkPDF: merge skdocument_pdf and skpdfdocument (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gyp/pdf.gypi ('k') | src/pdf/SkPDFDocument.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2011 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkDocument.h" 8 #include "SkDocument.h"
9 #include "SkPDFCanon.h" 9 #include "SkPDFCanon.h"
10 #include "SkPDFDocument.h" 10 #include "SkPDFCatalog.h"
11 #include "SkPDFDevice.h" 11 #include "SkPDFDevice.h"
12 #include "SkPDFFont.h"
13 #include "SkPDFPage.h"
14 #include "SkPDFTypes.h"
15 #include "SkStream.h"
16
17 static void emit_pdf_header(SkWStream* stream) {
18 stream->writeText("%PDF-1.4\n%");
19 // The PDF spec recommends including a comment with four bytes, all
20 // with their high bits set. This is "Skia" with the high bits set.
21 stream->write32(0xD3EBE9E1);
22 stream->writeText("\n");
23 }
24
25 static void emit_pdf_footer(SkWStream* stream,
26 SkPDFCatalog* catalog,
27 SkPDFObject* docCatalog,
28 int64_t objCount,
29 int32_t xRefFileOffset) {
30 SkPDFDict trailerDict;
31 // TODO(vandebo): Linearized format will take a Prev entry too.
32 // TODO(vandebo): PDF/A requires an ID entry.
33 trailerDict.insertInt("Size", int(objCount));
34 trailerDict.insert("Root", new SkPDFObjRef(docCatalog))->unref();
35
36 stream->writeText("trailer\n");
37 trailerDict.emitObject(stream, catalog);
38 stream->writeText("\nstartxref\n");
39 stream->writeBigDecAsText(xRefFileOffset);
40 stream->writeText("\n%%EOF");
41 }
42
43 static void perform_font_subsetting(SkPDFCatalog* catalog,
44 const SkTDArray<SkPDFPage*>& pages) {
45 SkASSERT(catalog);
46
47 SkPDFGlyphSetMap usage;
48 for (int i = 0; i < pages.count(); ++i) {
49 usage.merge(pages[i]->getFontGlyphUsage());
50 }
51 SkPDFGlyphSetMap::F2BIter iterator(usage);
52 const SkPDFGlyphSetMap::FontGlyphSetPair* entry = iterator.next();
53 while (entry) {
54 SkAutoTUnref<SkPDFFont> subsetFont(
55 entry->fFont->getFontSubset(entry->fGlyphSet));
56 if (subsetFont) {
57 catalog->setSubstitute(entry->fFont, subsetFont.get());
58 }
59 entry = iterator.next();
60 }
61 }
62
63 static bool emit_pdf_document(const SkTDArray<const SkPDFDevice*>& pageDevices,
64 SkWStream* stream) {
65 if (pageDevices.isEmpty()) {
66 return false;
67 }
68
69 SkTDArray<SkPDFPage*> pages;
70 SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict));
71
72 for (int i = 0; i < pageDevices.count(); i++) {
73 SkASSERT(pageDevices[i]);
74 SkASSERT(i == 0 ||
75 pageDevices[i - 1]->getCanon() == pageDevices[i]->getCanon());
76 // Reference from new passed to pages.
77 SkAutoTUnref<SkPDFPage> page(SkNEW_ARGS(SkPDFPage, (pageDevices[i])));
78 page->finalizePage();
79 page->appendDestinations(dests);
80 pages.push(page.detach());
81 }
82 SkPDFCatalog catalog;
83
84 SkTDArray<SkPDFDict*> pageTree;
85 SkAutoTUnref<SkPDFDict> docCatalog(SkNEW_ARGS(SkPDFDict, ("Catalog")));
86
87 SkPDFDict* pageTreeRoot;
88 SkPDFPage::GeneratePageTree(pages, &pageTree, &pageTreeRoot);
89
90 docCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref();
91
92 /* TODO(vandebo): output intent
93 SkAutoTUnref<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent");
94 outputIntent->insert("S", new SkPDFName("GTS_PDFA1"))->unref();
95 outputIntent->insert("OutputConditionIdentifier",
96 new SkPDFString("sRGB"))->unref();
97 SkAutoTUnref<SkPDFArray> intentArray = new SkPDFArray;
98 intentArray->append(outputIntent.get());
99 docCatalog->insert("OutputIntent", intentArray.get());
100 */
101
102 if (dests->size() > 0) {
103 docCatalog->insert("Dests", SkNEW_ARGS(SkPDFObjRef, (dests.get())))
104 ->unref();
105 }
106
107 // Build font subsetting info before proceeding.
108 perform_font_subsetting(&catalog, pages);
109
110 SkTSet<SkPDFObject*> resourceSet;
111 if (resourceSet.add(docCatalog.get())) {
112 docCatalog->addResources(&resourceSet, &catalog);
113 }
114 for (int i = 0; i < resourceSet.count(); ++i) {
115 SkAssertResult(catalog.addObject(resourceSet[i]));
116 }
117
118 size_t baseOffset = SkToOffT(stream->bytesWritten());
119 emit_pdf_header(stream);
120 SkTDArray<int32_t> offsets;
121 for (int i = 0; i < resourceSet.count(); ++i) {
122 SkPDFObject* object = resourceSet[i];
123 offsets.push(SkToS32(stream->bytesWritten() - baseOffset));
124 SkASSERT(object == catalog.getSubstituteObject(object));
125 SkASSERT(catalog.getObjectNumber(object) == i + 1);
126 stream->writeDecAsText(i + 1);
127 stream->writeText(" 0 obj\n"); // Generation number is always 0.
128 object->emitObject(stream, &catalog);
129 stream->writeText("\nendobj\n");
130 }
131 int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset);
132
133 int32_t objCount = SkToS32(offsets.count() + 1);
134
135 stream->writeText("xref\n0 ");
136 stream->writeDecAsText(objCount + 1);
137 stream->writeText("\n0000000000 65535 f \n");
138 for (int i = 0; i < offsets.count(); i++) {
139 SkASSERT(offsets[i] > 0);
140 stream->writeBigDecAsText(offsets[i], 10);
141 stream->writeText(" 00000 n \n");
142 }
143 emit_pdf_footer(stream, &catalog, docCatalog.get(), objCount,
144 xRefFileOffset);
145
146 // The page tree has both child and parent pointers, so it creates a
147 // reference cycle. We must clear that cycle to properly reclaim memory.
148 for (int i = 0; i < pageTree.count(); i++) {
149 pageTree[i]->clear();
150 }
151 pageTree.safeUnrefAll();
152 pages.unrefAll();
153 return true;
154 }
155
156 #if 0
157 // TODO(halcanary): expose notEmbeddableCount in SkDocument
158 void GetCountOfFontTypes(
159 const SkTDArray<SkPDFDevice*>& pageDevices,
160 int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1],
161 int* notSubsettableCount,
162 int* notEmbeddableCount) {
163 sk_bzero(counts, sizeof(int) *
164 (SkAdvancedTypefaceMetrics::kOther_Font + 1));
165 SkTDArray<SkFontID> seenFonts;
166 int notSubsettable = 0;
167 int notEmbeddable = 0;
168
169 for (int pageNumber = 0; pageNumber < pageDevices.count(); pageNumber++) {
170 const SkTDArray<SkPDFFont*>& fontResources =
171 pageDevices[pageNumber]->getFontResources();
172 for (int font = 0; font < fontResources.count(); font++) {
173 SkFontID fontID = fontResources[font]->typeface()->uniqueID();
174 if (seenFonts.find(fontID) == -1) {
175 counts[fontResources[font]->getType()]++;
176 seenFonts.push(fontID);
177 if (!fontResources[font]->canSubset()) {
178 notSubsettable++;
179 }
180 if (!fontResources[font]->canEmbed()) {
181 notEmbeddable++;
182 }
183 }
184 }
185 }
186 if (notSubsettableCount) {
187 *notSubsettableCount = notSubsettable;
188
189 }
190 if (notEmbeddableCount) {
191 *notEmbeddableCount = notEmbeddable;
192 }
193 }
194 #endif
195 ////////////////////////////////////////////////////////////////////////////////
12 196
13 namespace { 197 namespace {
14 class SkDocument_PDF : public SkDocument { 198 class SkDocument_PDF : public SkDocument {
15 public: 199 public:
16 SkDocument_PDF(SkWStream* stream, 200 SkDocument_PDF(SkWStream* stream,
17 void (*doneProc)(SkWStream*, bool), 201 void (*doneProc)(SkWStream*, bool),
18 SkScalar rasterDpi) 202 SkScalar rasterDpi)
19 : SkDocument(stream, doneProc) 203 : SkDocument(stream, doneProc)
20 , fRasterDpi(rasterDpi) {} 204 , fRasterDpi(rasterDpi) {}
21 205
(...skipping 20 matching lines...) Expand all
42 226
43 void onEndPage() SK_OVERRIDE { 227 void onEndPage() SK_OVERRIDE {
44 SkASSERT(fCanvas.get()); 228 SkASSERT(fCanvas.get());
45 fCanvas->flush(); 229 fCanvas->flush();
46 fCanvas.reset(NULL); 230 fCanvas.reset(NULL);
47 } 231 }
48 232
49 bool onClose(SkWStream* stream) SK_OVERRIDE { 233 bool onClose(SkWStream* stream) SK_OVERRIDE {
50 SkASSERT(!fCanvas.get()); 234 SkASSERT(!fCanvas.get());
51 235
52 bool success = SkPDFDocument::EmitPDF(fPageDevices, stream); 236 bool success = emit_pdf_document(fPageDevices, stream);
53 fPageDevices.unrefAll(); 237 fPageDevices.unrefAll();
54 fCanon.reset(); 238 fCanon.reset();
55 return success; 239 return success;
56 } 240 }
57 241
58 void onAbort() SK_OVERRIDE { 242 void onAbort() SK_OVERRIDE {
59 fPageDevices.unrefAll(); 243 fPageDevices.unrefAll();
60 fCanon.reset(); 244 fCanon.reset();
61 } 245 }
62 246
63 private: 247 private:
64 SkPDFCanon fCanon; 248 SkPDFCanon fCanon;
65 SkTDArray<const SkPDFDevice*> fPageDevices; 249 SkTDArray<const SkPDFDevice*> fPageDevices;
66 SkAutoTUnref<SkCanvas> fCanvas; 250 SkAutoTUnref<SkCanvas> fCanvas;
67 SkScalar fRasterDpi; 251 SkScalar fRasterDpi;
68 }; 252 };
69 } // namespace 253 } // namespace
70 /////////////////////////////////////////////////////////////////////////////// 254 ///////////////////////////////////////////////////////////////////////////////
71 255
72 SkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) { 256 SkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) {
73 return stream ? SkNEW_ARGS(SkDocument_PDF, (stream, NULL, dpi)) : NULL; 257 return stream ? SkNEW_ARGS(SkDocument_PDF, (stream, NULL, dpi)) : NULL;
74 } 258 }
75 259
76 static void delete_wstream(SkWStream* stream, bool aborted) {
77 SkDELETE(stream);
78 }
79
80 SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) { 260 SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) {
81 SkFILEWStream* stream = SkNEW_ARGS(SkFILEWStream, (path)); 261 SkFILEWStream* stream = SkNEW_ARGS(SkFILEWStream, (path));
82 if (!stream->isValid()) { 262 if (!stream->isValid()) {
83 SkDELETE(stream); 263 SkDELETE(stream);
84 return NULL; 264 return NULL;
85 } 265 }
266 auto delete_wstream = [](SkWStream* stream, bool) { SkDELETE(stream); };
86 return SkNEW_ARGS(SkDocument_PDF, (stream, delete_wstream, dpi)); 267 return SkNEW_ARGS(SkDocument_PDF, (stream, delete_wstream, dpi));
87 } 268 }
OLDNEW
« no previous file with comments | « gyp/pdf.gypi ('k') | src/pdf/SkPDFDocument.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698