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

Side by Side Diff: third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoderTest.cpp

Issue 2386453003: WIP: Implement APNG (Closed)
Patch Set: Process feedback on patch 12 Created 4 years, 1 month 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 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "platform/image-decoders/png/PNGImageDecoder.h"
6
7 #include "png.h"
8 #include "platform/image-decoders/ImageDecoderTestHelpers.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include <memory>
11
12 // @TODO(joostouwerling) test decoding failure on frame |n|, and check if the
13 // decoder reports having |n-1| frames.
14 // @TODO(joostouwerling) verify IEND before IDAT fails the decode.
15 // @TODO(joostouwerling) extend test image set with other image encodings, such
16 // as first frame fcTL and multiple chunks per frame.
17
18 namespace blink {
19
20 namespace {
21
22 std::unique_ptr<ImageDecoder> createDecoder(ImageDecoder::AlphaOption alphaOptio n)
23 {
24 return wrapUnique(new PNGImageDecoder(alphaOption,
25 ImageDecoder::ColorSpaceApplied,
26 ImageDecoder::noDecodedImageByteLimit));
27 }
28
29 std::unique_ptr<ImageDecoder> createDecoder()
30 {
31 return createDecoder(ImageDecoder::AlphaNotPremultiplied);
32 }
33
34 std::unique_ptr<ImageDecoder> createDecoderWithPngData(const char* pngFile)
35 {
36 auto decoder = createDecoder();
37 auto data = readFile(pngFile);
38 EXPECT_FALSE(data->isEmpty());
39 decoder->setData(data.get(), true);
40 return decoder;
41 }
42
43 void testSize(const char* pngFile, IntSize expectedSize)
44 {
45 auto decoder = createDecoderWithPngData(pngFile);
46 EXPECT_TRUE(decoder->isSizeAvailable());
47 EXPECT_EQ(expectedSize, decoder->size());
48 }
49
50 void writeUint32(uint32_t val, png_byte* data)
51 {
52 data[0] = val >> 24;
53 data[1] = val >> 16;
54 data[2] = val >> 8;
55 data[3] = val;
56 }
57
58 void testRepetitionCount(const char* pngFile, int expectedRepetitionCount)
59 {
60 auto decoder = createDecoderWithPngData(pngFile);
61 // Decode frame count should see the number of repetitions as well.
62 decoder->frameCount();
63 EXPECT_FALSE(decoder->failed());
64 EXPECT_EQ(expectedRepetitionCount, decoder->repetitionCount());
65 }
66
67 // Test whether querying for the size of the image works if we present the
68 // data byte by byte.
69 void testSizeByteByByte(const char *pngFile, size_t bytesNeededToDecodeSize,
70 IntSize expectedSize)
71 {
72 auto decoder = createDecoder();
73 auto data = readFile(pngFile);
74 ASSERT_FALSE(data->isEmpty());
75 ASSERT_LT(bytesNeededToDecodeSize, data->size());
76
77 for (size_t length = 1; length <= bytesNeededToDecodeSize; length++) {
78 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(),
79 length);
80 decoder->setData(tempData.get(), false);
81
82 if (length < bytesNeededToDecodeSize) {
83 EXPECT_FALSE(decoder->isSizeAvailable());
84 EXPECT_TRUE(decoder->size().isEmpty());
85 EXPECT_FALSE(decoder->failed());
86 } else {
87 EXPECT_TRUE(decoder->isSizeAvailable());
88 EXPECT_EQ(expectedSize, decoder->size());
89 }
90 }
91 EXPECT_FALSE(decoder->failed());
92 }
93
94 struct PublicFrameInfo {
95 size_t duration;
96 IntRect frameRect;
97 ImageFrame::AlphaBlendSource alphaBlend;
98 ImageFrame::DisposalMethod disposalMethod;
99 };
100
101 // This is the frame data for the following PNG image:
102 // /LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png
103 static PublicFrameInfo pngAnimatedFrameInfo[] = {
104 {500, {IntPoint(0, 0), IntSize(5, 5)}, ImageFrame::BlendAtopBgcolor,
105 ImageFrame::DisposeKeep},
106 {900, {IntPoint(1, 1), IntSize(3, 1)}, ImageFrame::BlendAtopBgcolor,
107 ImageFrame::DisposeOverwriteBgcolor},
108 {2000, {IntPoint(1, 2), IntSize(3, 2)}, ImageFrame::BlendAtopPreviousFrame,
109 ImageFrame::DisposeKeep},
110 {1500, {IntPoint(1, 2), IntSize(3, 1)}, ImageFrame::BlendAtopBgcolor,
111 ImageFrame::DisposeKeep},
112 };
113
114 void compareFrameWithExpectation(const PublicFrameInfo& expected,
115 const ImageFrame* frame)
116 {
117 EXPECT_EQ(expected.duration, frame->duration());
118 EXPECT_EQ(expected.frameRect, frame->originalFrameRect());
119 EXPECT_EQ(expected.disposalMethod, frame->getDisposalMethod());
120 EXPECT_EQ(expected.alphaBlend, frame->getAlphaBlendSource());
121 }
122
123 // This function removes |length| bytes at |offset|, and then calls frameCount.
124 // It assumes the missing bytes should result in a failed decode.
125 void testMissingDataBreaksDecoding(const char* pngFile, size_t offset,
126 size_t length)
127 {
128 auto decoder = createDecoder();
129 auto data = readFile(pngFile);
130 ASSERT_FALSE(data->isEmpty());
131
132 RefPtr<SharedBuffer> invalidData = SharedBuffer::create(data->data(),
133 offset);
134 invalidData->append(SharedBuffer::create(data->data() + offset + length,
135 data->size() - offset - length));
136 ASSERT_EQ(data->size() - length, invalidData->size());
137
138 decoder->setData(invalidData, true);
139 decoder->frameCount();
140 EXPECT_TRUE(decoder->failed());
141 }
142
143 // Decoding up to the indicated fcTL offset and then provide an fcTL with
144 // the wrong chunk size (20 instead of 26). It should break the decoder.
145 void testInvalidFctlSize(const char* pngFile, size_t offsetFctl,
146 size_t expectedFrameCountBeforeFail)
147 {
148 auto data = readFile(pngFile);
149 ASSERT_FALSE(data->isEmpty());
150
151 auto decoder = createDecoder();
152 RefPtr<SharedBuffer> invalidData = SharedBuffer::create(data->data(),
153 offsetFctl);
154
155 // Test if this gives the correct frame count, before the fcTL is parsed.
156 decoder->setData(invalidData, false);
157 EXPECT_EQ(expectedFrameCountBeforeFail, decoder->frameCount());
158 ASSERT_FALSE(decoder->failed());
159
160 // Append the wrong size to the data stream
161 png_byte sizeChunk[4];
162 writeUint32(20, sizeChunk);
163 invalidData->append(reinterpret_cast<char*>(sizeChunk), 4u);
164
165 // Skip the size in the original data, but provide the rest of the fcTL,
166 // which is 4B of tag, 26B of data and 4B of CRC, totalling 34B.
167 invalidData->append(data->data() + offsetFctl + 4, 34u);
168
169 decoder->setData(invalidData, false);
170 decoder->frameCount();
171 EXPECT_TRUE(decoder->failed());
172 }
173
174 void testDifferentActlFrameCountIsIgnored(const char* pngFile,
175 size_t offsetActl,
176 size_t injectedFrameCount,
177 size_t expectedFrameCount)
178 {
179 // First make sure that this tests makes sense.
180 ASSERT_NE(injectedFrameCount, expectedFrameCount);
181
182 auto data = readFile(pngFile);
183 auto decoder = createDecoder();
184 ASSERT_FALSE(data->isEmpty());
185
186 RefPtr<SharedBuffer> diffActlData = SharedBuffer::create(data->data(),
187 offsetActl + 8);
188 // Write the injectedFrameCount to the stream
189 png_byte sizeChunk[4];
190 writeUint32(injectedFrameCount, sizeChunk);
191 diffActlData->append(reinterpret_cast<char*>(sizeChunk), 4u);
192 // Append the rest of the data. The first |offsetActl + 12| bytes that are
193 // already in diffActlData should not be appended again.
194 diffActlData->append(data->data() + offsetActl + 12,
195 data->size() - offsetActl - 12);
196
197 decoder->setData(diffActlData, true);
198 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
199 }
200
201 // Test if the frame bitmap hashes of truncated decoding are equal to the
202 // hashes found by incremental decoding.
203 void testProgressiveDecoding(const char *pngFile)
204 {
205 RefPtr<SharedBuffer> fullData = readFile(pngFile);
206 ASSERT_TRUE(fullData.get());
207 const size_t fullLength = fullData->size();
208
209 std::unique_ptr<ImageDecoder> decoder;
210 ImageFrame* frame;
211
212 Vector<unsigned> truncatedHashes;
213 Vector<unsigned> progressiveHashes;
214
215 // Compute hashes when the file is truncated.
216 const size_t increment = 13;
217 for (size_t i = 1; i <= fullLength; i += increment) {
218 decoder = createDecoder();
219 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i);
220 decoder->setData(data.get(), i == fullLength);
221 size_t frameCount = decoder->frameCount();
222 ASSERT_FALSE(decoder->failed());
223 if (frameCount == 0) {
224 truncatedHashes.append(0);
225 continue;
226 }
227 frame = decoder->frameBufferAtIndex(frameCount - 1);
228 if (!frame) {
229 truncatedHashes.append(0);
230 continue;
231 }
232 truncatedHashes.append(hashBitmap(frame->bitmap()));
233 }
234
235 // Compute hashes when the file is progressively decoded.
236 decoder = createDecoder();
237 for (size_t i = 1; i <= fullLength; i += increment) {
238 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i);
239 decoder->setData(data.get(), i == fullLength);
240 ASSERT_FALSE(decoder->failed());
241 size_t frameCount = decoder->frameCount();
242 if (frameCount == 0) {
243 progressiveHashes.append(0);
244 continue;
245 }
246 frame = decoder->frameBufferAtIndex(frameCount - 1);
247 if (!frame) {
248 progressiveHashes.append(0);
249 continue;
250 }
251 progressiveHashes.append(hashBitmap(frame->bitmap()));
252 }
253
254 for (size_t i = 0; i < truncatedHashes.size(); ++i)
255 ASSERT_EQ(truncatedHashes[i], progressiveHashes[i]);
256 }
257
258 // Check that providing the full data after the first frame was partially
259 // decoded properly continues where it left off.
260 void testProgressiveDecodingContinuesAfterFullData(const char* pngFile,
261 size_t offsetMidFirstFrame)
262 {
263 auto fullData = readFile(pngFile);
264 auto decoder = createDecoder();
265 ASSERT_FALSE(fullData->isEmpty());
266
267 RefPtr<SharedBuffer> partialData =
268 SharedBuffer::create(fullData->data(), offsetMidFirstFrame);
269 decoder->setData(partialData, false);
270
271 EXPECT_EQ(1u, decoder->frameCount());
272 ImageFrame* frame = decoder->frameBufferAtIndex(0);
273 EXPECT_EQ(frame->getStatus(), ImageFrame::FramePartial);
274 unsigned hashPartial = hashBitmap(frame->bitmap());
275
276 decoder->setData(fullData.get(), true);
277 frame = decoder->frameBufferAtIndex(0);
278 EXPECT_EQ(frame->getStatus(), ImageFrame::FrameComplete);
279 unsigned hashFull = hashBitmap(frame->bitmap());
280
281 EXPECT_FALSE(decoder->failed());
282 EXPECT_NE(hashFull, hashPartial);
283 }
284
285 // This test verifies that the frame buffer contents change when progressively
286 // decoding the first frame. It should change more than 1 time: once for the
287 // first data, and at least once more thereafter. If |offsetFirstFrameEnd| == 0,
288 // the test uses the full data size of the image for its value.
289 void testProgressiveDecodingChangesFrameBuffer(const char* pngFile,
290 size_t offsetFirstFrameEnd,
291 size_t step = 1u)
292 {
293 auto fullData = readFile(pngFile);
294 auto decoder = createDecoder();
295 ASSERT_FALSE(fullData->isEmpty());
296
297 if (offsetFirstFrameEnd == 0)
298 offsetFirstFrameEnd = fullData->size();
299
300 size_t numTimesBufferChanged = 0;
301 unsigned lastHash;
302
303 for (size_t length = 1; length <= offsetFirstFrameEnd; length += step) {
304 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(),
305 length);
306 decoder->setData(data, false);
307 ImageFrame* frame = decoder->frameBufferAtIndex(0);
308 if (!frame)
309 continue;
310 unsigned newHash = hashBitmap(frame->bitmap());
311 if (newHash != lastHash) {
312 lastHash = newHash;
313 numTimesBufferChanged++;
314 }
315 }
316 EXPECT_GT(numTimesBufferChanged, 1u);
317 }
318
319 // @TODO(joostouwerling) Pull this up to ImageDecoderTestHelper since it is also
320 // used in WEBPImageDecoderTest
321 void testRandomDecodeAfterClearFrameBufferCache(const char* pngFile) {
322 SCOPED_TRACE(pngFile);
323
324 RefPtr<SharedBuffer> data = readFile(pngFile);
325 ASSERT_TRUE(data.get());
326 Vector<unsigned> baselineHashes;
327 createDecodingBaseline(&createDecoder, data.get(), &baselineHashes);
328 size_t frameCount = baselineHashes.size();
329
330 std::unique_ptr<ImageDecoder> decoder = createDecoder();
331 decoder->setData(data.get(), true);
332 for (size_t clearExceptFrame = 0; clearExceptFrame < frameCount;
333 ++clearExceptFrame) {
334 decoder->clearCacheExceptFrame(clearExceptFrame);
335 const size_t skippingStep = 2;
336 for (size_t i = 0; i < skippingStep; ++i) {
337 for (size_t j = 0; j < frameCount; j += skippingStep) {
338 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
339 ImageFrame* frame = decoder->frameBufferAtIndex(j);
340 EXPECT_EQ(baselineHashes[j], hashBitmap(frame->bitmap()));
341 }
342 }
343 }
344 }
345
346 } // Anonymous namespace
347
348 // Animated PNG Tests
349
350 TEST(AnimatedPNGTests, sizeTest)
351 {
352 testSize("/LayoutTests/fast/images/resources/png-animated-idat-part-of-animati on.png", IntSize(5, 5));
353 testSize("/LayoutTests/fast/images/resources/png-animated-idat-not-part-of-ani mation.png", IntSize(227, 35));
354 }
355
356 TEST(AnimatedPNGTests, repetitionCountTest)
357 {
358 testRepetitionCount("/LayoutTests/fast/images/resources/png-animated-idat-part -of-animation.png", 7u);
359 // This is an "animated" image with only one frame, that is, the IDAT is
360 // ignored and there is one fdAT frame. so it should be considered
361 // non-animated.
362 testRepetitionCount("/LayoutTests/fast/images/resources/png-animated-idat-not- part-of-animation.png", cAnimationNone);
363 }
364
365 // Test if the decoded metdata corresponds to the defined expectations
366 TEST(AnimatedPNGTests, MetaDataTest)
367 {
368 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png";
369 constexpr size_t expectedFrameCount = 4;
370
371 auto decoder = createDecoderWithPngData(pngFile);
372 ASSERT_EQ(expectedFrameCount, decoder->frameCount());
373 for (size_t i = 0; i < expectedFrameCount; i++)
374 compareFrameWithExpectation(pngAnimatedFrameInfo[i],
375 decoder->frameBufferAtIndex(i));
376 }
377
378 TEST(AnimatedPNGTests, ByteByByteSizeAvailable)
379 {
380 testSizeByteByByte("/LayoutTests/fast/images/resources/png-animated-idat-part- of-animation.png",
381 141u, IntSize(5, 5));
382 testSizeByteByByte("/LayoutTests/fast/images/resources/png-animated-idat-not-p art-of-animation.png",
383 79u, IntSize(227, 35));
384 }
385
386 // Test whether the frame metadata decoding also works when we provide the data
387 // byte by byte. This should cover the case when the client does not provide
388 // all data at once. At given offsets, we expect frames to become available.
389 // This test checks whether that is the case, and if so, if the frame data is
390 // equal to what we expected.
391 TEST(AnimatedPNGTests, ByteByByteMetaData)
392 {
393 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png";
394 constexpr size_t expectedFrameCount = 4;
395
396 // These are the byte offsets where each frame should have been parsed.
397 // It boils down to the offset of the first fcTL / IEND after the last
398 // frame data chunk, plus 8 bytes for recognition. The exception on this is
399 // the first frame, which is reported when its first framedata is seen.
400 size_t frameOffsets[expectedFrameCount] = {141, 249, 322, 430};
401
402 auto decoder = createDecoder();
403 auto data = readFile(pngFile);
404 ASSERT_FALSE(data->isEmpty());
405 size_t framesParsed = 0;
406
407 for (size_t length = 1; length <= frameOffsets[expectedFrameCount - 1]; length ++) {
408 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(),
409 length);
410 decoder->setData(tempData.get(), false);
411 EXPECT_FALSE(decoder->failed());
412 if (length < frameOffsets[framesParsed]) {
413 EXPECT_EQ(framesParsed, decoder->frameCount());
414 } else {
415 ASSERT_EQ(framesParsed + 1, decoder->frameCount());
416 compareFrameWithExpectation(pngAnimatedFrameInfo[framesParsed],
417 decoder->frameBufferAtIndex(framesParsed));
418 framesParsed++;
419 }
420 }
421 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
422 EXPECT_FALSE(decoder->failed());
423 }
424
425 // This tests if the frame count gets set correctly when parsing frameCount
426 // fails in one of the parsing queries.
427 //
428 // First, enough data is provided such that two frames should be registered.
429 // The decoder should at this point not be in the failed status.
430 //
431 // Then, we provide the rest of the data except for the last IEND chunk, but
432 // tell the decoder that this is all the data we have. Now, the decoder should
433 // be in the failed state since all data is provided but no IEND chunk has been
434 // seen. The frame count should be three, since one extra frame should be
435 // discovered. The fourth frame should *not* be registered since the reader
436 // should not be able to determine where the frame ends.
437 TEST(AnimatedPNGTests, FrameCountWithTruncatedData)
438 {
439 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png";
440 auto decoder = createDecoder();
441 auto data = readFile(pngFile);
442 ASSERT_FALSE(data->isEmpty());
443
444 // Parse up to and including the first two frames
445 const size_t offsetTwoFrames = 249;
446 const size_t expectedFramesAfter249Bytes = 2;
447 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(),
448 offsetTwoFrames);
449 decoder->setData(tempData.get(), false);
450 EXPECT_EQ(expectedFramesAfter249Bytes, decoder->frameCount());
451 EXPECT_FALSE(decoder->failed());
452
453 // Provide the rest of the data except for the last IEND chunk.
454 const size_t expectedFramesAfterAllExpect12Bytes = 3;
455 tempData = SharedBuffer::create(data->data(), data->size() - 12);
456 decoder->setData(tempData.get(), true);
457 EXPECT_EQ(expectedFramesAfterAllExpect12Bytes, decoder->frameCount());
458 EXPECT_TRUE(decoder->failed());
459 }
460
461 TEST(AnimatedPNGTests, TestRandomFrameDecode)
462 {
463 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/p ng-animated-idat-part-of-animation.png");
464 ASSERT_TRUE(fullData.get());
465 Vector<unsigned> baselineHashes;
466 createDecodingBaseline(&createDecoder, fullData.get(), &baselineHashes);
467 size_t frameCount = baselineHashes.size();
468
469 // Random decoding should get the same results as sequential decoding.
470 std::unique_ptr<ImageDecoder> decoder = createDecoder();
471 decoder->setData(fullData.get(), true);
472 const size_t skippingStep = 2;
473 for (size_t i = 0; i < skippingStep; ++i) {
474 for (size_t j = i; j < frameCount; j += skippingStep) {
475 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
476 ImageFrame* frame = decoder->frameBufferAtIndex(j);
477 EXPECT_EQ(baselineHashes[j], hashBitmap(frame->bitmap()));
478 }
479 }
480
481 // Decoding in reverse order.
482 decoder = createDecoder();
483 decoder->setData(fullData.get(), true);
484 for (size_t i = frameCount; i; --i) {
485 SCOPED_TRACE(testing::Message() << "Reverse i:" << i);
486 ImageFrame* frame = decoder->frameBufferAtIndex(i - 1);
487 EXPECT_EQ(baselineHashes[i - 1], hashBitmap(frame->bitmap()));
488 }
489
490 }
491
492 TEST(AnimatedPNGTests, TestDecodeAfterReallocation)
493 {
494 std::unique_ptr<ImageDecoder> decoder = createDecoder();
495 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/png-a nimated-idat-part-of-animation.png");
496 ASSERT_TRUE(data.get());
497
498 // Parse from |data|.
499 decoder->setData(data.get(), true);
500 size_t frameCount = decoder->frameCount();
501
502 // ... and then decode frames from |reallocatedData|.
503 RefPtr<SharedBuffer> reallocatedData = data.get()->copy();
504 ASSERT_TRUE(reallocatedData.get());
505 data.clear();
506 decoder->setData(reallocatedData.get(), true);
507
508 for (size_t i = 0; i < frameCount; ++i) {
509 const ImageFrame* const frame = decoder->frameBufferAtIndex(i);
510 EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
511 }
512 }
513
514 TEST(AnimatedPNGTests, ProgressiveDecode)
515 {
516 testProgressiveDecoding("/LayoutTests/fast/images/resources/png-animated-idat- part-of-animation.png");
517 }
518
519 TEST(AnimatedPNGTests, ParseAndDecodeByteByByte)
520 {
521 testByteByByteDecode(&createDecoder,
522 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-anima tion.png",
523 4u, 7u);
524 }
525
526 TEST(AnimatedPNGTests, FctlWrongSizeBreaksDecoding)
527 {
528 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png";
529 auto data = readFile(pngFile);
530 ASSERT_FALSE(data->isEmpty());
531
532 // Test the first fcTL in the stream. Because no frame data has been set
533 // at this point, the expected frame count is zero.
534 testInvalidFctlSize("/LayoutTests/fast/images/resources/png-animated-idat-part -of-animation.png",
535 95u, 0u);
536
537 // Test for the third fcTL in the stream. This should be tested as well,
538 // since the first fcTL is parsed in PNGImageReader::parseSize() whereas
539 // later fcTLs are parsed in PNGImageReader::parse() as part of framecount.
540 // The expected frame count before the fcTL chunk is 1u, since the second
541 // frame is registered when the third fcTL (or IEND) is seen.
542 testInvalidFctlSize("/LayoutTests/fast/images/resources/png-animated-idat-part -of-animation.png",
543 241u, 1u);
544
545 }
546
547 TEST(AnimatedPNGTests, MissingFctlDataBreaksDecoding)
548 {
549 // The fcTL chunk starts at 95u, add 10u to get to the content data, and
550 // remove 5 bytes of data.
551 testMissingDataBreaksDecoding(
552 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png" ,
553 105u, 5u);
554 }
555
556 TEST(AnimatedPNGTests, MissingActlResultsInNonAnimated)
557 {
558 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png";
559 auto data = readFile(pngFile);
560 auto decoder = createDecoder();
561 ASSERT_FALSE(data->isEmpty());
562
563 // Remove the acTL chunk from the stream.
564 size_t offsetActl = 33;
565 RefPtr<SharedBuffer> noActlData = SharedBuffer::create(data->data(),
566 offsetActl);
567 noActlData->append(data->data() + offsetActl + 20,
568 data->size() - offsetActl - 20);
569
570 decoder->setData(noActlData, true);
571 EXPECT_EQ(1u, decoder->frameCount());
572 EXPECT_FALSE(decoder->failed());
573 }
574
575 // Test if the indicated frame count by the acTL is ignored if the actual
576 // number of frames is different. Test for higher and lower indicated number.
577 TEST(AnimatedPNGTests, differentActlFrameCountIsIgnored)
578 {
579 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png";
580 testDifferentActlFrameCountIsIgnored(pngFile, 33u, 2u, 4u);
581 testDifferentActlFrameCountIsIgnored(pngFile, 33u, 8u, 4u);
582 }
583
584 // Check if a frame rectangle, that is larger than the image width, gets
585 // clipped correctly.
586 // @TODO(joostouwerling) use an image that also has data that needs to be
587 // clipped, not just report larger dimensions.
588 // @TODO(joostouwerling) determine how libpng handles larger / smaller images
589 // than indicated.
590 TEST(AnimatedPNGTests, frameRectIsClipped)
591 {
592 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png";
593 auto data = readFile(pngFile);
594 auto decoder = createDecoder();
595 ASSERT_FALSE(data->isEmpty());
596
597 // Change the width and height of the frame so it falls outside the image.
598 size_t offsetThirdFctl = 241 + 12;
599 RefPtr<SharedBuffer> modifiedData = SharedBuffer::create(data->data(),
600 offsetThirdFctl);
601 png_byte sizeChunk[8];
602 writeUint32(10, sizeChunk);
603 writeUint32(15, sizeChunk + 4);
604 modifiedData->append(const_cast<const char*>(
605 reinterpret_cast<char*>(sizeChunk)), 8u);
606 modifiedData->append(data->data() + offsetThirdFctl + 8,
607 data->size() - offsetThirdFctl - 8);
608
609 decoder->setData(modifiedData, true);
610
611 IntSize expectedSize(5, 5);
612 size_t expectedFrameCount = 4;
613 IntRect expectedFrameRect(IntPoint(1, 2), IntSize(4, 3));
614
615 EXPECT_TRUE(decoder->isSizeAvailable());
616 EXPECT_EQ(expectedSize, decoder->size());
617 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
618 ASSERT_FALSE(decoder->failed());
619 EXPECT_EQ(expectedFrameRect,
620 decoder->frameBufferAtIndex(2)->originalFrameRect());
621 }
622
623 TEST(AnimatedPNGTests, ProgressiveDecodingChangesFrameBuffer)
624 {
625 testProgressiveDecodingChangesFrameBuffer(
626 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png" , 249u);
627 }
628
629 TEST(AnimatedPNGTests, ProgressiveDecodingContinuesAfterFullData)
630 {
631 testProgressiveDecodingContinuesAfterFullData(
632 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png" , 160u);
633 }
634
635 TEST(AnimatedPNGTests, RandomDecodeAfterClearFrameBufferCache)
636 {
637 testRandomDecodeAfterClearFrameBufferCache(
638 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png" );
639 }
640
641 // Static PNG tests
642
643 TEST(StaticPNGTests, repetitionCountTest)
644 {
645 testRepetitionCount("/LayoutTests/fast/images/resources/png-simple.png",
646 cAnimationNone);
647 }
648
649 TEST(StaticPNGTests, sizeTest)
650 {
651 testSize("/LayoutTests/fast/images/resources/png-simple.png",
652 IntSize(111, 29));
653 }
654
655 TEST(StaticPNGTests, MetaDataTest)
656 {
657 const size_t expectedFrameCount = 1;
658 const size_t expectedDuration = 0;
659 auto decoder = createDecoderWithPngData("/LayoutTests/fast/images/resources/pn g-simple.png");
660 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
661 EXPECT_EQ(expectedDuration, decoder->frameDurationAtIndex(0));
662 }
663
664 TEST(StaticPNGTests, InvalidIHDRChunk)
665 {
666 testMissingDataBreaksDecoding(
667 "/LayoutTests/fast/images/resources/png-simple.png", 20u, 2u);
668 }
669
670 TEST(StaticPNGTests, ProgressiveDecoding)
671 {
672 testProgressiveDecoding("/LayoutTests/fast/images/resources/png-simple.png");
673 }
674
675 TEST(StaticPNGTests, ProgressiveDecodingChangesFrameBuffer)
676 {
677 testProgressiveDecodingChangesFrameBuffer(
678 "/LayoutTests/fast/images/resources/png-simple.png", 0u, 5u);
679 }
680
681 TEST(StaticPNGTests, ProgressiveDecodingContinuesAfterFullData)
682 {
683 testProgressiveDecodingContinuesAfterFullData(
684 "/LayoutTests/fast/images/resources/png-simple.png", 1000u);
685 }
686
687 }; // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698