Title: [147265] trunk/Source/WebCore
Revision
147265
Author
[email protected]
Date
2013-03-29 17:51:57 -0700 (Fri, 29 Mar 2013)

Log Message

When releasing a CGImage, we should also remove it from the subimage cache.
https://bugs.webkit.org/show_bug.cgi?id=102453

Patch by Yongjun Zhang <[email protected]> on 2013-03-29
Reviewed by Simon Fraser.

When we release an image(CGImageRef) from BitmapImage's cachedFrames, if the image was already
cached in subimage cache, it's ref count won't drop to 0 and the image won't be deleted.  Usually,
the subimage cache will clear the whole cache in a timer with 1 sec delay.  However, if WebCore has
to paint another subimage (not necessarily from the same CGImageRef) before this timer fires, we
will restart the timer and images inside the cache will stay longer than they should.

This patch does two things:
    - move SubimageCacheWithTimer and related helper struct into a separate file.
    - remove the image from subimage cache when we releasing the CGImageRef, this prevent subimage
cache holding the image after we released it.

No new tests, manually verified the CGImageRef is also removed from subimage cache
when we releasing the image from FrameData::clear.

* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* platform/graphics/cg/BitmapImageCG.cpp:
(WebCore::FrameData::clear): remove the image from subimage cache before we releasing it.
* platform/graphics/cg/GraphicsContextCG.cpp:
(WebCore):
(WebCore::GraphicsContext::drawNativeImage):
* platform/graphics/cg/SubimageCacheWithTimer.cpp: Added.
(WebCore):
(SubimageRequest):
(WebCore::SubimageRequest::SubimageRequest):
(WebCore::SubimageCacheAdder::hash):
(SubimageCacheAdder):
(WebCore::SubimageCacheAdder::equal):
(WebCore::SubimageCacheAdder::translate):
(WebCore::SubimageCacheWithTimer::SubimageCacheWithTimer):
(WebCore::SubimageCacheWithTimer::invalidateCacheTimerFired):
(WebCore::SubimageCacheWithTimer::getSubimage):
(WebCore::SubimageCacheWithTimer::clearImage):
(WebCore::subimageCache):
* platform/graphics/cg/SubimageCacheWithTimer.h: Added.
(WebCore):
(SubimageCacheWithTimer): Added a data member m_images to record which image and its subimages are cached.
(SubimageCacheEntry):
(SubimageCacheEntryTraits):
(WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits::isEmptyValue):
(WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits::constructDeletedValue):
(WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits::isDeletedValue):
(WebCore::SubimageCacheWithTimer::SubimageCacheHash::hash):
(WebCore::SubimageCacheWithTimer::SubimageCacheHash::equal):
(SubimageCacheHash):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (147264 => 147265)


--- trunk/Source/WebCore/ChangeLog	2013-03-30 00:19:18 UTC (rev 147264)
+++ trunk/Source/WebCore/ChangeLog	2013-03-30 00:51:57 UTC (rev 147265)
@@ -1,3 +1,56 @@
+2013-03-29  Yongjun Zhang  <[email protected]>
+
+        When releasing a CGImage, we should also remove it from the subimage cache.
+        https://bugs.webkit.org/show_bug.cgi?id=102453
+
+        Reviewed by Simon Fraser.
+
+        When we release an image(CGImageRef) from BitmapImage's cachedFrames, if the image was already
+        cached in subimage cache, it's ref count won't drop to 0 and the image won't be deleted.  Usually,
+        the subimage cache will clear the whole cache in a timer with 1 sec delay.  However, if WebCore has
+        to paint another subimage (not necessarily from the same CGImageRef) before this timer fires, we
+        will restart the timer and images inside the cache will stay longer than they should.
+
+        This patch does two things:
+            - move SubimageCacheWithTimer and related helper struct into a separate file.
+            - remove the image from subimage cache when we releasing the CGImageRef, this prevent subimage
+        cache holding the image after we released it.
+
+        No new tests, manually verified the CGImageRef is also removed from subimage cache
+        when we releasing the image from FrameData::clear.
+
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/graphics/cg/BitmapImageCG.cpp:
+        (WebCore::FrameData::clear): remove the image from subimage cache before we releasing it.
+        * platform/graphics/cg/GraphicsContextCG.cpp:
+        (WebCore):
+        (WebCore::GraphicsContext::drawNativeImage):
+        * platform/graphics/cg/SubimageCacheWithTimer.cpp: Added.
+        (WebCore):
+        (SubimageRequest):
+        (WebCore::SubimageRequest::SubimageRequest):
+        (WebCore::SubimageCacheAdder::hash):
+        (SubimageCacheAdder):
+        (WebCore::SubimageCacheAdder::equal):
+        (WebCore::SubimageCacheAdder::translate):
+        (WebCore::SubimageCacheWithTimer::SubimageCacheWithTimer):
+        (WebCore::SubimageCacheWithTimer::invalidateCacheTimerFired):
+        (WebCore::SubimageCacheWithTimer::getSubimage):
+        (WebCore::SubimageCacheWithTimer::clearImage):
+        (WebCore::subimageCache):
+        * platform/graphics/cg/SubimageCacheWithTimer.h: Added.
+        (WebCore):
+        (SubimageCacheWithTimer): Added a data member m_images to record which image and its subimages are cached.
+        (SubimageCacheEntry):
+        (SubimageCacheEntryTraits):
+        (WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits::isEmptyValue):
+        (WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits::constructDeletedValue):
+        (WebCore::SubimageCacheWithTimer::SubimageCacheEntryTraits::isDeletedValue):
+        (WebCore::SubimageCacheWithTimer::SubimageCacheHash::hash):
+        (WebCore::SubimageCacheWithTimer::SubimageCacheHash::equal):
+        (SubimageCacheHash):
+
 2013-03-29  Andy Estes  <[email protected]>
 
         Let cached resources from file: schemes expire immediately

Modified: trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj (147264 => 147265)


--- trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj	2013-03-30 00:19:18 UTC (rev 147264)
+++ trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj	2013-03-30 00:51:57 UTC (rev 147265)
@@ -31285,6 +31285,46 @@
 						</FileConfiguration>
 					</File>
 					<File
+						RelativePath="..\platform\graphics\cg\SubimageCacheWithTimer.cpp"
+						>
+						<FileConfiguration
+							Name="Debug_Cairo_CFLite|Win32"
+							ExcludedFromBuild="true"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release_Cairo_CFLite|Win32"
+							ExcludedFromBuild="true"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\platform\graphics\cg\SubimageCacheWithTimer.h"
+						>
+						<FileConfiguration
+							Name="Debug_Cairo_CFLite|Win32"
+							ExcludedFromBuild="true"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+							/>
+						</FileConfiguration>
+						<FileConfiguration
+							Name="Release_Cairo_CFLite|Win32"
+							ExcludedFromBuild="true"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+							/>
+						</FileConfiguration>
+					</File>
+					<File
 						RelativePath="..\platform\graphics\cg\ImageSourceCGWin.cpp"
 						>
 						<FileConfiguration

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (147264 => 147265)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2013-03-30 00:19:18 UTC (rev 147264)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2013-03-30 00:51:57 UTC (rev 147265)
@@ -692,6 +692,8 @@
 		1F3F19531499CA7600A5AEA7 /* PODFreeListArena.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F3F19521499CA7600A5AEA7 /* PODFreeListArena.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		1FAFBF1815A5FA6E00083A20 /* UTIUtilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1FAFBF1715A5FA5200083A20 /* UTIUtilities.mm */; };
 		1FAFBF1915A5FA7400083A20 /* UTIUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FAFBF1615A5FA5200083A20 /* UTIUtilities.h */; };
+		1FC40FB91655CCB60040F29E /* SubimageCacheWithTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1FC40FB81655C5910040F29E /* SubimageCacheWithTimer.cpp */; };
+		1FC40FBA1655CCB90040F29E /* SubimageCacheWithTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FC40FB71655C5910040F29E /* SubimageCacheWithTimer.h */; };
 		209B456B16796A7E00E54E4E /* JSCryptoCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 209B456A16796A7E00E54E4E /* JSCryptoCustom.cpp */; };
 		20D629261253690B00081543 /* InspectorInstrumentation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 20D629241253690B00081543 /* InspectorInstrumentation.cpp */; };
 		20D629271253690B00081543 /* InspectorInstrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = 20D629251253690B00081543 /* InspectorInstrumentation.h */; };
@@ -8071,6 +8073,8 @@
 		1F3F19521499CA7600A5AEA7 /* PODFreeListArena.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PODFreeListArena.h; sourceTree = "<group>"; };
 		1FAFBF1615A5FA5200083A20 /* UTIUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UTIUtilities.h; sourceTree = "<group>"; };
 		1FAFBF1715A5FA5200083A20 /* UTIUtilities.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UTIUtilities.mm; sourceTree = "<group>"; };
+		1FC40FB71655C5910040F29E /* SubimageCacheWithTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SubimageCacheWithTimer.h; sourceTree = "<group>"; };
+		1FC40FB81655C5910040F29E /* SubimageCacheWithTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SubimageCacheWithTimer.cpp; sourceTree = "<group>"; };
 		209B456A16796A7E00E54E4E /* JSCryptoCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCryptoCustom.cpp; sourceTree = "<group>"; };
 		20D629241253690B00081543 /* InspectorInstrumentation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorInstrumentation.cpp; sourceTree = "<group>"; };
 		20D629251253690B00081543 /* InspectorInstrumentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorInstrumentation.h; sourceTree = "<group>"; };
@@ -20702,6 +20706,8 @@
 				A80A38FD0E50CC8200A25EBC /* PatternCG.cpp */,
 				B27535360B053814002CE64F /* PDFDocumentImage.cpp */,
 				B27535370B053814002CE64F /* PDFDocumentImage.h */,
+				1FC40FB71655C5910040F29E /* SubimageCacheWithTimer.h */,
+				1FC40FB81655C5910040F29E /* SubimageCacheWithTimer.cpp */,
 				B275352A0B053814002CE64F /* TransformationMatrixCG.cpp */,
 			);
 			path = cg;
@@ -26114,6 +26120,7 @@
 				B8DBDB4C130B0F8A00F5CDB1 /* SetSelectionCommand.h in Headers */,
 				93F1994F08245E59001E9ABC /* Settings.h in Headers */,
 				53EF766B16530A61004CBE49 /* SettingsMacros.h in Headers */,
+				1FC40FBA1655CCB90040F29E /* SubimageCacheWithTimer.h in Headers */,
 				498770E91242C535002226BA /* Shader.h in Headers */,
 				0F3DD45012F5EA1B000D9190 /* ShadowBlur.h in Headers */,
 				BC5EB8C40E82031B00B25965 /* ShadowData.h in Headers */,
@@ -29570,6 +29577,7 @@
 				BC5EB80F0E81F2CE00B25965 /* StyleTransformData.cpp in Sources */,
 				BC5EB6990E81DA6300B25965 /* StyleVisualData.cpp in Sources */,
 				D000ED2711C1B9CD00C47726 /* SubframeLoader.cpp in Sources */,
+				1FC40FB91655CCB60040F29E /* SubimageCacheWithTimer.cpp in Sources */,
 				F55B3DD31251F12D003EF269 /* SubmitInputType.cpp in Sources */,
 				93E227E40AF589AD00D48324 /* SubresourceLoader.cpp in Sources */,
 				7E37EF2E1339208800B29250 /* SubresourceLoaderCF.cpp in Sources */,

Modified: trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp (147264 => 147265)


--- trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp	2013-03-30 00:19:18 UTC (rev 147264)
+++ trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp	2013-03-30 00:51:57 UTC (rev 147265)
@@ -31,6 +31,7 @@
 #include "FloatConversion.h"
 #include "GraphicsContextCG.h"
 #include "ImageObserver.h"
+#include "SubimageCacheWithTimer.h"
 #include <ApplicationServices/ApplicationServices.h>
 #include <wtf/RetainPtr.h>
 
@@ -52,6 +53,9 @@
     m_orientation = DefaultImageOrientation;
 
     if (m_frame) {
+#if CACHE_SUBIMAGES
+        subimageCache().clearImage(m_frame);
+#endif
         CGImageRelease(m_frame);
         m_frame = 0;
         return true;

Modified: trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp (147264 => 147265)


--- trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp	2013-03-30 00:19:18 UTC (rev 147264)
+++ trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp	2013-03-30 00:51:57 UTC (rev 147265)
@@ -37,6 +37,7 @@
 #include "Path.h"
 #include "Pattern.h"
 #include "ShadowBlur.h"
+#include "SubimageCacheWithTimer.h"
 #include "Timer.h"
 #include <CoreGraphics/CoreGraphics.h>
 #include <wtf/MathExtras.h>
@@ -79,117 +80,8 @@
 // FIXME: The following using declaration should be in <wtf/HashTraits.h>.
 using WTF::GenericHashTraits;
 
-#define CACHE_SUBIMAGES 1
-
 namespace WebCore {
 
-#if !CACHE_SUBIMAGES
-
-static inline RetainPtr<CGImageRef> subimage(CGImageRef image, const FloatRect& rect)
-{
-    return adoptCF(CGImageCreateWithImageInRect(image, rect));
-}
-
-#else // CACHE_SUBIMAGES
-
-static const double subimageCacheClearDelay = 1;
-static const int maxSubimageCacheSize = 300;
-
-struct SubimageCacheEntry {
-    RetainPtr<CGImageRef> image;
-    FloatRect rect;
-    RetainPtr<CGImageRef> subimage;
-};
-
-struct SubimageCacheEntryTraits : GenericHashTraits<SubimageCacheEntry> {
-    typedef HashTraits<RetainPtr<CGImageRef> > ImageTraits;
-
-    static const bool emptyValueIsZero = true;
-
-    static const bool hasIsEmptyValueFunction = true;
-    static bool isEmptyValue(const SubimageCacheEntry& value) { return !value.image; }
-
-    static void constructDeletedValue(SubimageCacheEntry& slot) { ImageTraits::constructDeletedValue(slot.image); }
-    static bool isDeletedValue(const SubimageCacheEntry& value) { return ImageTraits::isDeletedValue(value.image); }
-};
-
-struct SubimageCacheHash {
-    static unsigned hash(CGImageRef image, const FloatRect& rect)
-    {
-        return pairIntHash(PtrHash<CGImageRef>::hash(image),
-            (static_cast<unsigned>(rect.x()) << 16) | static_cast<unsigned>(rect.y()));
-    }
-    static unsigned hash(const SubimageCacheEntry& key)
-    {
-        return hash(key.image.get(), key.rect);
-    }
-    static bool equal(const SubimageCacheEntry& a, const SubimageCacheEntry& b)
-    {
-        return a.image == b.image && a.rect == b.rect;
-    }
-    static const bool safeToCompareToEmptyOrDeleted = true;
-};
-
-typedef HashSet<SubimageCacheEntry, SubimageCacheHash, SubimageCacheEntryTraits> SubimageCache;
-
-struct SubimageCacheWithTimer {
-    SubimageCache cache;
-    DeferrableOneShotTimer<SubimageCacheWithTimer> timer;
-
-    SubimageCacheWithTimer()
-        : timer(this, &SubimageCacheWithTimer::invalidateCacheTimerFired, subimageCacheClearDelay)
-    {
-    }
-
-    void invalidateCacheTimerFired(DeferrableOneShotTimer<SubimageCacheWithTimer>*);
-};
-
-static SubimageCacheWithTimer& subimageCache()
-{
-    static SubimageCacheWithTimer& cache = *new SubimageCacheWithTimer;
-    return cache;
-}
-
-void SubimageCacheWithTimer::invalidateCacheTimerFired(DeferrableOneShotTimer<SubimageCacheWithTimer>*)
-{
-    subimageCache().cache.clear();
-}
-
-struct SubimageRequest {
-    CGImageRef image;
-    const FloatRect& rect;
-    SubimageRequest(CGImageRef image, const FloatRect& rect) : image(image), rect(rect) { }
-};
-
-struct SubimageCacheAdder {
-    static unsigned hash(const SubimageRequest& value)
-    {
-        return SubimageCacheHash::hash(value.image, value.rect);
-    }
-    static bool equal(const SubimageCacheEntry& a, const SubimageRequest& b)
-    {
-        return a.image == b.image && a.rect == b.rect;
-    }
-    static void translate(SubimageCacheEntry& entry, const SubimageRequest& request, unsigned /*hashCode*/)
-    {
-        entry.image = request.image;
-        entry.rect = request.rect;
-        entry.subimage = adoptCF(CGImageCreateWithImageInRect(request.image, request.rect));
-    }
-};
-
-static RetainPtr<CGImageRef> subimage(CGImageRef image, const FloatRect& rect)
-{
-    SubimageCacheWithTimer& cache = subimageCache();
-    cache.timer.restart();
-    if (cache.cache.size() == maxSubimageCacheSize)
-        cache.cache.remove(cache.cache.begin());
-    ASSERT(cache.cache.size() < maxSubimageCacheSize);
-    return cache.cache.add<SubimageRequest, SubimageCacheAdder>(SubimageRequest(image, rect)).iterator->subimage;
-}
-
-#endif // CACHE_SUBIMAGES
-
 static void setCGFillColor(CGContextRef context, const Color& color, ColorSpace colorSpace)
 {
     CGContextSetFillColorWithColor(context, cachedCGColor(color, colorSpace));
@@ -306,7 +198,11 @@
             subimageRect.setHeight(ceilf(subimageRect.height() + topPadding));
             adjustedDestRect.setHeight(subimageRect.height() / yScale);
 
-            image = subimage(image.get(), subimageRect);
+#if CACHE_SUBIMAGES
+            image = subimageCache().getSubimage(image.get(), subimageRect);
+#else
+            image = adoptCF(CGImageCreateWithImageInRect(image, subimageRect));
+#endif
             if (currHeight < srcRect.maxY()) {
                 ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y);
                 adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale);

Added: trunk/Source/WebCore/platform/graphics/cg/SubimageCacheWithTimer.cpp (0 => 147265)


--- trunk/Source/WebCore/platform/graphics/cg/SubimageCacheWithTimer.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/graphics/cg/SubimageCacheWithTimer.cpp	2013-03-30 00:51:57 UTC (rev 147265)
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012, 2013 Apple 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 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 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 "SubimageCacheWithTimer.h"
+
+#include <wtf/Vector.h>
+
+#if CACHE_SUBIMAGES
+
+namespace WebCore {
+
+static const double subimageCacheClearDelay = 1;
+static const int maxSubimageCacheSize = 300;
+
+struct SubimageRequest {
+    CGImageRef image;
+    const FloatRect& rect;
+    SubimageRequest(CGImageRef image, const FloatRect& rect) : image(image), rect(rect) { }
+};
+
+struct SubimageCacheAdder {
+    static unsigned hash(const SubimageRequest& value)
+    {
+        return SubimageCacheWithTimer::SubimageCacheHash::hash(value.image, value.rect);
+    }
+
+    static bool equal(const SubimageCacheWithTimer::SubimageCacheEntry& a, const SubimageRequest& b)
+    {
+        return a.image == b.image && a.rect == b.rect;
+    }
+
+    static void translate(SubimageCacheWithTimer::SubimageCacheEntry& entry, const SubimageRequest& request, unsigned /*hashCode*/)
+    {
+        entry.image = request.image;
+        entry.rect = request.rect;
+        entry.subimage = adoptCF(CGImageCreateWithImageInRect(request.image, request.rect));
+    }
+};
+
+SubimageCacheWithTimer::SubimageCacheWithTimer()
+    : m_timer(this, &SubimageCacheWithTimer::invalidateCacheTimerFired, subimageCacheClearDelay)
+{
+}
+
+void SubimageCacheWithTimer::invalidateCacheTimerFired(DeferrableOneShotTimer<SubimageCacheWithTimer>*)
+{
+    m_images.clear();
+    m_cache.clear();
+}
+
+RetainPtr<CGImageRef> SubimageCacheWithTimer::getSubimage(CGImageRef image, const FloatRect& rect)
+{
+    m_timer.restart();
+    if (m_cache.size() == maxSubimageCacheSize) {
+        SubimageCacheEntry entry = *m_cache.begin();
+        m_images.remove(entry.image.get());
+        m_cache.remove(entry);
+    }
+
+    ASSERT(m_cache.size() < maxSubimageCacheSize);
+    SubimageCache::AddResult result = m_cache.add<SubimageRequest, SubimageCacheAdder>(SubimageRequest(image, rect));
+    if (result.isNewEntry)
+        m_images.add(image);
+
+    return result.iterator->subimage;
+}
+
+void SubimageCacheWithTimer::clearImage(CGImageRef image)
+{
+    if (m_images.contains(image)) {
+        Vector<SubimageCacheEntry> toBeRemoved;
+        SubimageCache::const_iterator end = m_cache.end();
+        for (SubimageCache::const_iterator it = m_cache.begin(); it != end; ++it) {
+            if (it->image.get() == image)
+                toBeRemoved.append(*it);
+        }
+
+        for (Vector<SubimageCacheEntry>::iterator removeIt = toBeRemoved.begin(); removeIt != toBeRemoved.end(); ++removeIt)
+            m_cache.remove(*removeIt);
+
+        m_images.removeAll(image);
+    }
+}
+
+SubimageCacheWithTimer& subimageCache()
+{
+    static SubimageCacheWithTimer& cache = *new SubimageCacheWithTimer;
+    return cache;
+}
+
+}
+
+#endif

Added: trunk/Source/WebCore/platform/graphics/cg/SubimageCacheWithTimer.h (0 => 147265)


--- trunk/Source/WebCore/platform/graphics/cg/SubimageCacheWithTimer.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/graphics/cg/SubimageCacheWithTimer.h	2013-03-30 00:51:57 UTC (rev 147265)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2012, 2013 Apple 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 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 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 SubimageCacheWithTimer_h
+#define SubimageCacheWithTimer_h
+
+#include "FloatRect.h"
+#include "Timer.h"
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <wtf/HashCountedSet.h>
+#include <wtf/HashSet.h>
+#include <wtf/HashTraits.h>
+#include <wtf/RetainPtr.h>
+
+#define CACHE_SUBIMAGES 1
+
+namespace WebCore {
+
+#if CACHE_SUBIMAGES
+
+class SubimageCacheWithTimer {
+    WTF_MAKE_NONCOPYABLE(SubimageCacheWithTimer); WTF_MAKE_FAST_ALLOCATED;
+
+public:
+    struct SubimageCacheEntry {
+        RetainPtr<CGImageRef> image;
+        FloatRect rect;
+        RetainPtr<CGImageRef> subimage;
+    };
+
+    struct SubimageCacheEntryTraits : WTF::GenericHashTraits<SubimageCacheEntry> {
+        typedef HashTraits<RetainPtr<CGImageRef> > ImageTraits;
+
+        static const bool emptyValueIsZero = true;
+
+        static const bool hasIsEmptyValueFunction = true;
+        static bool isEmptyValue(const SubimageCacheEntry& value) { return !value.image; }
+
+        static void constructDeletedValue(SubimageCacheEntry& slot) { ImageTraits::constructDeletedValue(slot.image); }
+        static bool isDeletedValue(const SubimageCacheEntry& value) { return ImageTraits::isDeletedValue(value.image); }
+    };
+
+    struct SubimageCacheHash {
+        static unsigned hash(CGImageRef image, const FloatRect& rect)
+        {
+            return WTF::pairIntHash(PtrHash<CGImageRef>::hash(image),
+                (static_cast<unsigned>(rect.x()) << 16) | static_cast<unsigned>(rect.y()));
+        }
+        static unsigned hash(const SubimageCacheEntry& key)
+        {
+            return hash(key.image.get(), key.rect);
+        }
+        static bool equal(const SubimageCacheEntry& a, const SubimageCacheEntry& b)
+        {
+            return a.image == b.image && a.rect == b.rect;
+        }
+        static const bool safeToCompareToEmptyOrDeleted = true;
+    };
+
+    typedef HashSet<SubimageCacheEntry, SubimageCacheHash, SubimageCacheEntryTraits> SubimageCache;
+
+public:
+    SubimageCacheWithTimer();
+    RetainPtr<CGImageRef> getSubimage(CGImageRef, const FloatRect&);
+    void clearImage(CGImageRef);
+
+private:
+    void invalidateCacheTimerFired(DeferrableOneShotTimer<SubimageCacheWithTimer>*);
+
+    HashCountedSet<CGImageRef> m_images;
+    SubimageCache m_cache;
+    DeferrableOneShotTimer<SubimageCacheWithTimer> m_timer;
+};
+
+SubimageCacheWithTimer& subimageCache();
+
+#endif // CACHE_SUBIMAGES
+
+}
+
+#endif // SubimageCacheWithTimer_h
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to