Bug 1249600 - Fallback to arial fonts or draw nothing if typeface is unavailable. r=bas, a=sledru
authorMason Chang <mchang@mozilla.com>
Fri, 20 May 2016 09:16:29 -0700
changeset 333033 c6fbc5c0fa3eeb780a229deb255e12c3adb75020
parent 333032 b3a6376fa4484e6aaaee576e56182289c8f356d9
child 333034 94069e0bf7660db33237dbd8bc7c148f36e2c87f
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas, sledru
bugs1249600
milestone48.0a2
Bug 1249600 - Fallback to arial fonts or draw nothing if typeface is unavailable. r=bas, a=sledru
gfx/2d/DrawTargetSkia.cpp
gfx/2d/ScaledFontDWrite.cpp
gfx/2d/ScaledFontDWrite.h
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -606,19 +606,23 @@ DrawTargetSkia::FillGlyphs(ScaledFont *a
       aFont->GetType() != FontType::GDI &&
       aFont->GetType() != FontType::DWRITE) {
     return;
   }
 
   MarkChanged();
 
   ScaledFontBase* skiaFont = static_cast<ScaledFontBase*>(aFont);
+  SkTypeface* typeface = skiaFont->GetSkTypeface();
+  if (!typeface) {
+    return;
+  }
 
   AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
-  paint.mPaint.setTypeface(skiaFont->GetSkTypeface());
+  paint.mPaint.setTypeface(typeface);
   paint.mPaint.setTextSize(SkFloatToScalar(skiaFont->mSize));
   paint.mPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
 
   bool shouldLCDRenderText = ShouldLCDRenderText(aFont->GetType(), aOptions.mAntialiasMode);
   paint.mPaint.setLCDRenderText(shouldLCDRenderText);
 
   if (aRenderingOptions && aRenderingOptions->GetType() == FontType::CAIRO) {
     const GlyphRenderingOptionsCairo* cairoOptions =
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -110,50 +110,90 @@ ScaledFontDWrite::GetPathForGlyphs(const
 
   CopyGlyphsToSink(aBuffer, pathBuilderD2D->GetSink());
 
   return pathBuilder->Finish();
 }
 
 
 #ifdef USE_SKIA
+bool
+ScaledFontDWrite::DefaultToArialFont(IDWriteFontCollection* aSystemFonts)
+{
+  // If we can't find the same font face as we're given, fallback to arial
+  static const WCHAR fontFamilyName[] = L"Arial";
+
+  UINT32 fontIndex;
+  BOOL exists;
+  HRESULT hr = aSystemFonts->FindFamilyName(fontFamilyName, &fontIndex, &exists);
+  if (FAILED(hr)) {
+    gfxCriticalNote << "Failed to get backup arial font font from system fonts. Code: " << hexa(hr);
+    return false;
+  }
+
+  hr = aSystemFonts->GetFontFamily(fontIndex, getter_AddRefs(mFontFamily));
+  if (FAILED(hr)) {
+    gfxCriticalNote << "Failed to get font family for arial. Code: " << hexa(hr);
+    return false;
+  }
+
+  hr = mFontFamily->GetFirstMatchingFont(DWRITE_FONT_WEIGHT_NORMAL,
+                                         DWRITE_FONT_STRETCH_NORMAL,
+                                         DWRITE_FONT_STYLE_NORMAL,
+                                         getter_AddRefs(mFont));
+  if (FAILED(hr)) {
+    gfxCriticalNote << "Failed to get a matching font for arial. Code: " << hexa(hr);
+    return false;
+  }
+
+  return true;
+}
+
 // This can happen if we have mixed backends which create DWrite
 // fonts in a mixed environment. e.g. a cairo content backend
 // but Skia canvas backend.
-void
+bool
 ScaledFontDWrite::GetFontDataFromSystemFonts(IDWriteFactory* aFactory)
 {
   MOZ_ASSERT(mFontFace);
   RefPtr<IDWriteFontCollection> systemFonts;
   HRESULT hr = aFactory->GetSystemFontCollection(getter_AddRefs(systemFonts));
   if (FAILED(hr)) {
-    gfxWarning() << "Failed to get system font collection from file data. Code: " << hexa(hr);
-    return;
+    gfxCriticalNote << "Failed to get system font collection from file data. Code: " << hexa(hr);
+    return false;
   }
 
   hr = systemFonts->GetFontFromFontFace(mFontFace, getter_AddRefs(mFont));
   if (FAILED(hr)) {
-    gfxWarning() << "Failed to get system font from font face. Code: " << hexa(hr);
-    return;
+    gfxCriticalNote << "Failed to get system font from font face. Code: " << hexa(hr);
+    return DefaultToArialFont(systemFonts);
   }
 
   hr = mFont->GetFontFamily(getter_AddRefs(mFontFamily));
   if (FAILED(hr)) {
-    gfxWarning() << "Failed to get font family from font face. Code: " << hexa(hr);
-    return;
+    gfxCriticalNote << "Failed to get font family from font face. Code: " << hexa(hr);
+    return DefaultToArialFont(systemFonts);
   }
+
+  return true;
 }
 
 SkTypeface*
 ScaledFontDWrite::GetSkTypeface()
 {
   if (!mTypeface) {
     IDWriteFactory *factory = DrawTargetD2D1::GetDWriteFactory();
+    if (!factory) {
+      return nullptr;
+    }
+
     if (!mFont || !mFontFamily) {
-      GetFontDataFromSystemFonts(factory);
+      if (!GetFontDataFromSystemFonts(factory)) {
+        return nullptr;
+      }
     }
 
     mTypeface = SkCreateTypefaceFromDWriteFont(factory, mFontFace, mFont, mFontFamily);
   }
   return mTypeface;
 }
 #endif
 
--- a/gfx/2d/ScaledFontDWrite.h
+++ b/gfx/2d/ScaledFontDWrite.h
@@ -41,17 +41,18 @@ public:
   void CopyGlyphsToSink(const GlyphBuffer &aBuffer, ID2D1GeometrySink *aSink);
 
   virtual bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton);
 
   virtual AntialiasMode GetDefaultAAMode();
 
 #ifdef USE_SKIA
   virtual SkTypeface* GetSkTypeface();
-  void GetFontDataFromSystemFonts(IDWriteFactory* aFactory);
+  bool GetFontDataFromSystemFonts(IDWriteFactory* aFactory);
+  bool DefaultToArialFont(IDWriteFontCollection* aSystemFonts);
 #endif
 
   // The font and font family are only used with Skia
   RefPtr<IDWriteFont> mFont;
   RefPtr<IDWriteFontFamily> mFontFamily;
   RefPtr<IDWriteFontFace> mFontFace;
 
 protected: