bug 594865 - fall back to GDI rendering on dwrite font list failure. r=bas a=blocking2.0
authorJonathan Kew <jfkthame@gmail.com>
Mon, 08 Nov 2010 11:02:27 +0000
changeset 57104 a0826dcd622854b23c8bd4e396cd13974b692e5c
parent 57103 0f92c4e81cf3b16caf7609666990215f862e0c30
child 57105 741e9889fbdec2063b06057e17831901116a332f
push id16789
push userjkew@mozilla.com
push dateMon, 08 Nov 2010 11:04:10 +0000
treeherdermozilla-central@a0826dcd6228 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas, blocking2
bugs594865
milestone2.0b8pre
first release with
nightly linux64
a0826dcd6228 / 4.0b8pre / 20101108040701 / files
nightly mac
a0826dcd6228 / 4.0b8pre / 20101108033818 / files
nightly win32
a0826dcd6228 / 4.0b8pre / 20101108043306 / files
nightly linux32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux64
nightly mac
nightly win32
bug 594865 - fall back to GDI rendering on dwrite font list failure. r=bas a=blocking2.0
gfx/thebes/gfxAndroidPlatform.cpp
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFT2FontList.h
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxGDIFontList.h
gfx/thebes/gfxMacPlatformFontList.h
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformFontList.h
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -265,17 +265,22 @@ gfxAndroidPlatform::GetStandardFamilyNam
     aFamilyName.Truncate();
     PRBool aborted;
     return ResolveFontName(aFontName, SimpleResolverCallback, &aFamilyName, aborted);
 }
 
 gfxPlatformFontList*
 gfxAndroidPlatform::CreatePlatformFontList()
 {
-    return new gfxFT2FontList();
+    gfxPlatformFontList* list = new gfxFT2FontList();
+    if (NS_SUCCEEDED(list->InitFontList())) {
+        return list;
+    }
+    gfxPlatformFontList::Shutdown();
+    return nsnull;
 }
 
 PRBool
 gfxAndroidPlatform::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
 {
     // check for strange format flags
     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
                  "strange font format hint set");
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -462,17 +462,17 @@ gfxDWriteFontList::MakePlatformFont(cons
         // We don't know how to deal with 0 faces either.
         delete entry;
         return nsnull;
     }
 
     return entry;
 }
 
-void
+nsresult
 gfxDWriteFontList::InitFontList()
 {
     HRESULT hr;
     gfxFontCache *fc = gfxFontCache::GetCache();
     if (fc) {
         fc->AgeAllGenerations();
     }
 
@@ -481,16 +481,20 @@ gfxDWriteFontList::InitFontList()
     mFontSubstitutes.Clear();
     mNonExistingFonts.Clear();
 
     nsRefPtr<IDWriteFontCollection> systemFonts;
     hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
         GetSystemFontCollection(getter_AddRefs(systemFonts));
     NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
 
+    if (FAILED(hr)) {
+        return NS_ERROR_FAILURE;
+    }
+
     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;
@@ -538,16 +542,18 @@ gfxDWriteFontList::InitFontList()
             }
             mFontFamilies.Put(name, fam);
         }
     }
 
     GetFontSubstitutes();
 
     StartLoader(kDelayBeforeLoadingFonts, kIntervalBetweenLoadingFonts);
+
+    return NS_OK;
 }
 
 static void
 RemoveCharsetFromFontSubstitute(nsAString &aName)
 {
     PRInt32 comma = aName.FindChar(PRUnichar(','));
     if (comma >= 0)
         aName.Truncate(comma);
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -186,16 +186,19 @@ protected:
 class gfxDWriteFontList : public gfxPlatformFontList {
 public:
     gfxDWriteFontList();
 
     static gfxDWriteFontList* PlatformFontList() {
         return static_cast<gfxDWriteFontList*>(sPlatformFontList);
     }
 
+    // initialize font lists
+    virtual nsresult InitFontList();
+
     virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle,
                                          PRBool& aNeedsBold);
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const PRUint8 *aFontData,
@@ -205,19 +208,16 @@ public:
                                    nsAString& aResolvedFontName);
 
     PRBool GetStandardFamilyName(const nsAString& aFontName,
                                  nsAString& aFamilyName);
 
 private:
     friend class gfxDWriteFontFamily;
 
-    // initialize font lists
-    virtual void InitFontList();
-
     nsresult GetFontSubstitutes();
 
     /**
      * Fonts listed in the registry as substitutes but for which no actual
      * font family is found.
      */
     nsTArray<nsString> mNonExistingFonts;
 
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -230,23 +230,25 @@ gfxFT2FontList::FindFonts()
     }
 
     mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
     mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
 
 #endif // XP_WIN && ANDROID
 }
 
-void
+nsresult
 gfxFT2FontList::InitFontList()
 {
     // reset font lists
     gfxPlatformFontList::InitFontList();
     
     FindFonts();
+
+    return NS_OK;
 }
 
 struct FullFontNameSearch {
     FullFontNameSearch(const nsAString& aFullName)
         : mFullName(aFullName), mFontEntry(nsnull)
     { }
 
     nsString     mFullName;
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -60,16 +60,16 @@ public:
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const PRUint8 *aFontData,
                                            PRUint32 aLength);
 
 protected:
-    virtual void InitFontList();
+    virtual nsresult InitFontList();
 
     void AppendFacesFromFontFile(const PRUnichar *aFileName);
     void AppendFacesFromFontFile(const char *aFileName);
     void FindFonts();
 };
 
 #endif /* GFX_FT2FONTLIST_H */
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -633,17 +633,17 @@ gfxGDIFontList::GetFontSubstitutes()
             mFontSubstitutes.Put(substituteName, ff);
         } else {
             mNonExistingFonts.AppendElement(substituteName);
         }
     }
     return NS_OK;
 }
 
-void
+nsresult
 gfxGDIFontList::InitFontList()
 {
     gfxFontCache *fc = gfxFontCache::GetCache();
     if (fc)
         fc->AgeAllGenerations();
 
     // reset font lists
     gfxPlatformFontList::InitFontList();
@@ -659,18 +659,20 @@ gfxGDIFontList::InitFontList()
     AutoDC hdc;
     int result = EnumFontFamiliesExW(hdc.GetDC(), &logfont,
                                      (FONTENUMPROCW)&EnumFontFamExProc,
                                      0, 0);
 
     GetFontSubstitutes();
 
     StartLoader(kDelayBeforeLoadingFonts, kIntervalBetweenLoadingFonts);
+
+    return NS_OK;
 }
-    
+
 int CALLBACK
 gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
                                       NEWTEXTMETRICEXW *lpntme,
                                       DWORD fontType,
                                       LPARAM lParam)
 {
     const LOGFONTW& lf = lpelfe->elfLogFont;
 
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -329,16 +329,19 @@ private:
 };
 
 class gfxGDIFontList : public gfxPlatformFontList {
 public:
     static gfxGDIFontList* PlatformFontList() {
         return static_cast<gfxGDIFontList*>(sPlatformFontList);
     }
 
+    // initialize font lists
+    virtual nsresult InitFontList();
+
     virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold);
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const PRUint8 *aFontData, PRUint32 aLength);
 
@@ -347,19 +350,16 @@ public:
 
 private:
     friend class gfxWindowsPlatform;
 
     gfxGDIFontList();
 
     void InitializeFontEmbeddingProcs();
 
-    // initialize font lists
-    virtual void InitFontList();
-
     nsresult GetFontSubstitutes();
 
     static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
                                           NEWTEXTMETRICEXW *lpntme,
                                           DWORD fontType,
                                           LPARAM lParam);
 
     typedef nsDataHashtable<nsStringHashKey, nsRefPtr<gfxFontFamily> > FontTable;
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -108,17 +108,17 @@ public:
     void ClearPrefFonts() { mPrefFonts.Clear(); }
 
 private:
     friend class gfxPlatformMac;
 
     gfxMacPlatformFontList();
 
     // initialize font lists
-    virtual void InitFontList();
+    virtual nsresult InitFontList();
 
     // special case font faces treated as font families (set via prefs)
     void InitSingleFaceList();
 
     // eliminate faces which have the same ATS font reference
     void EliminateDuplicateFaces(const nsAString& aFamilyName);
 
     static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg);
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -603,26 +603,26 @@ gfxMacPlatformFontList::gfxMacPlatformFo
     // we'll just end up doing a search and then caching the new result instead)
     mReplacementCharFallbackFamily = NS_LITERAL_STRING("Lucida Grande");
 
     // cache this in a static variable so that MacOSFontFamily objects
     // don't have to repeatedly look it up
     sFontManager = [NSFontManager sharedFontManager];
 }
 
-void
+nsresult
 gfxMacPlatformFontList::InitFontList()
 {
     nsAutoreleasePool localPool;
 
     ATSGeneration currentGeneration = ::ATSGetGeneration();
 
     // need to ignore notifications after adding each font
     if (mATSGeneration == currentGeneration)
-        return;
+        return NS_OK;
 
     mATSGeneration = currentGeneration;
     PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) updating to generation: %d", mATSGeneration));
 
     // reset font lists
     gfxPlatformFontList::InitFontList();
     
     // iterate over available families
@@ -667,16 +667,18 @@ gfxMacPlatformFontList::InitFontList()
         // Cocoa reports that Courier and Monaco are not fixed-pitch fonts
         // so explicitly tweak these settings
         SetFixedPitch(NS_LITERAL_STRING("Courier"));
         SetFixedPitch(NS_LITERAL_STRING("Monaco"));
     }
 
     // start the delayed cmap loader
     StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
+
+	return NS_OK;
 }
 
 void
 gfxMacPlatformFontList::InitSingleFaceList()
 {
     nsAutoTArray<nsString, 10> singleFaceFonts;
     gfxFontUtils::GetPrefsFontList("font.single-face-list", singleFaceFonts);
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -251,36 +251,36 @@ gfxPlatform::Init()
 #elif defined(XP_OS2)
     gPlatform = new gfxOS2Platform;
 #elif defined(ANDROID)
     gPlatform = new gfxAndroidPlatform;
 #endif
     if (!gPlatform)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    gPlatform->mScreenReferenceSurface =
-      gPlatform->CreateOffscreenSurface(gfxIntSize(1,1),
-                                        gfxASurface::CONTENT_COLOR_ALPHA);
-    if (!gPlatform->mScreenReferenceSurface) {
-      NS_ERROR("Could not initialize mScreenReferenceSurface");
-      Shutdown();
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-
     nsresult rv;
 
 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others
     rv = gfxPlatformFontList::Init();
     if (NS_FAILED(rv)) {
         NS_ERROR("Could not initialize gfxPlatformFontList");
         Shutdown();
         return rv;
     }
 #endif
 
+    gPlatform->mScreenReferenceSurface =
+        gPlatform->CreateOffscreenSurface(gfxIntSize(1,1),
+                                          gfxASurface::CONTENT_COLOR_ALPHA);
+    if (!gPlatform->mScreenReferenceSurface) {
+        NS_ERROR("Could not initialize mScreenReferenceSurface");
+        Shutdown();
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+
     rv = gfxFontCache::Init();
     if (NS_FAILED(rv)) {
         NS_ERROR("Could not initialize gfxFontCache");
         Shutdown();
         return rv;
     }
 
     rv = gfxTextRunWordCache::Init();
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -169,17 +169,19 @@ public:
                                  nsTArray<nsString>& aListOfFonts);
 
     /**
      * Rebuilds the any cached system font lists
      */
     virtual nsresult UpdateFontList();
 
     /**
-     * Create the platform font-list object (gfxPlatformFontList concrete subclass)
+     * Create the platform font-list object (gfxPlatformFontList concrete subclass).
+     * This function is responsible to create the appropriate subclass of
+     * gfxPlatformFontList *and* to call its InitFontList() method.
      */
     virtual gfxPlatformFontList *CreatePlatformFontList() {
         NS_NOTREACHED("oops, this platform doesn't have a gfxPlatformFontList implementation");
         return nsnull;
     }
 
     /**
      * Font name resolver, this returns actual font name(s) by the callback
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -133,17 +133,17 @@ gfxPlatformFontList::gfxPlatformFontList
             pref->AddObserver("font.name-list.", observer, PR_FALSE);
             pref->AddObserver("intl.accept_languages", observer, PR_FALSE);  // hmmmm...
         } else {
             delete observer;
         }
     }
 }
 
-void
+nsresult
 gfxPlatformFontList::InitFontList()
 {
     mFontFamilies.Clear();
     mOtherFamilyNames.Clear();
     mOtherFamilyNamesInitialized = PR_FALSE;
     if (mNeedFullnamePostscriptNames) {
         mFullnames.Clear();
         mPostscriptNames.Clear();
@@ -151,16 +151,20 @@ gfxPlatformFontList::InitFontList()
     mFaceNamesInitialized = PR_FALSE;
     mPrefFonts.Clear();
     CancelLoader();
 
     // initialize ranges of characters for which system-wide font search should be skipped
     mCodepointsWithNoFonts.reset();
     mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
     mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
+
+    sPlatformFontList = this;
+
+    return NS_OK;
 }
 
 void
 gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
 {
     aResult = aKeyName;
     ToLowerCase(aResult);
 }
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -62,27 +62,31 @@ public:
     static gfxPlatformFontList* PlatformFontList() {
         return sPlatformFontList;
     }
 
     static nsresult Init() {
         NS_TIME_FUNCTION;
 
         NS_ASSERTION(!sPlatformFontList, "What's this doing here?");
-        sPlatformFontList = gfxPlatform::GetPlatform()->CreatePlatformFontList();
-        if (!sPlatformFontList) return NS_ERROR_OUT_OF_MEMORY;
-        sPlatformFontList->InitFontList();
+        gfxPlatform::GetPlatform()->CreatePlatformFontList();
+        if (!sPlatformFontList) {
+            return NS_ERROR_OUT_OF_MEMORY;
+        }
         return NS_OK;
     }
 
     static void Shutdown() {
         delete sPlatformFontList;
         sPlatformFontList = nsnull;
     }
 
+    // initialize font lists
+    virtual nsresult InitFontList();
+
     void GetFontList (nsIAtom *aLangGroup,
                       const nsACString& aGenericFamily,
                       nsTArray<nsString>& aListOfFonts);
 
     virtual PRBool ResolveFontName(const nsAString& aFontName,
                                    nsAString& aResolvedFontName);
 
     void UpdateFontList() { InitFontList(); }
@@ -135,19 +139,16 @@ protected:
     gfxPlatformFontList(PRBool aNeedFullnamePostscriptNames = PR_TRUE);
 
     static gfxPlatformFontList *sPlatformFontList;
 
     static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
                                                nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                                void* userArg);
 
-    // initialize font lists
-    virtual void InitFontList();
-
     // separate initialization for reading in name tables, since this is expensive
     void InitOtherFamilyNames();
 
     static PLDHashOperator InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
                                                     nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                                     void* userArg);
 
     // read in all fullname/Postscript names for all font faces
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -66,17 +66,22 @@ gfxPlatformMac::gfxPlatformMac()
 gfxPlatformMac::~gfxPlatformMac()
 {
     gfxCoreTextShaper::Shutdown();
 }
 
 gfxPlatformFontList*
 gfxPlatformMac::CreatePlatformFontList()
 {
-    return new gfxMacPlatformFontList();
+    gfxPlatformFontList* list = new gfxMacPlatformFontList();
+    if (NS_SUCCEEDED(list->InitFontList())) {
+        return list;
+    }
+    gfxPlatformFontList::Shutdown();
+    return nsnull;
 }
 
 already_AddRefed<gfxASurface>
 gfxPlatformMac::CreateOffscreenSurface(const gfxIntSize& size,
                                        gfxASurface::gfxContentType contentType)
 {
     gfxASurface *newSurface = nsnull;
 
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -196,16 +196,18 @@ BuildKeyNameFromFontName(nsAString &aNam
 
 gfxWindowsPlatform::gfxWindowsPlatform()
 {
     mPrefFonts.Init(50);
 
     mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
     mUseClearTypeAlways = UNINITIALIZED_VALUE;
 
+    mUsingGDIFonts = PR_FALSE;
+
     /* 
      * Initialize COM 
      */ 
     CoInitialize(NULL); 
 
     mScreenDC = GetDC(NULL);
 
 #ifdef MOZ_FT2_FONTS
@@ -230,18 +232,17 @@ gfxWindowsPlatform::~gfxWindowsPlatform(
     if (mD2DDevice) {
         cairo_release_device(mD2DDevice);
     }
 #endif
 
     /* 
      * Uninitialize COM 
      */ 
-    CoUninitialize(); 
-
+    CoUninitialize();
 }
 
 void
 gfxWindowsPlatform::UpdateRenderMode()
 {
 /* Pick the default render mode differently between
  * desktop, Windows Mobile, and Windows CE.
  */
@@ -296,22 +297,23 @@ gfxWindowsPlatform::UpdateRenderMode()
         }
     }
 
     rv = pref->GetBoolPref("gfx.direct2d.disabled", &d2dDisabled);
     if (NS_FAILED(rv))
         d2dDisabled = PR_FALSE;
     rv = pref->GetBoolPref("gfx.direct2d.force-enabled", &d2dForceEnabled);
     if (NS_FAILED(rv))
-        d2dDisabled = PR_FALSE;
+        d2dForceEnabled = PR_FALSE;
 
     bool tryD2D = !d2dBlocked || d2dForceEnabled;
     
-    // Do not ever try if d2d is explicitly disabled.
-    if (d2dDisabled) {
+    // Do not ever try if d2d is explicitly disabled,
+    // or if we're not using DWrite fonts.
+    if (d2dDisabled || mUsingGDIFonts) {
         tryD2D = false;
     }
 
     if (isVistaOrHigher  && !safeMode && tryD2D) {
         VerifyD2DDevice(d2dForceEnabled);
         if (mD2DDevice) {
             mRenderMode = RENDER_DIRECT2D;
             mUseDirectWrite = PR_TRUE;
@@ -401,32 +403,48 @@ gfxWindowsPlatform::VerifyD2DDevice(PRBo
         }
     }
 
     if (!mD2DDevice && aAttemptForce) {
         mD2DDevice = cairo_d2d_create_device();
     }
 #endif
 }
+
 gfxPlatformFontList*
 gfxWindowsPlatform::CreatePlatformFontList()
 {
+    mUsingGDIFonts = PR_FALSE;
+    gfxPlatformFontList *pfl;
 #ifdef MOZ_FT2_FONTS
-    return new gfxFT2FontList();
+    pfl = new gfxFT2FontList();
 #else
 #ifdef CAIRO_HAS_DWRITE_FONT
-    if (!GetDWriteFactory()) {
-#endif
-        return new gfxGDIFontList();
-#ifdef CAIRO_HAS_DWRITE_FONT
-    } else {
-        return new gfxDWriteFontList();
+    if (GetDWriteFactory()) {
+        pfl = new gfxDWriteFontList();
+        if (NS_SUCCEEDED(pfl->InitFontList())) {
+            return pfl;
+        }
+        // DWrite font initialization failed! Don't know why this would happen,
+        // but apparently it can - see bug 594865.
+        // So we're going to fall back to GDI fonts & rendering.
+        gfxPlatformFontList::Shutdown();
+        SetRenderMode(RENDER_GDI);
     }
 #endif
+    pfl = new gfxGDIFontList();
+    mUsingGDIFonts = PR_TRUE;
 #endif
+
+    if (NS_SUCCEEDED(pfl->InitFontList())) {
+        return pfl;
+    }
+
+    gfxPlatformFontList::Shutdown();
+    return nsnull;
 }
 
 already_AddRefed<gfxASurface>
 gfxWindowsPlatform::CreateOffscreenSurface(const gfxIntSize& size,
                                            gfxASurface::gfxContentType contentType)
 {
     gfxASurface *surf = nsnull;
 
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -250,16 +250,17 @@ protected:
     PRBool mUseClearTypeForDownloadableFonts;
     PRBool mUseClearTypeAlways;
     HDC mScreenDC;
 
 private:
     void Init();
 
     PRBool mUseDirectWrite;
+    PRBool mUsingGDIFonts;
 
 #ifdef CAIRO_HAS_DWRITE_FONT
     nsRefPtr<IDWriteFactory> mDWriteFactory;
 #endif
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *mD2DDevice;
 #endif