blob: 319433f7d049966075d988c691ae81400bb7ab5a [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 Google Inc.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@google.com8a85d0c2011-06-24 19:12:12 +000010#include "SkData.h"
vandebo@chromium.orga09ef972010-12-01 22:17:20 +000011#include "SkFlate.h"
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000012#include "SkPDFCatalog.h"
13#include "SkPDFStream.h"
14#include "SkStream.h"
halcanaryc1dfa142014-06-26 14:00:31 -070015#include "SkStreamHelpers.h" // CopyStreamToData
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000016
vandebo@chromium.org421d6442011-07-20 17:39:01 +000017static bool skip_compression(SkPDFCatalog* catalog) {
vandebo@chromium.org238be8c2012-07-13 20:06:02 +000018 return SkToBool(catalog->getDocumentFlags() &
edisonn@google.com8c020612013-03-12 19:53:16 +000019 SkPDFDocument::kFavorSpeedOverSize_Flags);
vandebo@chromium.org421d6442011-07-20 17:39:01 +000020}
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +000021
vandebo@chromium.org26e14492013-08-26 22:52:09 +000022SkPDFStream::SkPDFStream(SkStream* stream) : fState(kUnused_State) {
halcanaryc1dfa142014-06-26 14:00:31 -070023 this->setData(stream);
vandebo@chromium.org421d6442011-07-20 17:39:01 +000024}
25
26SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
halcanaryc1dfa142014-06-26 14:00:31 -070027 this->setData(data);
vandebo@chromium.org421d6442011-07-20 17:39:01 +000028}
29
30SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
31 : SkPDFDict(),
vandebo@chromium.org26e14492013-08-26 22:52:09 +000032 fState(kUnused_State) {
halcanaryc1dfa142014-06-26 14:00:31 -070033 this->setData(pdfStream.fData.get());
vandebo@chromium.org421d6442011-07-20 17:39:01 +000034 bool removeLength = true;
35 // Don't uncompress an already compressed stream, but we could.
36 if (pdfStream.fState == kCompressed_State) {
37 fState = kCompressed_State;
38 removeLength = false;
vandebo@chromium.orga09ef972010-12-01 22:17:20 +000039 }
vandebo@chromium.org421d6442011-07-20 17:39:01 +000040 SkPDFDict::Iter dict(pdfStream);
41 SkPDFName* key;
42 SkPDFObject* value;
43 SkPDFName lengthName("Length");
44 for (key = dict.next(&value); key != NULL; key = dict.next(&value)) {
45 if (removeLength && *key == lengthName) {
46 continue;
47 }
48 this->insert(key, value);
49 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000050}
51
vandebo@chromium.org421d6442011-07-20 17:39:01 +000052SkPDFStream::~SkPDFStream() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000053
54void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
55 bool indirect) {
vandebo@chromium.org421d6442011-07-20 17:39:01 +000056 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000057 return emitIndirectObject(stream, catalog);
vandebo@chromium.org421d6442011-07-20 17:39:01 +000058 }
halcanaryc1dfa142014-06-26 14:00:31 -070059 SkAutoMutexAcquire lock(fMutex); // multiple threads could be calling emit
vandebo@chromium.org421d6442011-07-20 17:39:01 +000060 if (!this->populate(catalog)) {
61 return fSubstitute->emitObject(stream, catalog, indirect);
62 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000063
vandebo@chromium.orgd90c1412011-02-24 21:50:04 +000064 this->INHERITED::emitObject(stream, catalog, false);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000065 stream->writeText(" stream\n");
halcanaryc1dfa142014-06-26 14:00:31 -070066 if (fData.get()) {
67 stream->write(fData->data(), fData->size());
68 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000069 stream->writeText("\nendstream");
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000070}
71
72size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
vandebo@chromium.org421d6442011-07-20 17:39:01 +000073 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000074 return getIndirectOutputSize(catalog);
vandebo@chromium.org421d6442011-07-20 17:39:01 +000075 }
halcanaryc1dfa142014-06-26 14:00:31 -070076 SkAutoMutexAcquire lock(fMutex); // multiple threads could be calling emit
vandebo@chromium.org421d6442011-07-20 17:39:01 +000077 if (!this->populate(catalog)) {
78 return fSubstitute->getOutputSize(catalog, indirect);
79 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000080
vandebo@chromium.orgd90c1412011-02-24 21:50:04 +000081 return this->INHERITED::getOutputSize(catalog, false) +
halcanaryc1dfa142014-06-26 14:00:31 -070082 strlen(" stream\n\nendstream") + this->dataSize();
vandebo@chromium.org421d6442011-07-20 17:39:01 +000083}
84
85SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
86
commit-bot@chromium.orgd8d976e2013-07-08 23:17:57 +000087void SkPDFStream::setData(SkData* data) {
halcanaryc1dfa142014-06-26 14:00:31 -070088 fData.reset(SkSafeRef(data));
commit-bot@chromium.orgd8d976e2013-07-08 23:17:57 +000089}
90
vandebo@chromium.org421d6442011-07-20 17:39:01 +000091void SkPDFStream::setData(SkStream* stream) {
vandebo@chromium.org26e14492013-08-26 22:52:09 +000092 // Code assumes that the stream starts at the beginning and is rewindable.
93 if (stream) {
94 SkASSERT(stream->getPosition() == 0);
halcanaryc1dfa142014-06-26 14:00:31 -070095 fData.reset(CopyStreamToData(stream));
vandebo@chromium.org26e14492013-08-26 22:52:09 +000096 SkASSERT(stream->rewind());
halcanaryc1dfa142014-06-26 14:00:31 -070097 } else {
98 fData.reset(NULL);
vandebo@chromium.org26e14492013-08-26 22:52:09 +000099 }
halcanaryc1dfa142014-06-26 14:00:31 -0700100}
101
102size_t SkPDFStream::dataSize() const {
103 return fData.get() ? fData->size() : 0;
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000104}
105
106bool SkPDFStream::populate(SkPDFCatalog* catalog) {
107 if (fState == kUnused_State) {
108 if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
109 SkDynamicMemoryWStream compressedData;
110
111 SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData));
halcanaryc1dfa142014-06-26 14:00:31 -0700112 if (compressedData.getOffset() < this->dataSize()) {
113 fData.reset(compressedData.copyToData());
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000114 insertName("Filter", "FlateDecode");
115 }
116 fState = kCompressed_State;
117 } else {
118 fState = kNoCompression_State;
119 }
halcanaryc1dfa142014-06-26 14:00:31 -0700120 insertInt("Length", this->dataSize());
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000121 } else if (fState == kNoCompression_State && !skip_compression(catalog) &&
122 SkFlate::HaveFlate()) {
123 if (!fSubstitute.get()) {
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000124 fSubstitute.reset(new SkPDFStream(*this));
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000125 catalog->setSubstitute(this, fSubstitute.get());
126 }
127 return false;
128 }
129 return true;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000130}