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

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

Issue 2618633004: Add support for Animated PNG (Closed)
Patch Set: Fix LayoutTest due to accept header change Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "platform/image-decoders/png/PNGImageDecoder.h" 5 #include "platform/image-decoders/png/PNGImageDecoder.h"
6 6
7 #include <memory>
7 #include "platform/image-decoders/ImageDecoderTestHelpers.h" 8 #include "platform/image-decoders/ImageDecoderTestHelpers.h"
9 #include "png.h"
8 #include "testing/gtest/include/gtest/gtest.h" 10 #include "testing/gtest/include/gtest/gtest.h"
9 #include <memory> 11
12 // /LayoutTests/images/resources/png-animated-idat-part-of-animation.png
13 // is modified in multiple tests to simulate erroneous PNGs. As a reference,
14 // the table below shows how the file is structured.
15 //
16 // Offset | 8 33 95 133 172 210 241 279 314 352 422
17 // -------------------------------------------------------------------------
18 // Chunk | IHDR acTL fcTL IDAT fcTL fdAT fcTL fdAT fcTL fdAT IEND
19 //
20 // In between the acTL and fcTL there are two other chunks, PLTE and tRNS, but
21 // those are not specifically used in this test suite. The same holds for a
22 // tEXT chunk in between the last fdAT and IEND.
23 //
24 // In the current behavior of PNG image decoders, the 4 frames are detected when
25 // respectively 141, 249, 322 and 430 bytes are received. The first frame should
26 // be detected when the IDAT has been received, and non-first frames when the
27 // next fcTL or IEND chunk has been received. Note that all offsets are +8,
28 // because a chunk is identified by byte 4-7.
10 29
11 namespace blink { 30 namespace blink {
12 31
13 namespace { 32 namespace {
14 33
15 std::unique_ptr<ImageDecoder> createDecoder( 34 std::unique_ptr<ImageDecoder> createDecoder(
16 ImageDecoder::AlphaOption alphaOption) { 35 ImageDecoder::AlphaOption alphaOption) {
17 return WTF::wrapUnique(new PNGImageDecoder( 36 return WTF::wrapUnique(new PNGImageDecoder(
18 alphaOption, ColorBehavior::transformToTargetForTesting(), 37 alphaOption, ColorBehavior::transformToTargetForTesting(),
19 ImageDecoder::noDecodedImageByteLimit)); 38 ImageDecoder::noDecodedImageByteLimit));
(...skipping 10 matching lines...) Expand all
30 decoder->setData(data.get(), true); 49 decoder->setData(data.get(), true);
31 return decoder; 50 return decoder;
32 } 51 }
33 52
34 void testSize(const char* pngFile, IntSize expectedSize) { 53 void testSize(const char* pngFile, IntSize expectedSize) {
35 auto decoder = createDecoderWithPngData(pngFile); 54 auto decoder = createDecoderWithPngData(pngFile);
36 EXPECT_TRUE(decoder->isSizeAvailable()); 55 EXPECT_TRUE(decoder->isSizeAvailable());
37 EXPECT_EQ(expectedSize, decoder->size()); 56 EXPECT_EQ(expectedSize, decoder->size());
38 } 57 }
39 58
59 // Test whether querying for the size of the image works if we present the
60 // data byte by byte.
61 void testSizeByteByByte(const char* pngFile,
62 size_t bytesNeededToDecodeSize,
63 IntSize expectedSize) {
64 auto decoder = createDecoder();
65 auto data = readFile(pngFile);
66 ASSERT_FALSE(data->isEmpty());
67 ASSERT_LT(bytesNeededToDecodeSize, data->size());
68
69 const char* source = data->data();
70 RefPtr<SharedBuffer> partialData = SharedBuffer::create();
71 for (size_t length = 1; length <= bytesNeededToDecodeSize; length++) {
72 partialData->append(source++, 1u);
73 decoder->setData(partialData.get(), false);
74
75 if (length < bytesNeededToDecodeSize) {
76 EXPECT_FALSE(decoder->isSizeAvailable());
77 EXPECT_TRUE(decoder->size().isEmpty());
78 EXPECT_FALSE(decoder->failed());
79 } else {
80 EXPECT_TRUE(decoder->isSizeAvailable());
81 EXPECT_EQ(expectedSize, decoder->size());
82 }
83 }
84 EXPECT_FALSE(decoder->failed());
85 }
86
87 void writeUint32(uint32_t val, png_byte* data) {
88 data[0] = val >> 24;
89 data[1] = val >> 16;
90 data[2] = val >> 8;
91 data[3] = val;
92 }
93
40 void testRepetitionCount(const char* pngFile, int expectedRepetitionCount) { 94 void testRepetitionCount(const char* pngFile, int expectedRepetitionCount) {
41 auto decoder = createDecoderWithPngData(pngFile); 95 auto decoder = createDecoderWithPngData(pngFile);
42 // Decoding the frame count sets the repetition count as well. 96 // Decoding the frame count sets the number of repetitions as well.
43 decoder->frameCount(); 97 decoder->frameCount();
44 EXPECT_FALSE(decoder->failed()); 98 EXPECT_FALSE(decoder->failed());
45 EXPECT_EQ(expectedRepetitionCount, decoder->repetitionCount()); 99 EXPECT_EQ(expectedRepetitionCount, decoder->repetitionCount());
46 } 100 }
47 101
102 struct PublicFrameInfo {
103 size_t duration;
104 IntRect frameRect;
105 ImageFrame::AlphaBlendSource alphaBlend;
106 ImageFrame::DisposalMethod disposalMethod;
107 };
108
109 // This is the frame data for the following PNG image:
110 // /LayoutTests/images/resources/png-animated-idat-part-of-animation.png
111 static PublicFrameInfo pngAnimatedFrameInfo[] = {
112 {500,
113 {IntPoint(0, 0), IntSize(5, 5)},
114 ImageFrame::BlendAtopBgcolor,
115 ImageFrame::DisposeKeep},
116 {900,
117 {IntPoint(1, 1), IntSize(3, 1)},
118 ImageFrame::BlendAtopBgcolor,
119 ImageFrame::DisposeOverwriteBgcolor},
120 {2000,
121 {IntPoint(1, 2), IntSize(3, 2)},
122 ImageFrame::BlendAtopPreviousFrame,
123 ImageFrame::DisposeKeep},
124 {1500,
125 {IntPoint(1, 2), IntSize(3, 1)},
126 ImageFrame::BlendAtopBgcolor,
127 ImageFrame::DisposeKeep},
128 };
129
130 void compareFrameWithExpectation(const PublicFrameInfo& expected,
131 ImageDecoder* decoder,
132 size_t index) {
133 EXPECT_EQ(expected.duration, decoder->frameDurationAtIndex(index));
134
135 const auto* frame = decoder->frameBufferAtIndex(index);
136 ASSERT_TRUE(frame);
137
138 EXPECT_EQ(expected.duration, frame->duration());
139 EXPECT_EQ(expected.frameRect, frame->originalFrameRect());
140 EXPECT_EQ(expected.disposalMethod, frame->getDisposalMethod());
141 EXPECT_EQ(expected.alphaBlend, frame->getAlphaBlendSource());
142 }
143
144 // This function removes |length| bytes at |offset|, and then calls frameCount.
145 // It assumes the missing bytes should result in a failed decode because the
146 // parser jumps |length| bytes too far in the next chunk.
147 void testMissingDataBreaksDecoding(const char* pngFile,
148 size_t offset,
149 size_t length) {
150 auto decoder = createDecoder();
151 auto data = readFile(pngFile);
152 ASSERT_FALSE(data->isEmpty());
153
154 RefPtr<SharedBuffer> invalidData = SharedBuffer::create(data->data(), offset);
155 invalidData->append(data->data() + offset + length,
156 data->size() - offset - length);
157 ASSERT_EQ(data->size() - length, invalidData->size());
158
159 decoder->setData(invalidData, true);
160 decoder->frameCount();
161 EXPECT_TRUE(decoder->failed());
162 }
163
164 // Verify that a decoder with a parse error converts to a static image.
165 static void expectStatic(ImageDecoder* decoder) {
166 EXPECT_EQ(1u, decoder->frameCount());
167 EXPECT_FALSE(decoder->failed());
168
169 ImageFrame* frame = decoder->frameBufferAtIndex(0);
170 ASSERT_NE(nullptr, frame);
171 EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
172 EXPECT_FALSE(decoder->failed());
173 EXPECT_EQ(cAnimationNone, decoder->repetitionCount());
174 }
175
176 // Decode up to the indicated fcTL offset and then provide an fcTL with the
177 // wrong chunk size (20 instead of 26).
178 void testInvalidFctlSize(const char* pngFile,
179 size_t offsetFctl,
180 size_t expectedFrameCount,
181 bool shouldFail) {
182 auto data = readFile(pngFile);
183 ASSERT_FALSE(data->isEmpty());
184
185 auto decoder = createDecoder();
186 RefPtr<SharedBuffer> invalidData =
187 SharedBuffer::create(data->data(), offsetFctl);
188
189 // Test if this gives the correct frame count, before the fcTL is parsed.
190 decoder->setData(invalidData, false);
191 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
192 ASSERT_FALSE(decoder->failed());
193
194 // Append the wrong size to the data stream
195 png_byte sizeChunk[4];
196 writeUint32(20, sizeChunk);
197 invalidData->append(reinterpret_cast<char*>(sizeChunk), 4u);
198
199 // Skip the size in the original data, but provide a truncated fcTL,
200 // which is 4B of tag, 20B of data and 4B of CRC, totalling 28B.
201 invalidData->append(data->data() + offsetFctl + 4, 28u);
202 // Append the rest of the data
203 const size_t offsetPostFctl = offsetFctl + 38;
204 invalidData->append(data->data() + offsetPostFctl,
205 data->size() - offsetPostFctl);
206
207 decoder->setData(invalidData, false);
208 if (shouldFail) {
209 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
210 EXPECT_EQ(true, decoder->failed());
211 } else {
212 expectStatic(decoder.get());
213 }
214 }
215
48 // Verify that the decoder can successfully decode the first frame when 216 // Verify that the decoder can successfully decode the first frame when
49 // initially only half of the frame data is received, resulting in a partially 217 // initially only half of the frame data is received, resulting in a partially
50 // decoded image, and then the rest of the image data is received. Verify that 218 // decoded image, and then the rest of the image data is received. Verify that
51 // the bitmap hashes of the two stages are different. Also verify that the final 219 // the bitmap hashes of the two stages are different. Also verify that the final
52 // bitmap hash is equivalent to the hash when all data is provided at once. 220 // bitmap hash is equivalent to the hash when all data is provided at once.
53 // 221 //
54 // This verifies that decoder correctly keeps track of where it stopped 222 // This verifies that the decoder correctly keeps track of where it stopped
55 // decoding when the image was not yet fully received. 223 // decoding when the image was not yet fully received.
56 void testProgressiveDecodingContinuesAfterFullData(const char* pngFile, 224 void testProgressiveDecodingContinuesAfterFullData(const char* pngFile,
57 size_t offsetMidFirstFrame) { 225 size_t offsetMidFirstFrame) {
58 auto fullData = readFile(pngFile); 226 auto fullData = readFile(pngFile);
59 ASSERT_FALSE(fullData->isEmpty()); 227 ASSERT_FALSE(fullData->isEmpty());
60 228
61 auto decoderUpfront = createDecoder(); 229 auto decoderUpfront = createDecoder();
62 decoderUpfront->setData(fullData.get(), true); 230 decoderUpfront->setData(fullData.get(), true);
63 EXPECT_GE(1u, decoderUpfront->frameCount()); 231 EXPECT_GE(decoderUpfront->frameCount(), 1u);
64 const ImageFrame* const frameUpfront = decoderUpfront->frameBufferAtIndex(0); 232 const ImageFrame* const frameUpfront = decoderUpfront->frameBufferAtIndex(0);
65 ASSERT_EQ(ImageFrame::FrameComplete, frameUpfront->getStatus()); 233 ASSERT_EQ(ImageFrame::FrameComplete, frameUpfront->getStatus());
66 const unsigned hashUpfront = hashBitmap(frameUpfront->bitmap()); 234 const unsigned hashUpfront = hashBitmap(frameUpfront->bitmap());
67 235
68 auto decoder = createDecoder(); 236 auto decoder = createDecoder();
69 RefPtr<SharedBuffer> partialData = 237 RefPtr<SharedBuffer> partialData =
70 SharedBuffer::create(fullData->data(), offsetMidFirstFrame); 238 SharedBuffer::create(fullData->data(), offsetMidFirstFrame);
71 decoder->setData(partialData, false); 239 decoder->setData(partialData, false);
72 240
73 EXPECT_EQ(1u, decoder->frameCount()); 241 EXPECT_EQ(1u, decoder->frameCount());
74 const ImageFrame* frame = decoder->frameBufferAtIndex(0); 242 const ImageFrame* frame = decoder->frameBufferAtIndex(0);
75 EXPECT_EQ(frame->getStatus(), ImageFrame::FramePartial); 243 EXPECT_EQ(frame->getStatus(), ImageFrame::FramePartial);
76 const unsigned hashPartial = hashBitmap(frame->bitmap()); 244 const unsigned hashPartial = hashBitmap(frame->bitmap());
77 245
78 decoder->setData(fullData.get(), true); 246 decoder->setData(fullData.get(), true);
79 frame = decoder->frameBufferAtIndex(0); 247 frame = decoder->frameBufferAtIndex(0);
80 EXPECT_EQ(frame->getStatus(), ImageFrame::FrameComplete); 248 EXPECT_EQ(frame->getStatus(), ImageFrame::FrameComplete);
81 const unsigned hashFull = hashBitmap(frame->bitmap()); 249 const unsigned hashFull = hashBitmap(frame->bitmap());
82 250
83 EXPECT_FALSE(decoder->failed()); 251 EXPECT_FALSE(decoder->failed());
84 EXPECT_NE(hashFull, hashPartial); 252 EXPECT_NE(hashFull, hashPartial);
85 EXPECT_EQ(hashFull, hashUpfront); 253 EXPECT_EQ(hashFull, hashUpfront);
86 } 254 }
87 255
88 // Modify the frame data bytes for frame |frameIndex| so that decoding fails. 256 // Modify the frame data bytes for frame |frameIndex| so that decoding fails.
89 // Parsing should work fine, and is checked with |expectedFrameCountBefore|. If 257 // Parsing should work fine, and is checked with |expectedFrameCount|.
90 // the failure should invalidate the decoder, |expectFailure| should be set to
91 // true. If not, |expectedFrameCountAfter| should indicate the new frame count
92 // after the failure.
93 void testFailureDuringDecode(const char* file, 258 void testFailureDuringDecode(const char* file,
94 size_t idatOffset, 259 size_t idatOffset,
95 size_t frameIndex, 260 size_t frameIndex,
96 bool expectFailure, 261 size_t expectedFrameCount) {
97 size_t expectedFrameCountBefore,
98 size_t expectedFrameCountAfter = 0u) {
99 RefPtr<SharedBuffer> fullData = readFile(file); 262 RefPtr<SharedBuffer> fullData = readFile(file);
100 ASSERT_FALSE(fullData->isEmpty()); 263 ASSERT_FALSE(fullData->isEmpty());
101 264
102 // This is the offset where the frame data chunk frame |frameIndex| starts. 265 // This is the offset where the frame data chunk frame |frameIndex| starts.
103 RefPtr<SharedBuffer> data = 266 RefPtr<SharedBuffer> data =
104 SharedBuffer::create(fullData->data(), idatOffset + 8u); 267 SharedBuffer::create(fullData->data(), idatOffset + 8u);
105 // Repeat the first 8 bytes of the frame data. This should result in a 268 // Repeat the first 8 bytes of the frame data. This should result in a
106 // successful parse, since frame data is not analyzed in that step, but 269 // successful parse, since frame data is not analyzed in that step, but
107 // should give an error during decoding. 270 // should give an error during decoding.
108 data->append(fullData->data() + idatOffset, 8u); 271 data->append(fullData->data() + idatOffset, 8u);
109 data->append(fullData->data() + idatOffset + 16u, 272 data->append(fullData->data() + idatOffset + 16u,
110 fullData->size() - idatOffset - 16u); 273 fullData->size() - idatOffset - 16u);
111 274
112 auto decoder = createDecoder(); 275 auto decoder = createDecoder();
113 decoder->setData(data.get(), true); 276 decoder->setData(data.get(), true);
114 277
115 EXPECT_EQ(expectedFrameCountBefore, decoder->frameCount()); 278 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
116 279
117 const ImageFrame* const frame = decoder->frameBufferAtIndex(frameIndex); 280 decoder->frameBufferAtIndex(frameIndex);
118 EXPECT_EQ(expectFailure, decoder->failed()); 281 ASSERT_EQ(true, decoder->failed());
119 if (!expectFailure) { 282
120 EXPECT_EQ(expectedFrameCountAfter, decoder->frameCount()); 283 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
121 EXPECT_EQ(ImageFrame::FrameEmpty, frame->getStatus());
122 }
123 } 284 }
124 285
125 } // Anonymous namespace 286 } // Anonymous namespace
126 287
288 // Animated PNG Tests
289
290 TEST(AnimatedPNGTests, sizeTest) {
291 testSize(
292 "/LayoutTests/images/resources/"
293 "png-animated-idat-part-of-animation.png",
294 IntSize(5, 5));
295 testSize(
296 "/LayoutTests/images/resources/"
297 "png-animated-idat-not-part-of-animation.png",
298 IntSize(227, 35));
299 }
300
301 TEST(AnimatedPNGTests, repetitionCountTest) {
302 testRepetitionCount(
303 "/LayoutTests/images/resources/"
304 "png-animated-idat-part-of-animation.png",
305 6u);
306 // This is an "animated" image with only one frame, that is, the IDAT is
307 // ignored and there is one fdAT frame. so it should be considered
308 // non-animated.
309 testRepetitionCount(
310 "/LayoutTests/images/resources/"
311 "png-animated-idat-not-part-of-animation.png",
312 cAnimationNone);
313 }
314
315 // Test if the decoded metdata corresponds to the defined expectations
316 TEST(AnimatedPNGTests, MetaDataTest) {
317 const char* pngFile =
318 "/LayoutTests/images/resources/"
319 "png-animated-idat-part-of-animation.png";
320 constexpr size_t expectedFrameCount = 4;
321
322 auto decoder = createDecoderWithPngData(pngFile);
323 ASSERT_EQ(expectedFrameCount, decoder->frameCount());
324 for (size_t i = 0; i < expectedFrameCount; i++) {
325 compareFrameWithExpectation(pngAnimatedFrameInfo[i], decoder.get(), i);
326 }
327 }
328
329 TEST(AnimatedPNGTests, EmptyFrame) {
330 const char* pngFile = "/LayoutTests/images/resources/empty-frame.png";
331 auto decoder = createDecoderWithPngData(pngFile);
332 // Frame 0 is empty. Ensure that decoding frame 1 (which depends on frame 0)
333 // fails (rather than crashing).
334 EXPECT_EQ(2u, decoder->frameCount());
335 EXPECT_FALSE(decoder->failed());
336
337 ImageFrame* frame = decoder->frameBufferAtIndex(1);
338 EXPECT_TRUE(decoder->failed());
339 ASSERT_NE(nullptr, frame);
340 EXPECT_EQ(ImageFrame::FrameEmpty, frame->getStatus());
341 }
342
343 TEST(AnimatedPNGTests, ByteByByteSizeAvailable) {
344 testSizeByteByByte(
345 "/LayoutTests/images/resources/"
346 "png-animated-idat-part-of-animation.png",
347 141u, IntSize(5, 5));
348 testSizeByteByByte(
349 "/LayoutTests/images/resources/"
350 "png-animated-idat-not-part-of-animation.png",
351 79u, IntSize(227, 35));
352 }
353
354 TEST(AnimatedPNGTests, ByteByByteMetaData) {
355 const char* pngFile =
356 "/LayoutTests/images/resources/"
357 "png-animated-idat-part-of-animation.png";
358 constexpr size_t expectedFrameCount = 4;
359
360 // These are the byte offsets where each frame should have been parsed.
361 // It boils down to the offset of the first fcTL / IEND after the last
362 // frame data chunk, plus 8 bytes for recognition. The exception on this is
363 // the first frame, which is reported when its first framedata is seen.
364 size_t frameOffsets[expectedFrameCount] = {141, 249, 322, 430};
365
366 auto decoder = createDecoder();
367 auto data = readFile(pngFile);
368 ASSERT_FALSE(data->isEmpty());
369 size_t framesParsed = 0;
370
371 const char* source = data->data();
372 RefPtr<SharedBuffer> partialData = SharedBuffer::create();
373 for (size_t length = 1; length <= frameOffsets[expectedFrameCount - 1];
374 length++) {
375 partialData->append(source++, 1u);
376 decoder->setData(partialData.get(), false);
377 EXPECT_FALSE(decoder->failed());
378 if (length < frameOffsets[framesParsed]) {
379 EXPECT_EQ(framesParsed, decoder->frameCount());
380 } else {
381 ASSERT_EQ(framesParsed + 1, decoder->frameCount());
382 compareFrameWithExpectation(pngAnimatedFrameInfo[framesParsed],
383 decoder.get(), framesParsed);
384 framesParsed++;
385 }
386 }
387 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
388 EXPECT_FALSE(decoder->failed());
389 }
390
391 TEST(AnimatedPNGTests, TestRandomFrameDecode) {
392 testRandomFrameDecode(&createDecoder,
393 "/LayoutTests/images/resources/"
394 "png-animated-idat-part-of-animation.png",
395 2u);
396 }
397
398 TEST(AnimatedPNGTests, TestDecodeAfterReallocation) {
399 testDecodeAfterReallocatingData(&createDecoder,
400 "/LayoutTests/images/resources/"
401 "png-animated-idat-part-of-animation.png");
402 }
403
404 TEST(AnimatedPNGTests, ProgressiveDecode) {
405 testProgressiveDecoding(&createDecoder,
406 "/LayoutTests/images/resources/"
407 "png-animated-idat-part-of-animation.png",
408 13u);
409 }
410
411 TEST(AnimatedPNGTests, ParseAndDecodeByteByByte) {
412 testByteByByteDecode(&createDecoder,
413 "/LayoutTests/images/resources/"
414 "png-animated-idat-part-of-animation.png",
415 4u, 6u);
416 }
417
418 TEST(AnimatedPNGTests, FailureDuringParsing) {
419 // Test the first fcTL in the stream. Because no frame data has been set at
420 // this point, the expected frame count is zero. 95 bytes is just before the
421 // first fcTL chunk, at which the first frame is detected. This is before the
422 // IDAT, so it should be treated as a static image.
423 testInvalidFctlSize(
424 "/LayoutTests/images/resources/"
425 "png-animated-idat-part-of-animation.png",
426 95u, 0u, false);
427
428 // Test for the third fcTL in the stream. This should see 1 frame before the
429 // fcTL, and then fail when parsing it.
430 testInvalidFctlSize(
431 "/LayoutTests/images/resources/"
432 "png-animated-idat-part-of-animation.png",
433 241u, 1u, true);
434 }
435
436 TEST(AnimatedPNGTests, ActlErrors) {
437 const char* pngFile =
438 "/LayoutTests/images/resources/"
439 "png-animated-idat-part-of-animation.png";
440 auto data = readFile(pngFile);
441 ASSERT_FALSE(data->isEmpty());
442
443 const size_t offsetActl = 33u;
444 const size_t acTLSize = 20u;
445 {
446 // Remove the acTL chunk from the stream. This results in a static image.
447 RefPtr<SharedBuffer> noActlData =
448 SharedBuffer::create(data->data(), offsetActl);
449 noActlData->append(data->data() + offsetActl + acTLSize,
450 data->size() - offsetActl - acTLSize);
451
452 auto decoder = createDecoder();
453 decoder->setData(noActlData, true);
454 EXPECT_EQ(1u, decoder->frameCount());
455 EXPECT_FALSE(decoder->failed());
456 EXPECT_EQ(cAnimationNone, decoder->repetitionCount());
457 }
458
459 // Store the acTL for more tests.
460 char acTL[acTLSize];
461 memcpy(acTL, data->data() + offsetActl, acTLSize);
462
463 // Insert an extra acTL at a couple of different offsets.
464 // Prior to the IDAT, this should result in a static image. After, this
465 // should fail.
466 const struct {
467 size_t offset;
468 bool shouldFail;
469 } gRecs[] = {{8u, false},
470 {offsetActl, false},
471 {133u, false},
472 {172u, true},
473 {422u, true}};
474 for (const auto& rec : gRecs) {
475 const size_t offset = rec.offset;
476 RefPtr<SharedBuffer> extraActlData =
477 SharedBuffer::create(data->data(), offset);
478 extraActlData->append(acTL, acTLSize);
479 extraActlData->append(data->data() + offset, data->size() - offset);
480 auto decoder = createDecoder();
481 decoder->setData(extraActlData, true);
482 EXPECT_EQ(rec.shouldFail ? 0u : 1u, decoder->frameCount());
483 EXPECT_EQ(rec.shouldFail, decoder->failed());
484 }
485
486 // An acTL after IDAT is ignored.
487 pngFile =
488 "/LayoutTests/images/resources/"
489 "cHRM_color_spin.png";
490 {
491 auto data2 = readFile(pngFile);
492 ASSERT_FALSE(data2->isEmpty());
493 const size_t postIDATOffset = 30971u;
494 for (size_t times = 0; times < 2; times++) {
495 RefPtr<SharedBuffer> extraActlData =
496 SharedBuffer::create(data2->data(), postIDATOffset);
497 for (size_t i = 0; i < times; i++)
498 extraActlData->append(acTL, acTLSize);
499 extraActlData->append(data2->data() + postIDATOffset,
500 data2->size() - postIDATOffset);
501
502 auto decoder = createDecoder();
503 decoder->setData(extraActlData, true);
504 EXPECT_EQ(1u, decoder->frameCount());
505 EXPECT_FALSE(decoder->failed());
506 EXPECT_EQ(cAnimationNone, decoder->repetitionCount());
507 EXPECT_NE(nullptr, decoder->frameBufferAtIndex(0));
508 EXPECT_FALSE(decoder->failed());
509 }
510 }
511 }
512
513 TEST(AnimatedPNGTests, fdatBeforeIdat) {
514 const char* pngFile =
515 "/LayoutTests/images/resources/"
516 "png-animated-idat-not-part-of-animation.png";
517 auto data = readFile(pngFile);
518 ASSERT_FALSE(data->isEmpty());
519
520 // Insert fcTL and fdAT prior to the IDAT
521 const size_t idatOffset = 71u;
522 RefPtr<SharedBuffer> modifiedData =
523 SharedBuffer::create(data->data(), idatOffset);
524 // Copy fcTL and fdAT
525 const size_t fctlPlusFdatSize = 38u + 1566u;
526 modifiedData->append(data->data() + 2519u, fctlPlusFdatSize);
527 // Copy IDAT
528 modifiedData->append(data->data() + idatOffset, 2448u);
529 // Copy the remaining
530 modifiedData->append(data->data() + 4123u, 39u + 12u);
531 // Data has just been rearranged.
532 ASSERT_EQ(data->size(), modifiedData->size());
533
534 {
535 // This broken APNG will be treated as a static png.
536 auto decoder = createDecoder();
537 decoder->setData(modifiedData.get(), true);
538 expectStatic(decoder.get());
539 }
540
541 {
542 // Remove the acTL from the modified image. It now has fdAT before
543 // IDAT, but no acTL, so fdAT should be ignored.
544 const size_t offsetActl = 33u;
545 const size_t acTLSize = 20u;
546 RefPtr<SharedBuffer> modifiedData2 =
547 SharedBuffer::create(modifiedData->data(), offsetActl);
548 modifiedData2->append(modifiedData->data() + offsetActl + acTLSize,
549 modifiedData->size() - offsetActl - acTLSize);
550 auto decoder = createDecoder();
551 decoder->setData(modifiedData2.get(), true);
552 expectStatic(decoder.get());
553
554 // Likewise, if an acTL follows the fdAT, it is ignored.
555 const size_t insertionOffset = idatOffset + fctlPlusFdatSize - acTLSize;
556 RefPtr<SharedBuffer> modifiedData3 =
557 SharedBuffer::create(modifiedData2->data(), insertionOffset);
558 modifiedData3->append(data->data() + offsetActl, acTLSize);
559 modifiedData3->append(modifiedData2->data() + insertionOffset,
560 modifiedData2->size() - insertionOffset);
561 decoder = createDecoder();
562 decoder->setData(modifiedData3.get(), true);
563 expectStatic(decoder.get());
564 }
565 }
566
567 TEST(AnimatedPNGTests, IdatSizeMismatch) {
568 // The default image must fill the image
569 const char* pngFile =
570 "/LayoutTests/images/resources/"
571 "png-animated-idat-part-of-animation.png";
572 auto data = readFile(pngFile);
573 ASSERT_FALSE(data->isEmpty());
574
575 const size_t fctlOffset = 95u;
576 RefPtr<SharedBuffer> modifiedData =
577 SharedBuffer::create(data->data(), fctlOffset);
578 const size_t fctlSize = 38u;
579 png_byte fctl[fctlSize];
580 memcpy(fctl, data->data() + fctlOffset, fctlSize);
581 // Set the height to a smaller value, so it does not fill the image.
582 writeUint32(3, fctl + 16);
583 // Correct the crc
584 writeUint32(3210324191, fctl + 34);
585 modifiedData->append((const char*)fctl, fctlSize);
586 const size_t afterFctl = fctlOffset + fctlSize;
587 modifiedData->append(data->data() + afterFctl, data->size() - afterFctl);
588
589 auto decoder = createDecoder();
590 decoder->setData(modifiedData.get(), true);
591 expectStatic(decoder.get());
592 }
593
594 // Originally, the third frame has an offset of (1,2) and a size of (3,2). By
595 // changing the offset to (4,4), the frame rect is no longer within the image
596 // size of 5x5. This results in a failure.
597 TEST(AnimatedPNGTests, VerifyFrameOutsideImageSizeFails) {
598 const char* pngFile =
599 "/LayoutTests/images/resources/"
600 "png-animated-idat-part-of-animation.png";
601 auto data = readFile(pngFile);
602 auto decoder = createDecoder();
603 ASSERT_FALSE(data->isEmpty());
604
605 const size_t offsetThirdFctl = 241;
606 RefPtr<SharedBuffer> modifiedData =
607 SharedBuffer::create(data->data(), offsetThirdFctl);
608 const size_t fctlSize = 38u;
609 png_byte fctl[fctlSize];
610 memcpy(fctl, data->data() + offsetThirdFctl, fctlSize);
611 // Modify offset and crc.
612 writeUint32(4, fctl + 20u);
613 writeUint32(4, fctl + 24u);
614 writeUint32(3700322018, fctl + 34u);
615
616 modifiedData->append(const_cast<const char*>(reinterpret_cast<char*>(fctl)),
617 fctlSize);
618 modifiedData->append(data->data() + offsetThirdFctl + fctlSize,
619 data->size() - offsetThirdFctl - fctlSize);
620
621 decoder->setData(modifiedData, true);
622
623 IntSize expectedSize(5, 5);
624 EXPECT_TRUE(decoder->isSizeAvailable());
625 EXPECT_EQ(expectedSize, decoder->size());
626
627 const size_t expectedFrameCount = 0;
628 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
629 EXPECT_TRUE(decoder->failed());
630 }
631
632 TEST(AnimatedPNGTests, ProgressiveDecodingContinuesAfterFullData) {
633 // 160u is a randomly chosen offset in the IDAT chunk of the first frame.
634 testProgressiveDecodingContinuesAfterFullData(
635 "/LayoutTests/images/resources/"
636 "png-animated-idat-part-of-animation.png",
637 160u);
638 }
639
640 TEST(AnimatedPNGTests, RandomDecodeAfterClearFrameBufferCache) {
641 testRandomDecodeAfterClearFrameBufferCache(
642 &createDecoder,
643 "/LayoutTests/images/resources/"
644 "png-animated-idat-part-of-animation.png",
645 2u);
646 }
647
648 TEST(AnimatedPNGTests, VerifyAlphaBlending) {
649 testAlphaBlending(&createDecoder,
650 "/LayoutTests/images/resources/"
651 "png-animated-idat-part-of-animation.png");
652 }
653
654 // This tests if the frame count gets set correctly when parsing frameCount
655 // fails in one of the parsing queries.
656 //
657 // First, enough data is provided such that two frames should be registered.
658 // The decoder should at this point not be in the failed status.
659 //
660 // Then, we provide the rest of the data except for the last IEND chunk, but
661 // tell the decoder that this is all the data we have. The frame count should
662 // be three, since one extra frame should be discovered. The fourth frame
663 // should *not* be registered since the reader should not be able to determine
664 // where the frame ends. The decoder should *not* be in the failed state since
665 // there are three frames which can be shown.
666 // Attempting to decode the third frame should fail, since the file is
667 // truncated.
668 TEST(AnimatedPNGTests, FailureMissingIendChunk) {
669 RefPtr<SharedBuffer> fullData = readFile(
670 "/LayoutTests/images/resources/"
671 "png-animated-idat-part-of-animation.png");
672 ASSERT_FALSE(fullData->isEmpty());
673 auto decoder = createDecoder();
674
675 const size_t offsetTwoFrames = 249;
676 const size_t expectedFramesAfter249Bytes = 2;
677 RefPtr<SharedBuffer> tempData =
678 SharedBuffer::create(fullData->data(), offsetTwoFrames);
679 decoder->setData(tempData.get(), false);
680 EXPECT_EQ(expectedFramesAfter249Bytes, decoder->frameCount());
681 EXPECT_FALSE(decoder->failed());
682
683 // Provide the rest of the data except for the last IEND chunk.
684 const size_t expectedFramesAfterAllExcept12Bytes = 3;
685 tempData = SharedBuffer::create(fullData->data(), fullData->size() - 12);
686 decoder->setData(tempData.get(), true);
687 ASSERT_EQ(expectedFramesAfterAllExcept12Bytes, decoder->frameCount());
688
689 for (size_t i = 0; i < expectedFramesAfterAllExcept12Bytes; i++) {
690 EXPECT_FALSE(decoder->failed());
691 decoder->frameBufferAtIndex(i);
692 }
693
694 EXPECT_TRUE(decoder->failed());
695 }
696
697 TEST(AnimatedPNGTests, FailureDuringDecodingInvalidatesDecoder) {
698 testFailureDuringDecode(
699 "/LayoutTests/images/resources/"
700 "png-animated-idat-part-of-animation.png",
701 291u, // fdat offset for frame index 2, plus 12 to move past sequence
702 // number.
703 2u, // try to decode frame index 2
704 4u); // expected frame count before failure
705
706 testFailureDuringDecode(
707 "/LayoutTests/images/resources/"
708 "png-animated-idat-part-of-animation.png",
709 133u, // idat offset for frame index 0
710 0u, // try to decode frame index 0
711 4u); // expected frame count before failure
712 }
713
714 // Verify that a malformatted PNG, where the IEND appears before any frame data
715 // (IDAT), invalidates the decoder.
716 TEST(AnimatedPNGTests, VerifyIENDBeforeIDATInvalidatesDecoder) {
717 RefPtr<SharedBuffer> fullData = readFile(
718 "/LayoutTests/images/resources/"
719 "png-animated-idat-part-of-animation.png");
720 ASSERT_FALSE(fullData->isEmpty());
721 auto decoder = createDecoder();
722
723 const size_t offsetIDAT = 133;
724 RefPtr<SharedBuffer> data =
725 SharedBuffer::create(fullData->data(), offsetIDAT);
726 data->append(fullData->data() + fullData->size() - 12u, 12u);
727 data->append(fullData->data() + offsetIDAT, fullData->size() - offsetIDAT);
728 decoder->setData(data.get(), true);
729
730 const size_t expectedFrameCount = 0u;
731 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
732 EXPECT_TRUE(decoder->failed());
733 }
734
735 // All IDAT chunks must be before all fdAT chunks
736 TEST(AnimatedPNGTests, MixedDataChunks) {
737 const char* pngFile =
738 "/LayoutTests/images/resources/"
739 "png-animated-idat-part-of-animation.png";
740 RefPtr<SharedBuffer> fullData = readFile(pngFile);
741 ASSERT_FALSE(fullData->isEmpty());
742
743 // Add an extra fdAT after the first IDAT, skipping fcTL.
744 const size_t postIDAT = 172u;
745 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), postIDAT);
746 const size_t fcTLSize = 38u;
747 const size_t fdATSize = 31u;
748 png_byte fdAT[fdATSize];
749 memcpy(fdAT, fullData->data() + postIDAT + fcTLSize, fdATSize);
750 // Modify the sequence number
751 writeUint32(1u, fdAT + 8);
752 data->append((const char*)fdAT, fdATSize);
753 const size_t IENDOffset = 422u;
754 data->append(fullData->data() + IENDOffset, fullData->size() - IENDOffset);
755 auto decoder = createDecoder();
756 decoder->setData(data.get(), true);
757 decoder->frameCount();
758 EXPECT_TRUE(decoder->failed());
759
760 // Insert an IDAT after an fdAT.
761 const size_t postfdAT = postIDAT + fcTLSize + fdATSize;
762 data = SharedBuffer::create(fullData->data(), postfdAT);
763 const size_t IDATOffset = 133u;
764 data->append(fullData->data() + IDATOffset, postIDAT - IDATOffset);
765 // Append the rest.
766 data->append(fullData->data() + postIDAT, fullData->size() - postIDAT);
767 decoder = createDecoder();
768 decoder->setData(data.get(), true);
769 decoder->frameCount();
770 EXPECT_TRUE(decoder->failed());
771 }
772
773 // Verify that erroneous values for the disposal method and alpha blending
774 // cause the decoder to fail.
775 TEST(AnimatedPNGTests, VerifyInvalidDisposalAndBlending) {
776 const char* pngFile =
777 "/LayoutTests/images/resources/"
778 "png-animated-idat-part-of-animation.png";
779 RefPtr<SharedBuffer> fullData = readFile(pngFile);
780 ASSERT_FALSE(fullData->isEmpty());
781 auto decoder = createDecoder();
782
783 // The disposal byte in the frame control chunk is the 24th byte, alpha
784 // blending the 25th. |offsetDisposalOp| is 241 bytes to get to the third
785 // fctl chunk, 8 bytes to skip the length and tag bytes, and 24 bytes to get
786 // to the disposal op.
787 //
788 // Write invalid values to the disposal and alpha blending byte, correct the
789 // crc and append the rest of the buffer.
790 const size_t offsetDisposalOp = 241 + 8 + 24;
791 RefPtr<SharedBuffer> data =
792 SharedBuffer::create(fullData->data(), offsetDisposalOp);
793 png_byte disposalAndBlending[6u];
794 disposalAndBlending[0] = 7;
795 disposalAndBlending[1] = 9;
796 writeUint32(2408835439u, disposalAndBlending + 2u);
797 data->append(reinterpret_cast<char*>(disposalAndBlending), 6u);
798 data->append(fullData->data() + offsetDisposalOp + 6u,
799 fullData->size() - offsetDisposalOp - 6u);
800
801 decoder->setData(data.get(), true);
802 decoder->frameCount();
803 ASSERT_TRUE(decoder->failed());
804 }
805
806 // This test verifies that the following situation does not invalidate the
807 // decoder:
808 // - Frame 0 is decoded progressively, but there's not enough data to fully
809 // decode it.
810 // - The rest of the image data is received.
811 // - Frame X, with X > 0, and X does not depend on frame 0, is decoded.
812 // - Frame 0 is decoded.
813 // This is a tricky case since the decoder resets the png struct for each frame,
814 // and this test verifies that it does not break the decoding of frame 0, even
815 // though it already started in the first call.
816 TEST(AnimatedPNGTests, VerifySuccessfulFirstFrameDecodeAfterLaterFrame) {
817 const char* pngFile =
818 "/LayoutTests/images/resources/"
819 "png-animated-three-independent-frames.png";
820 auto decoder = createDecoder();
821 auto fullData = readFile(pngFile);
822 ASSERT_FALSE(fullData->isEmpty());
823
824 // 160u is a randomly chosen offset in the IDAT chunk of the first frame.
825 const size_t middleFirstFrame = 160u;
826 RefPtr<SharedBuffer> data =
827 SharedBuffer::create(fullData->data(), middleFirstFrame);
828 decoder->setData(data.get(), false);
829
830 ASSERT_EQ(1u, decoder->frameCount());
831 ASSERT_EQ(ImageFrame::FramePartial,
832 decoder->frameBufferAtIndex(0)->getStatus());
833
834 decoder->setData(fullData.get(), true);
835 ASSERT_EQ(3u, decoder->frameCount());
836 ASSERT_EQ(ImageFrame::FrameComplete,
837 decoder->frameBufferAtIndex(1)->getStatus());
838 // The point is that this call does not decode frame 0, which it won't do if
839 // it does not have it as its required previous frame.
840 ASSERT_EQ(kNotFound,
841 decoder->frameBufferAtIndex(1)->requiredPreviousFrameIndex());
842
843 EXPECT_EQ(ImageFrame::FrameComplete,
844 decoder->frameBufferAtIndex(0)->getStatus());
845 EXPECT_FALSE(decoder->failed());
846 }
847
848 // If the decoder attempts to decode a non-first frame which is subset and
849 // independent, it needs to discard its png_struct so it can use a modified
850 // IHDR. Test this by comparing a decode of frame 1 after frame 0 to a decode
851 // of frame 1 without decoding frame 0.
852 TEST(AnimatedPNGTests, DecodeFromIndependentFrame) {
853 const char* pngFile =
854 "/LayoutTests/images/resources/"
855 "png-animated-idat-part-of-animation.png";
856 auto originalData = readFile(pngFile);
857 ASSERT_FALSE(originalData->isEmpty());
858
859 // This file almost fits the bill. Modify it to dispose frame 0, making
860 // frame 1 independent.
861 const size_t kDisposeOffset = 127u;
862 auto data = SharedBuffer::create(originalData->data(), kDisposeOffset);
863 // 1 Corresponds to APNG_DISPOSE_OP_BACKGROUND
864 const char one = '\001';
865 data->append(&one, 1u);
866 // No need to modify the blend op
867 data->append(originalData->data() + kDisposeOffset + 1, 1u);
868 // Modify the CRC
869 png_byte crc[4];
870 writeUint32(2226670956, crc);
871 data->append(reinterpret_cast<const char*>(crc), 4u);
872 data->append(originalData->data() + data->size(),
873 originalData->size() - data->size());
874 ASSERT_EQ(originalData->size(), data->size());
875
876 auto decoder = createDecoder();
877 decoder->setData(data.get(), true);
878
879 ASSERT_EQ(4u, decoder->frameCount());
880 ASSERT_FALSE(decoder->failed());
881
882 auto* frame = decoder->frameBufferAtIndex(0);
883 ASSERT_TRUE(frame);
884 ASSERT_EQ(ImageFrame::DisposeOverwriteBgcolor, frame->getDisposalMethod());
885
886 frame = decoder->frameBufferAtIndex(1);
887 ASSERT_TRUE(frame);
888 ASSERT_FALSE(decoder->failed());
889 ASSERT_NE(IntRect({}, decoder->size()), frame->originalFrameRect());
890 ASSERT_EQ(kNotFound, frame->requiredPreviousFrameIndex());
891
892 const auto hash = hashBitmap(frame->bitmap());
893
894 // Now decode starting from frame 1.
895 decoder = createDecoder();
896 decoder->setData(data.get(), true);
897
898 frame = decoder->frameBufferAtIndex(1);
899 ASSERT_TRUE(frame);
900 EXPECT_EQ(hash, hashBitmap(frame->bitmap()));
901 }
902
903 // If the first frame is subset from IHDR (only allowed if the first frame is
904 // not the default image), the decoder has to destroy the png_struct it used
905 // for parsing so it can use a modified IHDR.
906 TEST(AnimatedPNGTests, SubsetFromIHDR) {
907 const char* pngFile =
908 "/LayoutTests/images/resources/"
909 "png-animated-idat-not-part-of-animation.png";
910 auto originalData = readFile(pngFile);
911 ASSERT_FALSE(originalData->isEmpty());
912
913 const size_t fcTLOffset = 2519u;
914 auto data = SharedBuffer::create(originalData->data(), fcTLOffset);
915
916 const size_t fcTLSize = 38u;
917 png_byte fcTL[fcTLSize];
918 memcpy(fcTL, originalData->data() + fcTLOffset, fcTLSize);
919 // Modify to have a subset frame (yOffset 1, height 34 out of 35).
920 writeUint32(34, fcTL + 16u);
921 writeUint32(1, fcTL + 24u);
922 writeUint32(3972842751, fcTL + 34u);
923 data->append(reinterpret_cast<const char*>(fcTL), fcTLSize);
924
925 // Append the rest of the data.
926 // Note: If PNGImageDecoder changes to reject an image with too many
927 // rows, the fdAT data will need to be modified as well.
928 data->append(originalData->data() + fcTLOffset + fcTLSize,
929 originalData->size() - data->size());
930 ASSERT_EQ(originalData->size(), data->size());
931
932 // This will test both byte by byte and using the full data, and compare.
933 testByteByByteDecode(createDecoder, data.get(), 1, cAnimationNone);
934 }
935
127 // Static PNG tests 936 // Static PNG tests
128 937
129 TEST(StaticPNGTests, repetitionCountTest) { 938 TEST(StaticPNGTests, repetitionCountTest) {
130 testRepetitionCount("/LayoutTests/images/resources/png-simple.png", 939 testRepetitionCount("/LayoutTests/images/resources/png-simple.png",
131 cAnimationNone); 940 cAnimationNone);
132 } 941 }
133 942
134 TEST(StaticPNGTests, sizeTest) { 943 TEST(StaticPNGTests, sizeTest) {
135 testSize("/LayoutTests/images/resources/png-simple.png", IntSize(111, 29)); 944 testSize("/LayoutTests/images/resources/png-simple.png", IntSize(111, 29));
136 } 945 }
137 946
138 TEST(StaticPNGTests, MetaDataTest) { 947 TEST(StaticPNGTests, MetaDataTest) {
139 const size_t expectedFrameCount = 1; 948 const size_t expectedFrameCount = 1;
140 const size_t expectedDuration = 0; 949 const size_t expectedDuration = 0;
141 auto decoder = 950 auto decoder =
142 createDecoderWithPngData("/LayoutTests/images/resources/png-simple.png"); 951 createDecoderWithPngData("/LayoutTests/images/resources/png-simple.png");
143 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); 952 EXPECT_EQ(expectedFrameCount, decoder->frameCount());
144 EXPECT_EQ(expectedDuration, decoder->frameDurationAtIndex(0)); 953 EXPECT_EQ(expectedDuration, decoder->frameDurationAtIndex(0));
145 } 954 }
146 955
956 TEST(StaticPNGTests, InvalidIHDRChunk) {
957 testMissingDataBreaksDecoding("/LayoutTests/images/resources/png-simple.png",
958 20u, 2u);
959 }
960
147 TEST(StaticPNGTests, ProgressiveDecoding) { 961 TEST(StaticPNGTests, ProgressiveDecoding) {
148 testProgressiveDecoding(&createDecoder, 962 testProgressiveDecoding(&createDecoder,
149 "/LayoutTests/images/resources/png-simple.png", 11u); 963 "/LayoutTests/images/resources/png-simple.png", 11u);
150 } 964 }
151 965
152 TEST(StaticPNGTests, ProgressiveDecodingContinuesAfterFullData) { 966 TEST(StaticPNGTests, ProgressiveDecodingContinuesAfterFullData) {
153 testProgressiveDecodingContinuesAfterFullData( 967 testProgressiveDecodingContinuesAfterFullData(
154 "/LayoutTests/images/resources/png-simple.png", 1000u); 968 "/LayoutTests/images/resources/png-simple.png", 1000u);
155 } 969 }
156 970
157 TEST(StaticPNGTests, FailureDuringDecodingInvalidatesDecoder) { 971 TEST(StaticPNGTests, FailureDuringDecodingInvalidatesDecoder) {
158 testFailureDuringDecode( 972 testFailureDuringDecode(
159 "/LayoutTests/images/resources/png-simple.png", 973 "/LayoutTests/images/resources/png-simple.png",
160 85u, // idat offset for frame index 0 974 85u, // idat offset for frame index 0
161 0u, // try to decode frame index 0 975 0u, // try to decode frame index 0
162 true, // expect the decoder to be invalidated after the failure
163 1u); // expected frame count before failure 976 1u); // expected frame count before failure
164 } 977 }
165 978
166 // For static images, frameIsCompleteAtIndex(0) should return true if and only 979 TEST(PNGTests, VerifyFrameCompleteBehavior) {
167 // if the frame is successfully decoded, not when it is fully received. 980 struct {
168 TEST(StaticPNGTests, VerifyFrameCompleteBehavior) { 981 const char* name;
169 auto decoder = 982 size_t expectedFrameCount;
170 createDecoderWithPngData("/LayoutTests/images/resources/png-simple.png"); 983 size_t offsetInFirstFrame;
171 EXPECT_EQ(1u, decoder->frameCount()); 984 } gRecs[] = {
172 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0)); 985 {"/LayoutTests/images/resources/"
173 EXPECT_EQ(ImageFrame::FrameComplete, 986 "png-animated-three-independent-frames.png",
174 decoder->frameBufferAtIndex(0)->getStatus()); 987 3u, 150u},
175 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); 988 {"/LayoutTests/images/resources/"
989 "png-animated-idat-part-of-animation.png",
990 4u, 160u},
991
992 {"/LayoutTests/images/resources/png-simple.png", 1u, 700u},
993 {"/LayoutTests/images/resources/lenna.png", 1u, 40000u},
994 };
995 for (const auto& rec : gRecs) {
996 auto fullData = readFile(rec.name);
997 ASSERT_TRUE(fullData.get());
998
999 // Create with enough data for part of the first frame.
1000 auto decoder = createDecoder();
1001 auto data = SharedBuffer::create(fullData->data(), rec.offsetInFirstFrame);
1002 decoder->setData(data.get(), false);
1003
1004 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0));
1005
1006 // Parsing the size is not enough to mark the frame as complete.
1007 EXPECT_TRUE(decoder->isSizeAvailable());
1008 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0));
1009
1010 const auto partialFrameCount = decoder->frameCount();
1011 EXPECT_EQ(1u, partialFrameCount);
1012
1013 // Frame is not complete, even after decoding partially.
1014 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0));
1015 auto* frame = decoder->frameBufferAtIndex(0);
1016 ASSERT_TRUE(frame);
1017 EXPECT_NE(ImageFrame::FrameComplete, frame->getStatus());
1018 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0));
1019
1020 decoder->setData(fullData.get(), true);
1021
1022 // With full data, parsing the size still does not mark a frame as
1023 // complete.
1024 EXPECT_TRUE(decoder->isSizeAvailable());
1025 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0));
1026
1027 const auto frameCount = decoder->frameCount();
1028 ASSERT_EQ(rec.expectedFrameCount, frameCount);
1029
1030 if (frameCount > 1u) {
1031 // After parsing (the full file), all frames are complete.
1032 for (size_t i = 0; i < frameCount; ++i)
1033 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(i));
1034 } else {
1035 // A single frame image is not reported complete until decoding.
1036 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0));
1037 }
1038
1039 frame = decoder->frameBufferAtIndex(0);
1040 ASSERT_TRUE(frame);
1041 EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
1042 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0));
1043 }
176 } 1044 }
177 1045
178 }; // namespace blink 1046 }; // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698