aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
authorGravatar scroggo <scroggo@google.com>2015-11-23 07:20:57 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-11-23 07:20:57 -0800
commit3389e00136188800b98ca69488c0418c374fd78b (patch)
tree6cbb5b6bc005e618daca29be3873f7211780ebbc /tests
parenta98419be092cce2a7ef27a09b6fd8065ff709cff (diff)
Add SkPngChunkReader.
This class allows a client of SkCodec to read chunks in the data stream that are not recognized by libpng. This is used by Android to specify ninepatch data. Taken from SkImageDecoder::Peeker. Modify the name of the class and its method to be more specific to their use. Make SkImageDecoder::Peeker a subclass of the new class, to help stage the change in Android. Add a test to verify that it works. BUG=skia:4574 BUG=skia:3257 Review URL: https://codereview.chromium.org/1040453002
Diffstat (limited to 'tests')
-rw-r--r--tests/CodexTest.cpp160
1 files changed, 160 insertions, 0 deletions
diff --git a/tests/CodexTest.cpp b/tests/CodexTest.cpp
index febaf7d43b..b53cbe1a4d 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