зеркало из https://github.com/mozilla/gecko-dev.git
Compact the font cache in low-memory situations or when font handles are running out. b=109974, r=shanjian, sr=waterson
This commit is contained in:
Родитель
770e9da69c
Коммит
d8ce96d9f4
|
@ -45,6 +45,8 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
class nsIImageRequest;
|
||||
class nsHashtable;
|
||||
|
@ -59,6 +61,9 @@ public:
|
|||
NS_IMETHOD GetDeviceContext(nsIDeviceContext *&aContext) const;
|
||||
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
|
||||
nsIFontMetrics *&aMetrics);
|
||||
|
||||
nsresult FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
|
||||
nsresult Compact();
|
||||
nsresult Flush();
|
||||
/* printer device context classes may create their own
|
||||
* subclasses of nsFontCache (and override this method) and override
|
||||
|
@ -72,12 +77,14 @@ protected:
|
|||
// ownership is implied. MMP.
|
||||
};
|
||||
|
||||
class NS_GFX DeviceContextImpl : public nsIDeviceContext
|
||||
class NS_GFX DeviceContextImpl : public nsIDeviceContext,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
DeviceContextImpl();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
NS_IMETHOD Init(nsNativeWidget aWidget);
|
||||
|
||||
|
@ -119,7 +126,7 @@ public:
|
|||
PRBool& aAliased);
|
||||
|
||||
NS_IMETHOD CreateFontCache();
|
||||
|
||||
NS_IMETHOD FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
|
||||
NS_IMETHOD FlushFontCache(void);
|
||||
|
||||
NS_IMETHOD GetDepth(PRUint32& aDepth);
|
||||
|
|
|
@ -338,6 +338,12 @@ public:
|
|||
NS_IMETHOD GetLocalFontName(const nsString& aFaceName, nsString& aLocalName,
|
||||
PRBool& aAliased) = 0;
|
||||
|
||||
/**
|
||||
* Notification when a font metrics instance created for this device is
|
||||
* about to be deleted
|
||||
*/
|
||||
NS_IMETHOD FontMetricsDeleted(const nsIFontMetrics* aFontMetrics) = 0;
|
||||
|
||||
/**
|
||||
* Attempt to free up resoruces by flushing out any fonts no longer
|
||||
* referenced by anything other than the font cache itself.
|
||||
|
|
|
@ -66,6 +66,10 @@ nsFontMetricsBeOS::~nsFontMetricsBeOS()
|
|||
delete mFont;
|
||||
mFont = nsnull;
|
||||
}
|
||||
if (mDeviceContext) {
|
||||
mDeviceContext->FontMetricsDeleted(this);
|
||||
mDeviceContext = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFontMetricsBeOS, nsIFontMetrics)
|
||||
|
@ -94,6 +98,7 @@ NS_IMETHODIMP nsFontMetricsBeOS::Init(const nsFont& aFont, nsIAtom* aLangGroup,
|
|||
|
||||
nsAutoString firstFace;
|
||||
mLangGroup = aLangGroup;
|
||||
mDeviceContext = aContext;
|
||||
if (NS_OK != aContext->FirstExistingFont(aFont, firstFace)) {
|
||||
aFont.GetFirstFamily(firstFace);
|
||||
}
|
||||
|
@ -166,6 +171,7 @@ NS_IMETHODIMP nsFontMetricsBeOS::Init(const nsFont& aFont, nsIAtom* aLangGroup,
|
|||
|
||||
NS_IMETHODIMP nsFontMetricsBeOS::Destroy()
|
||||
{
|
||||
mDeviceContext = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1069,6 +1069,11 @@ nsFontMetricsGTK::~nsFontMetricsGTK()
|
|||
|
||||
mWesternFont = nsnull;
|
||||
|
||||
if (mDeviceContext) {
|
||||
mDeviceContext->FontMetricsDeleted(this);
|
||||
mDeviceContext = nsnull;
|
||||
}
|
||||
|
||||
if (!--gFontMetricsGTKCount) {
|
||||
FreeGlobals();
|
||||
}
|
||||
|
@ -1237,7 +1242,7 @@ NS_IMETHODIMP nsFontMetricsGTK::Init(const nsFont& aFont, nsIAtom* aLangGroup,
|
|||
|
||||
NS_IMETHODIMP nsFontMetricsGTK::Destroy()
|
||||
{
|
||||
// NS_IF_RELEASE(mDeviceContext);
|
||||
mDeviceContext = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,10 @@ nsFontMetricsMac :: ~nsFontMetricsMac()
|
|||
delete mFont;
|
||||
mFont = nsnull;
|
||||
}
|
||||
if (mContext) {
|
||||
mContext->FontMetricsDeleted(this);
|
||||
mContext = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
@ -240,6 +244,7 @@ void nsFontMetricsMac::RealizeFont()
|
|||
NS_IMETHODIMP
|
||||
nsFontMetricsMac::Destroy()
|
||||
{
|
||||
mContext = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "nsUnicharUtils.h"
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS1(DeviceContextImpl, nsIDeviceContext)
|
||||
NS_IMPL_ISUPPORTS2(DeviceContextImpl, nsIDeviceContext, nsIObserver)
|
||||
|
||||
DeviceContextImpl :: DeviceContextImpl()
|
||||
{
|
||||
|
@ -63,6 +63,10 @@ static PRBool PR_CALLBACK DeleteValue(nsHashKey* aKey, void* aValue, void* closu
|
|||
|
||||
DeviceContextImpl :: ~DeviceContextImpl()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
|
||||
if (obs)
|
||||
obs->RemoveObserver(this, "memory-pressure");
|
||||
|
||||
if (nsnull != mFontCache)
|
||||
{
|
||||
delete mFontCache;
|
||||
|
@ -82,12 +86,27 @@ DeviceContextImpl :: ~DeviceContextImpl()
|
|||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DeviceContextImpl::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aSomeData)
|
||||
{
|
||||
if (mFontCache && !nsCRT::strcmp(aTopic, "memory-pressure")) {
|
||||
mFontCache->Compact();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl :: Init(nsNativeWidget aWidget)
|
||||
{
|
||||
mWidget = aWidget;
|
||||
|
||||
CommonInit();
|
||||
|
||||
// register as a memory-pressure observer to free font resources
|
||||
// in low-memory situations.
|
||||
nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
|
||||
if (obs)
|
||||
obs->AddObserver(this, "memory-pressure", PR_FALSE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -223,6 +242,14 @@ NS_IMETHODIMP DeviceContextImpl::CreateFontCache()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::FontMetricsDeleted(const nsIFontMetrics* aFontMetrics)
|
||||
{
|
||||
if (mFontCache) {
|
||||
mFontCache->FontMetricsDeleted(aFontMetrics);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
DeviceContextImpl::GetLocaleLangGroup(void)
|
||||
{
|
||||
|
@ -604,24 +631,23 @@ nsFontCache :: GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
|
|||
nsIFontMetrics *&aMetrics)
|
||||
{
|
||||
// First check our cache
|
||||
PRInt32 n = mFontMetrics.Count()-1;
|
||||
|
||||
// start from the end, which is where we put the most-recent-used element
|
||||
for (PRInt32 cnt = n; cnt >= 0; --cnt)
|
||||
{
|
||||
nsIFontMetrics* metrics = NS_STATIC_CAST(nsIFontMetrics*, mFontMetrics[cnt]);
|
||||
|
||||
nsIFontMetrics* fm;
|
||||
PRInt32 n = mFontMetrics.Count() - 1;
|
||||
for (PRInt32 i = n; i >= 0; --i) {
|
||||
fm = NS_STATIC_CAST(nsIFontMetrics*, mFontMetrics[i]);
|
||||
const nsFont* font;
|
||||
metrics->GetFont(font);
|
||||
if (aFont.Equals(*font)) {
|
||||
fm->GetFont(font);
|
||||
if (font->Equals(aFont)) {
|
||||
nsCOMPtr<nsIAtom> langGroup;
|
||||
metrics->GetLangGroup(getter_AddRefs(langGroup));
|
||||
fm->GetLangGroup(getter_AddRefs(langGroup));
|
||||
if (aLangGroup == langGroup.get()) {
|
||||
if (cnt != n) {
|
||||
if (i != n) {
|
||||
// promote it to the end of the cache
|
||||
mFontMetrics.MoveElement(cnt, n);
|
||||
mFontMetrics.MoveElement(i, n);
|
||||
}
|
||||
NS_ADDREF(aMetrics = metrics);
|
||||
NS_ADDREF(aMetrics = fm);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -629,28 +655,48 @@ nsFontCache :: GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
|
|||
|
||||
// It's not in the cache. Get font metrics and then cache them.
|
||||
|
||||
nsIFontMetrics *fm = nsnull;
|
||||
aMetrics = nsnull;
|
||||
nsresult rv = CreateFontMetricsInstance(&fm);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aMetrics = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = fm->Init(aFont, aLangGroup, mContext);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// the mFontMetrics list has the "head" at the end, because append is
|
||||
// cheaper than insert
|
||||
mFontMetrics.AppendElement(fm);
|
||||
aMetrics = fm;
|
||||
NS_ADDREF(aMetrics);
|
||||
return NS_OK;
|
||||
}
|
||||
fm->Destroy();
|
||||
NS_RELEASE(fm);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aMetrics = nsnull;
|
||||
return rv;
|
||||
// One reason why Init() fails is because the system is running out of resources.
|
||||
// e.g., on Win95/98 only a very limited number of GDI objects are available.
|
||||
// Compact the cache and try again.
|
||||
|
||||
Compact();
|
||||
rv = CreateFontMetricsInstance(&fm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = fm->Init(aFont, aLangGroup, mContext);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mFontMetrics.AppendElement(fm);
|
||||
aMetrics = fm;
|
||||
NS_ADDREF(aMetrics);
|
||||
return NS_OK;
|
||||
}
|
||||
fm->Destroy();
|
||||
NS_RELEASE(fm);
|
||||
|
||||
// could not setup a new one, send an old one (XXX search a "best match"?)
|
||||
|
||||
n = mFontMetrics.Count() - 1; // could have changed in Compact()
|
||||
if (n >= 0) {
|
||||
aMetrics = NS_STATIC_CAST(nsIFontMetrics*, mFontMetrics[n]);
|
||||
NS_ADDREF(aMetrics);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// the mFontMetrics list has the "head" at the end, because append is
|
||||
// cheaper than insert
|
||||
mFontMetrics.AppendElement(fm);
|
||||
|
||||
NS_ADDREF(fm);
|
||||
aMetrics = fm;
|
||||
return NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* PostScript and Xprint module may override this method to create
|
||||
|
@ -663,14 +709,37 @@ nsFontCache::CreateFontMetricsInstance(nsIFontMetrics** fm)
|
|||
return CallCreateInstance(kFontMetricsCID, fm);
|
||||
}
|
||||
|
||||
nsresult nsFontCache::FontMetricsDeleted(const nsIFontMetrics* aFontMetrics)
|
||||
{
|
||||
mFontMetrics.RemoveElement((void*)aFontMetrics);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsFontCache::Compact()
|
||||
{
|
||||
// Need to loop backward because the running element can be removed on the way
|
||||
for (PRInt32 i = mFontMetrics.Count()-1; i >= 0; --i) {
|
||||
nsIFontMetrics* fm = NS_STATIC_CAST(nsIFontMetrics*, mFontMetrics[i]);
|
||||
nsIFontMetrics* oldfm = fm;
|
||||
// Destroy() isn't here because we want our device context to be notified
|
||||
NS_RELEASE(fm); // this will reset fm to nsnull
|
||||
// if the font is really gone, it would have called back in
|
||||
// FontMetricsDeleted() and would have removed itself
|
||||
if (mFontMetrics.IndexOf(oldfm) >= 0) {
|
||||
// nope, the font is still there, so let's hold onto it too
|
||||
NS_ADDREF(oldfm);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsFontCache :: Flush()
|
||||
{
|
||||
PRInt32 i, n = mFontMetrics.Count();
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
nsIFontMetrics* fm = (nsIFontMetrics*) mFontMetrics.ElementAt(i);
|
||||
for (PRInt32 i = mFontMetrics.Count()-1; i >= 0; --i) {
|
||||
nsIFontMetrics* fm = NS_STATIC_CAST(nsIFontMetrics*, mFontMetrics[i]);
|
||||
// Destroy() will unhook our device context from the fm so that we won't
|
||||
// waste time in triggering the notification of FontMetricsDeleted()
|
||||
// in the subsequent release
|
||||
fm->Destroy();
|
||||
NS_RELEASE(fm);
|
||||
}
|
||||
|
|
|
@ -274,10 +274,12 @@ nsFontMetricsOS2::nsFontMetricsOS2()
|
|||
|
||||
nsFontMetricsOS2::~nsFontMetricsOS2()
|
||||
{
|
||||
Destroy();
|
||||
|
||||
delete mFont;
|
||||
delete mFontHandle;
|
||||
if (mDeviceContext) {
|
||||
mDeviceContext->FontMetricsDeleted(this);
|
||||
mDeviceContext = nsnull;
|
||||
}
|
||||
if (0 == --gFontMetricsOS2Count) {
|
||||
FreeGlobals();
|
||||
}
|
||||
|
@ -321,6 +323,7 @@ nsFontMetricsOS2::Init( const nsFont &aFont, nsIAtom* aLangGroup,
|
|||
|
||||
nsresult nsFontMetricsOS2::Destroy()
|
||||
{
|
||||
mDeviceContext = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -125,9 +125,12 @@ nsFontMetricsPh :: ~nsFontMetricsPh( )
|
|||
delete mFont;
|
||||
mFont = nsnull;
|
||||
}
|
||||
mDeviceContext = nsnull;
|
||||
if (mFontHandle)
|
||||
free (mFontHandle);
|
||||
if (mDeviceContext) {
|
||||
mDeviceContext->FontMetricsDeleted(this);
|
||||
mDeviceContext = nsnull;
|
||||
}
|
||||
FreeGlobals();
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,10 @@ nsFontMetricsPS :: ~nsFontMetricsPS()
|
|||
mAFMInfo = nsnull;
|
||||
}
|
||||
|
||||
|
||||
mDeviceContext = nsnull;
|
||||
if (mDeviceContext) {
|
||||
mDeviceContext->FontMetricsDeleted(this);
|
||||
mDeviceContext = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFontMetricsPS, nsIFontMetrics)
|
||||
|
|
|
@ -684,6 +684,10 @@ nsFontMetricsQT::~nsFontMetricsQT()
|
|||
delete mUserDefinedFont;
|
||||
mUserDefinedFont = nsnull;
|
||||
}
|
||||
if (mDeviceContext) {
|
||||
mDeviceContext->FontMetricsDeleted(this);
|
||||
mDeviceContext = nsnull;
|
||||
}
|
||||
if (!--gFontMetricsQTCount) {
|
||||
FreeGlobals();
|
||||
if (mQFontDB) {
|
||||
|
@ -893,6 +897,7 @@ QFontDatabase *nsFontMetricsQT::GetQFontDB()
|
|||
|
||||
NS_IMETHODIMP nsFontMetricsQT::Destroy()
|
||||
{
|
||||
mDeviceContext = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -403,7 +403,10 @@ nsFontMetricsWin::~nsFontMetricsWin()
|
|||
}
|
||||
mLoadedFonts.Clear();
|
||||
|
||||
mDeviceContext = nsnull;
|
||||
if (mDeviceContext) {
|
||||
mDeviceContext->FontMetricsDeleted(this);
|
||||
mDeviceContext = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LEAK_DEBUG
|
||||
|
|
|
@ -985,6 +985,11 @@ nsFontMetricsXlib::~nsFontMetricsXlib()
|
|||
mWesternFont = nsnull;
|
||||
mFontHandle = nsnull;
|
||||
|
||||
if (mDeviceContext) {
|
||||
mDeviceContext->FontMetricsDeleted(this);
|
||||
mDeviceContext = nsnull;
|
||||
}
|
||||
|
||||
if (!--gFontMetricsXlibCount) {
|
||||
FreeGlobals();
|
||||
}
|
||||
|
@ -1192,7 +1197,7 @@ nsFontMetricsXlib::Init(const nsFont& aFont, nsIAtom* aLangGroup,
|
|||
|
||||
NS_IMETHODIMP nsFontMetricsXlib::Destroy()
|
||||
{
|
||||
// NS_IF_RELEASE(mDeviceContext);
|
||||
mDeviceContext = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче