1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/codec/SkAndroidCodec.h" 9cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 10cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 11cb93a386Sopenharmony_ci#include "include/core/SkData.h" 12cb93a386Sopenharmony_ci#include "include/core/SkImage.h" 13cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 14cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 15cb93a386Sopenharmony_ci#include "tests/CodecPriv.h" 16cb93a386Sopenharmony_ci#include "tests/Test.h" 17cb93a386Sopenharmony_ci#include "tools/Resources.h" 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cistatic unsigned char gGIFData[] = { 20cb93a386Sopenharmony_ci 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x03, 0x00, 0x03, 0x00, 0xe3, 0x08, 21cb93a386Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 22cb93a386Sopenharmony_ci 0xff, 0x80, 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 23cb93a386Sopenharmony_ci 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 24cb93a386Sopenharmony_ci 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 25cb93a386Sopenharmony_ci 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x04, 26cb93a386Sopenharmony_ci 0x07, 0x50, 0x1c, 0x43, 0x40, 0x41, 0x23, 0x44, 0x00, 0x3b 27cb93a386Sopenharmony_ci}; 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_cistatic unsigned char gGIFDataNoColormap[] = { 30cb93a386Sopenharmony_ci // Header 31cb93a386Sopenharmony_ci 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 32cb93a386Sopenharmony_ci // Screen descriptor 33cb93a386Sopenharmony_ci 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 34cb93a386Sopenharmony_ci // Graphics control extension 35cb93a386Sopenharmony_ci 0x21, 0xf9, 0x04, 0x01, 0x0a, 0x00, 0x01, 0x00, 36cb93a386Sopenharmony_ci // Image descriptor 37cb93a386Sopenharmony_ci 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 38cb93a386Sopenharmony_ci // Image data 39cb93a386Sopenharmony_ci 0x02, 0x02, 0x4c, 0x01, 0x00, 40cb93a386Sopenharmony_ci // Trailer 41cb93a386Sopenharmony_ci 0x3b 42cb93a386Sopenharmony_ci}; 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_cistatic unsigned char gInterlacedGIF[] = { 45cb93a386Sopenharmony_ci 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x09, 0x00, 0x09, 0x00, 0xe3, 0x08, 0x00, 46cb93a386Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x80, 47cb93a386Sopenharmony_ci 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 48cb93a386Sopenharmony_ci 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 49cb93a386Sopenharmony_ci 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 50cb93a386Sopenharmony_ci 0x00, 0x09, 0x00, 0x09, 0x00, 0x40, 0x04, 0x1b, 0x50, 0x1c, 0x23, 0xe9, 0x44, 51cb93a386Sopenharmony_ci 0x23, 0x60, 0x9d, 0x09, 0x28, 0x1e, 0xf8, 0x6d, 0x64, 0x56, 0x9d, 0x53, 0xa8, 52cb93a386Sopenharmony_ci 0x7e, 0xa8, 0x65, 0x94, 0x5c, 0xb0, 0x8a, 0x45, 0x04, 0x00, 0x3b 53cb93a386Sopenharmony_ci}; 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_cistatic void test_gif_data_no_colormap(skiatest::Reporter* r, 56cb93a386Sopenharmony_ci void* data, 57cb93a386Sopenharmony_ci size_t size) { 58cb93a386Sopenharmony_ci SkBitmap bm; 59cb93a386Sopenharmony_ci bool imageDecodeSuccess = decode_memory(data, size, &bm); 60cb93a386Sopenharmony_ci REPORTER_ASSERT(r, imageDecodeSuccess); 61cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.width() == 1); 62cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.height() == 1); 63cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !(bm.empty())); 64cb93a386Sopenharmony_ci if (!(bm.empty())) { 65cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 0) == 0x00000000); 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci} 68cb93a386Sopenharmony_cistatic void test_gif_data(skiatest::Reporter* r, void* data, size_t size) { 69cb93a386Sopenharmony_ci SkBitmap bm; 70cb93a386Sopenharmony_ci bool imageDecodeSuccess = decode_memory(data, size, &bm); 71cb93a386Sopenharmony_ci REPORTER_ASSERT(r, imageDecodeSuccess); 72cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.width() == 3); 73cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.height() == 3); 74cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !(bm.empty())); 75cb93a386Sopenharmony_ci if (!(bm.empty())) { 76cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000); 77cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00); 78cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff); 79cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080); 80cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000); 81cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00); 82cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff); 83cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff); 84cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff); 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci} 87cb93a386Sopenharmony_cistatic void test_gif_data_dims(skiatest::Reporter* r, void* data, size_t size, int width, 88cb93a386Sopenharmony_ci int height) { 89cb93a386Sopenharmony_ci SkBitmap bm; 90cb93a386Sopenharmony_ci bool imageDecodeSuccess = decode_memory(data, size, &bm); 91cb93a386Sopenharmony_ci REPORTER_ASSERT(r, imageDecodeSuccess); 92cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.width() == width); 93cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.height() == height); 94cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !(bm.empty())); 95cb93a386Sopenharmony_ci} 96cb93a386Sopenharmony_cistatic void test_interlaced_gif_data(skiatest::Reporter* r, 97cb93a386Sopenharmony_ci void* data, 98cb93a386Sopenharmony_ci size_t size) { 99cb93a386Sopenharmony_ci SkBitmap bm; 100cb93a386Sopenharmony_ci bool imageDecodeSuccess = decode_memory(data, size, &bm); 101cb93a386Sopenharmony_ci REPORTER_ASSERT(r, imageDecodeSuccess); 102cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.width() == 9); 103cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.height() == 9); 104cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !(bm.empty())); 105cb93a386Sopenharmony_ci if (!(bm.empty())) { 106cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000); 107cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00); 108cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff); 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff); 111cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff); 112cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff); 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 4) == 0xff808080); 115cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(1, 4) == 0xff000000); 116cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(2, 4) == 0xff00ff00); 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 6) == 0xffff0000); 119cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(1, 6) == 0xffffff00); 120cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(2, 6) == 0xff00ffff); 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 8) == 0xffffffff); 123cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(1, 8) == 0xffff00ff); 124cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(2, 8) == 0xff0000ff); 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci} 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_cistatic void test_gif_data_short(skiatest::Reporter* r, 129cb93a386Sopenharmony_ci void* data, 130cb93a386Sopenharmony_ci size_t size) { 131cb93a386Sopenharmony_ci SkBitmap bm; 132cb93a386Sopenharmony_ci bool imageDecodeSuccess = decode_memory(data, size, &bm); 133cb93a386Sopenharmony_ci REPORTER_ASSERT(r, imageDecodeSuccess); 134cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.width() == 3); 135cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.height() == 3); 136cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !(bm.empty())); 137cb93a386Sopenharmony_ci if (!(bm.empty())) { 138cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000); 139cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00); 140cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff); 141cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080); 142cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000); 143cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00); 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci} 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci/** 148cb93a386Sopenharmony_ci This test will test the ability of the SkCodec to deal with 149cb93a386Sopenharmony_ci GIF files which have been mangled somehow. We want to display as 150cb93a386Sopenharmony_ci much of the GIF as possible. 151cb93a386Sopenharmony_ci*/ 152cb93a386Sopenharmony_ciDEF_TEST(Gif, reporter) { 153cb93a386Sopenharmony_ci // test perfectly good images. 154cb93a386Sopenharmony_ci test_gif_data(reporter, static_cast<void *>(gGIFData), sizeof(gGIFData)); 155cb93a386Sopenharmony_ci test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF), 156cb93a386Sopenharmony_ci sizeof(gInterlacedGIF)); 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci unsigned char badData[sizeof(gGIFData)]; 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci memcpy(badData, gGIFData, sizeof(gGIFData)); 161cb93a386Sopenharmony_ci badData[6] = 0x01; // image too wide 162cb93a386Sopenharmony_ci test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData)); 163cb93a386Sopenharmony_ci // "libgif warning [image too wide, expanding output to size]" 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci memcpy(badData, gGIFData, sizeof(gGIFData)); 166cb93a386Sopenharmony_ci badData[8] = 0x01; // image too tall 167cb93a386Sopenharmony_ci test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData)); 168cb93a386Sopenharmony_ci // "libgif warning [image too tall, expanding output to size]" 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci memcpy(badData, gGIFData, sizeof(gGIFData)); 171cb93a386Sopenharmony_ci badData[62] = 0x01; // image shifted right 172cb93a386Sopenharmony_ci test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 4, 3); 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci memcpy(badData, gGIFData, sizeof(gGIFData)); 175cb93a386Sopenharmony_ci badData[64] = 0x01; // image shifted down 176cb93a386Sopenharmony_ci test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3, 4); 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci memcpy(badData, gGIFData, sizeof(gGIFData)); 179cb93a386Sopenharmony_ci badData[62] = 0xff; // image shifted right 180cb93a386Sopenharmony_ci badData[63] = 0xff; 181cb93a386Sopenharmony_ci test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3 + 0xFFFF, 3); 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci memcpy(badData, gGIFData, sizeof(gGIFData)); 184cb93a386Sopenharmony_ci badData[64] = 0xff; // image shifted down 185cb93a386Sopenharmony_ci badData[65] = 0xff; 186cb93a386Sopenharmony_ci test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3, 3 + 0xFFFF); 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap), 189cb93a386Sopenharmony_ci sizeof(gGIFDataNoColormap)); 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci#ifdef SK_HAS_WUFFS_LIBRARY 192cb93a386Sopenharmony_ci // We are transitioning from an old GIF implementation to a new (Wuffs) GIF 193cb93a386Sopenharmony_ci // implementation. 194cb93a386Sopenharmony_ci // 195cb93a386Sopenharmony_ci // This test (without SK_HAS_WUFFS_LIBRARY) is overly specific to the old 196cb93a386Sopenharmony_ci // implementation. It claims that, for invalid (truncated) input, we can 197cb93a386Sopenharmony_ci // still 'decode' all of the pixels because no matter what palette index 198cb93a386Sopenharmony_ci // each pixel is, they're all equivalently transparent. It's not obvious 199cb93a386Sopenharmony_ci // that this off-spec behavior is worth preserving. Are real world users 200cb93a386Sopenharmony_ci // decoding truncated all-transparent GIF images?? 201cb93a386Sopenharmony_ci // 202cb93a386Sopenharmony_ci // Once the transition is complete, we can remove the #ifdef and delete the 203cb93a386Sopenharmony_ci // #else branch. 204cb93a386Sopenharmony_ci#else 205cb93a386Sopenharmony_ci // Since there is no color map, we do not even need to parse the image data 206cb93a386Sopenharmony_ci // to know that we should draw transparent. Truncate the file before the 207cb93a386Sopenharmony_ci // data. This should still succeed. 208cb93a386Sopenharmony_ci test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap), 31); 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ci // Likewise, incremental decoding should succeed here. 211cb93a386Sopenharmony_ci { 212cb93a386Sopenharmony_ci sk_sp<SkData> data = SkData::MakeWithoutCopy(gGIFDataNoColormap, 31); 213cb93a386Sopenharmony_ci std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data)); 214cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, codec); 215cb93a386Sopenharmony_ci if (codec) { 216cb93a386Sopenharmony_ci auto info = codec->getInfo().makeColorType(kN32_SkColorType); 217cb93a386Sopenharmony_ci SkBitmap bm; 218cb93a386Sopenharmony_ci bm.allocPixels(info); 219cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->startIncrementalDecode( 220cb93a386Sopenharmony_ci info, bm.getPixels(), bm.rowBytes())); 221cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->incrementalDecode()); 222cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bm.width() == 1); 223cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bm.height() == 1); 224cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !(bm.empty())); 225cb93a386Sopenharmony_ci if (!(bm.empty())) { 226cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bm.getColor(0, 0) == 0x00000000); 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci } 230cb93a386Sopenharmony_ci#endif 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci // test short Gif. 80 is missing a few bytes. 233cb93a386Sopenharmony_ci test_gif_data_short(reporter, static_cast<void *>(gGIFData), 80); 234cb93a386Sopenharmony_ci // "libgif warning [DGifGetLine]" 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_ci test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF), 237cb93a386Sopenharmony_ci 100); // 100 is missing a few bytes 238cb93a386Sopenharmony_ci // "libgif warning [interlace DGifGetLine]" 239cb93a386Sopenharmony_ci} 240cb93a386Sopenharmony_ci 241cb93a386Sopenharmony_ciDEF_TEST(Codec_GifInterlacedTruncated, r) { 242cb93a386Sopenharmony_ci // Check that gInterlacedGIF is exactly 102 bytes long, and that the final 243cb93a386Sopenharmony_ci // 30 bytes, in the half-open range [72, 102), consists of 0x1b (indicating 244cb93a386Sopenharmony_ci // a block of 27 bytes), then those 27 bytes, then 0x00 (end of the blocks) 245cb93a386Sopenharmony_ci // then 0x3b (end of the GIF). 246cb93a386Sopenharmony_ci if ((sizeof(gInterlacedGIF) != 102) || 247cb93a386Sopenharmony_ci (gInterlacedGIF[72] != 0x1b) || 248cb93a386Sopenharmony_ci (gInterlacedGIF[100] != 0x00) || 249cb93a386Sopenharmony_ci (gInterlacedGIF[101] != 0x3b)) { 250cb93a386Sopenharmony_ci ERRORF(r, "Invalid gInterlacedGIF data"); 251cb93a386Sopenharmony_ci return; 252cb93a386Sopenharmony_ci } 253cb93a386Sopenharmony_ci 254cb93a386Sopenharmony_ci // We want to test the GIF codec's output on some (but not all) of the 255cb93a386Sopenharmony_ci // LZW-compressed data. As is, there is only one block of LZW-compressed 256cb93a386Sopenharmony_ci // data, 27 bytes long. Wuffs can output partial results from a partial 257cb93a386Sopenharmony_ci // block, but some other GIF implementations output intermediate rows only 258cb93a386Sopenharmony_ci // on block boundaries, so truncating to a prefix of gInterlacedGIF isn't 259cb93a386Sopenharmony_ci // enough. We also have to modify the block size down from 0x1b so that the 260cb93a386Sopenharmony_ci // edited version still contains a complete block. In this case, it's a 261cb93a386Sopenharmony_ci // block of 10 bytes. 262cb93a386Sopenharmony_ci unsigned char data[83]; 263cb93a386Sopenharmony_ci memcpy(data, gInterlacedGIF, sizeof(data)); 264cb93a386Sopenharmony_ci data[72] = sizeof(data) - 73; 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci // Just like test_interlaced_gif_data, check that we get a 9x9 image. 267cb93a386Sopenharmony_ci SkBitmap bm; 268cb93a386Sopenharmony_ci bool imageDecodeSuccess = decode_memory(data, sizeof(data), &bm); 269cb93a386Sopenharmony_ci REPORTER_ASSERT(r, imageDecodeSuccess); 270cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.width() == 9); 271cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.height() == 9); 272cb93a386Sopenharmony_ci 273cb93a386Sopenharmony_ci // For an interlaced, non-transparent image, we thicken or replicate the 274cb93a386Sopenharmony_ci // rows of earlier interlace passes so that, when e.g. decoding a GIF 275cb93a386Sopenharmony_ci // sourced from a slow network connection, we show a richer intermediate 276cb93a386Sopenharmony_ci // image while waiting for the complete image. This replication is 277cb93a386Sopenharmony_ci // sometimes described as a "Haeberli inspired technique". 278cb93a386Sopenharmony_ci // 279cb93a386Sopenharmony_ci // For a 9 pixel high image, interlacing shuffles the row order to be: 0, 280cb93a386Sopenharmony_ci // 8, 4, 2, 6, 1, 3, 5, 7. Even though truncating to 10 bytes of 281cb93a386Sopenharmony_ci // LZW-compressed data only explicitly contains completed rows 0 and 8, we 282cb93a386Sopenharmony_ci // still expect row 7 to be set, due to replication, and therefore not 283cb93a386Sopenharmony_ci // transparent black (zero). 284cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 7) != 0); 285cb93a386Sopenharmony_ci} 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_ci// Regression test for decoding a gif image with sampleSize of 4, which was 288cb93a386Sopenharmony_ci// previously crashing. 289cb93a386Sopenharmony_ciDEF_TEST(Gif_Sampled, r) { 290cb93a386Sopenharmony_ci auto data = GetResourceAsData("images/test640x479.gif"); 291cb93a386Sopenharmony_ci REPORTER_ASSERT(r, data); 292cb93a386Sopenharmony_ci if (!data) { 293cb93a386Sopenharmony_ci return; 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci std::unique_ptr<SkStreamAsset> stream(new SkMemoryStream(std::move(data))); 296cb93a386Sopenharmony_ci std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromStream(std::move(stream))); 297cb93a386Sopenharmony_ci REPORTER_ASSERT(r, codec); 298cb93a386Sopenharmony_ci if (!codec) { 299cb93a386Sopenharmony_ci return; 300cb93a386Sopenharmony_ci } 301cb93a386Sopenharmony_ci 302cb93a386Sopenharmony_ci SkAndroidCodec::AndroidOptions options; 303cb93a386Sopenharmony_ci options.fSampleSize = 4; 304cb93a386Sopenharmony_ci 305cb93a386Sopenharmony_ci SkBitmap bm; 306cb93a386Sopenharmony_ci bm.allocPixels(codec->getInfo()); 307cb93a386Sopenharmony_ci const SkCodec::Result result = codec->getAndroidPixels(codec->getInfo(), bm.getPixels(), 308cb93a386Sopenharmony_ci bm.rowBytes(), &options); 309cb93a386Sopenharmony_ci REPORTER_ASSERT(r, result == SkCodec::kSuccess); 310cb93a386Sopenharmony_ci} 311cb93a386Sopenharmony_ci 312cb93a386Sopenharmony_ci// If a GIF file is truncated before the header for the first image is defined, 313cb93a386Sopenharmony_ci// we should not create an SkCodec. 314cb93a386Sopenharmony_ciDEF_TEST(Codec_GifTruncated, r) { 315cb93a386Sopenharmony_ci sk_sp<SkData> data(GetResourceAsData("images/test640x479.gif")); 316cb93a386Sopenharmony_ci if (!data) { 317cb93a386Sopenharmony_ci return; 318cb93a386Sopenharmony_ci } 319cb93a386Sopenharmony_ci 320cb93a386Sopenharmony_ci // This is right before the header for the first image. 321cb93a386Sopenharmony_ci data = SkData::MakeSubset(data.get(), 0, 446); 322cb93a386Sopenharmony_ci std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data)); 323cb93a386Sopenharmony_ci REPORTER_ASSERT(r, !codec); 324cb93a386Sopenharmony_ci} 325cb93a386Sopenharmony_ci 326cb93a386Sopenharmony_ci/* 327cb93a386Sopenharmony_ciFor the Codec_GifTruncated2 test, immediately below, 328cb93a386Sopenharmony_ciresources/images/box.gif's first 23 bytes are: 329cb93a386Sopenharmony_ci 330cb93a386Sopenharmony_ci00000000: 4749 4638 3961 c800 3700 203f 002c 0000 GIF89a..7. ?.,.. 331cb93a386Sopenharmony_ci00000010: 0000 c800 3700 85 ....7.. 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_ciThe breakdown: 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci@000 6 bytes magic "GIF89a" 336cb93a386Sopenharmony_ci@006 7 bytes Logical Screen Descriptor: 0xC8 0x00 ... 0x00 337cb93a386Sopenharmony_ci - width = 200 338cb93a386Sopenharmony_ci - height = 55 339cb93a386Sopenharmony_ci - flags = 0x20 340cb93a386Sopenharmony_ci - background color index, pixel aspect ratio bytes ignored 341cb93a386Sopenharmony_ci@00D 10 bytes Image Descriptor header: 0x2C 0x00 ... 0x85 342cb93a386Sopenharmony_ci - origin_x = 0 343cb93a386Sopenharmony_ci - origin_y = 0 344cb93a386Sopenharmony_ci - width = 200 345cb93a386Sopenharmony_ci - height = 55 346cb93a386Sopenharmony_ci - flags = 0x85, local color table, 64 RGB entries 347cb93a386Sopenharmony_ci 348cb93a386Sopenharmony_ciIn particular, 23 bytes is after the header, but before the color table. 349cb93a386Sopenharmony_ci*/ 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ciDEF_TEST(Codec_GifTruncated2, r) { 352cb93a386Sopenharmony_ci // Truncate box.gif at 21, 22 and 23 bytes. 353cb93a386Sopenharmony_ci // 354cb93a386Sopenharmony_ci // See also Codec_GifTruncated3 in this file, below. 355cb93a386Sopenharmony_ci // 356cb93a386Sopenharmony_ci // See also Codec_trunc in CodecAnimTest.cpp for this magic 23. 357cb93a386Sopenharmony_ci // 358cb93a386Sopenharmony_ci // See also Codec_GifPreMap in CodecPartialTest.cpp for this magic 23. 359cb93a386Sopenharmony_ci for (int i = 21; i < 24; i++) { 360cb93a386Sopenharmony_ci sk_sp<SkData> data(GetResourceAsData("images/box.gif")); 361cb93a386Sopenharmony_ci if (!data) { 362cb93a386Sopenharmony_ci return; 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_ci data = SkData::MakeSubset(data.get(), 0, i); 366cb93a386Sopenharmony_ci std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data)); 367cb93a386Sopenharmony_ci 368cb93a386Sopenharmony_ci if (i <= 21) { 369cb93a386Sopenharmony_ci if (codec) { 370cb93a386Sopenharmony_ci ERRORF(r, "Invalid data gave non-nullptr codec"); 371cb93a386Sopenharmony_ci } 372cb93a386Sopenharmony_ci return; 373cb93a386Sopenharmony_ci } 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_ci if (!codec) { 376cb93a386Sopenharmony_ci ERRORF(r, "Failed to create codec with partial data (truncated at %d)", i); 377cb93a386Sopenharmony_ci return; 378cb93a386Sopenharmony_ci } 379cb93a386Sopenharmony_ci 380cb93a386Sopenharmony_ci#ifdef SK_HAS_WUFFS_LIBRARY 381cb93a386Sopenharmony_ci // We are transitioning from an old GIF implementation to a new (Wuffs) 382cb93a386Sopenharmony_ci // GIF implementation. 383cb93a386Sopenharmony_ci // 384cb93a386Sopenharmony_ci // The input is truncated in the Image Descriptor, before the local 385cb93a386Sopenharmony_ci // color table, and before (21) or after (22, 23) the first frame's 386cb93a386Sopenharmony_ci // XYWH (left / top / width / height) can be decoded. A detailed 387cb93a386Sopenharmony_ci // breakdown of those 23 bytes is in a comment above this function. 388cb93a386Sopenharmony_ci // 389cb93a386Sopenharmony_ci // With the old implementation, this test claimed that "no frame is 390cb93a386Sopenharmony_ci // complete enough that it has its metadata". In terms of the 391cb93a386Sopenharmony_ci // underlying file format, this claim is true for truncating at 21 392cb93a386Sopenharmony_ci // bytes, but not true for 22 or 23. 393cb93a386Sopenharmony_ci // 394cb93a386Sopenharmony_ci // At 21 bytes, both the old and new implementation's MakeFromStream 395cb93a386Sopenharmony_ci // factory method returns a nullptr SkCodec*, because creating a 396cb93a386Sopenharmony_ci // SkCodec requires knowing the image width and height (as its 397cb93a386Sopenharmony_ci // constructor takes an SkEncodedInfo argument), and specifically for 398cb93a386Sopenharmony_ci // GIF, decoding the image width and height requires decoding the first 399cb93a386Sopenharmony_ci // frame's XYWH, as per 400cb93a386Sopenharmony_ci // https://raw.githubusercontent.com/google/wuffs/master/test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt 401cb93a386Sopenharmony_ci // 402cb93a386Sopenharmony_ci // At 22 or 23 bytes, the first frame is complete enough that we can 403cb93a386Sopenharmony_ci // fill in all of a SkCodec::FrameInfo's fields (other than 404cb93a386Sopenharmony_ci // fFullyReceived). Specifically, we can fill in fRequiredFrame and 405cb93a386Sopenharmony_ci // fAlphaType, even though we haven't yet decoded the frame's RGB 406cb93a386Sopenharmony_ci // palette entries, as we do know the frame rectangle and that every 407cb93a386Sopenharmony_ci // palette entry is fully opaque, due to the lack of a Graphic Control 408cb93a386Sopenharmony_ci // Extension before the Image Descriptor. 409cb93a386Sopenharmony_ci // 410cb93a386Sopenharmony_ci // The new implementation correctly reports that the first frame's 411cb93a386Sopenharmony_ci // metadata is complete enough. The old implementation does not. 412cb93a386Sopenharmony_ci // 413cb93a386Sopenharmony_ci // Once the transition is complete, we can remove the #ifdef and delete 414cb93a386Sopenharmony_ci // the #else code. 415cb93a386Sopenharmony_ci REPORTER_ASSERT(r, codec->getFrameCount() == 1); 416cb93a386Sopenharmony_ci#else 417cb93a386Sopenharmony_ci // The old implementation claimed: 418cb93a386Sopenharmony_ci // 419cb93a386Sopenharmony_ci // Although we correctly created a codec, no frame is 420cb93a386Sopenharmony_ci // complete enough that it has its metadata. Returning 0 421cb93a386Sopenharmony_ci // ensures that Chromium will not try to create a frame 422cb93a386Sopenharmony_ci // too early. 423cb93a386Sopenharmony_ci REPORTER_ASSERT(r, codec->getFrameCount() == 0); 424cb93a386Sopenharmony_ci#endif 425cb93a386Sopenharmony_ci } 426cb93a386Sopenharmony_ci} 427cb93a386Sopenharmony_ci 428cb93a386Sopenharmony_ci#ifdef SK_HAS_WUFFS_LIBRARY 429cb93a386Sopenharmony_ci// This tests that, after truncating the input, the pixels are still 430cb93a386Sopenharmony_ci// zero-initialized. If you comment out the SkSampler::Fill call in 431cb93a386Sopenharmony_ci// SkWuffsCodec::onStartIncrementalDecode, the test could still pass (in a 432cb93a386Sopenharmony_ci// standard configuration) but should fail with the MSAN memory sanitizer. 433cb93a386Sopenharmony_ciDEF_TEST(Codec_GifTruncated3, r) { 434cb93a386Sopenharmony_ci sk_sp<SkData> data(GetResourceAsData("images/box.gif")); 435cb93a386Sopenharmony_ci if (!data) { 436cb93a386Sopenharmony_ci return; 437cb93a386Sopenharmony_ci } 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci data = SkData::MakeSubset(data.get(), 0, 23); 440cb93a386Sopenharmony_ci sk_sp<SkImage> image(SkImage::MakeFromEncoded(data)); 441cb93a386Sopenharmony_ci 442cb93a386Sopenharmony_ci if (!image) { 443cb93a386Sopenharmony_ci ERRORF(r, "Missing image"); 444cb93a386Sopenharmony_ci return; 445cb93a386Sopenharmony_ci } 446cb93a386Sopenharmony_ci 447cb93a386Sopenharmony_ci REPORTER_ASSERT(r, image->width() == 200); 448cb93a386Sopenharmony_ci REPORTER_ASSERT(r, image->height() == 55); 449cb93a386Sopenharmony_ci 450cb93a386Sopenharmony_ci SkBitmap bm; 451cb93a386Sopenharmony_ci if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(200, 55))) { 452cb93a386Sopenharmony_ci ERRORF(r, "Failed to allocate pixels"); 453cb93a386Sopenharmony_ci return; 454cb93a386Sopenharmony_ci } 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_ci bm.eraseColor(SK_ColorTRANSPARENT); 457cb93a386Sopenharmony_ci 458cb93a386Sopenharmony_ci SkCanvas canvas(bm); 459cb93a386Sopenharmony_ci canvas.drawImage(image, 0, 0); 460cb93a386Sopenharmony_ci 461cb93a386Sopenharmony_ci for (int i = 0; i < image->width(); ++i) 462cb93a386Sopenharmony_ci for (int j = 0; j < image->height(); ++j) { 463cb93a386Sopenharmony_ci SkColor actual = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(i, j)); 464cb93a386Sopenharmony_ci if (actual != SK_ColorTRANSPARENT) { 465cb93a386Sopenharmony_ci ERRORF(r, "did not initialize pixels! %i, %i is %x", i, j, actual); 466cb93a386Sopenharmony_ci } 467cb93a386Sopenharmony_ci } 468cb93a386Sopenharmony_ci} 469cb93a386Sopenharmony_ci#endif 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ciDEF_TEST(Codec_gif_out_of_palette, r) { 472cb93a386Sopenharmony_ci if (GetResourcePath().isEmpty()) { 473cb93a386Sopenharmony_ci return; 474cb93a386Sopenharmony_ci } 475cb93a386Sopenharmony_ci 476cb93a386Sopenharmony_ci const char* path = "images/out-of-palette.gif"; 477cb93a386Sopenharmony_ci auto data = GetResourceAsData(path); 478cb93a386Sopenharmony_ci if (!data) { 479cb93a386Sopenharmony_ci ERRORF(r, "failed to find %s", path); 480cb93a386Sopenharmony_ci return; 481cb93a386Sopenharmony_ci } 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci auto codec = SkCodec::MakeFromData(std::move(data)); 484cb93a386Sopenharmony_ci if (!codec) { 485cb93a386Sopenharmony_ci ERRORF(r, "Could not create codec from %s", path); 486cb93a386Sopenharmony_ci return; 487cb93a386Sopenharmony_ci } 488cb93a386Sopenharmony_ci 489cb93a386Sopenharmony_ci SkBitmap bm; 490cb93a386Sopenharmony_ci bm.allocPixels(codec->getInfo()); 491cb93a386Sopenharmony_ci auto result = codec->getPixels(bm.pixmap()); 492cb93a386Sopenharmony_ci REPORTER_ASSERT(r, result == SkCodec::kSuccess, "Failed to decode %s with error %s", 493cb93a386Sopenharmony_ci path, SkCodec::ResultToString(result)); 494cb93a386Sopenharmony_ci 495cb93a386Sopenharmony_ci struct { 496cb93a386Sopenharmony_ci int x; 497cb93a386Sopenharmony_ci int y; 498cb93a386Sopenharmony_ci SkColor expected; 499cb93a386Sopenharmony_ci } pixels[] = { 500cb93a386Sopenharmony_ci { 0, 0, SK_ColorBLACK }, 501cb93a386Sopenharmony_ci { 1, 0, SK_ColorWHITE }, 502cb93a386Sopenharmony_ci { 0, 1, SK_ColorTRANSPARENT }, 503cb93a386Sopenharmony_ci { 1, 1, SK_ColorTRANSPARENT }, 504cb93a386Sopenharmony_ci }; 505cb93a386Sopenharmony_ci for (auto& pixel : pixels) { 506cb93a386Sopenharmony_ci auto actual = bm.getColor(pixel.x, pixel.y); 507cb93a386Sopenharmony_ci REPORTER_ASSERT(r, actual == pixel.expected, 508cb93a386Sopenharmony_ci "pixel (%i,%i) mismatch! expected: %x actual: %x", 509cb93a386Sopenharmony_ci pixel.x, pixel.y, pixel.expected, actual); 510cb93a386Sopenharmony_ci } 511cb93a386Sopenharmony_ci} 512cb93a386Sopenharmony_ci 513cb93a386Sopenharmony_ci// This tests decoding the GIF image created by this script: 514cb93a386Sopenharmony_ci// https://raw.githubusercontent.com/google/wuffs/6c2fb9a2fd9e3334ee7dabc1ad60bfc89158084f/test/data/artificial/gif-transparent-index.gif.make-artificial.txt 515cb93a386Sopenharmony_ci// 516cb93a386Sopenharmony_ci// It is a 4x2 animated image with 2 frames. The first frame is full of various 517cb93a386Sopenharmony_ci// red pixels. The second frame overlays a 3x1 rectangle at (1, 1): light blue, 518cb93a386Sopenharmony_ci// transparent, dark blue. 519cb93a386Sopenharmony_ciDEF_TEST(Codec_AnimatedTransparentGif, r) { 520cb93a386Sopenharmony_ci const char* path = "images/gif-transparent-index.gif"; 521cb93a386Sopenharmony_ci auto data = GetResourceAsData(path); 522cb93a386Sopenharmony_ci if (!data) { 523cb93a386Sopenharmony_ci ERRORF(r, "failed to find %s", path); 524cb93a386Sopenharmony_ci return; 525cb93a386Sopenharmony_ci } 526cb93a386Sopenharmony_ci 527cb93a386Sopenharmony_ci auto codec = SkCodec::MakeFromData(std::move(data)); 528cb93a386Sopenharmony_ci if (!codec) { 529cb93a386Sopenharmony_ci ERRORF(r, "Could not create codec from %s", path); 530cb93a386Sopenharmony_ci return; 531cb93a386Sopenharmony_ci } 532cb93a386Sopenharmony_ci 533cb93a386Sopenharmony_ci SkImageInfo info = codec->getInfo(); 534cb93a386Sopenharmony_ci if ((info.width() != 4) || (info.height() != 2) || (codec->getFrameInfo().size() != 2)) { 535cb93a386Sopenharmony_ci ERRORF(r, "Unexpected image info"); 536cb93a386Sopenharmony_ci return; 537cb93a386Sopenharmony_ci } 538cb93a386Sopenharmony_ci 539cb93a386Sopenharmony_ci for (bool use565 : { false, true }) { 540cb93a386Sopenharmony_ci SkBitmap bm; 541cb93a386Sopenharmony_ci bm.allocPixels(use565 ? info.makeColorType(kRGB_565_SkColorType) : info); 542cb93a386Sopenharmony_ci 543cb93a386Sopenharmony_ci for (int i = 0; i < 2; i++) { 544cb93a386Sopenharmony_ci SkCodec::Options options; 545cb93a386Sopenharmony_ci options.fFrameIndex = i; 546cb93a386Sopenharmony_ci options.fPriorFrame = (i > 0) ? (i - 1) : SkCodec::kNoFrame; 547cb93a386Sopenharmony_ci auto result = codec->getPixels(bm.pixmap(), &options); 548cb93a386Sopenharmony_ci#ifdef SK_HAS_WUFFS_LIBRARY 549cb93a386Sopenharmony_ci // No-op. Wuffs' GIF decoder supports animated 565. 550cb93a386Sopenharmony_ci#else 551cb93a386Sopenharmony_ci if (use565 && i > 0) { 552cb93a386Sopenharmony_ci // Unsupported. Quoting libgifcodec/SkLibGifCodec.cpp: 553cb93a386Sopenharmony_ci // 554cb93a386Sopenharmony_ci // In theory, we might be able to support this, but it's not 555cb93a386Sopenharmony_ci // clear that it is necessary (Chromium does not decode to 565, 556cb93a386Sopenharmony_ci // and Android does not decode frames beyond the first). 557cb93a386Sopenharmony_ci REPORTER_ASSERT(r, result != SkCodec::kSuccess, 558cb93a386Sopenharmony_ci "Unexpected success to decode frame %i", i); 559cb93a386Sopenharmony_ci continue; 560cb93a386Sopenharmony_ci } 561cb93a386Sopenharmony_ci#endif 562cb93a386Sopenharmony_ci REPORTER_ASSERT(r, result == SkCodec::kSuccess, "Failed to decode frame %i", i); 563cb93a386Sopenharmony_ci 564cb93a386Sopenharmony_ci // Per above: the first frame is full of various red pixels. 565cb93a386Sopenharmony_ci SkColor expectedPixels[2][4] = { 566cb93a386Sopenharmony_ci { 0xFF800000, 0xFF900000, 0xFFA00000, 0xFFB00000 }, 567cb93a386Sopenharmony_ci { 0xFFC00000, 0xFFD00000, 0xFFE00000, 0xFFF00000 }, 568cb93a386Sopenharmony_ci }; 569cb93a386Sopenharmony_ci if (use565) { 570cb93a386Sopenharmony_ci // For kRGB_565_SkColorType, copy the red channel's high 3 bits 571cb93a386Sopenharmony_ci // to its low 3 bits. 572cb93a386Sopenharmony_ci expectedPixels[0][0] = 0xFF840000; 573cb93a386Sopenharmony_ci expectedPixels[0][1] = 0xFF940000; 574cb93a386Sopenharmony_ci expectedPixels[0][2] = 0xFFA50000; 575cb93a386Sopenharmony_ci expectedPixels[0][3] = 0xFFB50000; 576cb93a386Sopenharmony_ci expectedPixels[1][0] = 0xFFC60000; 577cb93a386Sopenharmony_ci expectedPixels[1][1] = 0xFFD60000; 578cb93a386Sopenharmony_ci expectedPixels[1][2] = 0xFFE70000; 579cb93a386Sopenharmony_ci expectedPixels[1][3] = 0xFFF70000; 580cb93a386Sopenharmony_ci } 581cb93a386Sopenharmony_ci if (i > 0) { 582cb93a386Sopenharmony_ci // Per above: the second frame overlays a 3x1 rectangle at (1, 583cb93a386Sopenharmony_ci // 1): light blue, transparent, dark blue. 584cb93a386Sopenharmony_ci // 585cb93a386Sopenharmony_ci // Again, for kRGB_565_SkColorType, copy the blue channel's 586cb93a386Sopenharmony_ci // high 3 bits to its low 3 bits. 587cb93a386Sopenharmony_ci expectedPixels[1][1] = use565 ? 0xFF0000FF : 0xFF0000FF; 588cb93a386Sopenharmony_ci expectedPixels[1][3] = use565 ? 0xFF000052 : 0xFF000055; 589cb93a386Sopenharmony_ci } 590cb93a386Sopenharmony_ci 591cb93a386Sopenharmony_ci for (int y = 0; y < 2; y++) { 592cb93a386Sopenharmony_ci for (int x = 0; x < 4; x++) { 593cb93a386Sopenharmony_ci auto expected = expectedPixels[y][x]; 594cb93a386Sopenharmony_ci auto actual = bm.getColor(x, y); 595cb93a386Sopenharmony_ci REPORTER_ASSERT(r, actual == expected, 596cb93a386Sopenharmony_ci "use565 %i, frame %i, pixel (%i,%i) " 597cb93a386Sopenharmony_ci "mismatch! expected: %x actual: %x", 598cb93a386Sopenharmony_ci (int)use565, i, x, y, expected, actual); 599cb93a386Sopenharmony_ci } 600cb93a386Sopenharmony_ci } 601cb93a386Sopenharmony_ci } 602cb93a386Sopenharmony_ci } 603cb93a386Sopenharmony_ci} 604cb93a386Sopenharmony_ci 605cb93a386Sopenharmony_ci// This test verifies that a GIF frame outside the image dimensions is handled 606cb93a386Sopenharmony_ci// as desired: 607cb93a386Sopenharmony_ci// - The image reports a size of 0 x 0, but the first frame is 100 x 90. The 608cb93a386Sopenharmony_ci// image (or "canvas") is expanded to fit the first frame. The first frame is red. 609cb93a386Sopenharmony_ci// - The second frame is a green 75 x 75 rectangle, reporting its x-offset and 610cb93a386Sopenharmony_ci// y-offset to be 105, placing it off screen. The decoder interprets this as no 611cb93a386Sopenharmony_ci// change from the first frame. 612cb93a386Sopenharmony_ciDEF_TEST(Codec_xOffsetTooBig, r) { 613cb93a386Sopenharmony_ci const char* path = "images/xOffsetTooBig.gif"; 614cb93a386Sopenharmony_ci auto data = GetResourceAsData(path); 615cb93a386Sopenharmony_ci if (!data) { 616cb93a386Sopenharmony_ci ERRORF(r, "failed to find %s", path); 617cb93a386Sopenharmony_ci return; 618cb93a386Sopenharmony_ci } 619cb93a386Sopenharmony_ci 620cb93a386Sopenharmony_ci auto codec = SkCodec::MakeFromData(std::move(data)); 621cb93a386Sopenharmony_ci if (!codec) { 622cb93a386Sopenharmony_ci ERRORF(r, "Could not create codec from %s", path); 623cb93a386Sopenharmony_ci return; 624cb93a386Sopenharmony_ci } 625cb93a386Sopenharmony_ci 626cb93a386Sopenharmony_ci REPORTER_ASSERT(r, codec->getFrameCount() == 2); 627cb93a386Sopenharmony_ci 628cb93a386Sopenharmony_ci auto info = codec->getInfo(); 629cb93a386Sopenharmony_ci REPORTER_ASSERT(r, info.width() == 100 && info.height() == 90); 630cb93a386Sopenharmony_ci 631cb93a386Sopenharmony_ci SkBitmap bm; 632cb93a386Sopenharmony_ci bm.allocPixels(info); 633cb93a386Sopenharmony_ci for (int i = 0; i < 2; i++) { 634cb93a386Sopenharmony_ci SkCodec::FrameInfo frameInfo; 635cb93a386Sopenharmony_ci REPORTER_ASSERT(r, codec->getFrameInfo(i, &frameInfo)); 636cb93a386Sopenharmony_ci 637cb93a386Sopenharmony_ci SkIRect expectedRect = i == 0 ? SkIRect{0, 0, 100, 90} : SkIRect{100, 90, 100, 90}; 638cb93a386Sopenharmony_ci REPORTER_ASSERT(r, expectedRect == frameInfo.fFrameRect); 639cb93a386Sopenharmony_ci 640cb93a386Sopenharmony_ci SkCodec::Options options; 641cb93a386Sopenharmony_ci options.fFrameIndex = i; 642cb93a386Sopenharmony_ci REPORTER_ASSERT(r, SkCodec::kSuccess == codec->getPixels(bm.pixmap(), &options)); 643cb93a386Sopenharmony_ci 644cb93a386Sopenharmony_ci REPORTER_ASSERT(r, bm.getColor(0, 0) == SK_ColorRED); 645cb93a386Sopenharmony_ci } 646cb93a386Sopenharmony_ci} 647