Home | History | Annotate | Download | only in graphics
      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