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