| 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 "core/platform/FileSystem.h" | |
| 36 #include "core/platform/SharedBuffer.h" | |
| 37 #include "public/platform/Platform.h" | |
| 38 #include "public/platform/WebData.h" | |
| 39 #include "public/platform/WebSize.h" | |
| 40 #include "public/platform/WebUnitTestSupport.h" | |
| 41 #include "wtf/OwnPtr.h" | |
| 42 #include "wtf/PassOwnPtr.h" | |
| 43 #include "wtf/StringHasher.h" | |
| 44 #include "wtf/Vector.h" | |
| 45 | |
| 46 #include <gtest/gtest.h> | |
| 47 | |
| 48 using namespace WebCore; | |
| 49 using namespace WebKit; | |
| 50 | |
| 51 namespace { | |
| 52 | |
| 53 #if !OS(ANDROID) | |
| 54 | |
| 55 static PassRefPtr<SharedBuffer> readFile(const char* fileName) | |
| 56 { | |
| 57 String filePath = Platform::current()->unitTestSupport()->webKitRootDir(); | |
| 58 filePath.append(fileName); | |
| 59 | |
| 60 long long fileSize; | |
| 61 if (!getFileSize(filePath, fileSize)) | |
| 62 return 0; | |
| 63 | |
| 64 PlatformFileHandle handle = openFile(filePath, OpenForRead); | |
| 65 int fileLength = static_cast<int>(fileSize); | |
| 66 Vector<char> buffer(fileLength); | |
| 67 readFromFile(handle, buffer.data(), fileLength); | |
| 68 closeFile(handle); | |
| 69 return SharedBuffer::adoptVector(buffer); | |
| 70 } | |
| 71 | |
| 72 static PassOwnPtr<GIFImageDecoder> createDecoder() | |
| 73 { | |
| 74 return adoptPtr(new GIFImageDecoder(ImageSource::AlphaNotPremultiplied, Imag
eSource::GammaAndColorProfileApplied)); | |
| 75 } | |
| 76 | |
| 77 static unsigned hashSkBitmap(const SkBitmap& bitmap) | |
| 78 { | |
| 79 return StringHasher::hashMemory(bitmap.getPixels(), bitmap.getSize()); | |
| 80 } | |
| 81 | |
| 82 TEST(GIFImageDecoderTest, decodeTwoFrames) | |
| 83 { | |
| 84 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 85 | |
| 86 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 87 ASSERT_TRUE(data.get()); | |
| 88 decoder->setData(data.get(), true); | |
| 89 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount()); | |
| 90 | |
| 91 ImageFrame* frame = decoder->frameBufferAtIndex(0); | |
| 92 EXPECT_EQ(ImageFrame::FrameComplete, frame->status()); | |
| 93 EXPECT_EQ(16, frame->getSkBitmap().width()); | |
| 94 EXPECT_EQ(16, frame->getSkBitmap().height()); | |
| 95 | |
| 96 frame = decoder->frameBufferAtIndex(1); | |
| 97 EXPECT_EQ(ImageFrame::FrameComplete, frame->status()); | |
| 98 EXPECT_EQ(16, frame->getSkBitmap().width()); | |
| 99 EXPECT_EQ(16, frame->getSkBitmap().height()); | |
| 100 | |
| 101 EXPECT_EQ(2u, decoder->frameCount()); | |
| 102 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount()); | |
| 103 } | |
| 104 | |
| 105 TEST(GIFImageDecoderTest, parseAndDecode) | |
| 106 { | |
| 107 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 108 | |
| 109 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 110 ASSERT_TRUE(data.get()); | |
| 111 decoder->setData(data.get(), true); | |
| 112 EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount()); | |
| 113 | |
| 114 // This call will parse the entire file. | |
| 115 EXPECT_EQ(2u, decoder->frameCount()); | |
| 116 | |
| 117 ImageFrame* frame = decoder->frameBufferAtIndex(0); | |
| 118 EXPECT_EQ(ImageFrame::FrameComplete, frame->status()); | |
| 119 EXPECT_EQ(16, frame->getSkBitmap().width()); | |
| 120 EXPECT_EQ(16, frame->getSkBitmap().height()); | |
| 121 | |
| 122 frame = decoder->frameBufferAtIndex(1); | |
| 123 EXPECT_EQ(ImageFrame::FrameComplete, frame->status()); | |
| 124 EXPECT_EQ(16, frame->getSkBitmap().width()); | |
| 125 EXPECT_EQ(16, frame->getSkBitmap().height()); | |
| 126 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount()); | |
| 127 } | |
| 128 | |
| 129 TEST(GIFImageDecoderTest, parseByteByByte) | |
| 130 { | |
| 131 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 132 | |
| 133 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 134 ASSERT_TRUE(data.get()); | |
| 135 | |
| 136 size_t frameCount = 0; | |
| 137 | |
| 138 // Pass data to decoder byte by byte. | |
| 139 for (unsigned length = 1; length <= data->size(); ++length) { | |
| 140 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), lengt
h); | |
| 141 decoder->setData(tempData.get(), length == data->size()); | |
| 142 | |
| 143 EXPECT_LE(frameCount, decoder->frameCount()); | |
| 144 frameCount = decoder->frameCount(); | |
| 145 } | |
| 146 | |
| 147 EXPECT_EQ(2u, decoder->frameCount()); | |
| 148 | |
| 149 decoder->frameBufferAtIndex(0); | |
| 150 decoder->frameBufferAtIndex(1); | |
| 151 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount()); | |
| 152 } | |
| 153 | |
| 154 TEST(GIFImageDecoderTest, parseAndDecodeByteByByte) | |
| 155 { | |
| 156 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 157 | |
| 158 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated-gif-with-offsets.gif"); | |
| 159 ASSERT_TRUE(data.get()); | |
| 160 | |
| 161 size_t frameCount = 0; | |
| 162 size_t framesDecoded = 0; | |
| 163 | |
| 164 // Pass data to decoder byte by byte. | |
| 165 for (unsigned length = 1; length <= data->size(); ++length) { | |
| 166 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), lengt
h); | |
| 167 decoder->setData(tempData.get(), length == data->size()); | |
| 168 | |
| 169 EXPECT_LE(frameCount, decoder->frameCount()); | |
| 170 frameCount = decoder->frameCount(); | |
| 171 | |
| 172 ImageFrame* frame = decoder->frameBufferAtIndex(frameCount - 1); | |
| 173 if (frame && frame->status() == ImageFrame::FrameComplete && framesDecod
ed < frameCount) | |
| 174 ++framesDecoded; | |
| 175 } | |
| 176 | |
| 177 EXPECT_EQ(5u, decoder->frameCount()); | |
| 178 EXPECT_EQ(5u, framesDecoded); | |
| 179 EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount()); | |
| 180 } | |
| 181 | |
| 182 TEST(GIFImageDecoderTest, brokenSecondFrame) | |
| 183 { | |
| 184 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 185 | |
| 186 RefPtr<SharedBuffer> data = readFile("/Source/WebKit/chromium/tests/data/bro
ken.gif"); | |
| 187 ASSERT_TRUE(data.get()); | |
| 188 decoder->setData(data.get(), true); | |
| 189 | |
| 190 // One frame is detected but cannot be decoded. | |
| 191 EXPECT_EQ(1u, decoder->frameCount()); | |
| 192 ImageFrame* frame = decoder->frameBufferAtIndex(1); | |
| 193 EXPECT_FALSE(frame); | |
| 194 } | |
| 195 | |
| 196 TEST(GIFImageDecoderTest, progressiveDecode) | |
| 197 { | |
| 198 RefPtr<SharedBuffer> fullData = readFile("/Source/WebKit/chromium/tests/data
/radient.gif"); | |
| 199 ASSERT_TRUE(fullData.get()); | |
| 200 const size_t fullLength = fullData->size(); | |
| 201 | |
| 202 OwnPtr<GIFImageDecoder> decoder; | |
| 203 ImageFrame* frame; | |
| 204 | |
| 205 Vector<unsigned> truncatedHashes; | |
| 206 Vector<unsigned> progressiveHashes; | |
| 207 | |
| 208 // Compute hashes when the file is truncated. | |
| 209 const size_t increment = 1; | |
| 210 for (size_t i = 1; i <= fullLength; i += increment) { | |
| 211 decoder = createDecoder(); | |
| 212 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i); | |
| 213 decoder->setData(data.get(), i == fullLength); | |
| 214 frame = decoder->frameBufferAtIndex(0); | |
| 215 if (!frame) { | |
| 216 truncatedHashes.append(0); | |
| 217 continue; | |
| 218 } | |
| 219 truncatedHashes.append(hashSkBitmap(frame->getSkBitmap())); | |
| 220 } | |
| 221 | |
| 222 // Compute hashes when the file is progressively decoded. | |
| 223 decoder = createDecoder(); | |
| 224 for (size_t i = 1; i <= fullLength; i += increment) { | |
| 225 RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), i); | |
| 226 decoder->setData(data.get(), i == fullLength); | |
| 227 frame = decoder->frameBufferAtIndex(0); | |
| 228 if (!frame) { | |
| 229 progressiveHashes.append(0); | |
| 230 continue; | |
| 231 } | |
| 232 progressiveHashes.append(hashSkBitmap(frame->getSkBitmap())); | |
| 233 } | |
| 234 | |
| 235 bool match = true; | |
| 236 for (size_t i = 0; i < truncatedHashes.size(); ++i) { | |
| 237 if (truncatedHashes[i] != progressiveHashes[i]) { | |
| 238 match = false; | |
| 239 break; | |
| 240 } | |
| 241 } | |
| 242 EXPECT_TRUE(match); | |
| 243 } | |
| 244 | |
| 245 TEST(GIFImageDecoderTest, allDataReceivedTruncation) | |
| 246 { | |
| 247 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 248 | |
| 249 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 250 ASSERT_TRUE(data.get()); | |
| 251 | |
| 252 ASSERT_GE(data->size(), 10u); | |
| 253 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->siz
e() - 10); | |
| 254 decoder->setData(tempData.get(), true); | |
| 255 | |
| 256 EXPECT_EQ(2u, decoder->frameCount()); | |
| 257 EXPECT_FALSE(decoder->failed()); | |
| 258 | |
| 259 decoder->frameBufferAtIndex(0); | |
| 260 EXPECT_FALSE(decoder->failed()); | |
| 261 decoder->frameBufferAtIndex(1); | |
| 262 EXPECT_TRUE(decoder->failed()); | |
| 263 } | |
| 264 | |
| 265 TEST(GIFImageDecoderTest, frameIsComplete) | |
| 266 { | |
| 267 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 268 | |
| 269 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 270 ASSERT_TRUE(data.get()); | |
| 271 decoder->setData(data.get(), true); | |
| 272 | |
| 273 EXPECT_EQ(2u, decoder->frameCount()); | |
| 274 EXPECT_FALSE(decoder->failed()); | |
| 275 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | |
| 276 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1)); | |
| 277 } | |
| 278 | |
| 279 TEST(GIFImageDecoderTest, frameIsCompleteLoading) | |
| 280 { | |
| 281 OwnPtr<GIFImageDecoder> decoder(createDecoder()); | |
| 282 | |
| 283 RefPtr<SharedBuffer> data = readFile("/LayoutTests/fast/images/resources/ani
mated.gif"); | |
| 284 ASSERT_TRUE(data.get()); | |
| 285 | |
| 286 ASSERT_GE(data->size(), 10u); | |
| 287 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), data->siz
e() - 10); | |
| 288 decoder->setData(tempData.get(), false); | |
| 289 | |
| 290 EXPECT_EQ(2u, decoder->frameCount()); | |
| 291 EXPECT_FALSE(decoder->failed()); | |
| 292 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | |
| 293 EXPECT_FALSE(decoder->frameIsCompleteAtIndex(1)); | |
| 294 | |
| 295 decoder->setData(data.get(), true); | |
| 296 EXPECT_EQ(2u, decoder->frameCount()); | |
| 297 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(0)); | |
| 298 EXPECT_TRUE(decoder->frameIsCompleteAtIndex(1)); | |
| 299 } | |
| 300 | |
| 301 TEST(GIFImageDecoderTest, badTerminator) | |
| 302 { | |
| 303 RefPtr<SharedBuffer> referenceData = readFile("/Source/WebKit/chromium/tests
/data/radient.gif"); | |
| 304 RefPtr<SharedBuffer> testData = readFile("/Source/WebKit/chromium/tests/data
/radient-bad-terminator.gif"); | |
| 305 ASSERT_TRUE(referenceData.get()); | |
| 306 ASSERT_TRUE(testData.get()); | |
| 307 | |
| 308 OwnPtr<GIFImageDecoder> referenceDecoder(createDecoder()); | |
| 309 referenceDecoder->setData(referenceData.get(), true); | |
| 310 EXPECT_EQ(1u, referenceDecoder->frameCount()); | |
| 311 ImageFrame* referenceFrame = referenceDecoder->frameBufferAtIndex(0); | |
| 312 ASSERT(referenceFrame); | |
| 313 | |
| 314 OwnPtr<GIFImageDecoder> testDecoder(createDecoder()); | |
| 315 testDecoder->setData(testData.get(), true); | |
| 316 EXPECT_EQ(1u, testDecoder->frameCount()); | |
| 317 ImageFrame* testFrame = testDecoder->frameBufferAtIndex(0); | |
| 318 ASSERT(testFrame); | |
| 319 | |
| 320 EXPECT_EQ(hashSkBitmap(referenceFrame->getSkBitmap()), hashSkBitmap(testFram
e->getSkBitmap())); | |
| 321 } | |
| 322 | |
| 323 #endif | |
| 324 | |
| 325 } // namespace | |
| OLD | NEW |