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