Bug 1156742 Part 24: Add new Recorded event to record font data. r=bas
☠☠ backed out by 9bdfae920430 ☠ ☠
authorBob Owen <bobowencode@gmail.com>
Mon, 21 Dec 2015 20:33:14 +0000
changeset 277236 f08df57ff700640b9cc196b14044ba585c3cc63c
parent 277235 90c026d5dcb16cee4f024ff410fb8606ac214fff
child 277237 31c0aadae8e76c198b5e29a23b5cd346578f5b3c
push id29819
push usercbook@mozilla.com
push dateTue, 22 Dec 2015 10:47:17 +0000
treeherdermozilla-central@ad16863d1d45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs1156742
milestone46.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 1156742 Part 24: Add new Recorded event to record font data. r=bas We create and destroy ScaledFonts for every piece of text we write. That causes a huge amount of duplicated data within the recording. This splits out the recording of the font data itself from the ScaledFont. The key generated to determine uniqueness could probably be fairly easily faked, but for our purposes that doesn't matter.
gfx/2d/2D.h
gfx/2d/DrawEventRecorder.h
gfx/2d/DrawTargetRecording.cpp
gfx/2d/Factory.cpp
gfx/2d/NativeFontResourceDWrite.cpp
gfx/2d/NativeFontResourceDWrite.h
gfx/2d/NativeFontResourceGDI.cpp
gfx/2d/NativeFontResourceGDI.h
gfx/2d/RecordedEvent.cpp
gfx/2d/RecordedEvent.h
gfx/2d/SFNTData.cpp
gfx/2d/SFNTData.h
gfx/2d/ScaledFontDWrite.cpp
gfx/2d/ScaledFontDWrite.h
gfx/2d/ScaledFontWin.cpp
gfx/2d/ScaledFontWin.h
gfx/2d/moz.build
layout/printing/PrintTranslator.cpp
layout/printing/PrintTranslator.h
layout/printing/ipc/RemotePrintJobParent.cpp
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -662,16 +662,39 @@ public:
   }
 
 protected:
   ScaledFont() {}
 
   UserData mUserData;
 };
 
+/**
+ * Derived classes hold a native font resource from which to create
+ * 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.
+   *
+   * @param aIndex index for the font within the resource.
+   * @param aGlyphSize the size of ScaledFont required.
+   * @return an already_addrefed ScaledFont, containing nullptr if failed.
+   */
+  virtual already_AddRefed<ScaledFont>
+    CreateScaledFont(uint32_t aIndex, uint32_t aGlyphSize) = 0;
+
+  virtual ~NativeFontResource() {};
+};
+
 /** This class is designed to allow passing additional glyph rendering
  * parameters to the glyph drawing functions. This is an empty wrapper class
  * merely used to allow holding on to and passing around platform specific
  * parameters. This is because different platforms have unique rendering
  * parameters.
  */
 class GlyphRenderingOptions : public RefCounted<GlyphRenderingOptions>
 {
@@ -1187,26 +1210,25 @@ public:
 
   static already_AddRefed<DrawTarget>
     CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
 
   static already_AddRefed<ScaledFont>
     CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize);
 
   /**
-   * This creates a ScaledFont from TrueType data.
+   * This creates a NativeFontResource from TrueType data.
    *
    * @param aData Pointer to the data
    * @param aSize Size of the TrueType data
-   * @param aFaceIndex Index of the font face in the truetype data this ScaledFont needs to represent.
-   * @param aGlyphSize Size of the glyphs in this ScaledFont
-   * @param aType Type of ScaledFont that should be created.
+   * @param aType Type of NativeFontResource that should be created.
+   * @return a NativeFontResource of nullptr if failed.
    */
-  static already_AddRefed<ScaledFont>
-    CreateScaledFontForTrueTypeData(uint8_t *aData, uint32_t aSize, uint32_t aFaceIndex, Float aGlyphSize, FontType aType);
+  static already_AddRefed<NativeFontResource>
+    CreateNativeFontResource(uint8_t *aData, uint32_t aSize, FontType aType);
 
   /**
    * This creates a scaled font with an associated cairo_scaled_font_t, and
    * must be used when using the Cairo backend. The NativeFont and
    * cairo_scaled_font_t* parameters must correspond to the same font.
    */
   static already_AddRefed<ScaledFont>
     CreateScaledFontWithCairo(const NativeFont &aNativeFont, Float aSize, cairo_scaled_font_t* aScaledFont);
--- a/gfx/2d/DrawEventRecorder.h
+++ b/gfx/2d/DrawEventRecorder.h
@@ -41,28 +41,39 @@ public:
   void RemoveStoredObject(const ReferencePtr aObject) {
     mStoredObjects.erase(aObject);
   }
 
   bool HasStoredObject(const ReferencePtr aObject) {
     return mStoredObjects.find(aObject) != mStoredObjects.end();
   }
 
+  void AddStoredFontData(const uint64_t aFontDataKey) {
+    mStoredFontData.insert(aFontDataKey);
+  }
+
+  bool HasStoredFontData(const uint64_t aFontDataKey) {
+    return mStoredFontData.find(aFontDataKey) != mStoredFontData.end();
+  }
+
 protected:
   std::ostream *mOutputStream;
 
   virtual void Flush() = 0;
 
 #if defined(_MSC_VER)
   typedef std::unordered_set<const void*> ObjectSet;
+  typedef std::unordered_set<uint64_t> Uint64Set;
 #else
   typedef std::set<const void*> ObjectSet;
+  typedef std::set<uint64_t> Uint64Set;
 #endif
 
   ObjectSet mStoredObjects;
+  Uint64Set mStoredFontData;
 };
 
 class DrawEventRecorderFile : public DrawEventRecorderPrivate
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderFile)
   explicit DrawEventRecorderFile(const char *aFilename);
   ~DrawEventRecorderFile();
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -387,17 +387,25 @@ DrawTargetRecording::FillGlyphs(ScaledFo
                                 const DrawOptions &aOptions,
                                 const GlyphRenderingOptions *aRenderingOptions)
 {
   EnsurePatternDependenciesStored(aPattern);
 
   if (!aFont->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()))) {
   // TODO support font in b2g recordings
 #ifndef MOZ_WIDGET_GONK
-    mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, aFont));
+    RecordedFontData fontData(aFont);
+    RecordedFontDetails fontDetails;
+    if (fontData.GetFontDetails(fontDetails)) {
+      if (!mRecorder->HasStoredFontData(fontDetails.fontDataKey)) {
+        mRecorder->RecordEvent(fontData);
+        mRecorder->AddStoredFontData(fontDetails.fontDataKey);
+      }
+      mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, fontDetails));
+    }
 #endif
     RecordingFontUserData *userData = new RecordingFontUserData;
     userData->refPtr = aFont;
     userData->recorder = mRecorder;
     aFont->AddUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()), userData, 
                        &RecordingFontUserDataDestroyFunc);
   }
 
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -16,31 +16,33 @@
 #ifdef MOZ_ENABLE_FREETYPE
 #define USE_SKIA_FREETYPE
 #include "ScaledFontCairo.h"
 #endif
 #endif
 
 #if defined(WIN32)
 #include "ScaledFontWin.h"
+#include "NativeFontResourceGDI.h"
 #endif
 
 #ifdef XP_DARWIN
 #include "ScaledFontMac.h"
 #endif
 
 
 #ifdef XP_DARWIN
 #include "DrawTargetCG.h"
 #endif
 
 #ifdef WIN32
 #include "DrawTargetD2D.h"
 #include "DrawTargetD2D1.h"
 #include "ScaledFontDWrite.h"
+#include "NativeFontResourceDWrite.h"
 #include <d3d10_1.h>
 #include "HelpersD2D.h"
 #endif
 
 #include "DrawTargetDual.h"
 #include "DrawTargetTiled.h"
 #include "DrawTargetRecording.h"
 
@@ -535,51 +537,45 @@ Factory::CreateScaledFontForNativeFont(c
     }
 #endif
   default:
     gfxWarning() << "Invalid native font type specified.";
     return nullptr;
   }
 }
 
-already_AddRefed<ScaledFont>
-Factory::CreateScaledFontForTrueTypeData(uint8_t *aData, uint32_t aSize,
-                                         uint32_t aFaceIndex, Float aGlyphSize,
-                                         FontType aType)
+already_AddRefed<NativeFontResource>
+Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize,
+                                  FontType aType)
 {
   switch (aType) {
 #ifdef WIN32
   case FontType::DWRITE:
     {
-      return MakeAndAddRef<ScaledFontDWrite>(aData, aSize, aFaceIndex, aGlyphSize);
+      return NativeFontResourceDWrite::Create(aData, aSize,
+                                              /* aNeedsCairo = */ false);
     }
 #endif
   case FontType::CAIRO:
     {
-      RefPtr<ScaledFontBase> scaledFont;
-
 #ifdef WIN32
       if (GetDirect3D11Device()) {
-        scaledFont = new ScaledFontDWrite(aData, aSize, aFaceIndex, aGlyphSize);
+        return NativeFontResourceDWrite::Create(aData, aSize,
+                                                /* aNeedsCairo = */ true);
       } else {
-        scaledFont = new ScaledFontWin(aData, aSize, aFaceIndex, aGlyphSize);
-      }
-
-      if (!scaledFont->PopulateCairoScaledFont()) {
-        gfxWarning() << "Unable to create cairo scaled font from truetype data";
-        return nullptr;
+        return NativeFontResourceGDI::Create(aData, aSize,
+                                             /* aNeedsCairo = */ true);
       }
 #else
       gfxWarning() << "Unable to create cairo scaled font from truetype data";
+      return nullptr;
 #endif
-
-      return scaledFont.forget();
     }
   default:
-    gfxWarning() << "Unable to create requested font type from truetype data";
+    gfxWarning() << "Unable to create requested font resource from truetype data";
     return nullptr;
   }
 }
 
 already_AddRefed<ScaledFont>
 Factory::CreateScaledFontWithCairo(const NativeFont& aNativeFont, Float aSize, cairo_scaled_font_t* aScaledFont)
 {
 #ifdef USE_CAIRO
new file mode 100644
--- /dev/null
+++ b/gfx/2d/NativeFontResourceDWrite.cpp
@@ -0,0 +1,287 @@
+/* -*- 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 <unordered_map>
+
+#include "DrawTargetD2D.h"
+#include "Logging.h"
+#include "mozilla/RefPtr.h"
+
+namespace mozilla {
+namespace gfx {
+
+static Atomic<uint64_t> sNextFontFileKey;
+static std::unordered_map<uint64_t, IDWriteFontFileStream*> sFontFileStreams;
+
+class DWriteFontFileLoader : public IDWriteFontFileLoader
+{
+public:
+  DWriteFontFileLoader()
+  {
+  }
+
+  // IUnknown interface
+  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
+  {
+    if (iid == __uuidof(IDWriteFontFileLoader)) {
+      *ppObject = static_cast<IDWriteFontFileLoader*>(this);
+      return S_OK;
+    } else if (iid == __uuidof(IUnknown)) {
+      *ppObject = static_cast<IUnknown*>(this);
+      return S_OK;
+    } else {
+      return E_NOINTERFACE;
+    }
+  }
+
+  IFACEMETHOD_(ULONG, AddRef)()
+  {
+    return 1;
+  }
+
+  IFACEMETHOD_(ULONG, Release)()
+  {
+    return 1;
+  }
+
+  // IDWriteFontFileLoader methods
+  /**
+    * Important! Note the key here has to be a uint64_t that will have been
+    * generated by incrementing sNextFontFileKey.
+    */
+  virtual HRESULT STDMETHODCALLTYPE
+    CreateStreamFromKey(void const* fontFileReferenceKey,
+                        UINT32 fontFileReferenceKeySize,
+                        OUT IDWriteFontFileStream** fontFileStream);
+
+  /**
+    * Gets the singleton loader instance. Note that when using this font
+    * loader, the key must be a uint64_t that has been generated by incrementing
+    * sNextFontFileKey.
+    * Also note that this is _not_ threadsafe.
+    */
+  static IDWriteFontFileLoader* Instance()
+  {
+    if (!mInstance) {
+      mInstance = new DWriteFontFileLoader();
+      DrawTargetD2D::GetDWriteFactory()->
+          RegisterFontFileLoader(mInstance);
+    }
+    return mInstance;
+  }
+
+private:
+  static IDWriteFontFileLoader* mInstance;
+};
+
+class DWriteFontFileStream : public IDWriteFontFileStream
+{
+public:
+  /**
+    * Used by the FontFileLoader to create a new font stream,
+    * this font stream is created from data in memory. The memory
+    * passed may be released after object creation, it will be
+    * copied internally.
+    *
+    * @param aData Font data
+    */
+  DWriteFontFileStream(uint8_t *aData, uint32_t aSize, uint64_t aFontFileKey);
+  ~DWriteFontFileStream();
+
+  // IUnknown interface
+  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
+  {
+    if (iid == __uuidof(IDWriteFontFileStream)) {
+      *ppObject = static_cast<IDWriteFontFileStream*>(this);
+      return S_OK;
+    } else if (iid == __uuidof(IUnknown)) {
+      *ppObject = static_cast<IUnknown*>(this);
+      return S_OK;
+    } else {
+      return E_NOINTERFACE;
+    }
+  }
+
+  IFACEMETHOD_(ULONG, AddRef)()
+  {
+    ++mRefCnt;
+    return mRefCnt;
+  }
+
+  IFACEMETHOD_(ULONG, Release)()
+  {
+    --mRefCnt;
+    if (mRefCnt == 0) {
+      delete this;
+      return 0;
+    }
+    return mRefCnt;
+  }
+
+  // IDWriteFontFileStream methods
+  virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
+                                                     UINT64 fileOffset,
+                                                     UINT64 fragmentSize,
+                                                     OUT void** fragmentContext);
+
+  virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);
+
+  virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize);
+
+  virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);
+
+private:
+  std::vector<uint8_t> mData;
+  uint32_t mRefCnt;
+  uint64_t mFontFileKey;
+};
+
+IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = nullptr;
+
+HRESULT STDMETHODCALLTYPE
+DWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey,
+                                          UINT32 fontFileReferenceKeySize,
+                                          IDWriteFontFileStream **fontFileStream)
+{
+  if (!fontFileReferenceKey || !fontFileStream) {
+    return E_POINTER;
+  }
+
+  uint64_t fontFileKey = *static_cast<const uint64_t*>(fontFileReferenceKey);
+  auto found = sFontFileStreams.find(fontFileKey);
+  if (found == sFontFileStreams.end()) {
+    *fontFileStream = nullptr;
+    return E_FAIL;
+  }
+
+  found->second->AddRef();
+  *fontFileStream = found->second;
+  return S_OK;
+}
+
+DWriteFontFileStream::DWriteFontFileStream(uint8_t *aData, uint32_t aSize,
+                                           uint64_t aFontFileKey)
+  : mRefCnt(0)
+  , mFontFileKey(aFontFileKey)
+{
+  mData.resize(aSize);
+  memcpy(&mData.front(), aData, aSize);
+}
+
+DWriteFontFileStream::~DWriteFontFileStream()
+{
+  sFontFileStreams.erase(mFontFileKey);
+}
+
+HRESULT STDMETHODCALLTYPE
+DWriteFontFileStream::GetFileSize(UINT64 *fileSize)
+{
+  *fileSize = mData.size();
+  return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+DWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE
+DWriteFontFileStream::ReadFileFragment(const void **fragmentStart,
+                                       UINT64 fileOffset,
+                                       UINT64 fragmentSize,
+                                       void **fragmentContext)
+{
+  // We are required to do bounds checking.
+  if (fileOffset + fragmentSize > mData.size()) {
+    return E_FAIL;
+  }
+
+  // truncate the 64 bit fileOffset to size_t sized index into mData
+  size_t index = static_cast<size_t>(fileOffset);
+
+  // We should be alive for the duration of this.
+  *fragmentStart = &mData[index];
+  *fragmentContext = nullptr;
+  return S_OK;
+}
+
+void STDMETHODCALLTYPE
+DWriteFontFileStream::ReleaseFileFragment(void *fragmentContext)
+{
+}
+
+/* static */
+already_AddRefed<NativeFontResourceDWrite>
+NativeFontResourceDWrite::Create(uint8_t *aFontData, uint32_t aDataLength,
+                                 bool aNeedsCairo)
+{
+  IDWriteFactory *factory = DrawTargetD2D::GetDWriteFactory();
+  if (!factory) {
+    gfxWarning() << "Failed to get DWrite Factory.";
+    return nullptr;
+  }
+
+  uint64_t fontFileKey = sNextFontFileKey++;
+  RefPtr<IDWriteFontFileStream> ffsRef =
+    new DWriteFontFileStream(aFontData, aDataLength, fontFileKey);
+  sFontFileStreams[fontFileKey] = ffsRef;
+
+  RefPtr<IDWriteFontFile> fontFile;
+  HRESULT hr =
+    factory->CreateCustomFontFileReference(&fontFileKey, sizeof(fontFileKey),
+                                           DWriteFontFileLoader::Instance(),
+                                           getter_AddRefs(fontFile));
+  if (FAILED(hr)) {
+    gfxWarning() << "Failed to load font file from data!";
+    return nullptr;
+  }
+
+  BOOL isSupported;
+  DWRITE_FONT_FILE_TYPE fileType;
+  DWRITE_FONT_FACE_TYPE faceType;
+  UINT32 numberOfFaces;
+  hr = fontFile->Analyze(&isSupported, &fileType, &faceType, &numberOfFaces);
+  if (FAILED(hr) || !isSupported) {
+    gfxWarning() << "Font file is not supported.";
+    return nullptr;
+  }
+
+  RefPtr<NativeFontResourceDWrite> fontResource =
+    new NativeFontResourceDWrite(factory, fontFile.forget(), faceType,
+                                 numberOfFaces, aNeedsCairo);
+  return fontResource.forget();
+}
+
+already_AddRefed<ScaledFont>
+NativeFontResourceDWrite::CreateScaledFont(uint32_t aIndex, uint32_t aGlyphSize)
+{
+  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, aGlyphSize);
+  if (mNeedsCairo && !scaledFont->PopulateCairoScaledFont()) {
+    gfxWarning() << "Unable to create cairo scaled font DWrite font.";
+    return nullptr;
+  }
+
+  return scaledFont.forget();
+}
+
+} // gfx
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/2d/NativeFontResourceDWrite.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_gfx_NativeFontResourceDWrite_h
+#define mozilla_gfx_NativeFontResourceDWrite_h
+
+#include <dwrite.h>
+
+#include "2D.h"
+#include "mozilla/AlreadyAddRefed.h"
+
+namespace mozilla {
+namespace gfx {
+
+class NativeFontResourceDWrite final : public NativeFontResource
+{
+public:
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceDWrite)
+  /**
+   * Creates a NativeFontResourceDWrite 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 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, uint32_t aGlyphSize) 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)
+  {}
+
+  IDWriteFactory *mFactory;
+  RefPtr<IDWriteFontFile> mFontFile;
+  DWRITE_FONT_FACE_TYPE mFaceType;
+  uint32_t mNumberOfFaces;
+  bool mNeedsCairo;
+};
+
+} // gfx
+} // mozilla
+
+#endif // mozilla_gfx_NativeFontResourceDWrite_h
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/2d/NativeFontResourceGDI.cpp
@@ -0,0 +1,112 @@
+/* -*- 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 "NativeFontResourceGDI.h"
+
+#include "Logging.h"
+#include "mozilla/RefPtr.h"
+#include "ScaledFontWin.h"
+#include "SFNTData.h"
+
+namespace mozilla {
+namespace gfx {
+
+/* static */
+already_AddRefed<NativeFontResourceGDI>
+NativeFontResourceGDI::Create(uint8_t *aFontData, uint32_t aDataLength,
+                              bool aNeedsCairo)
+{
+  UniquePtr<SFNTData> sfntData = SFNTData::Create(aFontData, aDataLength);
+  if (!sfntData) {
+    gfxWarning() << "Failed to create SFNTData for ScaledFontWin.";
+    return nullptr;
+  }
+
+  Vector<mozilla::u16string> fontNames;
+  if (!sfntData->GetU16FullNames(fontNames)) {
+    gfxWarning() << "Failed to get font names from font.";
+    return nullptr;
+  }
+
+  // lfFaceName has a maximum length including null.
+  for (size_t i = 0; i < fontNames.length(); ++i) {
+    if (fontNames[i].size() > LF_FACESIZE - 1) {
+      fontNames[i].resize(LF_FACESIZE - 1);
+    }
+    // Add null to end for easy copying later.
+    fontNames[i].append(1, '\0');
+  }
+
+  DWORD numberOfFontsAdded;
+  HANDLE fontResourceHandle = ::AddFontMemResourceEx(aFontData, aDataLength,
+                                                     0, &numberOfFontsAdded);
+  if (!fontResourceHandle) {
+    gfxWarning() << "Failed to add memory font resource.";
+    return nullptr;
+  }
+
+  if (numberOfFontsAdded != fontNames.length()) {
+    gfxWarning() <<
+      "Number of fonts added doesn't match number of names extracted.";
+  }
+
+  RefPtr<NativeFontResourceGDI> fontResouce =
+    new NativeFontResourceGDI(fontResourceHandle, Move(fontNames), aNeedsCairo);
+
+  return fontResouce.forget();
+}
+
+NativeFontResourceGDI::~NativeFontResourceGDI()
+{
+  ::RemoveFontMemResourceEx(mFontResourceHandle);
+}
+
+already_AddRefed<ScaledFont>
+NativeFontResourceGDI::CreateScaledFont(uint32_t aIndex, uint32_t aGlyphSize)
+{
+  if (aIndex >= mFontNames.length()) {
+    gfxWarning() << "Font index is too high for font resource.";
+    return nullptr;
+  }
+
+  if (mFontNames[aIndex].empty()) {
+    gfxWarning() << "Font name for index is empty.";
+    return nullptr;
+  }
+
+  LOGFONT logFont;
+  logFont.lfHeight = 0;
+  logFont.lfWidth = 0;
+  logFont.lfEscapement = 0;
+  logFont.lfOrientation = 0;
+  logFont.lfWeight = FW_DONTCARE;
+  logFont.lfItalic = FALSE;
+  logFont.lfUnderline = FALSE;
+  logFont.lfStrikeOut = FALSE;
+  logFont.lfCharSet = DEFAULT_CHARSET;
+  logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
+  logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+  logFont.lfQuality = DEFAULT_QUALITY;
+  logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
+  // Copy name to mLogFont (null already included in font name). We cast here
+  // because for VS2015 char16_t != wchar_t, even though they are both 16 bit.
+  mFontNames[aIndex].copy(reinterpret_cast<char16_t*>(logFont.lfFaceName),
+                          mFontNames[aIndex].length());
+
+  // Constructor for ScaledFontWin dereferences and copies the LOGFONT, so we
+  // are safe to pass this reference.
+  RefPtr<ScaledFontBase> scaledFont = new ScaledFontWin(&logFont, aGlyphSize);
+  if (mNeedsCairo && !scaledFont->PopulateCairoScaledFont()) {
+    gfxWarning() << "Unable to create cairo scaled font DWrite font.";
+    return nullptr;
+  }
+
+  return scaledFont.forget();
+}
+
+} // gfx
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/2d/NativeFontResourceGDI.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_gfx_NativeFontResourceGDI_h
+#define mozilla_gfx_NativeFontResourceGDI_h
+
+#include <windows.h>
+
+#include "2D.h"
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/Vector.h"
+#include "u16string.h"
+
+namespace mozilla {
+namespace gfx {
+
+class NativeFontResourceGDI final : public NativeFontResource
+{
+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);
+
+  ~NativeFontResourceGDI();
+
+  already_AddRefed<ScaledFont>
+    CreateScaledFont(uint32_t aIndex, uint32_t aGlyphSize) final;
+
+private:
+  NativeFontResourceGDI(HANDLE aFontResourceHandle,
+                        Vector<mozilla::u16string>&& aFontNames,
+                        bool aNeedsCairo)
+    : mFontResourceHandle(aFontResourceHandle), mFontNames(Move(aFontNames))
+    , mNeedsCairo(aNeedsCairo)
+  {}
+
+  HANDLE mFontResourceHandle;
+  Vector<mozilla::u16string> mFontNames;
+  bool mNeedsCairo;
+};
+
+} // gfx
+} // mozilla
+
+#endif // mozilla_gfx_NativeFontResourceGDI_h
\ No newline at end of file
--- a/gfx/2d/RecordedEvent.cpp
+++ b/gfx/2d/RecordedEvent.cpp
@@ -5,16 +5,17 @@
 
 #include "RecordedEvent.h"
 
 #include "PathRecording.h"
 #include "RecordingTypes.h"
 #include "Tools.h"
 #include "Filters.h"
 #include "Logging.h"
+#include "SFNTData.h"
 
 namespace mozilla {
 namespace gfx {
 
 using namespace std;
 
 static std::string NameFromBackend(BackendType aType)
 {
@@ -73,16 +74,17 @@ RecordedEvent::LoadEventFromStream(std::
     LOAD_EVENT_TYPE(GRADIENTSTOPSDESTRUCTION, RecordedGradientStopsDestruction);
     LOAD_EVENT_TYPE(SNAPSHOT, RecordedSnapshot);
     LOAD_EVENT_TYPE(SCALEDFONTCREATION, RecordedScaledFontCreation);
     LOAD_EVENT_TYPE(SCALEDFONTDESTRUCTION, RecordedScaledFontDestruction);
     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);
   default:
     return nullptr;
   }
 }
 
 string
 RecordedEvent::GetEventName(EventType aType)
 {
@@ -148,16 +150,18 @@ RecordedEvent::GetEventName(EventType aT
   case MASKSURFACE:
     return "MaskSurface";
   case FILTERNODESETATTRIBUTE:
     return "SetAttribute";
   case FILTERNODESETINPUT:
     return "SetInput";
   case CREATESIMILARDRAWTARGET:
     return "CreateSimilarDrawTarget";
+  case FONTDATA:
+    return "FontData";
   default:
     return "Unknown";
   }
 }
 
 void
 RecordedEvent::RecordPatternData(std::ostream &aStream, const PatternStorage &aPattern) const
 {
@@ -1382,71 +1386,110 @@ RecordedSnapshot::RecordedSnapshot(istre
 }
 
 void
 RecordedSnapshot::OutputSimpleEventInfo(stringstream &aStringStream) const
 {
   aStringStream << "[" << mRefPtr << "] Snapshot Created (DT: " << mDT << ")";
 }
 
-RecordedScaledFontCreation::~RecordedScaledFontCreation()
+RecordedFontData::~RecordedFontData()
+{
+  delete[] mData;
+}
+
+void
+RecordedFontData::PlayEvent(Translator *aTranslator) const
+{
+  RefPtr<NativeFontResource> fontResource =
+    Factory::CreateNativeFontResource(mData, mFontDetails.size,
+                                      aTranslator->GetDesiredFontType());
+  aTranslator->AddNativeFontResource(mFontDetails.fontDataKey, fontResource);
+}
+
+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);
+}
+
+void
+RecordedFontData::OutputSimpleEventInfo(stringstream &aStringStream) const
 {
-  delete [] mData;
+  aStringStream << "Font Data of size " << mFontDetails.size;
+}
+
+void
+RecordedFontData::SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize)
+{
+  mData = new uint8_t[aSize];
+  memcpy(mData, aData, aSize);
+  mFontDetails.fontDataKey = SFNTData::GetUniqueKey(aData, aSize);
+  mFontDetails.size = aSize;
+  mFontDetails.index = aIndex;
+  mFontDetails.glyphSize = aGlyphSize;
+}
+
+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;
+  return true;
+}
+
+RecordedFontData::RecordedFontData(istream &aStream)
+  : RecordedEvent(FONTDATA)
+{
+  ReadElement(aStream, mFontDetails.fontDataKey);
+  ReadElement(aStream, mFontDetails.size);
+  mData = new uint8_t[mFontDetails.size];
+  aStream.read((char*)mData, mFontDetails.size);
 }
 
 void
 RecordedScaledFontCreation::PlayEvent(Translator *aTranslator) const
 {
-  RefPtr<ScaledFont> scaledFont =
-    Factory::CreateScaledFontForTrueTypeData(mData, mSize, mIndex, mGlyphSize,
-                                             aTranslator->GetDesiredFontType());
+  NativeFontResource *fontResource = aTranslator->LookupNativeFontResource(mFontDataKey);
+  RefPtr<ScaledFont> scaledFont = fontResource->CreateScaledFont(mIndex, mGlyphSize);
   aTranslator->AddScaledFont(mRefPtr, scaledFont);
 }
 
 void
 RecordedScaledFontCreation::RecordToStream(std::ostream &aStream) const
 {
-  if (!mGetFontFileDataSucceeded) {
-    gfxWarning()
-      << "Unable to record ScaledFont creation as no data was retrieved.";
-    return;
-  }
-
   WriteElement(aStream, mRefPtr);
+  WriteElement(aStream, mFontDataKey);
   WriteElement(aStream, mIndex);
   WriteElement(aStream, mGlyphSize);
-  WriteElement(aStream, mSize);
-  aStream.write((const char*)mData, mSize);
 }
 
 void
 RecordedScaledFontCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
 {
   aStringStream << "[" << mRefPtr << "] ScaledFont Created";
 }
 
-void
-RecordedScaledFontCreation::SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize)
-{
-  mData = new uint8_t[aSize];
-  memcpy(mData, aData, aSize);
-  mSize = aSize;
-  mIndex = aIndex;
-  mGlyphSize = aGlyphSize;
-}
-
 RecordedScaledFontCreation::RecordedScaledFontCreation(istream &aStream)
   : RecordedEvent(SCALEDFONTCREATION)
 {
   ReadElement(aStream, mRefPtr);
+  ReadElement(aStream, mFontDataKey);
   ReadElement(aStream, mIndex);
   ReadElement(aStream, mGlyphSize);
-  ReadElement(aStream, mSize);
-  mData = new uint8_t[mSize];
-  aStream.read((char*)mData, mSize);
 }
 
 void
 RecordedScaledFontDestruction::PlayEvent(Translator *aTranslator) const
 {
   aTranslator->RemoveScaledFont(mRefPtr);
 }
 
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -57,16 +57,24 @@ struct ReferencePtr
 
   operator void*() const {
     return (void*)mLongPtr;
   }
 
   uint64_t mLongPtr;
 };
 
+struct RecordedFontDetails
+{
+  uint64_t fontDataKey;
+  uint32_t size;
+  uint32_t index;
+  Float glyphSize;
+};
+
 // Used by the Azure drawing debugger (player2d)
 inline std::string StringFromPtr(ReferencePtr aPtr)
 {
   std::stringstream stream;
   stream << aPtr;
   return stream.str();
 }
 
@@ -76,28 +84,31 @@ 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 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 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;
 };
 
@@ -174,17 +185,18 @@ public:
     SCALEDFONTCREATION,
     SCALEDFONTDESTRUCTION,
     MASKSURFACE,
     FILTERNODECREATION,
     FILTERNODEDESTRUCTION,
     DRAWFILTER,
     FILTERNODESETATTRIBUTE,
     FILTERNODESETINPUT,
-    CREATESIMILARDRAWTARGET
+    CREATESIMILARDRAWTARGET,
+    FONTDATA,
   };
   static const uint32_t kTotalEventTypes = RecordedEvent::FILTERNODESETINPUT + 1;
 
   virtual ~RecordedEvent() {}
 
   static std::string GetEventName(EventType aType);
 
   virtual void PlayEvent(Translator *aTranslator) const {}
@@ -932,50 +944,84 @@ private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
   ReferencePtr mDT;
 
   MOZ_IMPLICIT RecordedSnapshot(std::istream &aStream);
 };
 
-class RecordedScaledFontCreation : public RecordedEvent {
+class RecordedFontData : public RecordedEvent {
 public:
-  static void FontDataProc(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize, void* aBaton)
+
+  static void FontDataProc(const uint8_t *aData, uint32_t aSize,
+                           uint32_t aIndex, Float aGlyphSize, void* aBaton)
   {
-    static_cast<RecordedScaledFontCreation*>(aBaton)->SetFontData(aData, aSize, aIndex, aGlyphSize);
+    auto recordedFontData = static_cast<RecordedFontData*>(aBaton);
+    recordedFontData->SetFontData(aData, aSize, aIndex, aGlyphSize);
   }
 
-  RecordedScaledFontCreation(ReferencePtr aRefPtr, ScaledFont *aScaledFont)
-    : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aRefPtr), mData(nullptr)
+  explicit RecordedFontData(ScaledFont *aScaledFont)
+    : RecordedEvent(FONTDATA), mData(nullptr)
   {
     mGetFontFileDataSucceeded = aScaledFont->GetFontFileData(&FontDataProc, this);
   }
 
-  ~RecordedScaledFontCreation();
+  ~RecordedFontData();
+
+  virtual void 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);
+
+  bool GetFontDetails(RecordedFontDetails& fontDetails);
+
+private:
+  friend class RecordedEvent;
+
+  uint8_t *mData;
+  RecordedFontDetails mFontDetails;
+
+  bool mGetFontFileDataSucceeded = false;
+
+  MOZ_IMPLICIT RecordedFontData(std::istream &aStream);
+};
+
+class RecordedScaledFontCreation : public RecordedEvent {
+public:
+
+  RecordedScaledFontCreation(ReferencePtr aRefPtr,
+                             RecordedFontDetails aFontDetails)
+    : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aRefPtr)
+    , mFontDataKey(aFontDetails.fontDataKey)
+    , mGlyphSize(aFontDetails.glyphSize) , mIndex(aFontDetails.index)
+  {
+  }
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "ScaledFont Creation"; }
   virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 
-  void SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize);
-
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
-  uint8_t *mData;
-  uint32_t mSize;
+  uint64_t mFontDataKey;
   Float mGlyphSize;
   uint32_t mIndex;
-  bool mGetFontFileDataSucceeded = false;
 
   MOZ_IMPLICIT RecordedScaledFontCreation(std::istream &aStream);
 };
 
 class RecordedScaledFontDestruction : public RecordedEvent {
 public:
   MOZ_IMPLICIT RecordedScaledFontDestruction(ReferencePtr aRefPtr)
     : RecordedEvent(SCALEDFONTDESTRUCTION), mRefPtr(aRefPtr)
--- a/gfx/2d/SFNTData.cpp
+++ b/gfx/2d/SFNTData.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SFNTData.h"
 
 #include <algorithm>
 
 #include "BigEndianInts.h"
 #include "Logging.h"
+#include "mozilla/HashFunctions.h"
 #include "SFNTNameTable.h"
 
 namespace mozilla {
 namespace gfx {
 
 #define TRUETYPE_TAG(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
 
 #pragma pack(push, 1)
@@ -111,25 +112,25 @@ private:
 UniquePtr<SFNTData>
 SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength)
 {
   MOZ_ASSERT(aFontData);
 
   // Check to see if this is a font collection.
   if (aDataLength < sizeof(TTCHeader)) {
     gfxWarning() << "Font data too short.";
-    return false;
+    return nullptr;
   }
 
   const TTCHeader *ttcHeader = reinterpret_cast<const TTCHeader*>(aFontData);
   if (ttcHeader->ttcTag == TRUETYPE_TAG('t', 't', 'c', 'f')) {
     uint32_t numFonts = ttcHeader->numFonts;
     if (aDataLength < sizeof(TTCHeader) + (numFonts * sizeof(BigEndianUint32))) {
       gfxWarning() << "Font data too short to contain full TTC Header.";
-      return false;
+      return nullptr;
     }
 
     UniquePtr<SFNTData> sfntData(new SFNTData);
     const BigEndianUint32* offset =
       reinterpret_cast<const BigEndianUint32*>(aFontData + sizeof(TTCHeader));
     const BigEndianUint32* endOfOffsets = offset + numFonts;
     while (offset != endOfOffsets) {
       if (!sfntData->AddFont(aFontData, aDataLength, *offset)) {
@@ -144,16 +145,33 @@ SFNTData::Create(const uint8_t *aFontDat
   UniquePtr<SFNTData> sfntData(new SFNTData);
   if (!sfntData->AddFont(aFontData, aDataLength, 0)) {
     return nullptr;
   }
 
   return Move(sfntData);
 }
 
+/* static */
+uint64_t
+SFNTData::GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength)
+{
+  uint64_t hash;
+  UniquePtr<SFNTData> sfntData = SFNTData::Create(aFontData, aDataLength);
+  mozilla::u16string firstName;
+  if (sfntData && sfntData->GetU16FullName(0, firstName)) {
+    hash = HashString(firstName.c_str(), firstName.length());
+  } else {
+    gfxWarning() << "Failed to get name from font data hashing whole font.";
+    hash = HashString(aFontData, aDataLength);
+  }
+
+  return hash << 32 | aDataLength;;
+}
+
 SFNTData::~SFNTData()
 {
   for (size_t i = 0; i < mFonts.length(); ++i) {
     delete mFonts[i];
   }
 }
 
 bool
@@ -163,16 +181,31 @@ SFNTData::GetU16FullName(uint32_t aIndex
     gfxWarning() << "aIndex to font data too high.";
     return false;
   }
 
   return mFonts[aIndex]->GetU16FullName(aU16FullName);
 }
 
 bool
+SFNTData::GetU16FullNames(Vector<mozilla::u16string>& aU16FullNames)
+{
+  bool fontFound = false;
+  for (size_t i = 0; i < mFonts.length(); ++i) {
+    mozilla::u16string name;
+    if (mFonts[i]->GetU16FullName(name)) {
+      fontFound = true;
+    }
+    aU16FullNames.append(Move(name));
+  }
+
+  return fontFound;
+}
+
+bool
 SFNTData::GetIndexForU16Name(const mozilla::u16string& aU16FullName,
                              uint32_t* aIndex)
 {
   for (size_t i = 0; i < mFonts.length(); ++i) {
     mozilla::u16string name;
     if (mFonts[i]->GetU16FullName(name) && name == aU16FullName) {
       *aIndex = i;
       return true;
--- a/gfx/2d/SFNTData.h
+++ b/gfx/2d/SFNTData.h
@@ -25,32 +25,52 @@ public:
    *
    * @param aFontData the SFNT data.
    * @param aDataLength length
    * @return UniquePtr to a SFNTData or nullptr if the header is invalid.
    */
   static UniquePtr<SFNTData> Create(const uint8_t *aFontData,
                                     uint32_t aDataLength);
 
+  /**
+   * Creates a unique key for the given font data.
+   *
+   * @param aFontData the SFNT data
+   * @param aDataLength length
+   * @return unique key to be used for caching
+   */
+  static uint64_t GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength);
+
   ~SFNTData();
 
   /**
    * Gets the full name from the name table of the font corresponding to the
    * index. If the full name string is not present it will use the family space
    * concatenated with the style.
    * This will only read names that are already UTF16.
    *
    * @param aFontData SFNT data.
    * @param aDataLength length of aFontData.
    * @param aU16FullName string to be populated with the full name.
    * @return true if the full name is successfully read.
    */
   bool GetU16FullName(uint32_t aIndex, mozilla::u16string& aU16FullName);
 
   /**
+   * Populate a Vector with the first UTF16 full name from each name table of
+   * the fonts. If the full name string is not present it will use the family
+   * space concatenated with the style.
+   * This will only read names that are already UTF16.
+   *
+   * @param aU16FullNames the Vector to be populated.
+   * @return true if at least one name found otherwise false.
+   */
+  bool GetU16FullNames(Vector<mozilla::u16string>& aU16FullNames);
+
+  /**
    * Returns the index for the first UTF16 name matching aU16FullName.
    *
    * @param aU16FullName full name to find.
    * @param aIndex out param for the index if found.
    * @return true if the full name is successfully read.
    */
   bool GetIndexForU16Name(const mozilla::u16string& aU16FullName, uint32_t* aIndex);
 
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -1,153 +1,25 @@
 /* -*- 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 "ScaledFontDWrite.h"
 #include "PathD2D.h"
-#include "DrawTargetD2D.h"
-#include "Logging.h"
 
 #include <vector>
-#include <unordered_map>
 
 #ifdef USE_CAIRO_SCALED_FONT
 #include "cairo-win32.h"
 #endif
 
 namespace mozilla {
 namespace gfx {
 
-static Atomic<uint64_t> sNextFontFileKey;
-static std::unordered_map<uint64_t, IDWriteFontFileStream*> sFontFileStreams;
-
-class DWriteFontFileLoader : public IDWriteFontFileLoader
-{
-public:
-  DWriteFontFileLoader()
-  {
-  }
-
-  // IUnknown interface
-  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
-  {
-    if (iid == __uuidof(IDWriteFontFileLoader)) {
-      *ppObject = static_cast<IDWriteFontFileLoader*>(this);
-      return S_OK;
-    } else if (iid == __uuidof(IUnknown)) {
-      *ppObject = static_cast<IUnknown*>(this);
-      return S_OK;
-    } else {
-      return E_NOINTERFACE;
-    }
-  }
-
-  IFACEMETHOD_(ULONG, AddRef)()
-  {
-    return 1;
-  }
-
-  IFACEMETHOD_(ULONG, Release)()
-  {
-    return 1;
-  }
-
-  // IDWriteFontFileLoader methods
-  /**
-    * Important! Note the key here -has- to be a pointer to an
-    * ffReferenceKey object.
-    */
-  virtual HRESULT STDMETHODCALLTYPE 
-    CreateStreamFromKey(void const* fontFileReferenceKey,
-                        UINT32 fontFileReferenceKeySize,
-                        OUT IDWriteFontFileStream** fontFileStream);
-
-  /**
-    * Gets the singleton loader instance. Note that when using this font
-    * loader, the key must be a pointer to an FallibleTArray<uint8_t>. This
-    * array will be empty when the function returns.
-    */
-  static IDWriteFontFileLoader* Instance()
-  {
-    if (!mInstance) {
-      mInstance = new DWriteFontFileLoader();
-      DrawTargetD2D::GetDWriteFactory()->
-          RegisterFontFileLoader(mInstance);
-    }
-    return mInstance;
-  }
-
-private:
-  static IDWriteFontFileLoader* mInstance;
-}; 
-
-class DWriteFontFileStream : public IDWriteFontFileStream
-{
-public:
-  /**
-    * Used by the FontFileLoader to create a new font stream,
-    * this font stream is created from data in memory. The memory
-    * passed may be released after object creation, it will be
-    * copied internally.
-    *
-    * @param aData Font data
-    */
-  DWriteFontFileStream(uint8_t *aData, uint32_t aSize, uint64_t aFontFileKey);
-  ~DWriteFontFileStream();
-
-  // IUnknown interface
-  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
-  {
-    if (iid == __uuidof(IDWriteFontFileStream)) {
-      *ppObject = static_cast<IDWriteFontFileStream*>(this);
-      return S_OK;
-    } else if (iid == __uuidof(IUnknown)) {
-      *ppObject = static_cast<IUnknown*>(this);
-      return S_OK;
-    } else {
-      return E_NOINTERFACE;
-    }
-  }
-
-  IFACEMETHOD_(ULONG, AddRef)()
-  {
-    ++mRefCnt;
-    return mRefCnt;
-  }
-
-  IFACEMETHOD_(ULONG, Release)()
-  {
-    --mRefCnt;
-    if (mRefCnt == 0) {
-      delete this;
-      return 0;
-    }
-    return mRefCnt;
-  }
-
-  // IDWriteFontFileStream methods
-  virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
-                                                     UINT64 fileOffset,
-                                                     UINT64 fragmentSize,
-                                                     OUT void** fragmentContext);
-
-  virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);
-
-  virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize);
-
-  virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);
-
-private:
-  std::vector<uint8_t> mData;
-  uint32_t mRefCnt;
-  uint64_t mFontFileKey;
-};
-
 static BYTE
 GetSystemTextQuality()
 {
   BOOL font_smoothing;
   UINT smoothing_type;
 
   if (!SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
     return DEFAULT_QUALITY;
@@ -211,135 +83,16 @@ DoGrayscale(IDWriteFontFace *aDWFace, Fl
         break;
       }
     }
     aDWFace->ReleaseFontTable(tableContext);
   }
   return true;
 }
 
-IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = nullptr;
-
-HRESULT STDMETHODCALLTYPE
-DWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey, 
-                                          UINT32 fontFileReferenceKeySize, 
-                                          IDWriteFontFileStream **fontFileStream)
-{
-  if (!fontFileReferenceKey || !fontFileStream) {
-    return E_POINTER;
-  }
-
-  uint64_t fontFileKey = *static_cast<const uint64_t*>(fontFileReferenceKey);
-  auto found = sFontFileStreams.find(fontFileKey);
-  if (found == sFontFileStreams.end()) {
-    *fontFileStream = nullptr;
-    return E_FAIL;
-  }
-
-  found->second->AddRef();
-  *fontFileStream = found->second;
-  return S_OK;
-}
-
-DWriteFontFileStream::DWriteFontFileStream(uint8_t *aData, uint32_t aSize,
-                                           uint64_t aFontFileKey)
-  : mRefCnt(0)
-  , mFontFileKey(aFontFileKey)
-{
-  mData.resize(aSize);
-  memcpy(&mData.front(), aData, aSize);
-}
-
-DWriteFontFileStream::~DWriteFontFileStream()
-{
-  sFontFileStreams.erase(mFontFileKey);
-}
-
-HRESULT STDMETHODCALLTYPE
-DWriteFontFileStream::GetFileSize(UINT64 *fileSize)
-{
-  *fileSize = mData.size();
-  return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE
-DWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
-{
-  return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE
-DWriteFontFileStream::ReadFileFragment(const void **fragmentStart,
-                                       UINT64 fileOffset,
-                                       UINT64 fragmentSize,
-                                       void **fragmentContext)
-{
-  // We are required to do bounds checking.
-  if (fileOffset + fragmentSize > mData.size()) {
-    return E_FAIL;
-  }
-
-  // truncate the 64 bit fileOffset to size_t sized index into mData
-  size_t index = static_cast<size_t>(fileOffset);
-
-  // We should be alive for the duration of this.
-  *fragmentStart = &mData[index];
-  *fragmentContext = nullptr;
-  return S_OK;
-}
-
-void STDMETHODCALLTYPE
-DWriteFontFileStream::ReleaseFileFragment(void *fragmentContext)
-{
-}
-
-ScaledFontDWrite::ScaledFontDWrite(uint8_t *aData, uint32_t aSize,
-                                   uint32_t aIndex, Float aGlyphSize)
-  : ScaledFontBase(aGlyphSize)
-{
-  IDWriteFactory *factory = DrawTargetD2D::GetDWriteFactory();
-
-  uint64_t fontFileKey = sNextFontFileKey++;
-  sFontFileStreams[fontFileKey] =
-    new DWriteFontFileStream(aData, aSize, fontFileKey);
-  RefPtr<IDWriteFontFileStream> ffsRef = sFontFileStreams[fontFileKey];
-
-  RefPtr<IDWriteFontFile> fontFile;
-  if (FAILED(factory->CreateCustomFontFileReference(&fontFileKey, sizeof(fontFileKey), DWriteFontFileLoader::Instance(), getter_AddRefs(fontFile)))) {
-    gfxWarning() << "Failed to load font file from data!";
-    return;
-  }
-
-  BOOL isSupported;
-  DWRITE_FONT_FILE_TYPE fileType;
-  DWRITE_FONT_FACE_TYPE faceType;
-  UINT32 numberOfFaces;
-  fontFile->Analyze(&isSupported, &fileType, &faceType, &numberOfFaces);
-  if (!isSupported) {
-    gfxWarning() << "Font file is not supported.";
-    return;
-  }
-
-  if (aIndex >= numberOfFaces) {
-    gfxWarning() << "Font face index is greater than number of fonts in file.";
-    return;
-  }
-
-  IDWriteFontFile *ff = fontFile;
-  if (FAILED(factory->CreateFontFace(faceType, 1, &ff, aIndex, DWRITE_FONT_SIMULATIONS_NONE, getter_AddRefs(mFontFace)))) {
-    gfxWarning() << "Failed to create font face from font file data!";
-    return;
-  }
-
-  // Now that we've successfully created the font take ownership of the
-  // reference, so that we know that the font file stream will be around if
-  // someone calls GetFontFileData.
-  mFontFileStream = ffsRef.forget();
-}
-
 already_AddRefed<Path>
 ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
 {
   if (aTarget->GetBackendType() != BackendType::DIRECT2D && aTarget->GetBackendType() != BackendType::DIRECT2D1_1) {
     return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget);
   }
 
   RefPtr<PathBuilder> pathBuilder = aTarget->CreatePathBuilder();
--- a/gfx/2d/ScaledFontDWrite.h
+++ b/gfx/2d/ScaledFontDWrite.h
@@ -17,17 +17,16 @@ namespace gfx {
 class ScaledFontDWrite final : public ScaledFontBase
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontDwrite)
   ScaledFontDWrite(IDWriteFontFace *aFont, Float aSize)
     : ScaledFontBase(aSize)
     , mFontFace(aFont)
   {}
-  ScaledFontDWrite(uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize);
 
   virtual FontType GetType() const { return FontType::DWRITE; }
 
   virtual already_AddRefed<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
   virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint);
 
   void CopyGlyphsToSink(const GlyphBuffer &aBuffer, ID2D1GeometrySink *aSink);
 
@@ -44,19 +43,16 @@ public:
 #endif
 
   RefPtr<IDWriteFontFace> mFontFace;
 
 protected:
 #ifdef USE_CAIRO_SCALED_FONT
   cairo_font_face_t* GetCairoFontFace() override;
 #endif
-
-private:
-  RefPtr<IDWriteFontFileStream> mFontFileStream;
 };
 
 class GlyphRenderingOptionsDWrite : public GlyphRenderingOptions
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptionsDWrite)
   GlyphRenderingOptionsDWrite(IDWriteRenderingParams *aParams)
     : mParams(aParams)
--- a/gfx/2d/ScaledFontWin.cpp
+++ b/gfx/2d/ScaledFontWin.cpp
@@ -1,15 +1,14 @@
 /* -*- 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 "ScaledFontBase.h"
 
 #include "AutoHelpersWin.h"
 #include "Logging.h"
 #include "SFNTData.h"
 
 #ifdef USE_SKIA
 #include "skia/include/ports/SkTypeface_win.h"
 #endif
@@ -22,67 +21,16 @@ namespace mozilla {
 namespace gfx {
 
 ScaledFontWin::ScaledFontWin(LOGFONT* aFont, Float aSize)
   : ScaledFontBase(aSize)
   , mLogFont(*aFont)
 {
 }
 
-ScaledFontWin::ScaledFontWin(uint8_t* aFontData, uint32_t aFontDataLength,
-                             uint32_t aIndex, Float aGlyphSize)
-  : ScaledFontBase(aGlyphSize)
-{
-  mLogFont.lfHeight = 0;
-  mLogFont.lfWidth = 0;
-  mLogFont.lfEscapement = 0;
-  mLogFont.lfOrientation = 0;
-  mLogFont.lfWeight = FW_DONTCARE;
-  mLogFont.lfItalic = FALSE;
-  mLogFont.lfUnderline = FALSE;
-  mLogFont.lfStrikeOut = FALSE;
-  mLogFont.lfCharSet = DEFAULT_CHARSET;
-  mLogFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
-  mLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
-  mLogFont.lfQuality = DEFAULT_QUALITY;
-  mLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
-  mLogFont.lfFaceName[0] = 0;
-
-  UniquePtr<SFNTData> sfntData = SFNTData::Create(aFontData, aFontDataLength);
-  if (!sfntData) {
-    gfxWarning() << "Failed to create SFNTData for ScaledFontWin.";
-    return;
-  }
-
-  mozilla::u16string fontName;
-  if (!sfntData->GetU16FullName(aIndex, fontName)) {
-    gfxWarning() << "Failed to get font name from font.";
-    return;
-  }
-
-  // Copy name to mLogFont and add null to end.
-  // lfFaceName has a maximum length including null.
-  if (fontName.size() > LF_FACESIZE - 1) {
-    fontName.resize(LF_FACESIZE - 1);
-  }
-  // We cast here because for VS2015 char16_t != wchar_t, even though they are
-  // both 16 bit.
-  fontName.copy(reinterpret_cast<char16_t*>(mLogFont.lfFaceName),
-                fontName.length());
-  mLogFont.lfFaceName[fontName.length()] = 0;
-
-  DWORD numberOfFontsAdded;
-  HANDLE fontHandle = ::AddFontMemResourceEx(aFontData, aFontDataLength, 0,
-                                             &numberOfFontsAdded);
-  if (fontHandle) {
-    mMemoryFontRemover.reset(new MemoryFontRemover(fontHandle));
-  }
-
-}
-
 bool
 ScaledFontWin::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
 {
   AutoDC dc;
   AutoSelectFont font(dc.GetDC(), &mLogFont);
 
   // Check for a font collection first.
   uint32_t table = 0x66637474; // 'ttcf'
--- a/gfx/2d/ScaledFontWin.h
+++ b/gfx/2d/ScaledFontWin.h
@@ -2,32 +2,26 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_SCALEDFONTWIN_H_
 #define MOZILLA_GFX_SCALEDFONTWIN_H_
 
 #include "ScaledFontBase.h"
-#include <windows.h>
-
-#include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 namespace gfx {
 
 class ScaledFontWin : public ScaledFontBase
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontWin)
   ScaledFontWin(LOGFONT* aFont, Float aSize);
 
-  ScaledFontWin(uint8_t* aFontData, uint32_t aFontDataLength, uint32_t aIndex,
-                Float aGlyphSize);
-
   virtual FontType GetType() const { return FontType::GDI; }
 
   bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) override;
 
 #ifdef USE_SKIA
   virtual SkTypeface* GetSkTypeface();
 #endif
 
@@ -36,23 +30,14 @@ protected:
   cairo_font_face_t* GetCairoFontFace() override;
 #endif
 
 private:
 #ifdef USE_SKIA
   friend class DrawTargetSkia;
 #endif
   LOGFONT mLogFont;
-
-  struct MemoryFontRemover
-  {
-    HANDLE memFontHandle;
-    MemoryFontRemover(HANDLE aMemFontHandle) : memFontHandle(aMemFontHandle) {}
-    ~MemoryFontRemover() { ::RemoveFontMemResourceEx(memFontHandle); }
-  };
-
-  UniquePtr<MemoryFontRemover> mMemoryFontRemover;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_SCALEDFONTWIN_H_ */
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -66,16 +66,18 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('coc
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     SOURCES += [
         'DrawTargetD2D.cpp',
         'DrawTargetD2D1.cpp',
         'ExtendInputEffectD2D1.cpp',
         'FilterNodeD2D1.cpp',
         'JobScheduler_win32.cpp',
+        'NativeFontResourceDWrite.cpp',
+        'NativeFontResourceGDI.cpp',
         'PathD2D.cpp',
         'RadialGradientEffectD2D1.cpp',
         'ScaledFontDWrite.cpp',
         'ScaledFontWin.cpp',
         'SourceSurfaceD2D.cpp',
         'SourceSurfaceD2D1.cpp',
         'SourceSurfaceD2DTarget.cpp',
     ]
--- a/layout/printing/PrintTranslator.cpp
+++ b/layout/printing/PrintTranslator.cpp
@@ -48,17 +48,17 @@ PrintTranslator::TranslateRecording(std:
   int32_t eventType;
   ReadElement(aRecording, eventType);
   while (aRecording.good()) {
     UniquePtr<RecordedEvent> recordedEvent(
       RecordedEvent::LoadEventFromStream(aRecording,
       static_cast<RecordedEvent::EventType>(eventType)));
 
     // Make sure that the whole event was read from the stream successfully.
-    if (!aRecording.good()) {
+    if (!aRecording.good() || !recordedEvent) {
       return false;
     }
 
     recordedEvent->PlayEvent(this);
     ReadElement(aRecording, eventType);
   }
 
   return true;
--- a/layout/printing/PrintTranslator.h
+++ b/layout/printing/PrintTranslator.h
@@ -7,32 +7,32 @@
 #ifndef mozilla_layout_PrintTranslator_h
 #define mozilla_layout_PrintTranslator_h
 
 #include <istream>
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Filters.h"
 #include "mozilla/gfx/RecordedEvent.h"
-#include "mozilla/unused.h"
 #include "nsRefPtrHashtable.h"
 
 class nsDeviceContext;
 
 namespace mozilla {
 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::NativeFontResource;
 
 class PrintTranslator final : public Translator
 {
 public:
   explicit PrintTranslator(nsDeviceContext* aDeviceContext);
 
   bool TranslateRecording(std::istream& aRecording);
 
@@ -73,16 +73,23 @@ public:
 
   ScaledFont* LookupScaledFont(ReferencePtr aRefPtr) final
   {
     ScaledFont* result = mScaledFonts.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
   {
     mDrawTargets.Put(aRefPtr, aDT);
   }
 
   void AddPath(ReferencePtr aRefPtr, Path *aPath) final
   {
     mPaths.Put(aRefPtr, aPath);
@@ -101,17 +108,22 @@ public:
   void AddGradientStops(ReferencePtr aRefPtr, GradientStops *aStops) final
   {
     mGradientStops.Put(aRefPtr, aStops);
   }
 
   void AddScaledFont(ReferencePtr aRefPtr, ScaledFont *aScaledFont) final
   {
     mScaledFonts.Put(aRefPtr, aScaledFont);
-    Unused << mSavedScaledFonts.PutEntry(aScaledFont);
+  }
+
+  void AddNativeFontResource(uint64_t aKey,
+                             NativeFontResource *aScaledFontResouce) final
+  {
+    mNativeFontResources.Put(aKey, aScaledFontResouce);
   }
 
   void RemoveDrawTarget(ReferencePtr aRefPtr) final
   {
     mDrawTargets.Remove(aRefPtr);
   }
 
   void RemovePath(ReferencePtr aRefPtr) final
@@ -134,18 +146,16 @@ public:
     mGradientStops.Remove(aRefPtr);
   }
 
   void RemoveScaledFont(ReferencePtr aRefPtr) final
   {
     mScaledFonts.Remove(aRefPtr);
   }
 
-  void ClearSavedFonts() { mSavedScaledFonts.Clear(); }
-
   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;
 
@@ -154,19 +164,15 @@ 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;
-
-  // We keep an extra reference to each scaled font, because they currently
-  // always get removed immediately. These can be cleared using ClearSavedFonts,
-  // when we know that things have been flushed to the print device.
-  nsTHashtable<nsRefPtrHashKey<ScaledFont>> mSavedScaledFonts;
+  nsRefPtrHashtable<nsUint64HashKey, NativeFontResource> mNativeFontResources;
 };
 
 } // namespace layout
 } // namespace mozilla
 
 #endif // mozilla_layout_PrintTranslator_h
--- a/layout/printing/ipc/RemotePrintJobParent.cpp
+++ b/layout/printing/ipc/RemotePrintJobParent.cpp
@@ -113,18 +113,16 @@ RemotePrintJobParent::PrintPage(const Sh
                                            aStoredPage.Size<char>()));
   mPrintTranslator->TranslateRecording(recording);
 
   rv = mPrintDeviceContext->EndPage();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  mPrintTranslator->ClearSavedFonts();
-
   return NS_OK;
 }
 
 bool
 RemotePrintJobParent::RecvFinalizePrint()
 {
   // EndDocument is sometimes called in the child even when BeginDocument has
   // not been called. See bug 1223332.