michael@0: michael@0: /* michael@0: * Copyright 2010 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkData.h" michael@0: #include "SkFlate.h" michael@0: #include "SkPDFCatalog.h" michael@0: #include "SkPDFStream.h" michael@0: #include "SkStream.h" michael@0: michael@0: static bool skip_compression(SkPDFCatalog* catalog) { michael@0: return SkToBool(catalog->getDocumentFlags() & michael@0: SkPDFDocument::kFavorSpeedOverSize_Flags); michael@0: } michael@0: michael@0: SkPDFStream::SkPDFStream(SkStream* stream) : fState(kUnused_State) { michael@0: setData(stream); michael@0: } michael@0: michael@0: SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) { michael@0: setData(data); michael@0: } michael@0: michael@0: SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream) michael@0: : SkPDFDict(), michael@0: fState(kUnused_State) { michael@0: setData(pdfStream.fData.get()); michael@0: bool removeLength = true; michael@0: // Don't uncompress an already compressed stream, but we could. michael@0: if (pdfStream.fState == kCompressed_State) { michael@0: fState = kCompressed_State; michael@0: removeLength = false; michael@0: } michael@0: SkPDFDict::Iter dict(pdfStream); michael@0: SkPDFName* key; michael@0: SkPDFObject* value; michael@0: SkPDFName lengthName("Length"); michael@0: for (key = dict.next(&value); key != NULL; key = dict.next(&value)) { michael@0: if (removeLength && *key == lengthName) { michael@0: continue; michael@0: } michael@0: this->insert(key, value); michael@0: } michael@0: } michael@0: michael@0: SkPDFStream::~SkPDFStream() {} michael@0: michael@0: void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog, michael@0: bool indirect) { michael@0: if (indirect) { michael@0: return emitIndirectObject(stream, catalog); michael@0: } michael@0: if (!this->populate(catalog)) { michael@0: return fSubstitute->emitObject(stream, catalog, indirect); michael@0: } michael@0: michael@0: this->INHERITED::emitObject(stream, catalog, false); michael@0: stream->writeText(" stream\n"); michael@0: stream->writeStream(fData.get(), fData->getLength()); michael@0: fData->rewind(); michael@0: stream->writeText("\nendstream"); michael@0: } michael@0: michael@0: size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) { michael@0: if (indirect) { michael@0: return getIndirectOutputSize(catalog); michael@0: } michael@0: if (!this->populate(catalog)) { michael@0: return fSubstitute->getOutputSize(catalog, indirect); michael@0: } michael@0: michael@0: return this->INHERITED::getOutputSize(catalog, false) + michael@0: strlen(" stream\n\nendstream") + fData->getLength(); michael@0: } michael@0: michael@0: SkPDFStream::SkPDFStream() : fState(kUnused_State) {} michael@0: michael@0: void SkPDFStream::setData(SkData* data) { michael@0: SkMemoryStream* stream = new SkMemoryStream; michael@0: stream->setData(data); michael@0: fData.reset(stream); // Transfer ownership. michael@0: } michael@0: michael@0: void SkPDFStream::setData(SkStream* stream) { michael@0: // Code assumes that the stream starts at the beginning and is rewindable. michael@0: if (stream) { michael@0: SkASSERT(stream->getPosition() == 0); michael@0: SkASSERT(stream->rewind()); michael@0: } michael@0: fData.reset(stream); michael@0: SkSafeRef(stream); michael@0: } michael@0: michael@0: bool SkPDFStream::populate(SkPDFCatalog* catalog) { michael@0: if (fState == kUnused_State) { michael@0: if (!skip_compression(catalog) && SkFlate::HaveFlate()) { michael@0: SkDynamicMemoryWStream compressedData; michael@0: michael@0: SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData)); michael@0: if (compressedData.getOffset() < fData->getLength()) { michael@0: SkMemoryStream* stream = new SkMemoryStream; michael@0: stream->setData(compressedData.copyToData())->unref(); michael@0: fData.reset(stream); // Transfer ownership. michael@0: insertName("Filter", "FlateDecode"); michael@0: } michael@0: fState = kCompressed_State; michael@0: } else { michael@0: fState = kNoCompression_State; michael@0: } michael@0: insertInt("Length", fData->getLength()); michael@0: } else if (fState == kNoCompression_State && !skip_compression(catalog) && michael@0: SkFlate::HaveFlate()) { michael@0: if (!fSubstitute.get()) { michael@0: fSubstitute.reset(new SkPDFStream(*this)); michael@0: catalog->setSubstitute(this, fSubstitute.get()); michael@0: } michael@0: return false; michael@0: } michael@0: return true; michael@0: }