зеркало из https://github.com/mozilla/pjs.git
Bug 602792. Use GDI for font table loading to avoid excessive dwrite I/O. r=bas, a=blocker
This commit is contained in:
Родитель
ab4ce354c6
Коммит
8910f7df7e
|
@ -275,7 +275,7 @@ CPPSRCS += gfxGDIFont.cpp \
|
|||
gfxGDIShaper.cpp \
|
||||
gfxUniscribeShaper.cpp \
|
||||
$(NULL)
|
||||
_OS_LIBS = usp10 msimg32 ole32 version
|
||||
_OS_LIBS = usp10 msimg32 ole32 version advapi32
|
||||
endif
|
||||
|
||||
CPPSRCS += gfxPDFSurface.cpp
|
||||
|
|
|
@ -34,19 +34,34 @@
|
|||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#ifdef MOZ_LOGGING
|
||||
#define FORCE_PR_LOG /* Allow logging in the release build */
|
||||
#endif /* MOZ_LOGGING */
|
||||
|
||||
#include "gfxDWriteFontList.h"
|
||||
#include "gfxDWriteFonts.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsILocaleService.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranch2.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#include "gfxGDIFontList.h"
|
||||
|
||||
#include "nsIWindowsRegKey.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo *gFontInitLog = nsnull;
|
||||
#define LOG(args) PR_LOG(gFontInitLog, PR_LOG_DEBUG, args)
|
||||
#define LOG_ENABLED() (gFontInitLog) && PR_LOG_TEST(gFontInitLog, PR_LOG_DEBUG)
|
||||
#endif /* PR_LOGGING */
|
||||
|
||||
// font info loader constants
|
||||
static const PRUint32 kDelayBeforeLoadingFonts = 8 * 1000; // 8secs
|
||||
static const PRUint32 kIntervalBetweenLoadingFonts = 150; // 150ms
|
||||
|
||||
// avoid doing this during startup even on slow machines but try to start
|
||||
// it soon enough so that system fallback doesn't happen first
|
||||
static const PRUint32 kDelayBeforeLoadingFonts = 120 * 1000; // 2 minutes after init
|
||||
static const PRUint32 kIntervalBetweenLoadingFonts = 2000; // every 2 seconds until complete
|
||||
|
||||
static __inline void
|
||||
BuildKeyNameFromFontName(nsAString &aName)
|
||||
|
@ -227,9 +242,34 @@ nsresult
|
|||
gfxDWriteFontEntry::GetFontTable(PRUint32 aTableTag,
|
||||
FallibleTArray<PRUint8> &aBuffer)
|
||||
{
|
||||
nsRefPtr<IDWriteFontFace> fontFace;
|
||||
gfxDWriteFontList *pFontList = gfxDWriteFontList::PlatformFontList();
|
||||
|
||||
if (mFont && pFontList->UseGDIFontTableAccess()) {
|
||||
LOGFONTW logfont = { 0 };
|
||||
if (!InitLogFont(mFont, &logfont))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
AutoDC dc;
|
||||
AutoSelectFont font(dc.GetDC(), &logfont);
|
||||
if (font.IsValid()) {
|
||||
PRInt32 tableSize =
|
||||
::GetFontData(dc.GetDC(), NS_SWAP32(aTableTag), 0, NULL, NULL);
|
||||
if (tableSize != GDI_ERROR) {
|
||||
if (aBuffer.SetLength(tableSize)) {
|
||||
::GetFontData(dc.GetDC(), NS_SWAP32(aTableTag), 0,
|
||||
aBuffer.Elements(), aBuffer.Length());
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
nsresult rv;
|
||||
nsRefPtr<IDWriteFontFace> fontFace;
|
||||
|
||||
rv = CreateFontFace(getter_AddRefs(fontFace));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -262,9 +302,33 @@ gfxDWriteFontEntry::GetFontTable(PRUint32 aTableTag,
|
|||
nsresult
|
||||
gfxDWriteFontEntry::ReadCMAP()
|
||||
{
|
||||
nsRefPtr<IDWriteFontFace> fontFace;
|
||||
HRESULT hr;
|
||||
nsresult rv;
|
||||
|
||||
// attempt this once, if errors occur leave a blank cmap
|
||||
if (mCmapInitialized)
|
||||
return NS_OK;
|
||||
mCmapInitialized = PR_TRUE;
|
||||
|
||||
// if loading via GDI, just use GetFontTable
|
||||
if (mFont && gfxDWriteFontList::PlatformFontList()->UseGDIFontTableAccess()) {
|
||||
const PRUint32 kCmapTag = TRUETYPE_TAG('c','m','a','p');
|
||||
AutoFallibleTArray<PRUint8,16384> buffer;
|
||||
|
||||
if (GetFontTable(kCmapTag, buffer) != NS_OK)
|
||||
return NS_ERROR_FAILURE;
|
||||
PRUint8 *cmap = buffer.Elements();
|
||||
|
||||
PRPackedBool unicodeFont = PR_FALSE, symbolFont = PR_FALSE;
|
||||
rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
|
||||
mCharacterMap, mUVSOffset,
|
||||
unicodeFont, symbolFont);
|
||||
mHasCmapTable = NS_SUCCEEDED(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// loading using dwrite, don't use GetFontTable to avoid copy
|
||||
nsRefPtr<IDWriteFontFace> fontFace;
|
||||
rv = CreateFontFace(getter_AddRefs(fontFace));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -296,7 +360,6 @@ gfxDWriteFontEntry::ReadCMAP()
|
|||
}
|
||||
fontFace->ReleaseFontTable(tableContext);
|
||||
|
||||
mCmapInitialized = PR_TRUE;
|
||||
mHasCmapTable = NS_SUCCEEDED(rv);
|
||||
return rv;
|
||||
}
|
||||
|
@ -331,6 +394,18 @@ gfxDWriteFontEntry::CreateFontFace(IDWriteFontFace **aFontFace,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
gfxDWriteFontEntry::InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
BOOL isInSystemCollection;
|
||||
IDWriteGdiInterop *gdi =
|
||||
gfxDWriteFontList::PlatformFontList()->GetGDIInterop();
|
||||
hr = gdi->ConvertFontToLOGFONT(aFont, aLogFont, &isInSystemCollection);
|
||||
return (FAILED(hr) ? PR_FALSE : PR_TRUE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// gfxDWriteFontList
|
||||
|
||||
|
@ -339,16 +414,27 @@ gfxDWriteFontList::gfxDWriteFontList()
|
|||
mFontSubstitutes.Init();
|
||||
}
|
||||
|
||||
// bug 602792 - CJK systems default to large CJK fonts which cause excessive
|
||||
// I/O strain during cold startup due to dwrite caching bugs. Default to
|
||||
// Arial to avoid this.
|
||||
|
||||
gfxFontEntry *
|
||||
gfxDWriteFontList::GetDefaultFont(const gfxFontStyle *aStyle,
|
||||
PRBool &aNeedsBold)
|
||||
{
|
||||
nsAutoString resolvedName;
|
||||
|
||||
// try Arial first
|
||||
if (ResolveFontName(NS_LITERAL_STRING("Arial"), resolvedName)) {
|
||||
return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
|
||||
}
|
||||
|
||||
// otherwise, use local default
|
||||
NONCLIENTMETRICSW ncm;
|
||||
ncm.cbSize = sizeof(ncm);
|
||||
BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
|
||||
sizeof(ncm), &ncm, 0);
|
||||
if (status) {
|
||||
nsAutoString resolvedName;
|
||||
if (ResolveFontName(nsDependentString(ncm.lfMessageFont.lfFaceName),
|
||||
resolvedName)) {
|
||||
return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
|
||||
|
@ -470,17 +556,52 @@ gfxDWriteFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
|
|||
nsresult
|
||||
gfxDWriteFontList::InitFontList()
|
||||
{
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
gFontInitLog = PR_NewLogModule("fontinit");
|
||||
|
||||
LARGE_INTEGER frequency; // ticks per second
|
||||
LARGE_INTEGER t1, t2, t3, t4, t5, t6; // ticks
|
||||
double elapsedTime, upTime;
|
||||
char nowTime[256], nowDate[256];
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT,
|
||||
NULL, NULL, nowTime, 256);
|
||||
GetDateFormat(LOCALE_INVARIANT, NULL, NULL, NULL, nowDate, 256);
|
||||
upTime = (double) GetTickCount();
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
QueryPerformanceCounter(&t1);
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT hr;
|
||||
gfxFontCache *fc = gfxFontCache::GetCache();
|
||||
if (fc) {
|
||||
fc->AgeAllGenerations();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrefBranch2> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
nsresult rv;
|
||||
|
||||
rv = pref->GetBoolPref(
|
||||
"gfx.font_rendering.directwrite.use_gdi_table_loading",
|
||||
&mGDIFontTableAccess);
|
||||
if (NS_FAILED(rv)) {
|
||||
mGDIFontTableAccess = PR_FALSE;
|
||||
}
|
||||
|
||||
gfxPlatformFontList::InitFontList();
|
||||
|
||||
mFontSubstitutes.Clear();
|
||||
mNonExistingFonts.Clear();
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (LOG_ENABLED()) {
|
||||
QueryPerformanceCounter(&t2);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsRefPtr<IDWriteFontCollection> systemFonts;
|
||||
hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
|
||||
GetSystemFontCollection(getter_AddRefs(systemFonts));
|
||||
|
@ -490,6 +611,24 @@ gfxDWriteFontList::InitFontList()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (LOG_ENABLED()) {
|
||||
QueryPerformanceCounter(&t3);
|
||||
}
|
||||
#endif
|
||||
|
||||
hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
|
||||
GetGdiInterop(getter_AddRefs(mGDIInterop));
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (LOG_ENABLED()) {
|
||||
QueryPerformanceCounter(&t4);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (UINT32 i = 0; i < systemFonts->GetFontFamilyCount(); i++) {
|
||||
nsRefPtr<IDWriteFontFamily> family;
|
||||
systemFonts->GetFontFamily(i, getter_AddRefs(family));
|
||||
|
@ -596,6 +735,33 @@ gfxDWriteFontList::InitFontList()
|
|||
|
||||
StartLoader(kDelayBeforeLoadingFonts, kIntervalBetweenLoadingFonts);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (LOG_ENABLED()) {
|
||||
QueryPerformanceCounter(&t5);
|
||||
|
||||
// determine dwrite version
|
||||
nsAutoString dwriteVers;
|
||||
gfxWindowsPlatform::GetPlatform()->GetDLLVersion(L"dwrite.dll",
|
||||
dwriteVers);
|
||||
LOG(("InitFontList\n"));
|
||||
LOG(("Start: %s %s\n", nowDate, nowTime));
|
||||
LOG(("Uptime: %9.3f s\n", upTime/1000));
|
||||
LOG(("dwrite version: %s\n", NS_ConvertUTF16toUTF8(dwriteVers).get()));
|
||||
elapsedTime = (t5.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
|
||||
LOG(("Total time in InitFontList: %9.3f ms (families: %d, %s)\n",
|
||||
elapsedTime, systemFonts->GetFontFamilyCount(),
|
||||
(mGDIFontTableAccess ? "gdi table access" : "dwrite table access")));
|
||||
elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
|
||||
LOG((" --- gfxPlatformFontList init: %9.3f ms\n", elapsedTime));
|
||||
elapsedTime = (t3.QuadPart - t2.QuadPart) * 1000.0 / frequency.QuadPart;
|
||||
LOG((" --- GetSystemFontCollection: %9.3f ms\n", elapsedTime));
|
||||
elapsedTime = (t4.QuadPart - t3.QuadPart) * 1000.0 / frequency.QuadPart;
|
||||
LOG((" --- GdiInterop object: %9.3f ms\n", elapsedTime));
|
||||
elapsedTime = (t5.QuadPart - t4.QuadPart) * 1000.0 / frequency.QuadPart;
|
||||
LOG((" --- iterate over families: %9.3f ms\n", elapsedTime));
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -607,48 +773,42 @@ RemoveCharsetFromFontSubstitute(nsAString &aName)
|
|||
aName.Truncate(comma);
|
||||
}
|
||||
|
||||
#define MAX_VALUE_NAME 512
|
||||
#define MAX_VALUE_DATA 512
|
||||
|
||||
nsresult
|
||||
gfxDWriteFontList::GetFontSubstitutes()
|
||||
{
|
||||
// Create the list of FontSubstitutes
|
||||
nsCOMPtr<nsIWindowsRegKey> regKey =
|
||||
do_CreateInstance("@mozilla.org/windows-registry-key;1");
|
||||
if (!regKey) {
|
||||
HKEY hKey;
|
||||
DWORD i, rv, lenAlias, lenActual, valueType;
|
||||
WCHAR aliasName[MAX_VALUE_NAME];
|
||||
WCHAR actualName[MAX_VALUE_DATA];
|
||||
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
|
||||
0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
NS_NAMED_LITERAL_STRING(
|
||||
kFontSubstitutesKey,
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
|
||||
|
||||
nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
|
||||
kFontSubstitutesKey,
|
||||
nsIWindowsRegKey::ACCESS_READ);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) {
|
||||
aliasName[0] = 0;
|
||||
lenAlias = sizeof(aliasName);
|
||||
actualName[0] = 0;
|
||||
lenActual = sizeof(actualName);
|
||||
rv = RegEnumValueW(hKey, i, aliasName, &lenAlias, NULL, &valueType,
|
||||
(LPBYTE)actualName, &lenActual);
|
||||
|
||||
PRUint32 count;
|
||||
rv = regKey->GetValueCount(&count);
|
||||
if (NS_FAILED(rv) || count == 0)
|
||||
return rv;
|
||||
for (PRUint32 i = 0; i < count; i++) {
|
||||
nsAutoString substituteName;
|
||||
rv = regKey->GetValueName(i, substituteName);
|
||||
if (NS_FAILED(rv) || substituteName.IsEmpty() ||
|
||||
substituteName.CharAt(1) == PRUnichar('@')) {
|
||||
continue;
|
||||
}
|
||||
PRUint32 valueType;
|
||||
rv = regKey->GetValueType(substituteName, &valueType);
|
||||
if (NS_FAILED(rv) || valueType != nsIWindowsRegKey::TYPE_STRING) {
|
||||
continue;
|
||||
}
|
||||
nsAutoString actualFontName;
|
||||
rv = regKey->ReadStringValue(substituteName, actualFontName);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aliasName[0] == WCHAR('@')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString substituteName((PRUnichar*) aliasName);
|
||||
nsAutoString actualFontName((PRUnichar*) actualName);
|
||||
RemoveCharsetFromFontSubstitute(substituteName);
|
||||
BuildKeyNameFromFontName(substituteName);
|
||||
RemoveCharsetFromFontSubstitute(actualFontName);
|
||||
|
|
|
@ -173,6 +173,8 @@ protected:
|
|||
IDWriteFontFace **aFontFace,
|
||||
DWRITE_FONT_SIMULATIONS aSimulations = DWRITE_FONT_SIMULATIONS_NONE);
|
||||
|
||||
static PRBool InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont);
|
||||
|
||||
/**
|
||||
* A fontentry only needs to have either of these. If it has both only
|
||||
* the IDWriteFont will be used.
|
||||
|
@ -210,6 +212,9 @@ public:
|
|||
PRBool GetStandardFamilyName(const nsAString& aFontName,
|
||||
nsAString& aFamilyName);
|
||||
|
||||
IDWriteGdiInterop *GetGDIInterop() { return mGDIInterop; }
|
||||
PRBool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
|
||||
|
||||
private:
|
||||
friend class gfxDWriteFontFamily;
|
||||
|
||||
|
@ -228,6 +233,10 @@ private:
|
|||
* alternative font names.
|
||||
*/
|
||||
FontTable mFontSubstitutes;
|
||||
|
||||
// whether to use GDI font table access routines
|
||||
PRBool mGDIFontTableAccess;
|
||||
nsRefPtr<IDWriteGdiInterop> mGDIInterop;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -122,31 +122,12 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
|
|||
: gfxFont(aFontEntry, aFontStyle, anAAOption)
|
||||
, mCairoFontFace(nsnull)
|
||||
, mCairoScaledFont(nsnull)
|
||||
, mInitialized(PR_FALSE)
|
||||
, mMetrics(nsnull)
|
||||
, mNeedsOblique(PR_FALSE)
|
||||
, mNeedsBold(aNeedsBold)
|
||||
, mUseSubpixelPositions(PR_FALSE)
|
||||
{
|
||||
gfxDWriteFontEntry *fe =
|
||||
static_cast<gfxDWriteFontEntry*>(aFontEntry);
|
||||
nsresult rv;
|
||||
DWRITE_FONT_SIMULATIONS sims = DWRITE_FONT_SIMULATIONS_NONE;
|
||||
if ((GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) &&
|
||||
!fe->IsItalic()) {
|
||||
// For this we always use the font_matrix for uniformity. Not the
|
||||
// DWrite simulation.
|
||||
mNeedsOblique = PR_TRUE;
|
||||
}
|
||||
if (aNeedsBold) {
|
||||
sims |= DWRITE_FONT_SIMULATIONS_BOLD;
|
||||
}
|
||||
|
||||
rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mIsValid = PR_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((anAAOption == gfxFont::kAntialiasDefault && UsingClearType()) ||
|
||||
anAAOption == gfxFont::kAntialiasSubpixel)
|
||||
{
|
||||
|
@ -155,8 +136,6 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
|
|||
// strike is going to be used
|
||||
}
|
||||
|
||||
ComputeMetrics();
|
||||
|
||||
if (FontCanSupportHarfBuzz()) {
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
}
|
||||
|
@ -170,6 +149,7 @@ gfxDWriteFont::~gfxDWriteFont()
|
|||
if (mCairoScaledFont) {
|
||||
cairo_scaled_font_destroy(mCairoScaledFont);
|
||||
}
|
||||
delete mMetrics;
|
||||
}
|
||||
|
||||
gfxFont*
|
||||
|
@ -179,6 +159,37 @@ gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
|
|||
&mStyle, mNeedsBold, anAAOption);
|
||||
}
|
||||
|
||||
void
|
||||
gfxDWriteFont::Initialize()
|
||||
{
|
||||
NS_ASSERTION(!mInitialized, "initializing gfxDWriteFont a second time");
|
||||
mInitialized = PR_TRUE;
|
||||
|
||||
gfxDWriteFontEntry *fe =
|
||||
static_cast<gfxDWriteFontEntry*>((gfxFontEntry*)mFontEntry);
|
||||
|
||||
nsresult rv;
|
||||
DWRITE_FONT_SIMULATIONS sims = DWRITE_FONT_SIMULATIONS_NONE;
|
||||
if ((GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) &&
|
||||
!fe->IsItalic()) {
|
||||
// For this we always use the font_matrix for uniformity. Not the
|
||||
// DWrite simulation.
|
||||
mNeedsOblique = PR_TRUE;
|
||||
}
|
||||
if (mNeedsBold) {
|
||||
sims |= DWRITE_FONT_SIMULATIONS_BOLD;
|
||||
}
|
||||
|
||||
rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mIsValid = PR_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
ComputeMetrics();
|
||||
}
|
||||
|
||||
void
|
||||
gfxDWriteFont::CreatePlatformShaper()
|
||||
{
|
||||
|
@ -194,7 +205,10 @@ gfxDWriteFont::GetUniqueName()
|
|||
const gfxFont::Metrics&
|
||||
gfxDWriteFont::GetMetrics()
|
||||
{
|
||||
return mMetrics;
|
||||
if (!mInitialized) {
|
||||
Initialize();
|
||||
}
|
||||
return *mMetrics;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -216,24 +230,27 @@ gfxDWriteFont::ComputeMetrics()
|
|||
mUseSubpixelPositions = PR_FALSE;
|
||||
}
|
||||
|
||||
mMetrics.xHeight =
|
||||
mMetrics = new gfxFont::Metrics;
|
||||
::memset(mMetrics, 0, sizeof(*mMetrics));
|
||||
|
||||
mMetrics->xHeight =
|
||||
((gfxFloat)fontMetrics.xHeight /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
|
||||
mMetrics.maxAscent =
|
||||
mMetrics->maxAscent =
|
||||
ceil(((gfxFloat)fontMetrics.ascent /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize);
|
||||
mMetrics.maxDescent =
|
||||
mMetrics->maxDescent =
|
||||
ceil(((gfxFloat)fontMetrics.descent /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize);
|
||||
mMetrics.maxHeight = mMetrics.maxAscent + mMetrics.maxDescent;
|
||||
mMetrics->maxHeight = mMetrics->maxAscent + mMetrics->maxDescent;
|
||||
|
||||
mMetrics.emHeight = mAdjustedSize;
|
||||
mMetrics.emAscent = mMetrics.emHeight *
|
||||
mMetrics.maxAscent / mMetrics.maxHeight;
|
||||
mMetrics.emDescent = mMetrics.emHeight - mMetrics.emAscent;
|
||||
mMetrics->emHeight = mAdjustedSize;
|
||||
mMetrics->emAscent = mMetrics->emHeight *
|
||||
mMetrics->maxAscent / mMetrics->maxHeight;
|
||||
mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
|
||||
|
||||
mMetrics.maxAdvance = mAdjustedSize;
|
||||
mMetrics->maxAdvance = mAdjustedSize;
|
||||
|
||||
// try to get the true maxAdvance value from 'hhea'
|
||||
PRUint8 *tableData;
|
||||
|
@ -250,27 +267,27 @@ gfxDWriteFont::ComputeMetrics()
|
|||
if (exists && len >= sizeof(mozilla::HheaTable)) {
|
||||
const mozilla::HheaTable* hhea =
|
||||
reinterpret_cast<const mozilla::HheaTable*>(tableData);
|
||||
mMetrics.maxAdvance = ((gfxFloat)PRUint16(hhea->advanceWidthMax) /
|
||||
mMetrics->maxAdvance = ((gfxFloat)PRUint16(hhea->advanceWidthMax) /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
}
|
||||
mFontFace->ReleaseFontTable(tableContext);
|
||||
}
|
||||
|
||||
mMetrics.internalLeading = NS_MAX(mMetrics.maxHeight - mMetrics.emHeight, 0.0);
|
||||
mMetrics.externalLeading =
|
||||
mMetrics->internalLeading = NS_MAX(mMetrics->maxHeight - mMetrics->emHeight, 0.0);
|
||||
mMetrics->externalLeading =
|
||||
ceil(((gfxFloat)fontMetrics.lineGap /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize);
|
||||
|
||||
UINT16 glyph = (PRUint16)GetSpaceGlyph();
|
||||
DWRITE_GLYPH_METRICS metrics;
|
||||
mFontFace->GetDesignGlyphMetrics(&glyph, 1, &metrics);
|
||||
mMetrics.spaceWidth =
|
||||
mMetrics->spaceWidth =
|
||||
((gfxFloat)metrics.advanceWidth /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
|
||||
// try to get aveCharWidth from the OS/2 table, fall back to measuring 'x'
|
||||
// if the table is not available
|
||||
mMetrics.aveCharWidth = 0;
|
||||
mMetrics->aveCharWidth = 0;
|
||||
hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('O', 'S', '/', '2'),
|
||||
(const void**)&tableData,
|
||||
&len,
|
||||
|
@ -283,23 +300,23 @@ gfxDWriteFont::ComputeMetrics()
|
|||
// two 16-bit fields here.
|
||||
const mozilla::OS2Table* os2 =
|
||||
reinterpret_cast<const mozilla::OS2Table*>(tableData);
|
||||
mMetrics.aveCharWidth = ((gfxFloat)PRInt16(os2->xAvgCharWidth) /
|
||||
mMetrics->aveCharWidth = ((gfxFloat)PRInt16(os2->xAvgCharWidth) /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
}
|
||||
mFontFace->ReleaseFontTable(tableContext);
|
||||
}
|
||||
|
||||
UINT32 ucs;
|
||||
if (mMetrics.aveCharWidth < 1) {
|
||||
if (mMetrics->aveCharWidth < 1) {
|
||||
ucs = L'x';
|
||||
if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph)) &&
|
||||
SUCCEEDED(mFontFace->GetDesignGlyphMetrics(&glyph, 1, &metrics))) {
|
||||
mMetrics.aveCharWidth =
|
||||
mMetrics->aveCharWidth =
|
||||
((gfxFloat)metrics.advanceWidth /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
} else {
|
||||
// Let's just assume the X is square.
|
||||
mMetrics.aveCharWidth =
|
||||
mMetrics->aveCharWidth =
|
||||
((gfxFloat)fontMetrics.xHeight /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
}
|
||||
|
@ -308,43 +325,43 @@ gfxDWriteFont::ComputeMetrics()
|
|||
ucs = L'0';
|
||||
if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph)) &&
|
||||
SUCCEEDED(mFontFace->GetDesignGlyphMetrics(&glyph, 1, &metrics))) {
|
||||
mMetrics.zeroOrAveCharWidth =
|
||||
mMetrics->zeroOrAveCharWidth =
|
||||
((gfxFloat)metrics.advanceWidth /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
} else {
|
||||
mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth;
|
||||
mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth;
|
||||
}
|
||||
|
||||
mMetrics.underlineOffset =
|
||||
mMetrics->underlineOffset =
|
||||
((gfxFloat)fontMetrics.underlinePosition /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
mMetrics.underlineSize =
|
||||
mMetrics->underlineSize =
|
||||
((gfxFloat)fontMetrics.underlineThickness /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
mMetrics.strikeoutOffset =
|
||||
mMetrics->strikeoutOffset =
|
||||
((gfxFloat)fontMetrics.strikethroughPosition /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
mMetrics.strikeoutSize =
|
||||
mMetrics->strikeoutSize =
|
||||
((gfxFloat)fontMetrics.strikethroughThickness /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
mMetrics.superscriptOffset = 0;
|
||||
mMetrics.subscriptOffset = 0;
|
||||
mMetrics->superscriptOffset = 0;
|
||||
mMetrics->subscriptOffset = 0;
|
||||
|
||||
mFUnitsConvFactor = GetAdjustedSize() / fontMetrics.designUnitsPerEm;
|
||||
mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm);
|
||||
|
||||
SanitizeMetrics(&mMetrics, GetFontEntry()->mIsBadUnderlineFont);
|
||||
SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
|
||||
|
||||
#if 0
|
||||
printf("Font: %p (%s) size: %f\n", this,
|
||||
NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
|
||||
printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
|
||||
printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance);
|
||||
printf(" internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading);
|
||||
printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
|
||||
printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
|
||||
printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
|
||||
printf(" spaceWidth: %f aveCharWidth: %f zeroOrAve: %f xHeight: %f\n",
|
||||
mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.zeroOrAveCharWidth, mMetrics.xHeight);
|
||||
mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->zeroOrAveCharWidth, mMetrics->xHeight);
|
||||
printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n",
|
||||
mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize,
|
||||
mMetrics.superscriptOffset, mMetrics.subscriptOffset);
|
||||
mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize,
|
||||
mMetrics->superscriptOffset, mMetrics->subscriptOffset);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -495,6 +512,9 @@ gfxDWriteFont::HasBitmapStrikeForSize(PRUint32 aSize)
|
|||
PRUint32
|
||||
gfxDWriteFont::GetSpaceGlyph()
|
||||
{
|
||||
if (!mInitialized) {
|
||||
Initialize();
|
||||
}
|
||||
UINT32 ucs = L' ';
|
||||
UINT16 glyph;
|
||||
HRESULT hr;
|
||||
|
@ -508,6 +528,9 @@ gfxDWriteFont::GetSpaceGlyph()
|
|||
PRBool
|
||||
gfxDWriteFont::SetupCairoFont(gfxContext *aContext)
|
||||
{
|
||||
if (!mInitialized) {
|
||||
Initialize();
|
||||
}
|
||||
cairo_scaled_font_t *scaledFont = CairoScaledFont();
|
||||
if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
|
||||
// Don't cairo_set_scaled_font as that would propagate the error to
|
||||
|
@ -518,6 +541,24 @@ gfxDWriteFont::SetupCairoFont(gfxContext *aContext)
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
gfxDWriteFont::IsValid()
|
||||
{
|
||||
if (!mInitialized) {
|
||||
Initialize();
|
||||
}
|
||||
return mFontFace != NULL;
|
||||
}
|
||||
|
||||
IDWriteFontFace*
|
||||
gfxDWriteFont::GetFontFace()
|
||||
{
|
||||
if (!mInitialized) {
|
||||
Initialize();
|
||||
}
|
||||
return mFontFace.get();
|
||||
}
|
||||
|
||||
cairo_font_face_t *
|
||||
gfxDWriteFont::CairoFontFace()
|
||||
{
|
||||
|
@ -655,7 +696,7 @@ gfxDWriteFont::GetGlyphWidth(gfxContext *aCtx, PRUint16 aGID)
|
|||
}
|
||||
} else {
|
||||
hr = mFontFace->GetGdiCompatibleGlyphMetrics(
|
||||
GetAdjustedSize(), 1.0f, nsnull, FALSE,
|
||||
FLOAT(mAdjustedSize), 1.0f, nsnull, FALSE,
|
||||
&aGID, 1, &glyphMetrics, FALSE);
|
||||
if (SUCCEEDED(hr)) {
|
||||
width =
|
||||
|
|
|
@ -69,11 +69,16 @@ public:
|
|||
|
||||
virtual PRBool SetupCairoFont(gfxContext *aContext);
|
||||
|
||||
virtual PRBool IsValid() { return mFontFace != NULL; }
|
||||
virtual PRBool IsValid();
|
||||
|
||||
gfxFloat GetAdjustedSize() const { return mAdjustedSize; }
|
||||
gfxFloat GetAdjustedSize() {
|
||||
if (!mInitialized) {
|
||||
Initialize();
|
||||
}
|
||||
return mAdjustedSize;
|
||||
}
|
||||
|
||||
IDWriteFontFace *GetFontFace() { return mFontFace.get(); }
|
||||
IDWriteFontFace *GetFontFace();
|
||||
|
||||
// override gfxFont table access function to bypass gfxFontEntry cache,
|
||||
// use DWrite API to get direct access to system font data
|
||||
|
@ -91,6 +96,8 @@ protected:
|
|||
|
||||
virtual void CreatePlatformShaper();
|
||||
|
||||
void Initialize(); // creates IDWriteFontFace and metrics
|
||||
|
||||
void ComputeMetrics();
|
||||
|
||||
PRBool HasBitmapStrikeForSize(PRUint32 aSize);
|
||||
|
@ -105,7 +112,8 @@ protected:
|
|||
cairo_font_face_t *mCairoFontFace;
|
||||
cairo_scaled_font_t *mCairoScaledFont;
|
||||
|
||||
gfxFont::Metrics mMetrics;
|
||||
PRBool mInitialized;
|
||||
gfxFont::Metrics *mMetrics;
|
||||
|
||||
// cache of glyph widths in 16.16 fixed-point pixels
|
||||
nsDataHashtable<nsUint32HashKey,PRInt32> mGlyphWidths;
|
||||
|
|
|
@ -967,7 +967,7 @@ public:
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
gfxFloat GetAdjustedSize() const {
|
||||
virtual gfxFloat GetAdjustedSize() {
|
||||
return mAdjustedSize > 0.0 ? mAdjustedSize : mStyle.size;
|
||||
}
|
||||
|
||||
|
|
|
@ -340,7 +340,7 @@ gfxGDIFont::Initialize()
|
|||
mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight);
|
||||
mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
|
||||
if (oMetrics.otmEMSquare > 0) {
|
||||
mFUnitsConvFactor = float(GetAdjustedSize() / oMetrics.otmEMSquare);
|
||||
mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare);
|
||||
}
|
||||
} else {
|
||||
// Make a best-effort guess at extended metrics
|
||||
|
|
|
@ -61,7 +61,7 @@ public:
|
|||
|
||||
HFONT GetHFONT() { if (!mMetrics) Initialize(); return mFont; }
|
||||
|
||||
gfxFloat GetAdjustedSize() const { return mAdjustedSize; }
|
||||
gfxFloat GetAdjustedSize() { if (!mMetrics) Initialize(); return mAdjustedSize; }
|
||||
|
||||
cairo_font_face_t *CairoFontFace() { return mFontFace; }
|
||||
cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; }
|
||||
|
|
|
@ -72,8 +72,11 @@ static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
|
|||
#define LOG_ENABLED() PR_LOG_TEST(gFontInfoLog, PR_LOG_DEBUG)
|
||||
|
||||
// font info loader constants
|
||||
static const PRUint32 kDelayBeforeLoadingFonts = 8 * 1000; // 8secs
|
||||
static const PRUint32 kIntervalBetweenLoadingFonts = 150; // 150ms
|
||||
|
||||
// avoid doing this during startup even on slow machines but try to start
|
||||
// it soon enough so that system fallback doesn't happen first
|
||||
static const PRUint32 kDelayBeforeLoadingFonts = 120 * 1000; // 2 minutes after init
|
||||
static const PRUint32 kIntervalBetweenLoadingFonts = 2000; // every 2 seconds until complete
|
||||
|
||||
static __inline void
|
||||
BuildKeyNameFromFontName(nsAString &aName)
|
||||
|
@ -593,44 +596,49 @@ RemoveCharsetFromFontSubstitute(nsAString &aName)
|
|||
aName.Truncate(comma);
|
||||
}
|
||||
|
||||
#define MAX_VALUE_NAME 512
|
||||
#define MAX_VALUE_DATA 512
|
||||
|
||||
nsresult
|
||||
gfxGDIFontList::GetFontSubstitutes()
|
||||
{
|
||||
// Create the list of FontSubstitutes
|
||||
nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
|
||||
if (!regKey)
|
||||
HKEY hKey;
|
||||
DWORD i, rv, lenAlias, lenActual, valueType;
|
||||
WCHAR aliasName[MAX_VALUE_NAME];
|
||||
WCHAR actualName[MAX_VALUE_DATA];
|
||||
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
|
||||
0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
NS_NAMED_LITERAL_STRING(kFontSubstitutesKey, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
|
||||
}
|
||||
|
||||
nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
|
||||
kFontSubstitutesKey, nsIWindowsRegKey::ACCESS_READ);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) {
|
||||
aliasName[0] = 0;
|
||||
lenAlias = sizeof(aliasName);
|
||||
actualName[0] = 0;
|
||||
lenActual = sizeof(actualName);
|
||||
rv = RegEnumValueW(hKey, i, aliasName, &lenAlias, NULL, &valueType,
|
||||
(LPBYTE)actualName, &lenActual);
|
||||
|
||||
PRUint32 count;
|
||||
rv = regKey->GetValueCount(&count);
|
||||
if (NS_FAILED(rv) || count == 0)
|
||||
return rv;
|
||||
for (PRUint32 i = 0; i < count; i++) {
|
||||
nsAutoString substituteName;
|
||||
rv = regKey->GetValueName(i, substituteName);
|
||||
if (NS_FAILED(rv) || substituteName.IsEmpty() || substituteName.CharAt(1) == PRUnichar('@'))
|
||||
continue;
|
||||
PRUint32 valueType;
|
||||
rv = regKey->GetValueType(substituteName, &valueType);
|
||||
if (NS_FAILED(rv) || valueType != nsIWindowsRegKey::TYPE_STRING)
|
||||
continue;
|
||||
nsAutoString actualFontName;
|
||||
rv = regKey->ReadStringValue(substituteName, actualFontName);
|
||||
if (NS_FAILED(rv))
|
||||
if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aliasName[0] == WCHAR('@')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString substituteName((PRUnichar*) aliasName);
|
||||
nsAutoString actualFontName((PRUnichar*) actualName);
|
||||
RemoveCharsetFromFontSubstitute(substituteName);
|
||||
BuildKeyNameFromFontName(substituteName);
|
||||
RemoveCharsetFromFontSubstitute(actualFontName);
|
||||
BuildKeyNameFromFontName(actualFontName);
|
||||
gfxFontFamily *ff;
|
||||
if (!actualFontName.IsEmpty() && (ff = mFontFamilies.GetWeak(actualFontName))) {
|
||||
if (!actualFontName.IsEmpty() &&
|
||||
(ff = mFontFamilies.GetWeak(actualFontName))) {
|
||||
mFontSubstitutes.Put(substituteName, ff);
|
||||
} else {
|
||||
mNonExistingFonts.AppendElement(substituteName);
|
||||
|
|
|
@ -204,6 +204,7 @@ pref("gfx.font_rendering.harfbuzz.level", 2);
|
|||
#ifdef XP_WIN
|
||||
#ifndef WINCE
|
||||
pref("gfx.font_rendering.directwrite.enabled", false);
|
||||
pref("gfx.font_rendering.directwrite.use_gdi_table_loading", true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче