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 16static bool skip_compression(SkPDFCatalog* catalog) { 17 return SkToBool(catalog->getDocumentFlags() & 18 SkPDFDocument::kFavorSpeedOverSize_Flags); 19} 20 21SkPDFStream::SkPDFStream(SkStream* stream) : fState(kUnused_State) { 22 setData(stream); 23} 24 25SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) { 26 setData(data); 27} 28 29SkPDFStream::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 51SkPDFStream::~SkPDFStream() {} 52 53void 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 69size_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 81SkPDFStream::SkPDFStream() : fState(kUnused_State) {} 82 83void SkPDFStream::setData(SkData* data) { 84 SkMemoryStream* stream = new SkMemoryStream; 85 stream->setData(data); 86 fData.reset(stream); // Transfer ownership. 87} 88 89void 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 99bool 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