From c0b92e301ea3878faaa1bc6cc7de8d75e39333a7 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 13 Jan 2012 11:37:46 +0000 Subject: [PATCH] bug 708075 - observe memory-pressure notification and discard cached gfxShapedWord records. r=roc --- gfx/thebes/gfxFont.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++ gfx/thebes/gfxFont.h | 12 +++++++++++ 2 files changed, 61 insertions(+) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index dedb16fae04..ad11bce8c30 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -69,6 +69,7 @@ #include "nsCompressedCharMap.h" #include "nsStyleConsts.h" #include "mozilla/Preferences.h" +#include "mozilla/Services.h" #include "cairo.h" #include "gfxFontTest.h" @@ -81,6 +82,7 @@ using namespace mozilla; using namespace mozilla::gfx; +using mozilla::services::GetObserverService; gfxFontCache *gfxFontCache::gGlobalCache = nsnull; @@ -954,6 +956,39 @@ gfxFontFamily::FindFont(const nsAString& aPostscriptName) return nsnull; } +/* + * gfxFontCache - global cache of gfxFont instances. + * Expires unused fonts after a short interval; + * notifies fonts to age their cached shaped-word records; + * observes memory-pressure notification and tells fonts to clear their + * shaped-word caches to free up memory. + */ + +// Observer for the memory-pressure notification, to trigger +// flushing of the shaped-word caches +class MemoryPressureObserver : public nsIObserver, + public nsSupportsWeakReference +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER +}; + +NS_IMPL_ISUPPORTS2(MemoryPressureObserver, nsIObserver, nsISupportsWeakReference) + +NS_IMETHODIMP +MemoryPressureObserver::Observe(nsISupports *aSubject, + const char *aTopic, + const PRUnichar *someData) +{ + if (!nsCRT::strcmp(aTopic, "memory-pressure")) { + gfxFontCache *fontCache = gfxFontCache::GetCache(); + if (fontCache) { + fontCache->FlushShapedWordCaches(); + } + } + return NS_OK; +} nsresult gfxFontCache::Init() @@ -986,6 +1021,12 @@ gfxFontCache::gfxFontCache() : nsExpirationTracker(FONT_TIMEOUT_SECONDS * 1000) { mFonts.Init(); + + nsCOMPtr obs = GetObserverService(); + if (obs) { + obs->AddObserver(new MemoryPressureObserver, "memory-pressure", false); + } + mWordCacheExpirationTimer = do_CreateInstance("@mozilla.org/timer;1"); if (mWordCacheExpirationTimer) { mWordCacheExpirationTimer-> @@ -1102,6 +1143,14 @@ gfxFontCache::WordCacheExpirationTimerCallback(nsITimer* aTimer, void* aCache) cache->mFonts.EnumerateEntries(AgeCachedWordsForFont, nsnull); } +/*static*/ +PLDHashOperator +gfxFontCache::ClearCachedWordsForFont(HashEntry* aHashEntry, void* aUserData) +{ + aHashEntry->mFont->ClearCachedWords(); + return PL_DHASH_NEXT; +} + void gfxFont::RunMetrics::CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft) { diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 65139b69ba4..a3fe6bd3d44 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -732,6 +732,10 @@ public: AgeAllGenerations(); } + void FlushShapedWordCaches() { + mFonts.EnumerateEntries(ClearCachedWordsForFont, nsnull); + } + protected: void DestroyFont(gfxFont *aFont); @@ -767,6 +771,7 @@ protected: nsTHashtable mFonts; + static PLDHashOperator ClearCachedWordsForFont(HashEntry* aHashEntry, void*); static PLDHashOperator AgeCachedWordsForFont(HashEntry* aHashEntry, void*); static void WordCacheExpirationTimerCallback(nsITimer* aTimer, void* aCache); nsCOMPtr mWordCacheExpirationTimer; @@ -1405,6 +1410,13 @@ public: } } + // Discard all cached word records; called on memory-pressure notification. + void ClearCachedWords() { + if (mWordCache.IsInitialized()) { + mWordCache.Clear(); + } + } + protected: // Call the appropriate shaper to generate glyphs for aText and store // them into aShapedWord.