Bug 1309205 - part 2 - provide NativeFontResourceFontconfig so that print_via_parent works on Linux. r=jfkthame
authorLee Salzman <lsalzman@mozilla.com>
Wed, 04 Jan 2017 14:01:12 -0500
changeset 327974 2797f193a147a4a09d508ae2e7417cd83e657ebd
parent 327973 5c25a123203a599f20d48840910bccf3ef707027
child 327975 5b9702d8fe4e8ddf3ce155e81d54b9d199805843
push id31160
push userphilringnalda@gmail.com
push dateThu, 05 Jan 2017 02:33:44 +0000
treeherdermozilla-central@f13abb8ba9f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1309205
milestone53.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 1309205 - part 2 - provide NativeFontResourceFontconfig so that print_via_parent works on Linux. r=jfkthame MozReview-Commit-ID: 94XcLKgwTPq
gfx/2d/2D.h
gfx/2d/Factory.cpp
gfx/2d/NativeFontResourceDWrite.cpp
gfx/2d/NativeFontResourceDWrite.h
gfx/2d/NativeFontResourceFontconfig.cpp
gfx/2d/NativeFontResourceFontconfig.h
gfx/2d/NativeFontResourceGDI.cpp
gfx/2d/NativeFontResourceGDI.h
gfx/2d/NativeFontResourceMac.cpp
gfx/2d/NativeFontResourceMac.h
gfx/2d/RecordedEvent.cpp
gfx/2d/RecordedEvent.h
gfx/2d/ScaledFontFontconfig.cpp
gfx/2d/ScaledFontFontconfig.h
gfx/2d/ScaledFontWin.cpp
gfx/2d/ScaledFontWin.h
gfx/2d/moz.build
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -674,18 +674,19 @@ struct GlyphMetrics
  * the font used for the drawing call.
  */
 class ScaledFont : public external::AtomicRefCounted<ScaledFont>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
   virtual ~ScaledFont() {}
 
-  typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, void *aBaton);
-  typedef void (*FontDescriptorOutput)(const uint8_t *aData, uint32_t aLength, Float aFontSize, void *aBaton);
+  typedef void (*FontFileDataOutput)(const uint8_t* aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, void* aBaton);
+  typedef void (*FontInstanceDataOutput)(const uint8_t* aData, uint32_t aLength, void* aBaton);
+  typedef void (*FontDescriptorOutput)(const uint8_t* aData, uint32_t aLength, Float aFontSize, void* aBaton);
 
   virtual FontType GetType() const = 0;
   virtual AntialiasMode GetDefaultAAMode() {
     if (gfxPrefs::DisableAllTextAA()) {
       return AntialiasMode::NONE;
     }
 
     return AntialiasMode::DEFAULT;
@@ -706,16 +707,18 @@ public:
   virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint = nullptr) = 0;
 
   /* This gets the metrics of a set of glyphs for the current font face.
    */
   virtual void GetGlyphDesignMetrics(const uint16_t* aGlyphIndices, uint32_t aNumGlyphs, GlyphMetrics* aGlyphMetrics) = 0;
 
   virtual bool GetFontFileData(FontFileDataOutput, void *) { return false; }
 
+  virtual bool GetFontInstanceData(FontInstanceDataOutput, void *) { return false; }
+
   virtual bool GetFontDescriptor(FontDescriptorOutput, void *) { return false; }
 
   void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
     mUserData.Add(key, userData, destroy);
   }
   void *GetUserData(UserDataKey *key) {
     return mUserData.Get(key);
   }
@@ -736,20 +739,23 @@ public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResource)
 
   /**
    * Creates a ScaledFont using the font corresponding to the index and
    * the given glyph size.
    *
    * @param aIndex index for the font within the resource.
    * @param aGlyphSize the size of ScaledFont required.
+   * @param aInstanceData pointer to read-only buffer of any available instance data.
+   * @param aInstanceDataLength the size of the instance data.
    * @return an already_addrefed ScaledFont, containing nullptr if failed.
    */
   virtual already_AddRefed<ScaledFont>
-    CreateScaledFont(uint32_t aIndex, Float aGlyphSize) = 0;
+    CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) = 0;
 
   virtual ~NativeFontResource() {};
 };
 
 /** This class is designed to allow passing additional glyph rendering
  * parameters to the glyph drawing functions. This is an empty wrapper class
  * merely used to allow holding on to and passing around platform specific
  * parameters. This is because different platforms have unique rendering
@@ -1394,16 +1400,23 @@ public:
    * @param aSize Size of the TrueType data
    * @param aType Type of NativeFontResource that should be created.
    * @return a NativeFontResource of nullptr if failed.
    */
   static already_AddRefed<NativeFontResource>
     CreateNativeFontResource(uint8_t *aData, uint32_t aSize, FontType aType);
 
   /**
+   * This creates a scaled font of the given type based on font descriptor
+   * data retrieved from ScaledFont::GetFontDescriptor.
+   */
+  static already_AddRefed<ScaledFont>
+    CreateScaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength, Float aSize);
+
+  /**
    * 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.
    */
   static already_AddRefed<ScaledFont>
     CreateScaledFontWithCairo(const NativeFont &aNativeFont, Float aSize, cairo_scaled_font_t* aScaledFont);
 
   /**
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -27,16 +27,17 @@
 
 #ifdef XP_DARWIN
 #include "ScaledFontMac.h"
 #include "NativeFontResourceMac.h"
 #endif
 
 #ifdef MOZ_WIDGET_GTK
 #include "ScaledFontFontconfig.h"
+#include "NativeFontResourceFontconfig.h"
 #endif
 
 #ifdef WIN32
 #include "DrawTargetD2D1.h"
 #include "ScaledFontDWrite.h"
 #include "NativeFontResourceDWrite.h"
 #include <d3d10_1.h>
 #include "HelpersD2D.h"
@@ -519,30 +520,50 @@ Factory::CreateNativeFontResource(uint8_
 #ifdef WIN32
       if (GetDWriteFactory()) {
         return NativeFontResourceDWrite::Create(aData, aSize,
                                                 /* aNeedsCairo = */ true);
       } else {
         return NativeFontResourceGDI::Create(aData, aSize,
                                              /* aNeedsCairo = */ true);
       }
-#elif XP_DARWIN
+#elif defined(XP_DARWIN)
       return NativeFontResourceMac::Create(aData, aSize);
+#elif defined(MOZ_WIDGET_GTK)
+      return NativeFontResourceFontconfig::Create(aData, aSize);
 #else
       gfxWarning() << "Unable to create cairo scaled font from truetype data";
       return nullptr;
 #endif
     }
   default:
     gfxWarning() << "Unable to create requested font resource from truetype data";
     return nullptr;
   }
 }
 
 already_AddRefed<ScaledFont>
+Factory::CreateScaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength, Float aSize)
+{
+  switch (aType) {
+#ifdef WIN32
+  case FontType::GDI:
+    return ScaledFontWin::CreateFromFontDescriptor(aData, aDataLength, aSize);
+#endif
+#ifdef MOZ_WIDGET_GTK
+  case FontType::FONTCONFIG:
+    return ScaledFontFontconfig::CreateFromFontDescriptor(aData, aDataLength, aSize);
+#endif
+  default:
+    gfxWarning() << "Invalid type specified for ScaledFont font descriptor";
+    return nullptr;
+  }
+}
+
+already_AddRefed<ScaledFont>
 Factory::CreateScaledFontWithCairo(const NativeFont& aNativeFont, 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, aSize);
--- a/gfx/2d/NativeFontResourceDWrite.cpp
+++ b/gfx/2d/NativeFontResourceDWrite.cpp
@@ -254,17 +254,18 @@ NativeFontResourceDWrite::Create(uint8_t
 
   RefPtr<NativeFontResourceDWrite> fontResource =
     new NativeFontResourceDWrite(factory, fontFile.forget(), faceType,
                                  numberOfFaces, aNeedsCairo);
   return fontResource.forget();
 }
 
 already_AddRefed<ScaledFont>
-NativeFontResourceDWrite::CreateScaledFont(uint32_t aIndex, Float aGlyphSize)
+NativeFontResourceDWrite::CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                                           const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
 {
   if (aIndex >= mNumberOfFaces) {
     gfxWarning() << "Font face index is too high for font resource.";
     return nullptr;
   }
 
   IDWriteFontFile *fontFile = mFontFile;
   RefPtr<IDWriteFontFace> fontFace;
--- a/gfx/2d/NativeFontResourceDWrite.h
+++ b/gfx/2d/NativeFontResourceDWrite.h
@@ -27,17 +27,18 @@ public:
    * @param aDataLength length of data.
    * @param aNeedsCairo whether the ScaledFont created needs a cairo scaled font
    * @return Referenced NativeFontResourceDWrite or nullptr if invalid.
    */
   static already_AddRefed<NativeFontResourceDWrite>
     Create(uint8_t *aFontData, uint32_t aDataLength, bool aNeedsCairo);
 
   already_AddRefed<ScaledFont>
-    CreateScaledFont(uint32_t aIndex, Float aGlyphSize) final;
+    CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final;
 
 private:
   NativeFontResourceDWrite(IDWriteFactory *aFactory,
                            already_AddRefed<IDWriteFontFile> aFontFile,
                            DWRITE_FONT_FACE_TYPE aFaceType,
                            uint32_t aNumberOfFaces, bool aNeedsCairo)
     : mFactory(aFactory), mFontFile(aFontFile), mFaceType(aFaceType)
     , mNumberOfFaces(aNumberOfFaces), mNeedsCairo(aNeedsCairo)
@@ -48,9 +49,9 @@ private:
   DWRITE_FONT_FACE_TYPE mFaceType;
   uint32_t mNumberOfFaces;
   bool mNeedsCairo;
 };
 
 } // gfx
 } // mozilla
 
-#endif // mozilla_gfx_NativeFontResourceDWrite_h
\ No newline at end of file
+#endif // mozilla_gfx_NativeFontResourceDWrite_h
new file mode 100644
--- /dev/null
+++ b/gfx/2d/NativeFontResourceFontconfig.cpp
@@ -0,0 +1,65 @@
+/* -*- 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 "Logging.h"
+
+namespace mozilla {
+namespace gfx {
+
+NativeFontResourceFontconfig::NativeFontResourceFontconfig(UniquePtr<uint8_t[]>&& aFontData, FT_Face aFace)
+  : mFontData(Move(aFontData)),
+    mFace(aFace)
+{
+}
+
+NativeFontResourceFontconfig::~NativeFontResourceFontconfig()
+{
+  if (mFace) {
+    FT_Done_Face(mFace);
+    mFace = nullptr;
+  }
+}
+
+already_AddRefed<NativeFontResourceFontconfig>
+NativeFontResourceFontconfig::Create(uint8_t *aFontData, uint32_t aDataLength)
+{
+  if (!aFontData || !aDataLength) {
+    return nullptr;
+  }
+  UniquePtr<uint8_t[]> fontData(new uint8_t[aDataLength]);
+  memcpy(fontData.get(), aFontData, aDataLength);
+
+  FT_Face face;
+  if (FT_New_Memory_Face(Factory::GetFTLibrary(), fontData.get(), aDataLength, 0, &face) != FT_Err_Ok) {
+    return nullptr;
+  }
+  if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != FT_Err_Ok) {
+    FT_Done_Face(face);
+    return nullptr;
+  }
+
+  RefPtr<NativeFontResourceFontconfig> resource =
+    new NativeFontResourceFontconfig(Move(fontData), face);
+  return resource.forget();
+}
+
+already_AddRefed<ScaledFont>
+NativeFontResourceFontconfig::CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                                               const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
+{
+  if (aInstanceDataLength < sizeof(ScaledFontFontconfig::InstanceData)) {
+    gfxWarning() << "Fontconfig scaled font instance data is truncated.";
+    return nullptr;
+  }
+  return ScaledFontFontconfig::CreateFromInstanceData(
+           *reinterpret_cast<const ScaledFontFontconfig::InstanceData*>(aInstanceData),
+           mFace, nullptr, 0, aGlyphSize);
+}
+
+} // gfx
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/2d/NativeFontResourceFontconfig.h
@@ -0,0 +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/. */
+
+#ifndef mozilla_gfx_NativeFontResourceFontconfig_h
+#define mozilla_gfx_NativeFontResourceFontconfig_h
+
+#include "2D.h"
+
+#include <cairo-ft.h>
+
+namespace mozilla {
+namespace gfx {
+
+class NativeFontResourceFontconfig final : public NativeFontResource
+{
+public:
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceFontconfig)
+
+  static already_AddRefed<NativeFontResourceFontconfig>
+    Create(uint8_t *aFontData, uint32_t aDataLength);
+
+  already_AddRefed<ScaledFont>
+    CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final;
+
+  ~NativeFontResourceFontconfig();
+
+private:
+  NativeFontResourceFontconfig(UniquePtr<uint8_t[]>&& aFontData, FT_Face aFace);
+
+  UniquePtr<uint8_t[]> mFontData;
+  FT_Face mFace;
+};
+
+} // gfx
+} // mozilla
+
+#endif // mozilla_gfx_NativeFontResourceFontconfig_h
--- a/gfx/2d/NativeFontResourceGDI.cpp
+++ b/gfx/2d/NativeFontResourceGDI.cpp
@@ -60,17 +60,18 @@ NativeFontResourceGDI::Create(uint8_t *a
 }
 
 NativeFontResourceGDI::~NativeFontResourceGDI()
 {
   ::RemoveFontMemResourceEx(mFontResourceHandle);
 }
 
 already_AddRefed<ScaledFont>
-NativeFontResourceGDI::CreateScaledFont(uint32_t aIndex, Float aGlyphSize)
+NativeFontResourceGDI::CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                                        const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
 {
   if (aIndex >= mFontNames.length()) {
     gfxWarning() << "Font index is too high for font resource.";
     return nullptr;
   }
 
   if (mFontNames[aIndex].empty()) {
     gfxWarning() << "Font name for index is empty.";
--- a/gfx/2d/NativeFontResourceGDI.h
+++ b/gfx/2d/NativeFontResourceGDI.h
@@ -31,17 +31,18 @@ public:
    * @return Referenced NativeFontResourceGDI or nullptr if invalid.
    */
   static already_AddRefed<NativeFontResourceGDI>
     Create(uint8_t *aFontData, uint32_t aDataLength, bool aNeedsCairo);
 
   ~NativeFontResourceGDI();
 
   already_AddRefed<ScaledFont>
-    CreateScaledFont(uint32_t aIndex, Float aGlyphSize) final;
+    CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final;
 
 private:
   NativeFontResourceGDI(HANDLE aFontResourceHandle,
                         Vector<mozilla::u16string>&& aFontNames,
                         bool aNeedsCairo)
     : mFontResourceHandle(aFontResourceHandle), mFontNames(Move(aFontNames))
     , mNeedsCairo(aNeedsCairo)
   {}
@@ -49,9 +50,9 @@ private:
   HANDLE mFontResourceHandle;
   Vector<mozilla::u16string> mFontNames;
   bool mNeedsCairo;
 };
 
 } // gfx
 } // mozilla
 
-#endif // mozilla_gfx_NativeFontResourceGDI_h
\ No newline at end of file
+#endif // mozilla_gfx_NativeFontResourceGDI_h
--- a/gfx/2d/NativeFontResourceMac.cpp
+++ b/gfx/2d/NativeFontResourceMac.cpp
@@ -45,17 +45,18 @@ NativeFontResourceMac::Create(uint8_t *a
   // passes ownership of fontRef to the NativeFontResourceMac instance
   RefPtr<NativeFontResourceMac> fontResource =
     new NativeFontResourceMac(fontRef);
 
   return fontResource.forget();
 }
 
 already_AddRefed<ScaledFont>
-NativeFontResourceMac::CreateScaledFont(uint32_t aIndex, Float aGlyphSize)
+NativeFontResourceMac::CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                                        const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
 {
   RefPtr<ScaledFontBase> scaledFont = new ScaledFontMac(mFontRef, aGlyphSize);
 
   if (!scaledFont->PopulateCairoScaledFont()) {
     gfxWarning() << "Unable to create cairo scaled Mac font.";
     return nullptr;
   }
 
--- a/gfx/2d/NativeFontResourceMac.h
+++ b/gfx/2d/NativeFontResourceMac.h
@@ -18,17 +18,18 @@ class NativeFontResourceMac final : publ
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceMac)
 
   static already_AddRefed<NativeFontResourceMac>
     Create(uint8_t *aFontData, uint32_t aDataLength);
 
   already_AddRefed<ScaledFont>
-    CreateScaledFont(uint32_t aIndex, Float aGlyphSize);
+    CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final;
 
   ~NativeFontResourceMac()
   {
     CFRelease(mFontRef);
   }
 
 private:
   explicit NativeFontResourceMac(CGFontRef aFontRef) : mFontRef(aFontRef) {}
--- a/gfx/2d/RecordedEvent.cpp
+++ b/gfx/2d/RecordedEvent.cpp
@@ -1581,42 +1581,37 @@ RecordedFontData::RecordedFontData(istre
 
 RecordedFontDescriptor::~RecordedFontDescriptor()
 {
 }
 
 bool
 RecordedFontDescriptor::PlayEvent(Translator *aTranslator) const
 {
-  MOZ_ASSERT(mType == FontType::GDI);
-
-  NativeFont nativeFont;
-  nativeFont.mType = (NativeFontType)mType;
-  nativeFont.mFont = (void*)&mData[0];
-
   RefPtr<ScaledFont> font =
-    Factory::CreateScaledFontForNativeFont(nativeFont, mFontSize);
-
-#ifdef USE_CAIRO_SCALED_FONT
-  static_cast<ScaledFontBase*>(font.get())->PopulateCairoScaledFont();
-#endif
+    Factory::CreateScaledFontFromFontDescriptor(mType, mData.data(), mData.size(), mFontSize);
+  if (!font) {
+    gfxDevCrash(LogReason::InvalidFont) <<
+      "Failed creating ScaledFont of type " << int(mType) << " from font descriptor";
+    return false;
+  }
 
   aTranslator->AddScaledFont(mRefPtr, font);
   return true;
 }
 
 void
 RecordedFontDescriptor::RecordToStream(std::ostream &aStream) const
 {
   MOZ_ASSERT(mHasDesc);
   WriteElement(aStream, mType);
   WriteElement(aStream, mFontSize);
   WriteElement(aStream, mRefPtr);
   WriteElement(aStream, (size_t)mData.size());
-  aStream.write((char*)&mData[0], mData.size());
+  aStream.write((char*)mData.data(), mData.size());
 }
 
 void
 RecordedFontDescriptor::OutputSimpleEventInfo(stringstream &aStringStream) const
 {
   aStringStream << "[" << mRefPtr << "] Font Descriptor";
 }
 
@@ -1632,56 +1627,70 @@ RecordedFontDescriptor::RecordedFontDesc
 {
   ReadElement(aStream, mType);
   ReadElement(aStream, mFontSize);
   ReadElement(aStream, mRefPtr);
 
   size_t size;
   ReadElement(aStream, size);
   mData.resize(size);
-  aStream.read((char*)&mData[0], size);
+  aStream.read((char*)mData.data(), size);
 }
 
 bool
 RecordedScaledFontCreation::PlayEvent(Translator *aTranslator) const
 {
   NativeFontResource *fontResource = aTranslator->LookupNativeFontResource(mFontDataKey);
   if (!fontResource) {
     gfxDevCrash(LogReason::NativeFontResourceNotFound) <<
       "NativeFontResource lookup failed for key |" << hexa(mFontDataKey) << "|.";
     return false;
   }
 
-  RefPtr<ScaledFont> scaledFont = fontResource->CreateScaledFont(mIndex, mGlyphSize);
+  RefPtr<ScaledFont> scaledFont =
+    fontResource->CreateScaledFont(mIndex, mGlyphSize, mInstanceData.data(), mInstanceData.size());
   aTranslator->AddScaledFont(mRefPtr, scaledFont);
   return true;
 }
 
 void
 RecordedScaledFontCreation::RecordToStream(std::ostream &aStream) const
 {
   WriteElement(aStream, mRefPtr);
   WriteElement(aStream, mFontDataKey);
   WriteElement(aStream, mIndex);
   WriteElement(aStream, mGlyphSize);
+  WriteElement(aStream, (size_t)mInstanceData.size());
+  aStream.write((char*)mInstanceData.data(), mInstanceData.size());
 }
 
 void
 RecordedScaledFontCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
 {
   aStringStream << "[" << mRefPtr << "] ScaledFont Created";
 }
 
+void
+RecordedScaledFontCreation::SetFontInstanceData(const uint8_t *aData, uint32_t aSize)
+{
+  mInstanceData.assign(aData, aData + aSize);
+}
+
 RecordedScaledFontCreation::RecordedScaledFontCreation(istream &aStream)
   : RecordedEvent(SCALEDFONTCREATION)
 {
   ReadElement(aStream, mRefPtr);
   ReadElement(aStream, mFontDataKey);
   ReadElement(aStream, mIndex);
   ReadElement(aStream, mGlyphSize);
+
+  size_t size;
+  ReadElement(aStream, size);
+  mInstanceData.resize(size);
+  aStream.read((char*)mInstanceData.data(), size);
 }
 
 bool
 RecordedScaledFontDestruction::PlayEvent(Translator *aTranslator) const
 {
   aTranslator->RemoveScaledFont(mRefPtr);
   return true;
 }
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -19,17 +19,17 @@ struct PathOp;
 class PathRecording;
 
 const uint32_t kMagicInt = 0xc001feed;
 
 // A change in major revision means a change in event binary format, causing
 // loss of backwards compatibility. Old streams will not work in a player
 // using a newer major revision. And new streams will not work in a player
 // using an older major revision.
-const uint16_t kMajorRevision = 5;
+const uint16_t kMajorRevision = 6;
 // A change in minor revision means additions of new events. New streams will
 // not play in older players.
 const uint16_t kMinorRevision = 0;
 
 struct ReferencePtr
 {
   ReferencePtr()
     : mLongPtr(0)
@@ -1042,25 +1042,25 @@ public:
   bool GetFontDetails(RecordedFontDetails& fontDetails);
 
 private:
   friend class RecordedEvent;
 
   uint8_t *mData;
   RecordedFontDetails mFontDetails;
 
-  bool mGetFontFileDataSucceeded = false;
+  bool mGetFontFileDataSucceeded;
 
   MOZ_IMPLICIT RecordedFontData(std::istream &aStream);
 };
 
 class RecordedFontDescriptor : public RecordedEvent {
 public:
 
-  static void FontDescCb(const uint8_t *aData, uint32_t aSize,
+  static void FontDescCb(const uint8_t* aData, uint32_t aSize,
                          Float aFontSize, void* aBaton)
   {
     auto recordedFontDesc = static_cast<RecordedFontDescriptor*>(aBaton);
     recordedFontDesc->SetFontDescriptor(aData, aSize, aFontSize);
   }
 
   explicit RecordedFontDescriptor(ScaledFont* aScaledFont)
     : RecordedEvent(FONTDESC)
@@ -1095,39 +1095,51 @@ private:
   ReferencePtr mRefPtr;
 
   MOZ_IMPLICIT RecordedFontDescriptor(std::istream &aStream);
 };
 
 class RecordedScaledFontCreation : public RecordedEvent {
 public:
 
-  RecordedScaledFontCreation(ReferencePtr aRefPtr,
+  static void FontInstanceDataProc(const uint8_t* aData, uint32_t aSize, void* aBaton)
+  {
+    auto recordedScaledFontCreation = static_cast<RecordedScaledFontCreation*>(aBaton);
+    recordedScaledFontCreation->SetFontInstanceData(aData, aSize);
+  }
+
+  RecordedScaledFontCreation(ScaledFont* aScaledFont,
                              RecordedFontDetails aFontDetails)
-    : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aRefPtr)
+    : RecordedEvent(SCALEDFONTCREATION)
+    , mRefPtr(aScaledFont)
     , mFontDataKey(aFontDetails.fontDataKey)
-    , mGlyphSize(aFontDetails.glyphSize) , mIndex(aFontDetails.index)
+    , mGlyphSize(aFontDetails.glyphSize)
+    , mIndex(aFontDetails.index)
   {
+    aScaledFont->GetFontInstanceData(FontInstanceDataProc, this);
   }
 
   virtual bool PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "ScaledFont Creation"; }
   virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 
+  void SetFontInstanceData(const uint8_t *aData, uint32_t aSize);
+
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
   uint64_t mFontDataKey;
   Float mGlyphSize;
   uint32_t mIndex;
+  std::vector<uint8_t> mInstanceData;
 
   MOZ_IMPLICIT RecordedScaledFontCreation(std::istream &aStream);
 };
 
 class RecordedScaledFontDestruction : public RecordedEvent {
 public:
   MOZ_IMPLICIT RecordedScaledFontDestruction(ReferencePtr aRefPtr)
     : RecordedEvent(SCALEDFONTDESTRUCTION), mRefPtr(aRefPtr)
--- a/gfx/2d/ScaledFontFontconfig.cpp
+++ b/gfx/2d/ScaledFontFontconfig.cpp
@@ -5,16 +5,20 @@
 
 #include "ScaledFontFontconfig.h"
 #include "Logging.h"
 
 #ifdef USE_SKIA
 #include "skia/include/ports/SkTypeface_cairo.h"
 #endif
 
+#include FT_TRUETYPE_TABLES_H
+
+#include <fontconfig/fcfreetype.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
 ScaledFontFontconfig::ScaledFontFontconfig(cairo_scaled_font_t* aScaledFont,
@@ -38,10 +42,321 @@ SkTypeface* ScaledFontFontconfig::GetSkT
   if (!mTypeface) {
     mTypeface = SkCreateTypefaceFromCairoFTFontWithFontconfig(mScaledFont, mPattern);
   }
 
   return mTypeface;
 }
 #endif
 
+bool
+ScaledFontFontconfig::GetFontFileData(FontFileDataOutput aDataCallback, void* aBaton)
+{
+  bool success = false;
+  // Lock the Cairo scaled font to force it to resolve the Fontconfig pattern to an FT_Face.
+  if (FT_Face face = cairo_ft_scaled_font_lock_face(GetCairoScaledFont())) {
+    FT_ULong length = 0;
+    // Request the SFNT file. This may not always succeed for all font types.
+    if (FT_Load_Sfnt_Table(face, 0, 0, nullptr, &length) == FT_Err_Ok) {
+      uint8_t* fontData = new uint8_t[length];
+      if (FT_Load_Sfnt_Table(face, 0, 0, fontData, &length) == FT_Err_Ok) {
+        aDataCallback(fontData, length, 0, mSize, aBaton);
+        success = true;
+      }
+      delete[] fontData;
+    }
+    cairo_ft_scaled_font_unlock_face(GetCairoScaledFont());
+  }
+  return success;
+}
+
+ScaledFontFontconfig::InstanceData::InstanceData(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern)
+  : mFlags(0)
+  , mHintStyle(FC_HINT_NONE)
+  , mSubpixelOrder(FC_RGBA_UNKNOWN)
+  , mLcdFilter(FC_LCD_LEGACY)
+{
+  // Record relevant Fontconfig properties into instance data.
+  FcBool autohint;
+  if (FcPatternGetBool(aPattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) {
+    mFlags |= AUTOHINT;
+  }
+  FcBool bitmap;
+  if (FcPatternGetBool(aPattern, FC_EMBEDDED_BITMAP, 0, &bitmap) == FcResultMatch && bitmap) {
+    mFlags |= EMBEDDED_BITMAP;
+  }
+  FcBool embolden;
+  if (FcPatternGetBool(aPattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) {
+    mFlags |= EMBOLDEN;
+  }
+  FcBool vertical;
+  if (FcPatternGetBool(aPattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) {
+    mFlags |= VERTICAL_LAYOUT;
+  }
+
+  FcBool antialias;
+  if (FcPatternGetBool(aPattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch || antialias) {
+    mFlags |= ANTIALIAS;
+
+    // Only record subpixel order and lcd filtering if antialiasing is enabled.
+    int rgba;
+    if (FcPatternGetInteger(aPattern, FC_RGBA, 0, &rgba) == FcResultMatch) {
+      mSubpixelOrder = rgba;
+    }
+    int filter;
+    if (FcPatternGetInteger(aPattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
+      mLcdFilter = filter;
+    }
+  }
+
+  cairo_font_options_t* fontOptions = cairo_font_options_create();
+  cairo_scaled_font_get_font_options(aScaledFont, fontOptions);
+  // For printer fonts, Cairo hint metrics and hinting will be disabled.
+  // For other fonts, allow hint metrics and hinting.
+  if (cairo_font_options_get_hint_metrics(fontOptions) != CAIRO_HINT_METRICS_OFF) {
+    mFlags |= HINT_METRICS;
+
+    FcBool hinting;
+    if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting) {
+      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);
+  }
+  if (mFlags & EMBEDDED_BITMAP) {
+    FcPatternAddBool(aPattern, FC_EMBEDDED_BITMAP, FcTrue);
+  }
+  if (mFlags & EMBOLDEN) {
+    FcPatternAddBool(aPattern, FC_EMBOLDEN, FcTrue);
+  }
+  if (mFlags & VERTICAL_LAYOUT) {
+    FcPatternAddBool(aPattern, FC_VERTICAL_LAYOUT, FcTrue);
+  }
+
+  if (mFlags & ANTIALIAS) {
+    FcPatternAddBool(aPattern, FC_ANTIALIAS, FcTrue);
+    if (mSubpixelOrder != FC_RGBA_UNKNOWN) {
+      FcPatternAddInteger(aPattern, FC_RGBA, mSubpixelOrder);
+    }
+    if (mLcdFilter != FC_LCD_LEGACY) {
+      FcPatternAddInteger(aPattern, FC_LCD_FILTER, mLcdFilter);
+    }
+  } else {
+    FcPatternAddBool(aPattern, FC_ANTIALIAS, FcFalse);
+  }
+
+  if (mHintStyle) {
+    FcPatternAddBool(aPattern, FC_HINTING, FcTrue);
+    FcPatternAddInteger(aPattern, FC_HINT_STYLE, mHintStyle);
+  } else {
+    FcPatternAddBool(aPattern, FC_HINTING, FcFalse);
+  }
+}
+
+void
+ScaledFontFontconfig::InstanceData::SetupFontOptions(cairo_font_options_t* aFontOptions) const
+{
+  // Try to build a sane initial set of Cairo font options based on the Fontconfig
+  // pattern.
+  if (mFlags & HINT_METRICS) {
+    // For regular (non-printer) fonts, enable hint metrics as well as hinting
+    // and (possibly subpixel) antialiasing.
+    cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_ON);
+
+    cairo_hint_style_t hinting;
+    switch (mHintStyle) {
+    case FC_HINT_NONE:
+      hinting = CAIRO_HINT_STYLE_NONE;
+      break;
+    case FC_HINT_SLIGHT:
+      hinting = CAIRO_HINT_STYLE_SLIGHT;
+      break;
+    case FC_HINT_MEDIUM:
+    default:
+      hinting = CAIRO_HINT_STYLE_MEDIUM;
+      break;
+    case FC_HINT_FULL:
+      hinting = CAIRO_HINT_STYLE_FULL;
+      break;
+    }
+    cairo_font_options_set_hint_style(aFontOptions, hinting);
+
+    if (mFlags & ANTIALIAS) {
+      cairo_subpixel_order_t subpixel = CAIRO_SUBPIXEL_ORDER_DEFAULT;
+      switch (mSubpixelOrder) {
+      case FC_RGBA_RGB:
+        subpixel = CAIRO_SUBPIXEL_ORDER_RGB;
+        break;
+      case FC_RGBA_BGR:
+        subpixel = CAIRO_SUBPIXEL_ORDER_BGR;
+        break;
+      case FC_RGBA_VRGB:
+        subpixel = CAIRO_SUBPIXEL_ORDER_VRGB;
+        break;
+      case FC_RGBA_VBGR:
+        subpixel = CAIRO_SUBPIXEL_ORDER_VBGR;
+        break;
+      default:
+        break;
+      }
+      if (subpixel != CAIRO_SUBPIXEL_ORDER_DEFAULT) {
+        cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
+        cairo_font_options_set_subpixel_order(aFontOptions, subpixel);
+      } else {
+        cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_GRAY);
+      }
+    } else {
+      cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_NONE);
+    }
+  } else {
+    // For printer fonts, disable hint metrics and hinting. Don't allow subpixel
+    // 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);
+}
+
+bool
+ScaledFontFontconfig::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
+{
+  InstanceData instance(GetCairoScaledFont(), mPattern);
+
+  aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance), aBaton);
+  return true;
+}
+
+bool
+ScaledFontFontconfig::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton)
+{
+  // Check if the Fontconfig pattern uses a font file and index to specify which
+  // font to load. If so, record these as a font descriptor along with any instance
+  // data required to rebuild a scaled font from it.
+  FcChar8* pathname = nullptr;
+  if (FcPatternGetString(mPattern, FC_FILE, 0, &pathname) != FcResultMatch) {
+    return false;
+  }
+  int index = 0;
+  FcPatternGetInteger(mPattern, FC_INDEX, 0, &index);
+  if (index < 0) {
+    return false;
+  }
+
+  size_t pathLength = strlen(reinterpret_cast<char*>(pathname)) + 1;
+  size_t dataLength = sizeof(FontDescriptor) + pathLength;
+  uint8_t* data = new uint8_t[dataLength];
+  FontDescriptor* desc = reinterpret_cast<FontDescriptor*>(data);
+  desc->mPathLength = pathLength;
+  desc->mIndex = index;
+  desc->mInstanceData = InstanceData(GetCairoScaledFont(), mPattern);
+  memcpy(data + sizeof(FontDescriptor), pathname, pathLength);
+
+  aCb(data, dataLength, mSize, aBaton);
+  return true;
+}
+
+already_AddRefed<ScaledFont>
+ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData,
+                                             FT_Face aFace, const char* aPathname, uint32_t aIndex,
+                                             Float aSize)
+
+{
+  FcPattern* pattern = FcPatternCreate();
+  if (!pattern) {
+    gfxWarning() << "Failing initializing Fontconfig pattern for scaled font";
+    return nullptr;
+  }
+  if (aFace) {
+    FcPatternAddFTFace(pattern, FC_FT_FACE, aFace);
+  } else {
+    FcPatternAddString(pattern, FC_FILE, reinterpret_cast<const FcChar8*>(aPathname));
+    FcPatternAddInteger(pattern, FC_INDEX, aIndex);
+  }
+  FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aSize);
+  aInstanceData.SetupPattern(pattern);
+
+  cairo_font_face_t* font = cairo_ft_font_face_create_for_pattern(pattern);
+  if (cairo_font_face_status(font) != CAIRO_STATUS_SUCCESS) {
+    gfxWarning() << "Failed creating Cairo font face for Fontconfig pattern";
+    FcPatternDestroy(pattern);
+    return nullptr;
+  }
+
+  cairo_matrix_t sizeMatrix;
+  aInstanceData.SetupFontMatrix(&sizeMatrix);
+
+  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 =
+    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";
+    FcPatternDestroy(pattern);
+    return nullptr;
+  }
+
+  RefPtr<ScaledFontFontconfig> scaledFont =
+    new ScaledFontFontconfig(cairoScaledFont, pattern, aSize);
+
+  FcPatternDestroy(pattern);
+
+  return scaledFont.forget();
+}
+
+already_AddRefed<ScaledFont>
+ScaledFontFontconfig::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize)
+{
+  if (aDataLength < sizeof(FontDescriptor)) {
+    gfxWarning() << "Fontconfig font descriptor is truncated.";
+    return nullptr;
+  }
+  const FontDescriptor* desc = reinterpret_cast<const FontDescriptor*>(aData);
+  if (desc->mPathLength < 1 ||
+      desc->mPathLength > aDataLength - sizeof(FontDescriptor)) {
+    gfxWarning() << "Pathname in Fontconfig font descriptor has invalid size.";
+    return nullptr;
+  }
+  const char* pathname = reinterpret_cast<const char*>(aData + sizeof(FontDescriptor));
+  if (pathname[desc->mPathLength - 1] != '\0') {
+    gfxWarning() << "Pathname in Fontconfig font descriptor is not terminated.";
+    return nullptr;
+  }
+  return CreateFromInstanceData(desc->mInstanceData, nullptr, pathname, desc->mIndex, aSize);
+}
+
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/2d/ScaledFontFontconfig.h
+++ b/gfx/2d/ScaledFontFontconfig.h
@@ -3,35 +3,84 @@
  * 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_SCALEDFONTFONTCONFIG_H_
 #define MOZILLA_GFX_SCALEDFONTFONTCONFIG_H_
 
 #include "ScaledFontBase.h"
 
-#include <fontconfig/fontconfig.h>
-#include <cairo.h>
+#include <cairo-ft.h>
 
 namespace mozilla {
 namespace gfx {
 
+class NativeFontResourceFontconfig;
+
 class ScaledFontFontconfig : public ScaledFontBase
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontFontconfig)
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontFontconfig, override)
   ScaledFontFontconfig(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern, Float aSize);
   ~ScaledFontFontconfig();
 
-  virtual FontType GetType() const { return FontType::FONTCONFIG; }
+  FontType GetType() const override { return FontType::FONTCONFIG; }
 
 #ifdef USE_SKIA
-  virtual SkTypeface* GetSkTypeface();
+  SkTypeface* GetSkTypeface() override;
 #endif
 
+  bool GetFontFileData(FontFileDataOutput aDataCallback, void* aBaton) override;
+
+  bool GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) override;
+
+  bool GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) override;
+
+  static already_AddRefed<ScaledFont>
+    CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize);
+
 private:
+  friend class NativeFontResourceFontconfig;
+
+  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;
+  };
+
+  struct FontDescriptor
+  {
+    uint32_t mPathLength;
+    uint32_t mIndex;
+    InstanceData mInstanceData;
+  };
+
+  static already_AddRefed<ScaledFont>
+    CreateFromInstanceData(const InstanceData& aInstanceData,
+                           FT_Face aFace, const char* aPathname, uint32_t aIndex,
+                           Float aSize);
+
   FcPattern* mPattern;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_SCALEDFONTFONTCONFIG_H_ */
--- a/gfx/2d/ScaledFontWin.cpp
+++ b/gfx/2d/ScaledFontWin.cpp
@@ -83,16 +83,33 @@ ScaledFontWin::GetFontFileData(FontFileD
 
 bool
 ScaledFontWin::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton)
 {
   aCb(reinterpret_cast<uint8_t*>(&mLogFont), sizeof(mLogFont), mSize, aBaton);
   return true;
 }
 
+already_AddRefed<ScaledFont>
+ScaledFontWin::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize)
+{
+  NativeFont nativeFont;
+  nativeFont.mType = NativeFontType::GDI_FONT_FACE;
+  nativeFont.mFont = (void*)aData;
+
+  RefPtr<ScaledFont> font =
+    Factory::CreateScaledFontForNativeFont(nativeFont, aSize);
+
+#ifdef USE_CAIRO_SCALED_FONT
+  static_cast<ScaledFontBase*>(font.get())->PopulateCairoScaledFont();
+#endif
+
+  return font.forget();
+}
+
 AntialiasMode
 ScaledFontWin::GetDefaultAAMode()
 {
   return GetSystemDefaultAAMode();
 }
 
 #ifdef USE_SKIA
 SkTypeface* ScaledFontWin::GetSkTypeface()
--- a/gfx/2d/ScaledFontWin.h
+++ b/gfx/2d/ScaledFontWin.h
@@ -18,16 +18,20 @@ public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontWin)
   ScaledFontWin(LOGFONT* aFont, Float aSize);
 
   virtual FontType GetType() const { return FontType::GDI; }
 
   bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) override;
 
   virtual bool GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) override;
+
+  static already_AddRefed<ScaledFont>
+    CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize);
+
   virtual AntialiasMode GetDefaultAAMode() override;
 
 #ifdef USE_SKIA
   virtual SkTypeface* GetSkTypeface();
 #endif
 
 protected:
 #ifdef USE_CAIRO_SCALED_FONT
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -85,16 +85,17 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wi
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'windows':
     SOURCES += [
         'JobScheduler_posix.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
     SOURCES += [
+        'NativeFontResourceFontconfig.cpp',
         'ScaledFontFontconfig.cpp',
     ]
 
 if CONFIG['MOZ_ENABLE_SKIA']:
     UNIFIED_SOURCES += [
         'convolver.cpp',
     ]
     SOURCES += [