aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/tests.gypi3
-rw-r--r--src/core/SkStream.cpp22
-rw-r--r--src/core/SkStreamPriv.h6
-rw-r--r--src/pdf/SkDeflate.cpp109
-rw-r--r--src/pdf/SkDeflate.h30
-rw-r--r--src/pdf/SkPDFStream.cpp6
-rw-r--r--tests/PDFDeflateWStreamTest.cpp100
-rw-r--r--tests/PDFFlateTest.cpp114
-rw-r--r--tests/PDFPrimitivesTest.cpp8
-rw-r--r--tests/StreamTest.cpp58
10 files changed, 191 insertions, 265 deletions
diff --git a/gyp/tests.gypi b/gyp/tests.gypi
index ad6a56ca6c..1fd87addf9 100644
--- a/gyp/tests.gypi
+++ b/gyp/tests.gypi
@@ -27,6 +27,7 @@
'tools.gyp:picture_utils',
'tools.gyp:resources',
'tools.gyp:sk_tool_utils',
+ 'zlib.gyp:zlib',
],
'conditions': [
[ 'skia_os not in ["linux", "freebsd", "openbsd", "solaris", "chromeos", "android"]', {
@@ -38,7 +39,7 @@
],
}],
[ 'not skia_pdf', {
- 'dependencies!': [ 'pdf.gyp:pdf' ],
+ 'dependencies!': [ 'pdf.gyp:pdf', 'zlib.gyp:zlib' ],
'dependencies': [ 'pdf.gyp:nopdf' ],
'sources!': [ '<!@(python find.py ../tests "PDF*.c*")', ],
}],
diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp
index ac73adbce5..f32f68a10a 100644
--- a/src/core/SkStream.cpp
+++ b/src/core/SkStream.cpp
@@ -950,3 +950,25 @@ SkStreamRewindable* SkStreamRewindableFromSkStream(SkStream* stream) {
return tempStream.detachAsStream(); // returns a SkBlockMemoryStream,
// cheaper than copying to SkData
}
+
+bool SkStreamCopy(SkWStream* out, SkStream* input) {
+ const char* base = static_cast<const char*>(input->getMemoryBase());
+ if (base && input->hasPosition() && input->hasLength()) {
+ // Shortcut that avoids the while loop.
+ size_t position = input->getPosition();
+ size_t length = input->getLength();
+ SkASSERT(length >= position);
+ return out->write(&base[position], length - position);
+ }
+ char scratch[4096];
+ size_t count;
+ while (true) {
+ count = input->read(scratch, sizeof(scratch));
+ if (0 == count) {
+ return true;
+ }
+ if (!out->write(scratch, count)) {
+ return false;
+ }
+ }
+}
diff --git a/src/core/SkStreamPriv.h b/src/core/SkStreamPriv.h
index 718097d1cc..d1af117674 100644
--- a/src/core/SkStreamPriv.h
+++ b/src/core/SkStreamPriv.h
@@ -43,4 +43,10 @@ SkData *SkCopyStreamToData(SkStream* stream);
*/
SkStreamRewindable* SkStreamRewindableFromSkStream(SkStream* stream);
+/**
+ * Copies the input stream from the current position to the end.
+ * Does not rewind the input stream.
+ */
+bool SkStreamCopy(SkWStream* out, SkStream* input);
+
#endif // SkStreamPriv_DEFINED
diff --git a/src/pdf/SkDeflate.cpp b/src/pdf/SkDeflate.cpp
index 0953ef27fb..2ca516c0e3 100644
--- a/src/pdf/SkDeflate.cpp
+++ b/src/pdf/SkDeflate.cpp
@@ -19,120 +19,15 @@ namespace {
#include "zlib.h"
#endif
-// static
-const size_t kBufferSize = 1024;
-
// Different zlib implementations use different T.
// We've seen size_t and unsigned.
template <typename T> void* skia_alloc_func(void*, T items, T size) {
return sk_calloc_throw(SkToSizeT(items) * SkToSizeT(size));
}
-static void skia_free_func(void*, void* address) { sk_free(address); }
-
-bool doFlate(bool compress, SkStream* src, SkWStream* dst) {
- uint8_t inputBuffer[kBufferSize];
- uint8_t outputBuffer[kBufferSize];
- z_stream flateData;
- flateData.zalloc = &skia_alloc_func;
- flateData.zfree = &skia_free_func;
- flateData.opaque = 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 = SkToUInt(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 (rc != Z_OK)
- break;
- 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 = SkToUInt(read);
- }
- if (compress)
- rc = deflate(&flateData, Z_NO_FLUSH);
- else
- rc = inflate(&flateData, Z_NO_FLUSH);
- }
- while (rc == Z_OK) {
- if (compress)
- rc = deflate(&flateData, Z_FINISH);
- else
- rc = inflate(&flateData, Z_FINISH);
- if (flateData.avail_out < kBufferSize) {
- 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, SkWStream* dst) {
- return doFlate(true, src, dst);
-}
-
-bool SkFlate::Deflate(const void* ptr, size_t len, SkWStream* dst) {
- SkMemoryStream stream(ptr, len);
- return doFlate(true, &stream, dst);
-}
-
-bool SkFlate::Deflate(const SkData* data, SkWStream* dst) {
- if (data) {
- SkMemoryStream stream(data->data(), data->size());
- return doFlate(true, &stream, dst);
- }
- return false;
-}
-
-// static
-bool SkFlate::Inflate(SkStream* src, SkWStream* dst) {
- return doFlate(false, src, dst);
-}
+void skia_free_func(void*, void* address) { sk_free(address); }
+} // namespace
#define SKDEFLATEWSTREAM_INPUT_BUFFER_SIZE 4096
#define SKDEFLATEWSTREAM_OUTPUT_BUFFER_SIZE 4224 // 4096 + 128, usually big
diff --git a/src/pdf/SkDeflate.h b/src/pdf/SkDeflate.h
index 0104c4514d..d7323789a8 100644
--- a/src/pdf/SkDeflate.h
+++ b/src/pdf/SkDeflate.h
@@ -13,36 +13,6 @@
#include "SkTypes.h"
#include "SkStream.h"
-class SkData;
-
-/** \class SkFlate
- A class to provide access to the flate compression algorithm.
-*/
-class SkFlate {
-public:
- /**
- * 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, SkWStream* dst);
-
- /**
- * 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(const void* src, size_t len, SkWStream* dst);
-
- /**
- * Use the flate compression algorithm to compress the data,
- * putting the result into dst. Returns false if an error occurs.
- */
- static bool Deflate(const SkData*, SkWStream* 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, SkWStream* dst);
-};
/**
* Wrap a stream in this class to compress the information written to
diff --git a/src/pdf/SkPDFStream.cpp b/src/pdf/SkPDFStream.cpp
index e709357e60..d21205cd38 100644
--- a/src/pdf/SkPDFStream.cpp
+++ b/src/pdf/SkPDFStream.cpp
@@ -29,9 +29,9 @@ void SkPDFStream::emitObject(SkWStream* stream,
if (fState == kUnused_State) {
fState = kNoCompression_State;
SkDynamicMemoryWStream compressedData;
-
- SkAssertResult(
- SkFlate::Deflate(fDataStream.get(), &compressedData));
+ SkDeflateWStream deflateWStream(&compressedData);
+ SkAssertResult(SkStreamCopy(&deflateWStream, fDataStream.get()));
+ deflateWStream.finalize();
SkAssertResult(fDataStream->rewind());
if (compressedData.getOffset() < this->dataSize()) {
SkAutoTDelete<SkStream> compressed(
diff --git a/tests/PDFDeflateWStreamTest.cpp b/tests/PDFDeflateWStreamTest.cpp
index bc0defc5fe..a85212c2c3 100644
--- a/tests/PDFDeflateWStreamTest.cpp
+++ b/tests/PDFDeflateWStreamTest.cpp
@@ -9,6 +9,98 @@
#include "SkRandom.h"
#include "Test.h"
+namespace {
+
+#ifdef ZLIB_INCLUDE
+ #include ZLIB_INCLUDE
+#else
+ #include "zlib.h"
+#endif
+
+// Different zlib implementations use different T.
+// We've seen size_t and unsigned.
+template <typename T> void* skia_alloc_func(void*, T items, T size) {
+ return sk_calloc_throw(SkToSizeT(items) * SkToSizeT(size));
+}
+
+void skia_free_func(void*, void* address) { sk_free(address); }
+
+/**
+ * Use the un-deflate compression algorithm to decompress the data in src,
+ * returning the result. Returns NULL if an error occurs.
+ */
+SkStreamAsset* stream_inflate(SkStream* src) {
+ SkDynamicMemoryWStream decompressedDynamicMemoryWStream;
+ SkWStream* dst = &decompressedDynamicMemoryWStream;
+
+ static const size_t kBufferSize = 1024;
+ uint8_t inputBuffer[kBufferSize];
+ uint8_t outputBuffer[kBufferSize];
+ z_stream flateData;
+ flateData.zalloc = &skia_alloc_func;
+ flateData.zfree = &skia_free_func;
+ flateData.opaque = NULL;
+ flateData.next_in = NULL;
+ flateData.avail_in = 0;
+ flateData.next_out = outputBuffer;
+ flateData.avail_out = kBufferSize;
+ int rc;
+ rc = inflateInit(&flateData);
+ if (rc != Z_OK)
+ return nullptr;
+
+ 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 = SkToUInt(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 (rc != Z_OK)
+ break;
+ 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 = SkToUInt(read);
+ }
+ rc = inflate(&flateData, Z_NO_FLUSH);
+ }
+ while (rc == Z_OK) {
+ rc = inflate(&flateData, Z_FINISH);
+ if (flateData.avail_out < kBufferSize) {
+ if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out))
+ return nullptr;
+ flateData.next_out = outputBuffer;
+ flateData.avail_out = kBufferSize;
+ }
+ }
+
+ inflateEnd(&flateData);
+ if (rc != Z_STREAM_END) {
+ return nullptr;
+ }
+ return decompressedDynamicMemoryWStream.detachAsStream();
+}
+} // namespace
+
DEF_TEST(SkDeflateWStream, r) {
SkRandom random(123456);
for (int i = 0; i < 50; ++i) {
@@ -34,13 +126,7 @@ DEF_TEST(SkDeflateWStream, r) {
}
SkAutoTDelete<SkStreamAsset> compressed(
dynamicMemoryWStream.detachAsStream());
-
- SkDynamicMemoryWStream decompressedDynamicMemoryWStream;
- SkAssertResult(SkFlate::Inflate(compressed,
- &decompressedDynamicMemoryWStream));
-
- SkAutoTDelete<SkStreamAsset> decompressed(
- decompressedDynamicMemoryWStream.detachAsStream());
+ SkAutoTDelete<SkStreamAsset> decompressed(stream_inflate(compressed));
if (decompressed->getLength() != size) {
ERRORF(r, "Decompression failed to get right size [%d]."
diff --git a/tests/PDFFlateTest.cpp b/tests/PDFFlateTest.cpp
deleted file mode 100644
index 64dc4e2586..0000000000
--- a/tests/PDFFlateTest.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkData.h"
-#include "SkDeflate.h"
-#include "SkStream.h"
-#include "Test.h"
-
-// A memory stream that reports zero size with the standard call, like
-// an unseekable file stream would.
-class SkZeroSizeMemStream : public SkMemoryStream {
-public:
- virtual size_t read(void* buffer, size_t size) {
- if (buffer == NULL && size == 0)
- return 0;
- if (buffer == NULL && size == kGetSizeKey)
- size = 0;
- return SkMemoryStream::read(buffer, size);
- }
-
- static const size_t kGetSizeKey = 0xDEADBEEF;
-};
-
-// Returns a deterministic data of the given size that should be
-// very compressible.
-static SkData* new_test_data(size_t dataSize) {
- SkAutoTMalloc<uint8_t> testBuffer(dataSize);
- for (size_t i = 0; i < dataSize; ++i) {
- testBuffer[SkToInt(i)] = i % 64;
- }
- return SkData::NewFromMalloc(testBuffer.detach(), dataSize);
-}
-
-static void TestFlate(skiatest::Reporter* reporter, SkMemoryStream* testStream,
- size_t dataSize) {
- SkASSERT(testStream != NULL);
-
- SkAutoDataUnref testData(new_test_data(dataSize));
- SkASSERT(testData->size() == dataSize);
-
- testStream->setMemory(testData->data(), dataSize, /*copyData=*/ true);
- SkDynamicMemoryWStream compressed;
- bool deflateSuccess = SkFlate::Deflate(testStream, &compressed);
- REPORTER_ASSERT(reporter, deflateSuccess);
-
- // Check that the input data wasn't changed.
- size_t inputSize = testStream->getLength();
- if (inputSize == 0) {
- inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey);
- }
- REPORTER_ASSERT(reporter, dataSize == inputSize);
- if (dataSize == inputSize) {
- REPORTER_ASSERT(reporter, memcmp(testData->data(),
- testStream->getMemoryBase(),
- dataSize) == 0);
- }
-
- size_t compressedSize = compressed.getOffset();
-
- SkAutoDataUnref compressedData(compressed.copyToData());
- testStream->setData(compressedData.get());
-
- SkDynamicMemoryWStream uncompressed;
- bool inflateSuccess = SkFlate::Inflate(testStream, &uncompressed);
- REPORTER_ASSERT(reporter, inflateSuccess);
-
- // Check that the input data wasn't changed.
- inputSize = testStream->getLength();
- if (inputSize == 0) {
- inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey);
- }
- REPORTER_ASSERT(reporter, compressedSize == inputSize);
- if (compressedData->size() == inputSize) {
- REPORTER_ASSERT(reporter, memcmp(testStream->getMemoryBase(),
- compressedData->data(),
- compressedData->size()) == 0);
- }
-
- // Check that the uncompressed data matches the source data.
- SkAutoDataUnref uncompressedData(uncompressed.copyToData());
- REPORTER_ASSERT(reporter, dataSize == uncompressedData->size());
- if (dataSize == uncompressedData->size()) {
- REPORTER_ASSERT(reporter, memcmp(testData->data(),
- uncompressedData->data(),
- dataSize) == 0);
- }
-
- if (compressedSize < 1) { return; }
-
- double compressionRatio = static_cast<double>(dataSize) / compressedSize;
- // Assert that some compression took place.
- REPORTER_ASSERT(reporter, compressionRatio > 1.2);
-
- if (reporter->verbose()) {
- SkDebugf("Flate Test: \t input size: " SK_SIZE_T_SPECIFIER
- "\tcompressed size: " SK_SIZE_T_SPECIFIER
- "\tratio: %.4g\n",
- dataSize, compressedSize, compressionRatio);
- }
-}
-
-DEF_TEST(Flate, reporter) {
- SkMemoryStream memStream;
- TestFlate(reporter, &memStream, 512);
- TestFlate(reporter, &memStream, 10240);
-
- SkZeroSizeMemStream fileStream;
- TestFlate(reporter, &fileStream, 512);
- TestFlate(reporter, &fileStream, 10240);
-}
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index b0b776527f..1d35c08cbb 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -99,12 +99,14 @@ static void TestPDFStream(skiatest::Reporter* reporter) {
SkAutoTUnref<SkPDFStream> stream(new SkPDFStream(streamData2.get()));
SkDynamicMemoryWStream compressedByteStream;
- SkFlate::Deflate(streamData2.get(), &compressedByteStream);
- SkAutoDataUnref compressedData(compressedByteStream.copyToData());
+ SkDeflateWStream deflateWStream(&compressedByteStream);
+ deflateWStream.write(streamBytes2, strlen(streamBytes2));
+ deflateWStream.finalize();
SkDynamicMemoryWStream expected;
expected.writeText("<</Filter /FlateDecode\n/Length 116>> stream\n");
- expected.write(compressedData->data(), compressedData->size());
+ compressedByteStream.writeToStream(&expected);
+ compressedByteStream.reset();
expected.writeText("\nendstream");
SkAutoDataUnref expectedResultData2(expected.copyToData());
SkString result = emit_to_string(*stream);
diff --git a/tests/StreamTest.cpp b/tests/StreamTest.cpp
index 926cfc2579..78c0e506db 100644
--- a/tests/StreamTest.cpp
+++ b/tests/StreamTest.cpp
@@ -11,6 +11,7 @@
#include "SkOSFile.h"
#include "SkRandom.h"
#include "SkStream.h"
+#include "SkStreamPriv.h"
#include "Test.h"
#ifndef SK_BUILD_FOR_WIN
@@ -335,3 +336,60 @@ DEF_TEST(StreamPeek_BlockMemoryStream, rep) {
}
stream_peek_test(rep, asset, expected);
}
+
+namespace {
+class DumbStream : public SkStream {
+public:
+ DumbStream(const uint8_t* data, size_t n)
+ : fData(data), fCount(n), fIdx(0) {}
+ size_t read(void* buffer, size_t size) override {
+ size_t c = SkTMin(fCount - fIdx, size);
+ if (c) {
+ memcpy(buffer, &fData[fIdx], size);
+ fIdx += c;
+ }
+ return c;
+ }
+ bool isAtEnd() const override {
+ return fCount > fIdx;
+ }
+ private:
+ const uint8_t* fData;
+ size_t fCount, fIdx;
+};
+} // namespace
+
+static void stream_copy_test(skiatest::Reporter* reporter,
+ const void* srcData,
+ size_t N,
+ SkStream* stream) {
+ SkDynamicMemoryWStream tgt;
+ if (!SkStreamCopy(&tgt, stream)) {
+ ERRORF(reporter, "SkStreamCopy failed");
+ return;
+ }
+ SkAutoTUnref<SkData> data(tgt.copyToData());
+ tgt.reset();
+ if (data->size() != N) {
+ ERRORF(reporter, "SkStreamCopy incorrect size");
+ return;
+ }
+ if (0 != memcmp(data->data(), srcData, N)) {
+ ERRORF(reporter, "SkStreamCopy bad copy");
+ }
+}
+
+DEF_TEST(StreamCopy, reporter) {
+ SkRandom random(123456);
+ static const size_t N = 10000;
+ uint8_t src[N];
+ for (size_t j = 0; j < N; ++j) {
+ src[j] = random.nextU() & 0xff;
+ }
+ // SkStreamCopy had two code paths; this test both.
+ DumbStream dumbStream(src, N);
+ stream_copy_test(reporter, src, N, &dumbStream);
+ SkMemoryStream smartStream(src, N);
+ stream_copy_test(reporter, src, N, &smartStream);
+
+}