зеркало из https://github.com/mozilla/pjs.git
Bug 419125 - Part 2 - Merge DeviceContextImpl into nsThebesDeviceContext; r+sr=vlad
This commit is contained in:
Родитель
820d64c57f
Коммит
d1b14afbf4
|
@ -63,7 +63,6 @@ EXPORTS = \
|
|||
nsIImage.h \
|
||||
nsGfxCIID.h \
|
||||
nsIRegion.h \
|
||||
nsDeviceContext.h \
|
||||
nsITheme.h \
|
||||
nsThemeConstants.h \
|
||||
$(NULL)
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Roland Mainz <Roland.Mainz@informatik.med.uni-giessen.de>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsDeviceContext_h___
|
||||
#define nsDeviceContext_h___
|
||||
|
||||
#include "nsIDeviceContext.h"
|
||||
#include "nsIDeviceContextSpec.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "gfxCore.h"
|
||||
|
||||
class nsIImageRequest;
|
||||
class nsHashtable;
|
||||
|
||||
class NS_GFX nsFontCache
|
||||
{
|
||||
public:
|
||||
nsFontCache();
|
||||
virtual ~nsFontCache();
|
||||
|
||||
virtual nsresult Init(nsIDeviceContext* aContext);
|
||||
virtual nsresult GetDeviceContext(nsIDeviceContext *&aContext) const;
|
||||
virtual nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
|
||||
gfxUserFontSet* aUserFontSet,
|
||||
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
|
||||
* DeviceContextImpl::CreateFontCache (see bug 81311).
|
||||
*/
|
||||
virtual nsresult CreateFontMetricsInstance(nsIFontMetrics** fm);
|
||||
|
||||
protected:
|
||||
nsTArray<nsIFontMetrics*> mFontMetrics;
|
||||
nsIDeviceContext *mContext; // we do not addref this since
|
||||
// ownership is implied. MMP.
|
||||
};
|
||||
|
||||
// inherit visibility from the NS_GFX class declaration
|
||||
#undef IMETHOD_VISIBILITY
|
||||
#define IMETHOD_VISIBILITY
|
||||
|
||||
class NS_GFX DeviceContextImpl : public nsIDeviceContext,
|
||||
public nsIObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
DeviceContextImpl();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
NS_IMETHOD Init(nsNativeWidget aWidget);
|
||||
|
||||
NS_IMETHOD CreateRenderingContext(nsIView *aView, nsIRenderingContext *&aContext);
|
||||
NS_IMETHOD CreateRenderingContext(nsIWidget *aWidget, nsIRenderingContext *&aContext);
|
||||
NS_IMETHOD CreateRenderingContext(nsIRenderingContext *&aContext){return NS_ERROR_NOT_IMPLEMENTED;}
|
||||
NS_IMETHOD CreateRenderingContextInstance(nsIRenderingContext *&aContext);
|
||||
|
||||
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
|
||||
gfxUserFontSet* aUserFontSet,
|
||||
nsIFontMetrics*& aMetrics);
|
||||
NS_IMETHOD GetMetricsFor(const nsFont& aFont,
|
||||
gfxUserFontSet* aUserFontSet,
|
||||
nsIFontMetrics*& aMetrics);
|
||||
|
||||
NS_IMETHOD FirstExistingFont(const nsFont& aFont, nsString& aFaceName);
|
||||
|
||||
NS_IMETHOD GetLocalFontName(const nsString& aFaceName, nsString& aLocalName,
|
||||
PRBool& aAliased);
|
||||
|
||||
NS_IMETHOD CreateFontCache();
|
||||
NS_IMETHOD FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
|
||||
NS_IMETHOD FlushFontCache(void);
|
||||
|
||||
NS_IMETHOD GetDepth(PRUint32& aDepth);
|
||||
|
||||
NS_IMETHOD GetPaletteInfo(nsPaletteInfo& aPaletteInfo);
|
||||
|
||||
NS_IMETHOD PrepareDocument(PRUnichar * aTitle,
|
||||
PRUnichar* aPrintToFileName) { return NS_OK; }
|
||||
NS_IMETHOD AbortDocument(void) { return NS_OK; }
|
||||
|
||||
NS_IMETHOD PrepareNativeWidget(nsIWidget *aWidget, void **aOut);
|
||||
NS_IMETHOD ClearCachedSystemFonts();
|
||||
|
||||
private:
|
||||
/* Helper methods for |CreateRenderingContext|&co. */
|
||||
nsresult InitRenderingContext(nsIRenderingContext *aContext, nsIWidget *aWindow);
|
||||
|
||||
protected:
|
||||
virtual ~DeviceContextImpl();
|
||||
|
||||
void CommonInit(void);
|
||||
nsresult CreateIconILGroupContext();
|
||||
virtual nsresult CreateFontAliasTable();
|
||||
nsresult AliasFont(const nsString& aFont,
|
||||
const nsString& aAlias, const nsString& aAltAlias,
|
||||
PRBool aForceAlias);
|
||||
void GetLocaleLangGroup(void);
|
||||
|
||||
nsFontCache *mFontCache;
|
||||
nsCOMPtr<nsIAtom> mLocaleLangGroup; // XXX temp fix for performance bug - erik
|
||||
nsHashtable* mFontAliasTable;
|
||||
|
||||
public:
|
||||
nsNativeWidget mWidget;
|
||||
#ifdef NS_DEBUG
|
||||
PRBool mInitialized;
|
||||
#endif
|
||||
};
|
||||
|
||||
#undef IMETHOD_VISIBILITY
|
||||
#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN
|
||||
|
||||
#endif /* nsDeviceContext_h___ */
|
|
@ -67,7 +67,6 @@ endif
|
|||
|
||||
CPPSRCS = \
|
||||
nsColor.cpp \
|
||||
nsDeviceContext.cpp \
|
||||
nsFont.cpp \
|
||||
nsRect.cpp \
|
||||
nsRegion.cpp \
|
||||
|
|
|
@ -1,609 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Roland Mainz <Roland.Mainz@informatik.med.uni-giessen.de>
|
||||
* IBM Corp.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsDeviceContext.h"
|
||||
#include "nsFont.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsGfxCIID.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsILanguageAtomService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIRenderingContext.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
#include "nsIThebesFontMetrics.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS3(DeviceContextImpl, nsIDeviceContext, nsIObserver, nsISupportsWeakReference)
|
||||
|
||||
DeviceContextImpl::DeviceContextImpl()
|
||||
{
|
||||
mAppUnitsPerDevPixel = -1;
|
||||
mAppUnitsPerInch = -1;
|
||||
mAppUnitsPerDevNotScaledPixel = -1;
|
||||
mPixelScale = 1.0f;
|
||||
|
||||
mFontCache = nsnull;
|
||||
mWidget = nsnull;
|
||||
mFontAliasTable = nsnull;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
mInitialized = PR_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static PRBool DeleteValue(nsHashKey* aKey, void* aValue, void* closure)
|
||||
{
|
||||
delete ((nsString*)aValue);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
DeviceContextImpl::~DeviceContextImpl()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
|
||||
if (obs)
|
||||
obs->RemoveObserver(this, "memory-pressure");
|
||||
|
||||
if (nsnull != mFontCache)
|
||||
{
|
||||
delete mFontCache;
|
||||
mFontCache = nsnull;
|
||||
}
|
||||
|
||||
if (nsnull != mFontAliasTable) {
|
||||
mFontAliasTable->Enumerate(DeleteValue);
|
||||
delete mFontAliasTable;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void DeviceContextImpl::CommonInit(void)
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
NS_ASSERTION(!mInitialized, "device context is initialized twice!");
|
||||
mInitialized = PR_TRUE;
|
||||
#endif
|
||||
|
||||
// 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_TRUE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::CreateRenderingContext(nsIView *aView, nsIRenderingContext *&aContext)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
aContext = nsnull;
|
||||
nsCOMPtr<nsIRenderingContext> pContext;
|
||||
rv = CreateRenderingContextInstance(*getter_AddRefs(pContext));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = InitRenderingContext(pContext, aView->GetWidget());
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aContext = pContext;
|
||||
NS_ADDREF(aContext);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::CreateRenderingContext(nsIWidget *aWidget, nsIRenderingContext *&aContext)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
aContext = nsnull;
|
||||
nsCOMPtr<nsIRenderingContext> pContext;
|
||||
rv = CreateRenderingContextInstance(*getter_AddRefs(pContext));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = InitRenderingContext(pContext, aWidget);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aContext = pContext;
|
||||
NS_ADDREF(aContext);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::CreateRenderingContextInstance(nsIRenderingContext *&aContext)
|
||||
{
|
||||
static NS_DEFINE_CID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIRenderingContext> pContext = do_CreateInstance(kRenderingContextCID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aContext = pContext;
|
||||
NS_ADDREF(aContext);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult DeviceContextImpl::InitRenderingContext(nsIRenderingContext *aContext, nsIWidget *aWin)
|
||||
{
|
||||
return aContext->Init(this, aWin);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::CreateFontCache()
|
||||
{
|
||||
mFontCache = new nsFontCache();
|
||||
if (!mFontCache) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return mFontCache->Init(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::FontMetricsDeleted(const nsIFontMetrics* aFontMetrics)
|
||||
{
|
||||
if (mFontCache) {
|
||||
mFontCache->FontMetricsDeleted(aFontMetrics);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
DeviceContextImpl::GetLocaleLangGroup(void)
|
||||
{
|
||||
if (!mLocaleLangGroup) {
|
||||
nsCOMPtr<nsILanguageAtomService> langService;
|
||||
langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
|
||||
if (langService) {
|
||||
mLocaleLangGroup = langService->GetLocaleLanguageGroup();
|
||||
}
|
||||
if (!mLocaleLangGroup) {
|
||||
mLocaleLangGroup = do_GetAtom("x-western");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont,
|
||||
nsIAtom* aLangGroup, gfxUserFontSet *aUserFontSet, nsIFontMetrics*& aMetrics)
|
||||
{
|
||||
if (nsnull == mFontCache) {
|
||||
nsresult rv = CreateFontCache();
|
||||
if (NS_FAILED(rv)) {
|
||||
aMetrics = nsnull;
|
||||
return rv;
|
||||
}
|
||||
// XXX temporary fix for performance problem -- erik
|
||||
GetLocaleLangGroup();
|
||||
}
|
||||
|
||||
// XXX figure out why aLangGroup is NULL sometimes
|
||||
if (!aLangGroup) {
|
||||
aLangGroup = mLocaleLangGroup;
|
||||
}
|
||||
|
||||
return mFontCache->GetMetricsFor(aFont, aLangGroup, aUserFontSet, aMetrics);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont,
|
||||
gfxUserFontSet *aUserFontSet,
|
||||
nsIFontMetrics*& aMetrics)
|
||||
{
|
||||
if (nsnull == mFontCache) {
|
||||
nsresult rv = CreateFontCache();
|
||||
if (NS_FAILED(rv)) {
|
||||
aMetrics = nsnull;
|
||||
return rv;
|
||||
}
|
||||
// XXX temporary fix for performance problem -- erik
|
||||
GetLocaleLangGroup();
|
||||
}
|
||||
return mFontCache->GetMetricsFor(aFont, mLocaleLangGroup, aUserFontSet,
|
||||
aMetrics);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::GetDepth(PRUint32& aDepth)
|
||||
{
|
||||
aDepth = 24;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::GetPaletteInfo(nsPaletteInfo& aPaletteInfo)
|
||||
{
|
||||
aPaletteInfo.isPaletteDevice = PR_FALSE;
|
||||
aPaletteInfo.sizePalette = 0;
|
||||
aPaletteInfo.numReserved = 0;
|
||||
aPaletteInfo.palette = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct FontEnumData {
|
||||
FontEnumData(nsIDeviceContext* aDC, nsString& aFaceName)
|
||||
: mDC(aDC), mFaceName(aFaceName)
|
||||
{}
|
||||
nsIDeviceContext* mDC;
|
||||
nsString& mFaceName;
|
||||
};
|
||||
|
||||
static PRBool FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
|
||||
{
|
||||
FontEnumData* data = (FontEnumData*)aData;
|
||||
// XXX for now, all generic fonts are presumed to exist
|
||||
// we may want to actually check if there's an installed conversion
|
||||
if (aGeneric) {
|
||||
data->mFaceName = aFamily;
|
||||
return PR_FALSE; // found one, stop.
|
||||
}
|
||||
else {
|
||||
nsAutoString local;
|
||||
PRBool aliased;
|
||||
data->mDC->GetLocalFontName(aFamily, local, aliased);
|
||||
if (aliased || (NS_SUCCEEDED(data->mDC->CheckFontExistence(local)))) {
|
||||
data->mFaceName = local;
|
||||
return PR_FALSE; // found one, stop.
|
||||
}
|
||||
}
|
||||
return PR_TRUE; // didn't exist, continue looking
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::FirstExistingFont(const nsFont& aFont, nsString& aFaceName)
|
||||
{
|
||||
FontEnumData data(this, aFaceName);
|
||||
if (aFont.EnumerateFamilies(FontEnumCallback, &data)) {
|
||||
return NS_ERROR_FAILURE; // ran out
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class FontAliasKey: public nsHashKey
|
||||
{
|
||||
public:
|
||||
FontAliasKey(const nsString& aString)
|
||||
{mString.Assign(aString);}
|
||||
|
||||
virtual PRUint32 HashCode(void) const;
|
||||
virtual PRBool Equals(const nsHashKey *aKey) const;
|
||||
virtual nsHashKey *Clone(void) const;
|
||||
|
||||
nsString mString;
|
||||
};
|
||||
|
||||
PRUint32 FontAliasKey::HashCode(void) const
|
||||
{
|
||||
PRUint32 hash = 0;
|
||||
const PRUnichar* string = mString.get();
|
||||
PRUnichar ch;
|
||||
while ((ch = *string++) != 0) {
|
||||
// FYI: hash = hash*37 + ch
|
||||
ch = ToUpperCase(ch);
|
||||
hash = ((hash << 5) + (hash << 2) + hash) + ch;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
PRBool FontAliasKey::Equals(const nsHashKey *aKey) const
|
||||
{
|
||||
return mString.Equals(((FontAliasKey*)aKey)->mString, nsCaseInsensitiveStringComparator());
|
||||
}
|
||||
|
||||
nsHashKey* FontAliasKey::Clone(void) const
|
||||
{
|
||||
return new FontAliasKey(mString);
|
||||
}
|
||||
nsresult DeviceContextImpl::CreateFontAliasTable()
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (nsnull == mFontAliasTable) {
|
||||
mFontAliasTable = new nsHashtable();
|
||||
if (nsnull != mFontAliasTable) {
|
||||
|
||||
nsAutoString times; times.AssignLiteral("Times");
|
||||
nsAutoString timesNewRoman; timesNewRoman.AssignLiteral("Times New Roman");
|
||||
nsAutoString timesRoman; timesRoman.AssignLiteral("Times Roman");
|
||||
nsAutoString arial; arial.AssignLiteral("Arial");
|
||||
nsAutoString helvetica; helvetica.AssignLiteral("Helvetica");
|
||||
nsAutoString courier; courier.AssignLiteral("Courier");
|
||||
nsAutoString courierNew; courierNew.AssignLiteral("Courier New");
|
||||
nsAutoString nullStr;
|
||||
|
||||
AliasFont(times, timesNewRoman, timesRoman, PR_FALSE);
|
||||
AliasFont(timesRoman, timesNewRoman, times, PR_FALSE);
|
||||
AliasFont(timesNewRoman, timesRoman, times, PR_FALSE);
|
||||
AliasFont(arial, helvetica, nullStr, PR_FALSE);
|
||||
AliasFont(helvetica, arial, nullStr, PR_FALSE);
|
||||
AliasFont(courier, courierNew, nullStr, PR_TRUE);
|
||||
AliasFont(courierNew, courier, nullStr, PR_FALSE);
|
||||
}
|
||||
else {
|
||||
result = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult DeviceContextImpl::AliasFont(const nsString& aFont,
|
||||
const nsString& aAlias, const nsString& aAltAlias,
|
||||
PRBool aForceAlias)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (nsnull != mFontAliasTable) {
|
||||
if (aForceAlias || NS_FAILED(CheckFontExistence(aFont))) {
|
||||
if (NS_SUCCEEDED(CheckFontExistence(aAlias))) {
|
||||
nsString* entry = new nsString(aAlias);
|
||||
if (nsnull != entry) {
|
||||
FontAliasKey key(aFont);
|
||||
mFontAliasTable->Put(&key, entry);
|
||||
}
|
||||
else {
|
||||
result = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
else if (!aAltAlias.IsEmpty() && NS_SUCCEEDED(CheckFontExistence(aAltAlias))) {
|
||||
nsString* entry = new nsString(aAltAlias);
|
||||
if (nsnull != entry) {
|
||||
FontAliasKey key(aFont);
|
||||
mFontAliasTable->Put(&key, entry);
|
||||
}
|
||||
else {
|
||||
result = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = NS_ERROR_FAILURE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::GetLocalFontName(const nsString& aFaceName, nsString& aLocalName,
|
||||
PRBool& aAliased)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (nsnull == mFontAliasTable) {
|
||||
result = CreateFontAliasTable();
|
||||
}
|
||||
|
||||
if (nsnull != mFontAliasTable) {
|
||||
FontAliasKey key(aFaceName);
|
||||
const nsString* alias = (const nsString*)mFontAliasTable->Get(&key);
|
||||
if (nsnull != alias) {
|
||||
aLocalName = *alias;
|
||||
aAliased = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
aLocalName = aFaceName;
|
||||
aAliased = PR_FALSE;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DeviceContextImpl::FlushFontCache(void)
|
||||
{
|
||||
if (nsnull != mFontCache)
|
||||
mFontCache->Flush();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
nsFontCache::nsFontCache()
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsFontCache);
|
||||
mContext = nsnull;
|
||||
}
|
||||
|
||||
nsFontCache::~nsFontCache()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsFontCache);
|
||||
Flush();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFontCache::Init(nsIDeviceContext* aContext)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aContext, "null ptr");
|
||||
// Note: we don't hold a reference to the device context, because it
|
||||
// holds a reference to us and we don't want circular references
|
||||
mContext = aContext;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFontCache::GetDeviceContext(nsIDeviceContext *&aContext) const
|
||||
{
|
||||
aContext = mContext;
|
||||
NS_IF_ADDREF(aContext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
|
||||
gfxUserFontSet *aUserFontSet, nsIFontMetrics *&aMetrics)
|
||||
{
|
||||
// First check our cache
|
||||
// start from the end, which is where we put the most-recent-used element
|
||||
|
||||
nsIFontMetrics* fm;
|
||||
PRInt32 n = mFontMetrics.Length() - 1;
|
||||
for (PRInt32 i = n; i >= 0; --i) {
|
||||
fm = mFontMetrics[i];
|
||||
nsIThebesFontMetrics* tfm = static_cast<nsIThebesFontMetrics*>(fm);
|
||||
if (fm->Font().Equals(aFont) && tfm->GetUserFontSet() == aUserFontSet) {
|
||||
nsCOMPtr<nsIAtom> langGroup;
|
||||
fm->GetLangGroup(getter_AddRefs(langGroup));
|
||||
if (aLangGroup == langGroup.get()) {
|
||||
if (i != n) {
|
||||
// promote it to the end of the cache
|
||||
mFontMetrics.RemoveElementAt(i);
|
||||
mFontMetrics.AppendElement(fm);
|
||||
}
|
||||
tfm->GetThebesFontGroup()->UpdateFontList();
|
||||
NS_ADDREF(aMetrics = fm);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It's not in the cache. Get font metrics and then cache them.
|
||||
|
||||
aMetrics = nsnull;
|
||||
nsresult rv = CreateFontMetricsInstance(&fm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = fm->Init(aFont, aLangGroup, mContext, aUserFontSet);
|
||||
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);
|
||||
|
||||
// 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, aUserFontSet);
|
||||
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.Length() - 1; // could have changed in Compact()
|
||||
if (n >= 0) {
|
||||
aMetrics = mFontMetrics[n];
|
||||
NS_ADDREF(aMetrics);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_POSTCONDITION(NS_SUCCEEDED(rv), "font metrics should not be null - bug 136248");
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* PostScript module may override this method to create
|
||||
* nsIFontMetrics objects with their own classes
|
||||
*/
|
||||
nsresult
|
||||
nsFontCache::CreateFontMetricsInstance(nsIFontMetrics** fm)
|
||||
{
|
||||
static NS_DEFINE_CID(kFontMetricsCID, NS_FONT_METRICS_CID);
|
||||
return CallCreateInstance(kFontMetricsCID, fm);
|
||||
}
|
||||
|
||||
nsresult nsFontCache::FontMetricsDeleted(const nsIFontMetrics* aFontMetrics)
|
||||
{
|
||||
mFontMetrics.RemoveElement(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.Length()-1; i >= 0; --i) {
|
||||
nsIFontMetrics* fm = 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()
|
||||
{
|
||||
for (PRInt32 i = mFontMetrics.Length()-1; i >= 0; --i) {
|
||||
nsIFontMetrics* fm = 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);
|
||||
}
|
||||
|
||||
mFontMetrics.Clear();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DeviceContextImpl::PrepareNativeWidget(nsIWidget *aWidget, void **aOut)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DeviceContextImpl::ClearCachedSystemFonts()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
|
@ -57,6 +57,7 @@ REQUIRES = xpcom \
|
|||
string \
|
||||
thebes \
|
||||
widget \
|
||||
locale \
|
||||
view \
|
||||
pref \
|
||||
unicharutil \
|
||||
|
@ -65,6 +66,10 @@ REQUIRES = xpcom \
|
|||
qcms \
|
||||
$(NULL)
|
||||
|
||||
ifeq (,$(filter windows,$(MOZ_WIDGET_TOOLKIT)))
|
||||
REQUIRES += uconv
|
||||
endif
|
||||
|
||||
CPPSRCS = \
|
||||
nsThebesDeviceContext.cpp \
|
||||
nsThebesImage.cpp \
|
||||
|
|
|
@ -37,12 +37,20 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsFont.h"
|
||||
#include "nsGfxCIID.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsILanguageAtomService.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
#include "nsThebesDeviceContext.h"
|
||||
#include "nsThebesRenderingContext.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIView.h"
|
||||
|
@ -114,7 +122,176 @@ static int x11_error_handler (Display *dpy, XErrorEvent *err) {
|
|||
PRLogModuleInfo* gThebesGFXLog = nsnull;
|
||||
#endif
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(nsThebesDeviceContext, DeviceContextImpl)
|
||||
class nsFontCache
|
||||
{
|
||||
public:
|
||||
nsFontCache();
|
||||
~nsFontCache();
|
||||
|
||||
nsresult Init(nsIDeviceContext* aContext);
|
||||
nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
|
||||
gfxUserFontSet* aUserFontSet,
|
||||
nsIFontMetrics*& aMetrics);
|
||||
|
||||
nsresult FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
|
||||
nsresult Compact();
|
||||
nsresult Flush();
|
||||
nsresult CreateFontMetricsInstance(nsIFontMetrics** fm);
|
||||
|
||||
protected:
|
||||
nsTArray<nsIFontMetrics*> mFontMetrics;
|
||||
nsIDeviceContext *mContext; // we do not addref this since
|
||||
// ownership is implied. MMP.
|
||||
};
|
||||
|
||||
nsFontCache::nsFontCache()
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsFontCache);
|
||||
mContext = nsnull;
|
||||
}
|
||||
|
||||
nsFontCache::~nsFontCache()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsFontCache);
|
||||
Flush();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFontCache::Init(nsIDeviceContext* aContext)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aContext, "null ptr");
|
||||
// Note: we don't hold a reference to the device context, because it
|
||||
// holds a reference to us and we don't want circular references
|
||||
mContext = aContext;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
|
||||
gfxUserFontSet* aUserFontSet, nsIFontMetrics*& aMetrics)
|
||||
{
|
||||
// First check our cache
|
||||
// start from the end, which is where we put the most-recent-used element
|
||||
|
||||
nsIFontMetrics* fm;
|
||||
PRInt32 n = mFontMetrics.Length() - 1;
|
||||
for (PRInt32 i = n; i >= 0; --i) {
|
||||
fm = mFontMetrics[i];
|
||||
nsIThebesFontMetrics* tfm = static_cast<nsIThebesFontMetrics*>(fm);
|
||||
if (fm->Font().Equals(aFont) && tfm->GetUserFontSet() == aUserFontSet) {
|
||||
nsCOMPtr<nsIAtom> langGroup;
|
||||
fm->GetLangGroup(getter_AddRefs(langGroup));
|
||||
if (aLangGroup == langGroup.get()) {
|
||||
if (i != n) {
|
||||
// promote it to the end of the cache
|
||||
mFontMetrics.RemoveElementAt(i);
|
||||
mFontMetrics.AppendElement(fm);
|
||||
}
|
||||
tfm->GetThebesFontGroup()->UpdateFontList();
|
||||
NS_ADDREF(aMetrics = fm);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It's not in the cache. Get font metrics and then cache them.
|
||||
|
||||
aMetrics = nsnull;
|
||||
nsresult rv = CreateFontMetricsInstance(&fm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = fm->Init(aFont, aLangGroup, mContext, aUserFontSet);
|
||||
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);
|
||||
|
||||
// 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, aUserFontSet);
|
||||
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.Length() - 1; // could have changed in Compact()
|
||||
if (n >= 0) {
|
||||
aMetrics = mFontMetrics[n];
|
||||
NS_ADDREF(aMetrics);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_POSTCONDITION(NS_SUCCEEDED(rv), "font metrics should not be null - bug 136248");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFontCache::CreateFontMetricsInstance(nsIFontMetrics** fm)
|
||||
{
|
||||
static NS_DEFINE_CID(kFontMetricsCID, NS_FONT_METRICS_CID);
|
||||
return CallCreateInstance(kFontMetricsCID, fm);
|
||||
}
|
||||
|
||||
nsresult nsFontCache::FontMetricsDeleted(const nsIFontMetrics* aFontMetrics)
|
||||
{
|
||||
mFontMetrics.RemoveElement(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.Length()-1; i >= 0; --i) {
|
||||
nsIFontMetrics* fm = 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()
|
||||
{
|
||||
for (PRInt32 i = mFontMetrics.Length()-1; i >= 0; --i) {
|
||||
nsIFontMetrics* fm = 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);
|
||||
}
|
||||
|
||||
mFontMetrics.Clear();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS3(nsThebesDeviceContext, nsIDeviceContext, nsIObserver, nsISupportsWeakReference)
|
||||
|
||||
nsThebesDeviceContext::nsThebesDeviceContext()
|
||||
{
|
||||
|
@ -125,6 +302,19 @@ nsThebesDeviceContext::nsThebesDeviceContext()
|
|||
|
||||
PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("#### Creating DeviceContext %p\n", this));
|
||||
|
||||
mAppUnitsPerDevPixel = nscoord(-1);
|
||||
mAppUnitsPerInch = nscoord(-1);
|
||||
mAppUnitsPerDevNotScaledPixel = nscoord(-1);
|
||||
mPixelScale = 1.0f;
|
||||
|
||||
mFontCache = nsnull;
|
||||
mWidget = nsnull;
|
||||
mFontAliasTable = nsnull;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
mInitialized = PR_FALSE;
|
||||
#endif
|
||||
|
||||
mDepth = 0;
|
||||
mWidth = 0;
|
||||
mHeight = 0;
|
||||
|
@ -136,8 +326,281 @@ nsThebesDeviceContext::nsThebesDeviceContext()
|
|||
#endif
|
||||
}
|
||||
|
||||
static PRBool DeleteValue(nsHashKey* aKey, void* aValue, void* closure)
|
||||
{
|
||||
delete ((nsString*)aValue);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsThebesDeviceContext::~nsThebesDeviceContext()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
|
||||
if (obs)
|
||||
obs->RemoveObserver(this, "memory-pressure");
|
||||
|
||||
if (nsnull != mFontCache) {
|
||||
delete mFontCache;
|
||||
mFontCache = nsnull;
|
||||
}
|
||||
|
||||
if (nsnull != mFontAliasTable) {
|
||||
mFontAliasTable->Enumerate(DeleteValue);
|
||||
delete mFontAliasTable;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThebesDeviceContext::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aSomeData)
|
||||
{
|
||||
if (mFontCache && !nsCRT::strcmp(aTopic, "memory-pressure")) {
|
||||
mFontCache->Compact();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsThebesDeviceContext::CreateFontCache()
|
||||
{
|
||||
mFontCache = new nsFontCache();
|
||||
if (!mFontCache) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return mFontCache->Init(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsThebesDeviceContext::FontMetricsDeleted(const nsIFontMetrics* aFontMetrics)
|
||||
{
|
||||
if (mFontCache) {
|
||||
mFontCache->FontMetricsDeleted(aFontMetrics);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsThebesDeviceContext::GetLocaleLangGroup(void)
|
||||
{
|
||||
if (!mLocaleLangGroup) {
|
||||
nsCOMPtr<nsILanguageAtomService> langService;
|
||||
langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
|
||||
if (langService) {
|
||||
mLocaleLangGroup = langService->GetLocaleLanguageGroup();
|
||||
}
|
||||
if (!mLocaleLangGroup) {
|
||||
mLocaleLangGroup = do_GetAtom("x-western");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsThebesDeviceContext::GetMetricsFor(const nsFont& aFont,
|
||||
nsIAtom* aLangGroup, gfxUserFontSet* aUserFontSet, nsIFontMetrics*& aMetrics)
|
||||
{
|
||||
if (nsnull == mFontCache) {
|
||||
nsresult rv = CreateFontCache();
|
||||
if (NS_FAILED(rv)) {
|
||||
aMetrics = nsnull;
|
||||
return rv;
|
||||
}
|
||||
// XXX temporary fix for performance problem -- erik
|
||||
GetLocaleLangGroup();
|
||||
}
|
||||
|
||||
// XXX figure out why aLangGroup is NULL sometimes
|
||||
if (!aLangGroup) {
|
||||
aLangGroup = mLocaleLangGroup;
|
||||
}
|
||||
|
||||
return mFontCache->GetMetricsFor(aFont, aLangGroup, aUserFontSet, aMetrics);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsThebesDeviceContext::GetMetricsFor(const nsFont& aFont,
|
||||
gfxUserFontSet* aUserFontSet,
|
||||
nsIFontMetrics*& aMetrics)
|
||||
{
|
||||
if (nsnull == mFontCache) {
|
||||
nsresult rv = CreateFontCache();
|
||||
if (NS_FAILED(rv)) {
|
||||
aMetrics = nsnull;
|
||||
return rv;
|
||||
}
|
||||
// XXX temporary fix for performance problem -- erik
|
||||
GetLocaleLangGroup();
|
||||
}
|
||||
return mFontCache->GetMetricsFor(aFont, mLocaleLangGroup, aUserFontSet,
|
||||
aMetrics);
|
||||
}
|
||||
|
||||
struct FontEnumData {
|
||||
FontEnumData(nsIDeviceContext* aDC, nsString& aFaceName)
|
||||
: mDC(aDC), mFaceName(aFaceName)
|
||||
{}
|
||||
nsIDeviceContext* mDC;
|
||||
nsString& mFaceName;
|
||||
};
|
||||
|
||||
static PRBool FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
|
||||
{
|
||||
FontEnumData* data = (FontEnumData*)aData;
|
||||
// XXX for now, all generic fonts are presumed to exist
|
||||
// we may want to actually check if there's an installed conversion
|
||||
if (aGeneric) {
|
||||
data->mFaceName = aFamily;
|
||||
return PR_FALSE; // found one, stop.
|
||||
}
|
||||
else {
|
||||
nsAutoString local;
|
||||
PRBool aliased;
|
||||
data->mDC->GetLocalFontName(aFamily, local, aliased);
|
||||
if (aliased || (NS_SUCCEEDED(data->mDC->CheckFontExistence(local)))) {
|
||||
data->mFaceName = local;
|
||||
return PR_FALSE; // found one, stop.
|
||||
}
|
||||
}
|
||||
return PR_TRUE; // didn't exist, continue looking
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsThebesDeviceContext::FirstExistingFont(const nsFont& aFont, nsString& aFaceName)
|
||||
{
|
||||
FontEnumData data(this, aFaceName);
|
||||
if (aFont.EnumerateFamilies(FontEnumCallback, &data)) {
|
||||
return NS_ERROR_FAILURE; // ran out
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class FontAliasKey: public nsHashKey
|
||||
{
|
||||
public:
|
||||
FontAliasKey(const nsString& aString)
|
||||
{ mString.Assign(aString); }
|
||||
|
||||
virtual PRUint32 HashCode(void) const;
|
||||
virtual PRBool Equals(const nsHashKey *aKey) const;
|
||||
virtual nsHashKey *Clone(void) const;
|
||||
|
||||
nsString mString;
|
||||
};
|
||||
|
||||
PRUint32 FontAliasKey::HashCode(void) const
|
||||
{
|
||||
PRUint32 hash = 0;
|
||||
const PRUnichar* string = mString.get();
|
||||
PRUnichar ch;
|
||||
while ((ch = *string++) != 0) {
|
||||
// FYI: hash = hash*37 + ch
|
||||
ch = ToUpperCase(ch);
|
||||
hash = ((hash << 5) + (hash << 2) + hash) + ch;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
PRBool FontAliasKey::Equals(const nsHashKey *aKey) const
|
||||
{
|
||||
return mString.Equals(((FontAliasKey*)aKey)->mString, nsCaseInsensitiveStringComparator());
|
||||
}
|
||||
|
||||
nsHashKey* FontAliasKey::Clone(void) const
|
||||
{
|
||||
return new FontAliasKey(mString);
|
||||
}
|
||||
|
||||
nsresult nsThebesDeviceContext::CreateFontAliasTable()
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (nsnull == mFontAliasTable) {
|
||||
mFontAliasTable = new nsHashtable();
|
||||
if (nsnull != mFontAliasTable) {
|
||||
|
||||
nsAutoString times; times.AssignLiteral("Times");
|
||||
nsAutoString timesNewRoman; timesNewRoman.AssignLiteral("Times New Roman");
|
||||
nsAutoString timesRoman; timesRoman.AssignLiteral("Times Roman");
|
||||
nsAutoString arial; arial.AssignLiteral("Arial");
|
||||
nsAutoString helvetica; helvetica.AssignLiteral("Helvetica");
|
||||
nsAutoString courier; courier.AssignLiteral("Courier");
|
||||
nsAutoString courierNew; courierNew.AssignLiteral("Courier New");
|
||||
nsAutoString nullStr;
|
||||
|
||||
AliasFont(times, timesNewRoman, timesRoman, PR_FALSE);
|
||||
AliasFont(timesRoman, timesNewRoman, times, PR_FALSE);
|
||||
AliasFont(timesNewRoman, timesRoman, times, PR_FALSE);
|
||||
AliasFont(arial, helvetica, nullStr, PR_FALSE);
|
||||
AliasFont(helvetica, arial, nullStr, PR_FALSE);
|
||||
AliasFont(courier, courierNew, nullStr, PR_TRUE);
|
||||
AliasFont(courierNew, courier, nullStr, PR_FALSE);
|
||||
}
|
||||
else {
|
||||
result = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult nsThebesDeviceContext::AliasFont(const nsString& aFont,
|
||||
const nsString& aAlias,
|
||||
const nsString& aAltAlias,
|
||||
PRBool aForceAlias)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (nsnull != mFontAliasTable) {
|
||||
if (aForceAlias || NS_FAILED(CheckFontExistence(aFont))) {
|
||||
if (NS_SUCCEEDED(CheckFontExistence(aAlias))) {
|
||||
nsString* entry = new nsString(aAlias);
|
||||
if (nsnull != entry) {
|
||||
FontAliasKey key(aFont);
|
||||
mFontAliasTable->Put(&key, entry);
|
||||
}
|
||||
else {
|
||||
result = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
else if (!aAltAlias.IsEmpty() && NS_SUCCEEDED(CheckFontExistence(aAltAlias))) {
|
||||
nsString* entry = new nsString(aAltAlias);
|
||||
if (nsnull != entry) {
|
||||
FontAliasKey key(aFont);
|
||||
mFontAliasTable->Put(&key, entry);
|
||||
}
|
||||
else {
|
||||
result = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = NS_ERROR_FAILURE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsThebesDeviceContext::GetLocalFontName(const nsString& aFaceName,
|
||||
nsString& aLocalName,
|
||||
PRBool& aAliased)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (nsnull == mFontAliasTable) {
|
||||
result = CreateFontAliasTable();
|
||||
}
|
||||
|
||||
if (nsnull != mFontAliasTable) {
|
||||
FontAliasKey key(aFaceName);
|
||||
const nsString* alias = (const nsString*)mFontAliasTable->Get(&key);
|
||||
if (nsnull != alias) {
|
||||
aLocalName = *alias;
|
||||
aAliased = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
aLocalName = aFaceName;
|
||||
aAliased = PR_FALSE;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsThebesDeviceContext::FlushFontCache(void)
|
||||
{
|
||||
if (nsnull != mFontCache)
|
||||
mFontCache->Flush();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
|
@ -286,7 +749,16 @@ nsThebesDeviceContext::Init(nsNativeWidget aWidget)
|
|||
|
||||
SetDPI();
|
||||
|
||||
CommonInit();
|
||||
#ifdef NS_DEBUG
|
||||
NS_ASSERTION(!mInitialized, "device context is initialized twice!");
|
||||
mInitialized = PR_TRUE;
|
||||
#endif
|
||||
|
||||
// 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_TRUE);
|
||||
|
||||
#if defined(MOZ_ENABLE_GTK2) && defined(MOZ_X11)
|
||||
if (getenv ("MOZ_X_SYNC")) {
|
||||
|
@ -466,7 +938,6 @@ nsThebesDeviceContext::GetPaletteInfo(nsPaletteInfo& aPaletteInfo)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThebesDeviceContext::ConvertPixel(nscolor aColor, PRUint32 & aPixel)
|
||||
{
|
||||
|
@ -691,10 +1162,8 @@ nsThebesDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect)
|
|||
mWidth = outRect->width;
|
||||
mHeight = outRect->height;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FindScreen
|
||||
//
|
||||
|
|
|
@ -41,16 +41,20 @@
|
|||
#define _NS_THEBESDEVICECONTEXT_H_
|
||||
|
||||
#include "nsIScreenManager.h"
|
||||
|
||||
#include "nsDeviceContext.h"
|
||||
#include "nsIDeviceContext.h"
|
||||
#include "nsIDeviceContextSpec.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "gfxContext.h"
|
||||
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
#include "prlog.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gThebesGFXLog;
|
||||
#endif
|
||||
|
@ -61,7 +65,12 @@ extern PRLogModuleInfo* gThebesGFXLog;
|
|||
#include "gfxOS2Surface.h"
|
||||
#endif
|
||||
|
||||
class nsThebesDeviceContext : public DeviceContextImpl
|
||||
class nsHashtable;
|
||||
class nsFontCache;
|
||||
|
||||
class nsThebesDeviceContext : public nsIDeviceContext,
|
||||
public nsIObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
nsThebesDeviceContext();
|
||||
|
@ -69,16 +78,32 @@ public:
|
|||
|
||||
static void Shutdown();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
NS_IMETHOD Init(nsNativeWidget aWidget);
|
||||
NS_IMETHOD InitForPrinting(nsIDeviceContextSpec *aDevSpec);
|
||||
NS_IMETHOD CreateRenderingContext(nsIView *aView, nsIRenderingContext *&aContext);
|
||||
|
||||
NS_IMETHOD CreateRenderingContext(nsIWidget *aWidget, nsIRenderingContext *&aContext);
|
||||
NS_IMETHOD CreateRenderingContext(nsIRenderingContext *&aContext);
|
||||
NS_IMETHOD CreateRenderingContextInstance(nsIRenderingContext *&aContext);
|
||||
|
||||
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
|
||||
gfxUserFontSet* aUserFontSet,
|
||||
nsIFontMetrics*& aMetrics);
|
||||
NS_IMETHOD GetMetricsFor(const nsFont& aFont,
|
||||
gfxUserFontSet* aUserFontSet,
|
||||
nsIFontMetrics*& aMetrics);
|
||||
|
||||
NS_IMETHOD FirstExistingFont(const nsFont& aFont, nsString& aFaceName);
|
||||
|
||||
NS_IMETHOD GetLocalFontName(const nsString& aFaceName, nsString& aLocalName,
|
||||
PRBool& aAliased);
|
||||
|
||||
NS_IMETHOD CreateFontCache();
|
||||
NS_IMETHOD FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
|
||||
NS_IMETHOD FlushFontCache(void);
|
||||
|
||||
NS_IMETHOD SupportsNativeWidgets(PRBool& aSupportsWidgets);
|
||||
NS_IMETHOD PrepareNativeWidget(nsIWidget *aWidget, void **aOut);
|
||||
|
||||
|
@ -93,7 +118,7 @@ public:
|
|||
|
||||
NS_IMETHOD ConvertPixel(nscolor aColor, PRUint32& aPixel);
|
||||
|
||||
NS_IMETHOD GetDeviceSurfaceDimensions(PRInt32& aWidth, PRInt32& aHeight);
|
||||
NS_IMETHOD GetDeviceSurfaceDimensions(nscoord& aWidth, nscoord& aHeight);
|
||||
NS_IMETHOD GetRect(nsRect& aRect);
|
||||
NS_IMETHOD GetClientRect(nsRect& aRect);
|
||||
|
||||
|
@ -126,6 +151,11 @@ public:
|
|||
#endif
|
||||
|
||||
protected:
|
||||
virtual nsresult CreateFontAliasTable();
|
||||
nsresult AliasFont(const nsString& aFont,
|
||||
const nsString& aAlias, const nsString& aAltAlias,
|
||||
PRBool aForceAlias);
|
||||
void GetLocaleLangGroup(void);
|
||||
nsresult SetDPI();
|
||||
void ComputeClientRectUsingScreen(nsRect *outRect);
|
||||
void ComputeFullAreaUsingScreen(nsRect *outRect);
|
||||
|
@ -133,7 +163,14 @@ protected:
|
|||
void CalcPrintingSize();
|
||||
void UpdateScaledAppUnits();
|
||||
|
||||
PRUint32 mDepth;
|
||||
PRUint32 mDepth;
|
||||
nsFontCache* mFontCache;
|
||||
nsCOMPtr<nsIAtom> mLocaleLangGroup; // XXX temp fix for performance bug - erik
|
||||
nsHashtable* mFontAliasTable;
|
||||
nsNativeWidget mWidget;
|
||||
#ifdef NS_DEBUG
|
||||
PRBool mInitialized;
|
||||
#endif
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIScreenManager> mScreenManager;
|
||||
|
|
Загрузка…
Ссылка в новой задаче