OLD | NEW |
---|---|
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 "platform/image-decoders/ImageDecoderTestHelpers.h" | 7 #include "platform/image-decoders/ImageDecoderTestHelpers.h" |
8 #include "png.h" | |
8 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
9 #include <memory> | 10 #include <memory> |
10 | 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. | |
29 | |
30 // @TODO(joostouwerling) extend test image set with other image encodings, such | |
31 // as first frame fcTL and multiple chunks per frame. | |
32 | |
11 namespace blink { | 33 namespace blink { |
12 | 34 |
13 namespace { | 35 namespace { |
14 | 36 |
15 std::unique_ptr<ImageDecoder> createDecoder( | 37 std::unique_ptr<ImageDecoder> createDecoder( |
16 ImageDecoder::AlphaOption alphaOption) { | 38 ImageDecoder::AlphaOption alphaOption) { |
17 return WTF::wrapUnique(new PNGImageDecoder( | 39 return WTF::wrapUnique(new PNGImageDecoder( |
18 alphaOption, ColorBehavior::transformToTargetForTesting(), | 40 alphaOption, ColorBehavior::transformToTargetForTesting(), |
19 ImageDecoder::noDecodedImageByteLimit)); | 41 ImageDecoder::noDecodedImageByteLimit)); |
20 } | 42 } |
21 | 43 |
22 std::unique_ptr<ImageDecoder> createDecoder() { | 44 std::unique_ptr<ImageDecoder> createDecoder() { |
23 return createDecoder(ImageDecoder::AlphaNotPremultiplied); | 45 return createDecoder(ImageDecoder::AlphaNotPremultiplied); |
24 } | 46 } |
25 | 47 |
26 std::unique_ptr<ImageDecoder> createDecoderWithPngData(const char* pngFile) { | 48 std::unique_ptr<ImageDecoder> createDecoderWithPngData(const char* pngFile) { |
27 auto decoder = createDecoder(); | 49 auto decoder = createDecoder(); |
28 auto data = readFile(pngFile); | 50 auto data = readFile(pngFile); |
29 EXPECT_FALSE(data->isEmpty()); | 51 EXPECT_FALSE(data->isEmpty()); |
30 decoder->setData(data.get(), true); | 52 decoder->setData(data.get(), true); |
31 return decoder; | 53 return decoder; |
32 } | 54 } |
33 | 55 |
34 void testSize(const char* pngFile, IntSize expectedSize) { | 56 void testSize(const char* pngFile, IntSize expectedSize) { |
35 auto decoder = createDecoderWithPngData(pngFile); | 57 auto decoder = createDecoderWithPngData(pngFile); |
36 EXPECT_TRUE(decoder->isSizeAvailable()); | 58 EXPECT_TRUE(decoder->isSizeAvailable()); |
37 EXPECT_EQ(expectedSize, decoder->size()); | 59 EXPECT_EQ(expectedSize, decoder->size()); |
38 } | 60 } |
39 | 61 |
62 // Test whether querying for the size of the image works if we present the | |
63 // data byte by byte. | |
64 void testSizeByteByByte(const char* pngFile, | |
65 size_t bytesNeededToDecodeSize, | |
66 IntSize expectedSize) { | |
67 auto decoder = createDecoder(); | |
68 auto data = readFile(pngFile); | |
69 ASSERT_FALSE(data->isEmpty()); | |
70 ASSERT_LT(bytesNeededToDecodeSize, data->size()); | |
71 | |
72 for (size_t length = 1; length <= bytesNeededToDecodeSize; length++) { | |
73 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), length); | |
74 decoder->setData(tempData.get(), false); | |
75 | |
76 if (length < bytesNeededToDecodeSize) { | |
77 EXPECT_FALSE(decoder->isSizeAvailable()); | |
78 EXPECT_TRUE(decoder->size().isEmpty()); | |
79 EXPECT_FALSE(decoder->failed()); | |
80 } else { | |
81 EXPECT_TRUE(decoder->isSizeAvailable()); | |
82 EXPECT_EQ(expectedSize, decoder->size()); | |
83 } | |
84 } | |
85 EXPECT_FALSE(decoder->failed()); | |
86 } | |
87 | |
88 void writeUint32(uint32_t val, png_byte* data) { | |
89 data[0] = val >> 24; | |
90 data[1] = val >> 16; | |
91 data[2] = val >> 8; | |
92 data[3] = val; | |
93 } | |
94 | |
40 void testRepetitionCount(const char* pngFile, int expectedRepetitionCount) { | 95 void testRepetitionCount(const char* pngFile, int expectedRepetitionCount) { |
41 auto decoder = createDecoderWithPngData(pngFile); | 96 auto decoder = createDecoderWithPngData(pngFile); |
42 // Decoding the frame count sets the repetition count as well. | 97 // Decode frame count should see the number of repetitions as well. |
43 decoder->frameCount(); | 98 decoder->frameCount(); |
44 EXPECT_FALSE(decoder->failed()); | 99 EXPECT_FALSE(decoder->failed()); |
45 EXPECT_EQ(expectedRepetitionCount, decoder->repetitionCount()); | 100 EXPECT_EQ(expectedRepetitionCount, decoder->repetitionCount()); |
46 } | 101 } |
47 | 102 |
103 struct PublicFrameInfo { | |
104 size_t duration; | |
105 IntRect frameRect; | |
106 ImageFrame::AlphaBlendSource alphaBlend; | |
107 ImageFrame::DisposalMethod disposalMethod; | |
108 }; | |
109 | |
110 // This is the frame data for the following PNG image: | |
111 // /LayoutTests/images/resources/png-animated-idat-part-of-animation.png | |
112 static PublicFrameInfo pngAnimatedFrameInfo[] = { | |
113 {500, | |
114 {IntPoint(0, 0), IntSize(5, 5)}, | |
115 ImageFrame::BlendAtopBgcolor, | |
116 ImageFrame::DisposeKeep}, | |
117 {900, | |
118 {IntPoint(1, 1), IntSize(3, 1)}, | |
119 ImageFrame::BlendAtopBgcolor, | |
120 ImageFrame::DisposeOverwriteBgcolor}, | |
121 {2000, | |
122 {IntPoint(1, 2), IntSize(3, 2)}, | |
123 ImageFrame::BlendAtopPreviousFrame, | |
124 ImageFrame::DisposeKeep}, | |
125 {1500, | |
126 {IntPoint(1, 2), IntSize(3, 1)}, | |
127 ImageFrame::BlendAtopBgcolor, | |
128 ImageFrame::DisposeKeep}, | |
129 }; | |
130 | |
131 void compareFrameWithExpectation(const PublicFrameInfo& expected, | |
132 const ImageFrame* frame) { | |
133 EXPECT_EQ(expected.duration, frame->duration()); | |
134 EXPECT_EQ(expected.frameRect, frame->originalFrameRect()); | |
135 EXPECT_EQ(expected.disposalMethod, frame->getDisposalMethod()); | |
136 EXPECT_EQ(expected.alphaBlend, frame->getAlphaBlendSource()); | |
137 } | |
138 | |
139 // This function removes |length| bytes at |offset|, and then calls frameCount. | |
140 // It assumes the missing bytes should result in a failed decode because the | |
141 // parser jumps |length| bytes too far in the next chunk. | |
142 void testMissingDataBreaksDecoding(const char* pngFile, | |
143 size_t offset, | |
144 size_t length) { | |
145 auto decoder = createDecoder(); | |
146 auto data = readFile(pngFile); | |
147 ASSERT_FALSE(data->isEmpty()); | |
148 | |
149 RefPtr<SharedBuffer> invalidData = SharedBuffer::create(data->data(), offset); | |
150 invalidData->append(data->data() + offset + length, | |
151 data->size() - offset - length); | |
152 ASSERT_EQ(data->size() - length, invalidData->size()); | |
153 | |
154 decoder->setData(invalidData, true); | |
155 decoder->frameCount(); | |
156 EXPECT_TRUE(decoder->failed()); | |
157 } | |
158 | |
159 // Decoding up to the indicated fcTL offset and then provide an fcTL with | |
160 // the wrong chunk size (20 instead of 26). It should break the decoder. | |
161 void testInvalidFctlSize(const char* pngFile, | |
162 size_t offsetFctl, | |
163 size_t expectedFrameCountBeforeFail, | |
164 bool expectedDecoderFailure) { | |
165 auto data = readFile(pngFile); | |
166 ASSERT_FALSE(data->isEmpty()); | |
167 | |
168 auto decoder = createDecoder(); | |
169 RefPtr<SharedBuffer> invalidData = | |
170 SharedBuffer::create(data->data(), offsetFctl); | |
171 | |
172 // Test if this gives the correct frame count, before the fcTL is parsed. | |
173 decoder->setData(invalidData, false); | |
174 EXPECT_EQ(expectedFrameCountBeforeFail, decoder->frameCount()); | |
175 ASSERT_FALSE(decoder->failed()); | |
176 | |
177 // Append the wrong size to the data stream | |
178 png_byte sizeChunk[4]; | |
179 writeUint32(20, sizeChunk); | |
180 invalidData->append(reinterpret_cast<char*>(sizeChunk), 4u); | |
181 | |
182 // Skip the size in the original data, but provide the rest of the fcTL, | |
183 // which is 4B of tag, 26B of data and 4B of CRC, totalling 34B. | |
184 invalidData->append(data->data() + offsetFctl + 4, 34u); | |
185 | |
186 decoder->setData(invalidData, false); | |
187 decoder->frameCount(); | |
188 EXPECT_EQ(expectedDecoderFailure, decoder->failed()); | |
189 } | |
190 | |
191 void testDifferentActlFrameCountIsIgnored(const char* pngFile, | |
192 size_t offsetActl, | |
193 size_t injectedFrameCount, | |
194 size_t expectedFrameCount) { | |
195 // First make sure that this tests makes sense. | |
196 ASSERT_NE(injectedFrameCount, expectedFrameCount); | |
197 | |
198 auto data = readFile(pngFile); | |
199 auto decoder = createDecoder(); | |
200 ASSERT_FALSE(data->isEmpty()); | |
201 | |
202 RefPtr<SharedBuffer> diffActlData = | |
203 SharedBuffer::create(data->data(), offsetActl + 8); | |
204 // Write the injectedFrameCount to the stream | |
205 png_byte sizeChunk[4]; | |
206 writeUint32(injectedFrameCount, sizeChunk); | |
207 diffActlData->append(reinterpret_cast<char*>(sizeChunk), 4u); | |
208 // Append the rest of the data. The first |offsetActl + 12| bytes that are | |
209 // already in diffActlData should not be appended again. | |
210 diffActlData->append(data->data() + offsetActl + 12, | |
211 data->size() - offsetActl - 12); | |
212 | |
213 decoder->setData(diffActlData, true); | |
214 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
215 } | |
216 | |
48 // Verify that the decoder can successfully decode the first frame when | 217 // 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 | 218 // 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 | 219 // 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 | 220 // 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. | 221 // bitmap hash is equivalent to the hash when all data is provided at once. |
53 // | 222 // |
54 // This verifies that decoder correctly keeps track of where it stopped | 223 // This verifies that decoder correctly keeps track of where it stopped |
55 // decoding when the image was not yet fully received. | 224 // decoding when the image was not yet fully received. |
56 void testProgressiveDecodingContinuesAfterFullData(const char* pngFile, | 225 void testProgressiveDecodingContinuesAfterFullData(const char* pngFile, |
57 size_t offsetMidFirstFrame) { | 226 size_t offsetMidFirstFrame) { |
58 auto fullData = readFile(pngFile); | 227 auto fullData = readFile(pngFile); |
59 ASSERT_FALSE(fullData->isEmpty()); | 228 ASSERT_FALSE(fullData->isEmpty()); |
60 | 229 |
61 auto decoderUpfront = createDecoder(); | 230 auto decoderUpfront = createDecoder(); |
62 decoderUpfront->setData(fullData.get(), true); | 231 decoderUpfront->setData(fullData.get(), true); |
63 EXPECT_GE(1u, decoderUpfront->frameCount()); | 232 EXPECT_GE(decoderUpfront->frameCount(), 1u); |
64 const ImageFrame* const frameUpfront = decoderUpfront->frameBufferAtIndex(0); | 233 const ImageFrame* const frameUpfront = decoderUpfront->frameBufferAtIndex(0); |
65 ASSERT_EQ(ImageFrame::FrameComplete, frameUpfront->getStatus()); | 234 ASSERT_EQ(ImageFrame::FrameComplete, frameUpfront->getStatus()); |
66 const unsigned hashUpfront = hashBitmap(frameUpfront->bitmap()); | 235 const unsigned hashUpfront = hashBitmap(frameUpfront->bitmap()); |
67 | 236 |
68 auto decoder = createDecoder(); | 237 auto decoder = createDecoder(); |
69 RefPtr<SharedBuffer> partialData = | 238 RefPtr<SharedBuffer> partialData = |
70 SharedBuffer::create(fullData->data(), offsetMidFirstFrame); | 239 SharedBuffer::create(fullData->data(), offsetMidFirstFrame); |
71 decoder->setData(partialData, false); | 240 decoder->setData(partialData, false); |
72 | 241 |
73 EXPECT_EQ(1u, decoder->frameCount()); | 242 EXPECT_EQ(1u, decoder->frameCount()); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
107 // should give an error during decoding. | 276 // should give an error during decoding. |
108 data->append(fullData->data() + idatOffset, 8u); | 277 data->append(fullData->data() + idatOffset, 8u); |
109 data->append(fullData->data() + idatOffset + 16u, | 278 data->append(fullData->data() + idatOffset + 16u, |
110 fullData->size() - idatOffset - 16u); | 279 fullData->size() - idatOffset - 16u); |
111 | 280 |
112 auto decoder = createDecoder(); | 281 auto decoder = createDecoder(); |
113 decoder->setData(data.get(), true); | 282 decoder->setData(data.get(), true); |
114 | 283 |
115 EXPECT_EQ(expectedFrameCountBefore, decoder->frameCount()); | 284 EXPECT_EQ(expectedFrameCountBefore, decoder->frameCount()); |
116 | 285 |
117 const ImageFrame* const frame = decoder->frameBufferAtIndex(frameIndex); | 286 decoder->frameBufferAtIndex(frameIndex); |
118 EXPECT_EQ(expectFailure, decoder->failed()); | 287 EXPECT_EQ(expectFailure, decoder->failed()); |
119 if (!expectFailure) { | 288 if (!expectFailure) { |
120 EXPECT_EQ(expectedFrameCountAfter, decoder->frameCount()); | 289 EXPECT_EQ(expectedFrameCountAfter, decoder->frameCount()); |
121 EXPECT_EQ(ImageFrame::FrameEmpty, frame->getStatus()); | 290 EXPECT_EQ(nullptr, decoder->frameBufferAtIndex(frameIndex)); |
scroggo_chromium
2016/12/14 14:18:06
If expectFailure is true, should perform a differe
joostouwerling
2016/12/16 19:59:32
Hmm, I don't think that is necessary if we already
| |
122 } | 291 } |
123 } | 292 } |
124 | 293 |
125 } // Anonymous namespace | 294 } // Anonymous namespace |
126 | 295 |
296 // Animated PNG Tests | |
297 | |
298 TEST(AnimatedPNGTests, sizeTest) { | |
299 testSize( | |
300 "/LayoutTests/images/resources/" | |
301 "png-animated-idat-part-of-animation.png", | |
302 IntSize(5, 5)); | |
303 testSize( | |
304 "/LayoutTests/images/resources/" | |
305 "png-animated-idat-not-part-of-animation.png", | |
306 IntSize(227, 35)); | |
307 } | |
308 | |
309 TEST(AnimatedPNGTests, repetitionCountTest) { | |
310 testRepetitionCount( | |
311 "/LayoutTests/images/resources/" | |
312 "png-animated-idat-part-of-animation.png", | |
313 7u); | |
314 // This is an "animated" image with only one frame, that is, the IDAT is | |
315 // ignored and there is one fdAT frame. so it should be considered | |
316 // non-animated. | |
317 testRepetitionCount( | |
318 "/LayoutTests/images/resources/" | |
319 "png-animated-idat-not-part-of-animation.png", | |
320 cAnimationNone); | |
321 } | |
322 | |
323 // Test if the decoded metdata corresponds to the defined expectations | |
324 TEST(AnimatedPNGTests, MetaDataTest) { | |
325 const char* pngFile = | |
326 "/LayoutTests/images/resources/" | |
327 "png-animated-idat-part-of-animation.png"; | |
328 constexpr size_t expectedFrameCount = 4; | |
329 | |
330 auto decoder = createDecoderWithPngData(pngFile); | |
331 ASSERT_EQ(expectedFrameCount, decoder->frameCount()); | |
332 for (size_t i = 0; i < expectedFrameCount; i++) { | |
333 compareFrameWithExpectation(pngAnimatedFrameInfo[i], | |
334 decoder->frameBufferAtIndex(i)); | |
335 } | |
336 } | |
337 | |
338 TEST(AnimatedPNGTests, ByteByByteSizeAvailable) { | |
339 testSizeByteByByte( | |
340 "/LayoutTests/images/resources/" | |
341 "png-animated-idat-part-of-animation.png", | |
342 141u, IntSize(5, 5)); | |
343 testSizeByteByByte( | |
344 "/LayoutTests/images/resources/" | |
345 "png-animated-idat-not-part-of-animation.png", | |
346 79u, IntSize(227, 35)); | |
347 } | |
348 | |
349 // Test whether the frame metadata decoding also works when we provide the data | |
350 // byte by byte. This should cover the case when the client does not provide | |
351 // all data at once. At given offsets, we expect frames to become available. | |
352 // This test checks whether that is the case, and if so, if the frame data is | |
353 // equal to what we expected. | |
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 for (size_t length = 1; length <= frameOffsets[expectedFrameCount - 1]; | |
372 length++) { | |
373 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), length); | |
374 decoder->setData(tempData.get(), false); | |
375 EXPECT_FALSE(decoder->failed()); | |
376 if (length < frameOffsets[framesParsed]) { | |
377 EXPECT_EQ(framesParsed, decoder->frameCount()); | |
378 } else { | |
379 ASSERT_EQ(framesParsed + 1, decoder->frameCount()); | |
380 compareFrameWithExpectation(pngAnimatedFrameInfo[framesParsed], | |
381 decoder->frameBufferAtIndex(framesParsed)); | |
382 framesParsed++; | |
383 } | |
384 } | |
385 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
386 EXPECT_FALSE(decoder->failed()); | |
387 } | |
388 | |
389 TEST(AnimatedPNGTests, TestRandomFrameDecode) { | |
390 testRandomFrameDecode(&createDecoder, | |
391 "/LayoutTests/images/resources/" | |
392 "png-animated-idat-part-of-animation.png", | |
393 2u); | |
394 } | |
395 | |
396 TEST(AnimatedPNGTests, TestDecodeAfterReallocation) { | |
397 testDecodeAfterReallocatingData(&createDecoder, | |
398 "/LayoutTests/images/resources/" | |
399 "png-animated-idat-part-of-animation.png"); | |
400 } | |
401 | |
402 TEST(AnimatedPNGTests, ProgressiveDecode) { | |
403 testProgressiveDecoding(&createDecoder, | |
404 "/LayoutTests/images/resources/" | |
405 "png-animated-idat-part-of-animation.png", | |
406 13u); | |
407 } | |
408 | |
409 TEST(AnimatedPNGTests, ParseAndDecodeByteByByte) { | |
410 testByteByByteDecode(&createDecoder, | |
411 "/LayoutTests/images/resources/" | |
412 "png-animated-idat-part-of-animation.png", | |
413 4u, 7u); | |
414 } | |
415 | |
416 TEST(AnimatedPNGTests, FailureDuringParsing) { | |
417 // Test the first fcTL in the stream. Because no frame data has been set at | |
418 // this point, the expected frame count is zero. 95 bytes is just before the | |
419 // first fcTL chunk, at which the first frame is detected. The decoder should | |
420 // be in the failed state since no frames were parsed before this error. | |
421 testInvalidFctlSize( | |
422 "/LayoutTests/images/resources/" | |
423 "png-animated-idat-part-of-animation.png", | |
424 95u, 0u, true); | |
425 | |
426 // Test for the third fcTL in the stream. This should be tested as well, | |
427 // since the first fcTL is parsed in PNGImageReader::parseSize() whereas | |
428 // later fcTLs are parsed in PNGImageReader::parse() as part of framecount. | |
429 // The expected frame count before the fcTL chunk is 1u, since the second | |
430 // frame is registered when the third fcTL (or IEND) is seen. | |
431 // | |
432 // This should *not* set the decoder to the failed state since the first | |
433 // frame was succesfully parsed, and we still want to show that frame. | |
434 testInvalidFctlSize( | |
435 "/LayoutTests/images/resources/" | |
436 "png-animated-idat-part-of-animation.png", | |
437 241u, 1u, false); | |
438 } | |
439 | |
440 TEST(AnimatedPNGTests, FailureDuringParsingDueToMissingFctlData) { | |
441 // The fcTL chunk starts at 95u, add 10u to get to the content data, and | |
442 // remove 5 bytes of data. This sets the decoder to the failed state since | |
443 // no frames were parsed yet. | |
444 testMissingDataBreaksDecoding( | |
445 "/LayoutTests/images/resources/" | |
446 "png-animated-idat-part-of-animation.png", | |
447 105u, 5u); | |
448 } | |
449 | |
450 TEST(AnimatedPNGTests, MissingActlResultsInNonAnimated) { | |
451 const char* pngFile = | |
452 "/LayoutTests/images/resources/" | |
453 "png-animated-idat-part-of-animation.png"; | |
454 auto data = readFile(pngFile); | |
455 auto decoder = createDecoder(); | |
456 ASSERT_FALSE(data->isEmpty()); | |
457 | |
458 // Remove the acTL chunk from the stream. | |
459 const size_t offsetActl = 33; | |
460 RefPtr<SharedBuffer> noActlData = | |
461 SharedBuffer::create(data->data(), offsetActl); | |
462 noActlData->append(data->data() + offsetActl + 20, | |
463 data->size() - offsetActl - 20); | |
464 | |
465 decoder->setData(noActlData, true); | |
466 EXPECT_EQ(1u, decoder->frameCount()); | |
467 EXPECT_FALSE(decoder->failed()); | |
468 } | |
469 | |
470 // Test if the indicated frame count by the acTL is ignored if the actual | |
471 // number of frames is different. Test for higher and lower indicated number. | |
472 TEST(AnimatedPNGTests, differentActlFrameCountIsIgnored) { | |
473 const char* pngFile = | |
474 "/LayoutTests/images/resources/" | |
475 "png-animated-idat-part-of-animation.png"; | |
476 testDifferentActlFrameCountIsIgnored(pngFile, 33u, 2u, 4u); | |
477 testDifferentActlFrameCountIsIgnored(pngFile, 33u, 8u, 4u); | |
478 } | |
479 | |
480 // Originally, the third frame has an offset of (1,2) and a size of (3,2). By | |
481 // changing the offset to (0,0) and the size to (4,4), a frame with not enough | |
482 // data is simulated. The expected result is that the decoder will only receive | |
483 // 1 row of data, since the data contains 6 pixels and each row is 4 pixels. | |
484 // | |
485 // When the decoder receives not enough data for a frame, the expected behavior | |
486 // is that nothing changes: the decoder should not be invalidated, and the | |
487 // frame should be considered successfully decoded. The reason for this is that | |
488 // the error could either be an invalid frame size, or an invalid data chunk. | |
489 // For now, the decoder does not take any action if not enough data is | |
490 // provided, as described in PNGImageDecoder::complete(). | |
491 TEST(AnimatedPNGTests, VerifyIncompleteFrameDataDoesNotInvalidateDecoder) { | |
492 const char* pngFile = | |
493 "/LayoutTests/images/resources/" | |
494 "png-animated-idat-part-of-animation.png"; | |
495 auto data = readFile(pngFile); | |
496 auto decoder = createDecoder(); | |
497 ASSERT_FALSE(data->isEmpty()); | |
498 | |
499 // Change the size and the offset of the frame, as described above. The size | |
500 // is stored in byte 12-19 of the fcTL chunk, and the offset in byte 20-27. | |
501 const size_t offsetThirdFctl = 241 + 12; | |
502 RefPtr<SharedBuffer> modifiedData = | |
503 SharedBuffer::create(data->data(), offsetThirdFctl); | |
504 png_byte rectChunk[16]; | |
505 writeUint32(4, rectChunk); | |
506 writeUint32(4, rectChunk + 4); | |
507 writeUint32(0, rectChunk + 8); | |
508 writeUint32(0, rectChunk + 12); | |
509 modifiedData->append( | |
510 const_cast<const char*>(reinterpret_cast<char*>(rectChunk)), 16u); | |
511 modifiedData->append(data->data() + offsetThirdFctl + 16, | |
512 data->size() - offsetThirdFctl - 16); | |
513 | |
514 decoder->setData(modifiedData, true); | |
515 | |
516 // Verify that parsing the image results in the expected meta data. | |
517 IntSize expectedSize(5, 5); | |
518 const size_t expectedFrameCount = 4; | |
519 IntRect expectedFrameRect(IntPoint(0, 0), IntSize(4, 4)); | |
520 EXPECT_TRUE(decoder->isSizeAvailable()); | |
521 EXPECT_EQ(expectedSize, decoder->size()); | |
522 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
523 ASSERT_FALSE(decoder->failed()); | |
524 | |
525 // Try to decode frame 3. This should not fail the decoder, and the frame | |
526 // should be FrameComplete. | |
527 const ImageFrame* const buffer = decoder->frameBufferAtIndex(2); | |
528 EXPECT_EQ(expectedFrameRect, buffer->originalFrameRect()); | |
529 EXPECT_FALSE(decoder->failed()); | |
530 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
531 EXPECT_EQ(ImageFrame::FrameComplete, buffer->getStatus()); | |
532 } | |
533 | |
534 // Originally, the third frame has an offset of (1,2) and a size of (3,2). By | |
535 // changing the offset to (4,4), the frame rect will extend the image size of | |
536 // 5x5. Verify that the frame is correctly clipped to a size of (1,1) without | |
537 // any decoding errors. Since this is the third frame, a decoding failure would | |
538 // result in the frame count being adjusted to 2, and the decoder would not be | |
539 // invalidated. Therefore, it is verified that after decoding frame 3 the | |
540 // decoder is still in a valid state and the frame count is still 4. | |
541 TEST(AnimatedPNGTests, VerifyFrameExtendsImageSizeClipsCorrectly) { | |
542 const char* pngFile = | |
543 "/LayoutTests/images/resources/" | |
544 "png-animated-idat-part-of-animation.png"; | |
545 auto data = readFile(pngFile); | |
546 auto decoder = createDecoder(); | |
547 ASSERT_FALSE(data->isEmpty()); | |
548 | |
549 // The offset of the frame rect is located 20 bytes into the fcTL chunk, after | |
550 // the length, tag, sequence number, width and height fields (all 4B). | |
551 const size_t offsetThirdFctl = 241 + 20; | |
552 RefPtr<SharedBuffer> modifiedData = | |
553 SharedBuffer::create(data->data(), offsetThirdFctl); | |
554 png_byte offsetChunk[8]; | |
555 writeUint32(4, offsetChunk); | |
556 writeUint32(4, offsetChunk + 4); | |
557 modifiedData->append( | |
558 const_cast<const char*>(reinterpret_cast<char*>(offsetChunk)), 8u); | |
559 modifiedData->append(data->data() + offsetThirdFctl + 8, | |
560 data->size() - offsetThirdFctl - 8); | |
561 | |
562 decoder->setData(modifiedData, true); | |
563 | |
564 // Verify that parsing the image results in the expected meta data. | |
565 IntSize expectedSize(5, 5); | |
566 const size_t expectedFrameCount = 4; | |
567 IntRect expectedFrameRect(IntPoint(4, 4), IntSize(1, 1)); | |
568 EXPECT_TRUE(decoder->isSizeAvailable()); | |
569 EXPECT_EQ(expectedSize, decoder->size()); | |
570 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
571 ASSERT_FALSE(decoder->failed()); | |
572 | |
573 // Try to decode frame 3. This should not fail the decoder, and the frame | |
574 // should be FrameComplete. | |
575 const ImageFrame* const buffer = decoder->frameBufferAtIndex(2); | |
576 EXPECT_EQ(expectedFrameRect, buffer->originalFrameRect()); | |
577 EXPECT_FALSE(decoder->failed()); | |
578 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
579 EXPECT_EQ(ImageFrame::FrameComplete, buffer->getStatus()); | |
580 } | |
581 | |
582 TEST(AnimatedPNGTests, ProgressiveDecodingContinuesAfterFullData) { | |
583 // 160u is a randomly chosen offset in the IDAT chunk of the first frame. | |
584 testProgressiveDecodingContinuesAfterFullData( | |
585 "/LayoutTests/images/resources/" | |
586 "png-animated-idat-part-of-animation.png", | |
587 160u); | |
588 } | |
589 | |
590 TEST(AnimatedPNGTests, RandomDecodeAfterClearFrameBufferCache) { | |
591 testRandomDecodeAfterClearFrameBufferCache( | |
592 &createDecoder, | |
593 "/LayoutTests/images/resources/" | |
594 "png-animated-idat-part-of-animation.png", | |
595 2u); | |
596 } | |
597 | |
598 TEST(AnimatedPNGTests, VerifyAlphaBlending) { | |
599 testAlphaBlending(&createDecoder, | |
600 "/LayoutTests/images/resources/" | |
601 "png-animated-idat-part-of-animation.png"); | |
602 } | |
603 | |
604 // This tests if the frame count gets set correctly when parsing frameCount | |
605 // fails in one of the parsing queries. | |
606 // | |
607 // First, enough data is provided such that two frames should be registered. | |
608 // The decoder should at this point not be in the failed status. | |
609 // | |
610 // Then, we provide the rest of the data except for the last IEND chunk, but | |
611 // tell the decoder that this is all the data we have. The frame count should | |
612 // be three, since one extra frame should be discovered. The fourth frame | |
613 // should *not* be registered since the reader should not be able to determine | |
614 // where the frame ends. The decoder should *not* be in the failed state since | |
615 // there are three frames which can be shown. | |
616 TEST(AnimatedPNGTests, FailureMissingIendChunk) { | |
617 RefPtr<SharedBuffer> fullData = readFile( | |
618 "/LayoutTests/images/resources/" | |
619 "png-animated-idat-part-of-animation.png"); | |
620 ASSERT_FALSE(fullData->isEmpty()); | |
621 auto decoder = createDecoder(); | |
622 | |
623 const size_t offsetTwoFrames = 249; | |
624 const size_t expectedFramesAfter249Bytes = 2; | |
625 RefPtr<SharedBuffer> tempData = | |
626 SharedBuffer::create(fullData->data(), offsetTwoFrames); | |
627 decoder->setData(tempData.get(), false); | |
628 EXPECT_EQ(expectedFramesAfter249Bytes, decoder->frameCount()); | |
629 EXPECT_FALSE(decoder->failed()); | |
630 | |
631 // Provide the rest of the data except for the last IEND chunk. | |
632 const size_t expectedFramesAfterAllExpect12Bytes = 3; | |
633 tempData = SharedBuffer::create(fullData->data(), fullData->size() - 12); | |
634 decoder->setData(tempData.get(), true); | |
635 EXPECT_EQ(expectedFramesAfterAllExpect12Bytes, decoder->frameCount()); | |
636 EXPECT_FALSE(decoder->failed()); | |
637 } | |
638 | |
639 TEST(AnimatedPNGTests, VerifyFrameCountChangesOnDecodingFailure) { | |
640 testFailureDuringDecode( | |
641 "/LayoutTests/images/resources/" | |
642 "png-animated-idat-part-of-animation.png", | |
643 279u, // idat offset for frame index 2 | |
644 2u, // try to decode frame index 2 | |
645 false, // expect the decoder to *not* be invalidated after the failure | |
646 4u, // expected frame count before failure | |
647 2u); // expected frame count after failure | |
648 | |
649 testFailureDuringDecode( | |
650 "/LayoutTests/images/resources/" | |
651 "png-animated-idat-part-of-animation.png", | |
652 133u, // idat offset for frame index 0 | |
653 0u, // try to decode frame index 0 | |
654 true, // expect the decoder to be invalidated after the failure | |
655 4u); // expected frame count before failure | |
656 } | |
657 | |
658 // Verify that a malformatted PNG, where the IEND appears before any frame data | |
659 // (IDAT), invalidates the decoder. | |
660 TEST(AnimatedPNGTests, VerifyIENDBeforeIDATInvalidatesDecoder) { | |
661 RefPtr<SharedBuffer> fullData = readFile( | |
662 "/LayoutTests/images/resources/" | |
663 "png-animated-idat-part-of-animation.png"); | |
664 ASSERT_FALSE(fullData->isEmpty()); | |
665 auto decoder = createDecoder(); | |
666 | |
667 const size_t offsetIDAT = 133; | |
668 RefPtr<SharedBuffer> data = | |
669 SharedBuffer::create(fullData->data(), offsetIDAT); | |
670 data->append(fullData->data() + fullData->size() - 12u, 12u); | |
671 data->append(fullData->data() + offsetIDAT, fullData->size() - offsetIDAT); | |
672 decoder->setData(data.get(), true); | |
673 | |
674 const size_t expectedFrameCount = 0u; | |
675 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
676 EXPECT_TRUE(decoder->failed()); | |
677 } | |
678 | |
679 // For animated images, frameIsCompleteAtIndex(i) should return true if the | |
680 // i-th frame is fully received. The frames don't need to be successfully | |
681 // decoded. | |
682 TEST(AnimatedPNGTests, VerifyFrameCompleteBehavior) { | |
683 const char* pngFile = | |
684 "/LayoutTests/images/resources/" | |
685 "png-animated-idat-part-of-animation.png"; | |
686 RefPtr<SharedBuffer> fullData = readFile(pngFile); | |
687 ASSERT_FALSE(fullData->isEmpty()); | |
688 auto decoder = createDecoder(); | |
689 | |
690 // When not all data for the first frame has been received, | |
691 // frameIsCompleteAtIndex(0) should return false. | |
692 const size_t offsetMidwayFirstFrame = 160; | |
693 RefPtr<SharedBuffer> data = | |
694 SharedBuffer::create(fullData->data(), offsetMidwayFirstFrame); | |
695 decoder->setData(data.get(), false); | |
696 EXPECT_EQ(1u, decoder->frameCount()); | |
697 ASSERT_FALSE(decoder->failed()); | |
698 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0)); | |
699 | |
700 // When all image data is received, every frame should be complete. | |
701 const size_t expectedFrameCount = 4; | |
702 decoder->setData(fullData.get(), true); | |
703 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
704 for (size_t index = 0; index < expectedFrameCount; index++) | |
705 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(index)); | |
706 } | |
707 | |
708 // Verify that erroneous values for the disposal method and alpha blending | |
709 // are parsed into the expected default values, respectively DisposeNotSpecified | |
710 // and BlendAtopBgcolor. | |
711 TEST(AnimatedPNGTests, VerifyInvalidDisposalAndBlendingDefaultCorrectly) { | |
712 const char* pngFile = | |
713 "/LayoutTests/images/resources/" | |
714 "png-animated-idat-part-of-animation.png"; | |
715 RefPtr<SharedBuffer> fullData = readFile(pngFile); | |
716 ASSERT_FALSE(fullData->isEmpty()); | |
717 auto decoder = createDecoder(); | |
718 | |
719 // The disposal byte in the frame control chunk is the 24th byte, alpha | |
720 // blending the 25th. |offsetDisposalOp| is 241 bytes to get to the third | |
721 // fctl chunk, 8 bytes to skip the length and tag bytes, and 24 bytes to get | |
722 // to the disposal op. | |
723 // | |
724 // Write random values to the disposal and alpha blending byte, and append | |
725 // the rest of the buffer. | |
726 const size_t offsetDisposalOp = 241 + 8 + 24; | |
727 RefPtr<SharedBuffer> data = | |
728 SharedBuffer::create(fullData->data(), offsetDisposalOp); | |
729 png_byte disposalAndBlending[2]; | |
730 disposalAndBlending[0] = 7; | |
731 disposalAndBlending[1] = 9; | |
732 data->append(reinterpret_cast<char*>(disposalAndBlending), 2u); | |
733 data->append(fullData->data() + offsetDisposalOp + 2u, | |
734 fullData->size() - offsetDisposalOp - 2u); | |
735 | |
736 decoder->setData(data.get(), true); | |
737 decoder->frameCount(); | |
738 ASSERT_FALSE(decoder->failed()); | |
739 EXPECT_EQ(ImageFrame::DisposalMethod::DisposeNotSpecified, | |
740 decoder->frameBufferAtIndex(2)->getDisposalMethod()); | |
741 EXPECT_EQ(ImageFrame::AlphaBlendSource::BlendAtopBgcolor, | |
742 decoder->frameBufferAtIndex(2)->getAlphaBlendSource()); | |
743 } | |
744 | |
745 // This test verifies that the following situation does not invalidate the | |
746 // decoder: | |
747 // - Frame 0 is decoded progressively, but there's not enough data to fully | |
748 // decode it. | |
749 // - The rest of the image data is received. | |
750 // - Frame X, with X > 0, and X does not depend on frame 0, is decoded. | |
751 // - Frame 0 is decoded. | |
752 // This is a tricky case since the decoder resets the png struct for each frame, | |
753 // and this test verifies that it does not break the decoding of frame 0, even | |
754 // though it already started in the first call. | |
755 TEST(AnimatedPNGTests, VerifySuccessfulFirstFrameDecodeAfterLaterFrame) { | |
756 const char* pngFile = | |
757 "/LayoutTests/images/resources/" | |
758 "png-animated-three-independent-frames.png"; | |
759 auto decoder = createDecoder(); | |
760 auto fullData = readFile(pngFile); | |
761 ASSERT_FALSE(fullData->isEmpty()); | |
762 | |
763 // 160u is a randomly chosen offset in the IDAT chunk of the first frame. | |
764 const size_t middleFirstFrame = 160u; | |
765 RefPtr<SharedBuffer> data = | |
766 SharedBuffer::create(fullData->data(), middleFirstFrame); | |
767 decoder->setData(data.get(), false); | |
768 | |
769 ASSERT_EQ(1u, decoder->frameCount()); | |
770 ImageFrame* frame0 = decoder->frameBufferAtIndex(0); | |
scroggo_chromium
2016/12/14 14:18:06
nit: Now that you do not hang onto frame0 (was tha
joostouwerling
2016/12/16 19:59:32
Done, and yes -- frame 0 was used later on, after
| |
771 ASSERT_EQ(ImageFrame::FramePartial, frame0->getStatus()); | |
772 | |
773 decoder->setData(fullData.get(), true); | |
774 ASSERT_EQ(3u, decoder->frameCount()); | |
775 ASSERT_EQ(ImageFrame::FrameComplete, | |
776 decoder->frameBufferAtIndex(1)->getStatus()); | |
777 ASSERT_EQ(kNotFound, | |
scroggo_chromium
2016/12/14 14:18:06
Maybe a comment here that the point is that this d
joostouwerling
2016/12/16 19:59:32
Done.
| |
778 decoder->frameBufferAtIndex(1)->requiredPreviousFrameIndex()); | |
779 | |
780 EXPECT_EQ(ImageFrame::FrameComplete, | |
781 decoder->frameBufferAtIndex(0)->getStatus()); | |
782 EXPECT_FALSE(decoder->failed()); | |
783 } | |
784 | |
127 // Static PNG tests | 785 // Static PNG tests |
128 | 786 |
129 TEST(StaticPNGTests, repetitionCountTest) { | 787 TEST(StaticPNGTests, repetitionCountTest) { |
130 testRepetitionCount("/LayoutTests/images/resources/png-simple.png", | 788 testRepetitionCount("/LayoutTests/images/resources/png-simple.png", |
131 cAnimationNone); | 789 cAnimationNone); |
132 } | 790 } |
133 | 791 |
134 TEST(StaticPNGTests, sizeTest) { | 792 TEST(StaticPNGTests, sizeTest) { |
135 testSize("/LayoutTests/images/resources/png-simple.png", IntSize(111, 29)); | 793 testSize("/LayoutTests/images/resources/png-simple.png", IntSize(111, 29)); |
136 } | 794 } |
137 | 795 |
138 TEST(StaticPNGTests, MetaDataTest) { | 796 TEST(StaticPNGTests, MetaDataTest) { |
139 const size_t expectedFrameCount = 1; | 797 const size_t expectedFrameCount = 1; |
140 const size_t expectedDuration = 0; | 798 const size_t expectedDuration = 0; |
141 auto decoder = | 799 auto decoder = |
142 createDecoderWithPngData("/LayoutTests/images/resources/png-simple.png"); | 800 createDecoderWithPngData("/LayoutTests/images/resources/png-simple.png"); |
143 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | 801 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); |
144 EXPECT_EQ(expectedDuration, decoder->frameDurationAtIndex(0)); | 802 EXPECT_EQ(expectedDuration, decoder->frameDurationAtIndex(0)); |
145 } | 803 } |
146 | 804 |
805 TEST(StaticPNGTests, InvalidIHDRChunk) { | |
806 testMissingDataBreaksDecoding("/LayoutTests/images/resources/png-simple.png", | |
807 20u, 2u); | |
808 } | |
809 | |
147 TEST(StaticPNGTests, ProgressiveDecoding) { | 810 TEST(StaticPNGTests, ProgressiveDecoding) { |
148 testProgressiveDecoding(&createDecoder, | 811 testProgressiveDecoding(&createDecoder, |
149 "/LayoutTests/images/resources/png-simple.png", 11u); | 812 "/LayoutTests/images/resources/png-simple.png", 11u); |
150 } | 813 } |
151 | 814 |
152 TEST(StaticPNGTests, ProgressiveDecodingContinuesAfterFullData) { | 815 TEST(StaticPNGTests, ProgressiveDecodingContinuesAfterFullData) { |
153 testProgressiveDecodingContinuesAfterFullData( | 816 testProgressiveDecodingContinuesAfterFullData( |
154 "/LayoutTests/images/resources/png-simple.png", 1000u); | 817 "/LayoutTests/images/resources/png-simple.png", 1000u); |
155 } | 818 } |
156 | 819 |
(...skipping 12 matching lines...) Expand all Loading... | |
169 auto decoder = | 832 auto decoder = |
170 createDecoderWithPngData("/LayoutTests/images/resources/png-simple.png"); | 833 createDecoderWithPngData("/LayoutTests/images/resources/png-simple.png"); |
171 EXPECT_EQ(1u, decoder->frameCount()); | 834 EXPECT_EQ(1u, decoder->frameCount()); |
172 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0)); | 835 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0)); |
173 EXPECT_EQ(ImageFrame::FrameComplete, | 836 EXPECT_EQ(ImageFrame::FrameComplete, |
174 decoder->frameBufferAtIndex(0)->getStatus()); | 837 decoder->frameBufferAtIndex(0)->getStatus()); |
175 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | 838 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); |
176 } | 839 } |
177 | 840 |
178 }; // namespace blink | 841 }; // namespace blink |
OLD | NEW |