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