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

Side by Side Diff: src/pdf/SkPDFDocument.cpp

Issue 1802033003: SkPDF: SkPDFDocument reorganized so that some objects can be serialized early. (Closed) Base URL: https://skia.googlesource.com/skia.git@SkPdfDumpMethod
Patch Set: Created 4 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
« src/pdf/SkPDFDocument.h ('K') | « src/pdf/SkPDFDocument.h ('k') | no next file » | 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 2011 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 "SkPDFCanon.h" 8 #include "SkPDFCanon.h"
9 #include "SkPDFDevice.h" 9 #include "SkPDFDevice.h"
10 #include "SkPDFDocument.h" 10 #include "SkPDFDocument.h"
11 #include "SkPDFFont.h" 11 #include "SkPDFFont.h"
12 #include "SkPDFMetadata.h"
13 #include "SkPDFStream.h" 12 #include "SkPDFStream.h"
14 #include "SkPDFTypes.h" 13 #include "SkPDFTypes.h"
15 #include "SkPDFUtils.h" 14 #include "SkPDFUtils.h"
16 #include "SkStream.h" 15 #include "SkStream.h"
17 16
18 static void emit_pdf_header(SkWStream* stream) { 17
19 stream->writeText("%PDF-1.4\n%"); 18 SkPDFObjectSerializer::SkPDFObjectSerializer() : fBaseOffset(0), fNextToBeSerial ized(0) {}
20 // The PDF spec recommends including a comment with four bytes, all 19
21 // with their high bits set. This is "Skia" with the high bits set. 20 template <class T> static void renew(T* t) { t->~T(); new (t) T; }
22 stream->write32(0xD3EBE9E1); 21
23 stream->writeText("\n"); 22 void SkPDFObjectSerializer::addObjectRecursively(const sk_sp<SkPDFObject>& objec t) {
23 fObjNumMap.addObjectRecursively(object.get(), fSubstituteMap);
24 } 24 }
25 25
26 static void emit_pdf_footer(SkWStream* stream, 26 void SkPDFObjectSerializer::serializeHeader(SkWStream* wStream, const SkPDFMetad ata& md) {
27 const SkPDFObjNumMap& objNumMap, 27 fBaseOffset = wStream->bytesWritten();
28 const SkPDFSubstituteMap& substitutes, 28 static const char kHeader[] = "%PDF-1.4\n%\xE1\xE9\xEB\xD3\n";
29 SkPDFObject* docCatalog, 29 wStream->write(kHeader, strlen(kHeader));
30 int64_t objCount, 30 // The PDF spec recommends including a comment with four
31 int32_t xRefFileOffset, 31 // bytes, all with their high bits set. "\xD3\xEB\xE9\xE1" is
32 sk_sp<SkPDFObject> info, 32 // "Skia" with the high bits set.
33 sk_sp<SkPDFObject> id) { 33 fInfoDict.reset(md.createDocumentInformationDict());
34 this->addObjectRecursively(fInfoDict);
35 this->serializeObjects(wStream);
36 }
37
38 // Serialize all objects in the fObjNumMap that have not yet been serialized;
39 void SkPDFObjectSerializer::serializeObjects(SkWStream* wStream) {
40 const auto& objects = fObjNumMap.objects();
tomhudson 2016/03/21 15:55:11 Still trying to stop worrying and love the auto; i
hal.canary 2016/03/21 18:49:18 Done.
41 while (fNextToBeSerialized < objects.count()) {
42 SkPDFObject* object = objects[fNextToBeSerialized].get();
43 int32_t index = fNextToBeSerialized + 1; // Skip object 0.
tomhudson 2016/03/21 15:55:11 I can see equivalent code in the previous version
hal.canary 2016/03/21 18:49:18 This is a PDF thing. Object zero is special. "Th
44 SkASSERT(fOffsets.count() == fNextToBeSerialized);
45 fOffsets.push(this->offset(wStream));
46 SkASSERT(object == fSubstituteMap.getSubstitute(object));
47 wStream->writeDecAsText(index);
48 wStream->writeText(" 0 obj\n"); // Generation number is always 0.
49 object->emitObject(wStream, fObjNumMap, fSubstituteMap);
50 wStream->writeText("\nendobj\n");
51 object->dump();
52 ++fNextToBeSerialized;
53 }
54 }
55
56 // Xref table and footer
57 void SkPDFObjectSerializer::serializeFooter(SkWStream* wStream,
58 const sk_sp<SkPDFObject> docCatalog,
59 sk_sp<SkPDFObject> id) {
60 this->serializeObjects(wStream);
61 int32_t xRefFileOffset = this->offset(wStream);
62 // Include the zeroth object in the count.
tomhudson 2016/03/21 15:55:12 Yeah, confusing after we previously skipped object
hal.canary 2016/03/21 18:49:18 Acknowledged.
63 int32_t objCount = SkToS32(fOffsets.count() + 1);
tomhudson 2016/03/21 15:55:12 Switched from int64_t to int32_t?
hal.canary 2016/03/21 18:49:17 For whatever reason, `writeDecAsText` takes an int
64 wStream->writeText("xref\n0 ");
65 wStream->writeDecAsText(objCount);
66 wStream->writeText("\n0000000000 65535 f \n");
67 for (int i = 0; i < fOffsets.count(); i++) {
68 wStream->writeBigDecAsText(fOffsets[i], 10);
69 wStream->writeText(" 00000 n \n");
70 }
34 SkPDFDict trailerDict; 71 SkPDFDict trailerDict;
35 // TODO(http://crbug.com/80908): Linearized format will take a 72 trailerDict.insertInt("Size", objCount);
36 // Prev entry too. 73 SkASSERT(docCatalog);
37 trailerDict.insertInt("Size", int(objCount)); 74 trailerDict.insertObjRef("Root", docCatalog);
tomhudson 2016/03/21 15:55:12 In the old code we explicitly ref'd this here?
hal.canary 2016/03/21 18:49:18 we switched to using sk_sp<T> no need.
38 trailerDict.insertObjRef("Root", sk_ref_sp(docCatalog)); 75 SkASSERT(fInfoDict);
39 SkASSERT(info); 76 trailerDict.insertObjRef("Info", std::move(fInfoDict));
40 trailerDict.insertObjRef("Info", std::move(info));
41 if (id) { 77 if (id) {
42 trailerDict.insertObject("ID", std::move(id)); 78 trailerDict.insertObject("ID", std::move(id));
43 } 79 }
44 stream->writeText("trailer\n"); 80 wStream->writeText("trailer\n");
45 trailerDict.emitObject(stream, objNumMap, substitutes); 81 trailerDict.emitObject(wStream, fObjNumMap, fSubstituteMap);
46 stream->writeText("\nstartxref\n"); 82 wStream->writeText("\nstartxref\n");
47 stream->writeBigDecAsText(xRefFileOffset); 83 wStream->writeBigDecAsText(xRefFileOffset);
48 stream->writeText("\n%%EOF"); 84 wStream->writeText("\n%%EOF");
85 }
86
87 int32_t SkPDFObjectSerializer::offset(SkWStream* wStream) {
88 size_t offset = wStream->bytesWritten();
89 SkASSERT(offset > fBaseOffset);
90 return SkToS32(offset - fBaseOffset);
49 } 91 }
50 92
51 static void perform_font_subsetting( 93 static void perform_font_subsetting(
52 const SkTArray<sk_sp<const SkPDFDevice>>& pageDevices, 94 const SkTArray<sk_sp<const SkPDFDevice>>& pageDevices,
53 SkPDFSubstituteMap* substituteMap) { 95 SkPDFSubstituteMap* substituteMap) {
54 SkASSERT(substituteMap); 96 SkASSERT(substituteMap);
55 97
56 SkPDFGlyphSetMap usage; 98 SkPDFGlyphSetMap usage;
57 for (const sk_sp<const SkPDFDevice>& pageDevice : pageDevices) { 99 for (const sk_sp<const SkPDFDevice>& pageDevice : pageDevices) {
58 usage.merge(pageDevice->getFontGlyphUsage()); 100 usage.merge(pageDevice->getFontGlyphUsage());
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 194
153 curNodes = nextRoundNodes; 195 curNodes = nextRoundNodes;
154 nextRoundNodes.rewind(); 196 nextRoundNodes.rewind();
155 treeCapacity *= kNodeSize; 197 treeCapacity *= kNodeSize;
156 } while (curNodes.count() > 1); 198 } while (curNodes.count() > 1);
157 199
158 pageTree->push(curNodes[0]); // Transfer reference. 200 pageTree->push(curNodes[0]); // Transfer reference.
159 return sk_ref_sp(curNodes[0]); 201 return sk_ref_sp(curNodes[0]);
160 } 202 }
161 203
162 static bool emit_pdf_document(const SkTArray<sk_sp<const SkPDFDevice>>& pageDevi ces,
163 const SkPDFMetadata& metadata,
164 SkWStream* stream) {
165 if (pageDevices.empty()) {
166 return false;
167 }
168
169 SkTDArray<SkPDFDict*> pages; // TODO: SkTArray<sk_sp<SkPDFDict>>
170 auto dests = sk_make_sp<SkPDFDict>();
171
172 for (const sk_sp<const SkPDFDevice>& pageDevice : pageDevices) {
173 SkASSERT(pageDevice);
174 SkASSERT(pageDevices[0]->getCanon() == pageDevice->getCanon());
175 sk_sp<SkPDFDict> page(create_pdf_page(pageDevice.get()));
176 pageDevice->appendDestinations(dests.get(), page.get());
177 pages.push(page.release());
178 }
179
180 auto docCatalog = sk_make_sp<SkPDFDict>("Catalog");
181
182 sk_sp<SkPDFObject> infoDict(metadata.createDocumentInformationDict());
183
184 sk_sp<SkPDFObject> id, xmp;
185 #ifdef SK_PDF_GENERATE_PDFA
186 SkPDFMetadata::UUID uuid = metadata.uuid();
187 // We use the same UUID for Document ID and Instance ID since this
188 // is the first revision of this document (and Skia does not
189 // support revising existing PDF documents).
190 // If we are not in PDF/A mode, don't use a UUID since testing
191 // works best with reproducible outputs.
192 id.reset(SkPDFMetadata::CreatePdfId(uuid, uuid));
193 xmp.reset(metadata.createXMPObject(uuid, uuid));
194 docCatalog->insertObjRef("Metadata", std::move(xmp));
195
196 // sRGB is specified by HTML, CSS, and SVG.
197 auto outputIntent = sk_make_sp<SkPDFDict>("OutputIntent");
198 outputIntent->insertName("S", "GTS_PDFA1");
199 outputIntent->insertString("RegistryName", "http://www.color.org");
200 outputIntent->insertString("OutputConditionIdentifier",
201 "sRGB IEC61966-2.1");
202 auto intentArray = sk_make_sp<SkPDFArray>();
203 intentArray->appendObject(std::move(outputIntent));
204 // Don't specify OutputIntents if we are not in PDF/A mode since
205 // no one has ever asked for this feature.
206 docCatalog->insertObject("OutputIntents", std::move(intentArray));
207 #endif
208
209 SkTDArray<SkPDFDict*> pageTree;
210 docCatalog->insertObjRef("Pages", generate_page_tree(pages, &pageTree));
211
212 if (dests->size() > 0) {
213 docCatalog->insertObjRef("Dests", std::move(dests));
214 }
215
216 // Build font subsetting info before proceeding.
217 SkPDFSubstituteMap substitutes;
218 perform_font_subsetting(pageDevices, &substitutes);
219
220 SkPDFObjNumMap objNumMap;
221 objNumMap.addObjectRecursively(infoDict.get(), substitutes);
222 objNumMap.addObjectRecursively(docCatalog.get(), substitutes);
223 size_t baseOffset = stream->bytesWritten();
224 emit_pdf_header(stream);
225 SkTDArray<int32_t> offsets;
226 for (int i = 0; i < objNumMap.objects().count(); ++i) {
227 SkPDFObject* object = objNumMap.objects()[i].get();
228 size_t offset = stream->bytesWritten();
229 // This assert checks that size(pdf_header) > 0 and that
230 // the output stream correctly reports bytesWritten().
231 SkASSERT(offset > baseOffset);
232 offsets.push(SkToS32(offset - baseOffset));
233 SkASSERT(object == substitutes.getSubstitute(object));
234 SkASSERT(objNumMap.getObjectNumber(object) == i + 1);
235 stream->writeDecAsText(i + 1);
236 stream->writeText(" 0 obj\n"); // Generation number is always 0.
237 object->emitObject(stream, objNumMap, substitutes);
238 stream->writeText("\nendobj\n");
239 object->dump();
240 }
241 int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset);
242
243 // Include the zeroth object in the count.
244 int32_t objCount = SkToS32(offsets.count() + 1);
245
246 stream->writeText("xref\n0 ");
247 stream->writeDecAsText(objCount);
248 stream->writeText("\n0000000000 65535 f \n");
249 for (int i = 0; i < offsets.count(); i++) {
250 SkASSERT(offsets[i] > 0);
251 stream->writeBigDecAsText(offsets[i], 10);
252 stream->writeText(" 00000 n \n");
253 }
254 emit_pdf_footer(stream, objNumMap, substitutes, docCatalog.get(), objCount,
255 xRefFileOffset, std::move(infoDict), std::move(id));
256
257 // The page tree has both child and parent pointers, so it creates a
258 // reference cycle. We must clear that cycle to properly reclaim memory.
259 for (int i = 0; i < pageTree.count(); i++) {
260 pageTree[i]->dump();
261 }
262 pageTree.safeUnrefAll();
263 pages.unrefAll();
264 return true;
265 }
266
267 #if 0 204 #if 0
268 // TODO(halcanary): expose notEmbeddableCount in SkDocument 205 // TODO(halcanary): expose notEmbeddableCount in SkDocument
269 void GetCountOfFontTypes( 206 void GetCountOfFontTypes(
270 const SkTDArray<SkPDFDevice*>& pageDevices, 207 const SkTDArray<SkPDFDevice*>& pageDevices,
271 int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1], 208 int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1],
272 int* notSubsettableCount, 209 int* notSubsettableCount,
273 int* notEmbeddableCount) { 210 int* notEmbeddableCount) {
274 sk_bzero(counts, sizeof(int) * 211 sk_bzero(counts, sizeof(int) *
275 (SkAdvancedTypefaceMetrics::kOther_Font + 1)); 212 (SkAdvancedTypefaceMetrics::kOther_Font + 1));
276 SkTDArray<SkFontID> seenFonts; 213 SkTDArray<SkFontID> seenFonts;
(...skipping 23 matching lines...) Expand all
300 } 237 }
301 if (notEmbeddableCount) { 238 if (notEmbeddableCount) {
302 *notEmbeddableCount = notEmbeddable; 239 *notEmbeddableCount = notEmbeddable;
303 } 240 }
304 } 241 }
305 #endif 242 #endif
306 243
307 template <typename T> static T* clone(const T* o) { return o ? new T(*o) : nullp tr; } 244 template <typename T> static T* clone(const T* o) { return o ? new T(*o) : nullp tr; }
308 //////////////////////////////////////////////////////////////////////////////// 245 ////////////////////////////////////////////////////////////////////////////////
309 246
310 namespace { 247 SkPDFDocument::SkPDFDocument(SkWStream* stream,
311 class SkPDFDocument : public SkDocument { 248 void (*doneProc)(SkWStream*, bool),
312 public: 249 SkScalar rasterDpi,
313 SkPDFDocument(SkWStream* stream, 250 SkPixelSerializer* jpegEncoder)
314 void (*doneProc)(SkWStream*, bool), 251 : SkDocument(stream, doneProc)
315 SkScalar rasterDpi, 252 , fRasterDpi(rasterDpi) {
316 SkPixelSerializer* jpegEncoder) 253 fCanon.setPixelSerializer(SkSafeRef(jpegEncoder));
317 : SkDocument(stream, doneProc) 254 }
318 , fRasterDpi(rasterDpi) { 255
319 fCanon.setPixelSerializer(SkSafeRef(jpegEncoder)); 256 SkPDFDocument::~SkPDFDocument() {
257 // subclasses must call close() in their destructors
tomhudson 2016/03/21 15:55:11 subclasses of SkDocument, or subclasses of SkPDFDo
hal.canary 2016/03/21 18:49:18 // subclasses of SkDocument
258 this->close();
259 }
260
261 void SkPDFDocument::serialize(const sk_sp<SkPDFObject>& object) {
tomhudson 2016/03/21 15:55:11 Name reads like it's going to serialize a single o
hal.canary 2016/03/21 18:49:18 new comments: /** Serialize the object
262 fObjectSerializer.addObjectRecursively(object);
263 fObjectSerializer.serializeObjects(this->getStream());
264 }
265
266 SkCanvas* SkPDFDocument::onBeginPage(SkScalar width, SkScalar height,
267 const SkRect& trimBox) {
268 SkASSERT(!fCanvas.get()); // end page was called.
tomhudson 2016/03/21 15:55:12 Nit: This comment unclear. Reading through the cod
hal.canary 2016/03/21 18:49:18 Done.
269 if (fPageDevices.empty()) { // if first page
270 fObjectSerializer.serializeHeader(this->getStream(), fMetadata);
271 }
272 SkISize pageSize = SkISize::Make(
273 SkScalarRoundToInt(width), SkScalarRoundToInt(height));
274 sk_sp<SkPDFDevice> device(
275 SkPDFDevice::Create(pageSize, fRasterDpi, &fCanon));
276 fCanvas.reset(new SkCanvas(device.get()));
277 fPageDevices.push_back(std::move(device));
278 fCanvas->clipRect(trimBox);
279 fCanvas->translate(trimBox.x(), trimBox.y());
280 return fCanvas.get();
281 }
282
283 void SkPDFDocument::onEndPage() {
284 SkASSERT(fCanvas.get());
285 fCanvas->flush();
286 fCanvas.reset(nullptr);
287 }
288
289 void SkPDFDocument::onAbort() {
290 fPageDevices.reset();
291 fCanon.reset();
292 renew(&fObjectSerializer);
tomhudson 2016/03/21 15:55:11 Should we be resetting fCanvas?
hal.canary 2016/03/21 18:49:18 Done.
293 }
294
295 void SkPDFDocument::setMetadata(const SkDocument::Attribute info[],
296 int infoCount,
297 const SkTime::DateTime* creationDate,
298 const SkTime::DateTime* modifiedDate) {
299 fMetadata.fInfo.reset(info, infoCount);
300 fMetadata.fCreation.reset(clone(creationDate));
301 fMetadata.fModified.reset(clone(modifiedDate));
302 }
303
304 bool SkPDFDocument::onClose(SkWStream* stream) {
305 SkASSERT(!fCanvas.get());
306 if (fPageDevices.empty()) {
307 fPageDevices.reset();
308 fCanon.reset();
309 renew(&fObjectSerializer);
310 return false;
311 }
312 SkTDArray<SkPDFDict*> pages; // TODO: SkTArray<sk_sp<SkPDFDict>>
313 auto dests = sk_make_sp<SkPDFDict>();
314
315 for (const sk_sp<const SkPDFDevice>& pageDevice : fPageDevices) {
316 SkASSERT(pageDevice);
317 SkASSERT(fPageDevices[0]->getCanon() == pageDevice->getCanon());
318 sk_sp<SkPDFDict> page(create_pdf_page(pageDevice.get()));
319 pageDevice->appendDestinations(dests.get(), page.get());
320 pages.push(page.release());
320 } 321 }
321 322
322 virtual ~SkPDFDocument() { 323 auto docCatalog = sk_make_sp<SkPDFDict>("Catalog");
323 // subclasses must call close() in their destructors 324
324 this->close(); 325 sk_sp<SkPDFObject> id, xmp;
326 #ifdef SK_PDF_GENERATE_PDFA
327 SkPDFMetadata::UUID uuid = metadata.uuid();
328 // We use the same UUID for Document ID and Instance ID since this
329 // is the first revision of this document (and Skia does not
330 // support revising existing PDF documents).
331 // If we are not in PDF/A mode, don't use a UUID since testing
332 // works best with reproducible outputs.
333 id.reset(SkPDFMetadata::CreatePdfId(uuid, uuid));
334 xmp.reset(metadata.createXMPObject(uuid, uuid));
335 docCatalog->insertObjRef("Metadata", std::move(xmp));
336
337 // sRGB is specified by HTML, CSS, and SVG.
338 auto outputIntent = sk_make_sp<SkPDFDict>("OutputIntent");
339 outputIntent->insertName("S", "GTS_PDFA1");
340 outputIntent->insertString("RegistryName", "http://www.color.org");
341 outputIntent->insertString("OutputConditionIdentifier",
342 "sRGB IEC61966-2.1");
343 auto intentArray = sk_make_sp<SkPDFArray>();
344 intentArray->appendObject(std::move(outputIntent));
345 // Don't specify OutputIntents if we are not in PDF/A mode since
346 // no one has ever asked for this feature.
347 docCatalog->insertObject("OutputIntents", std::move(intentArray));
348 #endif
349
350 SkTDArray<SkPDFDict*> pageTree;
351 docCatalog->insertObjRef("Pages", generate_page_tree(pages, &pageTree));
352
353 if (dests->size() > 0) {
354 docCatalog->insertObjRef("Dests", std::move(dests));
325 } 355 }
326 356
327 protected: 357 // Build font subsetting info before proceeding.
tomhudson 2016/03/21 15:55:12 Nit: unnecessary comment?
hal.canary 2016/03/21 18:49:18 // Build font subsetting info before calling addOb
328 SkCanvas* onBeginPage(SkScalar width, SkScalar height, 358 perform_font_subsetting(fPageDevices, &fObjectSerializer.fSubstituteMap);
329 const SkRect& trimBox) override {
330 SkASSERT(!fCanvas.get());
331 359
332 SkISize pageSize = SkISize::Make( 360 fObjectSerializer.addObjectRecursively(docCatalog);
333 SkScalarRoundToInt(width), SkScalarRoundToInt(height)); 361 fObjectSerializer.serializeObjects(this->getStream());
334 sk_sp<SkPDFDevice> device( 362 fObjectSerializer.serializeFooter(this->getStream(), docCatalog, std::move(i d));
335 SkPDFDevice::Create(pageSize, fRasterDpi, &fCanon)); 363 // // The page tree has both child and parent pointers, so it creates a
336 fCanvas.reset(new SkCanvas(device.get())); 364 // // reference cycle. We must clear that cycle to properly reclaim memory.
337 fPageDevices.push_back(std::move(device)); 365 // for (int i = 0; i < pageTree.count(); i++) {
338 fCanvas->clipRect(trimBox); 366 // pageTree[i]->dump();
339 fCanvas->translate(trimBox.x(), trimBox.y()); 367 // }
tomhudson 2016/03/21 15:55:11 Nit: Delete before committing?
hal.canary 2016/03/21 18:49:18 Done.
340 return fCanvas.get(); 368 pageTree.unrefAll(); // TODO: necesary?
341 } 369 pages.unrefAll();
370 fPageDevices.reset();
371 fCanon.reset();
372 renew(&fObjectSerializer);
373 return true;
374 }
342 375
343 void onEndPage() override {
344 SkASSERT(fCanvas.get());
345 fCanvas->flush();
346 fCanvas.reset(nullptr);
347 }
348
349 bool onClose(SkWStream* stream) override {
350 SkASSERT(!fCanvas.get());
351
352 bool success = emit_pdf_document(fPageDevices, fMetadata, stream);
353 fPageDevices.reset();
354 fCanon.reset();
355 return success;
356 }
357
358 void onAbort() override {
359 fPageDevices.reset();
360 fCanon.reset();
361 }
362
363 void setMetadata(const SkDocument::Attribute info[],
364 int infoCount,
365 const SkTime::DateTime* creationDate,
366 const SkTime::DateTime* modifiedDate) override {
367 fMetadata.fInfo.reset(info, infoCount);
368 fMetadata.fCreation.reset(clone(creationDate));
369 fMetadata.fModified.reset(clone(modifiedDate));
370 }
371
372 private:
373 SkPDFCanon fCanon;
374 SkTArray<sk_sp<const SkPDFDevice>> fPageDevices;
375 sk_sp<SkCanvas> fCanvas;
376 SkScalar fRasterDpi;
377 SkPDFMetadata fMetadata;
378 };
379 } // namespace
380 /////////////////////////////////////////////////////////////////////////////// 376 ///////////////////////////////////////////////////////////////////////////////
381 377
382 sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream, 378 sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream,
383 void (*proc)(SkWStream*, bool), 379 void (*proc)(SkWStream*, bool),
384 SkScalar dpi, 380 SkScalar dpi,
385 SkPixelSerializer* jpeg) { 381 SkPixelSerializer* jpeg) {
386 return stream ? sk_make_sp<SkPDFDocument>(stream, proc, dpi, jpeg) : nullptr ; 382 return stream ? sk_make_sp<SkPDFDocument>(stream, proc, dpi, jpeg) : nullptr ;
387 } 383 }
388 384
389 SkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) { 385 SkDocument* SkDocument::CreatePDF(SkWStream* stream, SkScalar dpi) {
390 return SkPDFMakeDocument(stream, nullptr, dpi, nullptr).release(); 386 return SkPDFMakeDocument(stream, nullptr, dpi, nullptr).release();
391 } 387 }
392 388
393 SkDocument* SkDocument::CreatePDF(SkWStream* stream, 389 SkDocument* SkDocument::CreatePDF(SkWStream* stream,
394 SkScalar dpi, 390 SkScalar dpi,
395 SkPixelSerializer* jpegEncoder) { 391 SkPixelSerializer* jpegEncoder) {
396 return SkPDFMakeDocument(stream, nullptr, dpi, jpegEncoder).release(); 392 return SkPDFMakeDocument(stream, nullptr, dpi, jpegEncoder).release();
397 } 393 }
398 394
399 SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) { 395 SkDocument* SkDocument::CreatePDF(const char path[], SkScalar dpi) {
400 auto delete_wstream = [](SkWStream* stream, bool) { delete stream; }; 396 auto delete_wstream = [](SkWStream* stream, bool) { delete stream; };
401 SkAutoTDelete<SkFILEWStream> stream(new SkFILEWStream(path)); 397 SkAutoTDelete<SkFILEWStream> stream(new SkFILEWStream(path));
402 return stream->isValid() 398 return stream->isValid()
403 ? SkPDFMakeDocument(stream.detach(), delete_wstream, dpi, nullptr).relea se() 399 ? SkPDFMakeDocument(stream.detach(), delete_wstream, dpi, nullptr).relea se()
404 : nullptr; 400 : nullptr;
405 } 401 }
OLDNEW
« src/pdf/SkPDFDocument.h ('K') | « src/pdf/SkPDFDocument.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698