OLD | NEW |
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 "SkPDFCanvas.h" | 9 #include "SkPDFCanvas.h" |
10 #include "SkPDFDevice.h" | 10 #include "SkPDFDevice.h" |
11 #include "SkPDFDocument.h" | 11 #include "SkPDFDocument.h" |
12 #include "SkPDFUtils.h" | 12 #include "SkPDFUtils.h" |
13 #include "SkStream.h" | 13 #include "SkStream.h" |
14 | 14 |
15 SkPDFObjectSerializer::SkPDFObjectSerializer() : fBaseOffset(0), fNextToBeSerial
ized(0) {} | 15 SkPDFObjectSerializer::SkPDFObjectSerializer() : fBaseOffset(0), fNextToBeSerial
ized(0) {} |
16 | 16 |
17 template <class T> static void renew(T* t) { t->~T(); new (t) T; } | 17 template <class T> static void renew(T* t) { t->~T(); new (t) T; } |
18 | 18 |
19 SkPDFObjectSerializer::~SkPDFObjectSerializer() { | 19 SkPDFObjectSerializer::~SkPDFObjectSerializer() { |
20 for (int i = 0; i < fObjNumMap.objects().count(); ++i) { | 20 for (int i = 0; i < fObjNumMap.objects().count(); ++i) { |
21 fObjNumMap.objects()[i]->drop(); | 21 fObjNumMap.objects()[i]->drop(); |
22 } | 22 } |
23 } | 23 } |
24 | 24 |
25 void SkPDFObjectSerializer::addObjectRecursively(const sk_sp<SkPDFObject>& objec
t) { | 25 void SkPDFObjectSerializer::addObjectRecursively(const sk_sp<SkPDFObject>& objec
t) { |
26 fObjNumMap.addObjectRecursively(object.get(), fSubstituteMap); | 26 fObjNumMap.addObjectRecursively(object.get()); |
27 } | 27 } |
28 | 28 |
29 #define SKPDF_MAGIC "\xD3\xEB\xE9\xE1" | 29 #define SKPDF_MAGIC "\xD3\xEB\xE9\xE1" |
30 #ifndef SK_BUILD_FOR_WIN32 | 30 #ifndef SK_BUILD_FOR_WIN32 |
31 static_assert((SKPDF_MAGIC[0] & 0x7F) == "Skia"[0], ""); | 31 static_assert((SKPDF_MAGIC[0] & 0x7F) == "Skia"[0], ""); |
32 static_assert((SKPDF_MAGIC[1] & 0x7F) == "Skia"[1], ""); | 32 static_assert((SKPDF_MAGIC[1] & 0x7F) == "Skia"[1], ""); |
33 static_assert((SKPDF_MAGIC[2] & 0x7F) == "Skia"[2], ""); | 33 static_assert((SKPDF_MAGIC[2] & 0x7F) == "Skia"[2], ""); |
34 static_assert((SKPDF_MAGIC[3] & 0x7F) == "Skia"[3], ""); | 34 static_assert((SKPDF_MAGIC[3] & 0x7F) == "Skia"[3], ""); |
35 #endif | 35 #endif |
36 void SkPDFObjectSerializer::serializeHeader(SkWStream* wStream, | 36 void SkPDFObjectSerializer::serializeHeader(SkWStream* wStream, |
(...skipping 14 matching lines...) Expand all Loading... |
51 void SkPDFObjectSerializer::serializeObjects(SkWStream* wStream) { | 51 void SkPDFObjectSerializer::serializeObjects(SkWStream* wStream) { |
52 const SkTArray<sk_sp<SkPDFObject>>& objects = fObjNumMap.objects(); | 52 const SkTArray<sk_sp<SkPDFObject>>& objects = fObjNumMap.objects(); |
53 while (fNextToBeSerialized < objects.count()) { | 53 while (fNextToBeSerialized < objects.count()) { |
54 SkPDFObject* object = objects[fNextToBeSerialized].get(); | 54 SkPDFObject* object = objects[fNextToBeSerialized].get(); |
55 int32_t index = fNextToBeSerialized + 1; // Skip object 0. | 55 int32_t index = fNextToBeSerialized + 1; // Skip object 0. |
56 // "The first entry in the [XREF] table (object number 0) is | 56 // "The first entry in the [XREF] table (object number 0) is |
57 // always free and has a generation number of 65,535; it is | 57 // always free and has a generation number of 65,535; it is |
58 // the head of the linked list of free objects." | 58 // the head of the linked list of free objects." |
59 SkASSERT(fOffsets.count() == fNextToBeSerialized); | 59 SkASSERT(fOffsets.count() == fNextToBeSerialized); |
60 fOffsets.push(this->offset(wStream)); | 60 fOffsets.push(this->offset(wStream)); |
61 SkASSERT(object == fSubstituteMap.getSubstitute(object)); | |
62 wStream->writeDecAsText(index); | 61 wStream->writeDecAsText(index); |
63 wStream->writeText(" 0 obj\n"); // Generation number is always 0. | 62 wStream->writeText(" 0 obj\n"); // Generation number is always 0. |
64 object->emitObject(wStream, fObjNumMap, fSubstituteMap); | 63 object->emitObject(wStream, fObjNumMap); |
65 wStream->writeText("\nendobj\n"); | 64 wStream->writeText("\nendobj\n"); |
66 object->drop(); | 65 object->drop(); |
67 ++fNextToBeSerialized; | 66 ++fNextToBeSerialized; |
68 } | 67 } |
69 } | 68 } |
70 | 69 |
71 // Xref table and footer | 70 // Xref table and footer |
72 void SkPDFObjectSerializer::serializeFooter(SkWStream* wStream, | 71 void SkPDFObjectSerializer::serializeFooter(SkWStream* wStream, |
73 const sk_sp<SkPDFObject> docCatalog, | 72 const sk_sp<SkPDFObject> docCatalog, |
74 sk_sp<SkPDFObject> id) { | 73 sk_sp<SkPDFObject> id) { |
(...skipping 11 matching lines...) Expand all Loading... |
86 SkPDFDict trailerDict; | 85 SkPDFDict trailerDict; |
87 trailerDict.insertInt("Size", objCount); | 86 trailerDict.insertInt("Size", objCount); |
88 SkASSERT(docCatalog); | 87 SkASSERT(docCatalog); |
89 trailerDict.insertObjRef("Root", docCatalog); | 88 trailerDict.insertObjRef("Root", docCatalog); |
90 SkASSERT(fInfoDict); | 89 SkASSERT(fInfoDict); |
91 trailerDict.insertObjRef("Info", std::move(fInfoDict)); | 90 trailerDict.insertObjRef("Info", std::move(fInfoDict)); |
92 if (id) { | 91 if (id) { |
93 trailerDict.insertObject("ID", std::move(id)); | 92 trailerDict.insertObject("ID", std::move(id)); |
94 } | 93 } |
95 wStream->writeText("trailer\n"); | 94 wStream->writeText("trailer\n"); |
96 trailerDict.emitObject(wStream, fObjNumMap, fSubstituteMap); | 95 trailerDict.emitObject(wStream, fObjNumMap); |
97 wStream->writeText("\nstartxref\n"); | 96 wStream->writeText("\nstartxref\n"); |
98 wStream->writeBigDecAsText(xRefFileOffset); | 97 wStream->writeBigDecAsText(xRefFileOffset); |
99 wStream->writeText("\n%%EOF"); | 98 wStream->writeText("\n%%EOF"); |
100 } | 99 } |
101 | 100 |
102 int32_t SkPDFObjectSerializer::offset(SkWStream* wStream) { | 101 int32_t SkPDFObjectSerializer::offset(SkWStream* wStream) { |
103 size_t offset = wStream->bytesWritten(); | 102 size_t offset = wStream->bytesWritten(); |
104 SkASSERT(offset > fBaseOffset); | 103 SkASSERT(offset > fBaseOffset); |
105 return SkToS32(offset - fBaseOffset); | 104 return SkToS32(offset - fBaseOffset); |
106 } | 105 } |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 } | 238 } |
240 auto contentObject = sk_make_sp<SkPDFStream>(fPageDevice->content()); | 239 auto contentObject = sk_make_sp<SkPDFStream>(fPageDevice->content()); |
241 this->serialize(contentObject); | 240 this->serialize(contentObject); |
242 page->insertObjRef("Contents", std::move(contentObject)); | 241 page->insertObjRef("Contents", std::move(contentObject)); |
243 fPageDevice->appendDestinations(fDests.get(), page.get()); | 242 fPageDevice->appendDestinations(fDests.get(), page.get()); |
244 fPages.emplace_back(std::move(page)); | 243 fPages.emplace_back(std::move(page)); |
245 fPageDevice.reset(nullptr); | 244 fPageDevice.reset(nullptr); |
246 } | 245 } |
247 | 246 |
248 void SkPDFDocument::onAbort() { | 247 void SkPDFDocument::onAbort() { |
| 248 this->reset(); |
| 249 } |
| 250 |
| 251 void SkPDFDocument::reset() { |
249 fCanvas.reset(nullptr); | 252 fCanvas.reset(nullptr); |
250 fPages.reset(); | 253 fPages.reset(); |
251 fCanon.reset(); | 254 fCanon.reset(); |
252 renew(&fObjectSerializer); | 255 renew(&fObjectSerializer); |
253 renew(&fGlyphUsage); | 256 fFonts.reset(); |
254 } | 257 } |
255 | 258 |
256 #ifdef SK_SUPPORT_LEGACY_DOCUMENT_API | 259 #ifdef SK_SUPPORT_LEGACY_DOCUMENT_API |
257 void SkPDFDocument::setMetadata(const SkDocument::Attribute info[], | 260 void SkPDFDocument::setMetadata(const SkDocument::Attribute info[], |
258 int infoCount, | 261 int infoCount, |
259 const SkTime::DateTime* creationDate, | 262 const SkTime::DateTime* creationDate, |
260 const SkTime::DateTime* modifiedDate) { | 263 const SkTime::DateTime* modifiedDate) { |
261 for (int i = 0; i < infoCount; ++i) { | 264 for (int i = 0; i < infoCount; ++i) { |
262 const SkDocument::Attribute& kv = info[i]; | 265 const SkDocument::Attribute& kv = info[i]; |
263 SkPDFMetadata::SetMetadataByKey(kv.fKey, kv.fValue, &fMetadata); | 266 SkPDFMetadata::SetMetadataByKey(kv.fKey, kv.fValue, &fMetadata); |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 outputIntent->insertObjRef("DestOutputProfile", | 415 outputIntent->insertObjRef("DestOutputProfile", |
413 make_srgb_color_profile()); | 416 make_srgb_color_profile()); |
414 auto intentArray = sk_make_sp<SkPDFArray>(); | 417 auto intentArray = sk_make_sp<SkPDFArray>(); |
415 intentArray->appendObject(std::move(outputIntent)); | 418 intentArray->appendObject(std::move(outputIntent)); |
416 return intentArray; | 419 return intentArray; |
417 } | 420 } |
418 | 421 |
419 bool SkPDFDocument::onClose(SkWStream* stream) { | 422 bool SkPDFDocument::onClose(SkWStream* stream) { |
420 SkASSERT(!fCanvas.get()); | 423 SkASSERT(!fCanvas.get()); |
421 if (fPages.empty()) { | 424 if (fPages.empty()) { |
422 fPages.reset(); | 425 this->reset(); |
423 fCanon.reset(); | |
424 renew(&fObjectSerializer); | |
425 renew(&fGlyphUsage); | |
426 return false; | 426 return false; |
427 } | 427 } |
428 auto docCatalog = sk_make_sp<SkPDFDict>("Catalog"); | 428 auto docCatalog = sk_make_sp<SkPDFDict>("Catalog"); |
429 if (fPDFA) { | 429 if (fPDFA) { |
430 SkASSERT(fXMP); | 430 SkASSERT(fXMP); |
431 docCatalog->insertObjRef("Metadata", fXMP); | 431 docCatalog->insertObjRef("Metadata", fXMP); |
432 // Don't specify OutputIntents if we are not in PDF/A mode since | 432 // Don't specify OutputIntents if we are not in PDF/A mode since |
433 // no one has ever asked for this feature. | 433 // no one has ever asked for this feature. |
434 docCatalog->insertObject("OutputIntents", make_srgb_output_intents()); | 434 docCatalog->insertObject("OutputIntents", make_srgb_output_intents()); |
435 } | 435 } |
436 SkASSERT(!fPages.empty()); | 436 SkASSERT(!fPages.empty()); |
437 docCatalog->insertObjRef("Pages", generate_page_tree(&fPages)); | 437 docCatalog->insertObjRef("Pages", generate_page_tree(&fPages)); |
438 SkASSERT(fPages.empty()); | 438 SkASSERT(fPages.empty()); |
439 | 439 |
440 if (fDests->size() > 0) { | 440 if (fDests->size() > 0) { |
441 docCatalog->insertObjRef("Dests", std::move(fDests)); | 441 docCatalog->insertObjRef("Dests", std::move(fDests)); |
442 } | 442 } |
443 | 443 |
444 // Build font subsetting info before calling addObjectRecursively(). | 444 // Build font subsetting info before calling addObjectRecursively(). |
445 for (const auto& entry : fGlyphUsage) { | 445 SkPDFCanon* canon = &fCanon; |
446 sk_sp<SkPDFObject> subsetFont = | 446 fFonts.foreach([canon](SkPDFFont* p){ p->getFontSubset(canon); }); |
447 entry.fFont->getFontSubset(&fCanon, &entry.fGlyphSet); | |
448 if (subsetFont) { | |
449 fObjectSerializer.fSubstituteMap.setSubstitute( | |
450 entry.fFont, subsetFont.get()); | |
451 } | |
452 } | |
453 | |
454 fObjectSerializer.addObjectRecursively(docCatalog); | 447 fObjectSerializer.addObjectRecursively(docCatalog); |
455 fObjectSerializer.serializeObjects(this->getStream()); | 448 fObjectSerializer.serializeObjects(this->getStream()); |
456 fObjectSerializer.serializeFooter(this->getStream(), docCatalog, fID); | 449 fObjectSerializer.serializeFooter(this->getStream(), docCatalog, fID); |
457 fCanon.reset(); | 450 this->reset(); |
458 renew(&fObjectSerializer); | |
459 renew(&fGlyphUsage); | |
460 return true; | 451 return true; |
461 } | 452 } |
462 | 453 |
463 /////////////////////////////////////////////////////////////////////////////// | 454 /////////////////////////////////////////////////////////////////////////////// |
464 | 455 |
465 sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream, | 456 sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream, |
466 void (*proc)(SkWStream*, bool), | 457 void (*proc)(SkWStream*, bool), |
467 SkScalar dpi, | 458 SkScalar dpi, |
468 const SkDocument::PDFMetadata& metadata, | 459 const SkDocument::PDFMetadata& metadata, |
469 sk_sp<SkPixelSerializer> jpeg, | 460 sk_sp<SkPixelSerializer> jpeg, |
(...skipping 14 matching lines...) Expand all Loading... |
484 } | 475 } |
485 | 476 |
486 sk_sp<SkDocument> SkDocument::MakePDF(SkWStream* stream, | 477 sk_sp<SkDocument> SkDocument::MakePDF(SkWStream* stream, |
487 SkScalar dpi, | 478 SkScalar dpi, |
488 const SkDocument::PDFMetadata& metadata, | 479 const SkDocument::PDFMetadata& metadata, |
489 sk_sp<SkPixelSerializer> jpegEncoder, | 480 sk_sp<SkPixelSerializer> jpegEncoder, |
490 bool pdfa) { | 481 bool pdfa) { |
491 return SkPDFMakeDocument(stream, nullptr, dpi, metadata, | 482 return SkPDFMakeDocument(stream, nullptr, dpi, metadata, |
492 std::move(jpegEncoder), pdfa); | 483 std::move(jpegEncoder), pdfa); |
493 } | 484 } |
OLD | NEW |