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 // The image /LT/f/i/r/png-animated-idat-part-of-animation.png is modified in | |
| 13 // multiple tests to simulate erroneous PNGs. As a reference, the table below | |
| 14 // 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 | |
| 33 namespace blink { | |
| 34 | |
| 35 namespace { | |
| 36 | |
| 37 std::unique_ptr<ImageDecoder> createDecoder(ImageDecoder::AlphaOption alphaOptio n) | |
| 38 { | |
| 39 return wrapUnique(new PNGImageDecoder(alphaOption, | |
| 40 ImageDecoder::ColorSpaceApplied, | |
| 41 ImageDecoder::noDecodedImageByteLimit)); | |
| 42 } | |
| 43 | |
| 44 std::unique_ptr<ImageDecoder> createDecoder() | |
| 45 { | |
| 46 return createDecoder(ImageDecoder::AlphaNotPremultiplied); | |
| 47 } | |
| 48 | |
| 49 std::unique_ptr<ImageDecoder> createDecoderWithPngData(const char* pngFile) | |
| 50 { | |
| 51 auto decoder = createDecoder(); | |
| 52 auto data = readFile(pngFile); | |
| 53 EXPECT_FALSE(data->isEmpty()); | |
| 54 decoder->setData(data.get(), true); | |
| 55 return decoder; | |
| 56 } | |
| 57 | |
| 58 void testSize(const char* pngFile, IntSize expectedSize) | |
| 59 { | |
| 60 auto decoder = createDecoderWithPngData(pngFile); | |
| 61 EXPECT_TRUE(decoder->isSizeAvailable()); | |
| 62 EXPECT_EQ(expectedSize, decoder->size()); | |
| 63 } | |
| 64 | |
| 65 void writeUint32(uint32_t val, png_byte* data) | |
| 66 { | |
| 67 data[0] = val >> 24; | |
| 68 data[1] = val >> 16; | |
| 69 data[2] = val >> 8; | |
| 70 data[3] = val; | |
| 71 } | |
| 72 | |
| 73 void testRepetitionCount(const char* pngFile, int expectedRepetitionCount) | |
| 74 { | |
| 75 auto decoder = createDecoderWithPngData(pngFile); | |
| 76 // Decode frame count should see the number of repetitions as well. | |
| 77 decoder->frameCount(); | |
| 78 EXPECT_FALSE(decoder->failed()); | |
| 79 EXPECT_EQ(expectedRepetitionCount, decoder->repetitionCount()); | |
| 80 } | |
| 81 | |
| 82 // Test whether querying for the size of the image works if we present the | |
| 83 // data byte by byte. | |
| 84 void testSizeByteByByte(const char *pngFile, size_t bytesNeededToDecodeSize, | |
| 85 IntSize expectedSize) | |
| 86 { | |
| 87 auto decoder = createDecoder(); | |
| 88 auto data = readFile(pngFile); | |
| 89 ASSERT_FALSE(data->isEmpty()); | |
| 90 ASSERT_LT(bytesNeededToDecodeSize, data->size()); | |
| 91 | |
| 92 for (size_t length = 1; length <= bytesNeededToDecodeSize; length++) { | |
| 93 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), | |
| 94 length); | |
| 95 decoder->setData(tempData.get(), false); | |
| 96 | |
| 97 if (length < bytesNeededToDecodeSize) { | |
| 98 EXPECT_FALSE(decoder->isSizeAvailable()); | |
| 99 EXPECT_TRUE(decoder->size().isEmpty()); | |
| 100 EXPECT_FALSE(decoder->failed()); | |
| 101 } else { | |
| 102 EXPECT_TRUE(decoder->isSizeAvailable()); | |
| 103 EXPECT_EQ(expectedSize, decoder->size()); | |
| 104 } | |
| 105 } | |
| 106 EXPECT_FALSE(decoder->failed()); | |
| 107 } | |
| 108 | |
| 109 struct PublicFrameInfo { | |
| 110 size_t duration; | |
| 111 IntRect frameRect; | |
| 112 ImageFrame::AlphaBlendSource alphaBlend; | |
| 113 ImageFrame::DisposalMethod disposalMethod; | |
| 114 }; | |
| 115 | |
| 116 // This is the frame data for the following PNG image: | |
| 117 // /LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png | |
| 118 static PublicFrameInfo pngAnimatedFrameInfo[] = { | |
| 119 {500, {IntPoint(0, 0), IntSize(5, 5)}, ImageFrame::BlendAtopBgcolor, | |
| 120 ImageFrame::DisposeKeep}, | |
| 121 {900, {IntPoint(1, 1), IntSize(3, 1)}, ImageFrame::BlendAtopBgcolor, | |
| 122 ImageFrame::DisposeOverwriteBgcolor}, | |
| 123 {2000, {IntPoint(1, 2), IntSize(3, 2)}, ImageFrame::BlendAtopPreviousFrame, | |
| 124 ImageFrame::DisposeKeep}, | |
| 125 {1500, {IntPoint(1, 2), IntSize(3, 1)}, ImageFrame::BlendAtopBgcolor, | |
| 126 ImageFrame::DisposeKeep}, | |
| 127 }; | |
| 128 | |
| 129 void compareFrameWithExpectation(const PublicFrameInfo& expected, | |
| 130 const ImageFrame* frame) | |
| 131 { | |
| 132 EXPECT_EQ(expected.duration, frame->duration()); | |
| 133 EXPECT_EQ(expected.frameRect, frame->originalFrameRect()); | |
| 134 EXPECT_EQ(expected.disposalMethod, frame->getDisposalMethod()); | |
| 135 EXPECT_EQ(expected.alphaBlend, frame->getAlphaBlendSource()); | |
| 136 } | |
| 137 | |
| 138 // This function removes |length| bytes at |offset|, and then calls frameCount. | |
| 139 // It assumes the missing bytes should result in a failed decode because the | |
| 140 // parser jumps |length| bytes too far in the next chunk. | |
| 141 void testMissingDataBreaksDecoding(const char* pngFile, size_t offset, | |
| 142 size_t length) | |
| 143 { | |
| 144 auto decoder = createDecoder(); | |
| 145 auto data = readFile(pngFile); | |
| 146 ASSERT_FALSE(data->isEmpty()); | |
| 147 | |
| 148 RefPtr<SharedBuffer> invalidData = SharedBuffer::create(data->data(), | |
| 149 offset); | |
| 150 invalidData->append(SharedBuffer::create(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 { | |
| 166 auto data = readFile(pngFile); | |
| 167 ASSERT_FALSE(data->isEmpty()); | |
| 168 | |
| 169 auto decoder = createDecoder(); | |
| 170 RefPtr<SharedBuffer> invalidData = SharedBuffer::create(data->data(), | |
| 171 offsetFctl); | |
| 172 | |
| 173 // Test if this gives the correct frame count, before the fcTL is parsed. | |
| 174 decoder->setData(invalidData, false); | |
| 175 EXPECT_EQ(expectedFrameCountBeforeFail, decoder->frameCount()); | |
| 176 ASSERT_FALSE(decoder->failed()); | |
| 177 | |
| 178 // Append the wrong size to the data stream | |
| 179 png_byte sizeChunk[4]; | |
| 180 writeUint32(20, sizeChunk); | |
| 181 invalidData->append(reinterpret_cast<char*>(sizeChunk), 4u); | |
| 182 | |
| 183 // Skip the size in the original data, but provide the rest of the fcTL, | |
| 184 // which is 4B of tag, 26B of data and 4B of CRC, totalling 34B. | |
| 185 invalidData->append(data->data() + offsetFctl + 4, 34u); | |
| 186 | |
| 187 decoder->setData(invalidData, false); | |
| 188 decoder->frameCount(); | |
| 189 EXPECT_EQ(expectedDecoderFailure, decoder->failed()); | |
| 190 } | |
| 191 | |
| 192 void testDifferentActlFrameCountIsIgnored(const char* pngFile, | |
| 193 size_t offsetActl, | |
| 194 size_t injectedFrameCount, | |
| 195 size_t expectedFrameCount) | |
| 196 { | |
| 197 // First make sure that this tests makes sense. | |
| 198 ASSERT_NE(injectedFrameCount, expectedFrameCount); | |
| 199 | |
| 200 auto data = readFile(pngFile); | |
| 201 auto decoder = createDecoder(); | |
| 202 ASSERT_FALSE(data->isEmpty()); | |
| 203 | |
| 204 RefPtr<SharedBuffer> diffActlData = SharedBuffer::create(data->data(), | |
| 205 offsetActl + 8); | |
| 206 // Write the injectedFrameCount to the stream | |
| 207 png_byte sizeChunk[4]; | |
| 208 writeUint32(injectedFrameCount, sizeChunk); | |
| 209 diffActlData->append(reinterpret_cast<char*>(sizeChunk), 4u); | |
| 210 // Append the rest of the data. The first |offsetActl + 12| bytes that are | |
| 211 // already in diffActlData should not be appended again. | |
| 212 diffActlData->append(data->data() + offsetActl + 12, | |
| 213 data->size() - offsetActl - 12); | |
| 214 | |
| 215 decoder->setData(diffActlData, true); | |
| 216 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 217 } | |
| 218 | |
| 219 // Test if the frame bitmap hashes of truncated decoding are equal to the | |
| 220 // hashes found by incremental decoding. | |
| 221 void testProgressiveDecoding(const char *pngFile) | |
| 222 { | |
| 223 RefPtr<SharedBuffer> fullData = readFile(pngFile); | |
| 224 ASSERT_TRUE(fullData.get()); | |
| 225 const size_t fullLength = fullData->size(); | |
| 226 | |
| 227 std::unique_ptr<ImageDecoder> decoder; | |
| 228 ImageFrame* frame; | |
| 229 | |
| 230 Vector<unsigned> truncatedHashes; | |
| 231 Vector<unsigned> progressiveHashes; | |
| 232 | |
| 233 // Compute hashes when the file is truncated. | |
| 234 const size_t increment = 13; | |
| 235 for (size_t i = 1; i <= fullLength; i += increment) { | |
| 236 decoder = createDecoder(); | |
| 237 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i); | |
| 238 decoder->setData(data.get(), i == fullLength); | |
| 239 size_t frameCount = decoder->frameCount(); | |
| 240 ASSERT_FALSE(decoder->failed()); | |
| 241 if (frameCount == 0) { | |
| 242 truncatedHashes.append(0); | |
| 243 continue; | |
| 244 } | |
| 245 frame = decoder->frameBufferAtIndex(frameCount - 1); | |
| 246 if (!frame) { | |
| 247 truncatedHashes.append(0); | |
| 248 continue; | |
| 249 } | |
| 250 truncatedHashes.append(hashBitmap(frame->bitmap())); | |
| 251 } | |
| 252 | |
| 253 // Compute hashes when the file is progressively decoded. | |
| 254 decoder = createDecoder(); | |
| 255 for (size_t i = 1; i <= fullLength; i += increment) { | |
| 256 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i); | |
| 257 decoder->setData(data.get(), i == fullLength); | |
| 258 ASSERT_FALSE(decoder->failed()); | |
| 259 size_t frameCount = decoder->frameCount(); | |
| 260 if (frameCount == 0) { | |
| 261 progressiveHashes.append(0); | |
| 262 continue; | |
| 263 } | |
| 264 frame = decoder->frameBufferAtIndex(frameCount - 1); | |
| 265 if (!frame) { | |
| 266 progressiveHashes.append(0); | |
| 267 continue; | |
| 268 } | |
| 269 progressiveHashes.append(hashBitmap(frame->bitmap())); | |
| 270 } | |
| 271 | |
| 272 for (size_t i = 0; i < truncatedHashes.size(); ++i) | |
| 273 ASSERT_EQ(truncatedHashes[i], progressiveHashes[i]); | |
| 274 } | |
| 275 | |
| 276 // Check that providing the full data after the first frame was partially | |
| 277 // decoded properly continues where it left off. | |
| 278 void testProgressiveDecodingContinuesAfterFullData(const char* pngFile, | |
| 279 size_t offsetMidFirstFrame) | |
| 280 { | |
| 281 auto fullData = readFile(pngFile); | |
| 282 auto decoder = createDecoder(); | |
| 283 ASSERT_FALSE(fullData->isEmpty()); | |
| 284 | |
| 285 RefPtr<SharedBuffer> partialData = | |
| 286 SharedBuffer::create(fullData->data(), offsetMidFirstFrame); | |
| 287 decoder->setData(partialData, false); | |
| 288 | |
| 289 EXPECT_EQ(1u, decoder->frameCount()); | |
| 290 ImageFrame* frame = decoder->frameBufferAtIndex(0); | |
| 291 EXPECT_EQ(frame->getStatus(), ImageFrame::FramePartial); | |
| 292 unsigned hashPartial = hashBitmap(frame->bitmap()); | |
| 293 | |
| 294 decoder->setData(fullData.get(), true); | |
| 295 frame = decoder->frameBufferAtIndex(0); | |
| 296 EXPECT_EQ(frame->getStatus(), ImageFrame::FrameComplete); | |
| 297 unsigned hashFull = hashBitmap(frame->bitmap()); | |
| 298 | |
| 299 EXPECT_FALSE(decoder->failed()); | |
| 300 EXPECT_NE(hashFull, hashPartial); | |
| 301 } | |
| 302 | |
| 303 // This test verifies that the frame buffer contents change when progressively | |
| 304 // decoding the first frame. It should change more than 1 time: once for the | |
| 305 // first data, and at least once more thereafter. If |offsetFirstFrameEnd| == 0, | |
| 306 // the test uses the full data size of the image for its value. | |
| 307 void testProgressiveDecodingChangesFrameBuffer(const char* pngFile, | |
| 308 size_t offsetFirstFrameEnd, | |
| 309 size_t step = 1u) | |
| 310 { | |
| 311 auto fullData = readFile(pngFile); | |
| 312 auto decoder = createDecoder(); | |
| 313 ASSERT_FALSE(fullData->isEmpty()); | |
| 314 | |
| 315 if (offsetFirstFrameEnd == 0) | |
| 316 offsetFirstFrameEnd = fullData->size(); | |
| 317 | |
| 318 size_t numTimesBufferChanged = 0; | |
| 319 unsigned lastHash; | |
| 320 | |
| 321 for (size_t length = 1; length <= offsetFirstFrameEnd; length += step) { | |
| 322 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), | |
| 323 length); | |
| 324 decoder->setData(data, false); | |
| 325 ImageFrame* frame = decoder->frameBufferAtIndex(0); | |
| 326 if (!frame) | |
| 327 continue; | |
| 328 unsigned newHash = hashBitmap(frame->bitmap()); | |
| 329 if (newHash != lastHash) { | |
| 330 lastHash = newHash; | |
| 331 numTimesBufferChanged++; | |
| 332 } | |
| 333 } | |
| 334 EXPECT_GT(numTimesBufferChanged, 1u); | |
| 335 } | |
| 336 | |
| 337 // @TODO(joostouwerling) Pull this up to ImageDecoderTestHelper since it is also | |
| 338 // used in WEBPImageDecoderTest | |
| 339 void testRandomDecodeAfterClearFrameBufferCache(const char* pngFile) { | |
| 340 SCOPED_TRACE(pngFile); | |
| 341 | |
| 342 RefPtr<SharedBuffer> data = readFile(pngFile); | |
| 343 ASSERT_TRUE(data.get()); | |
| 344 Vector<unsigned> baselineHashes; | |
| 345 createDecodingBaseline(&createDecoder, data.get(), &baselineHashes); | |
| 346 const size_t frameCount = baselineHashes.size(); | |
| 347 | |
| 348 std::unique_ptr<ImageDecoder> decoder = createDecoder(); | |
| 349 decoder->setData(data.get(), true); | |
| 350 for (size_t clearExceptFrame = 0; clearExceptFrame < frameCount; | |
| 351 ++clearExceptFrame) { | |
| 352 decoder->clearCacheExceptFrame(clearExceptFrame); | |
| 353 const size_t skippingStep = 2; | |
| 354 for (size_t i = 0; i < skippingStep; ++i) { | |
| 355 for (size_t j = 0; j < frameCount; j += skippingStep) { | |
| 356 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j); | |
| 357 ImageFrame* frame = decoder->frameBufferAtIndex(j); | |
| 358 EXPECT_EQ(baselineHashes[j], hashBitmap(frame->bitmap())); | |
| 359 } | |
| 360 } | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 uint32_t premultiplyColor(uint32_t c) { | |
| 365 return SkPremultiplyARGBInline(SkGetPackedA32(c), SkGetPackedR32(c), | |
| 366 SkGetPackedG32(c), SkGetPackedB32(c)); | |
| 367 } | |
| 368 | |
| 369 void verifyFramesMatch(const char* pngFile, | |
| 370 const ImageFrame* const a, | |
| 371 ImageFrame* const b) { | |
| 372 const SkBitmap& bitmapA = a->bitmap(); | |
| 373 const SkBitmap& bitmapB = b->bitmap(); | |
| 374 ASSERT_EQ(bitmapA.width(), bitmapB.width()); | |
| 375 ASSERT_EQ(bitmapA.height(), bitmapB.height()); | |
| 376 | |
| 377 int maxDifference = 0; | |
| 378 for (int y = 0; y < bitmapA.height(); ++y) { | |
| 379 for (int x = 0; x < bitmapA.width(); ++x) { | |
| 380 uint32_t colorA = *bitmapA.getAddr32(x, y); | |
| 381 if (!a->premultiplyAlpha()) | |
| 382 colorA = premultiplyColor(colorA); | |
| 383 uint32_t colorB = *bitmapB.getAddr32(x, y); | |
| 384 if (!b->premultiplyAlpha()) | |
| 385 colorB = premultiplyColor(colorB); | |
| 386 uint8_t* pixelA = reinterpret_cast<uint8_t*>(&colorA); | |
| 387 uint8_t* pixelB = reinterpret_cast<uint8_t*>(&colorB); | |
| 388 for (int channel = 0; channel < 4; ++channel) { | |
| 389 const int difference = abs(pixelA[channel] - pixelB[channel]); | |
| 390 if (difference > maxDifference) | |
| 391 maxDifference = difference; | |
| 392 } | |
| 393 } | |
| 394 } | |
| 395 | |
| 396 // Pre-multiplication could round the RGBA channel values. So, we declare | |
| 397 // that the frames match if the RGBA channel values differ by at most 2. | |
| 398 EXPECT_GE(2, maxDifference) << pngFile; | |
| 399 } | |
| 400 | |
| 401 // Verifies that result of alpha blending is similar for AlphaPremultiplied and | |
| 402 // AlphaNotPremultiplied cases. | |
| 403 void testAlphaBlending(const char* pngFile) { | |
| 404 RefPtr<SharedBuffer> data = readFile(pngFile); | |
| 405 ASSERT_TRUE(data.get()); | |
| 406 | |
| 407 std::unique_ptr<ImageDecoder> decoderA = | |
| 408 createDecoder(ImageDecoder::AlphaPremultiplied); | |
| 409 decoderA->setData(data.get(), true); | |
| 410 | |
| 411 std::unique_ptr<ImageDecoder> decoderB = | |
| 412 createDecoder(ImageDecoder::AlphaNotPremultiplied); | |
| 413 decoderB->setData(data.get(), true); | |
| 414 | |
| 415 size_t frameCount = decoderA->frameCount(); | |
| 416 ASSERT_EQ(frameCount, decoderB->frameCount()); | |
| 417 | |
| 418 for (size_t i = 0; i < frameCount; ++i) | |
| 419 verifyFramesMatch(pngFile, decoderA->frameBufferAtIndex(i), | |
| 420 decoderB->frameBufferAtIndex(i)); | |
| 421 } | |
| 422 | |
| 423 // Modify the frame data bytes for frame |frameIndex| so that decoding fails. | |
| 424 // Parsing should work fine, and is checked with |expectedFrameCountBefore|. If | |
| 425 // the failure should invalidate the decoder, |expectFailure| should be set to | |
| 426 // true. If not, |expectedFrameCountAfter| should indicate the new frame count | |
| 427 // after the failure. | |
| 428 void testFailureDuringDecode(const char *file, | |
| 429 size_t idatOffset, | |
| 430 size_t frameIndex, | |
| 431 bool expectFailure, | |
| 432 size_t expectedFrameCountBefore, | |
| 433 size_t expectedFrameCountAfter = 0u) | |
| 434 { | |
| 435 RefPtr<SharedBuffer> fullData = readFile(file); | |
| 436 ASSERT_FALSE(fullData->isEmpty()); | |
| 437 | |
| 438 // This is the offset where the frame data chunk frame |frameIndex| starts. | |
| 439 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), | |
| 440 idatOffset + 8u); | |
| 441 // Repeat the first 8 bytes of the frame data. This should result in a | |
| 442 // succesfull parse, since frame data is not analyzed in that step, but | |
| 443 // should give an error during decoding. | |
| 444 data->append(fullData->data() + idatOffset, 8u); | |
| 445 data->append(fullData->data() + idatOffset + 16u, | |
| 446 fullData->size() - idatOffset - 16u); | |
| 447 | |
| 448 auto decoder = createDecoder(); | |
| 449 decoder->setData(data.get(), true); | |
| 450 | |
| 451 EXPECT_EQ(expectedFrameCountBefore, decoder->frameCount()); | |
| 452 | |
| 453 const ImageFrame* const frame = decoder->frameBufferAtIndex(frameIndex); | |
| 454 EXPECT_EQ(expectFailure, decoder->failed()); | |
| 455 if (!expectFailure) { | |
| 456 EXPECT_EQ(expectedFrameCountAfter, decoder->frameCount()); | |
| 457 EXPECT_EQ(ImageFrame::FrameEmpty, frame->getStatus()); | |
| 458 } | |
| 459 } | |
| 460 | |
| 461 } // Anonymous namespace | |
| 462 | |
| 463 // Animated PNG Tests | |
| 464 | |
| 465 TEST(AnimatedPNGTests, sizeTest) | |
| 466 { | |
| 467 testSize("/LayoutTests/fast/images/resources/png-animated-idat-part-of-animati on.png", IntSize(5, 5)); | |
| 468 testSize("/LayoutTests/fast/images/resources/png-animated-idat-not-part-of-ani mation.png", IntSize(227, 35)); | |
| 469 } | |
| 470 | |
| 471 TEST(AnimatedPNGTests, repetitionCountTest) | |
| 472 { | |
| 473 testRepetitionCount("/LayoutTests/fast/images/resources/png-animated-idat-part -of-animation.png", 7u); | |
| 474 // This is an "animated" image with only one frame, that is, the IDAT is | |
| 475 // ignored and there is one fdAT frame. so it should be considered | |
| 476 // non-animated. | |
| 477 testRepetitionCount("/LayoutTests/fast/images/resources/png-animated-idat-not- part-of-animation.png", cAnimationNone); | |
| 478 } | |
| 479 | |
| 480 // Test if the decoded metdata corresponds to the defined expectations | |
| 481 TEST(AnimatedPNGTests, MetaDataTest) | |
| 482 { | |
| 483 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png"; | |
| 484 constexpr size_t expectedFrameCount = 4; | |
| 485 | |
| 486 auto decoder = createDecoderWithPngData(pngFile); | |
| 487 ASSERT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 488 for (size_t i = 0; i < expectedFrameCount; i++) | |
| 489 compareFrameWithExpectation(pngAnimatedFrameInfo[i], | |
| 490 decoder->frameBufferAtIndex(i)); | |
| 491 } | |
| 492 | |
| 493 TEST(AnimatedPNGTests, ByteByByteSizeAvailable) | |
| 494 { | |
| 495 testSizeByteByByte("/LayoutTests/fast/images/resources/png-animated-idat-part- of-animation.png", | |
| 496 141u, IntSize(5, 5)); | |
| 497 testSizeByteByByte("/LayoutTests/fast/images/resources/png-animated-idat-not-p art-of-animation.png", | |
| 498 79u, IntSize(227, 35)); | |
| 499 } | |
| 500 | |
| 501 // Test whether the frame metadata decoding also works when we provide the data | |
| 502 // byte by byte. This should cover the case when the client does not provide | |
| 503 // all data at once. At given offsets, we expect frames to become available. | |
| 504 // This test checks whether that is the case, and if so, if the frame data is | |
| 505 // equal to what we expected. | |
| 506 TEST(AnimatedPNGTests, ByteByByteMetaData) | |
| 507 { | |
| 508 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png"; | |
| 509 constexpr size_t expectedFrameCount = 4; | |
| 510 | |
| 511 // These are the byte offsets where each frame should have been parsed. | |
| 512 // It boils down to the offset of the first fcTL / IEND after the last | |
| 513 // frame data chunk, plus 8 bytes for recognition. The exception on this is | |
| 514 // the first frame, which is reported when its first framedata is seen. | |
| 515 size_t frameOffsets[expectedFrameCount] = {141, 249, 322, 430}; | |
| 516 | |
| 517 auto decoder = createDecoder(); | |
| 518 auto data = readFile(pngFile); | |
| 519 ASSERT_FALSE(data->isEmpty()); | |
| 520 size_t framesParsed = 0; | |
| 521 | |
| 522 for (size_t length = 1; length <= frameOffsets[expectedFrameCount - 1]; length ++) { | |
| 523 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), | |
| 524 length); | |
| 525 decoder->setData(tempData.get(), false); | |
| 526 EXPECT_FALSE(decoder->failed()); | |
| 527 if (length < frameOffsets[framesParsed]) { | |
| 528 EXPECT_EQ(framesParsed, decoder->frameCount()); | |
| 529 } else { | |
| 530 ASSERT_EQ(framesParsed + 1, decoder->frameCount()); | |
| 531 compareFrameWithExpectation(pngAnimatedFrameInfo[framesParsed], | |
| 532 decoder->frameBufferAtIndex(framesParsed)); | |
| 533 framesParsed++; | |
| 534 } | |
| 535 } | |
| 536 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 537 EXPECT_FALSE(decoder->failed()); | |
| 538 } | |
| 539 | |
| 540 TEST(AnimatedPNGTests, TestRandomFrameDecode) | |
| 541 { | |
| 542 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/p ng-animated-idat-part-of-animation.png"); | |
| 543 ASSERT_TRUE(fullData.get()); | |
| 544 Vector<unsigned> baselineHashes; | |
| 545 createDecodingBaseline(&createDecoder, fullData.get(), &baselineHashes); | |
| 546 const size_t frameCount = baselineHashes.size(); | |
| 547 | |
| 548 // Random decoding should get the same results as sequential decoding. | |
| 549 std::unique_ptr<ImageDecoder> decoder = createDecoder(); | |
| 550 decoder->setData(fullData.get(), true); | |
| 551 const size_t skippingStep = 2; | |
| 552 for (size_t i = 0; i < skippingStep; ++i) { | |
| 553 for (size_t j = i; j < frameCount; j += skippingStep) { | |
| 554 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j); | |
| 555 ImageFrame* frame = decoder->frameBufferAtIndex(j); | |
| 556 EXPECT_EQ(baselineHashes[j], hashBitmap(frame->bitmap())); | |
| 557 } | |
| 558 } | |
| 559 | |
| 560 // Decoding in reverse order. | |
| 561 decoder = createDecoder(); | |
| 562 decoder->setData(fullData.get(), true); | |
| 563 for (size_t i = frameCount; i; --i) { | |
| 564 SCOPED_TRACE(testing::Message() << "Reverse i:" << i); | |
| 565 ImageFrame* frame = decoder->frameBufferAtIndex(i - 1); | |
| 566 EXPECT_EQ(baselineHashes[i - 1], hashBitmap(frame->bitmap())); | |
| 567 } | |
| 568 | |
| 569 } | |
| 570 | |
| 571 TEST(AnimatedPNGTests, TestDecodeAfterReallocation) | |
| 572 { | |
| 573 std::unique_ptr<ImageDecoder> decoder = createDecoder(); | |
| 574 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/png-a nimated-idat-part-of-animation.png"); | |
| 575 ASSERT_TRUE(data.get()); | |
| 576 | |
| 577 // Parse from |data|. | |
| 578 decoder->setData(data.get(), true); | |
| 579 const size_t frameCount = decoder->frameCount(); | |
| 580 | |
| 581 // ... and then decode frames from |reallocatedData|. | |
| 582 RefPtr<SharedBuffer> reallocatedData = data.get()->copy(); | |
| 583 ASSERT_TRUE(reallocatedData.get()); | |
| 584 data.clear(); | |
| 585 decoder->setData(reallocatedData.get(), true); | |
| 586 | |
| 587 for (size_t i = 0; i < frameCount; ++i) { | |
| 588 const ImageFrame* const frame = decoder->frameBufferAtIndex(i); | |
| 589 EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus()); | |
| 590 } | |
| 591 } | |
| 592 | |
| 593 TEST(AnimatedPNGTests, ProgressiveDecode) | |
| 594 { | |
| 595 testProgressiveDecoding("/LayoutTests/fast/images/resources/png-animated-idat- part-of-animation.png"); | |
| 596 } | |
| 597 | |
| 598 TEST(AnimatedPNGTests, ParseAndDecodeByteByByte) | |
| 599 { | |
| 600 testByteByByteDecode(&createDecoder, | |
| 601 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-anima tion.png", | |
| 602 4u, 7u); | |
| 603 } | |
| 604 | |
| 605 TEST(AnimatedPNGTests, FailureDuringParsing) | |
| 606 { | |
| 607 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png"; | |
| 608 auto data = readFile(pngFile); | |
| 609 ASSERT_FALSE(data->isEmpty()); | |
| 610 | |
| 611 // Test the first fcTL in the stream. Because no frame data has been set at | |
| 612 // this point, the expected frame count is zero. 95 bytes is just before the | |
| 613 // first fcTL chunk, at which the first frame is detected. The decoder should | |
| 614 // be in the failed state since no frames were parsed before this error. | |
| 615 testInvalidFctlSize("/LayoutTests/fast/images/resources/png-animated-idat-part -of-animation.png", | |
| 616 95u, 0u, true); | |
| 617 | |
| 618 // Test for the third fcTL in the stream. This should be tested as well, | |
| 619 // since the first fcTL is parsed in PNGImageReader::parseSize() whereas | |
| 620 // later fcTLs are parsed in PNGImageReader::parse() as part of framecount. | |
| 621 // The expected frame count before the fcTL chunk is 1u, since the second | |
| 622 // frame is registered when the third fcTL (or IEND) is seen. | |
| 623 // | |
| 624 // This should *not* set the decoder to the failed state since the first | |
| 625 // frame was succesfully parsed, and we still want to show that frame. | |
| 626 testInvalidFctlSize("/LayoutTests/fast/images/resources/png-animated-idat-part -of-animation.png", | |
| 627 241u, 1u, false); | |
| 628 | |
| 629 } | |
| 630 | |
| 631 TEST(AnimatedPNGTests, FailureDuringParsingDueToMissingFctlData) | |
| 632 { | |
| 633 // The fcTL chunk starts at 95u, add 10u to get to the content data, and | |
| 634 // remove 5 bytes of data. This sets the decoder to the failed state since | |
| 635 // no frames were parsed yet. | |
| 636 testMissingDataBreaksDecoding( | |
| 637 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png" , | |
| 638 105u, 5u); | |
| 639 } | |
| 640 | |
| 641 TEST(AnimatedPNGTests, MissingActlResultsInNonAnimated) | |
| 642 { | |
| 643 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png"; | |
| 644 auto data = readFile(pngFile); | |
| 645 auto decoder = createDecoder(); | |
| 646 ASSERT_FALSE(data->isEmpty()); | |
| 647 | |
| 648 // Remove the acTL chunk from the stream. | |
| 649 const size_t offsetActl = 33; | |
| 650 RefPtr<SharedBuffer> noActlData = SharedBuffer::create(data->data(), | |
| 651 offsetActl); | |
| 652 noActlData->append(data->data() + offsetActl + 20, | |
| 653 data->size() - offsetActl - 20); | |
| 654 | |
| 655 decoder->setData(noActlData, true); | |
| 656 EXPECT_EQ(1u, decoder->frameCount()); | |
| 657 EXPECT_FALSE(decoder->failed()); | |
| 658 } | |
| 659 | |
| 660 // Test if the indicated frame count by the acTL is ignored if the actual | |
| 661 // number of frames is different. Test for higher and lower indicated number. | |
| 662 TEST(AnimatedPNGTests, differentActlFrameCountIsIgnored) | |
| 663 { | |
| 664 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png"; | |
| 665 testDifferentActlFrameCountIsIgnored(pngFile, 33u, 2u, 4u); | |
| 666 testDifferentActlFrameCountIsIgnored(pngFile, 33u, 8u, 4u); | |
| 667 } | |
| 668 | |
| 669 // Originally, the third frame has an offset of (1,2) and a size of (3,2). By | |
| 670 // changing the offset to (0,0) and the size to (4,4), a frame with not enough | |
| 671 // data is simulated. The expected result is that the decoder will only receive | |
| 672 // 1 row of data, since the data contains 6 pixels and each row is 4 pixels. | |
| 673 // | |
| 674 // When the decoder receives not enough data for a frame, the expected behavior | |
| 675 // is that nothing changes: the decoder should not be invalidated, and the | |
| 676 // frame should be considered successfully decoded. The reason for this is that | |
| 677 // the error could either be an invalid frame size, or an invalid data chunk. | |
| 678 // For now, the decoder does not take any action if not enough data is | |
| 679 // provided, as described in PNGImageDecoder::complete(). | |
| 680 TEST(AnimatedPNGTests, VerifyIncompleteFrameDataDoesNotInvalidateDecoder) | |
| 681 { | |
| 682 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png"; | |
| 683 auto data = readFile(pngFile); | |
| 684 auto decoder = createDecoder(); | |
| 685 ASSERT_FALSE(data->isEmpty()); | |
| 686 | |
| 687 // Change the size and the offset of the frame, as described above. The size | |
| 688 // is stored in byte 12-19 of the fcTL chunk, and the offset in byte 20-27. | |
| 689 const size_t offsetThirdFctl = 241 + 12; | |
| 690 RefPtr<SharedBuffer> modifiedData = SharedBuffer::create(data->data(), | |
| 691 offsetThirdFctl); | |
| 692 png_byte rectChunk[16]; | |
| 693 writeUint32(4, rectChunk); | |
| 694 writeUint32(4, rectChunk + 4); | |
| 695 writeUint32(0, rectChunk + 8); | |
| 696 writeUint32(0, rectChunk + 12); | |
| 697 modifiedData->append(const_cast<const char*>( | |
| 698 reinterpret_cast<char*>(rectChunk)), 16u); | |
| 699 modifiedData->append(data->data() + offsetThirdFctl + 16, | |
| 700 data->size() - offsetThirdFctl - 16); | |
| 701 | |
| 702 decoder->setData(modifiedData, true); | |
| 703 | |
| 704 // Verify that parsing the image results in the expected meta data. | |
| 705 IntSize expectedSize(5, 5); | |
| 706 const size_t expectedFrameCount = 4; | |
| 707 IntRect expectedFrameRect(IntPoint(0, 0), IntSize(4, 4)); | |
| 708 EXPECT_TRUE(decoder->isSizeAvailable()); | |
| 709 EXPECT_EQ(expectedSize, decoder->size()); | |
| 710 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 711 ASSERT_FALSE(decoder->failed()); | |
| 712 | |
| 713 // Try to decode frame 3. This should not fail the decoder, and the frame | |
| 714 // should be FrameComplete. | |
| 715 const ImageFrame* const buffer = decoder->frameBufferAtIndex(2); | |
| 716 EXPECT_EQ(expectedFrameRect, buffer->originalFrameRect()); | |
| 717 EXPECT_FALSE(decoder->failed()); | |
| 718 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 719 EXPECT_EQ(ImageFrame::FrameComplete, buffer->getStatus()); | |
| 720 } | |
| 721 | |
| 722 // Originally, the third frame has an offset of (1,2) and a size of (3,2). By | |
| 723 // changing the offset to (4,4), the frame rect will extend the image size of | |
| 724 // 5x5. Verify that the frame is correctly clipped to a size of (1,1) without | |
| 725 // any decoding errors. Since this is the third frame, a decoding failure would | |
| 726 // result in the frame count being adjusted to 2, and the decoder would not be | |
| 727 // invalidated. Therefore, it is verified that after decoding frame 3 the | |
| 728 // decoder is still in a valid state and the frame count is still 4. | |
| 729 TEST(AnimatedPNGTests, VerifyFrameExtendsImageSizeClipsCorrectly) | |
| 730 { | |
| 731 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png"; | |
| 732 auto data = readFile(pngFile); | |
| 733 auto decoder = createDecoder(); | |
| 734 ASSERT_FALSE(data->isEmpty()); | |
| 735 | |
| 736 // The offset of the frame rect is located 20 bytes into the fcTL chunk, after | |
| 737 // the length, tag, sequence number, width and height fields (all 4B). | |
| 738 const size_t offsetThirdFctl = 241 + 20; | |
| 739 RefPtr<SharedBuffer> modifiedData = SharedBuffer::create(data->data(), | |
| 740 offsetThirdFctl); | |
| 741 png_byte offsetChunk[8]; | |
| 742 writeUint32(4, offsetChunk); | |
| 743 writeUint32(4, offsetChunk + 4); | |
| 744 modifiedData->append(const_cast<const char*>( | |
| 745 reinterpret_cast<char*>(offsetChunk)), 8u); | |
| 746 modifiedData->append(data->data() + offsetThirdFctl + 8, | |
| 747 data->size() - offsetThirdFctl - 8); | |
| 748 | |
| 749 decoder->setData(modifiedData, true); | |
| 750 | |
| 751 // Verify that parsing the image results in the expected meta data. | |
| 752 IntSize expectedSize(5, 5); | |
| 753 const size_t expectedFrameCount = 4; | |
| 754 IntRect expectedFrameRect(IntPoint(4, 4), IntSize(1, 1)); | |
| 755 EXPECT_TRUE(decoder->isSizeAvailable()); | |
| 756 EXPECT_EQ(expectedSize, decoder->size()); | |
| 757 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 758 ASSERT_FALSE(decoder->failed()); | |
| 759 | |
| 760 // Try to decode frame 3. This should not fail the decoder, and the frame | |
| 761 // should be FrameComplete. | |
| 762 const ImageFrame* const buffer = decoder->frameBufferAtIndex(2); | |
| 763 EXPECT_EQ(expectedFrameRect, buffer->originalFrameRect()); | |
| 764 EXPECT_FALSE(decoder->failed()); | |
| 765 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 766 EXPECT_EQ(ImageFrame::FrameComplete, buffer->getStatus()); | |
| 767 } | |
| 768 | |
| 769 TEST(AnimatedPNGTests, ProgressiveDecodingChangesFrameBuffer) | |
| 770 { | |
| 771 testProgressiveDecodingChangesFrameBuffer( | |
| 772 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png" , 249u); | |
| 773 } | |
| 774 | |
| 775 TEST(AnimatedPNGTests, ProgressiveDecodingContinuesAfterFullData) | |
| 776 { | |
| 777 // 160u is a randomly chosen offset in the IDAT chunk of the first frame. | |
| 778 testProgressiveDecodingContinuesAfterFullData( | |
| 779 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png" , 160u); | |
| 780 } | |
| 781 | |
| 782 TEST(AnimatedPNGTests, RandomDecodeAfterClearFrameBufferCache) | |
| 783 { | |
| 784 testRandomDecodeAfterClearFrameBufferCache( | |
| 785 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png" ); | |
| 786 } | |
| 787 | |
| 788 TEST(AnimatedPNGTests, VerifyAlphaBlending) { | |
| 789 testAlphaBlending( | |
| 790 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png" ); | |
| 791 } | |
| 792 | |
| 793 // This tests if the frame count gets set correctly when parsing frameCount | |
| 794 // fails in one of the parsing queries. | |
| 795 // | |
| 796 // First, enough data is provided such that two frames should be registered. | |
| 797 // The decoder should at this point not be in the failed status. | |
| 798 // | |
| 799 // Then, we provide the rest of the data except for the last IEND chunk, but | |
| 800 // tell the decoder that this is all the data we have. The frame count should | |
| 801 // be three, since one extra frame should be discovered. The fourth frame | |
| 802 // should *not* be registered since the reader should not be able to determine | |
| 803 // where the frame ends. The decoder should *not* be in the failed state since | |
| 804 // there are three frames which can be shown. | |
| 805 TEST(AnimatedPNGTests, FailureMissingIendChunk) | |
| 806 { | |
| 807 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/p ng-animated-idat-part-of-animation.png"); | |
| 808 ASSERT_FALSE(fullData->isEmpty()); | |
| 809 auto decoder = createDecoder(); | |
| 810 | |
| 811 const size_t offsetTwoFrames = 249; | |
| 812 const size_t expectedFramesAfter249Bytes = 2; | |
| 813 RefPtr<SharedBuffer> tempData = SharedBuffer::create(fullData->data(), | |
| 814 offsetTwoFrames); | |
| 815 decoder->setData(tempData.get(), false); | |
| 816 EXPECT_EQ(expectedFramesAfter249Bytes, decoder->frameCount()); | |
| 817 EXPECT_FALSE(decoder->failed()); | |
| 818 | |
| 819 // Provide the rest of the data except for the last IEND chunk. | |
| 820 const size_t expectedFramesAfterAllExpect12Bytes = 3; | |
| 821 tempData = SharedBuffer::create(fullData->data(), fullData->size() - 12); | |
| 822 decoder->setData(tempData.get(), true); | |
| 823 EXPECT_EQ(expectedFramesAfterAllExpect12Bytes, decoder->frameCount()); | |
| 824 EXPECT_FALSE(decoder->failed()); | |
| 825 } | |
| 826 | |
| 827 TEST(AnimatedPNGTests, VerifyFrameCountChangesOnDecodingFailure) | |
| 828 { | |
| 829 testFailureDuringDecode( | |
| 830 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.pn g", | |
| 831 279u, // idat offset for frame index 2 | |
| 832 2u, // try to decode frame index 2 | |
| 833 false, // expect the decoder to *not* be invalidated after the failure | |
| 834 4u, // expected frame count before failure | |
| 835 2u); // expected frame count after failure | |
| 836 | |
| 837 testFailureDuringDecode( | |
| 838 "/LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.pn g", | |
| 839 133u, // idat offset for frame index 0 | |
| 840 0u, // try to decode frame index 0 | |
| 841 true, // expect the decoder to be invalidated after the failure | |
| 842 4u); // expected frame count before failure | |
| 843 } | |
| 844 | |
| 845 // Verify that a malformatted PNG, where the IEND appears before any frame data | |
| 846 // (IDAT), invalidates the decoder. | |
| 847 TEST(AnimatedPNGTests, VerifyIENDBeforeIDATInvalidatesDecoder) | |
| 848 { | |
| 849 RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/fast/images/resources/p ng-animated-idat-part-of-animation.png"); | |
| 850 ASSERT_FALSE(fullData->isEmpty()); | |
| 851 auto decoder = createDecoder(); | |
| 852 | |
| 853 const size_t offsetIDAT = 133; | |
| 854 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), | |
| 855 offsetIDAT); | |
| 856 data->append(fullData->data() + fullData->size() - 12u, 12u); | |
| 857 data->append(fullData->data() + offsetIDAT, fullData->size() - offsetIDAT); | |
| 858 decoder->setData(data.get(), true); | |
| 859 | |
| 860 const size_t expectedFrameCount = 0u; | |
| 861 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 862 EXPECT_TRUE(decoder->failed()); | |
| 863 } | |
| 864 | |
| 865 TEST(AnimatedPNGTests, VerifyFrameCompleteBehavior) | |
| 866 { | |
| 867 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png"; | |
| 868 RefPtr<SharedBuffer> fullData = readFile(pngFile); | |
| 869 ASSERT_FALSE(fullData->isEmpty()); | |
| 870 auto decoder = createDecoder(); | |
| 871 decoder->setData(fullData.get(), true); | |
| 872 | |
| 873 const size_t expectedFrameCount = 4; | |
| 874 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 875 ASSERT_FALSE(decoder->failed()); | |
| 876 | |
| 877 // The first frame is only considered complete if it has been fully decoded. | |
|
scroggo_chromium
2016/11/29 16:30:52
I think this behavior is wrong. I've gone back to
joostouwerling
2016/12/02 16:08:42
Yes, I agree. I think it is for the best to return
| |
| 878 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0)); | |
| 879 // Non-first frames are considered complete when they're fully received. | |
| 880 for (size_t index = 1; index < expectedFrameCount; index++) | |
| 881 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1)); | |
|
scroggo_chromium
2016/11/29 16:30:52
I think you meant to pass index to frameIsComplete
joostouwerling
2016/12/02 16:08:42
Done.
| |
| 882 // After decoding, the frame should be considered complete. | |
| 883 decoder->frameBufferAtIndex(0); | |
| 884 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | |
| 885 | |
| 886 // Also test that a progressive decode of frame 0 only returns true on | |
|
scroggo_chromium
2016/11/29 16:30:52
Again, I think this is the wrong behavior.
joostouwerling
2016/12/02 16:08:42
Acknowledged.
| |
| 887 // frameIsCompleteAtIndex when it is fully decoded. | |
| 888 decoder = createDecoder(); | |
| 889 const size_t offsetMidwayIDAT = 160; | |
| 890 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), | |
| 891 offsetMidwayIDAT); | |
| 892 decoder->setData(data.get(), false); | |
| 893 const ImageFrame* frame = decoder->frameBufferAtIndex(0); | |
| 894 EXPECT_EQ(ImageFrame::FramePartial, frame->getStatus()); | |
| 895 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(0)); | |
| 896 // With the full data provided, the status should switch to complete. | |
| 897 decoder->setData(fullData.get(), true); | |
| 898 frame = decoder->frameBufferAtIndex(0); | |
| 899 EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus()); | |
| 900 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | |
| 901 } | |
| 902 | |
| 903 // Static PNG tests | |
| 904 | |
| 905 TEST(StaticPNGTests, repetitionCountTest) | |
| 906 { | |
| 907 testRepetitionCount("/LayoutTests/fast/images/resources/png-simple.png", | |
| 908 cAnimationNone); | |
| 909 } | |
| 910 | |
| 911 TEST(StaticPNGTests, sizeTest) | |
| 912 { | |
| 913 testSize("/LayoutTests/fast/images/resources/png-simple.png", | |
| 914 IntSize(111, 29)); | |
| 915 } | |
| 916 | |
| 917 TEST(StaticPNGTests, MetaDataTest) | |
| 918 { | |
| 919 const size_t expectedFrameCount = 1; | |
| 920 const size_t expectedDuration = 0; | |
| 921 auto decoder = createDecoderWithPngData("/LayoutTests/fast/images/resources/pn g-simple.png"); | |
| 922 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
| 923 EXPECT_EQ(expectedDuration, decoder->frameDurationAtIndex(0)); | |
| 924 } | |
| 925 | |
| 926 TEST(StaticPNGTests, InvalidIHDRChunk) | |
| 927 { | |
| 928 testMissingDataBreaksDecoding( | |
| 929 "/LayoutTests/fast/images/resources/png-simple.png", 20u, 2u); | |
| 930 } | |
| 931 | |
| 932 TEST(StaticPNGTests, ProgressiveDecoding) | |
| 933 { | |
| 934 testProgressiveDecoding("/LayoutTests/fast/images/resources/png-simple.png"); | |
| 935 } | |
| 936 | |
| 937 TEST(StaticPNGTests, ProgressiveDecodingChangesFrameBuffer) | |
| 938 { | |
| 939 testProgressiveDecodingChangesFrameBuffer( | |
| 940 "/LayoutTests/fast/images/resources/png-simple.png", 0u, 5u); | |
| 941 } | |
| 942 | |
| 943 TEST(StaticPNGTests, ProgressiveDecodingContinuesAfterFullData) | |
| 944 { | |
| 945 testProgressiveDecodingContinuesAfterFullData( | |
| 946 "/LayoutTests/fast/images/resources/png-simple.png", 1000u); | |
| 947 } | |
| 948 | |
| 949 TEST(StaticPNGTests, FailureDuringDecodingInvalidatesDecoder) | |
| 950 { | |
| 951 testFailureDuringDecode( | |
| 952 "/LayoutTests/fast/images/resources/png-simple.png", | |
| 953 85u, // idat offset for frame index 0 | |
| 954 0u, // try to decode frame index 0 | |
| 955 true, // expect the decoder to be invalidated after the failure | |
| 956 1u); // expected frame count before failure | |
| 957 } | |
| 958 | |
| 959 }; // namespace blink | |
| OLD | NEW |