Chromium Code Reviews| Index: tests/CodecPartial.cpp |
| diff --git a/tests/CodecPartial.cpp b/tests/CodecPartial.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..08b2cec4c4b5e7406368fde00f3c616669fa23e0 |
| --- /dev/null |
| +++ b/tests/CodecPartial.cpp |
| @@ -0,0 +1,152 @@ |
| +/* |
| + * 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 "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) { |
| + return codec->getInfo().makeColorType(kN32_SkColorType).makeAlphaType(kPremul_SkAlphaType); |
| +} |
| + |
| +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(); } |
| + |
| +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); |
| + if (startResult != SkCodec::kSuccess) { |
| + ERRORF(r, "Failed to start scanline decode\n"); |
|
msarett
2016/05/20 18:21:38
nit: scanline -> incremental
scroggo_chromium
2016/05/20 18:58:37
Done.
|
| + return; |
| + } |
| + |
| + while (true) { |
| + const SkCodec::Result result = partialCodec->incrementalDecode( |
| + [&incremental](int rowNum) { |
| + return incremental.getAddr(0, rowNum); |
| + }); |
| + |
| + 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"); |
| +} |