1 /* 2 * Copyright (C) 2012 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 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "platform/graphics/ImageFrameGenerator.h" 28 29 #include "platform/SharedBuffer.h" 30 #include "platform/Task.h" 31 #include "platform/graphics/ImageDecodingStore.h" 32 #include "platform/graphics/test/MockImageDecoder.h" 33 #include "public/platform/Platform.h" 34 #include "public/platform/WebThread.h" 35 #include <gtest/gtest.h> 36 37 namespace WebCore { 38 39 namespace { 40 41 // Helper methods to generate standard sizes. 42 SkISize fullSize() { return SkISize::Make(100, 100); } 43 44 } // namespace 45 46 class ImageFrameGeneratorTest : public ::testing::Test, public MockImageDecoderClient { 47 public: 48 virtual void SetUp() OVERRIDE 49 { 50 ImageDecodingStore::instance()->setCacheLimitInBytes(1024 * 1024); 51 ImageDecodingStore::instance()->setImageCachingEnabled(true); 52 m_data = SharedBuffer::create(); 53 m_generator = ImageFrameGenerator::create(fullSize(), m_data, false); 54 useMockImageDecoderFactory(); 55 m_decodersDestroyed = 0; 56 m_frameBufferRequestCount = 0; 57 m_status = ImageFrame::FrameEmpty; 58 } 59 60 virtual void TearDown() OVERRIDE 61 { 62 ImageDecodingStore::instance()->clear(); 63 } 64 65 virtual void decoderBeingDestroyed() OVERRIDE 66 { 67 ++m_decodersDestroyed; 68 } 69 70 virtual void frameBufferRequested() OVERRIDE 71 { 72 ++m_frameBufferRequestCount; 73 } 74 75 virtual ImageFrame::Status status() OVERRIDE 76 { 77 ImageFrame::Status currentStatus = m_status; 78 m_status = m_nextFrameStatus; 79 return currentStatus; 80 } 81 82 virtual size_t frameCount() OVERRIDE { return 1; } 83 virtual int repetitionCount() const OVERRIDE { return cAnimationNone; } 84 virtual float frameDuration() const OVERRIDE { return 0; } 85 86 protected: 87 void useMockImageDecoderFactory() 88 { 89 m_generator->setImageDecoderFactory(MockImageDecoderFactory::create(this, fullSize())); 90 } 91 92 PassOwnPtr<ScaledImageFragment> createCompleteImage(const SkISize& size) 93 { 94 SkBitmap bitmap; 95 if (!bitmap.allocN32Pixels(size.width(), size.height())) 96 return nullptr; 97 return ScaledImageFragment::createComplete(size, 0, bitmap); 98 } 99 100 void addNewData() 101 { 102 m_data->append("g", 1); 103 m_generator->setData(m_data, false); 104 } 105 106 void setFrameStatus(ImageFrame::Status status) { m_status = m_nextFrameStatus = status; } 107 void setNextFrameStatus(ImageFrame::Status status) { m_nextFrameStatus = status; } 108 109 SkBitmap::Allocator* allocator() const { return m_generator->allocator(); } 110 void setAllocator(PassOwnPtr<SkBitmap::Allocator> allocator) 111 { 112 m_generator->setAllocator(allocator); 113 } 114 115 PassOwnPtr<ScaledImageFragment> decode(size_t index) 116 { 117 ImageDecoder* decoder = 0; 118 OwnPtr<ScaledImageFragment> fragment = m_generator->decode(index, &decoder); 119 delete decoder; 120 return fragment.release(); 121 } 122 123 RefPtr<SharedBuffer> m_data; 124 RefPtr<ImageFrameGenerator> m_generator; 125 int m_decodersDestroyed; 126 int m_frameBufferRequestCount; 127 ImageFrame::Status m_status; 128 ImageFrame::Status m_nextFrameStatus; 129 }; 130 131 TEST_F(ImageFrameGeneratorTest, cacheHit) 132 { 133 OwnPtr<ScaledImageFragment> completeImageTemp = createCompleteImage(fullSize()); 134 ASSERT_TRUE(completeImageTemp); 135 const ScaledImageFragment* fullImage = ImageDecodingStore::instance()->insertAndLockCache( 136 m_generator.get(), completeImageTemp.release()); 137 EXPECT_EQ(fullSize(), fullImage->scaledSize()); 138 ImageDecodingStore::instance()->unlockCache(m_generator.get(), fullImage); 139 140 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(fullSize()); 141 EXPECT_EQ(fullImage, tempImage); 142 EXPECT_EQ(fullSize(), tempImage->scaledSize()); 143 EXPECT_TRUE(m_generator->hasAlpha(0)); 144 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); 145 EXPECT_EQ(0, m_frameBufferRequestCount); 146 } 147 148 TEST_F(ImageFrameGeneratorTest, cacheMissWithIncompleteDecode) 149 { 150 setFrameStatus(ImageFrame::FramePartial); 151 152 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(fullSize()); 153 EXPECT_FALSE(tempImage->isComplete()); 154 EXPECT_EQ(1, m_frameBufferRequestCount); 155 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); 156 EXPECT_EQ(2, ImageDecodingStore::instance()->cacheEntries()); 157 EXPECT_EQ(1, ImageDecodingStore::instance()->imageCacheEntries()); 158 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); 159 160 addNewData(); 161 tempImage = m_generator->decodeAndScale(fullSize()); 162 EXPECT_FALSE(tempImage->isComplete()); 163 EXPECT_EQ(2, m_frameBufferRequestCount); 164 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); 165 EXPECT_EQ(3, ImageDecodingStore::instance()->cacheEntries()); 166 EXPECT_EQ(2, ImageDecodingStore::instance()->imageCacheEntries()); 167 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); 168 EXPECT_EQ(0, m_decodersDestroyed); 169 } 170 171 TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesComplete) 172 { 173 setFrameStatus(ImageFrame::FramePartial); 174 175 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(fullSize()); 176 EXPECT_FALSE(tempImage->isComplete()); 177 EXPECT_EQ(1, m_frameBufferRequestCount); 178 EXPECT_EQ(0, m_decodersDestroyed); 179 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); 180 EXPECT_EQ(2, ImageDecodingStore::instance()->cacheEntries()); 181 EXPECT_EQ(1, ImageDecodingStore::instance()->imageCacheEntries()); 182 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); 183 184 setFrameStatus(ImageFrame::FrameComplete); 185 addNewData(); 186 187 tempImage = m_generator->decodeAndScale(fullSize()); 188 EXPECT_TRUE(tempImage->isComplete()); 189 EXPECT_EQ(2, m_frameBufferRequestCount); 190 EXPECT_EQ(1, m_decodersDestroyed); 191 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); 192 EXPECT_EQ(2, ImageDecodingStore::instance()->cacheEntries()); 193 EXPECT_EQ(2, ImageDecodingStore::instance()->imageCacheEntries()); 194 EXPECT_EQ(0, ImageDecodingStore::instance()->decoderCacheEntries()); 195 196 tempImage = m_generator->decodeAndScale(fullSize()); 197 EXPECT_TRUE(tempImage->isComplete()); 198 EXPECT_EQ(2, m_frameBufferRequestCount); 199 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); 200 } 201 202 static void decodeThreadMain(ImageFrameGenerator* generator) 203 { 204 const ScaledImageFragment* tempImage = generator->decodeAndScale(fullSize()); 205 ImageDecodingStore::instance()->unlockCache(generator, tempImage); 206 } 207 208 TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesCompleteMultiThreaded) 209 { 210 setFrameStatus(ImageFrame::FramePartial); 211 212 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(fullSize()); 213 EXPECT_FALSE(tempImage->isComplete()); 214 EXPECT_EQ(1, m_frameBufferRequestCount); 215 EXPECT_EQ(0, m_decodersDestroyed); 216 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); 217 EXPECT_EQ(2, ImageDecodingStore::instance()->cacheEntries()); 218 EXPECT_EQ(1, ImageDecodingStore::instance()->imageCacheEntries()); 219 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); 220 221 // LocalFrame can now be decoded completely. 222 setFrameStatus(ImageFrame::FrameComplete); 223 addNewData(); 224 OwnPtr<blink::WebThread> thread = adoptPtr(blink::Platform::current()->createThread("DecodeThread")); 225 thread->postTask(new Task(WTF::bind(&decodeThreadMain, m_generator.get()))); 226 thread.clear(); 227 228 EXPECT_EQ(2, m_frameBufferRequestCount); 229 EXPECT_EQ(1, m_decodersDestroyed); 230 EXPECT_EQ(2, ImageDecodingStore::instance()->cacheEntries()); 231 EXPECT_EQ(2, ImageDecodingStore::instance()->imageCacheEntries()); 232 EXPECT_EQ(0, ImageDecodingStore::instance()->decoderCacheEntries()); 233 234 tempImage = m_generator->decodeAndScale(fullSize()); 235 EXPECT_TRUE(tempImage->isComplete()); 236 EXPECT_EQ(2, m_frameBufferRequestCount); 237 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); 238 } 239 240 TEST_F(ImageFrameGeneratorTest, incompleteBitmapCopied) 241 { 242 setFrameStatus(ImageFrame::FramePartial); 243 244 const ScaledImageFragment* tempImage= m_generator->decodeAndScale(fullSize()); 245 EXPECT_FALSE(tempImage->isComplete()); 246 EXPECT_EQ(1, m_frameBufferRequestCount); 247 248 ImageDecoder* tempDecoder = 0; 249 EXPECT_TRUE(ImageDecodingStore::instance()->lockDecoder(m_generator.get(), fullSize(), &tempDecoder)); 250 ASSERT_TRUE(tempDecoder); 251 EXPECT_NE(tempDecoder->frameBufferAtIndex(0)->getSkBitmap().getPixels(), tempImage->bitmap().getPixels()); 252 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); 253 ImageDecodingStore::instance()->unlockDecoder(m_generator.get(), tempDecoder); 254 } 255 256 TEST_F(ImageFrameGeneratorTest, resumeDecodeEmptyFrameTurnsComplete) 257 { 258 m_generator = ImageFrameGenerator::create(fullSize(), m_data, false, true); 259 useMockImageDecoderFactory(); 260 setFrameStatus(ImageFrame::FrameComplete); 261 262 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(fullSize(), 0); 263 EXPECT_TRUE(tempImage->isComplete()); 264 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); 265 266 setFrameStatus(ImageFrame::FrameEmpty); 267 setNextFrameStatus(ImageFrame::FrameComplete); 268 EXPECT_FALSE(m_generator->decodeAndScale(fullSize(), 1)); 269 } 270 271 TEST_F(ImageFrameGeneratorTest, frameHasAlpha) 272 { 273 setFrameStatus(ImageFrame::FramePartial); 274 ImageDecodingStore::instance()->unlockCache(m_generator.get(), m_generator->decodeAndScale(fullSize(), 1)); 275 EXPECT_TRUE(m_generator->hasAlpha(1)); 276 277 ImageDecoder* tempDecoder = 0; 278 EXPECT_TRUE(ImageDecodingStore::instance()->lockDecoder(m_generator.get(), fullSize(), &tempDecoder)); 279 ASSERT_TRUE(tempDecoder); 280 static_cast<MockImageDecoder*>(tempDecoder)->setFrameHasAlpha(false); 281 ImageDecodingStore::instance()->unlockDecoder(m_generator.get(), tempDecoder); 282 283 setFrameStatus(ImageFrame::FrameComplete); 284 ImageDecodingStore::instance()->unlockCache(m_generator.get(), m_generator->decodeAndScale(fullSize(), 1)); 285 EXPECT_FALSE(m_generator->hasAlpha(1)); 286 } 287 288 namespace { 289 290 class MockAllocator : public SkBitmap::Allocator { 291 public: 292 // N starts from 0. 293 MockAllocator(int failAtNthCall) 294 : m_callCount(0) 295 , m_failAtNthCall(failAtNthCall) 296 , m_defaultAllocator(adoptPtr(new DiscardablePixelRefAllocator())) 297 { 298 } 299 300 virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* colorTable) OVERRIDE 301 { 302 if (m_callCount++ == m_failAtNthCall) 303 return false; 304 return m_defaultAllocator->allocPixelRef(bitmap, colorTable); 305 } 306 307 int m_callCount; 308 int m_failAtNthCall; 309 OwnPtr<SkBitmap::Allocator> m_defaultAllocator; 310 }; 311 312 } // namespace 313 314 TEST_F(ImageFrameGeneratorTest, decodingAllocatorFailure) 315 { 316 // Try to emulate allocation failures at different stages. For now, the 317 // first allocation is for the bitmap in ImageFrame, the second is for the 318 // copy of partial bitmap. The loop will still work if the number or purpose 319 // of allocations change in the future. 320 for (int i = 0; ; ++i) { 321 SCOPED_TRACE(testing::Message() << "Allocation failure at call " << i); 322 setFrameStatus(ImageFrame::FramePartial); 323 setAllocator(adoptPtr(new MockAllocator(i))); 324 OwnPtr<ScaledImageFragment> image = decode(0); 325 if (i >= static_cast<MockAllocator*>(allocator())->m_callCount) { 326 // We have tested failures of all stages. This time all allocations 327 // were successful. 328 EXPECT_TRUE(image); 329 break; 330 } 331 EXPECT_FALSE(image); 332 } 333 } 334 335 } // namespace WebCore 336