Bug 1355931 - move font serialization from ScaledFont to UnscaledFont. r=jrmuizel
authorLee Salzman <lsalzman@mozilla.com>
Fri, 14 Apr 2017 14:11:00 -0400
changeset 353282 176ab833ca364efd64968171d4e62341dfcf8858
parent 353281 18d45aa984d6eb1bc0ce210e1c105a6b9e573b5f
child 353283 9ff13e2532a468213e7203455693060d496de96b
push id31661
push userarchaeopteryx@coole-files.de
push dateSat, 15 Apr 2017 18:00:16 +0000
treeherdermozilla-central@d65b53cf8fd9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1355931
milestone55.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 1355931 - move font serialization from ScaledFont to UnscaledFont. r=jrmuizel MozReview-Commit-ID: 3d1XMoe2BKj
gfx/2d/2D.h
gfx/2d/DrawTargetRecording.cpp
gfx/2d/Factory.cpp
gfx/2d/Logging.h
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/ScaledFontDWrite.cpp
gfx/2d/ScaledFontDWrite.h
gfx/2d/ScaledFontFontconfig.cpp
gfx/2d/ScaledFontFontconfig.h
gfx/2d/ScaledFontMac.cpp
gfx/2d/ScaledFontMac.h
gfx/2d/ScaledFontWin.cpp
gfx/2d/ScaledFontWin.h
gfx/2d/UnscaledFontDWrite.h
gfx/2d/UnscaledFontFreeType.cpp
gfx/2d/UnscaledFontFreeType.h
gfx/2d/UnscaledFontGDI.h
gfx/2d/UnscaledFontMac.h
gfx/2d/moz.build
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/thebes/gfxMacFont.cpp
layout/printing/PrintTranslator.h
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -58,16 +58,17 @@ struct gfxFontStyle;
 
 struct CGContext;
 typedef struct CGContext *CGContextRef;
 
 namespace mozilla {
 
 namespace gfx {
 
+class ScaledFont;
 class SourceSurface;
 class DataSourceSurface;
 class DrawTarget;
 class DrawEventRecorder;
 class FilterNode;
 class LogForwarder;
 
 struct NativeSurface {
@@ -706,16 +707,35 @@ public:
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(UnscaledFont)
 
   virtual ~UnscaledFont();
 
   virtual FontType GetType() const = 0;
 
   static uint32_t DeletionCounter() { return sDeletionCounter; }
 
+  typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex,
+                                     void *aBaton);
+  typedef void (*FontInstanceDataOutput)(const uint8_t* aData, uint32_t aLength, void* aBaton);
+  typedef void (*FontDescriptorOutput)(const uint8_t* aData, uint32_t aLength, void* aBaton);
+
+  virtual bool GetFontFileData(FontFileDataOutput, void *) { return false; }
+
+  virtual bool GetFontInstanceData(FontInstanceDataOutput, void *) { return false; }
+
+  virtual bool GetFontDescriptor(FontDescriptorOutput, void *) { return false; }
+
+  virtual already_AddRefed<ScaledFont>
+    CreateScaledFont(Float aGlyphSize,
+                     const uint8_t* aInstanceData,
+                     uint32_t aInstanceDataLength)
+  {
+    return nullptr;
+  }
+
 protected:
   UnscaledFont() {}
 
 private:
   static uint32_t sDeletionCounter;
 };
 
 /** This class is an abstraction of a backend/platform specific font object
@@ -723,27 +743,16 @@ private:
  * the font used for the drawing call.
  */
 class ScaledFont : public external::AtomicRefCounted<ScaledFont>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
   virtual ~ScaledFont() {}
 
-  typedef struct {
-    uint32_t mTag;
-    Float    mValue;
-  } VariationSetting;
-
-  typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize,
-                                     uint32_t aVariationCount, const VariationSetting* aVariations,
-                                     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 Float GetSize() const = 0;
   virtual AntialiasMode GetDefaultAAMode();
 
   /** This allows getting a path that describes the outline of a set of glyphs.
    * A target is passed in so that the guarantee is made the returned path
    * can be used with any DrawTarget that has the same backend as the one
    * passed in.
@@ -756,22 +765,25 @@ public:
    * others.
    */
   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; }
+  struct VariationSetting {
+    uint32_t mTag;
+    float    mValue;
+  };
+
+  typedef void (*FontInstanceDataOutput)(const uint8_t* aData, uint32_t aLength, void* aBaton);
 
   virtual bool GetFontInstanceData(FontInstanceDataOutput, void *) { return false; }
 
-  virtual bool GetFontDescriptor(FontDescriptorOutput, void *) { return false; }
-
   virtual bool CanSerialize() { return false; }
 
   void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
     mUserData.Add(key, userData, destroy);
   }
   void *GetUserData(UserDataKey *key) {
     return mUserData.Get(key);
   }
@@ -792,30 +804,29 @@ protected:
  * ScaledFonts.
  */
 class NativeFontResource : public RefCounted<NativeFontResource>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResource)
 
   /**
-   * Creates a ScaledFont using the font corresponding to the index and
-   * the given glyph size.
+   * Creates a UnscaledFont using the font corresponding to the index.
    *
    * @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.
+   * @return an already_addrefed UnscaledFont, containing nullptr if failed.
    */
-  virtual already_AddRefed<ScaledFont>
-    CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
-                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) = 0;
+  virtual already_AddRefed<UnscaledFont>
+    CreateUnscaledFont(uint32_t aIndex,
+                       const uint8_t* aInstanceData,
+                       uint32_t aInstanceDataLength) = 0;
 
-  virtual ~NativeFontResource() {};
+  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
  * parameters.
  */
@@ -1464,33 +1475,28 @@ public:
                                       const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize);
 #endif
 
   /**
    * This creates a NativeFontResource from TrueType data.
    *
    * @param aData Pointer to the data
    * @param aSize Size of the TrueType data
-   * @param aVariationCount Number of VariationSetting records provided.
-   * @param aVariations Pointer to VariationSetting records.
    * @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,
-                             uint32_t aVariationCount,
-                             const ScaledFont::VariationSetting* aVariations,
-                             FontType aType);
+    CreateNativeFontResource(uint8_t *aData, uint32_t aSize, FontType aType);
 
   /**
-   * This creates a scaled font of the given type based on font descriptor
+   * This creates an unscaled 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);
+  static already_AddRefed<UnscaledFont>
+    CreateUnscaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength);
 
   /**
    * 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,
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -383,42 +383,49 @@ void
 DrawTargetRecording::FillGlyphs(ScaledFont *aFont,
                                 const GlyphBuffer &aBuffer,
                                 const Pattern &aPattern,
                                 const DrawOptions &aOptions,
                                 const GlyphRenderingOptions *aRenderingOptions)
 {
   EnsurePatternDependenciesStored(aPattern);
 
-  if (!aFont->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()))) {
-    RecordedFontData fontData(aFont);
-    RecordedFontDetails fontDetails;
-    if (fontData.GetFontDetails(fontDetails)) {
-      // Try to serialise the whole font, just in case this is a web font that
-      // is not present on the system.
-      if (!mRecorder->HasStoredFontData(fontDetails.fontDataKey)) {
-        mRecorder->RecordEvent(fontData);
-        mRecorder->AddStoredFontData(fontDetails.fontDataKey);
+  UserDataKey* userDataKey = reinterpret_cast<UserDataKey*>(mRecorder.get());
+  if (!aFont->GetUserData(userDataKey)) {
+    UnscaledFont* unscaledFont = aFont->GetUnscaledFont();
+    if (!mRecorder->HasStoredObject(unscaledFont)) {
+      RecordedFontData fontData(unscaledFont);
+      RecordedFontDetails fontDetails;
+      if (fontData.GetFontDetails(fontDetails)) {
+        // Try to serialise the whole font, just in case this is a web font that
+        // is not present on the system.
+        if (!mRecorder->HasStoredFontData(fontDetails.fontDataKey)) {
+          mRecorder->RecordEvent(fontData);
+          mRecorder->AddStoredFontData(fontDetails.fontDataKey);
+        }
+        mRecorder->RecordEvent(RecordedUnscaledFontCreation(unscaledFont, fontDetails));
+      } else {
+        // If that fails, record just the font description and try to load it from
+        // the system on the other side.
+        RecordedFontDescriptor fontDesc(unscaledFont);
+        if (fontDesc.IsValid()) {
+          mRecorder->RecordEvent(fontDesc);
+        } else {
+          gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise UnscaledFont";
+        }
       }
-      mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, fontDetails));
-    } else {
-      // If that fails, record just the font description and try to load it from
-      // the system on the other side.
-      RecordedFontDescriptor fontDesc(aFont);
-      if (fontDesc.IsValid()) {
-        mRecorder->RecordEvent(fontDesc);
-      } else {
-        gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise ScaledFont";
-      }
+      mRecorder->AddStoredObject(unscaledFont);
     }
+
+    mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, unscaledFont));
+
     RecordingFontUserData *userData = new RecordingFontUserData;
     userData->refPtr = aFont;
     userData->recorder = mRecorder;
-    aFont->AddUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()), userData, 
-                       &RecordingFontUserDataDestroyFunc);
+    aFont->AddUserData(userDataKey, userData, &RecordingFontUserDataDestroyFunc);
   }
 
   mRecorder->RecordEvent(RecordedFillGlyphs(this, aFont, aPattern, aOptions, aBuffer.mGlyphs, aBuffer.mNumGlyphs));
   mFinalDT->FillGlyphs(aFont, aBuffer, *AdjustedPattern(aPattern), aOptions, aRenderingOptions);
 }
 
 void
 DrawTargetRecording::Mask(const Pattern &aSource,
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -19,26 +19,28 @@
 #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 "UnscaledFontFreeType.h"
 #endif
 
 #ifdef WIN32
 #include "DrawTargetD2D1.h"
 #include "ScaledFontDWrite.h"
 #include "NativeFontResourceDWrite.h"
 #include <d3d10_1.h>
 #include "HelpersD2D.h"
@@ -500,20 +502,17 @@ Factory::CreateScaledFontForNativeFont(c
 #endif
   default:
     gfxWarning() << "Invalid native font type specified.";
     return nullptr;
   }
 }
 
 already_AddRefed<NativeFontResource>
-Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize,
-                                  uint32_t aVariationCount,
-                                  const ScaledFont::VariationSetting* aVariations,
-                                  FontType aType)
+Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize, FontType aType)
 {
   switch (aType) {
 #ifdef WIN32
   case FontType::DWRITE:
     {
       return NativeFontResourceDWrite::Create(aData, aSize,
                                               /* aNeedsCairo = */ false);
     }
@@ -523,49 +522,47 @@ Factory::CreateNativeFontResource(uint8_
   case FontType::SKIA:
 #endif
     {
 #ifdef WIN32
       if (GetDWriteFactory()) {
         return NativeFontResourceDWrite::Create(aData, aSize,
                                                 /* aNeedsCairo = */ true);
       } else {
-        return NativeFontResourceGDI::Create(aData, aSize,
-                                             /* aNeedsCairo = */ true);
+        return NativeFontResourceGDI::Create(aData, aSize);
       }
 #elif defined(XP_DARWIN)
-      return NativeFontResourceMac::Create(aData, aSize,
-                                           aVariationCount, aVariations);
+      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)
+already_AddRefed<UnscaledFont>
+Factory::CreateUnscaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength)
 {
   switch (aType) {
 #ifdef WIN32
   case FontType::GDI:
-    return ScaledFontWin::CreateFromFontDescriptor(aData, aDataLength, aSize);
+    return UnscaledFontGDI::CreateFromFontDescriptor(aData, aDataLength);
 #endif
 #ifdef MOZ_WIDGET_GTK
   case FontType::FONTCONFIG:
-    return ScaledFontFontconfig::CreateFromFontDescriptor(aData, aDataLength, aSize);
+    return UnscaledFontFontconfig::CreateFromFontDescriptor(aData, aDataLength);
 #endif
   default:
-    gfxWarning() << "Invalid type specified for ScaledFont font descriptor";
+    gfxWarning() << "Invalid type specified for UnscaledFont font descriptor";
     return nullptr;
   }
 }
 
 already_AddRefed<ScaledFont>
 Factory::CreateScaledFontWithCairo(const NativeFont& aNativeFont,
                                    const RefPtr<UnscaledFont>& aUnscaledFont,
                                    Float aSize,
--- a/gfx/2d/Logging.h
+++ b/gfx/2d/Logging.h
@@ -126,16 +126,17 @@ enum class LogReason : int {
   AsyncTransactionTimeout, // 30
   TextureCreation,
   InvalidCacheSurface,
   AlphaWithBasicClient,
   UnbalancedClipStack,
   ProcessingError,
   InvalidDrawTarget,
   NativeFontResourceNotFound,
+  UnscaledFontNotFound,
   // End
   MustBeLessThanThis = 101,
 };
 
 struct BasicLogger
 {
   // For efficiency, this method exists and copies the logic of the
   // OutputMessage below.  If making any changes here, also make it
--- a/gfx/2d/NativeFontResourceDWrite.cpp
+++ b/gfx/2d/NativeFontResourceDWrite.cpp
@@ -1,15 +1,16 @@
 /* -*- 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 "NativeFontResourceDWrite.h"
+#include "UnscaledFontDWrite.h"
 
 #include <unordered_map>
 
 #include "DrawTargetD2D1.h"
 #include "Logging.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
@@ -253,36 +254,36 @@ 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,
-                                           const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
+already_AddRefed<UnscaledFont>
+NativeFontResourceDWrite::CreateUnscaledFont(uint32_t aIndex,
+                                             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;
   if (FAILED(mFactory->CreateFontFace(mFaceType, 1, &fontFile, aIndex,
     DWRITE_FONT_SIMULATIONS_NONE, getter_AddRefs(fontFace)))) {
     gfxWarning() << "Failed to create font face from font file data.";
     return nullptr;
   }
 
-  RefPtr<ScaledFontBase> scaledFont = new ScaledFontDWrite(fontFace, nullptr, aGlyphSize);
-  if (mNeedsCairo && !scaledFont->PopulateCairoScaledFont()) {
-    gfxWarning() << "Unable to create cairo scaled font DWrite font.";
-    return nullptr;
-  }
+  RefPtr<UnscaledFont> unscaledFont =
+    new UnscaledFontDWrite(fontFace,
+                           DWRITE_FONT_SIMULATIONS_NONE,
+                           mNeedsCairo);
 
-  return scaledFont.forget();
+  return unscaledFont.forget();
 }
 
 } // gfx
 } // mozilla
--- a/gfx/2d/NativeFontResourceDWrite.h
+++ b/gfx/2d/NativeFontResourceDWrite.h
@@ -26,19 +26,20 @@ public:
    * @param aFontData the SFNT data.
    * @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,
-                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final;
+  already_AddRefed<UnscaledFont>
+    CreateUnscaledFont(uint32_t aIndex,
+                       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)
--- a/gfx/2d/NativeFontResourceFontconfig.cpp
+++ b/gfx/2d/NativeFontResourceFontconfig.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "UnscaledFontFreeType.h"
 #include "Logging.h"
 
 namespace mozilla {
 namespace gfx {
 
 NativeFontResourceFontconfig::NativeFontResourceFontconfig(UniquePtr<uint8_t[]>&& aFontData, FT_Face aFace)
   : mFontData(Move(aFontData)),
     mFace(aFace)
@@ -43,23 +44,18 @@ NativeFontResourceFontconfig::Create(uin
     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)
+already_AddRefed<UnscaledFont>
+NativeFontResourceFontconfig::CreateUnscaledFont(uint32_t aIndex,
+                                                 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);
+  RefPtr<UnscaledFont> unscaledFont = new UnscaledFontFontconfig(mFace);
+  return unscaledFont.forget();
 }
 
 } // gfx
 } // mozilla
--- a/gfx/2d/NativeFontResourceFontconfig.h
+++ b/gfx/2d/NativeFontResourceFontconfig.h
@@ -18,19 +18,19 @@ 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;
+  already_AddRefed<UnscaledFont>
+    CreateUnscaledFont(uint32_t aIndex,
+                       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;
--- a/gfx/2d/NativeFontResourceGDI.cpp
+++ b/gfx/2d/NativeFontResourceGDI.cpp
@@ -4,60 +4,53 @@
  * 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 "NativeFontResourceGDI.h"
 
 #include "Logging.h"
 #include "mozilla/RefPtr.h"
 #include "ScaledFontWin.h"
+#include "UnscaledFontGDI.h"
 
 namespace mozilla {
 namespace gfx {
 
 /* static */
 already_AddRefed<NativeFontResourceGDI>
-NativeFontResourceGDI::Create(uint8_t *aFontData, uint32_t aDataLength,
-                              bool aNeedsCairo)
+NativeFontResourceGDI::Create(uint8_t *aFontData, uint32_t aDataLength)
 {
   DWORD numberOfFontsAdded;
   HANDLE fontResourceHandle = ::AddFontMemResourceEx(aFontData, aDataLength,
                                                      0, &numberOfFontsAdded);
   if (!fontResourceHandle) {
     gfxWarning() << "Failed to add memory font resource.";
     return nullptr;
   }
 
   RefPtr<NativeFontResourceGDI> fontResouce =
-    new NativeFontResourceGDI(fontResourceHandle, aNeedsCairo);
+    new NativeFontResourceGDI(fontResourceHandle);
 
   return fontResouce.forget();
 }
 
 NativeFontResourceGDI::~NativeFontResourceGDI()
 {
   ::RemoveFontMemResourceEx(mFontResourceHandle);
 }
 
-already_AddRefed<ScaledFont>
-NativeFontResourceGDI::CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
-                                        const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
+already_AddRefed<UnscaledFont>
+NativeFontResourceGDI::CreateUnscaledFont(uint32_t aIndex,
+                                          const uint8_t* aInstanceData,
+                                          uint32_t aInstanceDataLength)
 {
   if (aInstanceDataLength < sizeof(LOGFONT)) {
-    gfxWarning() << "GDI scaled font instance data is truncated.";
+    gfxWarning() << "GDI unscaled font instance data is truncated.";
     return nullptr;
   }
 
   const LOGFONT* logFont = reinterpret_cast<const LOGFONT*>(aInstanceData);
-
-  // Constructor for ScaledFontWin dereferences and copies the LOGFONT, so we
-  // are safe to pass this reference.
-  RefPtr<ScaledFontBase> scaledFont = new ScaledFontWin(logFont, nullptr, aGlyphSize);
-  if (mNeedsCairo && !scaledFont->PopulateCairoScaledFont()) {
-    gfxWarning() << "Unable to create cairo scaled font GDI font.";
-    return nullptr;
-  }
-
-  return scaledFont.forget();
+  RefPtr<UnscaledFont> unscaledFont = new UnscaledFontGDI(*logFont);
+  return unscaledFont.forget();
 }
 
 } // gfx
 } // mozilla
--- a/gfx/2d/NativeFontResourceGDI.h
+++ b/gfx/2d/NativeFontResourceGDI.h
@@ -21,35 +21,32 @@ class NativeFontResourceGDI final : publ
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceGDI)
   /**
    * Creates a NativeFontResourceGDI if data is valid. Note aFontData will be
    * copied if required and so can be released after calling.
    *
    * @param aFontData the SFNT data.
    * @param aDataLength length of data.
-   * @param aNeedsCairo whether the ScaledFont created need a cairo scaled font
    * @return Referenced NativeFontResourceGDI or nullptr if invalid.
    */
   static already_AddRefed<NativeFontResourceGDI>
-    Create(uint8_t *aFontData, uint32_t aDataLength, bool aNeedsCairo);
+    Create(uint8_t *aFontData, uint32_t aDataLength);
 
   ~NativeFontResourceGDI();
 
-  already_AddRefed<ScaledFont>
-    CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
-                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final;
+  already_AddRefed<UnscaledFont>
+    CreateUnscaledFont(uint32_t aIndex,
+                       const uint8_t* aInstanceData,
+                       uint32_t aInstanceDataLength) final;
 
 private:
-  NativeFontResourceGDI(HANDLE aFontResourceHandle,
-                        bool aNeedsCairo)
+  explicit NativeFontResourceGDI(HANDLE aFontResourceHandle)
     : mFontResourceHandle(aFontResourceHandle)
-    , mNeedsCairo(aNeedsCairo)
   {}
 
   HANDLE mFontResourceHandle;
-  bool mNeedsCairo;
 };
 
 } // gfx
 } // mozilla
 
 #endif // mozilla_gfx_NativeFontResourceGDI_h
--- a/gfx/2d/NativeFontResourceMac.cpp
+++ b/gfx/2d/NativeFontResourceMac.cpp
@@ -1,171 +1,32 @@
 /* -*- 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 "NativeFontResourceMac.h"
+#include "UnscaledFontMac.h"
 #include "Types.h"
 
 #include "mozilla/RefPtr.h"
 
 #ifdef MOZ_WIDGET_UIKIT
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
 #include "nsCocoaFeatures.h"
 
-// Simple helper class to automatically release a CFObject when it goes out
-// of scope.
-template<class T>
-class AutoRelease
-{
-public:
-  explicit AutoRelease(T aObject)
-    : mObject(aObject)
-  {
-  }
-
-  ~AutoRelease()
-  {
-    if (mObject) {
-      CFRelease(mObject);
-    }
-  }
-
-  operator T()
-  {
-    return mObject;
-  }
-
-  T forget()
-  {
-    T obj = mObject;
-    mObject = nullptr;
-    return obj;
-  }
-
-private:
-  T mObject;
-};
-
-// This is essentially identical to the similarly-named helper function
-// in gfx/thebes/gfxMacFont.cpp. Maybe we should put it somewhere that
-// can be shared by both Moz2d and Thebes callers?
-static CFDictionaryRef
-CreateVariationDictionaryOrNull(CGFontRef aCGFont, uint32_t aVariationCount,
-  const mozilla::gfx::ScaledFont::VariationSetting* aVariations)
-{
-  // Avoid calling potentially buggy variation APIs on pre-Sierra macOS
-  // versions (see bug 1331683)
-  if (!nsCocoaFeatures::OnSierraOrLater()) {
-    return nullptr;
-  }
-
-  AutoRelease<CTFontRef>
-    ctFont(CTFontCreateWithGraphicsFont(aCGFont, 0, nullptr, nullptr));
-  AutoRelease<CFArrayRef> axes(CTFontCopyVariationAxes(ctFont));
-  if (!axes) {
-    return nullptr;
-  }
-
-  CFIndex axisCount = CFArrayGetCount(axes);
-  AutoRelease<CFMutableDictionaryRef>
-    dict(CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
-                                   &kCFTypeDictionaryKeyCallBacks,
-                                   &kCFTypeDictionaryValueCallBacks));
-
-  // Number of variation settings passed in the aVariations parameter.
-  // This will typically be a very low value, so we just linear-search them.
-  bool allDefaultValues = true;
-
-  for (CFIndex i = 0; i < axisCount; ++i) {
-    // We sanity-check the axis info found in the CTFont, and bail out
-    // (returning null) if it doesn't have the expected types.
-    CFTypeRef axisInfo = CFArrayGetValueAtIndex(axes, i);
-    if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
-      return nullptr;
-    }
-    CFDictionaryRef axis = static_cast<CFDictionaryRef>(axisInfo);
-
-    CFTypeRef axisTag =
-        CFDictionaryGetValue(axis, kCTFontVariationAxisIdentifierKey);
-    if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) {
-      return nullptr;
-    }
-    int64_t tagLong;
-    if (!CFNumberGetValue(static_cast<CFNumberRef>(axisTag),
-                          kCFNumberSInt64Type, &tagLong)) {
-      return nullptr;
-    }
-
-    CFTypeRef axisName =
-      CFDictionaryGetValue(axis, kCTFontVariationAxisNameKey);
-    if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
-      return nullptr;
-    }
-
-    // Clamp axis values to the supported range.
-    CFTypeRef min = CFDictionaryGetValue(axis, kCTFontVariationAxisMinimumValueKey);
-    CFTypeRef max = CFDictionaryGetValue(axis, kCTFontVariationAxisMaximumValueKey);
-    CFTypeRef def = CFDictionaryGetValue(axis, kCTFontVariationAxisDefaultValueKey);
-    if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
-        !max || CFGetTypeID(max) != CFNumberGetTypeID() ||
-        !def || CFGetTypeID(def) != CFNumberGetTypeID()) {
-      return nullptr;
-    }
-    double minDouble;
-    double maxDouble;
-    double defDouble;
-    if (!CFNumberGetValue(static_cast<CFNumberRef>(min), kCFNumberDoubleType,
-                          &minDouble) ||
-        !CFNumberGetValue(static_cast<CFNumberRef>(max), kCFNumberDoubleType,
-                          &maxDouble) ||
-        !CFNumberGetValue(static_cast<CFNumberRef>(def), kCFNumberDoubleType,
-                          &defDouble)) {
-      return nullptr;
-    }
-
-    double value = defDouble;
-    for (uint32_t j = 0; j < aVariationCount; ++j) {
-      if (aVariations[j].mTag == tagLong) {
-        value = std::min(std::max<double>(aVariations[j].mValue,
-                                          minDouble),
-                         maxDouble);
-        if (value != defDouble) {
-          allDefaultValues = false;
-        }
-        break;
-      }
-    }
-    AutoRelease<CFNumberRef> valueNumber(CFNumberCreate(kCFAllocatorDefault,
-                                                        kCFNumberDoubleType,
-                                                        &value));
-    CFDictionaryAddValue(dict, axisName, valueNumber);
-  }
-
-  if (allDefaultValues) {
-    // We didn't actually set any non-default values, so throw away the
-    // variations dictionary and just use the default rendering.
-    return nullptr;
-  }
-
-  return dict.forget();
-}
-
 namespace mozilla {
 namespace gfx {
 
 /* static */
 already_AddRefed<NativeFontResourceMac>
-NativeFontResourceMac::Create(uint8_t *aFontData, uint32_t aDataLength,
-                              uint32_t aVariationCount,
-                              const ScaledFont::VariationSetting* aVariations)
+NativeFontResourceMac::Create(uint8_t *aFontData, uint32_t aDataLength)
 {
   // copy font data
   CFDataRef data = CFDataCreate(kCFAllocatorDefault, aFontData, aDataLength);
   if (!data) {
     return nullptr;
   }
 
   // create a provider
@@ -179,45 +40,27 @@ NativeFontResourceMac::Create(uint8_t *a
 
   // release our reference, font will keep it alive as long as needed
   CGDataProviderRelease(provider);
 
   if (!fontRef) {
     return nullptr;
   }
 
-  if (aVariationCount > 0) {
-    MOZ_ASSERT(aVariations);
-    AutoRelease<CFDictionaryRef>
-      varDict(CreateVariationDictionaryOrNull(fontRef, aVariationCount,
-                                              aVariations));
-    if (varDict) {
-      CGFontRef varFont = CGFontCreateCopyWithVariations(fontRef, varDict);
-      if (varFont) {
-        CFRelease(fontRef);
-        fontRef = varFont;
-      }
-    }
-  }
-
   // 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,
-                                        const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
+already_AddRefed<UnscaledFont>
+NativeFontResourceMac::CreateUnscaledFont(uint32_t aIndex,
+                                          const uint8_t* aInstanceData,
+                                          uint32_t aInstanceDataLength)
 {
-  RefPtr<ScaledFontBase> scaledFont = new ScaledFontMac(mFontRef, nullptr, aGlyphSize);
+  RefPtr<UnscaledFont> unscaledFont = new UnscaledFontMac(mFontRef);
 
-  if (!scaledFont->PopulateCairoScaledFont()) {
-    gfxWarning() << "Unable to create cairo scaled Mac font.";
-    return nullptr;
-  }
-
-  return scaledFont.forget();
+  return unscaledFont.forget();
 }
 
 } // gfx
 } // mozilla
--- a/gfx/2d/NativeFontResourceMac.h
+++ b/gfx/2d/NativeFontResourceMac.h
@@ -15,23 +15,22 @@ namespace mozilla {
 namespace gfx {
 
 class NativeFontResourceMac final : public NativeFontResource
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceMac)
 
   static already_AddRefed<NativeFontResourceMac>
-    Create(uint8_t *aFontData, uint32_t aDataLength,
-           uint32_t aVariationCount,
-           const ScaledFont::VariationSetting* aVariations);
+    Create(uint8_t *aFontData, uint32_t aDataLength);
 
-  already_AddRefed<ScaledFont>
-    CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
-                     const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final;
+  already_AddRefed<UnscaledFont>
+    CreateUnscaledFont(uint32_t aIndex,
+                       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
@@ -79,16 +79,18 @@ RecordedEvent::LoadEventFromStream(std::
     LOAD_EVENT_TYPE(MASKSURFACE, RecordedMaskSurface);
     LOAD_EVENT_TYPE(FILTERNODESETATTRIBUTE, RecordedFilterNodeSetAttribute);
     LOAD_EVENT_TYPE(FILTERNODESETINPUT, RecordedFilterNodeSetInput);
     LOAD_EVENT_TYPE(CREATESIMILARDRAWTARGET, RecordedCreateSimilarDrawTarget);
     LOAD_EVENT_TYPE(FONTDATA, RecordedFontData);
     LOAD_EVENT_TYPE(FONTDESC, RecordedFontDescriptor);
     LOAD_EVENT_TYPE(PUSHLAYER, RecordedPushLayer);
     LOAD_EVENT_TYPE(POPLAYER, RecordedPopLayer);
+    LOAD_EVENT_TYPE(UNSCALEDFONTCREATION, RecordedUnscaledFontCreation);
+    LOAD_EVENT_TYPE(UNSCALEDFONTDESTRUCTION, RecordedUnscaledFontDestruction);
   default:
     return nullptr;
   }
 }
 
 string
 RecordedEvent::GetEventName(EventType aType)
 {
@@ -162,16 +164,20 @@ RecordedEvent::GetEventName(EventType aT
   case FONTDATA:
     return "FontData";
   case FONTDESC:
     return "FontDescriptor";
   case PUSHLAYER:
     return "PushLayer";
   case POPLAYER:
     return "PopLayer";
+  case UNSCALEDFONTCREATION:
+    return "UnscaledFontCreation";
+  case UNSCALEDFONTDESTRUCTION:
+    return "UnscaledFontDestruction";
   default:
     return "Unknown";
   }
 }
 
 void
 RecordedEvent::RecordPatternData(std::ostream &aStream, const PatternStorage &aPattern) const
 {
@@ -1517,25 +1523,23 @@ void
 RecordedSnapshot::OutputSimpleEventInfo(stringstream &aStringStream) const
 {
   aStringStream << "[" << mRefPtr << "] Snapshot Created (DT: " << mDT << ")";
 }
 
 RecordedFontData::~RecordedFontData()
 {
   delete[] mData;
-  delete[] mVariations;
 }
 
 bool
 RecordedFontData::PlayEvent(Translator *aTranslator) const
 {
   RefPtr<NativeFontResource> fontResource =
     Factory::CreateNativeFontResource(mData, mFontDetails.size,
-                                      mFontDetails.variationCount, mVariations,
                                       aTranslator->GetDesiredFontType());
   if (!fontResource) {
     return false;
   }
 
   aTranslator->AddNativeFontResource(mFontDetails.fontDataKey, fontResource);
   return true;
 }
@@ -1543,157 +1547,208 @@ RecordedFontData::PlayEvent(Translator *
 void
 RecordedFontData::RecordToStream(std::ostream &aStream) const
 {
   MOZ_ASSERT(mGetFontFileDataSucceeded);
 
   WriteElement(aStream, mFontDetails.fontDataKey);
   WriteElement(aStream, mFontDetails.size);
   aStream.write((const char*)mData, mFontDetails.size);
-  WriteElement(aStream, mFontDetails.variationCount);
-  aStream.write((const char*)mVariations, mFontDetails.variationCount * sizeof(ScaledFont::VariationSetting));
 }
 
 void
 RecordedFontData::OutputSimpleEventInfo(stringstream &aStringStream) const
 {
   aStringStream << "Font Data of size " << mFontDetails.size;
 }
 
 void
-RecordedFontData::SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex,
-                              Float aGlyphSize, uint32_t aVariationCount,
-                              const ScaledFont::VariationSetting* aVariations)
+RecordedFontData::SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex)
 {
   mData = new uint8_t[aSize];
   memcpy(mData, aData, aSize);
-  uint32_t varDataSize = aVariationCount * sizeof(ScaledFont::VariationSetting);
   mFontDetails.fontDataKey =
-    SFNTData::GetUniqueKey(aData, aSize, varDataSize, aVariations);
+    SFNTData::GetUniqueKey(aData, aSize, 0, nullptr);
   mFontDetails.size = aSize;
   mFontDetails.index = aIndex;
-  mFontDetails.glyphSize = aGlyphSize;
-  mFontDetails.variationCount = aVariationCount;
-  if (aVariationCount > 0) {
-    mVariations = new ScaledFont::VariationSetting[aVariationCount];
-    memcpy(mVariations, aVariations, varDataSize);
-  }
 }
 
 bool
 RecordedFontData::GetFontDetails(RecordedFontDetails& fontDetails)
 {
   if (!mGetFontFileDataSucceeded) {
     return false;
   }
 
   fontDetails.fontDataKey = mFontDetails.fontDataKey;
   fontDetails.size = mFontDetails.size;
-  fontDetails.glyphSize = mFontDetails.glyphSize;
   fontDetails.index = mFontDetails.index;
-  fontDetails.variationCount = mFontDetails.variationCount;
   return true;
 }
 
 RecordedFontData::RecordedFontData(istream &aStream)
   : RecordedEvent(FONTDATA)
   , mData(nullptr)
-  , mVariations(nullptr)
 {
   ReadElement(aStream, mFontDetails.fontDataKey);
   ReadElement(aStream, mFontDetails.size);
   mData = new uint8_t[mFontDetails.size];
   aStream.read((char*)mData, mFontDetails.size);
-  ReadElement(aStream, mFontDetails.variationCount);
-  if (mFontDetails.variationCount > 0) {
-    mVariations = new ScaledFont::VariationSetting[mFontDetails.variationCount];
-    aStream.read((char*)mVariations, mFontDetails.variationCount * sizeof(ScaledFont::VariationSetting));
-  } else {
-    mVariations = nullptr;
-  }
 }
 
 RecordedFontDescriptor::~RecordedFontDescriptor()
 {
 }
 
 bool
 RecordedFontDescriptor::PlayEvent(Translator *aTranslator) const
 {
-  RefPtr<ScaledFont> font =
-    Factory::CreateScaledFontFromFontDescriptor(mType, mData.data(), mData.size(), mFontSize);
+  RefPtr<UnscaledFont> font =
+    Factory::CreateUnscaledFontFromFontDescriptor(mType, mData.data(), mData.size());
   if (!font) {
     gfxDevCrash(LogReason::InvalidFont) <<
-      "Failed creating ScaledFont of type " << int(mType) << " from font descriptor";
+      "Failed creating UnscaledFont of type " << int(mType) << " from font descriptor";
     return false;
   }
 
-  aTranslator->AddScaledFont(mRefPtr, font);
+  aTranslator->AddUnscaledFont(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.data(), mData.size());
 }
 
 void
 RecordedFontDescriptor::OutputSimpleEventInfo(stringstream &aStringStream) const
 {
   aStringStream << "[" << mRefPtr << "] Font Descriptor";
 }
 
 void
-RecordedFontDescriptor::SetFontDescriptor(const uint8_t* aData, uint32_t aSize, Float aFontSize)
+RecordedFontDescriptor::SetFontDescriptor(const uint8_t* aData, uint32_t aSize)
 {
   mData.assign(aData, aData + aSize);
-  mFontSize = aFontSize;
 }
 
 RecordedFontDescriptor::RecordedFontDescriptor(istream &aStream)
-  : RecordedEvent(FONTDATA)
+  : RecordedEvent(FONTDESC)
 {
   ReadElement(aStream, mType);
-  ReadElement(aStream, mFontSize);
   ReadElement(aStream, mRefPtr);
 
   size_t size;
   ReadElement(aStream, size);
   mData.resize(size);
   aStream.read((char*)mData.data(), size);
 }
 
 bool
-RecordedScaledFontCreation::PlayEvent(Translator *aTranslator) const
+RecordedUnscaledFontCreation::PlayEvent(Translator *aTranslator) const
 {
   NativeFontResource *fontResource = aTranslator->LookupNativeFontResource(mFontDataKey);
   if (!fontResource) {
     gfxDevCrash(LogReason::NativeFontResourceNotFound) <<
       "NativeFontResource lookup failed for key |" << hexa(mFontDataKey) << "|.";
     return false;
   }
 
+  RefPtr<UnscaledFont> unscaledFont =
+    fontResource->CreateUnscaledFont(mIndex, mInstanceData.data(), mInstanceData.size());
+  aTranslator->AddUnscaledFont(mRefPtr, unscaledFont);
+  return true;
+}
+
+void
+RecordedUnscaledFontCreation::RecordToStream(std::ostream &aStream) const
+{
+  WriteElement(aStream, mRefPtr);
+  WriteElement(aStream, mFontDataKey);
+  WriteElement(aStream, mIndex);
+  WriteElement(aStream, (size_t)mInstanceData.size());
+  aStream.write((char*)mInstanceData.data(), mInstanceData.size());
+}
+
+void
+RecordedUnscaledFontCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+  aStringStream << "[" << mRefPtr << "] UnscaledFont Created";
+}
+
+void
+RecordedUnscaledFontCreation::SetFontInstanceData(const uint8_t *aData, uint32_t aSize)
+{
+  mInstanceData.assign(aData, aData + aSize);
+}
+
+RecordedUnscaledFontCreation::RecordedUnscaledFontCreation(istream &aStream)
+  : RecordedEvent(UNSCALEDFONTCREATION)
+{
+  ReadElement(aStream, mRefPtr);
+  ReadElement(aStream, mFontDataKey);
+  ReadElement(aStream, mIndex);
+
+  size_t size;
+  ReadElement(aStream, size);
+  mInstanceData.resize(size);
+  aStream.read((char*)mInstanceData.data(), size);
+}
+
+bool
+RecordedUnscaledFontDestruction::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->RemoveUnscaledFont(mRefPtr);
+  return true;
+}
+
+void
+RecordedUnscaledFontDestruction::RecordToStream(ostream &aStream) const
+{
+  WriteElement(aStream, mRefPtr);
+}
+
+RecordedUnscaledFontDestruction::RecordedUnscaledFontDestruction(istream &aStream)
+  : RecordedEvent(UNSCALEDFONTDESTRUCTION)
+{
+  ReadElement(aStream, mRefPtr);
+}
+
+void
+RecordedUnscaledFontDestruction::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+  aStringStream << "[" << mRefPtr << "] UnscaledFont Destroyed";
+}
+
+bool
+RecordedScaledFontCreation::PlayEvent(Translator *aTranslator) const
+{
+  UnscaledFont* unscaledFont = aTranslator->LookupUnscaledFont(mUnscaledFont);
+  if (!unscaledFont) {
+    gfxDevCrash(LogReason::UnscaledFontNotFound) <<
+      "UnscaledFont lookup failed for key |" << hexa(mUnscaledFont) << "|.";
+    return false;
+  }
+
   RefPtr<ScaledFont> scaledFont =
-    fontResource->CreateScaledFont(mIndex, mGlyphSize, mInstanceData.data(), mInstanceData.size());
+    unscaledFont->CreateScaledFont(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, mUnscaledFont);
   WriteElement(aStream, mGlyphSize);
   WriteElement(aStream, (size_t)mInstanceData.size());
   aStream.write((char*)mInstanceData.data(), mInstanceData.size());
 }
 
 void
 RecordedScaledFontCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
 {
@@ -1705,18 +1760,17 @@ RecordedScaledFontCreation::SetFontInsta
 {
   mInstanceData.assign(aData, aData + aSize);
 }
 
 RecordedScaledFontCreation::RecordedScaledFontCreation(istream &aStream)
   : RecordedEvent(SCALEDFONTCREATION)
 {
   ReadElement(aStream, mRefPtr);
-  ReadElement(aStream, mFontDataKey);
-  ReadElement(aStream, mIndex);
+  ReadElement(aStream, mUnscaledFont);
   ReadElement(aStream, mGlyphSize);
 
   size_t size;
   ReadElement(aStream, size);
   mInstanceData.resize(size);
   aStream.read((char*)mInstanceData.data(), size);
 }
 
--- 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 = 8;
+const uint16_t kMajorRevision = 9;
 // 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)
@@ -62,18 +62,16 @@ struct ReferencePtr
   uint64_t mLongPtr;
 };
 
 struct RecordedFontDetails
 {
   uint64_t fontDataKey;
   uint32_t size;
   uint32_t index;
-  uint32_t variationCount;
-  Float glyphSize;
 };
 
 // Used by the Azure drawing debugger (player2d)
 inline std::string StringFromPtr(ReferencePtr aPtr)
 {
   std::stringstream stream;
   stream << aPtr;
   return stream.str();
@@ -85,29 +83,32 @@ public:
   virtual ~Translator() {}
 
   virtual DrawTarget *LookupDrawTarget(ReferencePtr aRefPtr) = 0;
   virtual Path *LookupPath(ReferencePtr aRefPtr) = 0;
   virtual SourceSurface *LookupSourceSurface(ReferencePtr aRefPtr) = 0;
   virtual FilterNode *LookupFilterNode(ReferencePtr aRefPtr) = 0;
   virtual GradientStops *LookupGradientStops(ReferencePtr aRefPtr) = 0;
   virtual ScaledFont *LookupScaledFont(ReferencePtr aRefPtr) = 0;
+  virtual UnscaledFont* LookupUnscaledFont(ReferencePtr aRefPtr) = 0;
   virtual NativeFontResource *LookupNativeFontResource(uint64_t aKey) = 0;
   virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget *aDT) = 0;
   virtual void RemoveDrawTarget(ReferencePtr aRefPtr) = 0;
   virtual void AddPath(ReferencePtr aRefPtr, Path *aPath) = 0;
   virtual void RemovePath(ReferencePtr aRefPtr) = 0;
   virtual void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface *aPath) = 0;
   virtual void RemoveSourceSurface(ReferencePtr aRefPtr) = 0;
   virtual void AddFilterNode(mozilla::gfx::ReferencePtr aRefPtr, FilterNode *aSurface) = 0;
   virtual void RemoveFilterNode(mozilla::gfx::ReferencePtr aRefPtr) = 0;
   virtual void AddGradientStops(ReferencePtr aRefPtr, GradientStops *aPath) = 0;
   virtual void RemoveGradientStops(ReferencePtr aRefPtr) = 0;
   virtual void AddScaledFont(ReferencePtr aRefPtr, ScaledFont *aScaledFont) = 0;
   virtual void RemoveScaledFont(ReferencePtr aRefPtr) = 0;
+  virtual void AddUnscaledFont(ReferencePtr aRefPtr, UnscaledFont* aUnscaledFont) = 0;
+  virtual void RemoveUnscaledFont(ReferencePtr aRefPtr) = 0;
   virtual void AddNativeFontResource(uint64_t aKey,
                                      NativeFontResource *aNativeFontResource) = 0;
 
   virtual already_AddRefed<DrawTarget> CreateDrawTarget(ReferencePtr aRefPtr,
                                                         const IntSize &aSize,
                                                         SurfaceFormat aFormat);
   virtual DrawTarget *GetReferenceDrawTarget() = 0;
   virtual FontType GetDesiredFontType() = 0;
@@ -192,16 +193,18 @@ public:
     DRAWFILTER,
     FILTERNODESETATTRIBUTE,
     FILTERNODESETINPUT,
     CREATESIMILARDRAWTARGET,
     FONTDATA,
     FONTDESC,
     PUSHLAYER,
     POPLAYER,
+    UNSCALEDFONTCREATION,
+    UNSCALEDFONTDESTRUCTION,
   };
   static const uint32_t kTotalEventTypes = RecordedEvent::FILTERNODESETINPUT + 1;
 
   virtual ~RecordedEvent() {}
 
   static std::string GetEventName(EventType aType);
 
   /**
@@ -1010,76 +1013,71 @@ private:
 
   MOZ_IMPLICIT RecordedSnapshot(std::istream &aStream);
 };
 
 class RecordedFontData : public RecordedEvent {
 public:
 
   static void FontDataProc(const uint8_t *aData, uint32_t aSize,
-                           uint32_t aIndex, Float aGlyphSize,
-                           uint32_t aVariationCount,
-                           const ScaledFont::VariationSetting* aVariations,
-                           void* aBaton)
+                           uint32_t aIndex, void* aBaton)
   {
     auto recordedFontData = static_cast<RecordedFontData*>(aBaton);
-    recordedFontData->SetFontData(aData, aSize, aIndex, aGlyphSize,
-                                  aVariationCount, aVariations);
+    recordedFontData->SetFontData(aData, aSize, aIndex);
   }
 
-  explicit RecordedFontData(ScaledFont *aScaledFont)
-    : RecordedEvent(FONTDATA), mData(nullptr), mVariations(nullptr)
+  explicit RecordedFontData(UnscaledFont *aUnscaledFont)
+    : RecordedEvent(FONTDATA), mData(nullptr)
   {
-    mGetFontFileDataSucceeded = aScaledFont->GetFontFileData(&FontDataProc, this);
+    mGetFontFileDataSucceeded = aUnscaledFont->GetFontFileData(&FontDataProc, this);
   }
 
   ~RecordedFontData();
 
+  bool IsValid() const { return mGetFontFileDataSucceeded; }
+
   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 "Font Data"; }
   virtual ReferencePtr GetObjectRef() const { return nullptr; };
 
-  void SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex,
-                   Float aGlyphSize, uint32_t aVariationCount,
-                   const ScaledFont::VariationSetting* aVariations);
+  void SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex);
 
   bool GetFontDetails(RecordedFontDetails& fontDetails);
 
 private:
   friend class RecordedEvent;
 
   uint8_t* mData;
-  ScaledFont::VariationSetting* mVariations;
   RecordedFontDetails mFontDetails;
 
   bool mGetFontFileDataSucceeded;
 
   MOZ_IMPLICIT RecordedFontData(std::istream &aStream);
 };
 
 class RecordedFontDescriptor : public RecordedEvent {
 public:
 
   static void FontDescCb(const uint8_t* aData, uint32_t aSize,
-                         Float aFontSize, void* aBaton)
+                         void* aBaton)
   {
     auto recordedFontDesc = static_cast<RecordedFontDescriptor*>(aBaton);
-    recordedFontDesc->SetFontDescriptor(aData, aSize, aFontSize);
+    recordedFontDesc->SetFontDescriptor(aData, aSize);
   }
 
-  explicit RecordedFontDescriptor(ScaledFont* aScaledFont)
+  explicit RecordedFontDescriptor(UnscaledFont* aUnscaledFont)
     : RecordedEvent(FONTDESC)
-    , mType(aScaledFont->GetType())
-    , mRefPtr(aScaledFont)
+    , mType(aUnscaledFont->GetType())
+    , mRefPtr(aUnscaledFont)
   {
-    mHasDesc = aScaledFont->GetFontDescriptor(FontDescCb, this);
+    mHasDesc = aUnscaledFont->GetFontDescriptor(FontDescCb, this);
   }
 
   ~RecordedFontDescriptor();
 
   bool IsValid() const { return mHasDesc; }
 
   virtual bool PlayEvent(Translator *aTranslator) const;
 
@@ -1087,44 +1085,102 @@ public:
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
 
   virtual std::string GetName() const { return "Font Desc"; }
   virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 
 private:
   friend class RecordedEvent;
 
-  void SetFontDescriptor(const uint8_t* aData, uint32_t aSize, Float aFontSize);
+  void SetFontDescriptor(const uint8_t* aData, uint32_t aSize);
 
   bool mHasDesc;
 
   FontType mType;
-  Float mFontSize;
   std::vector<uint8_t> mData;
   ReferencePtr mRefPtr;
 
   MOZ_IMPLICIT RecordedFontDescriptor(std::istream &aStream);
 };
 
+class RecordedUnscaledFontCreation : public RecordedEvent {
+public:
+  static void FontInstanceDataProc(const uint8_t* aData, uint32_t aSize, void* aBaton)
+  {
+    auto recordedUnscaledFontCreation = static_cast<RecordedUnscaledFontCreation*>(aBaton);
+    recordedUnscaledFontCreation->SetFontInstanceData(aData, aSize);
+  }
+
+  RecordedUnscaledFontCreation(UnscaledFont* aUnscaledFont,
+                               RecordedFontDetails aFontDetails)
+    : RecordedEvent(UNSCALEDFONTCREATION)
+    , mRefPtr(aUnscaledFont)
+    , mFontDataKey(aFontDetails.fontDataKey)
+    , mIndex(aFontDetails.index)
+  {
+    aUnscaledFont->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 "UnscaledFont 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;
+  uint32_t mIndex;
+  std::vector<uint8_t> mInstanceData;
+
+  MOZ_IMPLICIT RecordedUnscaledFontCreation(std::istream &aStream);
+};
+
+class RecordedUnscaledFontDestruction : public RecordedEvent {
+public:
+  MOZ_IMPLICIT RecordedUnscaledFontDestruction(ReferencePtr aRefPtr)
+    : RecordedEvent(UNSCALEDFONTDESTRUCTION), mRefPtr(aRefPtr)
+  {}
+
+  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 "UnscaledFont Destruction"; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
+private:
+  friend class RecordedEvent;
+
+  ReferencePtr mRefPtr;
+
+  MOZ_IMPLICIT RecordedUnscaledFontDestruction(std::istream &aStream);
+};
+
 class RecordedScaledFontCreation : public RecordedEvent {
 public:
 
   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)
+                             UnscaledFont* aUnscaledFont)
     : RecordedEvent(SCALEDFONTCREATION)
     , mRefPtr(aScaledFont)
-    , mFontDataKey(aFontDetails.fontDataKey)
-    , mGlyphSize(aFontDetails.glyphSize)
-    , mIndex(aFontDetails.index)
+    , mUnscaledFont(aUnscaledFont)
+    , mGlyphSize(aScaledFont->GetSize())
   {
     aScaledFont->GetFontInstanceData(FontInstanceDataProc, this);
   }
 
   virtual bool PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
@@ -1133,19 +1189,18 @@ public:
   virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 
   void SetFontInstanceData(const uint8_t *aData, uint32_t aSize);
 
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
-  uint64_t mFontDataKey;
+  ReferencePtr mUnscaledFont;
   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)
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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 "DrawTargetD2D1.h"
 #include "ScaledFontDWrite.h"
+#include "UnscaledFontDWrite.h"
 #include "PathD2D.h"
 #include "gfxFont.h"
 
 using namespace std;
 
 #ifdef USE_SKIA
 #include "PathSkia.h"
 #include "skia/include/core/SkPaint.h"
@@ -216,17 +217,17 @@ ScaledFontDWrite::CopyGlyphsToSink(const
                                   &offsets.front(), aBuffer.mNumGlyphs,
                                   FALSE, FALSE, aSink);
   if (FAILED(hr)) {
     gfxCriticalNote << "Failed to copy glyphs to geometry sink. Code: " << hexa(hr);
   }
 }
 
 bool
-ScaledFontDWrite::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
+UnscaledFontDWrite::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
 {
   UINT32 fileCount = 0;
   mFontFace->GetFiles(&fileCount, nullptr);
 
   if (fileCount > 1) {
     MOZ_ASSERT(false);
     return false;
   }
@@ -237,46 +238,59 @@ ScaledFontDWrite::GetFontFileData(FontFi
 
   RefPtr<IDWriteFontFile> file;
   mFontFace->GetFiles(&fileCount, getter_AddRefs(file));
 
   const void *referenceKey;
   UINT32 refKeySize;
   // XXX - This can currently crash for webfonts, as when we get the reference
   // key out of the file, that can be an invalid reference key for the loader
-  // we use it with. The fix to this is not obvious but it will probably 
+  // we use it with. The fix to this is not obvious but it will probably
   // have to happen inside thebes.
   file->GetReferenceKey(&referenceKey, &refKeySize);
 
   RefPtr<IDWriteFontFileLoader> loader;
   file->GetLoader(getter_AddRefs(loader));
-  
+
   RefPtr<IDWriteFontFileStream> stream;
   loader->CreateStreamFromKey(referenceKey, refKeySize, getter_AddRefs(stream));
 
   UINT64 fileSize64;
   stream->GetFileSize(&fileSize64);
   if (fileSize64 > UINT32_MAX) {
     MOZ_ASSERT(false);
     return false;
   }
-  
+
   uint32_t fileSize = static_cast<uint32_t>(fileSize64);
   const void *fragmentStart;
   void *context;
   stream->ReadFileFragment(&fragmentStart, 0, fileSize, &context);
 
-  aDataCallback((uint8_t*)fragmentStart, fileSize, mFontFace->GetIndex(), mSize,
-                0, nullptr, aBaton);
+  aDataCallback((uint8_t*)fragmentStart, fileSize, mFontFace->GetIndex(), aBaton);
 
   stream->ReleaseFileFragment(context);
 
   return true;
 }
 
+already_AddRefed<ScaledFont>
+UnscaledFontDWrite::CreateScaledFont(Float aGlyphSize,
+                                     const uint8_t* aInstanceData,
+                                     uint32_t aInstanceDataLength)
+{
+  RefPtr<ScaledFontBase> scaledFont = new ScaledFontDWrite(mFontFace, this, aGlyphSize);
+  if (mNeedsCairo && !scaledFont->PopulateCairoScaledFont()) {
+    gfxWarning() << "Unable to create cairo scaled font DWrite font.";
+    return nullptr;
+  }
+
+  return scaledFont.forget();
+}
+
 AntialiasMode
 ScaledFontDWrite::GetDefaultAAMode()
 {
   AntialiasMode defaultMode = GetSystemDefaultAAMode();
 
   if (defaultMode == AntialiasMode::GRAY) {
     if (!DoGrayscale(mFontFace, mSize)) {
       defaultMode = AntialiasMode::NONE;
--- a/gfx/2d/ScaledFontDWrite.h
+++ b/gfx/2d/ScaledFontDWrite.h
@@ -13,76 +13,74 @@ struct ID2D1GeometrySink;
 struct gfxFontStyle;
 
 namespace mozilla {
 namespace gfx {
 
 class ScaledFontDWrite final : public ScaledFontBase
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontDwrite)
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontDWrite, override)
   ScaledFontDWrite(IDWriteFontFace *aFont,
                    const RefPtr<UnscaledFont>& aUnscaledFont,
                    Float aSize)
     : ScaledFontBase(aUnscaledFont, aSize)
     , mFontFace(aFont)
     , mUseEmbeddedBitmap(false)
     , mForceGDIMode(false)
   {}
 
   ScaledFontDWrite(IDWriteFontFace *aFontFace,
                    const RefPtr<UnscaledFont>& aUnscaledFont,
                    Float aSize,
                    bool aUseEmbeddedBitmap,
                    bool aForceGDIMode,
                    const gfxFontStyle* aStyle);
 
-  virtual FontType GetType() const { return FontType::DWRITE; }
+  FontType GetType() const override { return FontType::DWRITE; }
 
-  virtual already_AddRefed<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
-  virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint);
+  already_AddRefed<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) override;
+  void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint) override;
 
   void CopyGlyphsToSink(const GlyphBuffer &aBuffer, ID2D1GeometrySink *aSink);
 
-  virtual void GetGlyphDesignMetrics(const uint16_t* aGlyphIndices, uint32_t aNumGlyphs, GlyphMetrics* aGlyphMetrics);
-
-  virtual bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton);
+  void GetGlyphDesignMetrics(const uint16_t* aGlyphIndices, uint32_t aNumGlyphs, GlyphMetrics* aGlyphMetrics) override;
 
-  virtual bool CanSerialize() override { return true; }
+  bool CanSerialize() override { return true; }
 
-  virtual AntialiasMode GetDefaultAAMode() override;
+  AntialiasMode GetDefaultAAMode() override;
 
   bool UseEmbeddedBitmaps() { return mUseEmbeddedBitmap; }
   bool ForceGDIMode() { return mForceGDIMode; }
 
 #ifdef USE_SKIA
-  virtual SkTypeface* GetSkTypeface();
+  SkTypeface* GetSkTypeface() override;
   SkFontStyle mStyle;
 #endif
 
   RefPtr<IDWriteFontFace> mFontFace;
   bool mUseEmbeddedBitmap;
   bool mForceGDIMode;
 
 protected:
 #ifdef USE_CAIRO_SCALED_FONT
   cairo_font_face_t* GetCairoFontFace() override;
 #endif
 };
 
 class GlyphRenderingOptionsDWrite : public GlyphRenderingOptions
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptionsDWrite)
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptionsDWrite, override)
   explicit GlyphRenderingOptionsDWrite(IDWriteRenderingParams *aParams)
     : mParams(aParams)
   {
   }
 
-  virtual FontType GetType() const { return FontType::DWRITE; }
+  FontType GetType() const override { return FontType::DWRITE; }
 
 private:
   friend class DrawTargetD2D;
   friend class DrawTargetD2D1;
 
   RefPtr<IDWriteRenderingParams> mParams;
 };
 
--- a/gfx/2d/ScaledFontFontconfig.cpp
+++ b/gfx/2d/ScaledFontFontconfig.cpp
@@ -1,22 +1,21 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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 "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
@@ -43,37 +42,16 @@ 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, 0, nullptr, 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;
@@ -248,62 +226,45 @@ 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)
+already_AddRefed<ScaledFont>
+UnscaledFontFontconfig::CreateScaledFont(Float aGlyphSize,
+                                         const uint8_t* aInstanceData,
+                                         uint32_t aInstanceDataLength)
 {
-  // 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;
+  if (aInstanceDataLength < sizeof(ScaledFontFontconfig::InstanceData)) {
+    gfxWarning() << "Fontconfig scaled font instance data is truncated.";
+    return nullptr;
   }
-  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);
-  delete[] data;
-  return true;
+  const ScaledFontFontconfig::InstanceData *instanceData =
+    reinterpret_cast<const ScaledFontFontconfig::InstanceData*>(aInstanceData);
+  return ScaledFontFontconfig::CreateFromInstanceData(*instanceData, this, aGlyphSize);
 }
 
 already_AddRefed<ScaledFont>
 ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData,
-                                             FT_Face aFace, const char* aPathname, uint32_t aIndex,
+                                             UnscaledFontFontconfig* aUnscaledFont,
                                              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);
+  if (aUnscaledFont->GetFace()) {
+    FcPatternAddFTFace(pattern, FC_FT_FACE, aUnscaledFont->GetFace());
   } else {
-    FcPatternAddString(pattern, FC_FILE, reinterpret_cast<const FcChar8*>(aPathname));
-    FcPatternAddInteger(pattern, FC_INDEX, aIndex);
+    FcPatternAddString(pattern, FC_FILE, reinterpret_cast<const FcChar8*>(aUnscaledFont->GetFile()));
+    FcPatternAddInteger(pattern, FC_INDEX, aUnscaledFont->GetIndex());
   }
   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);
@@ -327,38 +288,40 @@ ScaledFontFontconfig::CreateFromInstance
 
   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, nullptr, aSize);
+    new ScaledFontFontconfig(cairoScaledFont, pattern, aUnscaledFont, aSize);
 
   FcPatternDestroy(pattern);
 
   return scaledFont.forget();
 }
 
-already_AddRefed<ScaledFont>
-ScaledFontFontconfig::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize)
+already_AddRefed<UnscaledFont>
+UnscaledFontFontconfig::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength)
 {
   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') {
+  const char* path = reinterpret_cast<const char*>(aData + sizeof(FontDescriptor));
+  if (path[desc->mPathLength - 1] != '\0') {
     gfxWarning() << "Pathname in Fontconfig font descriptor is not terminated.";
     return nullptr;
   }
-  return CreateFromInstanceData(desc->mInstanceData, nullptr, pathname, desc->mIndex, aSize);
+
+  RefPtr<UnscaledFont> unscaledFont = new UnscaledFontFontconfig(path, desc->mIndex);
+  return unscaledFont.forget();
 }
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/2d/ScaledFontFontconfig.h
+++ b/gfx/2d/ScaledFontFontconfig.h
@@ -9,16 +9,17 @@
 #include "ScaledFontBase.h"
 
 #include <cairo-ft.h>
 
 namespace mozilla {
 namespace gfx {
 
 class NativeFontResourceFontconfig;
+class UnscaledFontFontconfig;
 
 class ScaledFontFontconfig : public ScaledFontBase
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontFontconfig, override)
   ScaledFontFontconfig(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern,
                        const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize);
   ~ScaledFontFontconfig();
@@ -26,27 +27,21 @@ public:
   FontType GetType() const override { return FontType::FONTCONFIG; }
 
 #ifdef USE_SKIA
   SkTypeface* GetSkTypeface() override;
 #endif
 
   bool CanSerialize() override { return true; }
 
-  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;
+  friend class UnscaledFontFontconfig;
 
   struct InstanceData
   {
     enum {
       ANTIALIAS       = 1 << 0,
       AUTOHINT        = 1 << 1,
       EMBEDDED_BITMAP = 1 << 2,
       EMBOLDEN        = 1 << 3,
@@ -63,26 +58,19 @@ private:
     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,
+                           UnscaledFontFontconfig* aUnscaledFont,
                            Float aSize);
 
   FcPattern* mPattern;
 };
 
 }
 }
 
--- a/gfx/2d/ScaledFontMac.cpp
+++ b/gfx/2d/ScaledFontMac.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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 "ScaledFontMac.h"
+#include "UnscaledFontMac.h"
 #ifdef USE_SKIA
 #include "PathSkia.h"
 #include "skia/include/core/SkPaint.h"
 #include "skia/include/core/SkPath.h"
 #include "skia/include/ports/SkTypeface_mac.h"
 #endif
 #include <vector>
 #include <dlfcn.h>
@@ -26,16 +27,50 @@ CGPathRef CGFontGetGlyphPath(CGFontRef f
 
 #ifdef USE_CAIRO_SCALED_FONT
 #include "cairo-quartz.h"
 #endif
 
 namespace mozilla {
 namespace gfx {
 
+// Simple helper class to automatically release a CFObject when it goes out
+// of scope.
+template<class T>
+class AutoRelease
+{
+public:
+  explicit AutoRelease(T aObject)
+    : mObject(aObject)
+  {
+  }
+
+  ~AutoRelease()
+  {
+    if (mObject) {
+      CFRelease(mObject);
+    }
+  }
+
+  operator T()
+  {
+    return mObject;
+  }
+
+  T forget()
+  {
+    T obj = mObject;
+    mObject = nullptr;
+    return obj;
+  }
+
+private:
+  T mObject;
+};
+
 ScaledFontMac::CTFontDrawGlyphsFuncT* ScaledFontMac::CTFontDrawGlyphsPtr = nullptr;
 bool ScaledFontMac::sSymbolLookupDone = false;
 
 // Helper to create a CTFont from a CGFont, copying any variations that were
 // set on the original CGFont.
 static CTFontRef
 CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont, CGFloat aSize)
 {
@@ -64,27 +99,31 @@ CreateCTFontFromCGFontWithVariations(CGF
     } else {
         ctFont = CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr, nullptr);
     }
     return ctFont;
 }
 
 ScaledFontMac::ScaledFontMac(CGFontRef aFont,
                              const RefPtr<UnscaledFont>& aUnscaledFont,
-                             Float aSize)
+                             Float aSize,
+                             bool aOwnsFont)
   : ScaledFontBase(aUnscaledFont, aSize)
 {
   if (!sSymbolLookupDone) {
     CTFontDrawGlyphsPtr =
       (CTFontDrawGlyphsFuncT*)dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
     sSymbolLookupDone = true;
   }
 
-  // XXX: should we be taking a reference
-  mFont = CGFontRetain(aFont);
+  if (!aOwnsFont) {
+    // XXX: should we be taking a reference
+    mFont = CGFontRetain(aFont);
+  }
+
   if (CTFontDrawGlyphsPtr != nullptr) {
     // only create mCTFont if we're going to be using the CTFontDrawGlyphs API
     mCTFont = CreateCTFontFromCGFontWithVariations(aFont, aSize);
   } else {
     mCTFont = nullptr;
   }
 }
 
@@ -209,17 +248,17 @@ static void CollectVariationSetting(cons
       (*vpp)->mTag = t;
       (*vpp)->mValue = v;
       (*vpp)++;
     }
   }
 }
 
 bool
-ScaledFontMac::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
+UnscaledFontMac::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
 {
     // We'll reconstruct a TTF font from the tables we can get from the CGFont
     CFArrayRef tags = CGFontCopyTableTags(mFont);
     CFIndex count = CFArrayGetCount(tags);
 
     TableRecord *records = new TableRecord[count];
     uint32_t offset = 0;
     offset += sizeof(uint32_t)*3;
@@ -276,16 +315,25 @@ ScaledFontMac::GetFontFileData(FontFileD
     delete[] records;
 
     // clear the checksumAdjust field before checksumming the whole font
     memset(&buf.data[checkSumAdjustmentOffset], 0, sizeof(uint32_t));
     uint32_t fontChecksum = CFSwapInt32HostToBig(0xb1b0afba - CalcTableChecksum(reinterpret_cast<const uint32_t*>(buf.data), offset));
     // set checkSumAdjust to the computed checksum
     memcpy(&buf.data[checkSumAdjustmentOffset], &fontChecksum, sizeof(fontChecksum));
 
+    // we always use an index of 0
+    aDataCallback(buf.data, buf.offset, 0, aBaton);
+
+    return true;
+}
+
+bool
+ScaledFontMac::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
+{
     // Collect any variation settings that were incorporated into the CTFont.
     uint32_t variationCount = 0;
     VariationSetting* variations = nullptr;
     // Avoid calling potentially buggy variation APIs on pre-Sierra macOS
     // versions (see bug 1331683)
     if (nsCocoaFeatures::OnSierraOrLater()) {
       if (mCTFont) {
         CFDictionaryRef dict = CTFontCopyVariation(mCTFont);
@@ -297,22 +345,168 @@ ScaledFontMac::GetFontFileData(FontFileD
             CFDictionaryApplyFunction(dict, CollectVariationSetting, &vPtr);
             variationCount = vPtr - variations;
           }
           CFRelease(dict);
         }
       }
     }
 
-    // we always use an index of 0
-    aDataCallback(buf.data, buf.offset, 0, mSize, variationCount, variations, aBaton);
+    aCb(reinterpret_cast<uint8_t*>(variations), variationCount * sizeof(VariationSetting), aBaton);
     delete[] variations;
 
     return true;
+}
 
+static CFDictionaryRef
+CreateVariationDictionaryOrNull(CGFontRef aCGFont, uint32_t aVariationCount,
+                                const ScaledFont::VariationSetting* aVariations)
+{
+  // Avoid calling potentially buggy variation APIs on pre-Sierra macOS
+  // versions (see bug 1331683)
+  if (!nsCocoaFeatures::OnSierraOrLater()) {
+    return nullptr;
+  }
+
+  AutoRelease<CTFontRef>
+    ctFont(CTFontCreateWithGraphicsFont(aCGFont, 0, nullptr, nullptr));
+  AutoRelease<CFArrayRef> axes(CTFontCopyVariationAxes(ctFont));
+  if (!axes) {
+    return nullptr;
+  }
+
+  CFIndex axisCount = CFArrayGetCount(axes);
+  AutoRelease<CFMutableDictionaryRef>
+    dict(CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
+                                   &kCFTypeDictionaryKeyCallBacks,
+                                   &kCFTypeDictionaryValueCallBacks));
+
+  // Number of variation settings passed in the aVariations parameter.
+  // This will typically be a very low value, so we just linear-search them.
+  bool allDefaultValues = true;
+
+  for (CFIndex i = 0; i < axisCount; ++i) {
+    // We sanity-check the axis info found in the CTFont, and bail out
+    // (returning null) if it doesn't have the expected types.
+    CFTypeRef axisInfo = CFArrayGetValueAtIndex(axes, i);
+    if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
+      return nullptr;
+    }
+    CFDictionaryRef axis = static_cast<CFDictionaryRef>(axisInfo);
+
+    CFTypeRef axisTag =
+        CFDictionaryGetValue(axis, kCTFontVariationAxisIdentifierKey);
+    if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) {
+      return nullptr;
+    }
+    int64_t tagLong;
+    if (!CFNumberGetValue(static_cast<CFNumberRef>(axisTag),
+                          kCFNumberSInt64Type, &tagLong)) {
+      return nullptr;
+    }
+
+    CFTypeRef axisName =
+      CFDictionaryGetValue(axis, kCTFontVariationAxisNameKey);
+    if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
+      return nullptr;
+    }
+
+    // Clamp axis values to the supported range.
+    CFTypeRef min = CFDictionaryGetValue(axis, kCTFontVariationAxisMinimumValueKey);
+    CFTypeRef max = CFDictionaryGetValue(axis, kCTFontVariationAxisMaximumValueKey);
+    CFTypeRef def = CFDictionaryGetValue(axis, kCTFontVariationAxisDefaultValueKey);
+    if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
+        !max || CFGetTypeID(max) != CFNumberGetTypeID() ||
+        !def || CFGetTypeID(def) != CFNumberGetTypeID()) {
+      return nullptr;
+    }
+    double minDouble;
+    double maxDouble;
+    double defDouble;
+    if (!CFNumberGetValue(static_cast<CFNumberRef>(min), kCFNumberDoubleType,
+                          &minDouble) ||
+        !CFNumberGetValue(static_cast<CFNumberRef>(max), kCFNumberDoubleType,
+                          &maxDouble) ||
+        !CFNumberGetValue(static_cast<CFNumberRef>(def), kCFNumberDoubleType,
+                          &defDouble)) {
+      return nullptr;
+    }
+
+    double value = defDouble;
+    for (uint32_t j = 0; j < aVariationCount; ++j) {
+      if (aVariations[j].mTag == tagLong) {
+        value = std::min(std::max<double>(aVariations[j].mValue,
+                                          minDouble),
+                         maxDouble);
+        if (value != defDouble) {
+          allDefaultValues = false;
+        }
+        break;
+      }
+    }
+    AutoRelease<CFNumberRef> valueNumber(CFNumberCreate(kCFAllocatorDefault,
+                                                        kCFNumberDoubleType,
+                                                        &value));
+    CFDictionaryAddValue(dict, axisName, valueNumber);
+  }
+
+  if (allDefaultValues) {
+    // We didn't actually set any non-default values, so throw away the
+    // variations dictionary and just use the default rendering.
+    return nullptr;
+  }
+
+  return dict.forget();
+}
+
+CGFontRef
+UnscaledFontMac::CreateCGFontWithVariations(CGFontRef aFont,
+                                            uint32_t aVariationCount,
+                                            const ScaledFont::VariationSetting* aVariations)
+{
+  MOZ_ASSERT(aVariationCount > 0);
+  MOZ_ASSERT(aVariations);
+
+  AutoRelease<CFDictionaryRef>
+    varDict(CreateVariationDictionaryOrNull(aFont, aVariationCount, aVariations));
+  if (!varDict) {
+    return nullptr;
+  }
+
+  return CGFontCreateCopyWithVariations(aFont, varDict);
+}
+
+already_AddRefed<ScaledFont>
+UnscaledFontMac::CreateScaledFont(Float aGlyphSize,
+                                  const uint8_t* aInstanceData,
+                                  uint32_t aInstanceDataLength)
+{
+  uint32_t variationCount =
+    aInstanceDataLength / sizeof(ScaledFont::VariationSetting);
+  const ScaledFont::VariationSetting* variations =
+    reinterpret_cast<const ScaledFont::VariationSetting*>(aInstanceData);
+
+  CGFontRef fontRef = mFont;
+  if (variationCount > 0) {
+    CGFontRef varFont =
+      CreateCGFontWithVariations(mFont, variationCount, variations);
+    if (varFont) {
+      fontRef = varFont;
+    }
+  }
+
+  RefPtr<ScaledFontMac> scaledFont =
+    new ScaledFontMac(fontRef, this, aGlyphSize, fontRef != mFont);
+
+  if (!scaledFont->PopulateCairoScaledFont()) {
+    gfxWarning() << "Unable to create cairo scaled Mac font.";
+    return nullptr;
+  }
+
+  return scaledFont.forget();
 }
 
 #ifdef USE_CAIRO_SCALED_FONT
 cairo_font_face_t*
 ScaledFontMac::GetCairoFontFace()
 {
   MOZ_ASSERT(mFont);
   return cairo_quartz_font_face_create_for_cgfont(mFont);
--- a/gfx/2d/ScaledFontMac.h
+++ b/gfx/2d/ScaledFontMac.h
@@ -35,30 +35,32 @@ public:
 
 private:
   Color mFontSmoothingBackgroundColor;
 };
 
 class ScaledFontMac : public ScaledFontBase
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontMac)
-  ScaledFontMac(CGFontRef aFont, const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize);
-  virtual ~ScaledFontMac();
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontMac, override)
+  ScaledFontMac(CGFontRef aFont, const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize, bool aOwnsFont = false);
+  ~ScaledFontMac();
 
-  virtual FontType GetType() const { return FontType::MAC; }
+  FontType GetType() const override { return FontType::MAC; }
 #ifdef USE_SKIA
-  virtual SkTypeface* GetSkTypeface();
+  SkTypeface* GetSkTypeface() override;
 #endif
-  virtual already_AddRefed<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
-  virtual bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton);
-  virtual bool CanSerialize() { return true; }
+  already_AddRefed<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) override;
+
+  bool GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) override;
+
+  bool CanSerialize() override { return true; }
 
 #ifdef USE_CAIRO_SCALED_FONT
-  cairo_font_face_t* GetCairoFontFace();
+  cairo_font_face_t* GetCairoFontFace() override;
 #endif
 
 private:
   friend class DrawTargetSkia;
   CGFontRef mFont;
   CTFontRef mCTFont; // only created if CTFontDrawGlyphs is available, otherwise null
 
   typedef void (CTFontDrawGlyphsFuncT)(CTFontRef,
--- a/gfx/2d/ScaledFontWin.cpp
+++ b/gfx/2d/ScaledFontWin.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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 "ScaledFontWin.h"
+#include "UnscaledFontGDI.h"
 
 #include "AutoHelpersWin.h"
 #include "Logging.h"
 #include "nsString.h"
 
 #ifdef USE_SKIA
 #include "skia/include/ports/SkTypeface_win.h"
 #endif
@@ -26,17 +27,17 @@ ScaledFontWin::ScaledFontWin(const LOGFO
                              const RefPtr<UnscaledFont>& aUnscaledFont,
                              Float aSize)
   : ScaledFontBase(aUnscaledFont, aSize)
   , mLogFont(*aFont)
 {
 }
 
 bool
-ScaledFontWin::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
+UnscaledFontGDI::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
 {
   AutoDC dc;
   AutoSelectFont font(dc.GetDC(), &mLogFont);
 
   // Check for a font collection first.
   uint32_t table = 0x66637474; // 'ttcf'
   uint32_t tableSize = ::GetFontData(dc.GetDC(), table, 0, nullptr, 0);
   if (tableSize == GDI_ERROR) {
@@ -51,43 +52,63 @@ ScaledFontWin::GetFontFileData(FontFileD
   UniquePtr<uint8_t[]> fontData(new uint8_t[tableSize]);
 
   uint32_t sizeGot =
     ::GetFontData(dc.GetDC(), table, 0, fontData.get(), tableSize);
   if (sizeGot != tableSize) {
     return false;
   }
 
-  aDataCallback(fontData.get(), tableSize, 0, mSize, 0, nullptr, aBaton);
+  aDataCallback(fontData.get(), tableSize, 0, aBaton);
   return true;
 }
 
 bool
 ScaledFontWin::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
 {
   aCb(reinterpret_cast<uint8_t*>(&mLogFont), sizeof(mLogFont), aBaton);
   return true;
 }
 
 bool
-ScaledFontWin::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton)
+UnscaledFontGDI::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton)
+{
+  aCb(reinterpret_cast<uint8_t*>(&mLogFont), sizeof(mLogFont), aBaton);
+  return true;
+}
+
+already_AddRefed<UnscaledFont>
+UnscaledFontGDI::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength)
 {
-  aCb(reinterpret_cast<uint8_t*>(&mLogFont), sizeof(mLogFont), mSize, aBaton);
-  return true;
+  if (aDataLength < sizeof(LOGFONT)) {
+    gfxWarning() << "GDI font descriptor is truncated.";
+    return nullptr;
+  }
+
+  const LOGFONT* logFont = reinterpret_cast<const LOGFONT*>(aData);
+  RefPtr<UnscaledFont> unscaledFont = new UnscaledFontGDI(*logFont);
+  return unscaledFont.forget();
 }
 
 already_AddRefed<ScaledFont>
-ScaledFontWin::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize)
+UnscaledFontGDI::CreateScaledFont(Float aGlyphSize,
+                                  const uint8_t* aInstanceData,
+                                  uint32_t aInstanceDataLength)
 {
+  if (aInstanceDataLength < sizeof(LOGFONT)) {
+    gfxWarning() << "GDI unscaled font instance data is truncated.";
+    return nullptr;
+  }
+
   NativeFont nativeFont;
   nativeFont.mType = NativeFontType::GDI_FONT_FACE;
-  nativeFont.mFont = (void*)aData;
+  nativeFont.mFont = (void*)aInstanceData;
 
   RefPtr<ScaledFont> font =
-    Factory::CreateScaledFontForNativeFont(nativeFont, nullptr, aSize);
+    Factory::CreateScaledFontForNativeFont(nativeFont, this, aGlyphSize);
 
 #ifdef USE_CAIRO_SCALED_FONT
   static_cast<ScaledFontBase*>(font.get())->PopulateCairoScaledFont();
 #endif
 
   return font.forget();
 }
 
--- a/gfx/2d/ScaledFontWin.h
+++ b/gfx/2d/ScaledFontWin.h
@@ -10,36 +10,29 @@
 #include <windows.h>
 
 namespace mozilla {
 namespace gfx {
 
 class ScaledFontWin : public ScaledFontBase
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontWin)
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontWin, override)
   ScaledFontWin(const LOGFONT* aFont,
                 const RefPtr<UnscaledFont>& aUnscaledFont,
                 Float aSize);
 
-  virtual FontType GetType() const { return FontType::GDI; }
-
-  bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) override;
+  FontType GetType() const override { return FontType::GDI; }
 
   bool GetFontInstanceData(FontInstanceDataOutput aCb, 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;
+  AntialiasMode GetDefaultAAMode() override;
 
 #ifdef USE_SKIA
-  virtual SkTypeface* GetSkTypeface();
+  SkTypeface* GetSkTypeface() override;
 #endif
 
 protected:
 #ifdef USE_CAIRO_SCALED_FONT
   cairo_font_face_t* GetCairoFontFace() override;
 #endif
 
 private:
--- a/gfx/2d/UnscaledFontDWrite.h
+++ b/gfx/2d/UnscaledFontDWrite.h
@@ -14,28 +14,38 @@ namespace mozilla {
 namespace gfx {
 
 class UnscaledFontDWrite final : public UnscaledFont
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(UnscaledFontDWrite, override)
   explicit UnscaledFontDWrite(const RefPtr<IDWriteFontFace>& aFontFace,
                               DWRITE_FONT_SIMULATIONS aSimulations =
-                                DWRITE_FONT_SIMULATIONS_NONE)
-    : mFontFace(aFontFace),
-      mSimulations(aSimulations)
+                                DWRITE_FONT_SIMULATIONS_NONE,
+                              bool aNeedsCairo = false)
+    : mFontFace(aFontFace)
+    , mSimulations(aSimulations)
+    , mNeedsCairo(aNeedsCairo)
   {}
 
   FontType GetType() const override { return FontType::DWRITE; }
 
   const RefPtr<IDWriteFontFace> GetFontFace() const { return mFontFace; }
   DWRITE_FONT_SIMULATIONS GetSimulations() const { return mSimulations; }
 
+  bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) override;
+
+  already_AddRefed<ScaledFont>
+    CreateScaledFont(Float aGlyphSize,
+                     const uint8_t* aInstanceData,
+                     uint32_t aInstanceDataLength) override;
+
 private:
   RefPtr<IDWriteFontFace> mFontFace;
   DWRITE_FONT_SIMULATIONS mSimulations;
+  bool mNeedsCairo;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_UNSCALEDFONTDWRITE_H_ */
 
new file mode 100644
--- /dev/null
+++ b/gfx/2d/UnscaledFontFreeType.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 FT_TRUETYPE_TABLES_H
+
+namespace mozilla {
+namespace gfx {
+
+bool
+UnscaledFontFreeType::GetFontFileData(FontFileDataOutput aDataCallback, void* aBaton)
+{
+  bool success = false;
+  FT_ULong length = 0;
+  // Request the SFNT file. This may not always succeed for all font types.
+  if (FT_Load_Sfnt_Table(mFace, 0, 0, nullptr, &length) == FT_Err_Ok) {
+    uint8_t* fontData = new uint8_t[length];
+    if (FT_Load_Sfnt_Table(mFace, 0, 0, fontData, &length) == FT_Err_Ok) {
+      aDataCallback(fontData, length, 0, aBaton);
+      success = true;
+    }
+    delete[] fontData;
+  }
+  return success;
+}
+
+bool
+UnscaledFontFreeType::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton)
+{
+  if (mFile.empty()) {
+    return false;
+  }
+
+  const char* path = mFile.c_str();
+  size_t pathLength = strlen(path) + 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 = mIndex;
+  memcpy(data + sizeof(FontDescriptor), path, pathLength);
+
+  aCb(data, dataLength, aBaton);
+  delete[] data;
+  return true;
+}
+
+} // namespace gfx
+} // namespace mozilla
+
--- a/gfx/2d/UnscaledFontFreeType.h
+++ b/gfx/2d/UnscaledFontFreeType.h
@@ -12,53 +12,82 @@
 
 namespace mozilla {
 namespace gfx {
 
 class UnscaledFontFreeType : public UnscaledFont
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(UnscaledFontFreeType, override)
-  explicit UnscaledFontFreeType(FT_Face aFace)
+  explicit UnscaledFontFreeType(FT_Face aFace,
+                                bool aOwnsFace = false)
     : mFace(aFace)
+    , mOwnsFace(aOwnsFace)
     , mIndex(0)
   {}
   explicit UnscaledFontFreeType(const char* aFile,
                                 uint32_t aIndex = 0)
     : mFace(nullptr)
+    , mOwnsFace(false)
     , mFile(aFile)
     , mIndex(aIndex)
   {}
+  ~UnscaledFontFreeType()
+  {
+    if (mOwnsFace) {
+      FT_Done_Face(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; }
 
+  struct FontDescriptor
+  {
+    uint32_t mPathLength;
+    uint32_t mIndex;
+  };
+
+  bool GetFontFileData(FontFileDataOutput aDataCallback, void* aBaton) override;
+
+  bool GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) override;
+
 private:
   FT_Face mFace;
+  bool mOwnsFace;
   std::string mFile;
   uint32_t mIndex;
 };
 
 #ifdef MOZ_WIDGET_GTK
 class UnscaledFontFontconfig : public UnscaledFontFreeType
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(UnscaledFontFontconfig, override)
-  explicit UnscaledFontFontconfig(FT_Face aFace)
-    : UnscaledFontFreeType(aFace)
+  explicit UnscaledFontFontconfig(FT_Face aFace,
+                                  bool aOwnsFace = false)
+    : UnscaledFontFreeType(aFace, aOwnsFace)
   {}
   explicit UnscaledFontFontconfig(const char* aFile,
                                   uint32_t aIndex = 0)
     : UnscaledFontFreeType(aFile, aIndex)
   {}
 
   FontType GetType() const override { return FontType::FONTCONFIG; }
+
+  static already_AddRefed<UnscaledFont>
+    CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength);
+
+  already_AddRefed<ScaledFont>
+    CreateScaledFont(Float aGlyphSize,
+                     const uint8_t* aInstanceData,
+                     uint32_t aInstanceDataLength) override;
 };
 #endif
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_UNSCALEDFONTFREETYPE_H_ */
 
--- a/gfx/2d/UnscaledFontGDI.h
+++ b/gfx/2d/UnscaledFontGDI.h
@@ -19,16 +19,28 @@ public:
   explicit UnscaledFontGDI(const LOGFONT& aLogFont)
     : mLogFont(aLogFont)
   {}
 
   FontType GetType() const override { return FontType::GDI; }
 
   const LOGFONT& GetLogFont() const { return mLogFont; }
 
+  bool GetFontFileData(FontFileDataOutput aDataCallback, void* aBaton) override;
+
+  bool GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) override;
+
+  static already_AddRefed<UnscaledFont>
+    CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength);
+
+  already_AddRefed<ScaledFont>
+    CreateScaledFont(Float aGlyphSize,
+                     const uint8_t* aInstanceData,
+                     uint32_t aInstanceDataLength) override;
+
 private:
   LOGFONT mLogFont;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_UNSCALEDFONTGDI_H_ */
--- a/gfx/2d/UnscaledFontMac.h
+++ b/gfx/2d/UnscaledFontMac.h
@@ -31,16 +31,28 @@ public:
   {
     CFRelease(mFont);
   }
 
   FontType GetType() const override { return FontType::MAC; }
 
   CGFontRef GetFont() const { return mFont; }
 
+  bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) override;
+
+  already_AddRefed<ScaledFont>
+    CreateScaledFont(Float aGlyphSize,
+                     const uint8_t* aInstanceData,
+                     uint32_t aInstanceDataLength) override;
+
+  static CGFontRef
+    CreateCGFontWithVariations(CGFontRef aFont,
+                               uint32_t aVariationCount,
+                               const ScaledFont::VariationSetting* aVariations);
+
 private:
   CGFontRef mFont;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_UNSCALEDFONTMAC_H_ */
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -93,16 +93,19 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'wind
     SOURCES += [
         'JobScheduler_posix.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3'):
     EXPORTS.mozilla.gfx += [
         'UnscaledFontFreeType.h',
     ]
+    SOURCES += [
+        'UnscaledFontFreeType.cpp',
+    ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
     SOURCES += [
         'NativeFontResourceFontconfig.cpp',
         'ScaledFontFontconfig.cpp',
     ]
 
 if CONFIG['MOZ_ENABLE_SKIA']:
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -151,33 +151,30 @@ WebRenderBridgeChild::DeallocExternalIma
   MOZ_ASSERT(aImageId);
   SendRemoveExternalImageId(aImageId);
 }
 
 struct FontFileData
 {
   wr::ByteBuffer mFontBuffer;
   uint32_t mFontIndex;
-  float mGlyphSize;
 };
 
 static void
 WriteFontFileData(const uint8_t* aData, uint32_t aLength, uint32_t aIndex,
-                  float aGlyphSize, uint32_t aVariationCount,
-                  const ScaledFont::VariationSetting* aVariations, void* aBaton)
+                  void* aBaton)
 {
   FontFileData* data = static_cast<FontFileData*>(aBaton);
 
   if (!data->mFontBuffer.Allocate(aLength)) {
     return;
   }
   memcpy(data->mFontBuffer.mData, aData, aLength);
 
   data->mFontIndex = aIndex;
-  data->mGlyphSize = aGlyphSize;
 }
 
 void
 WebRenderBridgeChild::PushGlyphs(wr::DisplayListBuilder& aBuilder, const nsTArray<GlyphArray>& aGlyphs,
                                  gfx::ScaledFont* aFont, const gfx::Point& aOffset, const gfx::Rect& aBounds,
                                  const gfx::Rect& aClip)
 {
   MOZ_ASSERT(aFont);
@@ -223,17 +220,17 @@ WebRenderBridgeChild::GetFontKeyForScale
   MOZ_ASSERT(unscaled);
 
   wr::FontKey key = {0, 0};
   if (mFontKeys.Get(unscaled, &key)) {
     return key;
   }
 
   FontFileData data;
-  if (!aScaledFont->GetFontFileData(WriteFontFileData, &data) ||
+  if (!unscaled->GetFontFileData(WriteFontFileData, &data) ||
       !data.mFontBuffer.mData) {
     return key;
   }
 
   key.mNamespace = GetNamespace();
   key.mHandle = GetNextResourceId();
 
   SendAddRawFont(key, data.mFontBuffer, data.mFontIndex);
--- a/gfx/thebes/gfxMacFont.cpp
+++ b/gfx/thebes/gfxMacFont.cpp
@@ -18,152 +18,16 @@
 #include "gfxTextRun.h"
 #include "nsCocoaFeatures.h"
 
 #include "cairo-quartz.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
-// Simple helper class to automatically release a CFObject when it goes out
-// of scope.
-template<class T>
-class AutoRelease
-{
-public:
-    explicit AutoRelease(T aObject)
-        : mObject(aObject)
-    {
-    }
-
-    ~AutoRelease()
-    {
-        if (mObject) {
-            CFRelease(mObject);
-        }
-    }
-
-    operator T()
-    {
-        return mObject;
-    }
-
-    T forget()
-    {
-        T obj = mObject;
-        mObject = nullptr;
-        return obj;
-    }
-
-private:
-    T mObject;
-};
-
-static CFDictionaryRef
-CreateVariationDictionaryOrNull(CGFontRef aCGFont,
-                                const nsTArray<gfxFontVariation>& aVariations)
-{
-    // Avoid calling potentially buggy variation APIs on pre-Sierra macOS
-    // versions (see bug 1331683)
-    if (!nsCocoaFeatures::OnSierraOrLater()) {
-        return nullptr;
-    }
-
-    AutoRelease<CTFontRef>
-      ctFont(CTFontCreateWithGraphicsFont(aCGFont, 0, nullptr, nullptr));
-    AutoRelease<CFArrayRef> axes(CTFontCopyVariationAxes(ctFont));
-    if (!axes) {
-        return nullptr;
-    }
-
-    CFIndex axisCount = CFArrayGetCount(axes);
-    AutoRelease<CFMutableDictionaryRef>
-        dict(CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
-                                       &kCFTypeDictionaryKeyCallBacks,
-                                       &kCFTypeDictionaryValueCallBacks));
-
-    // Number of variation settings passed in the aVariations parameter.
-    // This will typically be a very low value, so we just linear-search them.
-    uint32_t numVars = aVariations.Length();
-    bool allDefaultValues = true;
-
-    for (CFIndex i = 0; i < axisCount; ++i) {
-        // We sanity-check the axis info found in the CTFont, and bail out
-        // (returning null) if it doesn't have the expected types.
-        CFTypeRef axisInfo = CFArrayGetValueAtIndex(axes, i);
-        if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
-            return nullptr;
-        }
-        CFDictionaryRef axis = static_cast<CFDictionaryRef>(axisInfo);
-
-        CFTypeRef axisTag =
-            CFDictionaryGetValue(axis, kCTFontVariationAxisIdentifierKey);
-        if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) {
-            return nullptr;
-        }
-        int64_t tagLong;
-        if (!CFNumberGetValue(static_cast<CFNumberRef>(axisTag),
-                              kCFNumberSInt64Type, &tagLong)) {
-            return nullptr;
-        }
-
-        CFTypeRef axisName =
-            CFDictionaryGetValue(axis, kCTFontVariationAxisNameKey);
-        if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
-            return nullptr;
-        }
-
-        // Clamp axis values to the supported range.
-        CFTypeRef min = CFDictionaryGetValue(axis, kCTFontVariationAxisMinimumValueKey);
-        CFTypeRef max = CFDictionaryGetValue(axis, kCTFontVariationAxisMaximumValueKey);
-        CFTypeRef def = CFDictionaryGetValue(axis, kCTFontVariationAxisDefaultValueKey);
-        if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
-            !max || CFGetTypeID(max) != CFNumberGetTypeID() ||
-            !def || CFGetTypeID(def) != CFNumberGetTypeID()) {
-            return nullptr;
-        }
-        double minDouble;
-        double maxDouble;
-        double defDouble;
-        if (!CFNumberGetValue(static_cast<CFNumberRef>(min), kCFNumberDoubleType,
-                              &minDouble) ||
-            !CFNumberGetValue(static_cast<CFNumberRef>(max), kCFNumberDoubleType,
-                              &maxDouble) ||
-            !CFNumberGetValue(static_cast<CFNumberRef>(def), kCFNumberDoubleType,
-                              &defDouble)) {
-            return nullptr;
-        }
-
-        double value = defDouble;
-        for (uint32_t j = 0; j < numVars; ++j) {
-            if (aVariations[j].mTag == tagLong) {
-                value = std::min(std::max<double>(aVariations[j].mValue,
-                                                  minDouble),
-                                 maxDouble);
-                if (value != defDouble) {
-                    allDefaultValues = false;
-                }
-                break;
-            }
-        }
-        AutoRelease<CFNumberRef> valueNumber(CFNumberCreate(kCFAllocatorDefault,
-                                                            kCFNumberDoubleType,
-                                                            &value));
-        CFDictionaryAddValue(dict, axisName, valueNumber);
-    }
-
-    if (allDefaultValues) {
-        // We didn't actually set any non-default values, so throw away the
-        // variations dictionary and just use the default rendering.
-        return nullptr;
-    }
-
-    return dict.forget();
-}
-
 gfxMacFont::gfxMacFont(const RefPtr<UnscaledFontMac>& aUnscaledFont,
                        MacOSFontEntry *aFontEntry,
                        const gfxFontStyle *aFontStyle,
                        bool aNeedsBold)
     : gfxFont(aUnscaledFont, aFontEntry, aFontStyle),
       mCGFont(nullptr),
       mCTFont(nullptr),
       mFontFace(nullptr),
@@ -172,24 +36,26 @@ gfxMacFont::gfxMacFont(const RefPtr<Unsc
     mApplySyntheticBold = aNeedsBold;
 
     if (mVariationFont && aFontStyle->variationSettings.Length() > 0) {
         CGFontRef baseFont = aUnscaledFont->GetFont();
         if (!baseFont) {
             mIsValid = false;
             return;
         }
-        CFDictionaryRef variations =
-            CreateVariationDictionaryOrNull(baseFont, aFontStyle->variationSettings);
-        if (variations) {
-            mCGFont = ::CGFontCreateCopyWithVariations(baseFont, variations);
-            ::CFRelease(variations);
-        } else {
-            ::CFRetain(baseFont);
-            mCGFont = baseFont;
+        MOZ_ASSERT(sizeof(ScaledFont::VariationSetting) == sizeof(gfxFontVariation));
+        mCGFont =
+            UnscaledFontMac::CreateCGFontWithVariations(
+                baseFont,
+                aFontStyle->variationSettings.Length(),
+                reinterpret_cast<const ScaledFont::VariationSetting*>(
+                    aFontStyle->variationSettings.Elements()));
+        if (!mCGFont) {
+          ::CFRetain(baseFont);
+          mCGFont = baseFont;
         }
     } else {
         mCGFont = aUnscaledFont->GetFont();
         if (!mCGFont) {
             mIsValid = false;
             return;
         }
         ::CFRetain(mCGFont);
--- a/layout/printing/PrintTranslator.h
+++ b/layout/printing/PrintTranslator.h
@@ -22,16 +22,17 @@ namespace layout {
 using gfx::Translator;
 using gfx::ReferencePtr;
 using gfx::DrawTarget;
 using gfx::Path;
 using gfx::SourceSurface;
 using gfx::FilterNode;
 using gfx::GradientStops;
 using gfx::ScaledFont;
+using gfx::UnscaledFont;
 using gfx::NativeFontResource;
 
 class PrintTranslator final : public Translator
 {
 public:
   explicit PrintTranslator(nsDeviceContext* aDeviceContext);
 
   bool TranslateRecording(std::istream& aRecording);
@@ -73,16 +74,23 @@ public:
 
   ScaledFont* LookupScaledFont(ReferencePtr aRefPtr) final
   {
     ScaledFont* result = mScaledFonts.GetWeak(aRefPtr);
     MOZ_ASSERT(result);
     return result;
   }
 
+  UnscaledFont* LookupUnscaledFont(ReferencePtr aRefPtr) final
+  {
+    UnscaledFont* result = mUnscaledFonts.GetWeak(aRefPtr);
+    MOZ_ASSERT(result);
+    return result;
+  }
+
   NativeFontResource* LookupNativeFontResource(uint64_t aKey) final
   {
     NativeFontResource* result = mNativeFontResources.GetWeak(aKey);
     MOZ_ASSERT(result);
     return result;
   }
 
   void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget *aDT) final
@@ -110,16 +118,21 @@ public:
     mGradientStops.Put(aRefPtr, aStops);
   }
 
   void AddScaledFont(ReferencePtr aRefPtr, ScaledFont *aScaledFont) final
   {
     mScaledFonts.Put(aRefPtr, aScaledFont);
   }
 
+  void AddUnscaledFont(ReferencePtr aRefPtr, UnscaledFont* aUnscaledFont) final
+  {
+    mUnscaledFonts.Put(aRefPtr, aUnscaledFont);
+  }
+
   void AddNativeFontResource(uint64_t aKey,
                              NativeFontResource *aScaledFontResouce) final
   {
     mNativeFontResources.Put(aKey, aScaledFontResouce);
   }
 
   void RemoveDrawTarget(ReferencePtr aRefPtr) final
   {
@@ -146,16 +159,21 @@ public:
     mGradientStops.Remove(aRefPtr);
   }
 
   void RemoveScaledFont(ReferencePtr aRefPtr) final
   {
     mScaledFonts.Remove(aRefPtr);
   }
 
+  void RemoveUnscaledFont(ReferencePtr aRefPtr) final
+  {
+    mUnscaledFonts.Remove(aRefPtr);
+  }
+
   already_AddRefed<DrawTarget> CreateDrawTarget(ReferencePtr aRefPtr,
                                                 const gfx::IntSize &aSize,
                                                 gfx::SurfaceFormat aFormat) final;
 
   mozilla::gfx::DrawTarget* GetReferenceDrawTarget() final { return mBaseDT; }
 
   mozilla::gfx::FontType GetDesiredFontType() final;
 
@@ -164,15 +182,16 @@ private:
   RefPtr<DrawTarget> mBaseDT;
 
   nsRefPtrHashtable<nsPtrHashKey<void>, DrawTarget> mDrawTargets;
   nsRefPtrHashtable<nsPtrHashKey<void>, Path> mPaths;
   nsRefPtrHashtable<nsPtrHashKey<void>, SourceSurface> mSourceSurfaces;
   nsRefPtrHashtable<nsPtrHashKey<void>, FilterNode> mFilterNodes;
   nsRefPtrHashtable<nsPtrHashKey<void>, GradientStops> mGradientStops;
   nsRefPtrHashtable<nsPtrHashKey<void>, ScaledFont> mScaledFonts;
+  nsRefPtrHashtable<nsPtrHashKey<void>, UnscaledFont> mUnscaledFonts;
   nsRefPtrHashtable<nsUint64HashKey, NativeFontResource> mNativeFontResources;
 };
 
 } // namespace layout
 } // namespace mozilla
 
 #endif // mozilla_layout_PrintTranslator_h