2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #include "platform/image-decoders/webp/WEBPImageDecoder.h"
35 #include "platform/RuntimeEnabledFeatures.h"
36 #include "platform/SharedBuffer.h"
37 #include "public/platform/Platform.h"
38 #include "public/platform/WebData.h"
39 #include "public/platform/WebSize.h"
40 #include "public/platform/WebUnitTestSupport.h"
41 #include "wtf/OwnPtr.h"
42 #include "wtf/PassOwnPtr.h"
43 #include "wtf/StringHasher.h"
44 #include "wtf/Vector.h"
45 #include "wtf/dtoa/utils.h"
46 #include <gtest/gtest.h>
48 using namespace blink;
52 PassRefPtr<SharedBuffer> readFile(const char* fileName)
54 String filePath = Platform::current()->unitTestSupport()->webKitRootDir();
55 filePath.append(fileName);
57 return Platform::current()->unitTestSupport()->readFromFile(filePath);
60 PassOwnPtr<WEBPImageDecoder> createDecoder(ImageSource::AlphaOption alphaOption = ImageSource::AlphaNotPremultiplied)
62 return adoptPtr(new WEBPImageDecoder(alphaOption, ImageSource::GammaAndColorProfileApplied, ImageDecoder::noDecodedImageByteLimit));
65 unsigned hashSkBitmap(const SkBitmap& bitmap)
67 return StringHasher::hashMemory(bitmap.getPixels(), bitmap.getSize());
70 void createDecodingBaseline(SharedBuffer* data, Vector<unsigned>* baselineHashes)
72 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
73 decoder->setData(data, true);
74 size_t frameCount = decoder->frameCount();
75 for (size_t i = 0; i < frameCount; ++i) {
76 ImageFrame* frame = decoder->frameBufferAtIndex(i);
77 baselineHashes->append(hashSkBitmap(frame->getSkBitmap()));
81 void testRandomFrameDecode(const char* webpFile)
83 SCOPED_TRACE(webpFile);
85 RefPtr<SharedBuffer> fullData = readFile(webpFile);
86 ASSERT_TRUE(fullData.get());
87 Vector<unsigned> baselineHashes;
88 createDecodingBaseline(fullData.get(), &baselineHashes);
89 size_t frameCount = baselineHashes.size();
91 // Random decoding should get the same results as sequential decoding.
92 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
93 decoder->setData(fullData.get(), true);
94 const size_t skippingStep = 5;
95 for (size_t i = 0; i < skippingStep; ++i) {
96 for (size_t j = i; j < frameCount; j += skippingStep) {
97 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
98 ImageFrame* frame = decoder->frameBufferAtIndex(j);
99 EXPECT_EQ(baselineHashes[j], hashSkBitmap(frame->getSkBitmap()));
103 // Decoding in reverse order.
104 decoder = createDecoder();
105 decoder->setData(fullData.get(), true);
106 for (size_t i = frameCount; i; --i) {
107 SCOPED_TRACE(testing::Message() << "Reverse i:" << i);
108 ImageFrame* frame = decoder->frameBufferAtIndex(i - 1);
109 EXPECT_EQ(baselineHashes[i - 1], hashSkBitmap(frame->getSkBitmap()));
113 void testRandomDecodeAfterClearFrameBufferCache(const char* webpFile)
115 SCOPED_TRACE(webpFile);
117 RefPtr<SharedBuffer> data = readFile(webpFile);
118 ASSERT_TRUE(data.get());
119 Vector<unsigned> baselineHashes;
120 createDecodingBaseline(data.get(), &baselineHashes);
121 size_t frameCount = baselineHashes.size();
123 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
124 decoder->setData(data.get(), true);
125 for (size_t clearExceptFrame = 0; clearExceptFrame < frameCount; ++clearExceptFrame) {
126 decoder->clearCacheExceptFrame(clearExceptFrame);
127 const size_t skippingStep = 5;
128 for (size_t i = 0; i < skippingStep; ++i) {
129 for (size_t j = 0; j < frameCount; j += skippingStep) {
130 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
131 ImageFrame* frame = decoder->frameBufferAtIndex(j);
132 EXPECT_EQ(baselineHashes[j], hashSkBitmap(frame->getSkBitmap()));
138 void testDecodeAfterReallocatingData(const char* webpFile)
140 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
141 RefPtr<SharedBuffer> data = readFile(webpFile);
142 ASSERT_TRUE(data.get());
144 // Parse from 'data'.
145 decoder->setData(data.get(), true);
146 size_t frameCount = decoder->frameCount();
148 // ... and then decode frames from 'reallocatedData'.
149 RefPtr<SharedBuffer> reallocatedData = data.get()->copy();
150 ASSERT_TRUE(reallocatedData.get());
152 decoder->setData(reallocatedData.get(), true);
154 for (size_t i = 0; i < frameCount; ++i) {
155 const ImageFrame* const frame = decoder->frameBufferAtIndex(i);
156 EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
160 void testByteByByteDecode(const char* webpFile, size_t expectedFrameCount, int expectedRepetitionCount)
162 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
163 RefPtr<SharedBuffer> data = readFile(webpFile);
164 ASSERT_TRUE(data.get());
166 size_t frameCount = 0;
167 size_t framesDecoded = 0;
169 // Pass data to decoder byte by byte.
170 for (size_t length = 1; length <= data->size(); ++length) {
171 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), length);
172 decoder->setData(tempData.get(), length == data->size());
174 EXPECT_LE(frameCount, decoder->frameCount());
175 frameCount = decoder->frameCount();
177 ImageFrame* frame = decoder->frameBufferAtIndex(frameCount - 1);
178 if (frame && frame->status() == ImageFrame::FrameComplete && framesDecoded < frameCount)
181 if (decoder->failed())
185 EXPECT_FALSE(decoder->failed());
186 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
187 EXPECT_EQ(expectedFrameCount, framesDecoded);
188 EXPECT_EQ(expectedRepetitionCount, decoder->repetitionCount());
191 // If 'parseErrorExpected' is true, error is expected during parse (frameCount()
192 // call); else error is expected during decode (frameBufferAtIndex() call).
193 void testInvalidImage(const char* webpFile, bool parseErrorExpected)
195 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
197 RefPtr<SharedBuffer> data = readFile(webpFile);
198 ASSERT_TRUE(data.get());
199 decoder->setData(data.get(), true);
201 if (parseErrorExpected)
202 EXPECT_EQ(0u, decoder->frameCount());
204 EXPECT_LT(0u, decoder->frameCount());
205 ImageFrame* frame = decoder->frameBufferAtIndex(0);
207 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
210 uint32_t premultiplyColor(uint32_t c)
212 return SkPremultiplyARGBInline(SkGetPackedA32(c), SkGetPackedR32(c), SkGetPackedG32(c), SkGetPackedB32(c));
215 void verifyFramesMatch(const char* webpFile, const ImageFrame* const a, ImageFrame* const b)
217 const SkBitmap& bitmapA = a->getSkBitmap();
218 const SkBitmap& bitmapB = b->getSkBitmap();
219 ASSERT_EQ(bitmapA.width(), bitmapB.width());
220 ASSERT_EQ(bitmapA.height(), bitmapB.height());
222 int maxDifference = 0;
223 for (int y = 0; y < bitmapA.height(); ++y) {
224 for (int x = 0; x < bitmapA.width(); ++x) {
225 uint32_t colorA = *bitmapA.getAddr32(x, y);
226 if (!a->premultiplyAlpha())
227 colorA = premultiplyColor(colorA);
228 uint32_t colorB = *bitmapB.getAddr32(x, y);
229 if (!b->premultiplyAlpha())
230 colorB = premultiplyColor(colorB);
231 uint8_t* pixelA = reinterpret_cast<uint8_t*>(&colorA);
232 uint8_t* pixelB = reinterpret_cast<uint8_t*>(&colorB);
233 for (int channel = 0; channel < 4; ++channel) {
234 const int difference = abs(pixelA[channel] - pixelB[channel]);
235 if (difference > maxDifference)
236 maxDifference = difference;
241 // Pre-multiplication could round the RGBA channel values. So, we declare
242 // that the frames match if the RGBA channel values differ by at most 2.
243 EXPECT_GE(2, maxDifference) << webpFile;
246 // Verify that result of alpha blending is similar for AlphaPremultiplied and AlphaNotPremultiplied cases.
247 void testAlphaBlending(const char* webpFile)
249 RefPtr<SharedBuffer> data = readFile(webpFile);
250 ASSERT_TRUE(data.get());
252 OwnPtr<WEBPImageDecoder> decoderA = createDecoder(ImageSource::AlphaPremultiplied);
253 decoderA->setData(data.get(), true);
255 OwnPtr<WEBPImageDecoder> decoderB = createDecoder(ImageSource::AlphaNotPremultiplied);
256 decoderB->setData(data.get(), true);
258 size_t frameCount = decoderA->frameCount();
259 ASSERT_EQ(frameCount, decoderB->frameCount());
261 for (size_t i = 0; i < frameCount; ++i)
262 verifyFramesMatch(webpFile, decoderA->frameBufferAtIndex(i), decoderB->frameBufferAtIndex(i));
267 TEST(AnimatedWebPTests, uniqueGenerationIDs)
269 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
271 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/webp-animated.webp");
272 ASSERT_TRUE(data.get());
273 decoder->setData(data.get(), true);
275 ImageFrame* frame = decoder->frameBufferAtIndex(0);
276 uint32_t generationID0 = frame->getSkBitmap().getGenerationID();
277 frame = decoder->frameBufferAtIndex(1);
278 uint32_t generationID1 = frame->getSkBitmap().getGenerationID();
280 EXPECT_TRUE(generationID0 != generationID1);
283 TEST(AnimatedWebPTests, verifyAnimationParametersTransparentImage)
285 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
286 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
288 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/webp-animated.webp");
289 ASSERT_TRUE(data.get());
290 decoder->setData(data.get(), true);
292 const int canvasWidth = 11;
293 const int canvasHeight = 29;
294 const struct AnimParam {
295 int xOffset, yOffset, width, height;
296 ImageFrame::DisposalMethod disposalMethod;
297 ImageFrame::AlphaBlendSource alphaBlendSource;
300 } frameParameters[] = {
301 { 0, 0, 11, 29, ImageFrame::DisposeKeep, ImageFrame::BlendAtopPreviousFrame, 1000u, true },
302 { 2, 10, 7, 17, ImageFrame::DisposeKeep, ImageFrame::BlendAtopPreviousFrame, 500u, true },
303 { 2, 2, 7, 16, ImageFrame::DisposeKeep, ImageFrame::BlendAtopPreviousFrame, 1000u, true },
306 for (size_t i = 0; i < ARRAY_SIZE(frameParameters); ++i) {
307 const ImageFrame* const frame = decoder->frameBufferAtIndex(i);
308 EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
309 EXPECT_EQ(canvasWidth, frame->getSkBitmap().width());
310 EXPECT_EQ(canvasHeight, frame->getSkBitmap().height());
311 EXPECT_EQ(frameParameters[i].xOffset, frame->originalFrameRect().x());
312 EXPECT_EQ(frameParameters[i].yOffset, frame->originalFrameRect().y());
313 EXPECT_EQ(frameParameters[i].width, frame->originalFrameRect().width());
314 EXPECT_EQ(frameParameters[i].height, frame->originalFrameRect().height());
315 EXPECT_EQ(frameParameters[i].disposalMethod, frame->disposalMethod());
316 EXPECT_EQ(frameParameters[i].alphaBlendSource, frame->alphaBlendSource());
317 EXPECT_EQ(frameParameters[i].duration, frame->duration());
318 EXPECT_EQ(frameParameters[i].hasAlpha, frame->hasAlpha());
321 EXPECT_EQ(ARRAY_SIZE(frameParameters), decoder->frameCount());
322 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
325 TEST(AnimatedWebPTests, verifyAnimationParametersOpaqueFramesTransparentBackground)
327 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
328 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
330 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/webp-animated-opaque.webp");
331 ASSERT_TRUE(data.get());
332 decoder->setData(data.get(), true);
334 const int canvasWidth = 94;
335 const int canvasHeight = 87;
336 const struct AnimParam {
337 int xOffset, yOffset, width, height;
338 ImageFrame::DisposalMethod disposalMethod;
339 ImageFrame::AlphaBlendSource alphaBlendSource;
342 } frameParameters[] = {
343 { 4, 10, 33, 32, ImageFrame::DisposeOverwriteBgcolor, ImageFrame::BlendAtopPreviousFrame, 1000u, true },
344 { 34, 30, 33, 32, ImageFrame::DisposeOverwriteBgcolor, ImageFrame::BlendAtopPreviousFrame, 1000u, true },
345 { 62, 50, 32, 32, ImageFrame::DisposeOverwriteBgcolor, ImageFrame::BlendAtopPreviousFrame, 1000u, true },
346 { 10, 54, 32, 33, ImageFrame::DisposeOverwriteBgcolor, ImageFrame::BlendAtopPreviousFrame, 1000u, true },
349 for (size_t i = 0; i < ARRAY_SIZE(frameParameters); ++i) {
350 const ImageFrame* const frame = decoder->frameBufferAtIndex(i);
351 EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
352 EXPECT_EQ(canvasWidth, frame->getSkBitmap().width());
353 EXPECT_EQ(canvasHeight, frame->getSkBitmap().height());
354 EXPECT_EQ(frameParameters[i].xOffset, frame->originalFrameRect().x());
355 EXPECT_EQ(frameParameters[i].yOffset, frame->originalFrameRect().y());
356 EXPECT_EQ(frameParameters[i].width, frame->originalFrameRect().width());
357 EXPECT_EQ(frameParameters[i].height, frame->originalFrameRect().height());
358 EXPECT_EQ(frameParameters[i].disposalMethod, frame->disposalMethod());
359 EXPECT_EQ(frameParameters[i].alphaBlendSource, frame->alphaBlendSource());
360 EXPECT_EQ(frameParameters[i].duration, frame->duration());
361 EXPECT_EQ(frameParameters[i].hasAlpha, frame->hasAlpha());
364 EXPECT_EQ(ARRAY_SIZE(frameParameters), decoder->frameCount());
365 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
368 TEST(AnimatedWebPTests, verifyAnimationParametersBlendOverwrite)
370 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
371 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
373 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/webp-animated-no-blend.webp");
374 ASSERT_TRUE(data.get());
375 decoder->setData(data.get(), true);
377 const int canvasWidth = 94;
378 const int canvasHeight = 87;
379 const struct AnimParam {
380 int xOffset, yOffset, width, height;
381 ImageFrame::DisposalMethod disposalMethod;
382 ImageFrame::AlphaBlendSource alphaBlendSource;
385 } frameParameters[] = {
386 { 4, 10, 33, 32, ImageFrame::DisposeOverwriteBgcolor, ImageFrame::BlendAtopBgcolor, 1000u, true },
387 { 34, 30, 33, 32, ImageFrame::DisposeOverwriteBgcolor, ImageFrame::BlendAtopBgcolor, 1000u, true },
388 { 62, 50, 32, 32, ImageFrame::DisposeOverwriteBgcolor, ImageFrame::BlendAtopBgcolor, 1000u, true },
389 { 10, 54, 32, 33, ImageFrame::DisposeOverwriteBgcolor, ImageFrame::BlendAtopBgcolor, 1000u, true },
392 for (size_t i = 0; i < ARRAY_SIZE(frameParameters); ++i) {
393 const ImageFrame* const frame = decoder->frameBufferAtIndex(i);
394 EXPECT_EQ(ImageFrame::FrameComplete, frame->status());
395 EXPECT_EQ(canvasWidth, frame->getSkBitmap().width());
396 EXPECT_EQ(canvasHeight, frame->getSkBitmap().height());
397 EXPECT_EQ(frameParameters[i].xOffset, frame->originalFrameRect().x());
398 EXPECT_EQ(frameParameters[i].yOffset, frame->originalFrameRect().y());
399 EXPECT_EQ(frameParameters[i].width, frame->originalFrameRect().width());
400 EXPECT_EQ(frameParameters[i].height, frame->originalFrameRect().height());
401 EXPECT_EQ(frameParameters[i].disposalMethod, frame->disposalMethod());
402 EXPECT_EQ(frameParameters[i].alphaBlendSource, frame->alphaBlendSource());
403 EXPECT_EQ(frameParameters[i].duration, frame->duration());
404 EXPECT_EQ(frameParameters[i].hasAlpha, frame->hasAlpha());
407 EXPECT_EQ(ARRAY_SIZE(frameParameters), decoder->frameCount());
408 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
411 TEST(AnimatedWebPTests, parseAndDecodeByteByByte)
413 testByteByByteDecode("/LayoutTests/fast/images/resources/webp-animated.webp", 3u, cAnimationLoopInfinite);
414 testByteByByteDecode("/LayoutTests/fast/images/resources/webp-animated-icc-xmp.webp", 13u, 31999);
417 TEST(AnimatedWebPTests, invalidImages)
419 // ANMF chunk size is smaller than ANMF header size.
420 testInvalidImage("/LayoutTests/fast/images/resources/invalid-animated-webp.webp", true);
421 // One of the frame rectangles extends outside the image boundary.
422 testInvalidImage("/LayoutTests/fast/images/resources/invalid-animated-webp3.webp", true);
425 TEST(AnimatedWebPTests, truncatedLastFrame)
427 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
429 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/invalid-animated-webp2.webp");
430 ASSERT_TRUE(data.get());
431 decoder->setData(data.get(), true);
433 size_t frameCount = 8;
434 EXPECT_EQ(frameCount, decoder->frameCount());
435 ImageFrame* frame = decoder->frameBufferAtIndex(frameCount - 1);
437 frame = decoder->frameBufferAtIndex(0);
441 TEST(AnimatedWebPTests, truncatedInBetweenFrame)
443 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
445 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/invalid-animated-webp4.webp");
446 ASSERT_TRUE(fullData.get());
447 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), fullData->size() - 1);
448 decoder->setData(data.get(), false);
450 ImageFrame* frame = decoder->frameBufferAtIndex(2);
454 // Reproduce a crash that used to happen for a specific file with specific sequence of method calls.
455 TEST(AnimatedWebPTests, reproCrash)
457 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
459 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/invalid_vp8_vp8x.webp");
460 ASSERT_TRUE(fullData.get());
462 // Parse partial data up to which error in bitstream is not detected.
463 const size_t partialSize = 32768;
464 ASSERT_GT(fullData->size(), partialSize);
465 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), partialSize);
466 decoder->setData(data.get(), false);
467 EXPECT_EQ(1u, decoder->frameCount());
469 // Parse full data now. The error in bitstream should now be detected.
470 decoder->setData(fullData.get(), true);
471 EXPECT_EQ(0u, decoder->frameCount());
472 ImageFrame* frame = decoder->frameBufferAtIndex(0);
474 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
477 TEST(AnimatedWebPTests, progressiveDecode)
479 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/webp-animated.webp");
480 ASSERT_TRUE(fullData.get());
481 const size_t fullLength = fullData->size();
483 OwnPtr<WEBPImageDecoder> decoder;
486 Vector<unsigned> truncatedHashes;
487 Vector<unsigned> progressiveHashes;
489 // Compute hashes when the file is truncated.
490 const size_t increment = 1;
491 for (size_t i = 1; i <= fullLength; i += increment) {
492 decoder = createDecoder();
493 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i);
494 decoder->setData(data.get(), i == fullLength);
495 frame = decoder->frameBufferAtIndex(0);
497 truncatedHashes.append(0);
500 truncatedHashes.append(hashSkBitmap(frame->getSkBitmap()));
503 // Compute hashes when the file is progressively decoded.
504 decoder = createDecoder();
505 for (size_t i = 1; i <= fullLength; i += increment) {
506 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i);
507 decoder->setData(data.get(), i == fullLength);
508 frame = decoder->frameBufferAtIndex(0);
510 progressiveHashes.append(0);
513 progressiveHashes.append(hashSkBitmap(frame->getSkBitmap()));
517 for (size_t i = 0; i < truncatedHashes.size(); ++i) {
518 if (truncatedHashes[i] != progressiveHashes[i]) {
526 TEST(AnimatedWebPTests, frameIsCompleteAndDuration)
528 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
530 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/webp-animated.webp");
531 ASSERT_TRUE(data.get());
533 ASSERT_GE(data->size(), 10u);
534 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->size() - 10);
535 decoder->setData(tempData.get(), false);
537 EXPECT_EQ(2u, decoder->frameCount());
538 EXPECT_FALSE(decoder->failed());
539 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
540 EXPECT_EQ(1000, decoder->frameDurationAtIndex(0));
541 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1));
542 EXPECT_EQ(500, decoder->frameDurationAtIndex(1));
544 decoder->setData(data.get(), true);
545 EXPECT_EQ(3u, decoder->frameCount());
546 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
547 EXPECT_EQ(1000, decoder->frameDurationAtIndex(0));
548 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1));
549 EXPECT_EQ(500, decoder->frameDurationAtIndex(1));
550 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(2));
551 EXPECT_EQ(1000.0, decoder->frameDurationAtIndex(2));
554 TEST(AnimatedWebPTests, updateRequiredPreviousFrameAfterFirstDecode)
556 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
558 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/webp-animated.webp");
559 ASSERT_TRUE(fullData.get());
561 // Give it data that is enough to parse but not decode in order to check the status
562 // of requiredPreviousFrameIndex before decoding.
563 size_t partialSize = 1;
565 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), partialSize);
566 decoder->setData(data.get(), false);
568 } while (!decoder->frameCount() || decoder->frameBufferAtIndex(0)->status() == ImageFrame::FrameEmpty);
570 EXPECT_EQ(kNotFound, decoder->frameBufferAtIndex(0)->requiredPreviousFrameIndex());
571 size_t frameCount = decoder->frameCount();
572 for (size_t i = 1; i < frameCount; ++i)
573 EXPECT_EQ(i - 1, decoder->frameBufferAtIndex(i)->requiredPreviousFrameIndex());
575 decoder->setData(fullData.get(), true);
576 for (size_t i = 0; i < frameCount; ++i)
577 EXPECT_EQ(kNotFound, decoder->frameBufferAtIndex(i)->requiredPreviousFrameIndex());
580 TEST(AnimatedWebPTests, randomFrameDecode)
582 testRandomFrameDecode("/LayoutTests/fast/images/resources/webp-animated.webp");
583 testRandomFrameDecode("/LayoutTests/fast/images/resources/webp-animated-opaque.webp");
584 testRandomFrameDecode("/LayoutTests/fast/images/resources/webp-animated-large.webp");
585 testRandomFrameDecode("/LayoutTests/fast/images/resources/webp-animated-icc-xmp.webp");
588 TEST(AnimatedWebPTests, randomDecodeAfterClearFrameBufferCache)
590 testRandomDecodeAfterClearFrameBufferCache("/LayoutTests/fast/images/resources/webp-animated.webp");
591 testRandomDecodeAfterClearFrameBufferCache("/LayoutTests/fast/images/resources/webp-animated-opaque.webp");
592 testRandomDecodeAfterClearFrameBufferCache("/LayoutTests/fast/images/resources/webp-animated-large.webp");
593 testRandomDecodeAfterClearFrameBufferCache("/LayoutTests/fast/images/resources/webp-animated-icc-xmp.webp");
596 TEST(AnimatedWebPTests, resumePartialDecodeAfterClearFrameBufferCache)
598 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/webp-animated-large.webp");
599 ASSERT_TRUE(fullData.get());
600 Vector<unsigned> baselineHashes;
601 createDecodingBaseline(fullData.get(), &baselineHashes);
602 size_t frameCount = baselineHashes.size();
604 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
606 // Let frame 0 be partially decoded.
607 size_t partialSize = 1;
609 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), partialSize);
610 decoder->setData(data.get(), false);
612 } while (!decoder->frameCount() || decoder->frameBufferAtIndex(0)->status() == ImageFrame::FrameEmpty);
614 // Skip to the last frame and clear.
615 decoder->setData(fullData.get(), true);
616 EXPECT_EQ(frameCount, decoder->frameCount());
617 ImageFrame* lastFrame = decoder->frameBufferAtIndex(frameCount - 1);
618 EXPECT_EQ(baselineHashes[frameCount - 1], hashSkBitmap(lastFrame->getSkBitmap()));
619 decoder->clearCacheExceptFrame(kNotFound);
621 // Resume decoding of the first frame.
622 ImageFrame* firstFrame = decoder->frameBufferAtIndex(0);
623 EXPECT_EQ(ImageFrame::FrameComplete, firstFrame->status());
624 EXPECT_EQ(baselineHashes[0], hashSkBitmap(firstFrame->getSkBitmap()));
627 TEST(AnimatedWebPTests, decodeAfterReallocatingData)
629 testDecodeAfterReallocatingData("/LayoutTests/fast/images/resources/webp-animated.webp");
630 testDecodeAfterReallocatingData("/LayoutTests/fast/images/resources/webp-animated-icc-xmp.webp");
633 TEST(AnimatedWebPTests, alphaBlending)
635 testAlphaBlending("/LayoutTests/fast/images/resources/webp-animated.webp");
636 testAlphaBlending("/LayoutTests/fast/images/resources/webp-animated-semitransparent1.webp");
637 testAlphaBlending("/LayoutTests/fast/images/resources/webp-animated-semitransparent2.webp");
638 testAlphaBlending("/LayoutTests/fast/images/resources/webp-animated-semitransparent3.webp");
639 testAlphaBlending("/LayoutTests/fast/images/resources/webp-animated-semitransparent4.webp");
642 TEST(StaticWebPTests, truncatedImage)
644 // VP8 data is truncated.
645 testInvalidImage("/LayoutTests/fast/images/resources/truncated.webp", false);
646 // Chunk size in RIFF header doesn't match the file size.
647 testInvalidImage("/LayoutTests/fast/images/resources/truncated2.webp", true);
650 TEST(StaticWebPTests, incrementalDecode)
652 // Regression test for a bug where some valid images were failing to decode incrementally.
653 testByteByByteDecode("/LayoutTests/fast/images/resources/crbug.364830.webp", 1u, cAnimationNone);
656 TEST(StaticWebPTests, notAnimated)
658 OwnPtr<WEBPImageDecoder> decoder = createDecoder();
659 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/webp-color-profile-lossy.webp");
660 ASSERT_TRUE(data.get());
661 decoder->setData(data.get(), true);
662 EXPECT_EQ(1u, decoder->frameCount());
663 EXPECT_EQ(cAnimationNone, decoder->repetitionCount());