blob: 6c7b0e5a55b9178666cafaf58b30a938319287d2 [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
Leon Scroggins III4c119452018-01-20 10:33:24 -05008#include "CodecPriv.h"
9#include "Resources.h"
Ben Wagner1ebeefe2018-03-02 16:59:53 -050010#include "SkAndroidCodec.h"
11#include "SkAnimatedImage.h"
12#include "SkBitmap.h"
13#include "SkCanvas.h"
14#include "SkCodec.h"
15#include "SkColor.h"
16#include "SkData.h"
17#include "SkImageInfo.h"
Leon Scroggins III2f862202018-03-05 14:19:40 -050018#include "SkPicture.h"
Ben Wagner1ebeefe2018-03-02 16:59:53 -050019#include "SkRefCnt.h"
20#include "SkSize.h"
21#include "SkString.h"
22#include "SkTypes.h"
23#include "SkUnPreMultiply.h"
Leon Scroggins III4c119452018-01-20 10:33:24 -050024#include "Test.h"
25#include "sk_tool_utils.h"
26
Ben Wagner1ebeefe2018-03-02 16:59:53 -050027#include <algorithm>
28#include <memory>
Leon Scroggins III4c119452018-01-20 10:33:24 -050029#include <vector>
30
Leon Scroggins III2f862202018-03-05 14:19:40 -050031DEF_TEST(AnimatedImage_scaled, r) {
32 if (GetResourcePath().isEmpty()) {
33 return;
34 }
35
36 const char* file = "images/alphabetAnim.gif";
37 auto data = GetResourceAsData(file);
38 if (!data) {
39 ERRORF(r, "Could not get %s", file);
40 return;
41 }
42
43 auto codec = SkAndroidCodec::MakeFromCodec(SkCodec::MakeFromData(data));
44 if (!codec) {
45 ERRORF(r, "Could not create codec for %s", file);
46 return;
47 }
48
49 // Force the drawable follow its special case that requires scaling.
50 auto size = codec->getInfo().dimensions();
51 size.set(size.width() - 5, size.height() - 5);
52 auto rect = SkIRect::MakeSize(size);
53 auto image = SkAnimatedImage::Make(std::move(codec), size, rect, nullptr);
54 if (!image) {
55 ERRORF(r, "Failed to create animated image for %s", file);
56 return;
57 }
58
59 // Clear a bitmap to non-transparent and draw to it. pixels that are transparent
60 // in the image should not replace the original non-transparent color.
61 SkBitmap bm;
62 bm.allocPixels(SkImageInfo::MakeN32Premul(size.width(), size.height()));
63 bm.eraseColor(SK_ColorBLUE);
64 SkCanvas canvas(bm);
65 image->draw(&canvas);
66 for (int i = 0; i < size.width(); ++i)
67 for (int j = 0; j < size.height(); ++j) {
68 if (*bm.getAddr32(i, j) == SK_ColorTRANSPARENT) {
69 ERRORF(r, "Erased color underneath!");
70 return;
71 }
72 }
73}
74
Leon Scroggins III4c119452018-01-20 10:33:24 -050075DEF_TEST(AnimatedImage, r) {
76 if (GetResourcePath().isEmpty()) {
77 return;
78 }
79 for (const char* file : { "images/alphabetAnim.gif",
80 "images/colorTables.gif",
81 "images/webp-animated.webp",
82 "images/required.webp",
83 }) {
84 auto data = GetResourceAsData(file);
85 if (!data) {
86 ERRORF(r, "Could not get %s", file);
87 continue;
88 }
89
90 auto codec = SkCodec::MakeFromData(data);
91 if (!codec) {
92 ERRORF(r, "Could not create codec for %s", file);
93 continue;
94 }
95
96 const int defaultRepetitionCount = codec->getRepetitionCount();
97 std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
98 std::vector<SkBitmap> frames(frameInfos.size());
99 // Used down below for our test image.
100 const auto imageInfo = codec->getInfo().makeAlphaType(kPremul_SkAlphaType);
101
102 for (size_t i = 0; i < frameInfos.size(); ++i) {
103 auto info = codec->getInfo().makeAlphaType(frameInfos[i].fAlphaType);
104 auto& bm = frames[i];
105
106 SkCodec::Options options;
107 options.fFrameIndex = (int) i;
108 options.fPriorFrame = frameInfos[i].fRequiredFrame;
109 if (options.fPriorFrame == SkCodec::kNone) {
110 bm.allocPixels(info);
111 bm.eraseColor(0);
112 } else {
113 const SkBitmap& priorFrame = frames[options.fPriorFrame];
114 if (!sk_tool_utils::copy_to(&bm, priorFrame.colorType(), priorFrame)) {
115 ERRORF(r, "Failed to copy %s frame %i", file, options.fPriorFrame);
116 options.fPriorFrame = SkCodec::kNone;
117 }
118 REPORTER_ASSERT(r, bm.setAlphaType(frameInfos[i].fAlphaType));
119 }
120
121 auto result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(), &options);
122 if (result != SkCodec::kSuccess) {
123 ERRORF(r, "error in %s frame %zu: %s", file, i, SkCodec::ResultToString(result));
124 }
125 }
126
127 auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
128 if (!androidCodec) {
129 ERRORF(r, "Could not create androidCodec for %s", file);
130 continue;
131 }
132
133 auto animatedImage = SkAnimatedImage::Make(std::move(androidCodec));
134 if (!animatedImage) {
135 ERRORF(r, "Could not create animated image for %s", file);
136 continue;
137 }
138
Leon Scroggins IIIabe639c2018-01-26 11:06:12 -0500139 REPORTER_ASSERT(r, defaultRepetitionCount == animatedImage->getRepetitionCount());
140
Leon Scroggins III4c119452018-01-20 10:33:24 -0500141 auto testDraw = [r, &frames, &imageInfo, file](const sk_sp<SkAnimatedImage>& animatedImage,
142 int expectedFrame) {
143 SkBitmap test;
144 test.allocPixels(imageInfo);
145 test.eraseColor(0);
146 SkCanvas c(test);
147 animatedImage->draw(&c);
148
149 const SkBitmap& frame = frames[expectedFrame];
150 REPORTER_ASSERT(r, frame.colorType() == test.colorType());
151 REPORTER_ASSERT(r, frame.dimensions() == test.dimensions());
152 for (int i = 0; i < test.width(); ++i)
153 for (int j = 0; j < test.height(); ++j) {
154 SkColor expected = SkUnPreMultiply::PMColorToColor(*frame.getAddr32(i, j));
155 SkColor actual = SkUnPreMultiply::PMColorToColor(*test .getAddr32(i, j));
156 if (expected != actual) {
157 ERRORF(r, "frame %i of %s does not match at pixel %i, %i!"
158 " expected %x\tactual: %x",
159 expectedFrame, file, i, j, expected, actual);
160 SkString expected_name = SkStringPrintf("expected_%c", '0' + expectedFrame);
161 SkString actual_name = SkStringPrintf("actual_%c", '0' + expectedFrame);
162 write_bm(expected_name.c_str(), frame);
163 write_bm(actual_name.c_str(), test);
164 return false;
165 }
166 }
167 return true;
168 };
169
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500170 REPORTER_ASSERT(r, animatedImage->currentFrameDuration() == frameInfos[0].fDuration);
171
Leon Scroggins III4c119452018-01-20 10:33:24 -0500172 if (!testDraw(animatedImage, 0)) {
173 ERRORF(r, "Did not start with frame 0");
174 continue;
175 }
176
Leon Scroggins III4c119452018-01-20 10:33:24 -0500177 // Start at an arbitrary time.
Leon Scroggins III4c119452018-01-20 10:33:24 -0500178 bool failed = false;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500179 for (size_t i = 1; i < frameInfos.size(); ++i) {
180 const int frameTime = animatedImage->decodeNextFrame();
181 REPORTER_ASSERT(r, frameTime == animatedImage->currentFrameDuration());
182
Leon Scroggins III4c119452018-01-20 10:33:24 -0500183 if (i == frameInfos.size() - 1 && defaultRepetitionCount == 0) {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500184 REPORTER_ASSERT(r, frameTime == SkAnimatedImage::kFinished);
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500185 REPORTER_ASSERT(r, animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500186 } else {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500187 REPORTER_ASSERT(r, frameTime == frameInfos[i].fDuration);
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500188 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III4c119452018-01-20 10:33:24 -0500189 }
190
191 if (!testDraw(animatedImage, i)) {
192 ERRORF(r, "Did not update to %i properly", i);
193 failed = true;
194 break;
195 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500196 }
197
198 if (failed) {
199 continue;
200 }
201
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500202 animatedImage->reset();
203 REPORTER_ASSERT(r, !animatedImage->isFinished());
204 if (!testDraw(animatedImage, 0)) {
205 ERRORF(r, "reset failed");
206 continue;
207 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500208
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500209 // Test reset from all the frames.
210 // j is the frame to call reset on.
211 for (int j = 0; j < (int) frameInfos.size(); ++j) {
212 if (failed) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500213 break;
214 }
215
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500216 // i is the frame to decode.
217 for (int i = 0; i <= j; ++i) {
218 if (i == j) {
219 animatedImage->reset();
220 if (!testDraw(animatedImage, 0)) {
221 ERRORF(r, "reset failed for image %s from frame %i",
222 file, i);
223 failed = true;
224 break;
225 }
226 } else if (i != 0) {
227 animatedImage->decodeNextFrame();
228 if (!testDraw(animatedImage, i)) {
229 ERRORF(r, "failed to match frame %i in %s on iteration %i",
230 i, file, j);
231 failed = true;
232 break;
233 }
234 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500235 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500236 }
237
238 if (failed) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500239 continue;
240 }
241
242 for (int loopCount : { 0, 1, 2, 5 }) {
243 animatedImage = SkAnimatedImage::Make(SkAndroidCodec::MakeFromCodec(
244 SkCodec::MakeFromData(data)));
Leon Scroggins III4c119452018-01-20 10:33:24 -0500245 animatedImage->setRepetitionCount(loopCount);
Leon Scroggins IIIabe639c2018-01-26 11:06:12 -0500246 REPORTER_ASSERT(r, animatedImage->getRepetitionCount() == loopCount);
247
Leon Scroggins III4c119452018-01-20 10:33:24 -0500248 for (int loops = 0; loops <= loopCount; loops++) {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500249 if (failed) {
250 break;
251 }
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500252 REPORTER_ASSERT(r, !animatedImage->isFinished());
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500253 for (size_t i = 1; i <= frameInfos.size(); ++i) {
254 const int frameTime = animatedImage->decodeNextFrame();
255 if (frameTime == SkAnimatedImage::kFinished) {
256 if (loops != loopCount) {
257 ERRORF(r, "%s animation stopped early: loops: %i\tloopCount: %i",
258 file, loops, loopCount);
259 failed = true;
260 }
261 if (i != frameInfos.size() - 1) {
262 ERRORF(r, "%s animation stopped early: i: %i\tsize: %i",
263 file, i, frameInfos.size());
264 failed = true;
265 }
266 break;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500267 }
268 }
269 }
Leon Scroggins III8524c302018-01-22 12:31:21 -0500270
Leon Scroggins III2cb6cb12018-01-21 15:50:12 -0500271 if (!animatedImage->isFinished()) {
272 ERRORF(r, "%s animation should have finished with specified loop count (%i)",
273 file, loopCount);
274 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500275 }
276 }
277}