Bug 842894 - Support DirectWrite using the Skia backend. r=bas
authorMason Chang <mchang@mozilla.com>
Wed, 28 Oct 2015 14:54:54 -0700
changeset 305268 0c4702fbc9268041176571a4ba1decf79aa33621
parent 305267 1e2e66bf01dbbf7d5018185e925d975aa6189786
child 305269 0f2acb5edb41591a1c109eac293ee16ec3c6e38b
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs842894
milestone44.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 842894 - Support DirectWrite using the Skia backend. r=bas
gfx/2d/2D.h
gfx/2d/DrawTargetSkia.cpp
gfx/2d/Factory.cpp
gfx/2d/ScaledFontDWrite.cpp
gfx/2d/ScaledFontDWrite.h
gfx/skia/skia/include/ports/SkTypeface_win.h
gfx/skia/skia/src/ports/SkFontHost_win.cpp
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxDWriteFonts.cpp
gfx/thebes/gfxDWriteFonts.h
gfx/thebes/gfxWindowsPlatform.cpp
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -37,16 +37,19 @@ struct _cairo_scaled_font;
 typedef _cairo_scaled_font cairo_scaled_font_t;
 
 struct ID3D10Device1;
 struct ID3D10Texture2D;
 struct ID3D11Texture2D;
 struct ID3D11Device;
 struct ID2D1Device;
 struct IDWriteRenderingParams;
+struct IDWriteFont;
+struct IDWriteFontFamily;
+struct IDWriteFontFace;
 
 class GrContext;
 
 struct CGContext;
 typedef struct CGContext *CGContextRef;
 
 namespace mozilla {
 
@@ -1273,16 +1276,22 @@ public:
 
   static already_AddRefed<GlyphRenderingOptions>
     CreateDWriteGlyphRenderingOptions(IDWriteRenderingParams *aParams);
 
   static uint64_t GetD2DVRAMUsageDrawTarget();
   static uint64_t GetD2DVRAMUsageSourceSurface();
   static void D2DCleanup();
 
+  static already_AddRefed<ScaledFont>
+    CreateScaledFontForDWriteFont(IDWriteFont* aFont,
+                                  IDWriteFontFamily* aFontFamily,
+                                  IDWriteFontFace* aFontFace,
+                                  Float aSize);
+
 private:
   static ID2D1Device *mD2D1Device;
   static ID3D10Device1 *mD3D10Device;
   static ID3D11Device *mD3D11Device;
 #endif
 
   static DrawEventRecorder *mRecorder;
 };
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -568,17 +568,18 @@ void
 DrawTargetSkia::FillGlyphs(ScaledFont *aFont,
                            const GlyphBuffer &aBuffer,
                            const Pattern &aPattern,
                            const DrawOptions &aOptions,
                            const GlyphRenderingOptions *aRenderingOptions)
 {
   if (aFont->GetType() != FontType::MAC &&
       aFont->GetType() != FontType::SKIA &&
-      aFont->GetType() != FontType::GDI) {
+      aFont->GetType() != FontType::GDI &&
+      aFont->GetType() != FontType::DWRITE) {
     return;
   }
 
   MarkChanged();
 
   ScaledFontBase* skiaFont = static_cast<ScaledFontBase*>(aFont);
 
   AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -731,16 +731,25 @@ Factory::D2DCleanup()
   if (mD2D1Device) {
     mD2D1Device->Release();
     mD2D1Device = nullptr;
   }
   DrawTargetD2D1::CleanupD2D();
   DrawTargetD2D::CleanupD2D();
 }
 
+already_AddRefed<ScaledFont>
+Factory::CreateScaledFontForDWriteFont(IDWriteFont* aFont,
+                                       IDWriteFontFamily* aFontFamily,
+                                       IDWriteFontFace* aFontFace,
+                                       float aSize)
+{
+  return MakeAndAddRef<ScaledFontDWrite>(aFont, aFontFamily, aFontFace, aSize);
+}
+
 #endif // XP_WIN
 
 #ifdef USE_SKIA_GPU
 already_AddRefed<DrawTarget>
 Factory::CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
                                            const IntSize &aSize,
                                            SurfaceFormat aFormat)
 {
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -3,16 +3,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ScaledFontDWrite.h"
 #include "PathD2D.h"
 #include "DrawTargetD2D.h"
 #include "Logging.h"
 
+#ifdef USE_SKIA
+#include "PathSkia.h"
+#include "skia/include/core/SkPaint.h"
+#include "skia/include/core/SkPath.h"
+#include "skia/include/ports/SkTypeface_win.h"
+#endif
+
 #include <vector>
 
 namespace mozilla {
 namespace gfx {
 
 struct ffReferenceKey
 {
     uint8_t *mData;
@@ -282,16 +289,18 @@ DWriteFontFileStream::ReadFileFragment(c
 void STDMETHODCALLTYPE
 DWriteFontFileStream::ReleaseFileFragment(void *fragmentContext)
 {
 }
 
 ScaledFontDWrite::ScaledFontDWrite(uint8_t *aData, uint32_t aSize,
                                    uint32_t aIndex, Float aGlyphSize)
   : ScaledFontBase(aGlyphSize)
+  , mFont(nullptr)
+  , mFontFamily(nullptr)
 {
   IDWriteFactory *factory = DrawTargetD2D::GetDWriteFactory();
 
   ffReferenceKey key;
   key.mData = aData;
   key.mSize = aSize;
 
   RefPtr<IDWriteFontFile> fontFile;
@@ -318,16 +327,31 @@ ScaledFontDWrite::GetPathForGlyphs(const
   PathBuilderD2D *pathBuilderD2D =
     static_cast<PathBuilderD2D*>(pathBuilder.get());
 
   CopyGlyphsToSink(aBuffer, pathBuilderD2D->GetSink());
 
   return pathBuilder->Finish();
 }
 
+
+#ifdef USE_SKIA
+SkTypeface*
+ScaledFontDWrite::GetSkTypeface()
+{
+  MOZ_ASSERT(mFont);
+  if (!mTypeface) {
+    IDWriteFactory *factory = DrawTargetD2D::GetDWriteFactory();
+    // What to do if no font? How to create a font just with a font face?
+    mTypeface = SkCreateTypefaceFromDWriteFont(factory, mFontFace, mFont, mFontFamily);
+  }
+  return mTypeface;
+}
+#endif
+
 void
 ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint)
 {
   if (aBackendType != BackendType::DIRECT2D && aBackendType != BackendType::DIRECT2D1_1) {
     ScaledFontBase::CopyGlyphsToBuilder(aBuffer, aBuilder, aBackendType, aTransformHint);
     return;
   }
 
--- a/gfx/2d/ScaledFontDWrite.h
+++ b/gfx/2d/ScaledFontDWrite.h
@@ -14,40 +14,49 @@ struct ID2D1GeometrySink;
 namespace mozilla {
 namespace gfx {
 
 class ScaledFontDWrite final : public ScaledFontBase
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontDwrite)
   ScaledFontDWrite(IDWriteFontFace *aFont, Float aSize)
-    : mFontFace(aFont)
-    , ScaledFontBase(aSize)
+    : ScaledFontBase(aSize)
+    , mFont(nullptr)
+    , mFontFamily(nullptr)
+    , mFontFace(aFont)
   {}
+
   ScaledFontDWrite(uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize);
 
+  ScaledFontDWrite(IDWriteFont* aFont, IDWriteFontFamily* aFontFamily,
+                   IDWriteFontFace* aFontFace, Float aSize)
+    : ScaledFontBase(aSize)
+    , mFont(aFont)
+    , mFontFamily(aFontFamily)
+    , mFontFace(aFontFace)
+  {}
+
   virtual FontType GetType() const { return FontType::DWRITE; }
 
   virtual already_AddRefed<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
   virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint);
 
   void CopyGlyphsToSink(const GlyphBuffer &aBuffer, ID2D1GeometrySink *aSink);
 
   virtual bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton);
 
   virtual AntialiasMode GetDefaultAAMode();
 
 #ifdef USE_SKIA
-  virtual SkTypeface* GetSkTypeface()
-  {
-    MOZ_ASSERT(false, "Skia and DirectWrite do not mix");
-    return nullptr;
-  }
+  virtual SkTypeface* GetSkTypeface();
 #endif
 
+  RefPtr<IDWriteFont> mFont;
+  RefPtr<IDWriteFontFamily> mFontFamily;
   RefPtr<IDWriteFontFace> mFontFace;
 };
 
 class GlyphRenderingOptionsDWrite : public GlyphRenderingOptions
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptionsDWrite)
   GlyphRenderingOptionsDWrite(IDWriteRenderingParams *aParams)
--- a/gfx/skia/skia/include/ports/SkTypeface_win.h
+++ b/gfx/skia/skia/include/ports/SkTypeface_win.h
@@ -4,16 +4,17 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
 
 #ifndef SkTypeface_win_DEFINED
 #define SkTypeface_win_DEFINED
 
 #include "SkTypeface.h"
+#include <dwrite.h>
 
 /**
  *  Like the other Typeface create methods, this returns a new reference to the
  *  corresponding typeface for the specified logfont. The caller is responsible
  *  for calling unref() when it is finished.
  */
 SK_API SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&);
 
@@ -34,16 +35,26 @@ SK_API void SkLOGFONTFromTypeface(const 
 SK_API void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*)(const LOGFONT&));
 
 // Experimental!
 //
 class SkFontMgr;
 class SkRemotableFontMgr;
 struct IDWriteFactory;
 
+/**
+ *  Like the other Typeface create methods, this returns a new reference to the
+ *  corresponding typeface for the specified dwrite font. The caller is responsible
+ *  for calling unref() when it is finished.
+ */
+SK_API SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFactory* aFactory,
+                                                  IDWriteFontFace* aFontFace,
+                                                  IDWriteFont* aFont,
+                                                  IDWriteFontFamily* aFontFamily);
+
 SK_API SkFontMgr* SkFontMgr_New_GDI();
 SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory = NULL);
 
 /**
  *  Creates an SkFontMgr which renders using DirectWrite and obtains its data
  *  from the SkRemotableFontMgr.
  *
  *  If DirectWrite could not be initialized, will return NULL.
--- a/gfx/skia/skia/src/ports/SkFontHost_win.cpp
+++ b/gfx/skia/skia/src/ports/SkFontHost_win.cpp
@@ -22,16 +22,17 @@
 #include "SkOTUtils.h"
 #include "SkPath.h"
 #include "SkSFNTHeader.h"
 #include "SkStream.h"
 #include "SkString.h"
 #include "SkTemplates.h"
 #include "SkThread.h"
 #include "SkTypeface_win.h"
+#include "SkTypeface_win_dw.h"
 #include "SkTypefaceCache.h"
 #include "SkUtils.h"
 
 #include "SkTypes.h"
 #include <tchar.h>
 #include <usp10.h>
 #include <objbase.h>
 
@@ -337,16 +338,28 @@ SkTypeface* SkCreateTypefaceFromLOGFONT(
     SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
     if (NULL == face) {
         face = LogFontTypeface::Create(lf);
         SkTypefaceCache::Add(face, get_style(lf));
     }
     return face;
 }
 
+/***
+ * This guy is public.
+ */
+
+SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFactory* aFactory,
+                                           IDWriteFontFace* aFontFace,
+                                           IDWriteFont* aFont,
+                                           IDWriteFontFamily* aFontFamily)
+{
+  return DWriteFontTypeface::Create(aFactory, aFontFace, aFont, aFontFamily);
+}
+
 /**
  *  The created SkTypeface takes ownership of fontMemResource.
  */
 SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
     LOGFONT lf = origLF;
     make_canonical(&lf);
     FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource);
     SkTypefaceCache::Add(face, get_style(lf), false);
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -337,16 +337,34 @@ gfxDWriteFontFamily::AddSizeOfExcludingT
 void
 gfxDWriteFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
                                             FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
+already_AddRefed<IDWriteFont>
+gfxDWriteFontFamily::GetDefaultFont()
+{
+  RefPtr<IDWriteFont> font;
+  for (UINT32 i = 0; i < mDWFamily->GetFontCount(); i++) {
+    HRESULT hr = mDWFamily->GetFont(i, getter_AddRefs(font));
+    if (FAILED(hr)) {
+      NS_WARNING("Failed to get default font from existing family");
+      continue;
+    }
+
+    return font.forget();
+  }
+
+  NS_WARNING("No available DWrite fonts. Returning null");
+  return nullptr;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // gfxDWriteFontEntry
 
 gfxDWriteFontEntry::~gfxDWriteFontEntry()
 {
 }
 
 bool
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -52,16 +52,17 @@ public:
 
     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
 
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
 
+    already_AddRefed<IDWriteFont> GetDefaultFont();
 protected:
     /** This font family's directwrite fontfamily object */
     RefPtr<IDWriteFontFamily> mDWFamily;
     bool mForceGDIClassic;
 };
 
 /**
  * \brief Class representing DirectWrite FontEntry (a unique font style/family)
@@ -158,16 +159,20 @@ public:
     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
     bool GetForceGDIClassic() { return mForceGDIClassic; }
 
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
 
+    already_AddRefed<IDWriteFont> GetFont() {
+      return mFont.forget();
+    }
+
 protected:
     friend class gfxDWriteFont;
     friend class gfxDWriteFontList;
 
     virtual nsresult CopyFontTable(uint32_t aTableTag,
                                    FallibleTArray<uint8_t>& aBuffer) override;
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -77,17 +77,17 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntr
     , mMetrics(nullptr)
     , mSpaceGlyph(0)
     , mNeedsOblique(false)
     , mNeedsBold(aNeedsBold)
     , mUseSubpixelPositions(false)
     , mAllowManualShowGlyphs(true)
 {
     gfxDWriteFontEntry *fe =
-        static_cast<gfxDWriteFontEntry*>(aFontEntry);
+	        static_cast<gfxDWriteFontEntry*>(aFontEntry);
     nsresult rv;
     DWRITE_FONT_SIMULATIONS sims = DWRITE_FONT_SIMULATIONS_NONE;
     if ((GetStyle()->style != NS_FONT_STYLE_NORMAL) &&
         fe->IsUpright() &&
         GetStyle()->allowSyntheticStyle) {
             // For this we always use the font_matrix for uniformity. Not the
             // DWrite simulation.
             mNeedsOblique = true;
@@ -98,16 +98,31 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntr
 
     rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims);
 
     if (NS_FAILED(rv)) {
         mIsValid = false;
         return;
     }
 
+    mFont = fe->GetFont();
+    if (!mFont) {
+        gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList();
+        gfxDWriteFontFamily* defaultFontFamily =
+            static_cast<gfxDWriteFontFamily*>(fontList->GetDefaultFont(aFontStyle));
+
+        mFont = defaultFontFamily->GetDefaultFont();
+        NS_WARNING("Using default font");
+    }
+
+    HRESULT hr = mFont->GetFontFamily(getter_AddRefs(mFontFamily));
+    if (FAILED(hr)) {
+        MOZ_ASSERT(false);
+    }
+
     ComputeMetrics(anAAOption);
 }
 
 gfxDWriteFont::~gfxDWriteFont()
 {
     if (mCairoFontFace) {
         cairo_font_face_destroy(mCairoFontFace);
     }
@@ -682,16 +697,20 @@ gfxDWriteFont::GetScaledFont(mozilla::gf
   NativeFont nativeFont;
   nativeFont.mType = NativeFontType::DWRITE_FONT_FACE;
   nativeFont.mFont = GetFontFace();
 
   if (wantCairo) {
     mAzureScaledFont = Factory::CreateScaledFontWithCairo(nativeFont,
                                                         GetAdjustedSize(),
                                                         GetCairoScaledFont());
+  } else if (aTarget->GetBackendType() == BackendType::SKIA) {
+    mAzureScaledFont =
+            Factory::CreateScaledFontForDWriteFont(mFont, mFontFamily,
+                                                   mFontFace, GetAdjustedSize());
   } else {
     mAzureScaledFont = Factory::CreateScaledFontForNativeFont(nativeFont,
                                                             GetAdjustedSize());
   }
 
   mAzureScaledFontIsCairo = wantCairo;
 
   RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -86,16 +86,18 @@ protected:
     cairo_font_face_t *CairoFontFace();
 
     gfxFloat MeasureGlyphWidth(uint16_t aGlyph);
 
     DWRITE_MEASURING_MODE GetMeasuringMode();
     bool GetForceGDIClassic();
 
     RefPtr<IDWriteFontFace> mFontFace;
+    RefPtr<IDWriteFont> mFont;
+    RefPtr<IDWriteFontFamily> mFontFamily;
     cairo_font_face_t *mCairoFontFace;
 
     Metrics *mMetrics;
 
     // cache of glyph widths in 16.16 fixed-point pixels
     nsAutoPtr<nsDataHashtable<nsUint32HashKey,int32_t> > mGlyphWidths;
 
     uint32_t mSpaceGlyph;
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -685,19 +685,17 @@ gfxWindowsPlatform::VerifyD2DDevice(bool
 gfxPlatformFontList*
 gfxWindowsPlatform::CreatePlatformFontList()
 {
     gfxPlatformFontList *pfl;
 
 #ifdef CAIRO_HAS_DWRITE_FONT
     // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd
     // crashers so blacklist them altogether
-    if (IsNotWin7PreRTM() && GetDWriteFactory() &&
-        // Skia doesn't support DirectWrite fonts yet.
-       (gfxPlatform::GetDefaultContentBackend() != BackendType::SKIA)) {
+    if (IsNotWin7PreRTM() && 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();