Title: [141020] trunk/Source
Revision
141020
Author
[email protected]
Date
2013-01-28 15:40:01 -0800 (Mon, 28 Jan 2013)

Log Message

adding support for DiscardablePixelRef for caching lazily decoded images
https://bugs.webkit.org/show_bug.cgi?id=106842

Patch by Min Qin <[email protected]> on 2013-01-28
Reviewed by Stephen White.

Source/WebCore:

This change allows using discardable memory in the deferred image decoding path.
Fully decoded images are unpinned and stored in ImageDecodingStore.
Partially decoded images are pinned and stored in ImageDecodingStore.
Discardable memory allocation could fail. Fall back to heap allocation in that case.
There is a separate size limit for heap entries and no limit on discardable entries.
New tests are added to ImageDecodingStoreTests

* WebCore.gypi:
* platform/graphics/chromium/DiscardablePixelRef.cpp: Added.
  Added implementation of the DiscardablePixelRef object that is backed by discardable memory.
  Memory allocated to the DiscardablePixelRef can be purged when it is unlocked.
(WebCore::DiscardablePixelRefAllocator::allocPixelRef):
(WebCore):
(WebCore::DiscardablePixelRef::DiscardablePixelRef):
(WebCore::DiscardablePixelRef::~DiscardablePixelRef):
(WebCore::DiscardablePixelRef::allocAndLockDiscardableMemory):
(WebCore::DiscardablePixelRef::onLockPixels):
(WebCore::DiscardablePixelRef::onUnlockPixels):
(WebCore::DiscardablePixelRef::isDiscardable):
* platform/graphics/chromium/DiscardablePixelRef.h: Added.
  Added class definition of the DiscardablePixelRef.
(WebCore):
(DiscardablePixelRefAllocator):
(DiscardablePixelRef):
* platform/graphics/chromium/ImageDecodingStore.cpp:
  Added new cache replacement strategy for DiscardablePixelRef.
(WebCore::ImageDecodingStore::lockCache):
(WebCore::ImageDecodingStore::overwriteAndLockCache):
(WebCore::ImageDecodingStore::prune):
(WebCore::ImageDecodingStore::insertCacheInternal):
(WebCore::ImageDecodingStore::removeFromCacheInternal):
* platform/graphics/chromium/ImageDecodingStore.h:
  Added isDiscardable() calls to check if a cache entry is discardable.
(WebCore::ImageDecodingStore::CacheEntry::CacheEntry):
(WebCore::ImageDecodingStore::CacheEntry::overwriteCachedImage):
(WebCore::ImageDecodingStore::CacheEntry::isDiscardable):
(CacheEntry):
* platform/graphics/chromium/ImageFrameGenerator.cpp:
  Added some code to pass DiscardableMemoryAllocator to the image decoder.
(WebCore::ImageFrameGenerator::tryToScale):
(WebCore::ImageFrameGenerator::decode):
* platform/graphics/chromium/ImageFrameGenerator.h:
  Added a new member variable of type DiscardableMemoryAllocator.
(ImageFrameGenerator):
* platform/image-decoders/ImageDecoder.h:
  Added methods to pass Allocator to ImageFrame.
(ImageFrame):
(WebCore::ImageFrame::setMemoryAllocator):
(WebCore::ImageFrame::allocator):
(ImageDecoder):
(WebCore::ImageDecoder::setMemoryAllocator):
* platform/image-decoders/skia/ImageDecoderSkia.cpp:
  Added code to allocate pixel memory using the allocator passed from the caller.
(WebCore::ImageFrame::ImageFrame):
(WebCore::ImageFrame::operator=):
(WebCore::ImageFrame::setSize):

Source/WebKit/chromium:

Adding new tests for ImageDecodingStore

* WebKit.gypi:
* tests/ImageDecodingStoreTest.cpp:
(WebCore::ImageDecodingStoreTest::createCompleteImage):
(WebCore::ImageDecodingStoreTest::createIncompleteImage):
(WebCore::TEST_F):
(WebCore):
* tests/MockDiscardablePixelRef.h: Added.
(WebCore):
(MockDiscardablePixelRef):
(WebCore::MockDiscardablePixelRef::MockDiscardablePixelRef):
(WebCore::MockDiscardablePixelRef::~MockDiscardablePixelRef):
(WebCore::MockDiscardablePixelRef::discard):
(WebCore::MockDiscardablePixelRef::onLockPixels):
(WebCore::MockDiscardablePixelRef::onUnlockPixels):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (141019 => 141020)


--- trunk/Source/WebCore/ChangeLog	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebCore/ChangeLog	2013-01-28 23:40:01 UTC (rev 141020)
@@ -1,3 +1,67 @@
+2013-01-28  Min Qin  <[email protected]>
+
+        adding support for DiscardablePixelRef for caching lazily decoded images
+        https://bugs.webkit.org/show_bug.cgi?id=106842
+
+        Reviewed by Stephen White.
+
+        This change allows using discardable memory in the deferred image decoding path.
+        Fully decoded images are unpinned and stored in ImageDecodingStore.
+        Partially decoded images are pinned and stored in ImageDecodingStore.
+        Discardable memory allocation could fail. Fall back to heap allocation in that case.
+        There is a separate size limit for heap entries and no limit on discardable entries.
+        New tests are added to ImageDecodingStoreTests
+
+        * WebCore.gypi:
+        * platform/graphics/chromium/DiscardablePixelRef.cpp: Added.
+          Added implementation of the DiscardablePixelRef object that is backed by discardable memory.
+          Memory allocated to the DiscardablePixelRef can be purged when it is unlocked.
+        (WebCore::DiscardablePixelRefAllocator::allocPixelRef):
+        (WebCore):
+        (WebCore::DiscardablePixelRef::DiscardablePixelRef):
+        (WebCore::DiscardablePixelRef::~DiscardablePixelRef):
+        (WebCore::DiscardablePixelRef::allocAndLockDiscardableMemory):
+        (WebCore::DiscardablePixelRef::onLockPixels):
+        (WebCore::DiscardablePixelRef::onUnlockPixels):
+        (WebCore::DiscardablePixelRef::isDiscardable):
+        * platform/graphics/chromium/DiscardablePixelRef.h: Added.
+          Added class definition of the DiscardablePixelRef.
+        (WebCore):
+        (DiscardablePixelRefAllocator):
+        (DiscardablePixelRef):
+        * platform/graphics/chromium/ImageDecodingStore.cpp:
+          Added new cache replacement strategy for DiscardablePixelRef.
+        (WebCore::ImageDecodingStore::lockCache):
+        (WebCore::ImageDecodingStore::overwriteAndLockCache):
+        (WebCore::ImageDecodingStore::prune):
+        (WebCore::ImageDecodingStore::insertCacheInternal):
+        (WebCore::ImageDecodingStore::removeFromCacheInternal):
+        * platform/graphics/chromium/ImageDecodingStore.h:
+          Added isDiscardable() calls to check if a cache entry is discardable.
+        (WebCore::ImageDecodingStore::CacheEntry::CacheEntry):
+        (WebCore::ImageDecodingStore::CacheEntry::overwriteCachedImage):
+        (WebCore::ImageDecodingStore::CacheEntry::isDiscardable):
+        (CacheEntry):
+        * platform/graphics/chromium/ImageFrameGenerator.cpp:
+          Added some code to pass DiscardableMemoryAllocator to the image decoder.
+        (WebCore::ImageFrameGenerator::tryToScale):
+        (WebCore::ImageFrameGenerator::decode):
+        * platform/graphics/chromium/ImageFrameGenerator.h:
+          Added a new member variable of type DiscardableMemoryAllocator.
+        (ImageFrameGenerator):
+        * platform/image-decoders/ImageDecoder.h:
+          Added methods to pass Allocator to ImageFrame.
+        (ImageFrame):
+        (WebCore::ImageFrame::setMemoryAllocator):
+        (WebCore::ImageFrame::allocator):
+        (ImageDecoder):
+        (WebCore::ImageDecoder::setMemoryAllocator):
+        * platform/image-decoders/skia/ImageDecoderSkia.cpp:
+          Added code to allocate pixel memory using the allocator passed from the caller.
+        (WebCore::ImageFrame::ImageFrame):
+        (WebCore::ImageFrame::operator=):
+        (WebCore::ImageFrame::setSize):
+
 2013-01-28  Sheriff Bot  <[email protected]>
 
         Unreviewed, rolling out r140869.

Modified: trunk/Source/WebCore/WebCore.gypi (141019 => 141020)


--- trunk/Source/WebCore/WebCore.gypi	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebCore/WebCore.gypi	2013-01-28 23:40:01 UTC (rev 141020)
@@ -3867,6 +3867,8 @@
             'platform/graphics/chromium/CrossProcessFontLoading.mm',
             'platform/graphics/chromium/DeferredImageDecoder.cpp',
             'platform/graphics/chromium/DeferredImageDecoder.h',
+            'platform/graphics/chromium/DiscardablePixelRef.cpp',
+            'platform/graphics/chromium/DiscardablePixelRef.h',
             'platform/graphics/chromium/DrawingBufferChromium.cpp',
             'platform/graphics/chromium/Extensions3DChromium.h',
             'platform/graphics/chromium/FontCacheAndroid.cpp',

Added: trunk/Source/WebCore/platform/graphics/chromium/DiscardablePixelRef.cpp (0 => 141020)


--- trunk/Source/WebCore/platform/graphics/chromium/DiscardablePixelRef.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/graphics/chromium/DiscardablePixelRef.cpp	2013-01-28 23:40:01 UTC (rev 141020)
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DiscardablePixelRef.h"
+
+#include <public/Platform.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+namespace {
+
+// URI label for a discardable SkPixelRef.
+const char labelDiscardable[] = "discardable";
+
+} // namespace
+
+
+bool DiscardablePixelRefAllocator::allocPixelRef(SkBitmap* dst, SkColorTable* ctable)
+{
+    Sk64 size = dst->getSize64();
+    if (size.isNeg() || !size.is32())
+        return false;
+
+    SkAutoTUnref<DiscardablePixelRef> pixelRef(new DiscardablePixelRef(ctable, adoptPtr(new SkMutex())));
+    if (pixelRef->allocAndLockDiscardableMemory(size.get32())) {
+        pixelRef->setURI(labelDiscardable);
+        dst->setPixelRef(pixelRef.get());
+        // This method is only called when a DiscardablePixelRef is created to back a SkBitmap.
+        // It is necessary to lock this SkBitmap to have a valid pointer to pixels. Otherwise,
+        // this SkBitmap could be assigned to another SkBitmap and locking/unlocking the other
+        // SkBitmap will make this one losing its pixels.
+        dst->lockPixels();
+        return true;
+    }
+
+    // Fallback to heap allocator if discardable memory is not available.
+    return dst->allocPixels(ctable);
+}
+
+DiscardablePixelRef::DiscardablePixelRef(SkColorTable* ctable, PassOwnPtr<SkMutex> mutex)
+    : SkPixelRef(mutex.get())
+    , m_colorTable(ctable)
+    , m_lockedMemory(0)
+    , m_mutex(mutex)
+{
+}
+
+DiscardablePixelRef::~DiscardablePixelRef()
+{
+    SkSafeUnref(m_colorTable);
+}
+
+bool DiscardablePixelRef::allocAndLockDiscardableMemory(size_t bytes)
+{
+    m_discardable = adoptPtr(WebKit::Platform::current()->allocateAndLockDiscardableMemory(bytes));
+    if (m_discardable) {
+        m_lockedMemory = m_discardable->data();
+        return true;
+    }
+    return false;
+}
+
+void* DiscardablePixelRef::onLockPixels(SkColorTable** ctable)
+{
+    if (!m_lockedMemory && m_discardable->lock())
+        m_lockedMemory = m_discardable->data();
+
+    *ctable = m_colorTable;
+    return m_lockedMemory;
+}
+
+void DiscardablePixelRef::onUnlockPixels()
+{
+    if (m_lockedMemory)
+        m_discardable->unlock();
+    m_lockedMemory = 0;
+}
+
+bool DiscardablePixelRef::isDiscardable(SkPixelRef* pixelRef)
+{
+    // FIXME: DEFINE_STATIC_LOCAL is not thread safe.
+    // ImageDecodingStore provides the synchronization for this.
+    DEFINE_STATIC_LOCAL(const SkString, discardable, (labelDiscardable));
+    return pixelRef && pixelRef->getURI() && discardable.equals(pixelRef->getURI());
+}
+
+} // namespace WebCore
Property changes on: trunk/Source/WebCore/platform/graphics/chromium/DiscardablePixelRef.cpp
___________________________________________________________________

Added: svn:eol-style

Added: trunk/Source/WebCore/platform/graphics/chromium/DiscardablePixelRef.h (0 => 141020)


--- trunk/Source/WebCore/platform/graphics/chromium/DiscardablePixelRef.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/graphics/chromium/DiscardablePixelRef.h	2013-01-28 23:40:01 UTC (rev 141020)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DiscardablePixelRef_h
+#define DiscardablePixelRef_h
+
+#include "SkBitmap.h"
+#include "SkPixelRef.h"
+
+#include <public/WebDiscardableMemory.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+// Class for allocating the DiscardablePixelRef object.
+class DiscardablePixelRefAllocator : public SkBitmap::Allocator {
+    // SkBitmap::Allocator implementation. The discardable memory allocated
+    // after this call is locked and will not be purged until next
+    // onUnlockPixels().
+    virtual bool allocPixelRef(SkBitmap*, SkColorTable*);
+};
+
+// PixelRef object whose memory can be discarded when pixels are unlocked.
+class DiscardablePixelRef : public SkPixelRef {
+public:
+    DiscardablePixelRef(SkColorTable*, PassOwnPtr<SkMutex>);
+    ~DiscardablePixelRef();
+
+    static bool isDiscardable(SkPixelRef*);
+    bool allocAndLockDiscardableMemory(size_t);
+
+    SK_DECLARE_UNFLATTENABLE_OBJECT()
+
+protected:
+    // SkPixelRef implementation.
+    virtual void* onLockPixels(SkColorTable**);
+    virtual void onUnlockPixels();
+
+private:
+    SkColorTable* m_colorTable;
+    void* m_lockedMemory;
+    OwnPtr<WebKit::WebDiscardableMemory> m_discardable;
+    OwnPtr<SkMutex> m_mutex;
+};
+
+} // namespace WebCore
+
+#endif
Property changes on: trunk/Source/WebCore/platform/graphics/chromium/DiscardablePixelRef.h
___________________________________________________________________

Added: svn:eol-style

Modified: trunk/Source/WebCore/platform/graphics/chromium/ImageDecodingStore.cpp (141019 => 141020)


--- trunk/Source/WebCore/platform/graphics/chromium/ImageDecodingStore.cpp	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebCore/platform/graphics/chromium/ImageDecodingStore.cpp	2013-01-28 23:40:01 UTC (rev 141020)
@@ -82,28 +82,37 @@
     ASSERT(cachedImage);
 
     CacheEntry* cacheEntry = 0;
+    Vector<OwnPtr<CacheEntry> > cacheEntriesToDelete;
     {
         MutexLocker lock(m_mutex);
         CacheMap::iterator iter = m_cacheMap.find(std::make_pair(generator, scaledSize));
         if (iter == m_cacheMap.end())
             return false;
         cacheEntry = iter->value.get();
-        if (condition == CacheMustBeComplete && !cacheEntry->cachedImage()->isComplete())
+        ScaledImageFragment* image = cacheEntry->cachedImage();
+        if (condition == CacheMustBeComplete && !image->isComplete())
             return false;
 
         // Incomplete cache entry cannot be used more than once.
-        ASSERT(cacheEntry->cachedImage()->isComplete() || !cacheEntry->useCount());
+        ASSERT(image->isComplete() || !cacheEntry->useCount());
 
-        // Increment use count such that it doesn't get evicted.
-        cacheEntry->incrementUseCount();
+        image->bitmap().lockPixels();
+        if (image->bitmap().getPixels()) {
+            // Increment use count such that it doesn't get evicted.
+            cacheEntry->incrementUseCount();
 
-        // Complete cache entry doesn't have a decoder.
-        ASSERT(!cacheEntry->cachedImage()->isComplete() || !cacheEntry->cachedDecoder());
+            // Complete cache entry doesn't have a decoder.
+            ASSERT(!image->isComplete() || !cacheEntry->cachedDecoder());
 
-        if (decoder)
-            *decoder = cacheEntry->cachedDecoder();
-        *cachedImage = cacheEntry->cachedImage();
-        (*cachedImage)->bitmap().lockPixels();
+            if (decoder)
+                *decoder = cacheEntry->cachedDecoder();
+            *cachedImage = image;
+        } else {
+            image->bitmap().unlockPixels();
+            removeFromCacheInternal(cacheEntry, &cacheEntriesToDelete);
+            removeFromCacheListInternal(cacheEntriesToDelete);
+            return false;
+        }
     }
 
     return true;
@@ -160,6 +169,11 @@
         ASSERT(cacheEntry->useCount() == 1);
         ASSERT(!cacheEntry->cachedImage()->isComplete());
 
+        bool isNewImageDiscardable = DiscardablePixelRef::isDiscardable(newImage->bitmap().pixelRef());
+        if (cacheEntry->isDiscardable() && !isNewImageDiscardable)
+            incrementMemoryUsage(cacheEntry->memoryUsageInBytes());
+        else if (!cacheEntry->isDiscardable() && isNewImageDiscardable)
+            decrementMemoryUsage(cacheEntry->memoryUsageInBytes());
         trash = cacheEntry->overwriteCachedImage(newImage);
         newCachedImage = cacheEntry->cachedImage();
         // Lock the underlying SkBitmap to prevent it from being purged.
@@ -230,7 +244,7 @@
 
         // Walk the list of cache entries starting from the least recently used
         // and then keep them for deletion later.
-        while (cacheEntry && m_memoryUsageInBytes > m_cacheLimitInBytes) {
+        while (cacheEntry && (m_memoryUsageInBytes > m_cacheLimitInBytes || !m_cacheLimitInBytes)) {
             // Cache is not used; Remove it.
             if (!cacheEntry->useCount())
                 removeFromCacheInternal(cacheEntry, &cacheEntriesToDelete);
@@ -244,7 +258,8 @@
 
 void ImageDecodingStore::insertCacheInternal(PassOwnPtr<CacheEntry> cacheEntry)
 {
-    incrementMemoryUsage(cacheEntry->memoryUsageInBytes());
+    if (!cacheEntry->isDiscardable())
+        incrementMemoryUsage(cacheEntry->memoryUsageInBytes());
 
     // m_orderedCacheList is used to support LRU operations to reorder cache
     // entries quickly.
@@ -262,7 +277,8 @@
 
 void ImageDecodingStore::removeFromCacheInternal(const CacheEntry* cacheEntry, Vector<OwnPtr<CacheEntry> >* deletionList)
 {
-    decrementMemoryUsage(cacheEntry->memoryUsageInBytes());
+    if (!cacheEntry->isDiscardable())
+        decrementMemoryUsage(cacheEntry->memoryUsageInBytes());
 
     // Remove from m_cacheMap.
     CacheIdentifier key = cacheEntry->cacheKey();

Modified: trunk/Source/WebCore/platform/graphics/chromium/ImageDecodingStore.h (141019 => 141020)


--- trunk/Source/WebCore/platform/graphics/chromium/ImageDecodingStore.h	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebCore/platform/graphics/chromium/ImageDecodingStore.h	2013-01-28 23:40:01 UTC (rev 141020)
@@ -26,6 +26,7 @@
 #ifndef ImageDecodingStore_h
 #define ImageDecodingStore_h
 
+#include "DiscardablePixelRef.h"
 #include "ImageDecoder.h"
 #include "ScaledImageFragment.h"
 #include "SkTypes.h"
@@ -92,6 +93,7 @@
             , m_cachedImage(image)
             , m_cachedDecoder(decoder)
             , m_useCount(count)
+            , m_isDiscardable(DiscardablePixelRef::isDiscardable(m_cachedImage->bitmap().pixelRef()))
         {
         }
 
@@ -106,6 +108,7 @@
         ImageDecoder* cachedDecoder() const { return m_cachedDecoder.get(); }
         PassOwnPtr<ImageDecoder> overwriteCachedImage(PassOwnPtr<ScaledImageFragment> image)
         {
+            m_isDiscardable = DiscardablePixelRef::isDiscardable(image->bitmap().pixelRef());
             m_cachedImage = image;
             if (m_cachedImage->isComplete())
                 return m_cachedDecoder.release();
@@ -114,6 +117,7 @@
         int useCount() const { return m_useCount; }
         void incrementUseCount() { ++m_useCount; }
         void decrementUseCount() { --m_useCount; ASSERT(m_useCount >= 0); }
+        bool isDiscardable() const { return m_isDiscardable; }
 
         // FIXME: getSafeSize() returns size in bytes truncated to a 32-bits integer.
         //        Find a way to get the size in 64-bits.
@@ -126,6 +130,7 @@
         OwnPtr<ScaledImageFragment> m_cachedImage;
         OwnPtr<ImageDecoder> m_cachedDecoder;
         int m_useCount;
+        bool m_isDiscardable;
     };
 
     ImageDecodingStore();

Modified: trunk/Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp (141019 => 141020)


--- trunk/Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp	2013-01-28 23:40:01 UTC (rev 141020)
@@ -112,8 +112,13 @@
     if (!fullSizeImage && !ImageDecodingStore::instance()->lockCache(this, m_fullSize, ImageDecodingStore::CacheMustBeComplete, &fullSizeImage))
         return 0;
 
-    SkBitmap scaledBitmap = skia::ImageOperations::Resize(
-        fullSizeImage->bitmap(), resizeMethod(), scaledSize.width(), scaledSize.height());
+    DiscardablePixelRefAllocator allocator;
+    // This call allocates the DiscardablePixelRef and lock/unlocks it
+    // afterwards. So the memory allocated to the scaledBitmap can be
+    // discarded after this call. Need to lock the scaledBitmap and
+    // check the pixels before using it next time.
+    SkBitmap scaledBitmap = skia::ImageOperations::Resize(fullSizeImage->bitmap(), resizeMethod(), scaledSize.width(), scaledSize.height(), &allocator);
+
     OwnPtr<ScaledImageFragment> scaledImage = ScaledImageFragment::create(scaledSize, scaledBitmap, fullSizeImage->isComplete());
 
     ImageDecodingStore::instance()->unlockCache(this, fullSizeImage);
@@ -189,7 +194,15 @@
             return nullptr;
     }
 
+    // TODO: this is very ugly. We need to refactor the way how we can pass a
+    // memory allocator to image decoders.
+    (*decoder)->setMemoryAllocator(&m_allocator);
     (*decoder)->setData(data, allDataReceived);
+    // If this call returns a newly allocated DiscardablePixelRef, then
+    // ImageFrame::m_bitmap and the contained DiscardablePixelRef are locked.
+    // They will be unlocked when ImageDecoder is destroyed since ImageDecoder
+    // owns the ImageFrame. Partially decoded SkBitmap is thus inserted into the
+    // ImageDecodingStore while locked.
     ImageFrame* frame = (*decoder)->frameBufferAtIndex(0);
     (*decoder)->setData(0, false); // Unref SharedBuffer from ImageDecoder.
 

Modified: trunk/Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.h (141019 => 141020)


--- trunk/Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.h	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.h	2013-01-28 23:40:01 UTC (rev 141020)
@@ -26,6 +26,7 @@
 #ifndef ImageFrameGenerator_h
 #define ImageFrameGenerator_h
 
+#include "DiscardablePixelRef.h"
 #include "SkTypes.h"
 #include "SkBitmap.h"
 #include "SkSize.h"
@@ -79,6 +80,7 @@
     SkISize m_fullSize;
     ThreadSafeDataTransport m_data;
     bool m_decodeFailedAndEmpty;
+    DiscardablePixelRefAllocator m_allocator;
 
     OwnPtr<ImageDecoderFactory> m_imageDecoderFactory;
 

Modified: trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h (141019 => 141020)


--- trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h	2013-01-28 23:40:01 UTC (rev 141020)
@@ -157,6 +157,13 @@
         {
             return m_bitmap.bitmap();
         }
+
+        void setMemoryAllocator(SkBitmap::Allocator* allocator)
+        {
+            m_allocator = allocator;
+        }
+
+        SkBitmap::Allocator* allocator() const { return m_allocator; }
 #endif
 
         // Use fix point multiplier instead of integer division or floating point math.
@@ -212,6 +219,7 @@
 
 #if USE(SKIA)
         NativeImageSkia m_bitmap;
+        SkBitmap::Allocator* m_allocator;
 #else
         Vector<PixelData> m_backingStore;
         PixelData* m_bytes; // The memory is backed by m_backingStore.
@@ -406,6 +414,15 @@
 
         virtual void reportMemoryUsage(MemoryObjectInfo*) const;
 
+#if USE(SKIA)
+        virtual void setMemoryAllocator(SkBitmap::Allocator* allocator)
+        {
+            // FIXME: this doesn't work for images with multiple frames.
+            if (m_frameBufferCache.isEmpty())
+                m_frameBufferCache.resize(1);
+            m_frameBufferCache[0].setMemoryAllocator(allocator);
+        }
+#endif
     protected:
         void prepareScaleDataIfNecessary();
         int upperBoundScaledX(int origX, int searchStart = 0);

Modified: trunk/Source/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp (141019 => 141020)


--- trunk/Source/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp	2013-01-28 23:40:01 UTC (rev 141020)
@@ -32,7 +32,8 @@
 namespace WebCore {
 
 ImageFrame::ImageFrame()
-    : m_hasAlpha(false)
+    : m_allocator(0)
+    , m_hasAlpha(false)
     , m_status(FrameEmpty)
     , m_duration(0)
     , m_disposalMethod(DisposeNotSpecified)
@@ -49,6 +50,7 @@
     // Keep the pixels locked since we will be writing directly into the
     // bitmap throughout this object's lifetime.
     m_bitmap.bitmap().lockPixels();
+    setMemoryAllocator(other.allocator());
     setOriginalFrameRect(other.originalFrameRect());
     setStatus(other.status());
     setDuration(other.duration());
@@ -93,7 +95,7 @@
     ASSERT(!width() && !height());
 
     m_bitmap.bitmap().setConfig(SkBitmap::kARGB_8888_Config, newWidth, newHeight);
-    if (!m_bitmap.bitmap().allocPixels())
+    if (!m_bitmap.bitmap().allocPixels(m_allocator, 0))
         return false;
 
     zeroFillPixelData();

Modified: trunk/Source/WebKit/chromium/ChangeLog (141019 => 141020)


--- trunk/Source/WebKit/chromium/ChangeLog	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebKit/chromium/ChangeLog	2013-01-28 23:40:01 UTC (rev 141020)
@@ -1,3 +1,35 @@
+2013-01-28  Min Qin  <[email protected]>
+
+        adding support for DiscardablePixelRef for caching lazily decoded images
+        https://bugs.webkit.org/show_bug.cgi?id=106842
+
+        Reviewed by Stephen White.
+
+        Adding new tests for ImageDecodingStore
+
+        * WebKit.gypi:
+        * tests/ImageDecodingStoreTest.cpp:
+        (WebCore::ImageDecodingStoreTest::createCompleteImage):
+        (WebCore::ImageDecodingStoreTest::createIncompleteImage):
+        (WebCore::TEST_F):
+        (WebCore):
+        * tests/MockDiscardablePixelRef.h: Added.
+        (WebCore):
+        (MockDiscardablePixelRef):
+        (WebCore::MockDiscardablePixelRef::MockDiscardablePixelRef):
+        (WebCore::MockDiscardablePixelRef::~MockDiscardablePixelRef):
+        (WebCore::MockDiscardablePixelRef::discard):
+        (WebCore::MockDiscardablePixelRef::onLockPixels):
+        (WebCore::MockDiscardablePixelRef::onUnlockPixels):
+
+2013-01-28  Stephen Chenney  <[email protected]>
+
+        [Chromium] Fix the build.
+
+        Unreviewed build fix.
+
+        * src/AssertMatchingEnums.cpp: Move the include to the right place and remove the bad directory prefix.
+
 2013-01-28  Dan Alcantara  <[email protected]>
 
         [Chromium, Mobile] Do not show disambiguation pop up in mobile sites

Modified: trunk/Source/WebKit/chromium/WebKit.gypi (141019 => 141020)


--- trunk/Source/WebKit/chromium/WebKit.gypi	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebKit/chromium/WebKit.gypi	2013-01-28 23:40:01 UTC (rev 141020)
@@ -83,6 +83,7 @@
             'tests/ImageDecodingStoreTest.cpp',
             'tests/ImageFrameGeneratorTest.cpp',
             'tests/ImageLayerChromiumTest.cpp',
+            'tests/MockDiscardablePixelRef.h',
             'tests/MockImageDecoder.h',
             'tests/KeyboardTest.cpp',
             'tests/KURLTest.cpp',

Modified: trunk/Source/WebKit/chromium/tests/ImageDecodingStoreTest.cpp (141019 => 141020)


--- trunk/Source/WebKit/chromium/tests/ImageDecodingStoreTest.cpp	2013-01-28 23:38:14 UTC (rev 141019)
+++ trunk/Source/WebKit/chromium/tests/ImageDecodingStoreTest.cpp	2013-01-28 23:40:01 UTC (rev 141020)
@@ -28,6 +28,7 @@
 #include "ImageDecodingStore.h"
 
 #include "ImageFrameGenerator.h"
+#include "MockDiscardablePixelRef.h"
 #include "MockImageDecoder.h"
 #include "SharedBuffer.h"
 #include <gtest/gtest.h>
@@ -68,19 +69,25 @@
     }
 
 protected:
-    PassOwnPtr<ScaledImageFragment> createCompleteImage(const SkISize& size)
+    PassOwnPtr<ScaledImageFragment> createCompleteImage(const SkISize& size, bool discardable = false)
     {
         SkBitmap bitmap;
         bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
-        bitmap.allocPixels();
+        if (!discardable)
+            bitmap.allocPixels();
+        else
+            bitmap.setPixelRef(new MockDiscardablePixelRef())->unref();
         return ScaledImageFragment::create(size, bitmap, true);
     }
 
-    PassOwnPtr<ScaledImageFragment> createIncompleteImage(const SkISize& size)
+    PassOwnPtr<ScaledImageFragment> createIncompleteImage(const SkISize& size, bool discardable = false)
     {
         SkBitmap bitmap;
         bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
-        bitmap.allocPixels();
+        if (!discardable)
+            bitmap.allocPixels();
+        else
+            bitmap.setPixelRef(new MockDiscardablePixelRef())->unref();
         return ScaledImageFragment::create(size, bitmap, false);
     }
 
@@ -281,4 +288,59 @@
     ImageDecodingStore::instance()->unlockCache(m_generator.get(), cachedImage);
 }
 
+TEST_F(ImageDecodingStoreTest, lockCacheFailedAfterMemoryDiscarded)
+{
+    const ScaledImageFragment* cachedImage = ImageDecodingStore::instance()->insertAndLockCache(
+        m_generator.get(), createCompleteImage(SkISize::Make(1, 1), true), MockImageDecoder::create(this));
+    unlockCache(cachedImage);
+    MockDiscardablePixelRef* pixelRef = static_cast<MockDiscardablePixelRef*>(cachedImage->bitmap().pixelRef());
+    pixelRef->discard();
+    EXPECT_EQ(0, lockCache(SkISize::Make(1, 1)));
+    EXPECT_EQ(0u, ImageDecodingStore::instance()->cacheEntries());
+}
+
+TEST_F(ImageDecodingStoreTest, overwriteNonDiscardableCacheWithDiscardable)
+{
+
+    const SkISize size = SkISize::Make(1, 1);
+    const ScaledImageFragment* cachedImage = ImageDecodingStore::instance()->insertAndLockCache(
+        m_generator.get(), createIncompleteImage(size), MockImageDecoder::create(this));
+    ImageDecodingStore::instance()->unlockCache(m_generator.get(), cachedImage);
+    EXPECT_EQ(1u, ImageDecodingStore::instance()->cacheEntries());
+    EXPECT_LT(0u, ImageDecodingStore::instance()->memoryUsageInBytes());
+
+    ImageDecoder* decoder = 0;
+    EXPECT_TRUE(ImageDecodingStore::instance()->lockCache(m_generator.get(), size, ImageDecodingStore::CacheCanBeIncomplete, &cachedImage, &decoder));
+    EXPECT_FALSE(cachedImage->isComplete());
+
+    cachedImage = ImageDecodingStore::instance()->overwriteAndLockCache(
+        m_generator.get(), cachedImage, createCompleteImage(size, true));
+    EXPECT_TRUE(cachedImage->isComplete());
+    EXPECT_EQ(1u, ImageDecodingStore::instance()->cacheEntries());
+    EXPECT_EQ(0u, ImageDecodingStore::instance()->memoryUsageInBytes());
+    ImageDecodingStore::instance()->unlockCache(m_generator.get(), cachedImage);
+}
+
+TEST_F(ImageDecodingStoreTest, overwriteDiscardableCacheWithNonDiscardable)
+{
+
+    const SkISize size = SkISize::Make(1, 1);
+    const ScaledImageFragment* cachedImage = ImageDecodingStore::instance()->insertAndLockCache(
+        m_generator.get(), createIncompleteImage(size, true), MockImageDecoder::create(this));
+    ImageDecodingStore::instance()->unlockCache(m_generator.get(), cachedImage);
+    EXPECT_EQ(1u, ImageDecodingStore::instance()->cacheEntries());
+    EXPECT_EQ(0u, ImageDecodingStore::instance()->memoryUsageInBytes());
+
+    ImageDecoder* decoder = 0;
+    EXPECT_TRUE(ImageDecodingStore::instance()->lockCache(m_generator.get(), size, ImageDecodingStore::CacheCanBeIncomplete, &cachedImage, &decoder));
+    EXPECT_FALSE(cachedImage->isComplete());
+
+    cachedImage = ImageDecodingStore::instance()->overwriteAndLockCache(
+        m_generator.get(), cachedImage, createCompleteImage(size));
+    EXPECT_TRUE(cachedImage->isComplete());
+    EXPECT_EQ(1u, ImageDecodingStore::instance()->cacheEntries());
+    EXPECT_LT(0u, ImageDecodingStore::instance()->memoryUsageInBytes());
+    ImageDecodingStore::instance()->unlockCache(m_generator.get(), cachedImage);
+}
+
 } // namespace

Added: trunk/Source/WebKit/chromium/tests/MockDiscardablePixelRef.h (0 => 141020)


--- trunk/Source/WebKit/chromium/tests/MockDiscardablePixelRef.h	                        (rev 0)
+++ trunk/Source/WebKit/chromium/tests/MockDiscardablePixelRef.h	2013-01-28 23:40:01 UTC (rev 141020)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MockDiscardablePixelRef_h
+
+#include "SkBitmap.h"
+#include "SkPixelRef.h"
+
+namespace WebCore {
+
+class MockDiscardablePixelRef : public SkPixelRef {
+public:
+    MockDiscardablePixelRef() : discarded(false) { setURI("discardable"); }
+    ~MockDiscardablePixelRef() { }
+
+    void discard()
+    {
+        ASSERT(!m_lockedMemory);
+        discarded = true;
+    }
+
+    SK_DECLARE_UNFLATTENABLE_OBJECT()
+
+protected:
+    // SkPixelRef implementation.
+    virtual void* onLockPixels(SkColorTable**)
+    {
+        if (discarded)
+            return 0;
+        m_lockedMemory = &discarded;
+        return m_lockedMemory;
+    }
+
+    virtual void onUnlockPixels()
+    {
+        m_lockedMemory = 0;
+    }
+
+private:
+    void* m_lockedMemory;
+    bool discarded;
+};
+
+} // namespace WebCore
+
+#endif // MockDiscardablePixelRef_h
Property changes on: trunk/Source/WebKit/chromium/tests/MockDiscardablePixelRef.h
___________________________________________________________________

Added: svn:eol-style

_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to