blob: 07a63474cf05abbed00ebbe01528db762fbf630e [file] [log] [blame]
Leon Scroggins III4c119452018-01-20 10:33:24 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkAndroidCodec.h"
9#include "SkAnimatedImage.h"
10#include "SkCanvas.h"
11#include "SkCodec.h"
12#include "SkUnPreMultiply.h"
13
14#include "CodecPriv.h"
15#include "Resources.h"
16#include "Test.h"
17#include "sk_tool_utils.h"
18
19#include <vector>
20
21DEF_TEST(AnimatedImage, r) {
22 if (GetResourcePath().isEmpty()) {
23 return;
24 }
25 for (const char* file : { "images/alphabetAnim.gif",
26 "images/colorTables.gif",
27 "images/webp-animated.webp",
28 "images/required.webp",
29 }) {
30 auto data = GetResourceAsData(file);
31 if (!data) {
32 ERRORF(r, "Could not get %s", file);
33 continue;
34 }
35
36 auto codec = SkCodec::MakeFromData(data);
37 if (!codec) {
38 ERRORF(r, "Could not create codec for %s", file);
39 continue;
40 }
41
42 const int defaultRepetitionCount = codec->getRepetitionCount();
43 std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
44 std::vector<SkBitmap> frames(frameInfos.size());
45 // Used down below for our test image.
46 const auto imageInfo = codec->getInfo().makeAlphaType(kPremul_SkAlphaType);
47
48 for (size_t i = 0; i < frameInfos.size(); ++i) {
49 auto info = codec->getInfo().makeAlphaType(frameInfos[i].fAlphaType);
50 auto& bm = frames[i];
51
52 SkCodec::Options options;
53 options.fFrameIndex = (int) i;
54 options.fPriorFrame = frameInfos[i].fRequiredFrame;
55 if (options.fPriorFrame == SkCodec::kNone) {
56 bm.allocPixels(info);
57 bm.eraseColor(0);
58 } else {
59 const SkBitmap& priorFrame = frames[options.fPriorFrame];
60 if (!sk_tool_utils::copy_to(&bm, priorFrame.colorType(), priorFrame)) {
61 ERRORF(r, "Failed to copy %s frame %i", file, options.fPriorFrame);
62 options.fPriorFrame = SkCodec::kNone;
63 }
64 REPORTER_ASSERT(r, bm.setAlphaType(frameInfos[i].fAlphaType));
65 }
66
67 auto result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(), &options);
68 if (result != SkCodec::kSuccess) {
69 ERRORF(r, "error in %s frame %zu: %s", file, i, SkCodec::ResultToString(result));
70 }
71 }
72
73 auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
74 if (!androidCodec) {
75 ERRORF(r, "Could not create androidCodec for %s", file);
76 continue;
77 }
78
79 auto animatedImage = SkAnimatedImage::Make(std::move(androidCodec));
80 if (!animatedImage) {
81 ERRORF(r, "Could not create animated image for %s", file);
82 continue;
83 }
84
Leon Scroggins IIIabe639c2018-01-26 11:06:12 -050085 REPORTER_ASSERT(r, defaultRepetitionCount == animatedImage->getRepetitionCount());
86
Leon Scroggins III4c119452018-01-20 10:33:24 -050087 auto testDraw = [r, &frames, &imageInfo, file](const sk_sp<SkAnimatedImage>& animatedImage,
88 int expectedFrame) {
89 SkBitmap test;
90 test.allocPixels(imageInfo);
91 test.eraseColor(0);
92 SkCanvas c(test);
93 animatedImage->draw(&c);
94
95 const SkBitmap& frame = frames[expectedFrame];
96 REPORTER_ASSERT(r, frame.colorType() == test.colorType());
97 REPORTER_ASSERT(r, frame.dimensions() == test.dimensions());
98 for (int i = 0; i < test.width(); ++i)
99 for (int j = 0; j < test.height(); ++j) {
100 SkColor expected = SkUnPreMultiply::PMColorToColor(*frame.getAddr32(i, j));
101 SkColor actual = SkUnPreMultiply::PMColorToColor(*test .getAddr32(i, j));
102 if (expected != actual) {
103 ERRORF(r, "frame %i of %s does not match at pixel %i, %i!"
104 " expected %x\tactual: %x",
105 expectedFrame, file, i, j, expected, actual);
106 SkString expected_name = SkStringPrintf("expected_%c", '0' + expectedFrame);
107 SkString actual_name = SkStringPrintf("actual_%c", '0' + expectedFrame);
108 write_bm(expected_name.c_str(), frame);
109 write_bm(actual_name.c_str(), test);
110 return false;
111 }
112 }
113 return true;
114 };
115
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500116 REPORTER_ASSERT(r, animatedImage->currentFrameDuration() == frameInfos[0].fDuration);
117
Leon Scroggins III4c119452018-01-20 10:33:24 -0500118 if (!testDraw(animatedImage, 0)) {
119 ERRORF(r, "Did not start with frame 0");
120 continue;
121 }
122
Leon Scroggins III4c119452018-01-20 10:33:24 -0500123 // Start at an arbitrary time.
Leon Scroggins III4c119452018-01-20 10:33:24 -0500124 bool failed = false;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500125 for (size_t i = 1; i < frameInfos.size(); ++i) {
126 const int frameTime = animatedImage->decodeNextFrame();
127 REPORTER_ASSERT(r, frameTime == animatedImage->currentFrameDuration());
128
Leon Scroggins III4c119452018-01-20 10:33:24 -0500129 if (i == frameInfos.size() - 1 && defaultRepetitionCount == 0) {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500130 REPORTER_ASSERT(r, frameTime == SkAnimatedImage::kFinished);
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500131 REPORTER_ASSERT(r, animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500132 } else {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500133 REPORTER_ASSERT(r, frameTime == frameInfos[i].fDuration);
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500134 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500135 }
136
137 if (!testDraw(animatedImage, i)) {
138 ERRORF(r, "Did not update to %i properly", i);
139 failed = true;
140 break;
141 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500142 }
143
144 if (failed) {
145 continue;
146 }
147
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500148 animatedImage->reset();
149 REPORTER_ASSERT(r, !animatedImage->isFinished());
150 if (!testDraw(animatedImage, 0)) {
151 ERRORF(r, "reset failed");
152 continue;
153 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500154
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500155 // Test reset from all the frames.
156 // j is the frame to call reset on.
157 for (int j = 0; j < (int) frameInfos.size(); ++j) {
158 if (failed) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500159 break;
160 }
161
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500162 // i is the frame to decode.
163 for (int i = 0; i <= j; ++i) {
164 if (i == j) {
165 animatedImage->reset();
166 if (!testDraw(animatedImage, 0)) {
167 ERRORF(r, "reset failed for image %s from frame %i",
168 file, i);
169 failed = true;
170 break;
171 }
172 } else if (i != 0) {
173 animatedImage->decodeNextFrame();
174 if (!testDraw(animatedImage, i)) {
175 ERRORF(r, "failed to match frame %i in %s on iteration %i",
176 i, file, j);
177 failed = true;
178 break;
179 }
180 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500181 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500182 }
183
184 if (failed) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500185 continue;
186 }
187
188 for (int loopCount : { 0, 1, 2, 5 }) {
189 animatedImage = SkAnimatedImage::Make(SkAndroidCodec::MakeFromCodec(
190 SkCodec::MakeFromData(data)));
Leon Scroggins III4c119452018-01-20 10:33:24 -0500191 animatedImage->setRepetitionCount(loopCount);
Leon Scroggins IIIabe639c2018-01-26 11:06:12 -0500192 REPORTER_ASSERT(r, animatedImage->getRepetitionCount() == loopCount);
193
Leon Scroggins III4c119452018-01-20 10:33:24 -0500194 for (int loops = 0; loops <= loopCount; loops++) {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500195 if (failed) {
196 break;
197 }
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500198 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500199 for (size_t i = 1; i <= frameInfos.size(); ++i) {
200 const int frameTime = animatedImage->decodeNextFrame();
201 if (frameTime == SkAnimatedImage::kFinished) {
202 if (loops != loopCount) {
203 ERRORF(r, "%s animation stopped early: loops: %i\tloopCount: %i",
204 file, loops, loopCount);
205 failed = true;
206 }
207 if (i != frameInfos.size() - 1) {
208 ERRORF(r, "%s animation stopped early: i: %i\tsize: %i",
209 file, i, frameInfos.size());
210 failed = true;
211 }
212 break;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500213 }
214 }
215 }
Leon Scroggins III8524c302018-01-22 12:31:21 -0500216
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500217 if (!animatedImage->isFinished()) {
218 ERRORF(r, "%s animation should have finished with specified loop count (%i)",
219 file, loopCount);
220 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500221 }
222 }
223}