Bug 602792. Use GDI for font table loading to avoid excessive dwrite I/O. r=bas, a=blocker
authorJohn Daggett <jdaggett@mozilla.com>
Sat, 22 Jan 2011 01:44:32 +0900
changeset 61083 ea3a3ca326ee7b1cf907a87afc98727a3557e592
parent 61082 dbe700a4db442e49e7f79d6fc584f74b36576d04
child 61084 3428fc1009fe85194867d91679a90116b1ad6ff9
push idunknown
push userunknown
push dateunknown
reviewersbas, blocker
bugs602792
milestone2.0b10pre
Bug 602792. Use GDI for font table loading to avoid excessive dwrite I/O. r=bas, a=blocker
gfx/thebes/Makefile.in
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxDWriteFonts.cpp
gfx/thebes/gfxDWriteFonts.h
gfx/thebes/gfxFont.h
gfx/thebes/gfxGDIFont.cpp
gfx/thebes/gfxGDIFont.h
gfx/thebes/gfxGDIFontList.cpp
modules/libpref/src/init/all.js
--- a/gfx/thebes/Makefile.in
+++ b/gfx/thebes/Makefile.in
@@ -270,17 +270,17 @@ CPPSRCS	+= gfxDWriteFonts.cpp \
 	   gfxDWriteFontList.cpp \
 	   $(NULL)
 endif
 CPPSRCS	+= gfxGDIFont.cpp \
 	   gfxGDIFontList.cpp \
 	   gfxGDIShaper.cpp \
 	   gfxUniscribeShaper.cpp \
 	   $(NULL)
-_OS_LIBS = usp10 msimg32 ole32 version
+_OS_LIBS = usp10 msimg32 ole32 version advapi32
 endif
 
 CPPSRCS +=	gfxPDFSurface.cpp
 
 ifdef GNU_CXX
 _OS_LIBS	+= uuid
 endif
 OS_LIBS		+= $(call EXPAND_LIBNAME,$(_OS_LIBS))
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -29,29 +29,44 @@
  * 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 ***** */
+#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)
 {
     if (aName.Length() >= LF_FACESIZE)
         aName.Truncate(LF_FACESIZE - 1);
     ToLowerCase(aName);
 }
@@ -222,19 +237,44 @@ gfxDWriteFontEntry::IsSymbolFont()
         return PR_FALSE;
     }
 }
 
 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)) {
         return rv;
     }
 
     PRUint8 *tableData;
     PRUint32 len;
@@ -257,19 +297,43 @@ gfxDWriteFontEntry::GetFontTable(PRUint3
         fontFace->ReleaseFontTable(&tableContext);
     }
     return NS_OK;
 }
 
 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)) {
         return rv;
     }
 
     PRUint8 *tableData;
     PRUint32 len;
@@ -291,17 +355,16 @@ gfxDWriteFontEntry::ReadCMAP()
                                     len,
                                     mCharacterMap,
                                     mUVSOffset,
                                     isUnicode,
                                     isSymbol);
     }
     fontFace->ReleaseFontTable(tableContext);
 
-    mCmapInitialized = PR_TRUE;
     mHasCmapTable = NS_SUCCEEDED(rv);
     return rv;
 }
 
 gfxFont *
 gfxDWriteFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle,
                                        PRBool aNeedsBold)
 {
@@ -326,34 +389,57 @@ gfxDWriteFontEntry::CreateFontFace(IDWri
                            aFontFace);
     }
     if (FAILED(hr)) {
         return NS_ERROR_FAILURE;
     }
     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
 
 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);
         }
     }
 
     return nsnull;
 }
@@ -465,36 +551,89 @@ gfxDWriteFontList::MakePlatformFont(cons
     }
 
     return entry;
 }
 
 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));
     NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
 
     if (FAILED(hr)) {
         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));
 
         nsRefPtr<IDWriteLocalizedStrings> names;
         hr = family->GetFamilyNames(getter_AddRefs(names));
         if (FAILED(hr)) {
             continue;
@@ -591,69 +730,90 @@ gfxDWriteFontList::InitFontList()
         fam->SetOtherFamilyNamesInitialized();
     }
 
     mOtherFamilyNamesInitialized = PR_TRUE;
     GetFontSubstitutes();
 
     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;
 }
 
 static void
 RemoveCharsetFromFontSubstitute(nsAString &aName)
 {
     PRInt32 comma = aName.FindChar(PRUnichar(','));
     if (comma >= 0)
         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;
-    }
 
-    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)) {
+    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);
+
+        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))) {
             mFontSubstitutes.Put(substituteName, ff);
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -168,16 +168,18 @@ protected:
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
                                         PRBool aNeedsBold);
     
     nsresult CreateFontFace(
         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.
      */
     nsRefPtr<IDWriteFont> mFont;
     nsRefPtr<IDWriteFontFile> mFontFile;
     DWRITE_FONT_FACE_TYPE mFaceType;
 };
@@ -205,16 +207,19 @@ public:
                                            PRUint32 aLength);
     
     virtual PRBool ResolveFontName(const nsAString& aFontName,
                                    nsAString& aResolvedFontName);
 
     PRBool GetStandardFamilyName(const nsAString& aFontName,
                                  nsAString& aFamilyName);
 
+    IDWriteGdiInterop *GetGDIInterop() { return mGDIInterop; }
+    PRBool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
+
 private:
     friend class gfxDWriteFontFamily;
 
     nsresult GetFontSubstitutes();
 
     /**
      * Fonts listed in the registry as substitutes but for which no actual
      * font family is found.
@@ -223,12 +228,16 @@ private:
 
     typedef nsDataHashtable<nsStringHashKey, nsRefPtr<gfxFontFamily> > FontTable;
 
     /**
      * Table of font substitutes, we grab this from the registry to get
      * alternative font names.
      */
     FontTable mFontSubstitutes;
+
+    // whether to use GDI font table access routines
+    PRBool mGDIFontTableAccess;
+    nsRefPtr<IDWriteGdiInterop> mGDIInterop;
 };
 
 
 #endif /* GFX_DWRITEFONTLIST_H */
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -117,89 +117,103 @@ UsingClearType()
 // gfxDWriteFont
 gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
                              const gfxFontStyle *aFontStyle,
                              PRBool aNeedsBold,
                              AntialiasOption anAAOption)
     : 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)
     {
         mUseSubpixelPositions = PR_TRUE;
         // note that this may be reset to FALSE if we determine that a bitmap
         // strike is going to be used
     }
 
-    ComputeMetrics();
-
     if (FontCanSupportHarfBuzz()) {
         mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
     }
 }
 
 gfxDWriteFont::~gfxDWriteFont()
 {
     if (mCairoFontFace) {
         cairo_font_face_destroy(mCairoFontFace);
     }
     if (mCairoScaledFont) {
         cairo_scaled_font_destroy(mCairoScaledFont);
     }
+    delete mMetrics;
 }
 
 gfxFont*
 gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
 {
     return new gfxDWriteFont(static_cast<gfxDWriteFontEntry*>(mFontEntry.get()),
                              &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()
 {
     mPlatformShaper = new gfxDWriteShaper(this);
 }
 
 nsString
 gfxDWriteFont::GetUniqueName()
 {
     return mFontEntry->Name();
 }
 
 const gfxFont::Metrics&
 gfxDWriteFont::GetMetrics()
 {
-    return mMetrics;
+    if (!mInitialized) {
+        Initialize();
+    }
+    return *mMetrics;
 }
 
 void
 gfxDWriteFont::ComputeMetrics()
 {
     DWRITE_FONT_METRICS fontMetrics;
     mFontFace->GetMetrics(&fontMetrics);
 
@@ -211,145 +225,148 @@ gfxDWriteFont::ComputeMetrics()
         mAdjustedSize = mStyle.size;
     }
 
     if (HasBitmapStrikeForSize(NS_lround(mAdjustedSize))) {
         mAdjustedSize = NS_lround(mAdjustedSize);
         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;
     PRUint32 len;
     void *tableContext = NULL;
     BOOL exists;
     HRESULT hr =
         mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('h', 'h', 'e', 'a'),
                                    (const void**)&tableData,
                                    &len,
                                    &tableContext,
                                    &exists);
     if (SUCCEEDED(hr)) {
         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,
                                     &tableContext,
                                     &exists);
     if (SUCCEEDED(hr)) {
         if (exists && len >= 4) {
             // Not checking against sizeof(mozilla::OS2Table) here because older
             // versions of the table have different sizes; we only need the first
             // 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;
         }
     }
 
     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
 }
 
 using namespace mozilla; // for AutoSwap_* types
 
 struct EBLCHeader {
     AutoSwap_PRUint32 version;
     AutoSwap_PRUint32 numSizes;
@@ -490,39 +507,63 @@ gfxDWriteFont::HasBitmapStrikeForSize(PR
     mFontFace->ReleaseFontTable(tableContext);
 
     return hasStrike;
 }
 
 PRUint32
 gfxDWriteFont::GetSpaceGlyph()
 {
+    if (!mInitialized) {
+        Initialize();
+    }
     UINT32 ucs = L' ';
     UINT16 glyph;
     HRESULT hr;
     hr = mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph);
     if (FAILED(hr)) {
         return 0;
     }
     return glyph;
 }
 
 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
         // the cairo_t, precluding any further drawing.
         return PR_FALSE;
     }
     cairo_set_scaled_font(aContext->GetCairo(), scaledFont);
     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()
 {
     if (!mCairoFontFace) {
 #ifdef CAIRO_HAS_DWRITE_FONT
         mCairoFontFace = 
             cairo_dwrite_font_face_create_for_dwrite_fontface(
             ((gfxDWriteFontEntry*)mFontEntry.get())->mFont, mFontFace);
@@ -650,17 +691,17 @@ gfxDWriteFont::GetGlyphWidth(gfxContext 
                   &aGID, 1, &glyphMetrics, FALSE);
         if (SUCCEEDED(hr)) {
             width =
                 NS_lround(glyphMetrics.advanceWidth * mFUnitsConvFactor *
                           65536.0);
         }
     } else {
         hr = mFontFace->GetGdiCompatibleGlyphMetrics(
-                  GetAdjustedSize(), 1.0f, nsnull, FALSE,
+                  FLOAT(mAdjustedSize), 1.0f, nsnull, FALSE,
                   &aGID, 1, &glyphMetrics, FALSE);
         if (SUCCEEDED(hr)) {
             width =
                 NS_lround(glyphMetrics.advanceWidth * mFUnitsConvFactor) << 16;
         }
     }
 
     mGlyphWidths.Put(aGID, width);
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -64,21 +64,26 @@ public:
     virtual nsString GetUniqueName();
 
     virtual const gfxFont::Metrics& GetMetrics();
 
     virtual PRUint32 GetSpaceGlyph();
 
     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
     virtual hb_blob_t *GetFontTable(PRUint32 aTag);
 
     virtual PRBool ProvidesGlyphWidths() const {
         return !mUseSubpixelPositions ||
                (mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD);
@@ -86,31 +91,34 @@ public:
 
     virtual PRInt32 GetGlyphWidth(gfxContext *aCtx, PRUint16 aGID);
 
 protected:
     friend class gfxDWriteShaper;
 
     virtual void CreatePlatformShaper();
 
+    void Initialize(); // creates IDWriteFontFace and metrics
+
     void ComputeMetrics();
 
     PRBool HasBitmapStrikeForSize(PRUint32 aSize);
 
     cairo_font_face_t *CairoFontFace();
 
     cairo_scaled_font_t *CairoScaledFont();
 
     static void DestroyBlobFunc(void* userArg);
 
     nsRefPtr<IDWriteFontFace> mFontFace;
     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;
 
     PRPackedBool mNeedsOblique;
     PRPackedBool mNeedsBold;
     PRPackedBool mUseSubpixelPositions;
 };
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -962,17 +962,17 @@ public:
 
     virtual nsString GetUniqueName() { return GetName(); }
 
     virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) {
         // platforms where this actually matters should override
         return nsnull;
     }
 
-    gfxFloat GetAdjustedSize() const {
+    virtual gfxFloat GetAdjustedSize() {
         return mAdjustedSize > 0.0 ? mAdjustedSize : mStyle.size;
     }
 
     float FUnitsToDevUnitsFactor() const {
         // check this was set up during font initialization
         NS_ASSERTION(mFUnitsConvFactor > 0.0f, "mFUnitsConvFactor not valid");
         return mFUnitsConvFactor;
     }
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -335,17 +335,17 @@ gfxGDIFont::Initialize()
         } else {
             mMetrics->xHeight = gm.gmptGlyphOrigin.y;
         }
         mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading;
         gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent;
         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
         // this is based on general typographic guidelines
         
         // GetTextMetrics can fail if the font file has been removed
         // or corrupted recently.
         BOOL result = GetTextMetrics(dc.GetDC(), &metrics);
--- a/gfx/thebes/gfxGDIFont.h
+++ b/gfx/thebes/gfxGDIFont.h
@@ -56,17 +56,17 @@ public:
                const gfxFontStyle *aFontStyle,
                PRBool aNeedsBold,
                AntialiasOption anAAOption = kAntialiasDefault);
 
     virtual ~gfxGDIFont();
 
     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; }
 
     /* overrides for the pure virtual methods in gfxFont */
     virtual const gfxFont::Metrics& GetMetrics();
 
     virtual PRUint32 GetSpaceGlyph();
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -67,18 +67,21 @@
 #ifdef PR_LOGGING
 static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
 #endif /* PR_LOGGING */
 
 #define LOG(args) PR_LOG(gFontInfoLog, PR_LOG_DEBUG, args)
 #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)
 {
     if (aName.Length() >= LF_FACESIZE)
         aName.Truncate(LF_FACESIZE - 1);
     ToLowerCase(aName);
 }
@@ -588,54 +591,59 @@ gfxGDIFontList::gfxGDIFontList()
 static void
 RemoveCharsetFromFontSubstitute(nsAString &aName)
 {
     PRInt32 comma = aName.FindChar(PRUnichar(','));
     if (comma >= 0)
         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;
+    }
 
-    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('@'))
+    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);
+
+        if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) {
             continue;
-        PRUint32 valueType;
-        rv = regKey->GetValueType(substituteName, &valueType);
-        if (NS_FAILED(rv) || valueType != nsIWindowsRegKey::TYPE_STRING)
+        }
+
+        if (aliasName[0] == WCHAR('@')) {
             continue;
-        nsAutoString actualFontName;
-        rv = regKey->ReadStringValue(substituteName, actualFontName);
-        if (NS_FAILED(rv))
-            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);
         }
     }
     return NS_OK;
 }
 
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -199,16 +199,17 @@ pref("gfx.downloadable_fonts.sanitize.pr
 pref("gfx.downloadable_fonts.sanitize.preserve_otl_tables", true);
 #endif
 
 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
 
 pref("accessibility.browsewithcaret", false);
 pref("accessibility.warn_on_browsewithcaret", true);
 
 pref("accessibility.browsewithcaret_shortcut.enabled", true);