Bug 1249600. Fallback to arial fonts or draw nothing if typeface is unavailable. r=bas
authorMason Chang <mchang@mozilla.com>
Fri, 20 May 2016 09:16:29 -0700
changeset 337805 be999dda2b73a286f038ad15eb08eb8be94e76db
parent 337804 3449c8ff31c99c48476ae111f6af6357cb3ce256
child 337806 cd58054bde907f41e75c9f4a57c83994c23e6088
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs1249600
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1249600. Fallback to arial fonts or draw nothing if typeface is unavailable. r=bas
gfx/2d/DrawTargetSkia.cpp
gfx/2d/ScaledFontDWrite.cpp
gfx/2d/ScaledFontDWrite.h
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -1013,19 +1013,23 @@ DrawTargetSkia::FillGlyphs(ScaledFont *a
   if (ShouldUseCGToFillGlyphs(aRenderingOptions, aPattern)) {
     if (FillGlyphsWithCG(aFont, aBuffer, aPattern, aOptions, aRenderingOptions)) {
       return;
     }
   }
 #endif
 
   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: