| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #include "config.h" | |
| 32 | |
| 33 #include "core/platform/image-decoders/gif/GIFImageDecoder.h" | |
| 34 | |
| 35 #include <gtest/gtest.h> | |
| 36 #include "core/platform/FileSystem.h" | |
| 37 #include "core/platform/SharedBuffer.h" | |
| 38 #include <public/Platform.h> | |
| 39 #include <public/WebData.h> | |
| 40 #include <public/WebSize.h> | |
| 41 #include <public/WebUnitTestSupport.h> | |
| 42 #include <wtf/OwnPtr.h> | |
| 43 #include <wtf/PassOwnPtr.h> | |
| 44 #include <wtf/StringHasher.h> | |
| 45 #include <wtf/Vector.h> | |
| 46 | |
| 47 using namespace WebCore; | |
| 48 using namespace WebKit; | |
| 49 | |
| 50 namespace { | |
| 51 | |
| 52 #if !OS(ANDROID) | |
| 53 | |
| 54 static PassRefPtr<SharedBuffer> readFile(const char* fileName) | |
| 55 { | |
| 56 String filePath = Platform::current()->unitTestSupport()->webKitRootDir(); | |
| 57 filePath.append(fileName); | |
| 58 | |
| 59 long long fileSize; | |
| 60 if (!getFileSize(filePath, fileSize)) | |
| 61 return 0; | |
| 62 | |
| 63 PlatformFileHandle handle = openFile(filePath, OpenForRead); | |
| 64 int fileLength = static_cast<int>(fileSize); | |
| 65 Vector<char> buffer(fileLength); | |
| 66 readFromFile(handle, buffer.data(), fileLength); | |
| 67 closeFile(handle); | |
| 68 return SharedBuffer::adoptVector(buffer); | |
| 69 } | |
| 70 | |
| 71 static PassOwnPtr<GIFImageDecoder> createDecoder() | |
| 72 { | |
| 73 return adoptPtr(new GIFImageDecoder(ImageSource::AlphaNotPremultiplied, Imag
eSource::GammaAndColorProfileApplied)); | |
| 74 } | |
| 75 | |
| 76 static unsigned hashSkBitmap(const SkBitmap& bitmap) | |
| 77 { | |
| 78 return StringHasher::hashMemory(bitmap.getPixels(), bitmap.getSize()); | |
| 79 } | |
| 80 | |
| 81 TEST(GIFImageDecoderTest, decodeTwoFrames) | |
| 82 { | |
| 83 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 84 | |
| 85 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 86 ASSERT_TRUE(data.get()); | |
| 87 decoder->setData(data.get(), true); | |
| 88 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount()); | |
| 89 | |
| 90 ImageFrame* frame = decoder->frameBufferAtIndex(0); | |
| 91 EXPECT_EQ(ImageFrame::FrameComplete, frame->status()); | |
| 92 EXPECT_EQ(16, frame->getSkBitmap().width()); | |
| 93 EXPECT_EQ(16, frame->getSkBitmap().height()); | |
| 94 | |
| 95 frame = decoder->frameBufferAtIndex(1); | |
| 96 EXPECT_EQ(ImageFrame::FrameComplete, frame->status()); | |
| 97 EXPECT_EQ(16, frame->getSkBitmap().width()); | |
| 98 EXPECT_EQ(16, frame->getSkBitmap().height()); | |
| 99 | |
| 100 EXPECT_EQ(2u, decoder->frameCount()); | |
| 101 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount()); | |
| 102 } | |
| 103 | |
| 104 TEST(GIFImageDecoderTest, parseAndDecode) | |
| 105 { | |
| 106 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 107 | |
| 108 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 109 ASSERT_TRUE(data.get()); | |
| 110 decoder->setData(data.get(), true); | |
| 111 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount()); | |
| 112 | |
| 113 // This call will parse the entire file. | |
| 114 EXPECT_EQ(2u, decoder->frameCount()); | |
| 115 | |
| 116 ImageFrame* frame = decoder->frameBufferAtIndex(0); | |
| 117 EXPECT_EQ(ImageFrame::FrameComplete, frame->status()); | |
| 118 EXPECT_EQ(16, frame->getSkBitmap().width()); | |
| 119 EXPECT_EQ(16, frame->getSkBitmap().height()); | |
| 120 | |
| 121 frame = decoder->frameBufferAtIndex(1); | |
| 122 EXPECT_EQ(ImageFrame::FrameComplete, frame->status()); | |
| 123 EXPECT_EQ(16, frame->getSkBitmap().width()); | |
| 124 EXPECT_EQ(16, frame->getSkBitmap().height()); | |
| 125 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount()); | |
| 126 } | |
| 127 | |
| 128 TEST(GIFImageDecoderTest, parseByteByByte) | |
| 129 { | |
| 130 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 131 | |
| 132 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 133 ASSERT_TRUE(data.get()); | |
| 134 | |
| 135 size_t frameCount = 0; | |
| 136 | |
| 137 // Pass data to decoder byte by byte. | |
| 138 for (unsigned length = 1; length <= data->size(); ++length) { | |
| 139 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), lengt
h); | |
| 140 decoder->setData(tempData.get(), length == data->size()); | |
| 141 | |
| 142 EXPECT_LE(frameCount, decoder->frameCount()); | |
| 143 frameCount = decoder->frameCount(); | |
| 144 } | |
| 145 | |
| 146 EXPECT_EQ(2u, decoder->frameCount()); | |
| 147 | |
| 148 decoder->frameBufferAtIndex(0); | |
| 149 decoder->frameBufferAtIndex(1); | |
| 150 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount()); | |
| 151 } | |
| 152 | |
| 153 TEST(GIFImageDecoderTest, parseAndDecodeByteByByte) | |
| 154 { | |
| 155 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 156 | |
| 157 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated-gif-with-offsets.gif"); | |
| 158 ASSERT_TRUE(data.get()); | |
| 159 | |
| 160 size_t frameCount = 0; | |
| 161 size_t framesDecoded = 0; | |
| 162 | |
| 163 // Pass data to decoder byte by byte. | |
| 164 for (unsigned length = 1; length <= data->size(); ++length) { | |
| 165 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), lengt
h); | |
| 166 decoder->setData(tempData.get(), length == data->size()); | |
| 167 | |
| 168 EXPECT_LE(frameCount, decoder->frameCount()); | |
| 169 frameCount = decoder->frameCount(); | |
| 170 | |
| 171 ImageFrame* frame = decoder->frameBufferAtIndex(frameCount - 1); | |
| 172 if (frame && frame->status() == ImageFrame::FrameComplete && framesDecod
ed < frameCount) | |
| 173 ++framesDecoded; | |
| 174 } | |
| 175 | |
| 176 EXPECT_EQ(5u, decoder->frameCount()); | |
| 177 EXPECT_EQ(5u, framesDecoded); | |
| 178 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount()); | |
| 179 } | |
| 180 | |
| 181 TEST(GIFImageDecoderTest, brokenSecondFrame) | |
| 182 { | |
| 183 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 184 | |
| 185 RefPtr<SharedBuffer> data = readFile("/Source/WebKit/chromium/tests/data/bro
ken.gif"); | |
| 186 ASSERT_TRUE(data.get()); | |
| 187 decoder->setData(data.get(), true); | |
| 188 | |
| 189 // One frame is detected but cannot be decoded. | |
| 190 EXPECT_EQ(1u, decoder->frameCount()); | |
| 191 ImageFrame* frame = decoder->frameBufferAtIndex(1); | |
| 192 EXPECT_FALSE(frame); | |
| 193 } | |
| 194 | |
| 195 TEST(GIFImageDecoderTest, progressiveDecode) | |
| 196 { | |
| 197 RefPtr<SharedBuffer> fullData = readFile("/Source/WebKit/chromium/tests/data
/radient.gif"); | |
| 198 ASSERT_TRUE(fullData.get()); | |
| 199 const size_t fullLength = fullData->size(); | |
| 200 | |
| 201 OwnPtr<GIFImageDecoder> decoder; | |
| 202 ImageFrame* frame; | |
| 203 | |
| 204 Vector<unsigned> truncatedHashes; | |
| 205 Vector<unsigned> progressiveHashes; | |
| 206 | |
| 207 // Compute hashes when the file is truncated. | |
| 208 const size_t increment = 1; | |
| 209 for (size_t i = 1; i <= fullLength; i += increment) { | |
| 210 decoder = createDecoder(); | |
| 211 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i); | |
| 212 decoder->setData(data.get(), i == fullLength); | |
| 213 frame = decoder->frameBufferAtIndex(0); | |
| 214 if (!frame) { | |
| 215 truncatedHashes.append(0); | |
| 216 continue; | |
| 217 } | |
| 218 truncatedHashes.append(hashSkBitmap(frame->getSkBitmap())); | |
| 219 } | |
| 220 | |
| 221 // Compute hashes when the file is progressively decoded. | |
| 222 decoder = createDecoder(); | |
| 223 for (size_t i = 1; i <= fullLength; i += increment) { | |
| 224 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i); | |
| 225 decoder->setData(data.get(), i == fullLength); | |
| 226 frame = decoder->frameBufferAtIndex(0); | |
| 227 if (!frame) { | |
| 228 progressiveHashes.append(0); | |
| 229 continue; | |
| 230 } | |
| 231 progressiveHashes.append(hashSkBitmap(frame->getSkBitmap())); | |
| 232 } | |
| 233 | |
| 234 bool match = true; | |
| 235 for (size_t i = 0; i < truncatedHashes.size(); ++i) { | |
| 236 if (truncatedHashes[i] != progressiveHashes[i]) { | |
| 237 match = false; | |
| 238 break; | |
| 239 } | |
| 240 } | |
| 241 EXPECT_TRUE(match); | |
| 242 } | |
| 243 | |
| 244 TEST(GIFImageDecoderTest, allDataReceivedTruncation) | |
| 245 { | |
| 246 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 247 | |
| 248 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 249 ASSERT_TRUE(data.get()); | |
| 250 | |
| 251 ASSERT_GE(data->size(), 10u); | |
| 252 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->siz
e() - 10); | |
| 253 decoder->setData(tempData.get(), true); | |
| 254 | |
| 255 EXPECT_EQ(2u, decoder->frameCount()); | |
| 256 EXPECT_FALSE(decoder->failed()); | |
| 257 | |
| 258 decoder->frameBufferAtIndex(0); | |
| 259 EXPECT_FALSE(decoder->failed()); | |
| 260 decoder->frameBufferAtIndex(1); | |
| 261 EXPECT_TRUE(decoder->failed()); | |
| 262 } | |
| 263 | |
| 264 TEST(GIFImageDecoderTest, frameIsComplete) | |
| 265 { | |
| 266 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 267 | |
| 268 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 269 ASSERT_TRUE(data.get()); | |
| 270 decoder->setData(data.get(), true); | |
| 271 | |
| 272 EXPECT_EQ(2u, decoder->frameCount()); | |
| 273 EXPECT_FALSE(decoder->failed()); | |
| 274 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | |
| 275 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1)); | |
| 276 } | |
| 277 | |
| 278 TEST(GIFImageDecoderTest, frameIsCompleteLoading) | |
| 279 { | |
| 280 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 281 | |
| 282 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 283 ASSERT_TRUE(data.get()); | |
| 284 | |
| 285 ASSERT_GE(data->size(), 10u); | |
| 286 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->siz
e() - 10); | |
| 287 decoder->setData(tempData.get(), false); | |
| 288 | |
| 289 EXPECT_EQ(2u, decoder->frameCount()); | |
| 290 EXPECT_FALSE(decoder->failed()); | |
| 291 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | |
| 292 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(1)); | |
| 293 | |
| 294 decoder->setData(data.get(), true); | |
| 295 EXPECT_EQ(2u, decoder->frameCount()); | |
| 296 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | |
| 297 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1)); | |
| 298 } | |
| 299 | |
| 300 TEST(GIFImageDecoderTest, badTerminator) | |
| 301 { | |
| 302 RefPtr<SharedBuffer> referenceData = readFile("/Source/WebKit/chromium/tests
/data/radient.gif"); | |
| 303 RefPtr<SharedBuffer> testData = readFile("/Source/WebKit/chromium/tests/data
/radient-bad-terminator.gif"); | |
| 304 ASSERT_TRUE(referenceData.get()); | |
| 305 ASSERT_TRUE(testData.get()); | |
| 306 | |
| 307 OwnPtr<GIFImageDecoder> referenceDecoder(createDecoder()); | |
| 308 referenceDecoder->setData(referenceData.get(), true); | |
| 309 EXPECT_EQ(1u, referenceDecoder->frameCount()); | |
| 310 ImageFrame* referenceFrame = referenceDecoder->frameBufferAtIndex(0); | |
| 311 ASSERT(referenceFrame); | |
| 312 | |
| 313 OwnPtr<GIFImageDecoder> testDecoder(createDecoder()); | |
| 314 testDecoder->setData(testData.get(), true); | |
| 315 EXPECT_EQ(1u, testDecoder->frameCount()); | |
| 316 ImageFrame* testFrame = testDecoder->frameBufferAtIndex(0); | |
| 317 ASSERT(testFrame); | |
| 318 | |
| 319 EXPECT_EQ(hashSkBitmap(referenceFrame->getSkBitmap()), hashSkBitmap(testFram
e->getSkBitmap())); | |
| 320 } | |
| 321 | |
| 322 #endif | |
| 323 | |
| 324 } // namespace | |
| OLD | NEW |