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