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