blob: cbbef2ddd2342594ac5f562269baa8c54819be32 [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
85 auto testDraw = [r, &frames, &imageInfo, file](const sk_sp<SkAnimatedImage>& animatedImage,
86 int expectedFrame) {
87 SkBitmap test;
88 test.allocPixels(imageInfo);
89 test.eraseColor(0);
90 SkCanvas c(test);
91 animatedImage->draw(&c);
92
93 const SkBitmap& frame = frames[expectedFrame];
94 REPORTER_ASSERT(r, frame.colorType() == test.colorType());
95 REPORTER_ASSERT(r, frame.dimensions() == test.dimensions());
96 for (int i = 0; i < test.width(); ++i)
97 for (int j = 0; j < test.height(); ++j) {
98 SkColor expected = SkUnPreMultiply::PMColorToColor(*frame.getAddr32(i, j));
99 SkColor actual = SkUnPreMultiply::PMColorToColor(*test .getAddr32(i, j));
100 if (expected != actual) {
101 ERRORF(r, "frame %i of %s does not match at pixel %i, %i!"
102 " expected %x\tactual: %x",
103 expectedFrame, file, i, j, expected, actual);
104 SkString expected_name = SkStringPrintf("expected_%c", '0' + expectedFrame);
105 SkString actual_name = SkStringPrintf("actual_%c", '0' + expectedFrame);
106 write_bm(expected_name.c_str(), frame);
107 write_bm(actual_name.c_str(), test);
108 return false;
109 }
110 }
111 return true;
112 };
113
114 REPORTER_ASSERT(r, !animatedImage->isRunning());
115 if (!testDraw(animatedImage, 0)) {
116 ERRORF(r, "Did not start with frame 0");
117 continue;
118 }
119
120 animatedImage->start();
121 REPORTER_ASSERT(r, animatedImage->isRunning());
122 if (!testDraw(animatedImage, 0)) {
123 ERRORF(r, "After starting, still not on frame 0");
124 continue;
125 }
126
127 // Start at an arbitrary time.
128 double currentTime = 100000;
129 bool failed = false;
130 for (size_t i = 0; i < frameInfos.size(); ++i) {
131 double next = animatedImage->update(currentTime);
132 if (i == frameInfos.size() - 1 && defaultRepetitionCount == 0) {
Leon Scroggins III8524c302018-01-22 12:31:21 -0500133 REPORTER_ASSERT(r, next == SkAnimatedImage::kNotRunning);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500134 REPORTER_ASSERT(r, !animatedImage->isRunning());
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500135 REPORTER_ASSERT(r, animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500136 } else {
137 REPORTER_ASSERT(r, animatedImage->isRunning());
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500138 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500139 double expectedNext = currentTime + frameInfos[i].fDuration;
140 if (next != expectedNext) {
141 ERRORF(r, "Time did not match for frame %i: next: %g expected: %g",
142 i, next, expectedNext);
143 failed = true;
144 break;
145 }
146 }
147
148 if (!testDraw(animatedImage, i)) {
149 ERRORF(r, "Did not update to %i properly", i);
150 failed = true;
151 break;
152 }
153
154 // Update, but not to the next frame.
155 REPORTER_ASSERT(r, animatedImage->update((next - currentTime) / 2) == next);
156 if (!testDraw(animatedImage, i)) {
157 ERRORF(r, "Should still be on frame %i", i);
158 failed = true;
159 break;
160 }
161
162 currentTime = next;
163 }
164
165 if (failed) {
166 continue;
167 }
168
169 // Create a new animated image and test stop.
170 animatedImage = SkAnimatedImage::Make(SkAndroidCodec::MakeFromCodec(
171 SkCodec::MakeFromData(data)));
172
173 animatedImage->start();
174 currentTime = 100000;
175 // Do not go to the last frame, so it should still be running after.
176 for (size_t i = 0; i < frameInfos.size() - 1; ++i) {
177 double next = animatedImage->update(currentTime);
178 if (!testDraw(animatedImage, i)) {
179 ERRORF(r, "Error during stop tests.");
180 failed = true;
181 break;
182 }
183
184 double interval = next - currentTime;
185 animatedImage->stop();
186 REPORTER_ASSERT(r, !animatedImage->isRunning());
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500187 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500188
189 currentTime = next;
190 double stoppedNext = animatedImage->update(currentTime);
Leon Scroggins III8524c302018-01-22 12:31:21 -0500191 REPORTER_ASSERT(r, stoppedNext == SkAnimatedImage::kNotRunning);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500192 if (!testDraw(animatedImage, i)) {
193 ERRORF(r, "Advanced the frame while stopped?");
194 failed = true;
195 break;
196 }
197
198 animatedImage->start();
199 currentTime += interval;
200 }
201
202 if (failed) {
203 return;
204 }
205
206 REPORTER_ASSERT(r, animatedImage->isRunning());
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500207 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500208 animatedImage->reset();
209 if (!testDraw(animatedImage, 0)) {
210 ERRORF(r, "reset failed");
211 continue;
212 }
213
214 for (int loopCount : { 0, 1, 2, 5 }) {
215 animatedImage = SkAnimatedImage::Make(SkAndroidCodec::MakeFromCodec(
216 SkCodec::MakeFromData(data)));
217 animatedImage->start();
218 animatedImage->setRepetitionCount(loopCount);
219 for (int loops = 0; loops <= loopCount; loops++) {
220 REPORTER_ASSERT(r, animatedImage->isRunning());
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500221 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500222 for (size_t i = 0; i < frameInfos.size(); ++i) {
223 double next = animatedImage->update(currentTime);
224 if (animatedImage->isRunning()) {
225 currentTime = next;
Leon Scroggins III8524c302018-01-22 12:31:21 -0500226 } else {
227 REPORTER_ASSERT(r, next == SkAnimatedImage::kNotRunning);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500228 }
229 }
230 }
Leon Scroggins III8524c302018-01-22 12:31:21 -0500231
Leon Scroggins III4c119452018-01-20 10:33:24 -0500232 if (animatedImage->isRunning()) {
233 ERRORF(r, "%s animation still running after %i loops", file, loopCount);
234 }
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500235
236 if (!animatedImage->isFinished()) {
237 ERRORF(r, "%s animation should have finished with specified loop count (%i)",
238 file, loopCount);
239 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500240 }
241 }
242}