| Index: tests/CodexTest.cpp
|
| diff --git a/tests/CodexTest.cpp b/tests/CodexTest.cpp
|
| index febaf7d43b84ee5e0176c6218f433b8d02832ae6..b53cbe1a4d7dd6c468af08f678f4b27087e91be6 100644
|
| --- a/tests/CodexTest.cpp
|
| +++ b/tests/CodexTest.cpp
|
| @@ -12,8 +12,12 @@
|
| #include "SkData.h"
|
| #include "SkMD5.h"
|
| #include "SkRandom.h"
|
| +#include "SkStream.h"
|
| +#include "SkPngChunkReader.h"
|
| #include "Test.h"
|
|
|
| +#include "png.h"
|
| +
|
| static SkStreamAsset* resource(const char path[]) {
|
| SkString fullPath = GetResourcePath(path);
|
| return SkStream::NewFromFile(fullPath.c_str());
|
| @@ -685,3 +689,159 @@ DEF_TEST(Codec_Params, r) {
|
| test_invalid_parameters(r, "index8.png");
|
| test_invalid_parameters(r, "mandrill.wbmp");
|
| }
|
| +
|
| +static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
|
| + SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr);
|
| + if (!sk_stream->write(data, len)) {
|
| + png_error(png_ptr, "sk_write_fn Error!");
|
| + }
|
| +}
|
| +
|
| +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
|
| +DEF_TEST(Codec_pngChunkReader, r) {
|
| + // Create a dummy bitmap. Use unpremul RGBA for libpng.
|
| + SkBitmap bm;
|
| + const int w = 1;
|
| + const int h = 1;
|
| + const SkImageInfo bmInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType,
|
| + kUnpremul_SkAlphaType);
|
| + bm.setInfo(bmInfo);
|
| + bm.allocPixels();
|
| + bm.eraseColor(SK_ColorBLUE);
|
| + SkMD5::Digest goodDigest;
|
| + md5(bm, &goodDigest);
|
| +
|
| + // Write to a png file.
|
| + png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
| + REPORTER_ASSERT(r, png);
|
| + if (!png) {
|
| + return;
|
| + }
|
| +
|
| + png_infop info = png_create_info_struct(png);
|
| + REPORTER_ASSERT(r, info);
|
| + if (!info) {
|
| + png_destroy_write_struct(&png, nullptr);
|
| + return;
|
| + }
|
| +
|
| + if (setjmp(png_jmpbuf(png))) {
|
| + ERRORF(r, "failed writing png");
|
| + png_destroy_write_struct(&png, &info);
|
| + return;
|
| + }
|
| +
|
| + SkDynamicMemoryWStream wStream;
|
| + png_set_write_fn(png, (void*) (&wStream), codex_test_write_fn, nullptr);
|
| +
|
| + png_set_IHDR(png, info, (png_uint_32)w, (png_uint_32)h, 8,
|
| + PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
|
| + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
| +
|
| + // Create some chunks that match the Android framework's use.
|
| + static png_unknown_chunk gUnknowns[] = {
|
| + { "npOl", (png_byte*)"outline", sizeof("outline"), PNG_HAVE_PLTE },
|
| + { "npLb", (png_byte*)"layoutBounds", sizeof("layoutBounds"), PNG_HAVE_PLTE },
|
| + { "npTc", (png_byte*)"ninePatchData", sizeof("ninePatchData"), PNG_HAVE_PLTE },
|
| + };
|
| +
|
| + png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"npOl\0npLb\0npTc\0", 3);
|
| + png_set_unknown_chunks(png, info, gUnknowns, SK_ARRAY_COUNT(gUnknowns));
|
| +#if PNG_LIBPNG_VER < 10600
|
| + /* Deal with unknown chunk location bug in 1.5.x and earlier */
|
| + png_set_unknown_chunk_location(png, info, 0, PNG_HAVE_PLTE);
|
| + png_set_unknown_chunk_location(png, info, 1, PNG_HAVE_PLTE);
|
| +#endif
|
| +
|
| + png_write_info(png, info);
|
| +
|
| + for (int j = 0; j < h; j++) {
|
| + png_bytep row = (png_bytep)(bm.getAddr(0, j));
|
| + png_write_rows(png, &row, 1);
|
| + }
|
| + png_write_end(png, info);
|
| + png_destroy_write_struct(&png, &info);
|
| +
|
| + class ChunkReader : public SkPngChunkReader {
|
| + public:
|
| + ChunkReader(skiatest::Reporter* r)
|
| + : fReporter(r)
|
| + {
|
| + this->reset();
|
| + }
|
| +
|
| + bool readChunk(const char tag[], const void* data, size_t length) override {
|
| + for (size_t i = 0; i < SK_ARRAY_COUNT(gUnknowns); ++i) {
|
| + if (!strcmp(tag, (const char*) gUnknowns[i].name)) {
|
| + // Tag matches. This should have been the first time we see it.
|
| + REPORTER_ASSERT(fReporter, !fSeen[i]);
|
| + fSeen[i] = true;
|
| +
|
| + // Data and length should match
|
| + REPORTER_ASSERT(fReporter, length == gUnknowns[i].size);
|
| + REPORTER_ASSERT(fReporter, !strcmp((const char*) data,
|
| + (const char*) gUnknowns[i].data));
|
| + return true;
|
| + }
|
| + }
|
| + ERRORF(fReporter, "Saw an unexpected unknown chunk.");
|
| + return true;
|
| + }
|
| +
|
| + bool allHaveBeenSeen() {
|
| + bool ret = true;
|
| + for (auto seen : fSeen) {
|
| + ret &= seen;
|
| + }
|
| + return ret;
|
| + }
|
| +
|
| + void reset() {
|
| + sk_bzero(fSeen, sizeof(fSeen));
|
| + }
|
| +
|
| + private:
|
| + skiatest::Reporter* fReporter; // Unowned
|
| + bool fSeen[3];
|
| + };
|
| +
|
| + ChunkReader chunkReader(r);
|
| +
|
| + // Now read the file with SkCodec.
|
| + SkAutoTUnref<SkData> data(wStream.copyToData());
|
| + SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data, &chunkReader));
|
| + REPORTER_ASSERT(r, codec);
|
| + if (!codec) {
|
| + return;
|
| + }
|
| +
|
| + // Now compare to the original.
|
| + SkBitmap decodedBm;
|
| + decodedBm.setInfo(codec->getInfo());
|
| + decodedBm.allocPixels();
|
| + SkCodec::Result result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(),
|
| + decodedBm.rowBytes());
|
| + REPORTER_ASSERT(r, SkCodec::kSuccess == result);
|
| +
|
| + if (decodedBm.colorType() != bm.colorType()) {
|
| + SkBitmap tmp;
|
| + bool success = decodedBm.copyTo(&tmp, bm.colorType());
|
| + REPORTER_ASSERT(r, success);
|
| + if (!success) {
|
| + return;
|
| + }
|
| +
|
| + tmp.swap(decodedBm);
|
| + }
|
| +
|
| + compare_to_good_digest(r, goodDigest, decodedBm);
|
| + REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());
|
| +
|
| + // Decoding again will read the chunks again.
|
| + chunkReader.reset();
|
| + REPORTER_ASSERT(r, !chunkReader.allHaveBeenSeen());
|
| + result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(), decodedBm.rowBytes());
|
| + REPORTER_ASSERT(r, SkCodec::kSuccess == result);
|
| + REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());
|
| +}
|
| +#endif // PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
|
|
|