blob: 95d7fc6d2ef04e62d2e441b13604e1a75b21febb [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
116 REPORTER_ASSERT(r, !animatedImage->isRunning());
117 if (!testDraw(animatedImage, 0)) {
118 ERRORF(r, "Did not start with frame 0");
119 continue;
120 }
121
122 animatedImage->start();
123 REPORTER_ASSERT(r, animatedImage->isRunning());
124 if (!testDraw(animatedImage, 0)) {
125 ERRORF(r, "After starting, still not on frame 0");
126 continue;
127 }
128
129 // Start at an arbitrary time.
130 double currentTime = 100000;
131 bool failed = false;
132 for (size_t i = 0; i < frameInfos.size(); ++i) {
133 double next = animatedImage->update(currentTime);
134 if (i == frameInfos.size() - 1 && defaultRepetitionCount == 0) {
Leon Scroggins III8524c302018-01-22 12:31:21 -0500135 REPORTER_ASSERT(r, next == SkAnimatedImage::kNotRunning);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500136 REPORTER_ASSERT(r, !animatedImage->isRunning());
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500137 REPORTER_ASSERT(r, animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500138 } else {
139 REPORTER_ASSERT(r, animatedImage->isRunning());
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500140 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500141 double expectedNext = currentTime + frameInfos[i].fDuration;
142 if (next != expectedNext) {
143 ERRORF(r, "Time did not match for frame %i: next: %g expected: %g",
144 i, next, expectedNext);
145 failed = true;
146 break;
147 }
148 }
149
150 if (!testDraw(animatedImage, i)) {
151 ERRORF(r, "Did not update to %i properly", i);
152 failed = true;
153 break;
154 }
155
156 // Update, but not to the next frame.
157 REPORTER_ASSERT(r, animatedImage->update((next - currentTime) / 2) == next);
158 if (!testDraw(animatedImage, i)) {
159 ERRORF(r, "Should still be on frame %i", i);
160 failed = true;
161 break;
162 }
163
164 currentTime = next;
165 }
166
167 if (failed) {
168 continue;
169 }
170
171 // Create a new animated image and test stop.
172 animatedImage = SkAnimatedImage::Make(SkAndroidCodec::MakeFromCodec(
173 SkCodec::MakeFromData(data)));
174
175 animatedImage->start();
176 currentTime = 100000;
177 // Do not go to the last frame, so it should still be running after.
178 for (size_t i = 0; i < frameInfos.size() - 1; ++i) {
179 double next = animatedImage->update(currentTime);
180 if (!testDraw(animatedImage, i)) {
181 ERRORF(r, "Error during stop tests.");
182 failed = true;
183 break;
184 }
185
186 double interval = next - currentTime;
187 animatedImage->stop();
188 REPORTER_ASSERT(r, !animatedImage->isRunning());
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500189 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500190
191 currentTime = next;
192 double stoppedNext = animatedImage->update(currentTime);
Leon Scroggins III8524c302018-01-22 12:31:21 -0500193 REPORTER_ASSERT(r, stoppedNext == SkAnimatedImage::kNotRunning);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500194 if (!testDraw(animatedImage, i)) {
195 ERRORF(r, "Advanced the frame while stopped?");
196 failed = true;
197 break;
198 }
199
200 animatedImage->start();
201 currentTime += interval;
202 }
203
204 if (failed) {
205 return;
206 }
207
208 REPORTER_ASSERT(r, animatedImage->isRunning());
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500209 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500210 animatedImage->reset();
211 if (!testDraw(animatedImage, 0)) {
212 ERRORF(r, "reset failed");
213 continue;
214 }
215
216 for (int loopCount : { 0, 1, 2, 5 }) {
217 animatedImage = SkAnimatedImage::Make(SkAndroidCodec::MakeFromCodec(
218 SkCodec::MakeFromData(data)));
219 animatedImage->start();
220 animatedImage->setRepetitionCount(loopCount);
Leon Scroggins IIIabe639c2018-01-26 11:06:12 -0500221 REPORTER_ASSERT(r, animatedImage->getRepetitionCount() == loopCount);
222
Leon Scroggins III4c119452018-01-20 10:33:24 -0500223 for (int loops = 0; loops <= loopCount; loops++) {
224 REPORTER_ASSERT(r, animatedImage->isRunning());
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500225 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500226 for (size_t i = 0; i < frameInfos.size(); ++i) {
227 double next = animatedImage->update(currentTime);
228 if (animatedImage->isRunning()) {
229 currentTime = next;
Leon Scroggins III8524c302018-01-22 12:31:21 -0500230 } else {
231 REPORTER_ASSERT(r, next == SkAnimatedImage::kNotRunning);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500232 }
233 }
234 }
Leon Scroggins III8524c302018-01-22 12:31:21 -0500235
Leon Scroggins III4c119452018-01-20 10:33:24 -0500236 if (animatedImage->isRunning()) {
237 ERRORF(r, "%s animation still running after %i loops", file, loopCount);
238 }
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500239
240 if (!animatedImage->isFinished()) {
241 ERRORF(r, "%s animation should have finished with specified loop count (%i)",
242 file, loopCount);
243 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500244 }
245 }
246}