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 "third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h"
32
33 #include <memory>
34
35 #include "base/stl_util.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37 #include "third_party/blink/public/platform/web_data.h"
38 #include "third_party/blink/public/platform/web_size.h"
39 #include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
40 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
41 #include "third_party/blink/renderer/platform/wtf/vector.h"
42
43 namespace blink {
44
45 namespace {
46
47 struct AnimParam {
48 int x_offset, y_offset, width, height;
49 ImageFrame::DisposalMethod disposal_method;
50 ImageFrame::AlphaBlendSource alpha_blend_source;
51 base::TimeDelta duration;
52 bool has_alpha;
53 };
54
CreateWEBPDecoder(ImageDecoder::AlphaOption alpha_option)55 std::unique_ptr<ImageDecoder> CreateWEBPDecoder(
56 ImageDecoder::AlphaOption alpha_option) {
57 return std::make_unique<WEBPImageDecoder>(
58 alpha_option, ColorBehavior::TransformToSRGB(),
59 ImageDecoder::kNoDecodedImageByteLimit);
60 }
61
CreateWEBPDecoder()62 std::unique_ptr<ImageDecoder> CreateWEBPDecoder() {
63 return CreateWEBPDecoder(ImageDecoder::kAlphaNotPremultiplied);
64 }
65
66 // If 'parse_error_expected' is true, error is expected during parse
67 // (FrameCount() call); else error is expected during decode
68 // (FrameBufferAtIndex() call).
TestInvalidImage(const char * webp_file,bool parse_error_expected)69 void TestInvalidImage(const char* webp_file, bool parse_error_expected) {
70 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
71
72 scoped_refptr<SharedBuffer> data = ReadFile(webp_file);
73 ASSERT_TRUE(data.get());
74 decoder->SetData(data.get(), true);
75
76 if (parse_error_expected) {
77 EXPECT_EQ(0u, decoder->FrameCount());
78 EXPECT_FALSE(decoder->DecodeFrameBufferAtIndex(0));
79 } else {
80 EXPECT_GT(decoder->FrameCount(), 0u);
81 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
82 ASSERT_TRUE(frame);
83 EXPECT_EQ(ImageFrame::kFramePartial, frame->GetStatus());
84 }
85 EXPECT_EQ(kAnimationLoopOnce, decoder->RepetitionCount());
86 EXPECT_TRUE(decoder->Failed());
87 }
88
89 } // anonymous namespace
90
TEST(AnimatedWebPTests,uniqueGenerationIDs)91 TEST(AnimatedWebPTests, uniqueGenerationIDs) {
92 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
93
94 scoped_refptr<SharedBuffer> data =
95 ReadFile("/images/resources/webp-animated.webp");
96 ASSERT_TRUE(data.get());
97 decoder->SetData(data.get(), true);
98
99 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
100 uint32_t generation_id0 = frame->Bitmap().getGenerationID();
101 frame = decoder->DecodeFrameBufferAtIndex(1);
102 uint32_t generation_id1 = frame->Bitmap().getGenerationID();
103
104 EXPECT_TRUE(generation_id0 != generation_id1);
105 }
106
TEST(AnimatedWebPTests,verifyAnimationParametersTransparentImage)107 TEST(AnimatedWebPTests, verifyAnimationParametersTransparentImage) {
108 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
109 EXPECT_EQ(kAnimationLoopOnce, decoder->RepetitionCount());
110
111 scoped_refptr<SharedBuffer> data =
112 ReadFile("/images/resources/webp-animated.webp");
113 ASSERT_TRUE(data.get());
114 decoder->SetData(data.get(), true);
115
116 const int kCanvasWidth = 11;
117 const int kCanvasHeight = 29;
118 const AnimParam kFrameParameters[] = {
119 {0, 0, 11, 29, ImageFrame::kDisposeKeep,
120 ImageFrame::kBlendAtopPreviousFrame,
121 base::TimeDelta::FromMilliseconds(1000), true},
122 {2, 10, 7, 17, ImageFrame::kDisposeKeep,
123 ImageFrame::kBlendAtopPreviousFrame,
124 base::TimeDelta::FromMilliseconds(500), true},
125 {2, 2, 7, 16, ImageFrame::kDisposeKeep,
126 ImageFrame::kBlendAtopPreviousFrame,
127 base::TimeDelta::FromMilliseconds(1000), true},
128 };
129
130 for (size_t i = 0; i < base::size(kFrameParameters); ++i) {
131 const ImageFrame* const frame = decoder->DecodeFrameBufferAtIndex(i);
132 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
133 EXPECT_EQ(kCanvasWidth, frame->Bitmap().width());
134 EXPECT_EQ(kCanvasHeight, frame->Bitmap().height());
135 EXPECT_EQ(kFrameParameters[i].x_offset, frame->OriginalFrameRect().X());
136 EXPECT_EQ(kFrameParameters[i].y_offset, frame->OriginalFrameRect().Y());
137 EXPECT_EQ(kFrameParameters[i].width, frame->OriginalFrameRect().Width());
138 EXPECT_EQ(kFrameParameters[i].height, frame->OriginalFrameRect().Height());
139 EXPECT_EQ(kFrameParameters[i].disposal_method, frame->GetDisposalMethod());
140 EXPECT_EQ(kFrameParameters[i].alpha_blend_source,
141 frame->GetAlphaBlendSource());
142 EXPECT_EQ(kFrameParameters[i].duration, frame->Duration());
143 EXPECT_EQ(kFrameParameters[i].has_alpha, frame->HasAlpha());
144 }
145
146 EXPECT_EQ(base::size(kFrameParameters), decoder->FrameCount());
147 EXPECT_EQ(kAnimationLoopInfinite, decoder->RepetitionCount());
148 }
149
TEST(AnimatedWebPTests,verifyAnimationParametersOpaqueFramesTransparentBackground)150 TEST(AnimatedWebPTests,
151 verifyAnimationParametersOpaqueFramesTransparentBackground) {
152 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
153 EXPECT_EQ(kAnimationLoopOnce, decoder->RepetitionCount());
154
155 scoped_refptr<SharedBuffer> data =
156 ReadFile("/images/resources/webp-animated-opaque.webp");
157 ASSERT_TRUE(data.get());
158 decoder->SetData(data.get(), true);
159
160 const int kCanvasWidth = 94;
161 const int kCanvasHeight = 87;
162 const AnimParam kFrameParameters[] = {
163 {4, 10, 33, 32, ImageFrame::kDisposeOverwriteBgcolor,
164 ImageFrame::kBlendAtopPreviousFrame,
165 base::TimeDelta::FromMilliseconds(1000), true},
166 {34, 30, 33, 32, ImageFrame::kDisposeOverwriteBgcolor,
167 ImageFrame::kBlendAtopPreviousFrame,
168 base::TimeDelta::FromMilliseconds(1000), true},
169 {62, 50, 32, 32, ImageFrame::kDisposeOverwriteBgcolor,
170 ImageFrame::kBlendAtopPreviousFrame,
171 base::TimeDelta::FromMilliseconds(1000), true},
172 {10, 54, 32, 33, ImageFrame::kDisposeOverwriteBgcolor,
173 ImageFrame::kBlendAtopPreviousFrame,
174 base::TimeDelta::FromMilliseconds(1000), true},
175 };
176
177 for (size_t i = 0; i < base::size(kFrameParameters); ++i) {
178 const ImageFrame* const frame = decoder->DecodeFrameBufferAtIndex(i);
179 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
180 EXPECT_EQ(kCanvasWidth, frame->Bitmap().width());
181 EXPECT_EQ(kCanvasHeight, frame->Bitmap().height());
182 EXPECT_EQ(kFrameParameters[i].x_offset, frame->OriginalFrameRect().X());
183 EXPECT_EQ(kFrameParameters[i].y_offset, frame->OriginalFrameRect().Y());
184 EXPECT_EQ(kFrameParameters[i].width, frame->OriginalFrameRect().Width());
185 EXPECT_EQ(kFrameParameters[i].height, frame->OriginalFrameRect().Height());
186 EXPECT_EQ(kFrameParameters[i].disposal_method, frame->GetDisposalMethod());
187 EXPECT_EQ(kFrameParameters[i].alpha_blend_source,
188 frame->GetAlphaBlendSource());
189 EXPECT_EQ(kFrameParameters[i].duration, frame->Duration());
190 EXPECT_EQ(kFrameParameters[i].has_alpha, frame->HasAlpha());
191 }
192
193 EXPECT_EQ(base::size(kFrameParameters), decoder->FrameCount());
194 EXPECT_EQ(kAnimationLoopInfinite, decoder->RepetitionCount());
195 }
196
TEST(AnimatedWebPTests,verifyAnimationParametersBlendOverwrite)197 TEST(AnimatedWebPTests, verifyAnimationParametersBlendOverwrite) {
198 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
199 EXPECT_EQ(kAnimationLoopOnce, decoder->RepetitionCount());
200
201 scoped_refptr<SharedBuffer> data =
202 ReadFile("/images/resources/webp-animated-no-blend.webp");
203 ASSERT_TRUE(data.get());
204 decoder->SetData(data.get(), true);
205
206 const int kCanvasWidth = 94;
207 const int kCanvasHeight = 87;
208 const AnimParam kFrameParameters[] = {
209 {4, 10, 33, 32, ImageFrame::kDisposeOverwriteBgcolor,
210 ImageFrame::kBlendAtopBgcolor, base::TimeDelta::FromMilliseconds(1000),
211 true},
212 {34, 30, 33, 32, ImageFrame::kDisposeOverwriteBgcolor,
213 ImageFrame::kBlendAtopBgcolor, base::TimeDelta::FromMilliseconds(1000),
214 true},
215 {62, 50, 32, 32, ImageFrame::kDisposeOverwriteBgcolor,
216 ImageFrame::kBlendAtopBgcolor, base::TimeDelta::FromMilliseconds(1000),
217 true},
218 {10, 54, 32, 33, ImageFrame::kDisposeOverwriteBgcolor,
219 ImageFrame::kBlendAtopBgcolor, base::TimeDelta::FromMilliseconds(1000),
220 true},
221 };
222
223 for (size_t i = 0; i < base::size(kFrameParameters); ++i) {
224 const ImageFrame* const frame = decoder->DecodeFrameBufferAtIndex(i);
225 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
226 EXPECT_EQ(kCanvasWidth, frame->Bitmap().width());
227 EXPECT_EQ(kCanvasHeight, frame->Bitmap().height());
228 EXPECT_EQ(kFrameParameters[i].x_offset, frame->OriginalFrameRect().X());
229 EXPECT_EQ(kFrameParameters[i].y_offset, frame->OriginalFrameRect().Y());
230 EXPECT_EQ(kFrameParameters[i].width, frame->OriginalFrameRect().Width());
231 EXPECT_EQ(kFrameParameters[i].height, frame->OriginalFrameRect().Height());
232 EXPECT_EQ(kFrameParameters[i].disposal_method, frame->GetDisposalMethod());
233 EXPECT_EQ(kFrameParameters[i].alpha_blend_source,
234 frame->GetAlphaBlendSource());
235 EXPECT_EQ(kFrameParameters[i].duration, frame->Duration());
236 EXPECT_EQ(kFrameParameters[i].has_alpha, frame->HasAlpha());
237 }
238
239 EXPECT_EQ(base::size(kFrameParameters), decoder->FrameCount());
240 EXPECT_EQ(kAnimationLoopInfinite, decoder->RepetitionCount());
241 }
242
TEST(AnimatedWebPTests,parseAndDecodeByteByByte)243 TEST(AnimatedWebPTests, parseAndDecodeByteByByte) {
244 TestByteByByteDecode(&CreateWEBPDecoder,
245 "/images/resources/webp-animated.webp", 3u,
246 kAnimationLoopInfinite);
247 TestByteByByteDecode(&CreateWEBPDecoder,
248 "/images/resources/webp-animated-icc-xmp.webp", 13u,
249 31999);
250 }
251
TEST(AnimatedWebPTests,invalidImages)252 TEST(AnimatedWebPTests, invalidImages) {
253 // ANMF chunk size is smaller than ANMF header size.
254 TestInvalidImage("/images/resources/invalid-animated-webp.webp", true);
255 // One of the frame rectangles extends outside the image boundary.
256 TestInvalidImage("/images/resources/invalid-animated-webp3.webp", true);
257 }
258
TEST(AnimatedWebPTests,truncatedLastFrame)259 TEST(AnimatedWebPTests, truncatedLastFrame) {
260 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
261
262 scoped_refptr<SharedBuffer> data =
263 ReadFile("/images/resources/invalid-animated-webp2.webp");
264 ASSERT_TRUE(data.get());
265 decoder->SetData(data.get(), true);
266
267 size_t frame_count = 8;
268 EXPECT_EQ(frame_count, decoder->FrameCount());
269 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
270 ASSERT_TRUE(frame);
271 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
272 EXPECT_FALSE(decoder->Failed());
273 frame = decoder->DecodeFrameBufferAtIndex(frame_count - 1);
274 ASSERT_TRUE(frame);
275 EXPECT_EQ(ImageFrame::kFramePartial, frame->GetStatus());
276 EXPECT_TRUE(decoder->Failed());
277 frame = decoder->DecodeFrameBufferAtIndex(0);
278 ASSERT_TRUE(frame);
279 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
280 }
281
TEST(AnimatedWebPTests,truncatedInBetweenFrame)282 TEST(AnimatedWebPTests, truncatedInBetweenFrame) {
283 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
284
285 const Vector<char> full_data =
286 ReadFile("/images/resources/invalid-animated-webp4.webp")
287 ->CopyAs<Vector<char>>();
288 scoped_refptr<SharedBuffer> data =
289 SharedBuffer::Create(full_data.data(), full_data.size() - 1);
290 decoder->SetData(data.get(), false);
291
292 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(1);
293 ASSERT_TRUE(frame);
294 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
295 frame = decoder->DecodeFrameBufferAtIndex(2);
296 ASSERT_TRUE(frame);
297 EXPECT_EQ(ImageFrame::kFramePartial, frame->GetStatus());
298 EXPECT_TRUE(decoder->Failed());
299 }
300
301 // Tests for a crash that used to happen for a specific file with specific
302 // sequence of method calls.
TEST(AnimatedWebPTests,reproCrash)303 TEST(AnimatedWebPTests, reproCrash) {
304 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
305
306 scoped_refptr<SharedBuffer> full_data_buffer =
307 ReadFile("/images/resources/invalid_vp8_vp8x.webp");
308 ASSERT_TRUE(full_data_buffer.get());
309 const Vector<char> full_data = full_data_buffer->CopyAs<Vector<char>>();
310
311 // Parse partial data up to which error in bitstream is not detected.
312 const size_t kPartialSize = 32768;
313 ASSERT_GT(full_data.size(), kPartialSize);
314 scoped_refptr<SharedBuffer> data =
315 SharedBuffer::Create(full_data.data(), kPartialSize);
316 decoder->SetData(data.get(), false);
317 EXPECT_EQ(1u, decoder->FrameCount());
318 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
319 ASSERT_TRUE(frame);
320 EXPECT_EQ(ImageFrame::kFramePartial, frame->GetStatus());
321 EXPECT_FALSE(decoder->Failed());
322
323 // Parse full data now. The error in bitstream should now be detected.
324 decoder->SetData(full_data_buffer.get(), true);
325 EXPECT_EQ(1u, decoder->FrameCount());
326 frame = decoder->DecodeFrameBufferAtIndex(0);
327 ASSERT_TRUE(frame);
328 EXPECT_EQ(ImageFrame::kFramePartial, frame->GetStatus());
329 EXPECT_EQ(kAnimationLoopOnce, decoder->RepetitionCount());
330 EXPECT_TRUE(decoder->Failed());
331 }
332
TEST(AnimatedWebPTests,progressiveDecode)333 TEST(AnimatedWebPTests, progressiveDecode) {
334 TestProgressiveDecoding(&CreateWEBPDecoder,
335 "/images/resources/webp-animated.webp");
336 }
337
TEST(AnimatedWebPTests,frameIsCompleteAndDuration)338 TEST(AnimatedWebPTests, frameIsCompleteAndDuration) {
339 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
340
341 scoped_refptr<SharedBuffer> data_buffer =
342 ReadFile("/images/resources/webp-animated.webp");
343 ASSERT_TRUE(data_buffer.get());
344 const Vector<char> data = data_buffer->CopyAs<Vector<char>>();
345
346 ASSERT_GE(data.size(), 10u);
347 scoped_refptr<SharedBuffer> temp_data =
348 SharedBuffer::Create(data.data(), data.size() - 10);
349 decoder->SetData(temp_data.get(), false);
350
351 EXPECT_EQ(2u, decoder->FrameCount());
352 EXPECT_FALSE(decoder->Failed());
353 EXPECT_TRUE(decoder->FrameIsReceivedAtIndex(0));
354 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000),
355 decoder->FrameDurationAtIndex(0));
356 EXPECT_TRUE(decoder->FrameIsReceivedAtIndex(1));
357 EXPECT_EQ(base::TimeDelta::FromMilliseconds(500),
358 decoder->FrameDurationAtIndex(1));
359
360 decoder->SetData(data_buffer.get(), true);
361 EXPECT_EQ(3u, decoder->FrameCount());
362 EXPECT_TRUE(decoder->FrameIsReceivedAtIndex(0));
363 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000),
364 decoder->FrameDurationAtIndex(0));
365 EXPECT_TRUE(decoder->FrameIsReceivedAtIndex(1));
366 EXPECT_EQ(base::TimeDelta::FromMilliseconds(500),
367 decoder->FrameDurationAtIndex(1));
368 EXPECT_TRUE(decoder->FrameIsReceivedAtIndex(2));
369 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000),
370 decoder->FrameDurationAtIndex(2));
371 }
372
TEST(AnimatedWebPTests,updateRequiredPreviousFrameAfterFirstDecode)373 TEST(AnimatedWebPTests, updateRequiredPreviousFrameAfterFirstDecode) {
374 TestUpdateRequiredPreviousFrameAfterFirstDecode(
375 &CreateWEBPDecoder, "/images/resources/webp-animated.webp");
376 }
377
TEST(AnimatedWebPTests,randomFrameDecode)378 TEST(AnimatedWebPTests, randomFrameDecode) {
379 TestRandomFrameDecode(&CreateWEBPDecoder,
380 "/images/resources/webp-animated.webp");
381 TestRandomFrameDecode(&CreateWEBPDecoder,
382 "/images/resources/webp-animated-opaque.webp");
383 TestRandomFrameDecode(&CreateWEBPDecoder,
384 "/images/resources/webp-animated-large.webp");
385 TestRandomFrameDecode(&CreateWEBPDecoder,
386 "/images/resources/webp-animated-icc-xmp.webp");
387 }
388
TEST(AnimatedWebPTests,randomDecodeAfterClearFrameBufferCache)389 TEST(AnimatedWebPTests, randomDecodeAfterClearFrameBufferCache) {
390 TestRandomDecodeAfterClearFrameBufferCache(
391 &CreateWEBPDecoder, "/images/resources/webp-animated.webp");
392 TestRandomDecodeAfterClearFrameBufferCache(
393 &CreateWEBPDecoder, "/images/resources/webp-animated-opaque.webp");
394 TestRandomDecodeAfterClearFrameBufferCache(
395 &CreateWEBPDecoder, "/images/resources/webp-animated-large.webp");
396 TestRandomDecodeAfterClearFrameBufferCache(
397 &CreateWEBPDecoder, "/images/resources/webp-animated-icc-xmp.webp");
398 }
399
TEST(AnimatedWebPTests,resumePartialDecodeAfterClearFrameBufferCache)400 TEST(AnimatedWebPTests,
401 resumePartialDecodeAfterClearFrameBufferCache) {
402 TestResumePartialDecodeAfterClearFrameBufferCache(
403 &CreateWEBPDecoder, "/images/resources/webp-animated-large.webp");
404 }
405
TEST(AnimatedWebPTests,decodeAfterReallocatingData)406 TEST(AnimatedWebPTests, decodeAfterReallocatingData) {
407 TestDecodeAfterReallocatingData(&CreateWEBPDecoder,
408 "/images/resources/webp-animated.webp");
409 TestDecodeAfterReallocatingData(
410 &CreateWEBPDecoder, "/images/resources/webp-animated-icc-xmp.webp");
411 }
412
TEST(AnimatedWebPTests,alphaBlending)413 TEST(AnimatedWebPTests, alphaBlending) {
414 TestAlphaBlending(&CreateWEBPDecoder, "/images/resources/webp-animated.webp");
415 TestAlphaBlending(&CreateWEBPDecoder,
416 "/images/resources/webp-animated-semitransparent1.webp");
417 TestAlphaBlending(&CreateWEBPDecoder,
418 "/images/resources/webp-animated-semitransparent2.webp");
419 TestAlphaBlending(&CreateWEBPDecoder,
420 "/images/resources/webp-animated-semitransparent3.webp");
421 TestAlphaBlending(&CreateWEBPDecoder,
422 "/images/resources/webp-animated-semitransparent4.webp");
423 }
424
TEST(AnimatedWebPTests,isSizeAvailable)425 TEST(AnimatedWebPTests, isSizeAvailable) {
426 TestByteByByteSizeAvailable(&CreateWEBPDecoder,
427 "/images/resources/webp-animated.webp", 142u,
428 false, kAnimationLoopInfinite);
429 // FIXME: Add color profile support for animated webp images.
430 TestByteByByteSizeAvailable(&CreateWEBPDecoder,
431 "/images/resources/webp-animated-icc-xmp.webp",
432 1404u, false, 31999);
433 }
434
TEST(AnimatedWEBPTests,clearCacheExceptFrameWithAncestors)435 TEST(AnimatedWEBPTests, clearCacheExceptFrameWithAncestors) {
436 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
437
438 scoped_refptr<SharedBuffer> full_data =
439 ReadFile("/images/resources/webp-animated.webp");
440 ASSERT_TRUE(full_data.get());
441 decoder->SetData(full_data.get(), true);
442
443 ASSERT_EQ(3u, decoder->FrameCount());
444 // We need to store pointers to the image frames, since calling
445 // FrameBufferAtIndex will decode the frame if it is not FrameComplete,
446 // and we want to read the status of the frame without decoding it again.
447 ImageFrame* buffers[3];
448 size_t buffer_sizes[3];
449 for (size_t i = 0; i < decoder->FrameCount(); i++) {
450 buffers[i] = decoder->DecodeFrameBufferAtIndex(i);
451 ASSERT_EQ(ImageFrame::kFrameComplete, buffers[i]->GetStatus());
452 buffer_sizes[i] = decoder->FrameBytesAtIndex(i);
453 }
454
455 // Explicitly set the required previous frame for the frames, since this test
456 // is designed on this chain. Whether the frames actually depend on each
457 // other is not important for this test - ClearCacheExceptFrame just looks at
458 // the frame status and the required previous frame.
459 buffers[1]->SetRequiredPreviousFrameIndex(0);
460 buffers[2]->SetRequiredPreviousFrameIndex(1);
461
462 // Clear the cache except for a single frame. All other frames should be
463 // cleared to FrameEmpty, since this frame is FrameComplete.
464 EXPECT_EQ(buffer_sizes[0] + buffer_sizes[2],
465 decoder->ClearCacheExceptFrame(1));
466 EXPECT_EQ(ImageFrame::kFrameEmpty, buffers[0]->GetStatus());
467 EXPECT_EQ(ImageFrame::kFrameComplete, buffers[1]->GetStatus());
468 EXPECT_EQ(ImageFrame::kFrameEmpty, buffers[2]->GetStatus());
469
470 // Verify that the required previous frame is also preserved if the provided
471 // frame is not FrameComplete. The simulated situation is:
472 //
473 // Frame 0 <--------- Frame 1 <--------- Frame 2
474 // FrameComplete depends on FrameComplete depends on FramePartial
475 //
476 // The expected outcome is that frame 1 and frame 2 are preserved, since
477 // frame 1 is necessary to fully decode frame 2.
478 for (size_t i = 0; i < decoder->FrameCount(); i++) {
479 ASSERT_EQ(ImageFrame::kFrameComplete,
480 decoder->DecodeFrameBufferAtIndex(i)->GetStatus());
481 }
482 buffers[2]->SetStatus(ImageFrame::kFramePartial);
483 EXPECT_EQ(buffer_sizes[0], decoder->ClearCacheExceptFrame(2));
484 EXPECT_EQ(ImageFrame::kFrameEmpty, buffers[0]->GetStatus());
485 EXPECT_EQ(ImageFrame::kFrameComplete, buffers[1]->GetStatus());
486 EXPECT_EQ(ImageFrame::kFramePartial, buffers[2]->GetStatus());
487
488 // Verify that the nearest FrameComplete required frame is preserved if
489 // earlier required frames in the ancestor list are not FrameComplete. The
490 // simulated situation is:
491 //
492 // Frame 0 <--------- Frame 1 <--------- Frame 2
493 // FrameComplete depends on FrameEmpty depends on FramePartial
494 //
495 // The expected outcome is that frame 0 and frame 2 are preserved. Frame 2
496 // should be preserved since it is the frame passed to ClearCacheExceptFrame.
497 // Frame 0 should be preserved since it is the nearest FrameComplete ancestor.
498 // Thus, since frame 1 is FrameEmpty, no data is cleared in this case.
499 for (size_t i = 0; i < decoder->FrameCount(); i++) {
500 ASSERT_EQ(ImageFrame::kFrameComplete,
501 decoder->DecodeFrameBufferAtIndex(i)->GetStatus());
502 }
503 buffers[1]->SetStatus(ImageFrame::kFrameEmpty);
504 buffers[2]->SetStatus(ImageFrame::kFramePartial);
505 EXPECT_EQ(0u, decoder->ClearCacheExceptFrame(2));
506 EXPECT_EQ(ImageFrame::kFrameComplete, buffers[0]->GetStatus());
507 EXPECT_EQ(ImageFrame::kFrameEmpty, buffers[1]->GetStatus());
508 EXPECT_EQ(ImageFrame::kFramePartial, buffers[2]->GetStatus());
509 }
510
TEST(StaticWebPTests,truncatedImage)511 TEST(StaticWebPTests, truncatedImage) {
512 // VP8 data is truncated.
513 TestInvalidImage("/images/resources/truncated.webp", false);
514 // Chunk size in RIFF header doesn't match the file size.
515 TestInvalidImage("/images/resources/truncated2.webp", true);
516 }
517
518 // Regression test for a bug where some valid images were failing to decode
519 // incrementally.
TEST(StaticWebPTests,incrementalDecode)520 TEST(StaticWebPTests, incrementalDecode) {
521 TestByteByByteDecode(&CreateWEBPDecoder,
522 "/images/resources/crbug.364830.webp", 1u,
523 kAnimationNone);
524 }
525
TEST(StaticWebPTests,isSizeAvailable)526 TEST(StaticWebPTests, isSizeAvailable) {
527 TestByteByByteSizeAvailable(&CreateWEBPDecoder,
528 "/images/resources/webp-color-profile-lossy.webp",
529 520u, true, kAnimationNone);
530 TestByteByByteSizeAvailable(&CreateWEBPDecoder, "/images/resources/test.webp",
531 30u, false, kAnimationNone);
532 }
533
TEST(StaticWebPTests,notAnimated)534 TEST(StaticWebPTests, notAnimated) {
535 std::unique_ptr<ImageDecoder> decoder = CreateWEBPDecoder();
536 scoped_refptr<SharedBuffer> data =
537 ReadFile("/images/resources/webp-color-profile-lossy.webp");
538 ASSERT_TRUE(data.get());
539 decoder->SetData(data.get(), true);
540 EXPECT_EQ(1u, decoder->FrameCount());
541 EXPECT_EQ(kAnimationNone, decoder->RepetitionCount());
542 }
543
544 } // namespace blink
545