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