Bug 1470515 - refactor ScaledFontFreeType for Android WR. r=rhunt
authorLee Salzman <lsalzman@mozilla.com>
Thu, 14 Jun 2018 16:42:56 -0700
changeset 423654 4a20ed6e2fee8c64419134ad5b6778f26bfffaec
parent 423653 2293404aad33465a91a13f9f49483907f9ed423a
child 423655 acfeb7bae5bba024111e12932a71bb80c5a2b1df
push id34190
push userebalazs@mozilla.com
push dateTue, 26 Jun 2018 14:53:39 +0000
treeherdermozilla-central@348090c6b5c4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrhunt
bugs1470515
milestone63.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 1470515 - refactor ScaledFontFreeType for Android WR. r=rhunt
gfx/2d/2D.h
gfx/2d/DrawTargetSkia.cpp
gfx/2d/Factory.cpp
gfx/2d/NativeFontResourceFontconfig.cpp
gfx/2d/NativeFontResourceFontconfig.h
gfx/2d/NativeFontResourceFreeType.cpp
gfx/2d/NativeFontResourceFreeType.h
gfx/2d/RecordedEventImpl.h
gfx/2d/ScaledFontBase.h
gfx/2d/ScaledFontCairo.cpp
gfx/2d/ScaledFontCairo.h
gfx/2d/ScaledFontFontconfig.cpp
gfx/2d/ScaledFontFontconfig.h
gfx/2d/ScaledFontFreeType.cpp
gfx/2d/ScaledFontFreeType.h
gfx/2d/ScaledFontWin.cpp
gfx/2d/Types.h
gfx/2d/UnscaledFontFreeType.cpp
gfx/2d/UnscaledFontFreeType.h
gfx/2d/moz.build
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFT2Fonts.cpp
gfx/thebes/gfxFT2Fonts.h
gfx/thebes/gfxFcPlatformFontList.cpp
gfx/thebes/gfxGDIFont.cpp
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -41,19 +41,16 @@
 #endif
 
 struct _cairo_surface;
 typedef _cairo_surface cairo_surface_t;
 
 struct _cairo_scaled_font;
 typedef _cairo_scaled_font cairo_scaled_font_t;
 
-struct _FcPattern;
-typedef _FcPattern FcPattern;
-
 struct FT_LibraryRec_;
 typedef FT_LibraryRec_* FT_Library;
 
 struct FT_FaceRec_;
 typedef FT_FaceRec_* FT_Face;
 
 struct ID3D11Texture2D;
 struct ID3D11Device;
@@ -1638,27 +1635,16 @@ public:
     CreateWrapAndRecordDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT);
 
   static already_AddRefed<DrawTarget>
     CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT, IntSize aSize);
 
   static already_AddRefed<DrawTarget>
     CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, bool aUninitialized = false);
 
-  static already_AddRefed<ScaledFont>
-    CreateScaledFontForNativeFont(const NativeFont &aNativeFont,
-                                  const RefPtr<UnscaledFont>& aUnscaledFont,
-                                  Float aSize);
-
-#ifdef MOZ_WIDGET_GTK
-  static already_AddRefed<ScaledFont>
-    CreateScaledFontForFontconfigFont(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern,
-                                      const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize);
-#endif
-
 #ifdef XP_DARWIN
   static already_AddRefed<ScaledFont>
     CreateScaledFontForMacFont(CGFontRef aCGFont, const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
                                const Color& aFontSmoothingBackgroundColor, bool aUseFontSmoothing = true,
                                bool aApplySyntheticBold = false);
 #endif
 
   /**
@@ -1677,25 +1663,27 @@ public:
   /**
    * This creates an unscaled font of the given type based on font descriptor
    * data retrieved from ScaledFont::GetFontDescriptor.
    */
   static already_AddRefed<UnscaledFont>
     CreateUnscaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex);
 
   /**
-   * This creates a scaled font with an associated cairo_scaled_font_t, and
-   * must be used when using the Cairo backend. The NativeFont and
-   * cairo_scaled_font_t* parameters must correspond to the same font.
+   * Creates a ScaledFont from the supplied NativeFont.
+   *
+   * If aScaledFont is supplied, this creates a scaled font with an associated
+   * cairo_scaled_font_t. The NativeFont and cairo_scaled_font_t* parameters must
+   * correspond to the same font.
    */
   static already_AddRefed<ScaledFont>
-    CreateScaledFontWithCairo(const NativeFont &aNativeFont,
-                              const RefPtr<UnscaledFont>& aUnscaledFont,
-                              Float aSize,
-                              cairo_scaled_font_t* aScaledFont);
+    CreateScaledFontForNativeFont(const NativeFont &aNativeFont,
+                                  const RefPtr<UnscaledFont>& aUnscaledFont,
+                                  Float aSize,
+                                  cairo_scaled_font_t* aScaledFont = nullptr);
 
   /**
    * This creates a simple data source surface for a certain size. It allocates
    * new memory for the surface. This memory is freed when the surface is
    * destroyed.  The caller is responsible for handing the case where nullptr
    * is returned. The surface is not zeroed unless requested.
    */
   static already_AddRefed<DataSourceSurface>
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "DrawTargetSkia.h"
 #include "SourceSurfaceSkia.h"
 #include "ScaledFontBase.h"
-#include "ScaledFontCairo.h"
 #include "FilterNodeSoftware.h"
 #include "HelpersSkia.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CheckedInt.h"
 
 #include "skia/include/core/SkSurface.h"
 #include "skia/include/core/SkTypeface.h"
@@ -985,16 +984,17 @@ DrawTargetSkia::ShouldLCDRenderText(Font
 
   if (aAntialiasMode == AntialiasMode::DEFAULT) {
     switch (aFontType) {
       case FontType::MAC:
       case FontType::GDI:
       case FontType::DWRITE:
       case FontType::FONTCONFIG:
         return true;
+      case FontType::FREETYPE:
       default:
         // TODO: Figure out what to do for the other platforms.
         return false;
     }
   }
   return (aAntialiasMode == AntialiasMode::SUBPIXEL);
 }
 
@@ -1347,18 +1347,17 @@ ShouldUseCGToFillGlyphs(ScaledFont* aFon
 }
 
 #endif
 
 static bool
 CanDrawFont(ScaledFont* aFont)
 {
   switch (aFont->GetType()) {
-  case FontType::SKIA:
-  case FontType::CAIRO:
+  case FontType::FREETYPE:
   case FontType::FONTCONFIG:
   case FontType::MAC:
   case FontType::GDI:
   case FontType::DWRITE:
     return true;
   default:
     return false;
   }
@@ -1410,18 +1409,17 @@ DrawTargetSkia::DrawGlyphs(ScaledFont* a
   paint.mPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
 
   bool shouldLCDRenderText = ShouldLCDRenderText(aFont->GetType(), aaMode);
   paint.mPaint.setLCDRenderText(shouldLCDRenderText);
 
   bool useSubpixelText = true;
 
   switch (aFont->GetType()) {
-  case FontType::SKIA:
-  case FontType::CAIRO:
+  case FontType::FREETYPE:
   case FontType::FONTCONFIG:
     // SkFontHost_cairo does not support subpixel text positioning,
     // so only enable it for other font hosts.
     useSubpixelText = false;
     break;
   case FontType::MAC:
     if (aaMode == AntialiasMode::GRAY) {
       // Normally, Skia enables LCD FontSmoothing which creates thicker fonts
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -4,46 +4,46 @@
  * 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 "2D.h"
 #include "Swizzle.h"
 
 #ifdef USE_CAIRO
 #include "DrawTargetCairo.h"
-#include "ScaledFontCairo.h"
 #include "SourceSurfaceCairo.h"
 #endif
 
 #ifdef USE_SKIA
 #include "DrawTargetSkia.h"
 #include "ScaledFontBase.h"
-#ifdef MOZ_ENABLE_FREETYPE
-#define USE_SKIA_FREETYPE
-#include "ScaledFontCairo.h"
-#endif
 #endif
 
 #if defined(WIN32)
 #include "ScaledFontWin.h"
 #include "NativeFontResourceGDI.h"
 #include "UnscaledFontGDI.h"
 #endif
 
 #ifdef XP_DARWIN
 #include "ScaledFontMac.h"
 #include "NativeFontResourceMac.h"
 #endif
 
 #ifdef MOZ_WIDGET_GTK
 #include "ScaledFontFontconfig.h"
-#include "NativeFontResourceFontconfig.h"
+#include "NativeFontResourceFreeType.h"
 #include "UnscaledFontFreeType.h"
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "ScaledFontFreeType.h"
+#include "NativeFontResourceFreeType.h"
+#endif
+
 #ifdef WIN32
 #include "DrawTargetD2D1.h"
 #include "ScaledFontDWrite.h"
 #include "NativeFontResourceDWrite.h"
 #include <d3d10_1.h>
 #include "HelpersD2D.h"
 #include "HelpersWinFonts.h"
 #include "mozilla/Mutex.h"
@@ -573,42 +573,39 @@ Factory::GetMaxSurfaceSize(BackendType a
   default:
     return 0;
   }
 }
 
 already_AddRefed<ScaledFont>
 Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont,
                                        const RefPtr<UnscaledFont>& aUnscaledFont,
-                                       Float aSize)
+                                       Float aSize,
+                                       cairo_scaled_font_t* aScaledFont)
 {
   switch (aNativeFont.mType) {
 #ifdef WIN32
-  case NativeFontType::DWRITE_FONT_FACE:
+  case NativeFontType::GDI_LOGFONT:
     {
-      return MakeAndAddRef<ScaledFontDWrite>(static_cast<IDWriteFontFace*>(aNativeFont.mFont), aUnscaledFont, aSize);
-    }
-#if defined(USE_CAIRO) || defined(USE_SKIA)
-  case NativeFontType::GDI_FONT_FACE:
-    {
-      return MakeAndAddRef<ScaledFontWin>(static_cast<LOGFONT*>(aNativeFont.mFont), aUnscaledFont, aSize);
-    }
-#endif
+      RefPtr<ScaledFontWin> font = MakeAndAddRef<ScaledFontWin>(static_cast<LOGFONT*>(aNativeFont.mFont), aUnscaledFont, aSize);
+#ifdef USE_CAIRO
+      if (aScaledFont) {
+        font->SetCairoScaledFont(aScaledFont);
+      } else {
+        font->PopulateCairoScaledFont();
+      }
 #endif
-#ifdef XP_DARWIN
-  case NativeFontType::MAC_FONT_FACE:
-    {
-      return MakeAndAddRef<ScaledFontMac>(static_cast<CGFontRef>(aNativeFont.mFont), aUnscaledFont, aSize);
+      return font.forget();
     }
-#endif
-#if defined(USE_CAIRO) || defined(USE_SKIA_FREETYPE)
-  case NativeFontType::CAIRO_FONT_FACE:
-    {
-      return MakeAndAddRef<ScaledFontCairo>(static_cast<cairo_scaled_font_t*>(aNativeFont.mFont), aUnscaledFont, aSize);
-    }
+#elif defined(MOZ_WIDGET_GTK)
+  case NativeFontType::FONTCONFIG_PATTERN:
+    return MakeAndAddRef<ScaledFontFontconfig>(aScaledFont, static_cast<FcPattern*>(aNativeFont.mFont), aUnscaledFont, aSize);
+#elif defined(MOZ_WIDGET_ANDROID)
+  case NativeFontType::FREETYPE_FACE:
+    return MakeAndAddRef<ScaledFontFreeType>(aScaledFont, static_cast<FT_Face>(aNativeFont.mFont), aUnscaledFont, aSize);
 #endif
   default:
     gfxWarning() << "Invalid native font type specified.";
     return nullptr;
   }
 }
 
 already_AddRefed<NativeFontResource>
@@ -626,16 +623,20 @@ Factory::CreateNativeFontResource(uint8_
     return NativeFontResourceGDI::Create(aData, aSize);
 #elif defined(XP_DARWIN)
   case FontType::MAC:
     return NativeFontResourceMac::Create(aData, aSize);
 #elif defined(MOZ_WIDGET_GTK)
   case FontType::FONTCONFIG:
     return NativeFontResourceFontconfig::Create(aData, aSize,
                                                 static_cast<FT_Library>(aFontContext));
+#elif defined(MOZ_WIDGET_ANDROID)
+  case FontType::FREETYPE:
+    return NativeFontResourceFreeType::Create(aData, aSize,
+                                              static_cast<FT_Library>(aFontContext));
 #endif
   default:
     gfxWarning() << "Unable to create requested font resource from truetype data";
     return nullptr;
   }
 }
 
 already_AddRefed<UnscaledFont>
@@ -651,44 +652,16 @@ Factory::CreateUnscaledFontFromFontDescr
     return UnscaledFontFontconfig::CreateFromFontDescriptor(aData, aDataLength, aIndex);
 #endif
   default:
     gfxWarning() << "Invalid type specified for UnscaledFont font descriptor";
     return nullptr;
   }
 }
 
-already_AddRefed<ScaledFont>
-Factory::CreateScaledFontWithCairo(const NativeFont& aNativeFont,
-                                   const RefPtr<UnscaledFont>& aUnscaledFont,
-                                   Float aSize,
-                                   cairo_scaled_font_t* aScaledFont)
-{
-#ifdef USE_CAIRO
-  // In theory, we could pull the NativeFont out of the cairo_scaled_font_t*,
-  // but that would require a lot of code that would be otherwise repeated in
-  // various backends.
-  // Therefore, we just reuse CreateScaledFontForNativeFont's implementation.
-  RefPtr<ScaledFont> font = CreateScaledFontForNativeFont(aNativeFont, aUnscaledFont, aSize);
-  static_cast<ScaledFontBase*>(font.get())->SetCairoScaledFont(aScaledFont);
-  return font.forget();
-#else
-  return nullptr;
-#endif
-}
-
-#ifdef MOZ_WIDGET_GTK
-already_AddRefed<ScaledFont>
-Factory::CreateScaledFontForFontconfigFont(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern,
-                                           const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize)
-{
-  return MakeAndAddRef<ScaledFontFontconfig>(aScaledFont, aPattern, aUnscaledFont, aSize);
-}
-#endif
-
 #ifdef XP_DARWIN
 already_AddRefed<ScaledFont>
 Factory::CreateScaledFontForMacFont(CGFontRef aCGFont,
                                     const RefPtr<UnscaledFont>& aUnscaledFont,
                                     Float aSize,
                                     const Color& aFontSmoothingBackgroundColor,
                                     bool aUseFontSmoothing,
                                     bool aApplySyntheticBold)
rename from gfx/2d/NativeFontResourceFontconfig.cpp
rename to gfx/2d/NativeFontResourceFreeType.cpp
--- a/gfx/2d/NativeFontResourceFontconfig.cpp
+++ b/gfx/2d/NativeFontResourceFreeType.cpp
@@ -1,41 +1,41 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "NativeFontResourceFontconfig.h"
-#include "ScaledFontFontconfig.h"
+#include "NativeFontResourceFreeType.h"
 #include "UnscaledFontFreeType.h"
 #include "Logging.h"
 
 namespace mozilla {
 namespace gfx {
 
-NativeFontResourceFontconfig::NativeFontResourceFontconfig(UniquePtr<uint8_t[]>&& aFontData,
-                                                           uint32_t aDataLength,
-                                                           FT_Face aFace)
+NativeFontResourceFreeType::NativeFontResourceFreeType(UniquePtr<uint8_t[]>&& aFontData,
+                                                       uint32_t aDataLength,
+                                                       FT_Face aFace)
   : mFontData(std::move(aFontData))
   , mDataLength(aDataLength)
   , mFace(aFace)
 {
 }
 
-NativeFontResourceFontconfig::~NativeFontResourceFontconfig()
+NativeFontResourceFreeType::~NativeFontResourceFreeType()
 {
   if (mFace) {
     Factory::ReleaseFTFace(mFace);
     mFace = nullptr;
   }
 }
 
-already_AddRefed<NativeFontResourceFontconfig>
-NativeFontResourceFontconfig::Create(uint8_t *aFontData, uint32_t aDataLength, FT_Library aFTLibrary)
+template<class T>
+already_AddRefed<T>
+NativeFontResourceFreeType::CreateInternal(uint8_t *aFontData, uint32_t aDataLength, FT_Library aFTLibrary)
 {
   if (!aFontData || !aDataLength) {
     return nullptr;
   }
   UniquePtr<uint8_t[]> fontData(new (fallible) uint8_t[aDataLength]);
   if (!fontData) {
     return nullptr;
   }
@@ -45,29 +45,59 @@ NativeFontResourceFontconfig::Create(uin
   if (!face) {
     return nullptr;
   }
   if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != FT_Err_Ok) {
     Factory::ReleaseFTFace(face);
     return nullptr;
   }
 
-  RefPtr<NativeFontResourceFontconfig> resource =
-    new NativeFontResourceFontconfig(std::move(fontData), aDataLength, face);
+  RefPtr<T> resource = new T(std::move(fontData), aDataLength, face);
   return resource.forget();
 }
 
+#ifdef MOZ_WIDGET_ANDROID
+already_AddRefed<NativeFontResourceFreeType>
+NativeFontResourceFreeType::Create(uint8_t *aFontData, uint32_t aDataLength, FT_Library aFTLibrary)
+{
+  return CreateInternal<NativeFontResourceFreeType>(aFontData, aDataLength, aFTLibrary);
+}
+
+already_AddRefed<UnscaledFont>
+NativeFontResourceFreeType::CreateUnscaledFont(uint32_t aIndex,
+                                               const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
+{
+  RefPtr<UnscaledFont> unscaledFont = new UnscaledFontFreeType(mFace, this);
+  return unscaledFont.forget();
+}
+#endif
+
+FT_Face
+NativeFontResourceFreeType::CloneFace()
+{
+  return Factory::NewFTFaceFromData(mFace->glyph->library, mFontData.get(), mDataLength, 0);
+}
+
+#ifdef MOZ_WIDGET_GTK
+NativeFontResourceFontconfig::NativeFontResourceFontconfig(UniquePtr<uint8_t[]>&& aFontData,
+                                                           uint32_t aDataLength,
+                                                           FT_Face aFace)
+  : NativeFontResourceFreeType(std::move(aFontData), aDataLength, aFace)
+{
+}
+
 already_AddRefed<UnscaledFont>
 NativeFontResourceFontconfig::CreateUnscaledFont(uint32_t aIndex,
                                                  const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
 {
   RefPtr<UnscaledFont> unscaledFont = new UnscaledFontFontconfig(mFace, this);
   return unscaledFont.forget();
 }
 
-FT_Face
-NativeFontResourceFontconfig::CloneFace()
+already_AddRefed<NativeFontResourceFontconfig>
+NativeFontResourceFontconfig::Create(uint8_t *aFontData, uint32_t aDataLength, FT_Library aFTLibrary)
 {
-  return Factory::NewFTFaceFromData(mFace->glyph->library, mFontData.get(), mDataLength, 0);
+  return CreateInternal<NativeFontResourceFontconfig>(aFontData, aDataLength, aFTLibrary);
 }
+#endif
 
 } // gfx
 } // mozilla
rename from gfx/2d/NativeFontResourceFontconfig.h
rename to gfx/2d/NativeFontResourceFreeType.h
--- a/gfx/2d/NativeFontResourceFontconfig.h
+++ b/gfx/2d/NativeFontResourceFreeType.h
@@ -1,47 +1,75 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
-#ifndef mozilla_gfx_NativeFontResourceFontconfig_h
-#define mozilla_gfx_NativeFontResourceFontconfig_h
+#ifndef mozilla_gfx_NativeFontResourceFreeType_h
+#define mozilla_gfx_NativeFontResourceFreeType_h
 
 #include "2D.h"
 
 #include <cairo-ft.h>
 #include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 namespace gfx {
 
-class NativeFontResourceFontconfig final : public NativeFontResource
+class NativeFontResourceFreeType : public NativeFontResource
+{
+public:
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceFreeType, override)
+
+#ifdef MOZ_WIDGET_ANDROID
+  static already_AddRefed<NativeFontResourceFreeType>
+    Create(uint8_t *aFontData, uint32_t aDataLength, FT_Library aFTLibrary = nullptr);
+
+  already_AddRefed<UnscaledFont>
+    CreateUnscaledFont(uint32_t aIndex,
+                       const uint8_t* aInstanceData, uint32_t aInstanceDataLength) override;
+#endif
+
+  ~NativeFontResourceFreeType();
+
+  FT_Face CloneFace();
+
+protected:
+  NativeFontResourceFreeType(UniquePtr<uint8_t[]>&& aFontData,
+                             uint32_t aDataLength,
+                             FT_Face aFace);
+
+  template<class T>
+  static already_AddRefed<T>
+    CreateInternal(uint8_t *aFontData, uint32_t aDataLength, FT_Library aFTLibrary);
+
+  UniquePtr<uint8_t[]> mFontData;
+  uint32_t mDataLength;
+  FT_Face mFace;
+};
+
+#ifdef MOZ_WIDGET_GTK
+class NativeFontResourceFontconfig final : public NativeFontResourceFreeType
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceFontconfig, override)
 
   static already_AddRefed<NativeFontResourceFontconfig>
     Create(uint8_t *aFontData, uint32_t aDataLength, FT_Library aFTLibrary = nullptr);
 
   already_AddRefed<UnscaledFont>
     CreateUnscaledFont(uint32_t aIndex,
                        const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final;
 
-  ~NativeFontResourceFontconfig();
+private:
+  friend class NativeFontResourceFreeType;
 
-  FT_Face CloneFace();
-
-private:
   NativeFontResourceFontconfig(UniquePtr<uint8_t[]>&& aFontData,
                                uint32_t aDataLength,
                                FT_Face aFace);
-
-  UniquePtr<uint8_t[]> mFontData;
-  uint32_t mDataLength;
-  FT_Face mFace;
 };
+#endif
 
 } // gfx
 } // mozilla
 
-#endif // mozilla_gfx_NativeFontResourceFontconfig_h
+#endif // mozilla_gfx_NativeFontResourceFreeType_h
--- a/gfx/2d/RecordedEventImpl.h
+++ b/gfx/2d/RecordedEventImpl.h
@@ -3057,17 +3057,17 @@ RecordedFontData::GetFontDetails(Recorde
   fontDetails.size = mFontDetails.size;
   fontDetails.index = mFontDetails.index;
   return true;
 }
 
 template<class S>
 RecordedFontData::RecordedFontData(S &aStream)
   : RecordedEventDerived(FONTDATA)
-  , mType(FontType::SKIA)
+  , mType(FontType::UNKNOWN)
   , mData(nullptr)
 {
   ReadElement(aStream, mType);
   ReadElement(aStream, mFontDetails.fontDataKey);
   ReadElement(aStream, mFontDetails.size);
   mData = new (fallible) uint8_t[mFontDetails.size];
   if (!mData) {
     gfxCriticalNote << "RecordedFontData failed to allocate data for playback of size " << mFontDetails.size;
--- a/gfx/2d/ScaledFontBase.h
+++ b/gfx/2d/ScaledFontBase.h
@@ -40,19 +40,16 @@ public:
   virtual void GetGlyphDesignMetrics(const uint16_t* aGlyphIndices, uint32_t aNumGlyphs, GlyphMetrics* aGlyphMetrics) override;
 
   virtual Float GetSize() const override { return mSize; }
 
 #ifdef USE_SKIA
   virtual SkTypeface* GetSkTypeface() { return mTypeface; }
 #endif
 
-  // Not true, but required to instantiate a ScaledFontBase.
-  virtual FontType GetType() const override { return FontType::SKIA; }
-
 #ifdef USE_CAIRO_SCALED_FONT
   bool PopulateCairoScaledFont();
   virtual cairo_scaled_font_t* GetCairoScaledFont() override { return mScaledFont; }
   virtual void SetCairoScaledFont(cairo_scaled_font_t* font) override;
 #endif
 
 protected:
   friend class DrawTargetSkia;
--- a/gfx/2d/ScaledFontFontconfig.cpp
+++ b/gfx/2d/ScaledFontFontconfig.cpp
@@ -1,27 +1,26 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "ScaledFontFontconfig.h"
 #include "UnscaledFontFreeType.h"
-#include "NativeFontResourceFontconfig.h"
+#include "NativeFontResourceFreeType.h"
 #include "Logging.h"
 #include "StackArray.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 
 #ifdef USE_SKIA
 #include "skia/include/ports/SkTypeface_cairo.h"
 #endif
 
 #include <fontconfig/fcfreetype.h>
-#include <dlfcn.h>
 
 #include FT_MULTIPLE_MASTERS_H
 
 namespace mozilla {
 namespace gfx {
 
 // On Linux and Android our "platform" font is a cairo_scaled_font_t and we use
 // an SkFontHost implementation that allows Skia to render using this.
@@ -105,23 +104,16 @@ ScaledFontFontconfig::InstanceData::Inst
       int hintstyle;
       if (FcPatternGetInteger(aPattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) {
         hintstyle = FC_HINT_FULL;
       }
       mHintStyle = hintstyle;
     }
   }
   cairo_font_options_destroy(fontOptions);
-
-  // Some fonts supply an adjusted size or otherwise use the font matrix for italicization.
-  // Record the scale and the skew to accomodate both of these cases.
-  cairo_matrix_t fontMatrix;
-  cairo_scaled_font_get_font_matrix(aScaledFont, &fontMatrix);
-  mScale = Float(fontMatrix.xx);
-  mSkew = Float(fontMatrix.xy);
 }
 
 void
 ScaledFontFontconfig::InstanceData::SetupPattern(FcPattern* aPattern) const
 {
   if (mFlags & AUTOHINT) {
     FcPatternAddBool(aPattern, FC_AUTOHINT, FcTrue);
   }
@@ -215,86 +207,27 @@ ScaledFontFontconfig::InstanceData::Setu
     // antialiasing.
     cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_OFF);
     cairo_font_options_set_hint_style(aFontOptions, CAIRO_HINT_STYLE_NONE);
     cairo_font_options_set_antialias(aFontOptions,
       mFlags & ANTIALIAS ? CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE);
   }
 }
 
-void
-ScaledFontFontconfig::InstanceData::SetupFontMatrix(cairo_matrix_t* aFontMatrix) const
-{
-  // Build a font matrix that will reproduce a possibly adjusted size
-  // and any italics/skew. This is just the concatenation of a simple
-  // scale matrix with a matrix that skews on the X axis.
-  cairo_matrix_init(aFontMatrix, mScale, 0, mSkew, mScale, 0, 0);
-}
-
-void
-ScaledFontFontconfig::GetVariationSettings(std::vector<FontVariation>* aVariations)
-{
-  aVariations->clear();
-
-  typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**);
-  typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*);
-  typedef FT_Error (*GetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
-  static GetVarFunc getVar;
-  static DoneVarFunc doneVar;
-  static GetVarDesignCoordsFunc getCoords;
-  static bool firstTime = true;
-  if (firstTime) {
-    firstTime = false;
-    getVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var");
-    doneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var");
-    getCoords = (GetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT, "FT_Get_Var_Design_Coordinates");
-  }
-
-  if (!getVar || !getCoords) {
-    return;
-  }
-
-  cairo_scaled_font_t* sf = GetCairoScaledFont();
-  FT_Face face = cairo_ft_scaled_font_lock_face(sf);
-  if (face && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
-    FT_MM_Var* mmVar;
-    if ((*getVar)(face, &mmVar) == FT_Err_Ok) {
-      aVariations->reserve(mmVar->num_axis);
-      StackArray<FT_Fixed, 32> coords(mmVar->num_axis);
-      if ((*getCoords)(face, mmVar->num_axis, coords.data()) == FT_Err_Ok) {
-        bool changed = false;
-        for (uint32_t i = 0; i < mmVar->num_axis; i++) {
-          if (coords[i] != mmVar->axis[i].def) {
-            changed = true;
-          }
-          aVariations->push_back(FontVariation{uint32_t(mmVar->axis[i].tag),
-                                               float(coords[i] / 65536.0)});
-        }
-        if (!changed) {
-          aVariations->clear();
-        }
-      }
-      if (doneVar) {
-        (*doneVar)(face->glyph->library, mmVar);
-      } else {
-        free(mmVar);
-      }
-    }
-  }
-  cairo_ft_scaled_font_unlock_face(sf);
-}
-
 bool
 ScaledFontFontconfig::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
 {
   InstanceData instance(GetCairoScaledFont(), mPattern);
 
   std::vector<FontVariation> variations;
   if (HasVariationSettings()) {
-    GetVariationSettings(&variations);
+    FT_Face face = nullptr;
+    if (FcPatternGetFTFace(mPattern, FC_FT_FACE, 0, &face) == FcResultMatch) {
+      UnscaledFontFreeType::GetVariationSettingsFromFace(&variations, face);
+    }
   }
 
   aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance),
       variations.data(), variations.size(), aBaton);
   return true;
 }
 
 bool
@@ -409,17 +342,20 @@ ScaledFontFontconfig::GetWRFontInstanceO
       break;
     }
   }
 
   *aOutOptions = Some(options);
   *aOutPlatformOptions = Some(platformOptions);
 
   if (HasVariationSettings()) {
-    GetVariationSettings(aOutVariations);
+    FT_Face face = nullptr;
+    if (FcPatternGetFTFace(mPattern, FC_FT_FACE, 0, &face) == FcResultMatch) {
+      UnscaledFontFreeType::GetVariationSettingsFromFace(aOutVariations, face);
+    }
   }
 
   return true;
 }
 
 already_AddRefed<ScaledFont>
 UnscaledFontFontconfig::CreateScaledFont(Float aGlyphSize,
                                          const uint8_t* aInstanceData,
@@ -537,17 +473,17 @@ ScaledFontFontconfig::CreateFromInstance
       aNativeFontResource->Release();
       cairo_font_face_destroy(font);
       FcPatternDestroy(pattern);
       return nullptr;
     }
   }
 
   cairo_matrix_t sizeMatrix;
-  aInstanceData.SetupFontMatrix(&sizeMatrix);
+  cairo_matrix_init(&sizeMatrix, aSize, 0, 0, aSize, 0, 0);
 
   cairo_matrix_t identityMatrix;
   cairo_matrix_init_identity(&identityMatrix);
 
   cairo_font_options_t *fontOptions = cairo_font_options_create();
   aInstanceData.SetupFontOptions(fontOptions);
 
   cairo_scaled_font_t* cairoScaledFont =
@@ -566,86 +502,38 @@ ScaledFontFontconfig::CreateFromInstance
     new ScaledFontFontconfig(cairoScaledFont, pattern, aUnscaledFont, aSize);
 
   cairo_scaled_font_destroy(cairoScaledFont);
   FcPatternDestroy(pattern);
 
   // Only apply variations if we have an explicitly cloned face. Otherwise,
   // if the pattern holds the pathname, Cairo will handle setting of variations.
   if (varFace) {
-    scaledFont->ApplyVariations(aVariations, aNumVariations);
+    UnscaledFontFreeType::ApplyVariationsToFace(aVariations, aNumVariations, varFace);
   }
 
   return scaledFont.forget();
 }
 
-void
-ScaledFontFontconfig::ApplyVariations(const FontVariation* aVariations,
-                                      uint32_t aNumVariations)
-{
-  typedef FT_Error (*SetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
-  static SetVarDesignCoordsFunc setCoords;
-  static bool firstTime = true;
-  if (firstTime) {
-    firstTime = false;
-    setCoords = (SetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT, "FT_Set_Var_Design_Coordinates");
-  }
-
-  if (!setCoords) {
-    return;
-  }
-
-  cairo_scaled_font_t* sf = GetCairoScaledFont();
-  FT_Face face = cairo_ft_scaled_font_lock_face(sf);
-  if (face && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
-    StackArray<FT_Fixed, 32> coords(aNumVariations);
-    for (uint32_t i = 0; i < aNumVariations; i++) {
-      coords[i] = std::round(aVariations[i].mValue * 65536.0f);
-    }
-    if ((*setCoords)(face, aNumVariations, coords.data()) != FT_Err_Ok) {
-      // ignore the problem?
-    }
-  }
-  cairo_ft_scaled_font_unlock_face(sf);
-}
-
 bool
 ScaledFontFontconfig::HasVariationSettings()
 {
   // Check if the FT face has been cloned.
   FT_Face face = nullptr;
   return FcPatternGetFTFace(mPattern, FC_FT_FACE, 0, &face) == FcResultMatch &&
          face && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS &&
          face != static_cast<UnscaledFontFontconfig*>(mUnscaledFont.get())->GetFace();
 }
 
 already_AddRefed<UnscaledFont>
 UnscaledFontFontconfig::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex)
 {
-  if (aDataLength <= 1) {
+  if (aDataLength == 0) {
     gfxWarning() << "Fontconfig font descriptor is truncated.";
     return nullptr;
   }
   const char* path = reinterpret_cast<const char*>(aData);
-  if (path[aDataLength - 1] != '\0') {
-    gfxWarning() << "Pathname in Fontconfig font descriptor is not terminated.";
-    return nullptr;
-  }
-
-  RefPtr<UnscaledFont> unscaledFont = new UnscaledFontFontconfig(path, aIndex);
+  RefPtr<UnscaledFont> unscaledFont = new UnscaledFontFontconfig(std::string(path, aDataLength), aIndex);
   return unscaledFont.forget();
 }
 
-bool
-UnscaledFontFontconfig::GetWRFontDescriptor(WRFontDescriptorOutput aCb, void* aBaton)
-{
-  if (mFile.empty()) {
-    return false;
-  }
-
-  const char* path = mFile.c_str();
-  size_t pathLength = strlen(path);
-  aCb(reinterpret_cast<const uint8_t*>(path), pathLength, mIndex, aBaton);
-  return true;
-}
-
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/2d/ScaledFontFontconfig.h
+++ b/gfx/2d/ScaledFontFontconfig.h
@@ -34,49 +34,42 @@ public:
   bool CanSerialize() override { return true; }
 
   bool GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) override;
 
   bool GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
                                 Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
                                 std::vector<FontVariation>* aOutVariations) override;
 
-  void ApplyVariations(const FontVariation* aVariations, uint32_t aNumVariations);
-
   bool HasVariationSettings() override;
 
 private:
   friend class NativeFontResourceFontconfig;
   friend class UnscaledFontFontconfig;
 
-  void GetVariationSettings(std::vector<FontVariation>* aVariations);
-
   struct InstanceData
   {
     enum {
       ANTIALIAS       = 1 << 0,
       AUTOHINT        = 1 << 1,
       EMBEDDED_BITMAP = 1 << 2,
       EMBOLDEN        = 1 << 3,
       VERTICAL_LAYOUT = 1 << 4,
       HINT_METRICS    = 1 << 5
     };
 
     InstanceData(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern);
 
     void SetupPattern(FcPattern* aPattern) const;
     void SetupFontOptions(cairo_font_options_t* aFontOptions) const;
-    void SetupFontMatrix(cairo_matrix_t* aFontMatrix) const;
 
     uint8_t mFlags;
     uint8_t mHintStyle;
     uint8_t mSubpixelOrder;
     uint8_t mLcdFilter;
-    Float mScale;
-    Float mSkew;
   };
 
   static already_AddRefed<ScaledFont>
     CreateFromInstanceData(const InstanceData& aInstanceData,
                            UnscaledFontFontconfig* aUnscaledFont,
                            Float aSize,
                            const FontVariation* aVariations,
                            uint32_t aNumVariations,
rename from gfx/2d/ScaledFontCairo.cpp
rename to gfx/2d/ScaledFontFreeType.cpp
--- a/gfx/2d/ScaledFontCairo.cpp
+++ b/gfx/2d/ScaledFontFreeType.cpp
@@ -1,41 +1,226 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "ScaledFontCairo.h"
+#include "ScaledFontFreeType.h"
+#include "UnscaledFontFreeType.h"
+#include "NativeFontResourceFreeType.h"
 #include "Logging.h"
+#include "StackArray.h"
+#include "mozilla/webrender/WebRenderTypes.h"
 
-#if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE)
+#ifdef USE_SKIA
 #include "skia/include/ports/SkTypeface_cairo.h"
 #endif
 
+#include FT_MULTIPLE_MASTERS_H
+
 namespace mozilla {
 namespace gfx {
 
 // On Linux and Android our "platform" font is a cairo_scaled_font_t and we use
 // an SkFontHost implementation that allows Skia to render using this.
 // This is mainly because FT_Face is not good for sharing between libraries, which
 // is a requirement when we consider runtime switchable backends and so on
-ScaledFontCairo::ScaledFontCairo(cairo_scaled_font_t* aScaledFont,
-                                 const RefPtr<UnscaledFont>& aUnscaledFont,
-                                 Float aSize)
+ScaledFontFreeType::ScaledFontFreeType(cairo_scaled_font_t* aScaledFont,
+                                       FT_Face aFace,
+                                       const RefPtr<UnscaledFont>& aUnscaledFont,
+                                       Float aSize)
   : ScaledFontBase(aUnscaledFont, aSize)
+  , mFace(aFace)
 {
   SetCairoScaledFont(aScaledFont);
 }
 
-#if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE)
-SkTypeface* ScaledFontCairo::GetSkTypeface()
+#ifdef USE_SKIA
+SkTypeface* ScaledFontFreeType::GetSkTypeface()
 {
   if (!mTypeface) {
     mTypeface = SkCreateTypefaceFromCairoFTFont(mScaledFont);
   }
 
   return mTypeface;
 }
 #endif
 
+bool
+ScaledFontFreeType::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
+{
+  std::vector<FontVariation> variations;
+  if (HasVariationSettings()) {
+    UnscaledFontFreeType::GetVariationSettingsFromFace(&variations, mFace);
+  }
+
+  aCb(nullptr, 0, variations.data(), variations.size(), aBaton);
+  return true;
+}
+
+bool
+ScaledFontFreeType::GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
+                                             Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
+                                             std::vector<FontVariation>* aOutVariations)
+{
+  wr::FontInstanceOptions options;
+  options.render_mode = wr::FontRenderMode::Alpha;
+  // FIXME: Cairo-FT metrics are not compatible with subpixel positioning.
+  // options.flags = wr::FontInstanceFlags::SUBPIXEL_POSITION;
+  options.flags = 0;
+  options.bg_color = wr::ToColorU(Color());
+
+  wr::FontInstancePlatformOptions platformOptions;
+  platformOptions.lcd_filter = wr::FontLCDFilter::None;
+  platformOptions.hinting = wr::FontHinting::None;
+
+  *aOutOptions = Some(options);
+  *aOutPlatformOptions = Some(platformOptions);
+
+  if (HasVariationSettings()) {
+    UnscaledFontFreeType::GetVariationSettingsFromFace(aOutVariations, mFace);
+  }
+
+  return true;
+}
+
+static cairo_user_data_key_t sNativeFontResourceKey;
+
+static void
+ReleaseNativeFontResource(void* aData)
+{
+  static_cast<NativeFontResource*>(aData)->Release();
+}
+
+static cairo_user_data_key_t sFaceKey;
+
+static void
+ReleaseFace(void* aData)
+{
+  Factory::ReleaseFTFace(static_cast<FT_Face>(aData));
+}
+
+already_AddRefed<ScaledFont>
+UnscaledFontFreeType::CreateScaledFont(Float aGlyphSize,
+                                       const uint8_t* aInstanceData,
+                                       uint32_t aInstanceDataLength,
+                                       const FontVariation* aVariations,
+                                       uint32_t aNumVariations)
+{
+  FT_Face face = GetFace();
+  if (!face) {
+    gfxWarning() << "Attempted to deserialize FreeType scaled font without FreeType face";
+    return nullptr;
+  }
+
+  NativeFontResourceFreeType* nfr = static_cast<NativeFontResourceFreeType*>(mNativeFontResource.get());
+  FT_Face varFace = nullptr;
+  if (nfr && aNumVariations > 0) {
+    varFace = nfr->CloneFace();
+    if (varFace) {
+      face = varFace;
+    } else {
+      gfxWarning() << "Failed cloning face for variations";
+    }
+  }
+
+  StackArray<FT_Fixed, 32> coords(aNumVariations);
+  for (uint32_t i = 0; i < aNumVariations; i++) {
+    coords[i] = std::round(aVariations[i].mValue * 65536.0);
+  }
+
+  int flags = FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING;
+  cairo_font_face_t* font =
+    cairo_ft_font_face_create_for_ft_face(face, flags, coords.data(), aNumVariations);
+  if (cairo_font_face_status(font) != CAIRO_STATUS_SUCCESS) {
+    gfxWarning() << "Failed creating Cairo font face for FreeType face";
+    if (varFace) {
+      Factory::ReleaseFTFace(varFace);
+    }
+    return nullptr;
+  }
+
+
+  if (nfr) {
+    // Bug 1362117 - Cairo may keep the font face alive after the owning NativeFontResource
+    // was freed. To prevent this, we must bind the NativeFontResource to the font face so that
+    // it stays alive at least as long as the font face.
+    nfr->AddRef();
+    // Bug 1412545 - Setting Cairo font user data is not thread-safe. If FT_Faces match,
+    // cairo_ft_font_face_create_for_ft_face may share Cairo faces. We need to lock setting user data
+    // to prevent races if multiple threads are thus sharing the same Cairo face.
+    FT_Library library = face->glyph->library;
+    Factory::LockFTLibrary(library);
+    cairo_status_t err = CAIRO_STATUS_SUCCESS;
+    bool cleanupFace = false;
+    if (varFace) {
+      err = cairo_font_face_set_user_data(font,
+                                          &sFaceKey,
+                                          varFace,
+                                          ReleaseFace);
+    }
+
+    if (err != CAIRO_STATUS_SUCCESS) {
+      cleanupFace = true;
+    } else {
+      err = cairo_font_face_set_user_data(font,
+                                          &sNativeFontResourceKey,
+                                          nfr,
+                                          ReleaseNativeFontResource);
+    }
+    Factory::UnlockFTLibrary(library);
+    if (err != CAIRO_STATUS_SUCCESS) {
+      gfxWarning() << "Failed binding NativeFontResource to Cairo font face";
+      if (varFace && cleanupFace) {
+        Factory::ReleaseFTFace(varFace);
+      }
+      nfr->Release();
+      cairo_font_face_destroy(font);
+      return nullptr;
+    }
+  }
+
+  cairo_matrix_t sizeMatrix;
+  cairo_matrix_init(&sizeMatrix, aGlyphSize, 0, 0, aGlyphSize, 0, 0);
+
+  cairo_matrix_t identityMatrix;
+  cairo_matrix_init_identity(&identityMatrix);
+
+  cairo_font_options_t *fontOptions = cairo_font_options_create();
+  cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
+
+  cairo_scaled_font_t* cairoScaledFont =
+    cairo_scaled_font_create(font, &sizeMatrix, &identityMatrix, fontOptions);
+
+  cairo_font_options_destroy(fontOptions);
+
+  cairo_font_face_destroy(font);
+
+  if (cairo_scaled_font_status(cairoScaledFont) != CAIRO_STATUS_SUCCESS) {
+    gfxWarning() << "Failed creating Cairo scaled font for font face";
+    return nullptr;
+  }
+
+  RefPtr<ScaledFontFreeType> scaledFont =
+    new ScaledFontFreeType(cairoScaledFont, face, this, aGlyphSize);
+
+  cairo_scaled_font_destroy(cairoScaledFont);
+
+  // Only apply variations if we have an explicitly cloned face. Otherwise,
+  // if the pattern holds the pathname, Cairo will handle setting of variations.
+  if (varFace) {
+    ApplyVariationsToFace(aVariations, aNumVariations, varFace);
+  }
+
+  return scaledFont.forget();
+}
+
+bool
+ScaledFontFreeType::HasVariationSettings()
+{
+  // Check if the FT face has been cloned.
+  return mFace && mFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS &&
+         mFace != static_cast<UnscaledFontFreeType*>(mUnscaledFont.get())->GetFace();
+}
+
 } // namespace gfx
 } // namespace mozilla
rename from gfx/2d/ScaledFontCairo.h
rename to gfx/2d/ScaledFontFreeType.h
--- a/gfx/2d/ScaledFontCairo.h
+++ b/gfx/2d/ScaledFontFreeType.h
@@ -4,31 +4,47 @@
  * 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/. */
 
 #ifndef MOZILLA_GFX_SCALEDFONTCAIRO_H_
 #define MOZILLA_GFX_SCALEDFONTCAIRO_H_
 
 #include "ScaledFontBase.h"
 
-#include "cairo.h"
+#include <cairo-ft.h>
 
 namespace mozilla {
 namespace gfx {
 
-class ScaledFontCairo : public ScaledFontBase
+class ScaledFontFreeType : public ScaledFontBase
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontCairo, override)
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontFreeType, override)
 
-  ScaledFontCairo(cairo_scaled_font_t* aScaledFont,
-                  const RefPtr<UnscaledFont>& aUnscaledFont,
-                  Float aSize);
+  ScaledFontFreeType(cairo_scaled_font_t* aScaledFont,
+                     FT_Face aFace,
+                     const RefPtr<UnscaledFont>& aUnscaledFont,
+                     Float aSize);
 
-#if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE)
+  FontType GetType() const override { return FontType::FREETYPE; }
+
+#ifdef USE_SKIA
   virtual SkTypeface* GetSkTypeface() override;
 #endif
+
+  bool CanSerialize() override { return true; }
+
+  bool GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) override;
+
+  bool GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
+                                Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
+                                std::vector<FontVariation>* aOutVariations) override;
+
+  bool HasVariationSettings() override;
+
+private:
+  FT_Face mFace;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_SCALEDFONTCAIRO_H_ */
--- a/gfx/2d/ScaledFontWin.cpp
+++ b/gfx/2d/ScaledFontWin.cpp
@@ -104,27 +104,20 @@ UnscaledFontGDI::CreateScaledFont(Float 
                                   uint32_t aNumVariations)
 {
   if (aInstanceDataLength < sizeof(LOGFONT)) {
     gfxWarning() << "GDI unscaled font instance data is truncated.";
     return nullptr;
   }
 
   NativeFont nativeFont;
-  nativeFont.mType = NativeFontType::GDI_FONT_FACE;
+  nativeFont.mType = NativeFontType::GDI_LOGFONT;
   nativeFont.mFont = (void*)aInstanceData;
 
-  RefPtr<ScaledFont> font =
-    Factory::CreateScaledFontForNativeFont(nativeFont, this, aGlyphSize);
-
-#ifdef USE_CAIRO_SCALED_FONT
-  static_cast<ScaledFontBase*>(font.get())->PopulateCairoScaledFont();
-#endif
-
-  return font.forget();
+  return Factory::CreateScaledFontForNativeFont(nativeFont, this, aGlyphSize);
 }
 
 AntialiasMode
 ScaledFontWin::GetDefaultAAMode()
 {
   return GetSystemDefaultAAMode();
 }
 
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -149,37 +149,33 @@ enum class BackendType : int8_t {
   // Add new entries above this line.
   BACKEND_LAST
 };
 
 enum class FontType : int8_t {
   DWRITE,
   GDI,
   MAC,
-  SKIA,
-  CAIRO,
-  COREGRAPHICS,
   FONTCONFIG,
-  FREETYPE
+  FREETYPE,
+  UNKNOWN
 };
 
 enum class NativeSurfaceType : int8_t {
   D3D10_TEXTURE,
   CAIRO_CONTEXT,
   CGCONTEXT,
   CGCONTEXT_ACCELERATED,
   OPENGL_TEXTURE
 };
 
 enum class NativeFontType : int8_t {
-  DWRITE_FONT_FACE,
-  GDI_FONT_FACE,
-  MAC_FONT_FACE,
-  SKIA_FONT_FACE,
-  CAIRO_FONT_FACE
+  GDI_LOGFONT,
+  FREETYPE_FACE,
+  FONTCONFIG_PATTERN,
 };
 
 enum class FontStyle : int8_t {
   NORMAL,
   ITALIC,
   BOLD,
   BOLD_ITALIC
 };
--- a/gfx/2d/UnscaledFontFreeType.cpp
+++ b/gfx/2d/UnscaledFontFreeType.cpp
@@ -1,18 +1,24 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "UnscaledFontFreeType.h"
+#include "NativeFontResourceFreeType.h"
+#include "ScaledFontFreeType.h"
+#include "Logging.h"
+#include "StackArray.h"
 
+#include FT_MULTIPLE_MASTERS_H
 #include FT_TRUETYPE_TABLES_H
 
+#include <dlfcn.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
 
 namespace mozilla {
 namespace gfx {
@@ -64,17 +70,116 @@ UnscaledFontFreeType::GetFontFileData(Fo
 
 bool
 UnscaledFontFreeType::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton)
 {
   if (mFile.empty()) {
     return false;
   }
 
-  const char* path = mFile.c_str();
-  size_t pathLength = strlen(path) + 1;
-  aCb(reinterpret_cast<const uint8_t*>(path), pathLength, mIndex, aBaton);
+  aCb(reinterpret_cast<const uint8_t*>(mFile.data()), mFile.size(), mIndex, aBaton);
+  return true;
+}
+
+bool
+UnscaledFontFreeType::GetWRFontDescriptor(WRFontDescriptorOutput aCb, void* aBaton)
+{
+  if (mFile.empty()) {
+    return false;
+  }
+
+  aCb(reinterpret_cast<const uint8_t*>(mFile.data()), mFile.size(), mIndex, aBaton);
   return true;
 }
 
+void
+UnscaledFontFreeType::GetVariationSettingsFromFace(std::vector<FontVariation>* aVariations,
+                                                   FT_Face aFace)
+{
+  if (!aFace || !(aFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
+    return;
+  }
+
+  typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**);
+  typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*);
+  typedef FT_Error (*GetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
+#if MOZ_TREE_FREETYPE
+  GetVarFunc getVar = &FT_Get_MM_Var;
+  DoneVarFunc doneVar = &FT_Done_MM_Var;
+  GetVarDesignCoordsFunc getCoords = &FT_Get_Var_Design_Coordinates;
+#else
+  static GetVarFunc getVar;
+  static DoneVarFunc doneVar;
+  static GetVarDesignCoordsFunc getCoords;
+  static bool firstTime = true;
+  if (firstTime) {
+    firstTime = false;
+    getVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var");
+    doneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var");
+    getCoords = (GetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT, "FT_Get_Var_Design_Coordinates");
+  }
+  if (!getVar || !getCoords) {
+    return;
+  }
+#endif
+
+  FT_MM_Var* mmVar = nullptr;
+  if ((*getVar)(aFace, &mmVar) == FT_Err_Ok) {
+    aVariations->reserve(mmVar->num_axis);
+    StackArray<FT_Fixed, 32> coords(mmVar->num_axis);
+    if ((*getCoords)(aFace, mmVar->num_axis, coords.data()) == FT_Err_Ok) {
+      bool changed = false;
+      for (uint32_t i = 0; i < mmVar->num_axis; i++) {
+        if (coords[i] != mmVar->axis[i].def) {
+          changed = true;
+        }
+        aVariations->push_back(FontVariation{uint32_t(mmVar->axis[i].tag),
+                                             float(coords[i] / 65536.0)});
+      }
+      if (!changed) {
+        aVariations->clear();
+      }
+    }
+    if (doneVar) {
+      (*doneVar)(aFace->glyph->library, mmVar);
+    } else {
+      free(mmVar);
+    }
+  }
+}
+
+void
+UnscaledFontFreeType::ApplyVariationsToFace(const FontVariation* aVariations,
+                                            uint32_t aNumVariations,
+                                            FT_Face aFace)
+{
+  if (!aFace || !(aFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
+    return;
+  }
+
+  typedef FT_Error (*SetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
+#ifdef MOZ_TREE_FREETYPE
+  SetVarDesignCoordsFunc setCoords = &FT_Set_Var_Design_Coordinates;
+#else
+  typedef FT_Error (*SetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
+  static SetVarDesignCoordsFunc setCoords;
+  static bool firstTime = true;
+  if (firstTime) {
+    firstTime = false;
+    setCoords = (SetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT, "FT_Set_Var_Design_Coordinates");
+  }
+  if (!setCoords) {
+    return;
+  }
+#endif
+
+  StackArray<FT_Fixed, 32> coords(aNumVariations);
+  for (uint32_t i = 0; i < aNumVariations; i++) {
+    coords[i] = std::round(aVariations[i].mValue * 65536.0f);
+  }
+  if ((*setCoords)(aFace, aNumVariations, coords.data()) != FT_Err_Ok) {
+    // ignore the problem?
+  }
+}
+
 } // namespace gfx
 } // namespace mozilla
 
--- a/gfx/2d/UnscaledFontFreeType.h
+++ b/gfx/2d/UnscaledFontFreeType.h
@@ -9,16 +9,19 @@
 
 #include <cairo-ft.h>
 
 #include "2D.h"
 
 namespace mozilla {
 namespace gfx {
 
+class ScaledFontFreeType;
+class ScaledFontFontconfig;
+
 class UnscaledFontFreeType : public UnscaledFont
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(UnscaledFontFreeType, override)
   explicit UnscaledFontFreeType(FT_Face aFace,
                                 bool aOwnsFace = false)
     : mFace(aFace)
     , mOwnsFace(aOwnsFace)
@@ -26,75 +29,113 @@ public:
   {}
   explicit UnscaledFontFreeType(const char* aFile,
                                 uint32_t aIndex = 0)
     : mFace(nullptr)
     , mOwnsFace(false)
     , mFile(aFile)
     , mIndex(aIndex)
   {}
+  explicit UnscaledFontFreeType(std::string&& aFile,
+                                uint32_t aIndex = 0)
+    : mFace(nullptr)
+    , mOwnsFace(false)
+    , mFile(std::move(aFile))
+    , mIndex(aIndex)
+  {}
+  UnscaledFontFreeType(FT_Face aFace,
+                       NativeFontResource* aNativeFontResource)
+    : mFace(aFace)
+    , mOwnsFace(false)
+    , mIndex(0)
+    , mNativeFontResource(aNativeFontResource)
+  {}
   ~UnscaledFontFreeType()
   {
     if (mOwnsFace) {
       Factory::ReleaseFTFace(mFace);
     }
   }
 
   FontType GetType() const override { return FontType::FREETYPE; }
 
   FT_Face GetFace() const { return mFace; }
   const char* GetFile() const { return mFile.c_str(); }
   uint32_t GetIndex() const { return mIndex; }
+  const RefPtr<NativeFontResource>& GetNativeFontResource() const { return mNativeFontResource; }
 
   bool GetFontFileData(FontFileDataOutput aDataCallback, void* aBaton) override;
 
   bool GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) override;
 
+  bool GetWRFontDescriptor(WRFontDescriptorOutput aCb, void* aBaton) override;
+
+#ifdef MOZ_WIDGET_ANDROID
+  already_AddRefed<ScaledFont>
+    CreateScaledFont(Float aGlyphSize,
+                     const uint8_t* aInstanceData,
+                     uint32_t aInstanceDataLength,
+                     const FontVariation* aVariations,
+                     uint32_t aNumVariations) override;
+#endif
+
 protected:
   FT_Face mFace;
   bool mOwnsFace;
   std::string mFile;
   uint32_t mIndex;
+  RefPtr<NativeFontResource> mNativeFontResource;
+
+private:
+  friend class ScaledFontFreeType;
+  friend class ScaledFontFontconfig;
+
+  static void
+    GetVariationSettingsFromFace(std::vector<FontVariation>* aVariations,
+                                 FT_Face aFace);
+
+  static void
+    ApplyVariationsToFace(const FontVariation* aVariations,
+                          uint32_t aNumVariations,
+                          FT_Face aFace);
 };
 
 #ifdef MOZ_WIDGET_GTK
 class UnscaledFontFontconfig : public UnscaledFontFreeType
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(UnscaledFontFontconfig, override)
   explicit UnscaledFontFontconfig(FT_Face aFace,
                                   bool aOwnsFace = false)
     : UnscaledFontFreeType(aFace, aOwnsFace)
   {}
   explicit UnscaledFontFontconfig(const char* aFile,
                                   uint32_t aIndex = 0)
     : UnscaledFontFreeType(aFile, aIndex)
   {}
+  explicit UnscaledFontFontconfig(std::string&& aFile,
+                                  uint32_t aIndex = 0)
+    : UnscaledFontFreeType(std::move(aFile), aIndex)
+  {}
   UnscaledFontFontconfig(FT_Face aFace,
                          NativeFontResource* aNativeFontResource)
-    : UnscaledFontFreeType(aFace, false)
-    , mNativeFontResource(aNativeFontResource)
+    : UnscaledFontFreeType(aFace, aNativeFontResource)
   {}
 
   FontType GetType() const override { return FontType::FONTCONFIG; }
 
   static already_AddRefed<UnscaledFont>
     CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex);
 
   already_AddRefed<ScaledFont>
     CreateScaledFont(Float aGlyphSize,
                      const uint8_t* aInstanceData,
                      uint32_t aInstanceDataLength,
                      const FontVariation* aVariations,
                      uint32_t aNumVariations) override;
-
-  bool GetWRFontDescriptor(WRFontDescriptorOutput aCb, void* aBaton) override;
-
-private:
-  RefPtr<NativeFontResource> mNativeFontResource;
 };
 #endif
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_UNSCALEDFONTFREETYPE_H_ */
 
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -101,25 +101,30 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'wind
         'JobScheduler_posix.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk3'):
     EXPORTS.mozilla.gfx += [
         'UnscaledFontFreeType.h',
     ]
     SOURCES += [
+        'NativeFontResourceFreeType.cpp',
         'UnscaledFontFreeType.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
     SOURCES += [
-        'NativeFontResourceFontconfig.cpp',
         'ScaledFontFontconfig.cpp',
     ]
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
+    SOURCES += [
+        'ScaledFontFreeType.cpp',
+    ]
+
 if CONFIG['MOZ_ENABLE_SKIA']:
     SOURCES += [
         'ConvolutionFilter.cpp',
         'DrawTargetSkia.cpp',
         'PathSkia.cpp',
         'SourceSurfaceSkia.cpp',
     ]
     if CONFIG['CC_TYPE'] == 'clang':
@@ -179,17 +184,16 @@ UNIFIED_SOURCES += [
     'Path.cpp',
     'PathCairo.cpp',
     'PathHelpers.cpp',
     'PathRecording.cpp',
     'Quaternion.cpp',
     'RecordedEvent.cpp',
     'Scale.cpp',
     'ScaledFontBase.cpp',
-    'ScaledFontCairo.cpp',
     'SFNTData.cpp',
     'SFNTNameTable.cpp',
     'SourceSurfaceCairo.cpp',
     'SourceSurfaceCapture.cpp',
     'SourceSurfaceRawData.cpp',
     'Swizzle.cpp',
 ]
 
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -284,19 +284,17 @@ WebRenderBridgeChild::PushGlyphs(wr::Dis
                     aGlyphOptions);
 }
 
 wr::FontInstanceKey
 WebRenderBridgeChild::GetFontKeyForScaledFont(gfx::ScaledFont* aScaledFont)
 {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(aScaledFont);
-  MOZ_ASSERT((aScaledFont->GetType() == gfx::FontType::DWRITE) ||
-             (aScaledFont->GetType() == gfx::FontType::MAC) ||
-             (aScaledFont->GetType() == gfx::FontType::FONTCONFIG));
+  MOZ_ASSERT(aScaledFont->CanSerialize());
 
   wr::FontInstanceKey instanceKey = { wr::IdNamespace { 0 }, 0 };
   if (mFontInstanceKeys.Get(aScaledFont, &instanceKey)) {
     return instanceKey;
   }
 
   wr::IpcResourceUpdateQueue resources(this);
 
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -75,17 +75,17 @@ BuildKeyNameFromFontName(nsAString &aNam
 // This allows us to read font names, tables, etc if necessary
 // without permanently instantiating a freetype face and consuming
 // memory long-term.
 // This may fail (resulting in a null FT_Face), e.g. if it fails to
 // allocate memory to uncompress a font from omnijar.
 class AutoFTFace {
 public:
     explicit AutoFTFace(FT2FontEntry* aFontEntry)
-        : mFace(nullptr), mFontDataBuf(nullptr), mOwnsFace(false)
+        : mFace(nullptr), mFontDataBuf(nullptr), mDataLength(0), mOwnsFace(false)
     {
         if (aFontEntry->mFTFace) {
             mFace = aFontEntry->mFTFace;
             return;
         }
 
         NS_ASSERTION(!aFontEntry->mFilename.IsEmpty(),
                      "can't use AutoFTFace for fonts without a filename");
@@ -225,36 +225,42 @@ FT2FontEntry::Clone() const
     fe->mFilename = mFilename;
     fe->mFTFontIndex = mFTFontIndex;
     fe->mWeightRange = mWeightRange;
     fe->mStretchRange = mStretchRange;
     fe->mStyleRange = mStyleRange;
     return fe;
 }
 
+static cairo_user_data_key_t sFTFaceKey;
+
 gfxFont*
 FT2FontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle)
 {
     cairo_scaled_font_t *scaledFont = CreateScaledFont(aFontStyle);
     if (!scaledFont) {
         return nullptr;
     }
 
     RefPtr<UnscaledFontFreeType> unscaledFont(mUnscaledFont);
     if (!unscaledFont) {
         unscaledFont =
-            mFilename.IsEmpty() ?
-                new UnscaledFontFreeType(mFTFace) :
+            !mFilename.IsEmpty() && mFilename[0] == '/' ?
                 new UnscaledFontFreeType(mFilename.BeginReading(),
-                                         mFTFontIndex);
+                                         mFTFontIndex) :
+                new UnscaledFontFreeType(mFTFace);
         mUnscaledFont = unscaledFont;
     }
 
-    gfxFont *font = new gfxFT2Font(unscaledFont, scaledFont, this,
-                                   aFontStyle);
+    cairo_font_face_t* face = cairo_scaled_font_get_font_face(scaledFont);
+    FT_Face ftFace = static_cast<FT_Face>(cairo_font_face_get_user_data(face, &sFTFaceKey));
+
+    gfxFont *font = new gfxFT2Font(unscaledFont, scaledFont,
+                                   ftFace ? ftFace : mFTFace,
+                                   this, aFontStyle);
     cairo_scaled_font_destroy(scaledFont);
     return font;
 }
 
 /* static */
 FT2FontEntry*
 FT2FontEntry::CreateFontEntry(const nsAString& aFontName,
                               WeightRange aWeight,
@@ -466,34 +472,33 @@ FT2FontEntry::CairoFontFace(const gfxFon
         // Resolve variations from entry (descriptor) and style (property)
         AutoTArray<gfxFontVariation,8> settings;
         GetVariationsForStyle(settings, aStyle ? *aStyle : gfxFontStyle());
         AutoTArray<FT_Fixed,8> coords;
         gfxFT2FontBase::SetupVarCoords(mFTFace, settings, &coords);
         // Create a separate FT_Face because we need to apply custom
         // variation settings to it.
         FT_Face ftFace;
-        if (!mFilename.IsEmpty()) {
+        if (!mFilename.IsEmpty() && mFilename[0] == '/') {
             ftFace = Factory::NewFTFace(nullptr, mFilename.get(), mFTFontIndex);
         } else {
             auto ufd = reinterpret_cast<FTUserFontData*>(
                 cairo_font_face_get_user_data(mFontFace, &sFTUserFontDataKey));
             ftFace = Factory::NewFTFaceFromData(nullptr, ufd->FontData(),
                                                 ufd->Length(), mFTFontIndex);
         }
         // The variation coordinates will actually be applied to ftFace by
         // gfxFT2FontBase::InitMetrics, so we don't need to do it here.
         cairo_font_face_t* cairoFace =
             cairo_ft_font_face_create_for_ft_face(ftFace, flags,
                                                   coords.Elements(),
                                                   coords.Length());
         // Set up user data to properly release the FT_Face when the cairo face
         // is deleted.
-        static cairo_user_data_key_t sDestroyFaceKey;
-        if (cairo_font_face_set_user_data(cairoFace, &sDestroyFaceKey, ftFace,
+        if (cairo_font_face_set_user_data(cairoFace, &sFTFaceKey, ftFace,
                     (cairo_destroy_func_t)&Factory::ReleaseFTFace)) {
             // set_user_data failed! discard, and fall back to default face
             cairo_font_face_destroy(cairoFace);
             FT_Done_Face(ftFace);
         } else {
             return cairoFace;
         }
     }
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -158,41 +158,45 @@ gfxFT2Font::AddRange(const char16_t *aTe
                                                                 true, 1),
                                    &details);
         }
     }
 }
 
 gfxFT2Font::gfxFT2Font(const RefPtr<UnscaledFontFreeType>& aUnscaledFont,
                        cairo_scaled_font_t *aCairoFont,
+                       FT_Face aFTFace,
                        FT2FontEntry *aFontEntry,
                        const gfxFontStyle *aFontStyle)
     : gfxFT2FontBase(aUnscaledFont, aCairoFont, aFontEntry, aFontStyle)
     , mCharGlyphCache(32)
+    , mFTFace(aFTFace)
 {
     NS_ASSERTION(mFontEntry, "Unable to find font entry for font.  Something is whack.");
     // TODO: use FreeType emboldening instead of multi-strike?
     mApplySyntheticBold = aFontStyle->NeedsSyntheticBold(aFontEntry);
 }
 
 gfxFT2Font::~gfxFT2Font()
 {
 }
 
 already_AddRefed<ScaledFont>
 gfxFT2Font::GetScaledFont(DrawTarget *aTarget)
 {
     if (!mAzureScaledFont) {
         NativeFont nativeFont;
-        nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
-        nativeFont.mFont = GetCairoScaledFont();
+        nativeFont.mType = NativeFontType::FREETYPE_FACE;
+        nativeFont.mFont = mFTFace;
+
         mAzureScaledFont =
-            Factory::CreateScaledFontForNativeFont(nativeFont,
-                                                   GetUnscaledFont(),
-                                                   GetAdjustedSize());
+          Factory::CreateScaledFontForNativeFont(nativeFont,
+                                                 GetUnscaledFont(),
+                                                 GetAdjustedSize(),
+                                                 GetCairoScaledFont());
     }
 
     RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
     return scaledFont.forget();
 }
 
 void
 gfxFT2Font::FillGlyphDataForChar(FT_Face face, uint32_t ch, CachedGlyphData *gd)
--- a/gfx/thebes/gfxFT2Fonts.h
+++ b/gfx/thebes/gfxFT2Fonts.h
@@ -16,16 +16,17 @@
 #include "gfxUserFontSet.h"
 
 class FT2FontEntry;
 
 class gfxFT2Font : public gfxFT2FontBase {
 public: // new functions
     gfxFT2Font(const RefPtr<mozilla::gfx::UnscaledFontFreeType>& aUnscaledFont,
                cairo_scaled_font_t *aCairoFont,
+               FT_Face aFTFace,
                FT2FontEntry *aFontEntry,
                const gfxFontStyle *aFontStyle);
     virtual ~gfxFT2Font ();
 
     FT2FontEntry *GetFontEntry();
 
     virtual already_AddRefed<mozilla::gfx::ScaledFont>
     GetScaledFont(DrawTarget *aTarget) override;
@@ -77,12 +78,13 @@ protected:
     void AddRange(const char16_t *aText,
                   uint32_t         aOffset,
                   uint32_t         aLength,
                   gfxShapedText   *aShapedText);
 
     typedef nsBaseHashtableET<nsUint32HashKey, CachedGlyphData> CharGlyphMapEntryType;
     typedef nsTHashtable<CharGlyphMapEntryType> CharGlyphMap;
     CharGlyphMap mCharGlyphCache;
+    FT_Face mFTFace;
 };
 
 #endif /* GFX_FT2FONTS_H */
 
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -1453,21 +1453,25 @@ gfxFontconfigFont::gfxFontconfigFont(con
 gfxFontconfigFont::~gfxFontconfigFont()
 {
 }
 
 already_AddRefed<ScaledFont>
 gfxFontconfigFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
 {
     if (!mAzureScaledFont) {
+        NativeFont nativeFont;
+        nativeFont.mType = NativeFontType::FONTCONFIG_PATTERN;
+        nativeFont.mFont = GetPattern();
+
         mAzureScaledFont =
-            Factory::CreateScaledFontForFontconfigFont(GetCairoScaledFont(),
-                                                       GetPattern(),
-                                                       GetUnscaledFont(),
-                                                       GetAdjustedSize());
+          Factory::CreateScaledFontForNativeFont(nativeFont,
+                                                 GetUnscaledFont(),
+                                                 GetAdjustedSize(),
+                                                 GetCairoScaledFont());
     }
 
     RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
     return scaledFont.forget();
 }
 
 gfxFcPlatformFontList::gfxFcPlatformFontList()
     : mLocalNames(64)
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -136,26 +136,26 @@ gfxGDIFont::SetupCairoFont(DrawTarget* a
     return true;
 }
 
 already_AddRefed<ScaledFont>
 gfxGDIFont::GetScaledFont(DrawTarget *aTarget)
 {
     if (!mAzureScaledFont) {
         NativeFont nativeFont;
-        nativeFont.mType = NativeFontType::GDI_FONT_FACE;
+        nativeFont.mType = NativeFontType::GDI_LOGFONT;
         LOGFONT lf;
         GetObject(GetHFONT(), sizeof(LOGFONT), &lf);
         nativeFont.mFont = &lf;
 
         mAzureScaledFont =
-          Factory::CreateScaledFontWithCairo(nativeFont,
-                                             GetUnscaledFont(),
-                                             GetAdjustedSize(),
-                                             GetCairoScaledFont());
+          Factory::CreateScaledFontForNativeFont(nativeFont,
+                                                 GetUnscaledFont(),
+                                                 GetAdjustedSize(),
+                                                 GetCairoScaledFont());
     }
 
     RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
     return scaledFont.forget();
 }
 
 gfxFont::RunMetrics
 gfxGDIFont::Measure(const gfxTextRun *aTextRun,