31#include <initializer_list>
91 T expected,
T actual) {
92 REPORTER_ASSERT(r, expected == actual,
"%s's frame %i has wrong %s! expected:"
111 static const struct {
116 std::vector<int> fRequiredFrames;
118 std::vector<SkAlphaType> fAlphas;
121 std::vector<int> fDurations;
122 int fRepetitionCount;
123 std::vector<SkCodecAnimation::DisposalMethod> fDisposalMethods;
124 std::vector<bool> fAlphaWithinBounds;
125 std::vector<SkCodecAnimation::Blend> fBlends;
126 std::vector<SkIRect> fFrameRects;
128 {
"images/required.gif", 7,
129 { 0, 1, 2, 3, 4, 5 },
131 { 100, 100, 100, 100, 100, 100, 100 },
133 { kKeep, kRestoreBG, kKeep, kKeep, kKeep, kRestoreBG, kKeep },
134 {
false,
true,
true,
true,
true,
true,
true },
135 { kSrcOver, kSrcOver, kSrcOver, kSrcOver, kSrcOver, kSrcOver,
137 { {0, 0, 100, 100}, {0, 0, 75, 75}, {0, 0, 50, 50}, {0, 0, 60, 60},
138 {0, 0, 100, 100}, {0, 0, 50, 50}, {0, 0, 75, 75}},
140 {
"images/alphabetAnim.gif", 13,
141 { kNoFrame, 0, 0, 0, 0, 5, 6, kNoFrame, kNoFrame, 9, 10, 11 },
144 { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 },
146 { kKeep, kRestorePrev, kRestorePrev, kRestorePrev, kRestorePrev,
147 kRestoreBG, kKeep, kRestoreBG, kRestoreBG, kKeep, kKeep,
149 {
true,
false,
true,
false,
true,
true,
true,
true,
true,
true,
true,
true,
true },
150 { kSrcOver, kSrcOver, kSrcOver, kSrcOver, kSrcOver, kSrcOver,
151 kSrcOver, kSrcOver, kSrcOver, kSrcOver, kSrcOver, kSrcOver,
153 { {25, 25, 75, 75}, {25, 25, 75, 75}, {25, 25, 75, 75}, {37, 37, 62, 62},
154 {37, 37, 62, 62}, {25, 25, 75, 75}, {0, 0, 50, 50}, {0, 0, 100, 100},
155 {25, 25, 75, 75}, {25, 25, 75, 75}, {0, 0, 100, 100}, {25, 25, 75, 75},
158 {
"images/randPixelsAnim2.gif", 4,
162 { kOpaque, kOpaque, kOpaque },
164 { 0, 1000, 170, 40 },
167 { kKeep, kKeep, kRestorePrev, kKeep },
168 {
false,
true,
false,
false },
169 { kSrcOver, kSrcOver, kSrcOver, kSrcOver },
170 { {0, 0, 8, 8}, {6, 6, 8, 8}, {4, 4, 8, 8}, {7, 0, 8, 8} },
172 {
"images/randPixelsAnim.gif", 13,
174 { 0, 1, 2, 3, 4, 3, 6, 7, 7, 7, 9, 9 },
178 { 0, 1000, 170, 40, 220, 7770, 90, 90, 90, 90, 90, 90, 90 },
181 { kKeep, kKeep, kKeep, kKeep, kRestoreBG, kRestoreBG, kRestoreBG,
182 kRestoreBG, kRestorePrev, kRestoreBG, kRestorePrev, kRestorePrev,
184 {
false,
true,
true,
false,
true,
true,
false,
false,
true,
true,
false,
false,
186 { kSrcOver, kSrcOver, kSrcOver, kSrcOver, kSrcOver, kSrcOver,
187 kSrcOver, kSrcOver, kSrcOver, kSrcOver, kSrcOver, kSrcOver,
189 { {4, 4, 12, 12}, {4, 4, 12, 12}, {4, 4, 12, 12}, {0, 0, 8, 8}, {8, 8, 16, 16},
190 {8, 8, 16, 16}, {8, 8, 16, 16}, {2, 2, 10, 10}, {7, 7, 15, 15}, {7, 7, 15, 15},
191 {7, 7, 15, 15}, {0, 0, 8, 8}, {14, 14, 16, 16} },
193 {
"images/box.gif", 1, {}, {}, {},
SkCodec::kRepetitionCountInfinite, { kKeep }, {}, {}, {} },
194 {
"images/color_wheel.gif", 1, {}, {}, {},
SkCodec::kRepetitionCountInfinite, { kKeep }, {}, {}, {} },
195 {
"images/test640x479.gif", 4, { 0, 1, 2 },
196 { kOpaque, kOpaque, kOpaque },
197 { 200, 200, 200, 200 },
199 { kKeep, kKeep, kKeep, kKeep },
200 {
false,
true,
true,
true },
201 { kSrcOver, kSrcOver, kSrcOver, kSrcOver },
202 { {0, 0, 640, 479}, {0, 0, 640, 479}, {0, 0, 640, 479}, {0, 0, 640, 479} },
204 {
"images/colorTables.gif", 2, { 0 }, { kOpaque }, { 1000, 1000 }, 5,
205 { kKeep, kKeep }, {
false,
true}, { kSrcOver, kSrcOver },
206 { {0, 0, 640, 400}, {0, 0, 640, 200}},
209 {
"images/arrow.png", 1, {}, {}, {}, 0, {}, {}, {}, {} },
210 {
"images/google_chrome.ico", 1, {}, {}, {}, 0, {}, {}, {}, {} },
211 {
"images/brickwork-texture.jpg", 1, {}, {}, {}, 0, {}, {}, {}, {} },
212#if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
213 {
"images/dng_with_preview.dng", 1, {}, {}, {}, 0, {}, {}, {}, {} },
215 {
"images/mandrill.wbmp", 1, {}, {}, {}, 0, {}, {}, {}, {} },
216 {
"images/randPixels.bmp", 1, {}, {}, {}, 0, {}, {}, {}, {} },
217 {
"images/yellow_rose.webp", 1, {}, {}, {}, 0, {}, {}, {}, {} },
218 {
"images/stoplight.webp", 3, { 0, 1 }, { kOpaque, kOpaque },
220 { kKeep, kKeep, kKeep }, {
false,
false,
false},
221 {kSrcOver, kSrcOver, kSrcOver},
222 { {0, 0, 11, 29}, {2, 10, 9, 27}, {2, 2, 9, 18}},
224 {
"images/blendBG.webp", 7,
225 { 0, kNoFrame, kNoFrame, kNoFrame, 4, 4 },
227 { 525, 500, 525, 437, 609, 729, 444 },
229 { kKeep, kKeep, kKeep, kKeep, kKeep, kKeep, kKeep },
230 {
false,
true,
false,
true,
false,
true,
true },
231 { kSrc, kSrcOver, kSrc, kSrc, kSrc, kSrc, kSrc },
232 { {0, 0, 200, 200}, {0, 0, 200, 200}, {0, 0, 200, 200}, {0, 0, 200, 200},
233 {0, 0, 200, 200}, {100, 100, 200, 200}, {100, 100, 200, 200} },
235 {
"images/required.webp", 7,
236 { 0, 1, 1, kNoFrame, 4, 4 },
238 { 100, 100, 100, 100, 100, 100, 100 },
240 { kKeep, kRestoreBG, kKeep, kKeep, kKeep, kRestoreBG, kKeep },
241 {
false,
false,
false,
false,
false,
false,
false },
242 { kSrc, kSrcOver, kSrcOver, kSrcOver, kSrc, kSrcOver,
244 { {0, 0, 100, 100}, {0, 0, 75, 75}, {0, 0, 50, 50}, {0, 0, 60, 60},
245 {0, 0, 100, 100}, {0, 0, 50, 50}, {0, 0, 75, 75}},
249 for (
const auto& rec : gRecs) {
260 ERRORF(r,
"Failed to create an SkCodec from '%s'", rec.fName);
269 const int expected = rec.fFrameCount;
270 if (rec.fRequiredFrames.size() + 1 !=
static_cast<size_t>(expected)) {
271 ERRORF(r,
"'%s' has wrong number entries in fRequiredFrames; expected: %i\tactual: %zu",
272 rec.fName, expected - 1, rec.fRequiredFrames.size());
277 if (rec.fDurations.size() !=
static_cast<size_t>(expected)) {
278 ERRORF(r,
"'%s' has wrong number entries in fDurations; expected: %i\tactual: %zu",
279 rec.fName, expected, rec.fDurations.size());
283 if (rec.fAlphas.size() + 1 !=
static_cast<size_t>(expected)) {
284 ERRORF(r,
"'%s' has wrong number entries in fAlphas; expected: %i\tactual: %zu",
285 rec.fName, expected - 1, rec.fAlphas.size());
289 if (rec.fDisposalMethods.size() !=
static_cast<size_t>(expected)) {
290 ERRORF(r,
"'%s' has wrong number entries in fDisposalMethods; "
291 "expected %i\tactual: %zu",
292 rec.fName, expected, rec.fDisposalMethods.size());
297 enum class TestMode {
302 for (
auto mode : { TestMode::kVector, TestMode::kIndividual }) {
307 std::vector<SkCodec::FrameInfo> frameInfos;
309 case TestMode::kVector:
310 frameInfos = codec->getFrameInfo();
312 frameCount = frameInfos.empty() ? 1 : frameInfos.size();
314 case TestMode::kIndividual:
315 frameCount = codec->getFrameCount();
319 if (frameCount != expected) {
320 ERRORF(r,
"'%s' expected frame count: %i\tactual: %i",
321 rec.fName, expected, frameCount);
338 const int repetitionCount = codec->getRepetitionCount();
339 if (repetitionCount != rec.fRepetitionCount) {
340 ERRORF(r,
"%s repetition count does not match! expected: %i\tactual: %i",
341 rec.fName, rec.fRepetitionCount, repetitionCount);
345 if (1 == frameCount) {
349 for (
int i = 0;
i < frameCount;
i++) {
352 case TestMode::kVector:
353 frameInfo = frameInfos[
i];
355 case TestMode::kIndividual:
361 if (rec.fDurations[
i] != frameInfo.
fDuration) {
362 ERRORF(r,
"%s frame %i's durations do not match! expected: %i\tactual: %i",
363 rec.fName,
i, rec.fDurations[
i], frameInfo.
fDuration);
378 auto expectedAlpha = 0 ==
i ? codec->getInfo().alphaType() : rec.fAlphas[
i-1];
380 if (expectedAlpha != alpha) {
381 ERRORF(r,
"%s's frame %i has wrong alpha type! expected: %s\tactual: %s",
388 ERRORF(r,
"%s's frame %i has wrong dependency! expected: %i\tactual: %i",
394 reporter_assert_equals<bool>(r, rec.fName,
i,
"alpha within bounds",
395 rec.fAlphaWithinBounds[
i],
398 reporter_assert_equals(r, rec.fName,
i,
"blend mode", rec.fBlends[
i],
401 reporter_assert_equals(r, rec.fName,
i,
"frame rect", rec.fFrameRects[
i],
405 if (TestMode::kIndividual ==
mode) {
417 std::vector<SkBitmap> cachedFrames(frameCount);
418 const auto info = codec->getInfo().makeColorType(kN32_SkColorType);
421 auto decodeInfo =
info;
442 ERRORF(r,
"Using a kRestorePrevious frame as fPriorFrame should fail");
446 ERRORF(r,
"Failed to decode frame %i from %s when providing prior frame %i, "
447 "error %i", index, rec.fName, cachedIndex,
result);
452 for (
int i = 0;
i < frameCount;
i++) {
457 const auto reqFrame = frameInfos[
i].fRequiredFrame;
462 for (
int j = reqFrame; j <
i; j++) {
473 const size_t rowLen =
info.bytesPerPixel() *
info.width();
474 for (
int y = 0;
y <
info.height();
y++) {
475 const void* cachedAddr = cachedFrame.
getAddr(0,
y);
479 const bool lineMatches = memcmp(cachedAddr,
addr, rowLen) == 0;
485 ERRORF(r,
"%s's frame %i is different (starting from line %i) when "
486 "providing prior frame %i!", rec.fName,
i,
y, j);
519 for (
int sampleSize : { 8, 32, 100 }) {
520 auto dimensions = codec->codec()->getScaledDimensions(1.0f / sampleSize);
521 info =
info.makeDimensions(dimensions);
526 for (
int i = 0;
i < codec->codec()->getFrameCount(); ++
i) {
550 for (
int y = 0;
y <
info.height(); ++
y) {
552 ERRORF(r,
"pixel mismatch for sample size %i, frame %i resulting in "
553 "dimensions %i x %i line %i\n",
554 sampleSize,
i,
info.width(),
info.height(),
y);
586#if defined(SK_ENABLE_SKOTTIE)
591 static constexpr struct {
596 {
"images/alphabetAnim.gif" , 1300, {100, 100} },
597 {
"images/randPixels.gif" , 0, { 8, 8} },
598 {
"images/randPixels.jpg" , 0, { 8, 8} },
599 {
"images/randPixels.png" , 0, { 8, 8} },
600 {
"images/stoplight.webp" , 2500, { 11, 29} },
601 {
"images/stoplight_h.webp" , 2500, { 29, 11} },
602 {
"images/orientation/1.webp", 0, {100, 80} },
603 {
"images/orientation/2.webp", 0, {100, 80} },
604 {
"images/orientation/3.webp", 0, {100, 80} },
605 {
"images/orientation/4.webp", 0, {100, 80} },
606 {
"images/orientation/5.webp", 0, {100, 80} },
607 {
"images/orientation/6.webp", 0, {100, 80} },
608 {
"images/orientation/7.webp", 0, {100, 80} },
609 {
"images/orientation/8.webp", 0, {100, 80} },
616 auto player = std::make_unique<SkAnimCodecPlayer>(std::move(codec));
620 auto f0 = player->getFrame();
623 "Mismatched size for initial frame of %s",
test.fFile);
626 auto f1 = player->getFrame();
629 "Mismatched size for frame at 500 ms of %s",
test.fFile);
static void test_animated_AndroidCodec(skiatest::Reporter *r, const char *file)
static bool restore_previous(const SkCodec::FrameInfo &info)
void write_bm(const char *name, const SkBitmap &bm)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static const TestCase gTests[]
sk_sp< SkData > GetResourceAsData(const char *resource)
SkString GetResourcePath(const char *resource)
@ kOpaque_SkAlphaType
pixel is opaque
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
@ kBottomLeft_SkEncodedOrigin
@ kLeftTop_SkEncodedOrigin
@ kTopRight_SkEncodedOrigin
@ kBottomRight_SkEncodedOrigin
@ kTopLeft_SkEncodedOrigin
@ kLeftBottom_SkEncodedOrigin
@ kRightBottom_SkEncodedOrigin
@ kRightTop_SkEncodedOrigin
static SkMatrix SkEncodedOriginToMatrix(SkEncodedOrigin origin, int w, int h)
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
#define REPORTER_ASSERT(r, cond,...)
static std::unique_ptr< SkAndroidCodec > MakeFromCodec(std::unique_ptr< SkCodec >)
void allocPixels(const SkImageInfo &info, size_t rowBytes)
void * getAddr(int x, int y) const
uint32_t * getAddr32(int x, int y) const
static std::unique_ptr< SkCodec > MakeFromData(sk_sp< SkData >, SkSpan< const SkCodecs::Decoder > decoders, SkPngChunkReader *=nullptr)
static constexpr int kRepetitionCountInfinite
static constexpr int kNoFrame
static sk_sp< SkData > MakeSubset(const SkData *src, size_t offset, size_t length)
static SkColor blend(SkColor dst, SkColor src, void(*mode)(float, float, float, float *, float *, float *))
unsigned useCenter Optional< SkMatrix > matrix
sk_sp< SkBlender > blender SkRect rect
DEF_SWITCHES_START aot vmservice shared library name
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
static SkString to_string(int n)
static DecodeResult decode(std::string path)
static SkScalar prop(SkScalar radius, SkScalar newSize, SkScalar oldSize)
SkCodecAnimation::DisposalMethod fDisposalMethod
SkCodecAnimation::Blend fBlend
bool fHasAlphaWithinBounds
std::shared_ptr< const fml::Mapping > data