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

Side by Side Diff: third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp

Issue 2930513004: [WIP] Move ImageDecoders to SkCodec
Patch Set: Adding check for decoder creation Created 3 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 "platform/image-decoders/gif/GIFImageDecoder.h"
32
33 #include <memory>
34 #include "platform/SharedBuffer.h"
35 #include "platform/image-decoders/ImageDecoderTestHelpers.h"
36 #include "platform/wtf/PtrUtil.h"
37 #include "platform/wtf/Vector.h"
38 #include "public/platform/WebData.h"
39 #include "public/platform/WebSize.h"
40 #include "testing/gtest/include/gtest/gtest.h"
41
42 namespace blink {
43
44 namespace {
45
46 const char kLayoutTestResourcesDir[] = "LayoutTests/images/resources";
47
48 std::unique_ptr<ImageDecoder> CreateDecoder() {
49 return WTF::WrapUnique(
50 new GIFImageDecoder(ImageDecoder::kAlphaNotPremultiplied,
51 ColorBehavior::TransformToTargetForTesting(),
52 ImageDecoder::kNoDecodedImageByteLimit));
53 }
54
55 void TestRepetitionCount(const char* dir,
56 const char* file,
57 int expected_repetition_count) {
58 std::unique_ptr<ImageDecoder> decoder = CreateDecoder();
59 RefPtr<SharedBuffer> data = ReadFile(dir, file);
60 ASSERT_TRUE(data.Get());
61 decoder->SetData(data.Get(), true);
62 EXPECT_EQ(kAnimationLoopOnce,
63 decoder->RepetitionCount()); // Default value before decode.
64
65 for (size_t i = 0; i < decoder->FrameCount(); ++i) {
66 ImageFrame* frame = decoder->FrameBufferAtIndex(i);
67 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
68 }
69
70 EXPECT_EQ(expected_repetition_count,
71 decoder->RepetitionCount()); // Expected value after decode.
72 }
73
74 } // anonymous namespace
75
76 TEST(GIFImageDecoderTest, decodeTwoFrames) {
77 std::unique_ptr<ImageDecoder> decoder = CreateDecoder();
78
79 RefPtr<SharedBuffer> data = ReadFile(kLayoutTestResourcesDir, "animated.gif");
80 ASSERT_TRUE(data.Get());
81 decoder->SetData(data.Get(), true);
82 EXPECT_EQ(kAnimationLoopOnce, decoder->RepetitionCount());
83
84 ImageFrame* frame = decoder->FrameBufferAtIndex(0);
85 uint32_t generation_id0 = frame->Bitmap().getGenerationID();
86 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
87 EXPECT_EQ(16, frame->Bitmap().width());
88 EXPECT_EQ(16, frame->Bitmap().height());
89
90 frame = decoder->FrameBufferAtIndex(1);
91 uint32_t generation_id1 = frame->Bitmap().getGenerationID();
92 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
93 EXPECT_EQ(16, frame->Bitmap().width());
94 EXPECT_EQ(16, frame->Bitmap().height());
95 EXPECT_TRUE(generation_id0 != generation_id1);
96
97 EXPECT_EQ(2u, decoder->FrameCount());
98 EXPECT_EQ(kAnimationLoopInfinite, decoder->RepetitionCount());
99 }
100
101 TEST(GIFImageDecoderTest, parseAndDecode) {
102 std::unique_ptr<ImageDecoder> decoder = CreateDecoder();
103
104 RefPtr<SharedBuffer> data = ReadFile(kLayoutTestResourcesDir, "animated.gif");
105 ASSERT_TRUE(data.Get());
106 decoder->SetData(data.Get(), true);
107 EXPECT_EQ(kAnimationLoopOnce, decoder->RepetitionCount());
108
109 // This call will parse the entire file.
110 EXPECT_EQ(2u, decoder->FrameCount());
111
112 ImageFrame* frame = decoder->FrameBufferAtIndex(0);
113 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
114 EXPECT_EQ(16, frame->Bitmap().width());
115 EXPECT_EQ(16, frame->Bitmap().height());
116
117 frame = decoder->FrameBufferAtIndex(1);
118 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
119 EXPECT_EQ(16, frame->Bitmap().width());
120 EXPECT_EQ(16, frame->Bitmap().height());
121 EXPECT_EQ(kAnimationLoopInfinite, decoder->RepetitionCount());
122 }
123
124 TEST(GIFImageDecoderTest, parseByteByByte) {
125 std::unique_ptr<ImageDecoder> decoder = CreateDecoder();
126
127 RefPtr<SharedBuffer> data = ReadFile(kLayoutTestResourcesDir, "animated.gif");
128 ASSERT_TRUE(data.Get());
129
130 size_t frame_count = 0;
131
132 // Pass data to decoder byte by byte.
133 for (size_t length = 1; length <= data->size(); ++length) {
134 RefPtr<SharedBuffer> temp_data = SharedBuffer::Create(data->Data(), length);
135 decoder->SetData(temp_data.Get(), length == data->size());
136
137 EXPECT_LE(frame_count, decoder->FrameCount());
138 frame_count = decoder->FrameCount();
139 }
140
141 EXPECT_EQ(2u, decoder->FrameCount());
142
143 decoder->FrameBufferAtIndex(0);
144 decoder->FrameBufferAtIndex(1);
145 EXPECT_EQ(kAnimationLoopInfinite, decoder->RepetitionCount());
146 }
147
148 TEST(GIFImageDecoderTest, parseAndDecodeByteByByte) {
149 TestByteByByteDecode(&CreateDecoder, kLayoutTestResourcesDir,
150 "animated-gif-with-offsets.gif", 5u,
151 kAnimationLoopInfinite);
152 }
153
154 TEST(GIFImageDecoderTest, brokenSecondFrame) {
155 std::unique_ptr<ImageDecoder> decoder = CreateDecoder();
156
157 RefPtr<SharedBuffer> data = ReadFile(kDecodersTestingDir, "broken.gif");
158 ASSERT_TRUE(data.Get());
159 decoder->SetData(data.Get(), true);
160
161 // One frame is detected but cannot be decoded.
162 EXPECT_EQ(1u, decoder->FrameCount());
163 ImageFrame* frame = decoder->FrameBufferAtIndex(1);
164 EXPECT_FALSE(frame);
165 }
166
167 TEST(GIFImageDecoderTest, progressiveDecode) {
168 TestProgressiveDecoding(&CreateDecoder, kDecodersTestingDir, "radient.gif");
169 }
170
171 TEST(GIFImageDecoderTest, allDataReceivedTruncation) {
172 std::unique_ptr<ImageDecoder> decoder = CreateDecoder();
173
174 RefPtr<SharedBuffer> data = ReadFile(kLayoutTestResourcesDir, "animated.gif");
175 ASSERT_TRUE(data.Get());
176
177 ASSERT_GE(data->size(), 10u);
178 RefPtr<SharedBuffer> temp_data =
179 SharedBuffer::Create(data->Data(), data->size() - 10);
180 decoder->SetData(temp_data.Get(), true);
181
182 EXPECT_EQ(2u, decoder->FrameCount());
183 EXPECT_FALSE(decoder->Failed());
184
185 decoder->FrameBufferAtIndex(0);
186 EXPECT_FALSE(decoder->Failed());
187 decoder->FrameBufferAtIndex(1);
188 EXPECT_TRUE(decoder->Failed());
189 }
190
191 TEST(GIFImageDecoderTest, frameIsComplete) {
192 std::unique_ptr<ImageDecoder> decoder = CreateDecoder();
193
194 RefPtr<SharedBuffer> data = ReadFile(kLayoutTestResourcesDir, "animated.gif");
195 ASSERT_TRUE(data.Get());
196 decoder->SetData(data.Get(), true);
197
198 EXPECT_EQ(2u, decoder->FrameCount());
199 EXPECT_FALSE(decoder->Failed());
200 EXPECT_TRUE(decoder->FrameIsCompleteAtIndex(0));
201 EXPECT_TRUE(decoder->FrameIsCompleteAtIndex(1));
202 EXPECT_EQ(kAnimationLoopInfinite, decoder->RepetitionCount());
203 }
204
205 TEST(GIFImageDecoderTest, frameIsCompleteLoading) {
206 std::unique_ptr<ImageDecoder> decoder = CreateDecoder();
207
208 RefPtr<SharedBuffer> data = ReadFile(kLayoutTestResourcesDir, "animated.gif");
209 ASSERT_TRUE(data.Get());
210
211 ASSERT_GE(data->size(), 10u);
212 RefPtr<SharedBuffer> temp_data =
213 SharedBuffer::Create(data->Data(), data->size() - 10);
214 decoder->SetData(temp_data.Get(), false);
215
216 EXPECT_EQ(2u, decoder->FrameCount());
217 EXPECT_FALSE(decoder->Failed());
218 EXPECT_TRUE(decoder->FrameIsCompleteAtIndex(0));
219 EXPECT_FALSE(decoder->FrameIsCompleteAtIndex(1));
220
221 decoder->SetData(data.Get(), true);
222 EXPECT_EQ(2u, decoder->FrameCount());
223 EXPECT_TRUE(decoder->FrameIsCompleteAtIndex(0));
224 EXPECT_TRUE(decoder->FrameIsCompleteAtIndex(1));
225 }
226
227 TEST(GIFImageDecoderTest, badTerminator) {
228 RefPtr<SharedBuffer> reference_data =
229 ReadFile(kDecodersTestingDir, "radient.gif");
230 RefPtr<SharedBuffer> test_data =
231 ReadFile(kDecodersTestingDir, "radient-bad-terminator.gif");
232 ASSERT_TRUE(reference_data.Get());
233 ASSERT_TRUE(test_data.Get());
234
235 std::unique_ptr<ImageDecoder> reference_decoder = CreateDecoder();
236 reference_decoder->SetData(reference_data.Get(), true);
237 EXPECT_EQ(1u, reference_decoder->FrameCount());
238 ImageFrame* reference_frame = reference_decoder->FrameBufferAtIndex(0);
239 DCHECK(reference_frame);
240
241 std::unique_ptr<ImageDecoder> test_decoder = CreateDecoder();
242 test_decoder->SetData(test_data.Get(), true);
243 EXPECT_EQ(1u, test_decoder->FrameCount());
244 ImageFrame* test_frame = test_decoder->FrameBufferAtIndex(0);
245 DCHECK(test_frame);
246
247 EXPECT_EQ(HashBitmap(reference_frame->Bitmap()),
248 HashBitmap(test_frame->Bitmap()));
249 }
250
251 TEST(GIFImageDecoderTest, updateRequiredPreviousFrameAfterFirstDecode) {
252 TestUpdateRequiredPreviousFrameAfterFirstDecode(
253 &CreateDecoder, kLayoutTestResourcesDir, "animated-10color.gif");
254 }
255
256 TEST(GIFImageDecoderTest, randomFrameDecode) {
257 // Single frame image.
258 TestRandomFrameDecode(&CreateDecoder, kDecodersTestingDir, "radient.gif");
259 // Multiple frame images.
260 TestRandomFrameDecode(&CreateDecoder, kLayoutTestResourcesDir,
261 "animated-gif-with-offsets.gif");
262 TestRandomFrameDecode(&CreateDecoder, kLayoutTestResourcesDir,
263 "animated-10color.gif");
264 }
265
266 TEST(GIFImageDecoderTest, randomDecodeAfterClearFrameBufferCache) {
267 // Single frame image.
268 TestRandomDecodeAfterClearFrameBufferCache(
269 &CreateDecoder, kDecodersTestingDir, "radient.gif");
270 // Multiple frame images.
271 TestRandomDecodeAfterClearFrameBufferCache(
272 &CreateDecoder, kLayoutTestResourcesDir, "animated-gif-with-offsets.gif");
273 TestRandomDecodeAfterClearFrameBufferCache(
274 &CreateDecoder, kLayoutTestResourcesDir, "animated-10color.gif");
275 }
276
277 TEST(GIFImageDecoderTest, resumePartialDecodeAfterClearFrameBufferCache) {
278 TestResumePartialDecodeAfterClearFrameBufferCache(
279 &CreateDecoder, kLayoutTestResourcesDir, "animated-10color.gif");
280 }
281
282 // The first LZW codes in the image are invalid values that try to create a loop
283 // in the dictionary. Decoding should fail, but not infinitely loop or corrupt
284 // memory.
285 TEST(GIFImageDecoderTest, badInitialCode) {
286 RefPtr<SharedBuffer> test_data =
287 ReadFile(kDecodersTestingDir, "bad-initial-code.gif");
288 ASSERT_TRUE(test_data.Get());
289
290 std::unique_ptr<ImageDecoder> test_decoder = CreateDecoder();
291 test_decoder->SetData(test_data.Get(), true);
292 EXPECT_EQ(1u, test_decoder->FrameCount());
293 ASSERT_TRUE(test_decoder->FrameBufferAtIndex(0));
294 EXPECT_TRUE(test_decoder->Failed());
295 }
296
297 // The image has an invalid LZW code that exceeds dictionary size. Decoding
298 // should fail.
299 TEST(GIFImageDecoderTest, badCode) {
300 RefPtr<SharedBuffer> test_data =
301 ReadFile(kDecodersTestingDir, "bad-code.gif");
302 ASSERT_TRUE(test_data.Get());
303
304 std::unique_ptr<ImageDecoder> test_decoder = CreateDecoder();
305 test_decoder->SetData(test_data.Get(), true);
306 EXPECT_EQ(1u, test_decoder->FrameCount());
307 ASSERT_TRUE(test_decoder->FrameBufferAtIndex(0));
308 EXPECT_TRUE(test_decoder->Failed());
309 }
310
311 TEST(GIFImageDecoderTest, invalidDisposalMethod) {
312 std::unique_ptr<ImageDecoder> decoder = CreateDecoder();
313
314 // The image has 2 frames, with disposal method 4 and 5, respectively.
315 RefPtr<SharedBuffer> data =
316 ReadFile(kDecodersTestingDir, "invalid-disposal-method.gif");
317 ASSERT_TRUE(data.Get());
318 decoder->SetData(data.Get(), true);
319
320 EXPECT_EQ(2u, decoder->FrameCount());
321 // Disposal method 4 is converted to ImageFrame::DisposeOverwritePrevious.
322 EXPECT_EQ(ImageFrame::kDisposeOverwritePrevious,
323 decoder->FrameBufferAtIndex(0)->GetDisposalMethod());
324 // Disposal method 5 is ignored.
325 EXPECT_EQ(ImageFrame::kDisposeNotSpecified,
326 decoder->FrameBufferAtIndex(1)->GetDisposalMethod());
327 }
328
329 TEST(GIFImageDecoderTest, firstFrameHasGreaterSizeThanScreenSize) {
330 RefPtr<SharedBuffer> full_data = ReadFile(
331 kDecodersTestingDir, "first-frame-has-greater-size-than-screen-size.gif");
332 ASSERT_TRUE(full_data.Get());
333
334 std::unique_ptr<ImageDecoder> decoder;
335 IntSize frame_size;
336
337 // Compute hashes when the file is truncated.
338 for (size_t i = 1; i <= full_data->size(); ++i) {
339 decoder = CreateDecoder();
340 RefPtr<SharedBuffer> data = SharedBuffer::Create(full_data->Data(), i);
341 decoder->SetData(data.Get(), i == full_data->size());
342
343 if (decoder->IsSizeAvailable() && !frame_size.Width() &&
344 !frame_size.Height()) {
345 frame_size = decoder->DecodedSize();
346 continue;
347 }
348
349 ASSERT_EQ(frame_size.Width(), decoder->DecodedSize().Width());
350 ASSERT_EQ(frame_size.Height(), decoder->DecodedSize().Height());
351 }
352 }
353
354 TEST(GIFImageDecoderTest, verifyRepetitionCount) {
355 TestRepetitionCount(kLayoutTestResourcesDir, "full2loop.gif", 2);
356 TestRepetitionCount(kDecodersTestingDir, "radient.gif", kAnimationNone);
357 }
358
359 TEST(GIFImageDecoderTest, bitmapAlphaType) {
360 RefPtr<SharedBuffer> full_data = ReadFile(kDecodersTestingDir, "radient.gif");
361 ASSERT_TRUE(full_data.Get());
362
363 // Empirically chosen truncation size:
364 // a) large enough to produce a partial frame &&
365 // b) small enough to not fully decode the frame
366 const size_t kTruncateSize = 800;
367 ASSERT_TRUE(kTruncateSize < full_data->size());
368 RefPtr<SharedBuffer> partial_data =
369 SharedBuffer::Create(full_data->Data(), kTruncateSize);
370
371 std::unique_ptr<ImageDecoder> premul_decoder = WTF::WrapUnique(
372 new GIFImageDecoder(ImageDecoder::kAlphaPremultiplied,
373 ColorBehavior::TransformToTargetForTesting(),
374 ImageDecoder::kNoDecodedImageByteLimit));
375 std::unique_ptr<ImageDecoder> unpremul_decoder = WTF::WrapUnique(
376 new GIFImageDecoder(ImageDecoder::kAlphaNotPremultiplied,
377 ColorBehavior::TransformToTargetForTesting(),
378 ImageDecoder::kNoDecodedImageByteLimit));
379
380 // Partially decoded frame => the frame alpha type is unknown and should
381 // reflect the requested format.
382 premul_decoder->SetData(partial_data.Get(), false);
383 ASSERT_TRUE(premul_decoder->FrameCount());
384 unpremul_decoder->SetData(partial_data.Get(), false);
385 ASSERT_TRUE(unpremul_decoder->FrameCount());
386 ImageFrame* premul_frame = premul_decoder->FrameBufferAtIndex(0);
387 EXPECT_TRUE(premul_frame &&
388 premul_frame->GetStatus() != ImageFrame::kFrameComplete);
389 EXPECT_EQ(premul_frame->Bitmap().alphaType(), kPremul_SkAlphaType);
390 ImageFrame* unpremul_frame = unpremul_decoder->FrameBufferAtIndex(0);
391 EXPECT_TRUE(unpremul_frame &&
392 unpremul_frame->GetStatus() != ImageFrame::kFrameComplete);
393 EXPECT_EQ(unpremul_frame->Bitmap().alphaType(), kUnpremul_SkAlphaType);
394
395 // Fully decoded frame => the frame alpha type is known (opaque).
396 premul_decoder->SetData(full_data.Get(), true);
397 ASSERT_TRUE(premul_decoder->FrameCount());
398 unpremul_decoder->SetData(full_data.Get(), true);
399 ASSERT_TRUE(unpremul_decoder->FrameCount());
400 premul_frame = premul_decoder->FrameBufferAtIndex(0);
401 EXPECT_TRUE(premul_frame &&
402 premul_frame->GetStatus() == ImageFrame::kFrameComplete);
403 EXPECT_EQ(premul_frame->Bitmap().alphaType(), kOpaque_SkAlphaType);
404 unpremul_frame = unpremul_decoder->FrameBufferAtIndex(0);
405 EXPECT_TRUE(unpremul_frame &&
406 unpremul_frame->GetStatus() == ImageFrame::kFrameComplete);
407 EXPECT_EQ(unpremul_frame->Bitmap().alphaType(), kOpaque_SkAlphaType);
408 }
409
410 namespace {
411 // Needed to exercise ImageDecoder::SetMemoryAllocator, but still does the
412 // default allocation.
413 class Allocator final : public SkBitmap::Allocator {
414 bool allocPixelRef(SkBitmap* dst, SkColorTable* ctable) override {
415 return dst->tryAllocPixels(ctable);
416 }
417 };
418 }
419
420 // Ensure that calling SetMemoryAllocator does not short-circuit
421 // InitializeNewFrame.
422 TEST(GIFImageDecoderTest, externalAllocator) {
423 auto data = ReadFile(kLayoutTestResourcesDir, "boston.gif");
424 ASSERT_TRUE(data.Get());
425
426 auto decoder = CreateDecoder();
427 decoder->SetData(data.Get(), true);
428
429 Allocator allocator;
430 decoder->SetMemoryAllocator(&allocator);
431 EXPECT_EQ(1u, decoder->FrameCount());
432 ImageFrame* frame = decoder->FrameBufferAtIndex(0);
433 decoder->SetMemoryAllocator(nullptr);
434
435 ASSERT_TRUE(frame);
436 EXPECT_EQ(IntRect(IntPoint(), decoder->Size()), frame->OriginalFrameRect());
437 EXPECT_FALSE(frame->HasAlpha());
438 }
439
440 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698