| 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 |