aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/config/SkUserConfig.h6
-rw-r--r--include/core/SkFlate.h48
-rw-r--r--include/pdf/SkPDFStream.h7
-rw-r--r--src/core/SkFlate.cpp129
-rw-r--r--src/core/core_files.mk1
-rw-r--r--src/pdf/SkPDFStream.cpp24
6 files changed, 209 insertions, 6 deletions
diff --git a/include/config/SkUserConfig.h b/include/config/SkUserConfig.h
index 8f63ce45a7..a2df7456e3 100644
--- a/include/config/SkUserConfig.h
+++ b/include/config/SkUserConfig.h
@@ -117,6 +117,12 @@
*/
//#define SK_SUPPORT_LCDTEXT
+/* If zlib is available and you want to support the flate compression
+ algorithm (used in PDF generation), define SK_ZLIB_INCLUDE to be the
+ include path.
+ */
+//#define SK_ZLIB_INCLUDE <zlib.h>
+
/* If SK_DEBUG is defined, then you can optionally define SK_SUPPORT_UNITTEST
which will run additional self-tests at startup. These can take a long time,
so this flag is optional.
diff --git a/include/core/SkFlate.h b/include/core/SkFlate.h
new file mode 100644
index 0000000000..c496b6fc97
--- /dev/null
+++ b/include/core/SkFlate.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkFlate_DEFINED
+#define SkFlate_DEFINED
+
+#include "SkTypes.h"
+
+class SkDynamicMemoryWStream;
+class SkStream;
+
+/** \class SkFlate
+ A class to provide access to the flate compression algorithm.
+*/
+class SkFlate {
+public:
+ /** Indicates if the flate algorithm is available.
+ */
+ static bool HaveFlate();
+
+ /** Use the flate compression algorithm to compress the data in src,
+ putting the result into dst. Returns false if an error occurs.
+ */
+ static bool Deflate(SkStream* src, SkDynamicMemoryWStream* dst);
+
+ /** Use the flate compression algorithm to decompress the data in src,
+ putting the result into dst. Returns false if an error occurs.
+ */
+ static bool Inflate(SkStream* src, SkDynamicMemoryWStream* dst);
+
+private:
+ static const size_t kBufferSize;
+};
+
+#endif
diff --git a/include/pdf/SkPDFStream.h b/include/pdf/SkPDFStream.h
index 24a96422be..10a40b6f98 100644
--- a/include/pdf/SkPDFStream.h
+++ b/include/pdf/SkPDFStream.h
@@ -19,9 +19,9 @@
#include "SkPDFTypes.h"
#include "SkRefCnt.h"
+#include "SkStream.h"
#include "SkTemplates.h"
-class SkStream;
class SkPDFCatalog;
/** \class SkPDFStream
@@ -57,7 +57,10 @@ public:
private:
SkPDFDict fDict;
- SkRefPtr<SkStream> fData;
+ size_t fLength;
+ // Only one of the two streams will be valid.
+ SkRefPtr<SkStream> fPlainData;
+ SkDynamicMemoryWStream fCompressedData;
};
#endif
diff --git a/src/core/SkFlate.cpp b/src/core/SkFlate.cpp
new file mode 100644
index 0000000000..a9adece75e
--- /dev/null
+++ b/src/core/SkFlate.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SkFlate.h"
+#include "SkStream.h"
+
+#ifndef SK_ZLIB_INCLUDE
+bool SkFlate::HaveFlate() { return false; }
+bool SkFlate::Deflate(SkStream*, SkDynamicMemoryWStream*) { return false; }
+bool SkFlate::Inflate(SkStream*, SkDynamicMemoryWStream*) { return false; }
+#else
+
+// static
+const size_t SkFlate::kBufferSize = 1024;
+
+// static
+bool SkFlate::HaveFlate() {
+ return true;
+}
+
+namespace {
+
+#include SK_ZLIB_INCLUDE
+
+bool doFlate(bool compress, const size_t kBufferSize, SkStream* src,
+ SkDynamicMemoryWStream* dst) {
+ uint8_t inputBuffer[kBufferSize];
+ uint8_t outputBuffer[kBufferSize];
+ z_stream flateData;
+ flateData.zalloc = NULL;
+ flateData.zfree = NULL;
+ flateData.next_in = NULL;
+ flateData.avail_in = 0;
+ flateData.next_out = outputBuffer;
+ flateData.avail_out = kBufferSize;
+ int rc;
+ if (compress)
+ rc = deflateInit(&flateData, Z_DEFAULT_COMPRESSION);
+ else
+ rc = inflateInit(&flateData);
+ if (rc != Z_OK)
+ return false;
+
+ uint8_t* input = (uint8_t*)src->getMemoryBase();
+ size_t inputLength = src->getLength();
+ if (input == NULL || inputLength < 0) {
+ input = NULL;
+ flateData.next_in = inputBuffer;
+ flateData.avail_in = 0;
+ } else {
+ flateData.next_in = input;
+ flateData.avail_in = inputLength;
+ }
+
+ rc = Z_OK;
+ while (true) {
+ if (flateData.avail_out < kBufferSize) {
+ if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out)) {
+ rc = Z_BUF_ERROR;
+ break;
+ }
+ flateData.next_out = outputBuffer;
+ flateData.avail_out = kBufferSize;
+ }
+ if (flateData.avail_in == 0) {
+ if (input != NULL)
+ break;
+ size_t read = src->read(&inputBuffer, kBufferSize);
+ if (read == 0)
+ break;
+ flateData.next_in = inputBuffer;
+ flateData.avail_in = read;
+ }
+ if (compress)
+ rc = deflate(&flateData, Z_NO_FLUSH);
+ else
+ rc = inflate(&flateData, Z_NO_FLUSH);
+ if (rc != Z_OK)
+ break;
+ }
+ while (rc == Z_OK) {
+ if (compress)
+ rc = deflate(&flateData, Z_FINISH);
+ else
+ rc = inflate(&flateData, Z_FINISH);
+ if (flateData.avail_out > 0) {
+ if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out))
+ return false;
+ flateData.next_out = outputBuffer;
+ flateData.avail_out = kBufferSize;
+ }
+ }
+
+ if (compress)
+ deflateEnd(&flateData);
+ else
+ inflateEnd(&flateData);
+ if (rc == Z_STREAM_END)
+ return true;
+ return false;
+}
+
+}
+
+// static
+bool SkFlate::Deflate(SkStream* src, SkDynamicMemoryWStream* dst) {
+ return doFlate(true, kBufferSize, src, dst);
+}
+
+// static
+bool SkFlate::Inflate(SkStream* src, SkDynamicMemoryWStream* dst) {
+ return doFlate(false, kBufferSize, src, dst);
+}
+
+#endif
+
diff --git a/src/core/core_files.mk b/src/core/core_files.mk
index e84365a7cb..af7b876859 100644
--- a/src/core/core_files.mk
+++ b/src/core/core_files.mk
@@ -37,6 +37,7 @@ SOURCE := \
SkEdgeBuilder.cpp \
SkEdgeClipper.cpp \
SkFilterProc.cpp \
+ SkFlate.cpp \
SkFlattenable.cpp \
SkFloat.cpp \
SkFloatBits.cpp \
diff --git a/src/pdf/SkPDFStream.cpp b/src/pdf/SkPDFStream.cpp
index 8be4f118ec..6947ae4df9 100644
--- a/src/pdf/SkPDFStream.cpp
+++ b/src/pdf/SkPDFStream.cpp
@@ -14,12 +14,25 @@
* limitations under the License.
*/
+#include "SkFlate.h"
#include "SkPDFCatalog.h"
#include "SkPDFStream.h"
#include "SkStream.h"
-SkPDFStream::SkPDFStream(SkStream* stream) : fData(stream) {
- SkRefPtr<SkPDFInt> lenValue = new SkPDFInt(fData->read(NULL, 0));
+SkPDFStream::SkPDFStream(SkStream* stream) {
+ if (SkFlate::HaveFlate()) {
+ SkAssertResult(SkFlate::Deflate(stream, &fCompressedData));
+ fLength = fCompressedData.getOffset();
+
+ SkRefPtr<SkPDFName> flateFilter = new SkPDFName("FlateDecode");
+ flateFilter->unref(); // SkRefPtr and new both took a reference.
+ fDict.insert("Filter", flateFilter.get());
+ } else {
+ fPlainData = stream;
+ fLength = fPlainData->getLength();
+ }
+
+ SkRefPtr<SkPDFInt> lenValue = new SkPDFInt(fLength);
lenValue->unref(); // SkRefPtr and new both took a reference.
fDict.insert("Length", lenValue.get());
}
@@ -34,7 +47,10 @@ void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
fDict.emitObject(stream, catalog, false);
stream->writeText(" stream\n");
- stream->write(fData->getMemoryBase(), fData->read(NULL, 0));
+ if (fPlainData.get())
+ stream->write(fPlainData->getMemoryBase(), fLength);
+ else
+ stream->write(fCompressedData.getStream(), fLength);
stream->writeText("\nendstream");
}
@@ -43,7 +59,7 @@ size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
return getIndirectOutputSize(catalog);
return fDict.getOutputSize(catalog, false) +
- strlen(" stream\n\nendstream") + fData->read(NULL, 0);
+ strlen(" stream\n\nendstream") + fLength;
}
void SkPDFStream::insert(SkPDFName* key, SkPDFObject* value) {