blob: 49c71560c2d6ae2172231c5553cd53fb213b908c [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"
15
vandebo@chromium.org421d6442011-07-20 17:39:01 +000016static bool skip_compression(SkPDFCatalog* catalog) {
17 return catalog->getDocumentFlags() & SkPDFDocument::kNoCompression_Flag;
18}
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +000019
vandebo@chromium.org421d6442011-07-20 17:39:01 +000020SkPDFStream::SkPDFStream(SkStream* stream)
21 : fState(kUnused_State),
22 fData(stream) {
23}
24
25SkPDFStream::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
32SkPDFStream::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;
vandebo@chromium.orga09ef972010-12-01 22:17:20 +000041 }
vandebo@chromium.org421d6442011-07-20 17:39:01 +000042 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 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000052}
53
vandebo@chromium.org421d6442011-07-20 17:39:01 +000054SkPDFStream::~SkPDFStream() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000055
56void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
57 bool indirect) {
vandebo@chromium.org421d6442011-07-20 17:39:01 +000058 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000059 return emitIndirectObject(stream, catalog);
vandebo@chromium.org421d6442011-07-20 17:39:01 +000060 }
61 if (!this->populate(catalog)) {
62 return fSubstitute->emitObject(stream, catalog, indirect);
63 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000064
vandebo@chromium.orgd90c1412011-02-24 21:50:04 +000065 this->INHERITED::emitObject(stream, catalog, false);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000066 stream->writeText(" stream\n");
vandebo@chromium.org421d6442011-07-20 17:39:01 +000067 stream->write(fData->getMemoryBase(), fData->getLength());
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000068 stream->writeText("\nendstream");
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000069}
70
71size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
vandebo@chromium.org421d6442011-07-20 17:39:01 +000072 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000073 return getIndirectOutputSize(catalog);
vandebo@chromium.org421d6442011-07-20 17:39:01 +000074 }
75 if (!this->populate(catalog)) {
76 return fSubstitute->getOutputSize(catalog, indirect);
77 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000078
vandebo@chromium.orgd90c1412011-02-24 21:50:04 +000079 return this->INHERITED::getOutputSize(catalog, false) +
vandebo@chromium.org421d6442011-07-20 17:39:01 +000080 strlen(" stream\n\nendstream") + fData->getLength();
81}
82
83SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
84
85void SkPDFStream::setData(SkStream* stream) {
86 fData = stream;
87}
88
89bool 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;
vandebo@chromium.org610f7162012-03-14 18:34:15 +000097 stream->setData(compressedData.copyToData())->unref();
vandebo@chromium.org421d6442011-07-20 17:39:01 +000098 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;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000117}