Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Side by Side Diff: Source/WebKit/chromium/tests/GIFImageDecoderTest.cpp

Issue 15350006: Decode GIF image frames on demand. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Rebased Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32
33 #include "core/platform/image-decoders/gif/GIFImageDecoder.h"
34
35 #include <gtest/gtest.h>
36 #include "core/platform/FileSystem.h"
37 #include "core/platform/SharedBuffer.h"
38 #include <public/Platform.h>
39 #include <public/WebData.h>
40 #include <public/WebSize.h>
41 #include <public/WebUnitTestSupport.h>
42 #include <wtf/OwnPtr.h>
43 #include <wtf/PassOwnPtr.h>
44 #include <wtf/StringHasher.h>
45 #include <wtf/Vector.h>
46
47 using namespace WebCore;
48 using namespace WebKit;
49
50 namespace {
51
52 #if !OS(ANDROID)
53
54 static PassRefPtr<SharedBuffer> readFile(const char* fileName)
55 {
56 String filePath = Platform::current()->unitTestSupport()->webKitRootDir();
57 filePath.append(fileName);
58
59 long long fileSize;
60 if (!getFileSize(filePath, fileSize))
61 return 0;
62
63 PlatformFileHandle handle = openFile(filePath, OpenForRead);
64 int fileLength = static_cast<int>(fileSize);
65 Vector<char> buffer(fileLength);
66 readFromFile(handle, buffer.data(), fileLength);
67 closeFile(handle);
68 return SharedBuffer::adoptVector(buffer);
69 }
70
71 static PassOwnPtr<GIFImageDecoder> createDecoder()
72 {
73 return adoptPtr(new GIFImageDecoder(ImageSource::AlphaNotPremultiplied, Imag eSource::GammaAndColorProfileApplied));
74 }
75
76 static unsigned hashSkBitmap(const SkBitmap& bitmap)
77 {
78 return StringHasher::hashMemory(bitmap.getPixels(), bitmap.getSize());
79 }
80
81 TEST(GIFImageDecoderTest, decodeTwoFrames)
82 {
83 OwnPtr<GIFImageDecoder> decoder(createDecoder());
84
85 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani mated.gif");
86 ASSERT_TRUE(data.get());
87 decoder->setData(data.get(), true);
88 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
89
90 ImageFrame* frame = decoder->frameBufferAtIndex(0);
91 EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
92 EXPECT_EQ(16, frame->getSkBitmap().width());
93 EXPECT_EQ(16, frame->getSkBitmap().height());
94
95 frame = decoder->frameBufferAtIndex(1);
96 EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
97 EXPECT_EQ(16, frame->getSkBitmap().width());
98 EXPECT_EQ(16, frame->getSkBitmap().height());
99
100 EXPECT_EQ(2u, decoder->frameCount());
101 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
102 }
103
104 TEST(GIFImageDecoderTest, parseAndDecode)
105 {
106 OwnPtr<GIFImageDecoder> decoder(createDecoder());
107
108 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani mated.gif");
109 ASSERT_TRUE(data.get());
110 decoder->setData(data.get(), true);
111 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
112
113 // This call will parse the entire file.
114 EXPECT_EQ(2u, decoder->frameCount());
115
116 ImageFrame* frame = decoder->frameBufferAtIndex(0);
117 EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
118 EXPECT_EQ(16, frame->getSkBitmap().width());
119 EXPECT_EQ(16, frame->getSkBitmap().height());
120
121 frame = decoder->frameBufferAtIndex(1);
122 EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
123 EXPECT_EQ(16, frame->getSkBitmap().width());
124 EXPECT_EQ(16, frame->getSkBitmap().height());
125 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
126 }
127
128 TEST(GIFImageDecoderTest, parseByteByByte)
129 {
130 OwnPtr<GIFImageDecoder> decoder(createDecoder());
131
132 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani mated.gif");
133 ASSERT_TRUE(data.get());
134
135 size_t frameCount = 0;
136
137 // Pass data to decoder byte by byte.
138 for (unsigned length = 1; length <= data->size(); ++length) {
139 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), lengt h);
140 decoder->setData(tempData.get(), length == data->size());
141
142 EXPECT_LE(frameCount, decoder->frameCount());
143 frameCount = decoder->frameCount();
144 }
145
146 EXPECT_EQ(2u, decoder->frameCount());
147
148 decoder->frameBufferAtIndex(0);
149 decoder->frameBufferAtIndex(1);
150 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
151 }
152
153 TEST(GIFImageDecoderTest, parseAndDecodeByteByByte)
154 {
155 OwnPtr<GIFImageDecoder> decoder(createDecoder());
156
157 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani mated-gif-with-offsets.gif");
158 ASSERT_TRUE(data.get());
159
160 size_t frameCount = 0;
161 size_t framesDecoded = 0;
162
163 // Pass data to decoder byte by byte.
164 for (unsigned length = 1; length <= data->size(); ++length) {
165 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), lengt h);
166 decoder->setData(tempData.get(), length == data->size());
167
168 EXPECT_LE(frameCount, decoder->frameCount());
169 frameCount = decoder->frameCount();
170
171 ImageFrame* frame = decoder->frameBufferAtIndex(frameCount - 1);
172 if (frame && frame->status() == ImageFrame::FrameComplete && framesDecod ed < frameCount)
173 ++framesDecoded;
174 }
175
176 EXPECT_EQ(5u, decoder->frameCount());
177 EXPECT_EQ(5u, framesDecoded);
178 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
179 }
180
181 TEST(GIFImageDecoderTest, brokenSecondFrame)
182 {
183 OwnPtr<GIFImageDecoder> decoder(createDecoder());
184
185 RefPtr<SharedBuffer> data = readFile("/Source/WebKit/chromium/tests/data/bro ken.gif");
186 ASSERT_TRUE(data.get());
187 decoder->setData(data.get(), true);
188
189 // One frame is detected but cannot be decoded.
190 EXPECT_EQ(1u, decoder->frameCount());
191 ImageFrame* frame = decoder->frameBufferAtIndex(1);
192 EXPECT_FALSE(frame);
193 }
194
195 TEST(GIFImageDecoderTest, progressiveDecode)
196 {
197 RefPtr<SharedBuffer> fullData = readFile("/Source/WebKit/chromium/tests/data /radient.gif");
198 ASSERT_TRUE(fullData.get());
199 const size_t fullLength = fullData->size();
200
201 OwnPtr<GIFImageDecoder> decoder;
202 ImageFrame* frame;
203
204 Vector<unsigned> truncatedHashes;
205 Vector<unsigned> progressiveHashes;
206
207 // Compute hashes when the file is truncated.
208 const size_t increment = 1;
209 for (size_t i = 1; i <= fullLength; i += increment) {
210 decoder = createDecoder();
211 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i);
212 decoder->setData(data.get(), i == fullLength);
213 frame = decoder->frameBufferAtIndex(0);
214 if (!frame) {
215 truncatedHashes.append(0);
216 continue;
217 }
218 truncatedHashes.append(hashSkBitmap(frame->getSkBitmap()));
219 }
220
221 // Compute hashes when the file is progressively decoded.
222 decoder = createDecoder();
223 for (size_t i = 1; i <= fullLength; i += increment) {
224 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i);
225 decoder->setData(data.get(), i == fullLength);
226 frame = decoder->frameBufferAtIndex(0);
227 if (!frame) {
228 progressiveHashes.append(0);
229 continue;
230 }
231 progressiveHashes.append(hashSkBitmap(frame->getSkBitmap()));
232 }
233
234 bool match = true;
235 for (size_t i = 0; i < truncatedHashes.size(); ++i) {
236 if (truncatedHashes[i] != progressiveHashes[i]) {
237 match = false;
238 break;
239 }
240 }
241 EXPECT_TRUE(match);
242 }
243
244 TEST(GIFImageDecoderTest, allDataReceivedTruncation)
245 {
246 OwnPtr<GIFImageDecoder> decoder(createDecoder());
247
248 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani mated.gif");
249 ASSERT_TRUE(data.get());
250
251 ASSERT_GE(data->size(), 10u);
252 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->siz e() - 10);
253 decoder->setData(tempData.get(), true);
254
255 EXPECT_EQ(2u, decoder->frameCount());
256 EXPECT_FALSE(decoder->failed());
257
258 decoder->frameBufferAtIndex(0);
259 EXPECT_FALSE(decoder->failed());
260 decoder->frameBufferAtIndex(1);
261 EXPECT_TRUE(decoder->failed());
262 }
263
264 TEST(GIFImageDecoderTest, frameIsComplete)
265 {
266 OwnPtr<GIFImageDecoder> decoder(createDecoder());
267
268 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani mated.gif");
269 ASSERT_TRUE(data.get());
270 decoder->setData(data.get(), true);
271
272 EXPECT_EQ(2u, decoder->frameCount());
273 EXPECT_FALSE(decoder->failed());
274 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
275 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1));
276 }
277
278 TEST(GIFImageDecoderTest, frameIsCompleteLoading)
279 {
280 OwnPtr<GIFImageDecoder> decoder(createDecoder());
281
282 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani mated.gif");
283 ASSERT_TRUE(data.get());
284
285 ASSERT_GE(data->size(), 10u);
286 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->siz e() - 10);
287 decoder->setData(tempData.get(), false);
288
289 EXPECT_EQ(2u, decoder->frameCount());
290 EXPECT_FALSE(decoder->failed());
291 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
292 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(1));
293
294 decoder->setData(data.get(), true);
295 EXPECT_EQ(2u, decoder->frameCount());
296 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
297 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1));
298 }
299
300 TEST(GIFImageDecoderTest, badTerminator)
301 {
302 RefPtr<SharedBuffer> referenceData = readFile("/Source/WebKit/chromium/tests /data/radient.gif");
303 RefPtr<SharedBuffer> testData = readFile("/Source/WebKit/chromium/tests/data /radient-bad-terminator.gif");
304 ASSERT_TRUE(referenceData.get());
305 ASSERT_TRUE(testData.get());
306
307 OwnPtr<GIFImageDecoder> referenceDecoder(createDecoder());
308 referenceDecoder->setData(referenceData.get(), true);
309 EXPECT_EQ(1u, referenceDecoder->frameCount());
310 ImageFrame* referenceFrame = referenceDecoder->frameBufferAtIndex(0);
311 ASSERT(referenceFrame);
312
313 OwnPtr<GIFImageDecoder> testDecoder(createDecoder());
314 testDecoder->setData(testData.get(), true);
315 EXPECT_EQ(1u, testDecoder->frameCount());
316 ImageFrame* testFrame = testDecoder->frameBufferAtIndex(0);
317 ASSERT(testFrame);
318
319 EXPECT_EQ(hashSkBitmap(referenceFrame->getSkBitmap()), hashSkBitmap(testFram e->getSkBitmap()));
320 }
321
322 #endif
323
324 } // namespace
OLDNEW
« no previous file with comments | « Source/WebKit/chromium/tests/DragImageTest.cpp ('k') | Source/WebKit/chromium/tests/ImageLayerChromiumTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698