Chromium Code Reviews| 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(injectedFrameCount != expectedFrameCount); | |
|
scroggo_chromium
2016/10/26 18:25:58
Sorry, I meant
ASSERT_NE(injectedFrameCount, ex
scroggo_chromium
2016/10/28 14:20:32
(It is helpful if you respond to comments that rec
joostouwerling
2016/10/28 18:41:25
Acknowledged.
| |
| 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 = 10; | |
| 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 } // Anonymous namespace | |
| 253 | |
| 254 // Animated PNG Tests | |
| 255 | |
| 256 TEST(AnimatedPNGTests, sizeTest) | |
| 257 { | |
| 258 testSize("/LayoutTests/fast/images/resources/png-animated-idat-part-of-anima tion.png", IntSize(5, 5)); | |
| 259 testSize("/LayoutTests/fast/images/resources/png-animated-idat-not-part-of-a nimation.png", IntSize(227, 35)); | |
| 260 } | |
| 261 | |
| 262 TEST(AnimatedPNGTests, repetitionCountTest) | |
| 263 { | |
| 264 testRepetitionCount("/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png", 7u); | |
| 265 // This is an "animated" image with only one frame, that is, the IDAT is | |
| 266 // ignored and there is one fdAT frame. so it should be considered | |
| 267 // non-animated. | |
| 268 testRepetitionCount("/LayoutTests/fast/images/resources/png-animated-idat-no t-part-of-animation.png", cAnimationNone); | |
| 269 } | |
| 270 | |
| 271 // Test if the decoded metdata corresponds to the defined expectations | |
| 272 TEST(AnimatedPNGTests, MetaDataTest) | |
| 273 { | |
| 274 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat- part-of-animation.png"; | |
| 275 constexpr size_t expectedFrameCount = 4; | |
| 276 | |
| 277 auto decoder = createDecoderWithPngData(pngFile); | |
| 278 ASSERT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 279 for (size_t i = 0; i < expectedFrameCount; i++) | |
| 280 compareFrameWithExpectation(pngAnimatedFrameInfo[i], | |
| 281 decoder->frameBufferAtIndex(i)); | |
| 282 } | |
| 283 | |
| 284 TEST(AnimatedPNGTests, ByteByByteSizeAvailable) | |
| 285 { | |
| 286 testSizeByteByByte("/LayoutTests/fast/images/resources/png-animated-idat-par t-of-animation.png", | |
| 287 141u, IntSize(5, 5)); | |
| 288 testSizeByteByByte("/LayoutTests/fast/images/resources/png-animated-idat-not -part-of-animation.png", | |
| 289 79u, IntSize(227, 35)); | |
| 290 } | |
| 291 | |
| 292 // Test whether the frame metadata decoding also works when we provide the data | |
| 293 // byte by byte. This should cover the case when the client does not provide | |
| 294 // all data at once. At given offsets, we expect frames to become available. | |
| 295 // This test checks whether that is the case, and if so, if the frame data is | |
| 296 // equal to what we expected. | |
| 297 TEST(AnimatedPNGTests, ByteByByteMetaData) | |
| 298 { | |
| 299 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat- part-of-animation.png"; | |
| 300 constexpr size_t expectedFrameCount = 4; | |
| 301 | |
| 302 // These are the byte offsets where each frame should have been parsed. | |
| 303 // It boils down to the offset of the first fcTL / IEND after the last | |
| 304 // frame data chunk, plus 8 bytes for recognition. | |
| 305 size_t frameOffsets[expectedFrameCount] = {180, 249, 322, 430}; | |
| 306 | |
| 307 auto decoder = createDecoder(); | |
| 308 auto data = readFile(pngFile); | |
| 309 ASSERT_FALSE(data->isEmpty()); | |
| 310 size_t framesParsed = 0; | |
| 311 | |
| 312 for (size_t length = 1; length <= frameOffsets[expectedFrameCount - 1]; leng th++) { | |
| 313 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), | |
| 314 length); | |
| 315 decoder->setData(tempData.get(), false); | |
| 316 EXPECT_FALSE(decoder->failed()); | |
| 317 if (length < frameOffsets[framesParsed]) { | |
| 318 EXPECT_EQ(framesParsed, decoder->frameCount()); | |
| 319 } else { | |
| 320 ASSERT_EQ(framesParsed + 1, decoder->frameCount()); | |
| 321 compareFrameWithExpectation(pngAnimatedFrameInfo[framesParsed], | |
| 322 decoder->frameBufferAtIndex(framesParsed )); | |
| 323 framesParsed++; | |
| 324 } | |
| 325 } | |
| 326 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 327 EXPECT_FALSE(decoder->failed()); | |
| 328 } | |
| 329 | |
| 330 // This tests if the frame count gets set correctly when parsing frameCount | |
| 331 // fails in one of the parsing queries. | |
| 332 // | |
| 333 // First, enough data is provided such that two frames should be registered. | |
| 334 // The decoder should at this point not be in the failed status. | |
| 335 // | |
| 336 // Then, we provide the rest of the data except for the last IEND chunk, but | |
| 337 // tell the decoder that this is all the data we have. Now, the decoder should | |
| 338 // be in the failed state since all data is provided but no IEND chunk has been | |
| 339 // seen. The frame count should be three, since one extra frame should be | |
| 340 // discovered. The fourth frame should *not* be registered since the reader | |
| 341 // should not be able to determine where the frame ends. | |
| 342 TEST(AnimatedPNGTests, FrameCountWithTruncatedData) | |
| 343 { | |
| 344 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat- part-of-animation.png"; | |
| 345 auto decoder = createDecoder(); | |
| 346 auto data = readFile(pngFile); | |
| 347 ASSERT_FALSE(data->isEmpty()); | |
| 348 | |
| 349 // Parse up to and including the first two frames | |
| 350 const size_t offsetTwoFrames = 249; | |
| 351 const size_t expectedFramesAfter249Bytes = 2; | |
| 352 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), | |
| 353 offsetTwoFrames); | |
| 354 decoder->setData(tempData.get(), false); | |
| 355 EXPECT_EQ(expectedFramesAfter249Bytes, decoder->frameCount()); | |
| 356 EXPECT_FALSE(decoder->failed()); | |
| 357 | |
| 358 // Provide the rest of the data except for the last IEND chunk. | |
| 359 const size_t expectedFramesAfterAllExpect12Bytes = 3; | |
| 360 tempData = SharedBuffer::create(data->data(), data->size() - 12); | |
| 361 decoder->setData(tempData.get(), true); | |
| 362 EXPECT_EQ(expectedFramesAfterAllExpect12Bytes, decoder->frameCount()); | |
| 363 EXPECT_TRUE(decoder->failed()); | |
| 364 } | |
| 365 | |
| 366 TEST(AnimatedPNGTests, TestRandomFrameDecode) | |
| 367 { | |
| 368 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources /png-animated-idat-part-of-animation.png"); | |
| 369 ASSERT_TRUE(fullData.get()); | |
| 370 Vector<unsigned> baselineHashes; | |
| 371 createDecodingBaseline(&createDecoder, fullData.get(), &baselineHashes); | |
| 372 size_t frameCount = baselineHashes.size(); | |
| 373 | |
| 374 // Random decoding should get the same results as sequential decoding. | |
| 375 std::unique_ptr<ImageDecoder> decoder = createDecoder(); | |
| 376 decoder->setData(fullData.get(), true); | |
| 377 const size_t skippingStep = 2; | |
| 378 for (size_t i = 0; i < skippingStep; ++i) { | |
| 379 for (size_t j = i; j < frameCount; j += skippingStep) { | |
| 380 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j); | |
| 381 ImageFrame* frame = decoder->frameBufferAtIndex(j); | |
| 382 EXPECT_EQ(baselineHashes[j], hashBitmap(frame->bitmap())); | |
| 383 } | |
| 384 } | |
| 385 | |
| 386 // Decoding in reverse order. | |
| 387 decoder = createDecoder(); | |
| 388 decoder->setData(fullData.get(), true); | |
| 389 for (size_t i = frameCount; i; --i) { | |
| 390 SCOPED_TRACE(testing::Message() << "Reverse i:" << i); | |
| 391 ImageFrame* frame = decoder->frameBufferAtIndex(i - 1); | |
| 392 EXPECT_EQ(baselineHashes[i - 1], hashBitmap(frame->bitmap())); | |
| 393 } | |
| 394 | |
| 395 } | |
| 396 | |
| 397 TEST(AnimatedPNGTests, TestDecodeAfterReallocation) | |
| 398 { | |
| 399 std::unique_ptr<ImageDecoder> decoder = createDecoder(); | |
| 400 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/png -animated-idat-part-of-animation.png"); | |
| 401 ASSERT_TRUE(data.get()); | |
| 402 | |
| 403 // Parse from |data|. | |
| 404 decoder->setData(data.get(), true); | |
| 405 size_t frameCount = decoder->frameCount(); | |
| 406 | |
| 407 // ... and then decode frames from |reallocatedData|. | |
| 408 RefPtr<SharedBuffer> reallocatedData = data.get()->copy(); | |
| 409 ASSERT_TRUE(reallocatedData.get()); | |
| 410 data.clear(); | |
| 411 decoder->setData(reallocatedData.get(), true); | |
| 412 | |
| 413 for (size_t i = 0; i < frameCount; ++i) { | |
| 414 const ImageFrame* const frame = decoder->frameBufferAtIndex(i); | |
| 415 EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus()); | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 TEST(AnimatedPNGTests, ProgressiveDecode) | |
| 420 { | |
| 421 testProgressiveDecoding("/LayoutTests/fast/images/resources/png-animated-ida t-part-of-animation.png"); | |
| 422 } | |
| 423 | |
| 424 TEST(AnimatedPNGTests, ParseAndDecodeByteByByte) | |
| 425 { | |
| 426 testByteByByteDecode(&createDecoder, | |
| 427 "/LayoutTests/fast/images/resources/png-animated-idat-p art-of-animation.png", | |
| 428 4u, 7u); | |
| 429 } | |
| 430 | |
| 431 TEST(AnimatedPNGTests, FctlWrongSizeBreaksDecoding) | |
| 432 { | |
| 433 const char* pngFile = "//LayoutTests/fast/images/resources/png-animated-idat -part-of-animation.png"; | |
| 434 auto data = readFile(pngFile); | |
| 435 ASSERT_FALSE(data->isEmpty()); | |
| 436 | |
| 437 // Test the first fcTL in the stream. Because no frame data has been set | |
| 438 // at this point, the expected frame count is zero. | |
| 439 testInvalidFctlSize("//LayoutTests/fast/images/resources/png-animated-idat-p art-of-animation.png", | |
| 440 95u, 0u); | |
| 441 | |
| 442 // Test for the third fcTL in the stream. This should be tested as well, | |
| 443 // since the first fcTL is parsed in PNGImageReader::parseSize() whereas | |
| 444 // later fcTLs are parsed in PNGImageReader::parse() as part of framecount. | |
| 445 // The expected frame count before the fcTL chunk is 1u, since the second | |
| 446 // frame is registered when the third fcTL (or IEND) is seen. | |
| 447 testInvalidFctlSize("//LayoutTests/fast/images/resources/png-animated-idat-p art-of-animation.png", | |
| 448 241u, 1u); | |
| 449 | |
| 450 } | |
| 451 | |
| 452 TEST(AnimatedPNGTests, MissingFctlDataBreaksDecoding) | |
| 453 { | |
| 454 // The fcTL chunk starts at 95u, add 10u to get to the content data, and | |
| 455 // remove 5 bytes of data. | |
| 456 testMissingDataBreaksDecoding( | |
| 457 "//LayoutTests/fast/images/resources/png-animated-idat-part-of-animation .png", | |
| 458 105u, 5u); | |
| 459 } | |
| 460 | |
| 461 TEST(AnimatedPNGTests, MissingActlResultsInNonAnimated) | |
| 462 { | |
| 463 const char* pngFile = "//LayoutTests/fast/images/resources/png-animated-idat -part-of-animation.png"; | |
| 464 auto data = readFile(pngFile); | |
| 465 auto decoder = createDecoder(); | |
| 466 ASSERT_FALSE(data->isEmpty()); | |
| 467 | |
| 468 // Remove the acTL chunk from the stream. | |
| 469 size_t offsetActl = 33; | |
| 470 RefPtr<SharedBuffer> noActlData = SharedBuffer::create(data->data(), | |
| 471 offsetActl); | |
| 472 noActlData->append(data->data() + offsetActl + 20, | |
| 473 data->size() - offsetActl - 20); | |
| 474 | |
| 475 decoder->setData(noActlData, true); | |
| 476 EXPECT_EQ(1u, decoder->frameCount()); | |
| 477 EXPECT_FALSE(decoder->failed()); | |
| 478 } | |
| 479 | |
| 480 // Test if the indicated frame count by the acTL is ignored if the actual | |
| 481 // number of frames is different. Test for higher and lower indicated number. | |
| 482 TEST(AnimatedPNGTests, differentActlFrameCountIsIgnored) | |
| 483 { | |
| 484 const char* pngFile = "//LayoutTests/fast/images/resources/png-animated-idat -part-of-animation.png"; | |
| 485 testDifferentActlFrameCountIsIgnored(pngFile, 33u, 2u, 4u); | |
| 486 testDifferentActlFrameCountIsIgnored(pngFile, 33u, 8u, 4u); | |
| 487 } | |
| 488 | |
| 489 // Check if a frame rectangle, that is larger than the image width, gets | |
| 490 // clipped correctly. | |
| 491 TEST(AnimatedPNGTests, frameRectIsClipped) | |
| 492 { | |
| 493 const char* pngFile = "//LayoutTests/fast/images/resources/png-animated-idat -part-of-animation.png"; | |
| 494 auto data = readFile(pngFile); | |
| 495 auto decoder = createDecoder(); | |
| 496 ASSERT_FALSE(data->isEmpty()); | |
| 497 | |
| 498 // Change the width and height of the frame so it falls outside the image. | |
|
scroggo_chromium
2016/10/26 18:25:58
I don't think this is a realistic test. Although y
scroggo_chromium
2016/10/28 14:20:32
Maybe it's silly of me to say "this is what a brok
joostouwerling
2016/10/28 18:41:25
I don't completely understand what you mean with "
scroggo_chromium
2016/10/31 13:35:11
My original comment was that I would expect a brok
joostouwerling
2016/10/31 18:40:19
I could not find any explicit tests for corrupt PN
| |
| 499 size_t offsetThirdFctl = 241 + 12; | |
| 500 RefPtr<SharedBuffer> modifiedData = SharedBuffer::create(data->data(), | |
| 501 offsetThirdFctl); | |
| 502 png_byte sizeChunk[8]; | |
| 503 writeUint32(10, sizeChunk); | |
| 504 writeUint32(15, sizeChunk + 4); | |
| 505 modifiedData->append(const_cast<const char*>( | |
| 506 reinterpret_cast<char*>(sizeChunk)), 8u); | |
| 507 modifiedData->append(data->data() + offsetThirdFctl + 8, | |
| 508 data->size() - offsetThirdFctl - 8); | |
| 509 | |
| 510 decoder->setData(modifiedData, true); | |
| 511 | |
| 512 IntSize expectedSize(5, 5); | |
| 513 size_t expectedFrameCount = 4; | |
| 514 IntRect expectedFrameRect(IntPoint(1, 2), IntSize(4, 3)); | |
| 515 | |
| 516 EXPECT_TRUE(decoder->isSizeAvailable()); | |
| 517 EXPECT_EQ(expectedSize, decoder->size()); | |
| 518 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 519 ASSERT_FALSE(decoder->failed()); | |
| 520 EXPECT_EQ(expectedFrameRect, | |
| 521 decoder->frameBufferAtIndex(2)->originalFrameRect()); | |
| 522 | |
| 523 } | |
| 524 | |
| 525 // Static PNG tests | |
| 526 | |
| 527 TEST(StaticPNGTests, repetitionCountTest) | |
| 528 { | |
| 529 testRepetitionCount("/LayoutTests/fast/images/resources/png-simple.png", | |
| 530 cAnimationNone); | |
| 531 } | |
| 532 | |
| 533 TEST(StaticPNGTests, sizeTest) | |
| 534 { | |
| 535 testSize("/LayoutTests/fast/images/resources/png-simple.png", | |
| 536 IntSize(111, 29)); | |
| 537 } | |
| 538 | |
| 539 TEST(StaticPNGTests, MetaDataTest) | |
| 540 { | |
| 541 const size_t expectedFrameCount = 1; | |
| 542 const size_t expectedDuration = 0; | |
| 543 auto decoder = createDecoderWithPngData("/LayoutTests/fast/images/resources/ png-simple.png"); | |
| 544 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 545 EXPECT_EQ(expectedDuration, decoder->frameDurationAtIndex(0)); | |
| 546 } | |
| 547 | |
| 548 // This test removes two random byets from the IHDR chunk. The decoder should | |
| 549 // fail on this since all IHDR data is necessary to decode a PNG image. | |
| 550 TEST(StaticPNGTests, InvalidIHDRChunk) | |
| 551 { | |
| 552 testMissingDataBreaksDecoding( | |
| 553 "//LayoutTests/fast/images/resources/png-simple.png", 20u, 2u); | |
| 554 } | |
| 555 | |
| 556 TEST(StaticPNGTests, ProgressiveDecoding) | |
| 557 { | |
| 558 testProgressiveDecoding("/LayoutTests/fast/images/resources/png-simple.png") ; | |
| 559 } | |
| 560 | |
| 561 }; // namespace blink | |
| OLD | NEW |