diff options
Diffstat (limited to 'tests/CodecPartial.cpp')
-rw-r--r-- | tests/CodecPartial.cpp | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/tests/CodecPartial.cpp b/tests/CodecPartial.cpp new file mode 100644 index 0000000000..8775e87c63 --- /dev/null +++ b/tests/CodecPartial.cpp @@ -0,0 +1,155 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkBitmap.h" +#include "SkCodec.h" +#include "SkData.h" +#include "SkImageInfo.h" +#include "SkRWBuffer.h" +#include "SkString.h" + +#include "Resources.h" +#include "Test.h" + +static sk_sp<SkData> make_from_resource(const char* name) { + SkString fullPath = GetResourcePath(name); + return SkData::MakeFromFileName(fullPath.c_str()); +} + +static SkImageInfo standardize_info(SkCodec* codec) { + SkImageInfo defaultInfo = codec->getInfo(); + // Note: This drops the SkColorSpace, allowing the equality check between two + // different codecs created from the same file to have the same SkImageInfo. + return SkImageInfo::MakeN32Premul(defaultInfo.width(), defaultInfo.height()); +} + +static bool create_truth(sk_sp<SkData> data, SkBitmap* dst) { + SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data.get())); + if (!codec) { + return false; + } + + const SkImageInfo info = standardize_info(codec); + dst->allocPixels(info); + return SkCodec::kSuccess == codec->getPixels(info, dst->getPixels(), dst->rowBytes()); +} + +/* + * Represents a stream without all of its data. + */ +class HaltingStream : public SkStream { +public: + HaltingStream(sk_sp<SkData> data) + : fTotalSize(data->size()) + , fLimit(fTotalSize / 2) + , fStream(std::move(data)) + {} + + void addNewData() { + // Arbitrary size, but deliberately different from + // the buffer size used by SkPngCodec. + fLimit = SkTMin(fTotalSize, fLimit + 1000); + } + + size_t read(void* buffer, size_t size) override { + if (fStream.getPosition() + size > fLimit) { + size = fLimit - fStream.getPosition(); + } + + return fStream.read(buffer, size); + } + + bool isAtEnd() const override { + return fStream.isAtEnd(); + } + + bool hasPosition() const override { return true; } + size_t getPosition() const override { return fStream.getPosition(); } + bool rewind() override { return fStream.rewind(); } + bool move(long offset) override { return fStream.move(offset); } + +private: + const size_t fTotalSize; + size_t fLimit; + SkMemoryStream fStream; +}; + +static void test_partial(skiatest::Reporter* r, const char* name) { + sk_sp<SkData> file = make_from_resource(name); + if (!file) { + SkDebugf("missing resource %s\n", name); + return; + } + + SkBitmap truth; + if (!create_truth(file, &truth)) { + ERRORF(r, "Failed to decode %s\n", name); + return; + } + + const size_t fileSize = file->size(); + + // Now decode part of the file + HaltingStream* stream = new HaltingStream(file); + + // Note that we cheat and hold on to a pointer to stream, though it is owned by + // partialCodec. + SkAutoTDelete<SkCodec> partialCodec(SkCodec::NewFromStream(stream)); + if (!partialCodec) { + // Technically, this could be a small file where half the file is not + // enough. + ERRORF(r, "Failed to create codec for %s", name); + return; + } + + const SkImageInfo info = standardize_info(partialCodec); + SkASSERT(info == truth.info()); + SkBitmap incremental; + incremental.allocPixels(info); + + const SkCodec::Result startResult = partialCodec->startIncrementalDecode(info, + incremental.getPixels(), incremental.rowBytes()); + if (startResult != SkCodec::kSuccess) { + ERRORF(r, "Failed to start incremental decode\n"); + return; + } + + while (true) { + const SkCodec::Result result = partialCodec->incrementalDecode(); + + if (stream->getPosition() == fileSize) { + REPORTER_ASSERT(r, result == SkCodec::kSuccess); + break; + } + + SkASSERT(stream->getPosition() < fileSize); + + REPORTER_ASSERT(r, result == SkCodec::kIncompleteInput); + + // Append an arbitrary amount of data. + stream->addNewData(); + } + + // compare to original + for (int i = 0; i < info.height(); i++) { + REPORTER_ASSERT(r, !memcmp(truth.getAddr(0, 0), incremental.getAddr(0, 0), + info.minRowBytes())); + } +} + +DEF_TEST(Codec_partial, r) { + test_partial(r, "plane.png"); + test_partial(r, "plane_interlaced.png"); + test_partial(r, "yellow_rose.png"); + test_partial(r, "index8.png"); + test_partial(r, "color_wheel.png"); + test_partial(r, "mandrill_256.png"); + test_partial(r, "mandrill_32.png"); + test_partial(r, "arrow.png"); + test_partial(r, "randPixels.png"); + test_partial(r, "baby_tux.png"); +} |