1 2 /* 3 * Copyright 2010 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "SkData.h" 11 #include "SkFlate.h" 12 #include "SkPDFCatalog.h" 13 #include "SkPDFStream.h" 14 #include "SkStream.h" 15 16 static bool skip_compression(SkPDFCatalog* catalog) { 17 return SkToBool(catalog->getDocumentFlags() & 18 SkPDFDocument::kFavorSpeedOverSize_Flags); 19 } 20 21 SkPDFStream::SkPDFStream(SkStream* stream) : fState(kUnused_State) { 22 setData(stream); 23 } 24 25 SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) { 26 setData(data); 27 } 28 29 SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream) 30 : SkPDFDict(), 31 fState(kUnused_State) { 32 setData(pdfStream.fData.get()); 33 bool removeLength = true; 34 // Don't uncompress an already compressed stream, but we could. 35 if (pdfStream.fState == kCompressed_State) { 36 fState = kCompressed_State; 37 removeLength = false; 38 } 39 SkPDFDict::Iter dict(pdfStream); 40 SkPDFName* key; 41 SkPDFObject* value; 42 SkPDFName lengthName("Length"); 43 for (key = dict.next(&value); key != NULL; key = dict.next(&value)) { 44 if (removeLength && *key == lengthName) { 45 continue; 46 } 47 this->insert(key, value); 48 } 49 } 50 51 SkPDFStream::~SkPDFStream() {} 52 53 void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 54 bool indirect) { 55 if (indirect) { 56 return emitIndirectObject(stream, catalog); 57 } 58 if (!this->populate(catalog)) { 59 return fSubstitute->emitObject(stream, catalog, indirect); 60 } 61 62 this->INHERITED::emitObject(stream, catalog, false); 63 stream->writeText(" stream\n"); 64 stream->writeStream(fData.get(), fData->getLength()); 65 fData->rewind(); 66 stream->writeText("\nendstream"); 67 } 68 69 size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 70 if (indirect) { 71 return getIndirectOutputSize(catalog); 72 } 73 if (!this->populate(catalog)) { 74 return fSubstitute->getOutputSize(catalog, indirect); 75 } 76 77 return this->INHERITED::getOutputSize(catalog, false) + 78 strlen(" stream\n\nendstream") + fData->getLength(); 79 } 80 81 SkPDFStream::SkPDFStream() : fState(kUnused_State) {} 82 83 void SkPDFStream::setData(SkData* data) { 84 SkMemoryStream* stream = new SkMemoryStream; 85 stream->setData(data); 86 fData.reset(stream); // Transfer ownership. 87 } 88 89 void SkPDFStream::setData(SkStream* stream) { 90 // Code assumes that the stream starts at the beginning and is rewindable. 91 if (stream) { 92 SkASSERT(stream->getPosition() == 0); 93 SkASSERT(stream->rewind()); 94 } 95 fData.reset(stream); 96 SkSafeRef(stream); 97 } 98 99 bool SkPDFStream::populate(SkPDFCatalog* catalog) { 100 if (fState == kUnused_State) { 101 if (!skip_compression(catalog) && SkFlate::HaveFlate()) { 102 SkDynamicMemoryWStream compressedData; 103 104 SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData)); 105 if (compressedData.getOffset() < fData->getLength()) { 106 SkMemoryStream* stream = new SkMemoryStream; 107 stream->setData(compressedData.copyToData())->unref(); 108 fData.reset(stream); // Transfer ownership. 109 insertName("Filter", "FlateDecode"); 110 } 111 fState = kCompressed_State; 112 } else { 113 fState = kNoCompression_State; 114 } 115 insertInt("Length", fData->getLength()); 116 } else if (fState == kNoCompression_State && !skip_compression(catalog) && 117 SkFlate::HaveFlate()) { 118 if (!fSubstitute.get()) { 119 fSubstitute.reset(new SkPDFStream(*this)); 120 catalog->setSubstitute(this, fSubstitute.get()); 121 } 122 return false; 123 } 124 return true; 125 } 126