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::kNoCompression_Flags); 19 } 20 21 SkPDFStream::SkPDFStream(SkStream* stream) 22 : fState(kUnused_State), 23 fData(stream) { 24 SkSafeRef(stream); 25 } 26 27 SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) { 28 SkMemoryStream* stream = new SkMemoryStream; 29 stream->setData(data); 30 fData.reset(stream); // Transfer ownership. 31 } 32 33 SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream) 34 : SkPDFDict(), 35 fState(kUnused_State), 36 fData(pdfStream.fData.get()) { 37 fData.get()->ref(); 38 bool removeLength = true; 39 // Don't uncompress an already compressed stream, but we could. 40 if (pdfStream.fState == kCompressed_State) { 41 fState = kCompressed_State; 42 removeLength = false; 43 } 44 SkPDFDict::Iter dict(pdfStream); 45 SkPDFName* key; 46 SkPDFObject* value; 47 SkPDFName lengthName("Length"); 48 for (key = dict.next(&value); key != NULL; key = dict.next(&value)) { 49 if (removeLength && *key == lengthName) { 50 continue; 51 } 52 this->insert(key, value); 53 } 54 } 55 56 SkPDFStream::~SkPDFStream() {} 57 58 void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 59 bool indirect) { 60 if (indirect) { 61 return emitIndirectObject(stream, catalog); 62 } 63 if (!this->populate(catalog)) { 64 return fSubstitute->emitObject(stream, catalog, indirect); 65 } 66 67 this->INHERITED::emitObject(stream, catalog, false); 68 stream->writeText(" stream\n"); 69 stream->write(fData->getMemoryBase(), fData->getLength()); 70 stream->writeText("\nendstream"); 71 } 72 73 size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 74 if (indirect) { 75 return getIndirectOutputSize(catalog); 76 } 77 if (!this->populate(catalog)) { 78 return fSubstitute->getOutputSize(catalog, indirect); 79 } 80 81 return this->INHERITED::getOutputSize(catalog, false) + 82 strlen(" stream\n\nendstream") + fData->getLength(); 83 } 84 85 SkPDFStream::SkPDFStream() : fState(kUnused_State) {} 86 87 void SkPDFStream::setData(SkStream* stream) { 88 fData.reset(stream); 89 SkSafeRef(stream); 90 } 91 92 bool SkPDFStream::populate(SkPDFCatalog* catalog) { 93 if (fState == kUnused_State) { 94 if (!skip_compression(catalog) && SkFlate::HaveFlate()) { 95 SkDynamicMemoryWStream compressedData; 96 97 SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData)); 98 if (compressedData.getOffset() < fData->getLength()) { 99 SkMemoryStream* stream = new SkMemoryStream; 100 stream->setData(compressedData.copyToData())->unref(); 101 fData.reset(stream); // Transfer ownership. 102 insertName("Filter", "FlateDecode"); 103 } 104 fState = kCompressed_State; 105 } else { 106 fState = kNoCompression_State; 107 } 108 insertInt("Length", fData->getLength()); 109 } else if (fState == kNoCompression_State && !skip_compression(catalog) && 110 SkFlate::HaveFlate()) { 111 if (!fSubstitute.get()) { 112 fSubstitute.reset(new SkPDFStream(*this)); 113 catalog->setSubstitute(this, fSubstitute.get()); 114 } 115 return false; 116 } 117 return true; 118 } 119