Bug 602792. Use GDI for font table loading to avoid excessive dwrite I/O. r=bas, a=blocker

This commit is contained in:
John Daggett 2011-01-22 01:44:32 +09:00
Родитель ab4ce354c6
Коммит 8910f7df7e
10 изменённых файлов: 359 добавлений и 132 удалений

Просмотреть файл

@ -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