Bug 1455848 - use paths for WR font handles on Windows. r=jrmuizel
☠☠ backed out by a237a1078ce3 ☠ ☠
authorLee Salzman <lsalzman@mozilla.com>
Thu, 17 Jan 2019 15:45:07 -0500
changeset 515172 b8444f241aca60ed9f7520b89bb0865c61da96f3
parent 515171 f0f4bf8af10a1ba026623963950277dac0814360
child 515173 44a36f0fe512edff298758ebe736bfbcfa6d9842
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1455848
milestone66.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 1455848 - use paths for WR font handles on Windows. r=jrmuizel Differential Revision: https://phabricator.services.mozilla.com/D16896
gfx/2d/ScaledFontDWrite.cpp
gfx/layers/ipc/PWebRenderBridge.ipdl
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/webrender_bindings/Cargo.toml
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/src/moz2d_renderer.rs
gfx/wr/webrender/Cargo.toml
gfx/wr/webrender/src/platform/unix/font.rs
gfx/wr/webrender/src/platform/windows/font.rs
gfx/wr/webrender_api/Cargo.toml
gfx/wr/webrender_api/src/font.rs
gfx/wr/webrender_api/src/lib.rs
gfx/wr/wrench/Cargo.toml
gfx/wr/wrench/src/wrench.rs
gfx/wr/wrench/src/yaml_frame_writer.rs
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -313,176 +313,91 @@ bool UnscaledFontDWrite::GetFontFileData
   aDataCallback((uint8_t*)fragmentStart, fileSize, mFontFace->GetIndex(),
                 aBaton);
 
   stream->ReleaseFileFragment(context);
 
   return true;
 }
 
-static bool GetDWriteName(RefPtr<IDWriteLocalizedStrings> aNames,
-                          std::vector<WCHAR>& aOutName) {
-  BOOL exists = false;
-  UINT32 index = 0;
-  HRESULT hr = aNames->FindLocaleName(L"en-us", &index, &exists);
-  if (FAILED(hr)) {
-    return false;
-  }
-  if (!exists) {
-    // No english found, use whatever is first in the list.
-    index = 0;
-  }
-
-  UINT32 length;
-  hr = aNames->GetStringLength(index, &length);
-  if (FAILED(hr)) {
-    return false;
-  }
-  aOutName.resize(length + 1);
-  hr = aNames->GetString(index, aOutName.data(), length + 1);
-  return SUCCEEDED(hr);
-}
-
-static bool GetDWriteFamilyName(const RefPtr<IDWriteFontFamily>& aFamily,
-                                std::vector<WCHAR>& aOutName) {
-  RefPtr<IDWriteLocalizedStrings> names;
-  HRESULT hr = aFamily->GetFamilyNames(getter_AddRefs(names));
-  if (FAILED(hr)) {
-    return false;
-  }
-  return GetDWriteName(names, aOutName);
-}
-
-static void GetFontFileNames(RefPtr<IDWriteFontFace> aFontFace,
-                             std::vector<WCHAR>& aFamilyName,
-                             std::vector<WCHAR>& aFileNames) {
-  MOZ_ASSERT(aFamilyName.size() >= 1 && aFamilyName.back() == 0);
-
+static bool GetFontFileName(RefPtr<IDWriteFontFace> aFontFace,
+                            std::vector<WCHAR>& aFileName) {
   UINT32 numFiles;
   HRESULT hr = aFontFace->GetFiles(&numFiles, nullptr);
   if (FAILED(hr)) {
-    gfxCriticalNote << "Failed getting file count for font \""
-                    << &aFamilyName[0] << "\"";
-    return;
-  } else if (!numFiles) {
-    gfxCriticalNote << "No files found for font \"" << &aFamilyName[0] << "\"";
-    return;
+    gfxDebug() << "Failed getting file count for WR font";
+    return false;
+  } else if (numFiles != 1) {
+    gfxDebug() << "Invalid file count " << numFiles << " for WR font";
+    return false;
   }
-  std::vector<RefPtr<IDWriteFontFile>> files;
-  files.resize(numFiles);
-  hr = aFontFace->GetFiles(&numFiles, getter_AddRefs(files[0]));
+
+  RefPtr<IDWriteFontFile> file;
+  hr = aFontFace->GetFiles(&numFiles, getter_AddRefs(file));
   if (FAILED(hr)) {
-    gfxCriticalNote << "Failed getting files for font \"" << &aFamilyName[0]
-                    << "\"";
-    return;
+    gfxDebug() << "Failed getting file for WR font";
+    return false;
   }
 
-  for (auto& file : files) {
-    const void* key;
-    UINT32 keySize;
-    hr = file->GetReferenceKey(&key, &keySize);
-    if (FAILED(hr)) {
-      gfxCriticalNote << "Failed getting file ref key for font \""
-                      << &aFamilyName[0] << "\"";
-      return;
-    }
-    RefPtr<IDWriteFontFileLoader> loader;
-    hr = file->GetLoader(getter_AddRefs(loader));
-    if (FAILED(hr)) {
-      gfxCriticalNote << "Failed getting file loader for font \""
-                      << &aFamilyName[0] << "\"";
-      return;
-    }
-    RefPtr<IDWriteLocalFontFileLoader> localLoader;
-    loader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader),
-                           (void**)getter_AddRefs(localLoader));
-    if (!localLoader) {
-      gfxCriticalNote << "Failed querying loader interface for font \""
-                      << &aFamilyName[0] << "\"";
-      return;
-    }
-    UINT32 pathLen;
-    hr = localLoader->GetFilePathLengthFromKey(key, keySize, &pathLen);
-    if (FAILED(hr)) {
-      gfxCriticalNote << "Failed getting path length for font \""
-                      << &aFamilyName[0] << "\"";
-      return;
-    }
-    size_t offset = aFileNames.size();
-    aFileNames.resize(offset + pathLen + 1);
-    hr = localLoader->GetFilePathFromKey(key, keySize, &aFileNames[offset],
-                                         pathLen + 1);
-    if (FAILED(hr)) {
-      aFileNames.resize(offset);
-      gfxCriticalNote << "Failed getting path for font \"" << &aFamilyName[0]
-                      << "\"";
-      return;
-    }
-    MOZ_ASSERT(aFileNames.back() == 0);
-    DWORD attribs = GetFileAttributesW(&aFileNames[offset]);
-    if (attribs == INVALID_FILE_ATTRIBUTES) {
-      gfxCriticalNote << "sending font family \"" << &aFamilyName[0]
-                      << "\" with invalid file \"" << &aFileNames[offset]
-                      << "\"";
-    }
+  const void* key;
+  UINT32 keySize;
+  hr = file->GetReferenceKey(&key, &keySize);
+  if (FAILED(hr)) {
+    gfxDebug() << "Failed getting file ref key for WR font";
+    return false;
+  }
+  RefPtr<IDWriteFontFileLoader> loader;
+  hr = file->GetLoader(getter_AddRefs(loader));
+  if (FAILED(hr)) {
+    gfxDebug() << "Failed getting file loader for WR font";
+    return false;
+  }
+  RefPtr<IDWriteLocalFontFileLoader> localLoader;
+  loader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader),
+                         (void**)getter_AddRefs(localLoader));
+  if (!localLoader) {
+    gfxDebug() << "Failed querying loader interface for WR font";
+    return false;
   }
+  UINT32 pathLen;
+  hr = localLoader->GetFilePathLengthFromKey(key, keySize, &pathLen);
+  if (FAILED(hr)) {
+    gfxDebug() << "Failed getting path length for WR font";
+    return false;
+  }
+  aFileName.resize(pathLen + 1);
+  hr = localLoader->GetFilePathFromKey(key, keySize, aFileName.data(),
+                                       pathLen + 1);
+  if (FAILED(hr) || aFileName.back() != 0) {
+    gfxDebug() << "Failed getting path for WR font";
+    return false;
+  }
+  DWORD attribs = GetFileAttributesW(aFileName.data());
+  if (attribs == INVALID_FILE_ATTRIBUTES) {
+    gfxDebug() << "Invalid file \"" << aFileName.data() << "\" for WR font";
+    return false;
+  }
+  aFileName.pop_back();
+  return true;
 }
 
 bool UnscaledFontDWrite::GetWRFontDescriptor(WRFontDescriptorOutput aCb,
                                              void* aBaton) {
   if (!mFont) {
     return false;
   }
 
-  RefPtr<IDWriteFontFamily> family;
-  HRESULT hr = mFont->GetFontFamily(getter_AddRefs(family));
-  if (FAILED(hr)) {
-    return false;
-  }
-
-  DWRITE_FONT_WEIGHT weight = mFont->GetWeight();
-  DWRITE_FONT_STRETCH stretch = mFont->GetStretch();
-  DWRITE_FONT_STYLE style = mFont->GetStyle();
-
-  RefPtr<IDWriteFont> match;
-  hr = family->GetFirstMatchingFont(weight, stretch, style,
-                                    getter_AddRefs(match));
-  if (FAILED(hr) || match->GetWeight() != weight ||
-      match->GetStretch() != stretch || match->GetStyle() != style) {
-    return false;
-  }
-
-  std::vector<WCHAR> familyName;
-  if (!GetDWriteFamilyName(family, familyName)) {
+  std::vector<WCHAR> fileName;
+  if (!GetFontFileName(mFontFace, fileName)) {
     return false;
   }
-
-  RefPtr<IDWriteFontCollection> systemFonts = Factory::GetDWriteSystemFonts();
-  if (!systemFonts) {
-    return false;
-  }
+  uint32_t index = mFontFace->GetIndex();
 
-  UINT32 idx;
-  BOOL exists;
-  hr = systemFonts->FindFamilyName(familyName.data(), &idx, &exists);
-  if (FAILED(hr) || !exists) {
-    return false;
-  }
-
-  // FIXME: Debugging kluge for bug 1455848. Remove once debugged!
-  GetFontFileNames(mFontFace, familyName, familyName);
-
-  // The style information that identifies the font can be encoded easily in
-  // less than 32 bits. Since the index is needed for font descriptors, only
-  // the family name and style information, pass along the style in the index
-  // data to avoid requiring a more complicated structure packing for it in
-  // the data payload.
-  uint32_t index = weight | (stretch << 16) | (style << 24);
-  aCb(reinterpret_cast<const uint8_t*>(familyName.data()),
-      familyName.size() * sizeof(WCHAR), index, aBaton);
+  aCb(reinterpret_cast<const uint8_t*>(fileName.data()),
+      fileName.size() * sizeof(WCHAR), index, aBaton);
   return true;
 }
 
 ScaledFontDWrite::InstanceData::InstanceData(
     const wr::FontInstanceOptions* aOptions,
     const wr::FontInstancePlatformOptions* aPlatformOptions)
     : mUseEmbeddedBitmap(false),
       mForceGDIMode(false),
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -77,19 +77,16 @@ parent:
   sync SetTestSampleTime(TimeStamp sampleTime);
   sync LeaveTestMode();
   sync GetAnimationValue(uint64_t aCompositorAnimationsId) returns (OMTAValue value);
   sync SetAsyncScrollOffset(ViewID scrollId, float x, float y);
   sync SetAsyncZoom(ViewID scrollId, float zoom);
   async FlushApzRepaints();
   sync GetAPZTestData() returns (APZTestData data);
 
-  // Debugging routine for bug 1455848.
-  async ValidateFontDescriptor(uint8_t[] desc);
-
   async Shutdown();
   sync ShutdownSync();
 child:
   async WrUpdated(IdNamespace aNewIdNamespace, TextureFactoryIdentifier textureFactoryIdentifier);
   async WrReleasedImages(ExternalImageKeyPair[] pairs);
   async __delete__();
 };
 
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -221,26 +221,16 @@ static void WriteFontFileData(const uint
 }
 
 static void WriteFontDescriptor(const uint8_t* aData, uint32_t aLength,
                                 uint32_t aIndex, void* aBaton) {
   FontFileDataSink* sink = static_cast<FontFileDataSink*>(aBaton);
 
   *sink->mFontKey = sink->mWrBridge->GetNextFontKey();
 
-#ifdef XP_WIN
-  // FIXME: Debugging kluge for bug 1455848. Remove once debugged!
-  nsTArray<uint8_t> data;
-  data.AppendElements(aData, aLength);
-  sink->mWrBridge->SendValidateFontDescriptor(data);
-  aLength =
-      uint32_t(wcsnlen_s((const wchar_t*)aData, aLength / sizeof(wchar_t)) *
-               sizeof(wchar_t));
-#endif
-
   sink->mResources->AddFontDescriptor(
       *sink->mFontKey, Range<uint8_t>(const_cast<uint8_t*>(aData), aLength),
       aIndex);
 }
 
 void WebRenderBridgeChild::PushGlyphs(
     wr::DisplayListBuilder& aBuilder, Range<const wr::GlyphInstance> aGlyphs,
     gfx::ScaledFont* aFont, const wr::ColorF& aColor,
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -31,20 +31,16 @@
 #include "mozilla/layers/WebRenderImageHost.h"
 #include "mozilla/layers/WebRenderTextureHost.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Unused.h"
 #include "mozilla/webrender/RenderThread.h"
 #include "mozilla/widget/CompositorWidget.h"
 
-#ifdef XP_WIN
-#  include "dwrite.h"
-#endif
-
 #ifdef MOZ_GECKO_PROFILER
 #  include "ProfilerMarkerPayload.h"
 #endif
 
 bool is_in_main_thread() { return NS_IsMainThread(); }
 
 bool is_in_compositor_thread() {
   return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
@@ -701,59 +697,16 @@ void WebRenderBridgeParent::ObserveShare
   if (!mDestroyed) {
     Unused << SendWrReleasedImages(aPairs);
   }
   for (const auto& pair : aPairs) {
     SharedSurfacesParent::Release(pair.id);
   }
 }
 
-// Debugging kluge for bug 1455848. Remove once debugged!
-mozilla::ipc::IPCResult WebRenderBridgeParent::RecvValidateFontDescriptor(
-    nsTArray<uint8_t>&& aData) {
-  if (mDestroyed) {
-    return IPC_OK();
-  }
-#ifdef XP_WIN
-  nsTArray<uint8_t> data(aData);
-  wchar_t* family = (wchar_t*)data.Elements();
-  size_t remaining = data.Length() / sizeof(wchar_t);
-  size_t familyLength = wcsnlen_s(family, remaining);
-  MOZ_ASSERT(familyLength < remaining && family[familyLength] == 0);
-  remaining -= familyLength + 1;
-  wchar_t* files = family + familyLength + 1;
-  BOOL exists = FALSE;
-  if (RefPtr<IDWriteFontCollection> systemFonts =
-          Factory::GetDWriteSystemFonts()) {
-    UINT32 idx;
-    systemFonts->FindFamilyName(family, &idx, &exists);
-  }
-  if (!remaining) {
-    gfxCriticalNote << (exists ? "found" : "MISSING") << " font family \""
-                    << family << "\" has no files!";
-  }
-  while (remaining > 0) {
-    size_t fileLength = wcsnlen_s(files, remaining);
-    MOZ_ASSERT(fileLength < remaining && files[fileLength] == 0);
-    DWORD attribs = GetFileAttributesW(files);
-    if (!exists || attribs == INVALID_FILE_ATTRIBUTES) {
-      gfxCriticalNote << (exists ? "found" : "MISSING") << " font family \""
-                      << family << "\" has "
-                      << (attribs == INVALID_FILE_ATTRIBUTES ? "INVALID"
-                                                             : "valid")
-                      << "(" << hexa(attribs) << ")"
-                      << " file \"" << files << "\"";
-    }
-    remaining -= fileLength + 1;
-    files += fileLength + 1;
-  }
-#endif
-  return IPC_OK();
-}
-
 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvUpdateResources(
     nsTArray<OpUpdateResource>&& aResourceUpdates,
     nsTArray<RefCountedShmem>&& aSmallShmems,
     nsTArray<ipc::Shmem>&& aLargeShmems) {
   if (mDestroyed) {
     wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
     wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
     return IPC_OK();
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -120,19 +120,16 @@ class WebRenderBridgeParent final : publ
       const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime,
       const nsCString& aTxnURL, const TimeStamp& aFwdTime) override;
   mozilla::ipc::IPCResult RecvSetFocusTarget(
       const FocusTarget& aFocusTarget) override;
   mozilla::ipc::IPCResult RecvParentCommands(
       nsTArray<WebRenderParentCommand>&& commands) override;
   mozilla::ipc::IPCResult RecvGetSnapshot(PTextureParent* aTexture) override;
 
-  mozilla::ipc::IPCResult RecvValidateFontDescriptor(
-      nsTArray<uint8_t>&& aData) override;
-
   mozilla::ipc::IPCResult RecvSetLayersObserverEpoch(
       const LayersObserverEpoch& aChildEpoch) override;
 
   mozilla::ipc::IPCResult RecvClearCachedResources() override;
   mozilla::ipc::IPCResult RecvScheduleComposite() override;
   mozilla::ipc::IPCResult RecvCapture() override;
   mozilla::ipc::IPCResult RecvSyncWithCompositor() override;
 
--- a/gfx/webrender_bindings/Cargo.toml
+++ b/gfx/webrender_bindings/Cargo.toml
@@ -18,15 +18,15 @@ fxhash = "0.2.1"
 
 [dependencies.webrender]
 path = "../wr/webrender"
 version = "0.59.0"
 default-features = false
 features = ["capture", "serialize_program"]
 
 [target.'cfg(target_os = "windows")'.dependencies]
-dwrote = "0.7"
+dwrote = "0.8"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.6"
 core-graphics = "0.17.1"
 foreign-types = "0.3.0"
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1,9 +1,15 @@
 use std::ffi::{CStr, CString};
+#[cfg(not(target_os = "macos"))]
+use std::ffi::OsString;
+#[cfg(target_os = "windows")]
+use std::os::windows::ffi::OsStringExt;
+#[cfg(not(any(target_os = "macos", target_os = "windows")))]
+use std::os::unix::ffi::OsStringExt;
 use std::io::Cursor;
 use std::{mem, slice, ptr, env};
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::cell::RefCell;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::ops::Range;
@@ -23,19 +29,16 @@ use webrender::{Device, Shaders, WrShade
 use thread_profiler::register_thread_with_profiler;
 use moz2d_renderer::Moz2dBlobImageHandler;
 use program_cache::{WrProgramCache, remove_disk_cache};
 use app_units::Au;
 use rayon;
 use euclid::SideOffsets2D;
 use nsstring::nsAString;
 
-#[cfg(target_os = "windows")]
-use dwrote::{FontDescriptor, FontWeight, FontStretch, FontStyle};
-
 #[cfg(target_os = "macos")]
 use core_foundation::string::CFString;
 #[cfg(target_os = "macos")]
 use core_graphics::font::CGFont;
 
 extern "C" {
     #[cfg(target_os = "android")]
     fn __android_log_write(prio: c_int, tag: *const c_char, text: *const c_char) -> c_int;
@@ -1708,21 +1711,19 @@ pub extern "C" fn wr_api_capture(
 }
 
 #[cfg(target_os = "windows")]
 fn read_font_descriptor(
     bytes: &mut WrVecU8,
     index: u32
 ) -> NativeFontHandle {
     let wchars = bytes.convert_into_vec::<u16>();
-    FontDescriptor {
-        family_name: String::from_utf16(&wchars).unwrap(),
-        weight: FontWeight::from_u32(index & 0xffff),
-        stretch: FontStretch::from_u32((index >> 16) & 0xff),
-        style: FontStyle::from_u32((index >> 24) & 0xff),
+    NativeFontHandle {
+        path: PathBuf::from(OsString::from_wide(&wchars)),
+        index,
     }
 }
 
 #[cfg(target_os = "macos")]
 fn read_font_descriptor(
     bytes: &mut WrVecU8,
     _index: u32
 ) -> NativeFontHandle {
@@ -1732,19 +1733,19 @@ fn read_font_descriptor(
     NativeFontHandle(font)
 }
 
 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
 fn read_font_descriptor(
     bytes: &mut WrVecU8,
     index: u32
 ) -> NativeFontHandle {
-    let cstr = CString::new(bytes.flush_into_vec()).unwrap();
+    let chars = bytes.flush_into_vec();
     NativeFontHandle {
-        pathname: String::from(cstr.to_str().unwrap()),
+        path: PathBuf::from(OsString::from_vec(chars)),
         index,
     }
 }
 
 #[no_mangle]
 pub extern "C" fn wr_resource_updates_add_font_descriptor(
     txn: &mut Transaction,
     key: WrFontKey,
--- a/gfx/webrender_bindings/src/moz2d_renderer.rs
+++ b/gfx/webrender_bindings/src/moz2d_renderer.rs
@@ -25,16 +25,18 @@ use std;
 #[cfg(target_os = "windows")]
 use dwrote;
 
 #[cfg(target_os = "macos")]
 use foreign_types::ForeignType;
 
 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
 use std::ffi::CString;
+#[cfg(not(any(target_os = "macos", target_os = "windows")))]
+use std::os::unix::ffi::OsStrExt;
 
 /// Local print-debugging utility
 macro_rules! dlog {
     ($($e:expr),*) => { {$(let _ = $e;)*} }
     //($($t:tt)*) => { println!($($t)*) }
 }
 
 /// Debug prints a blob's item bounds, indicating whether the bounds are dirty or not.
@@ -650,30 +652,29 @@ impl Moz2dBlobImageHandler {
     }
 
     /// Does early preprocessing of a blob's resources.
     ///
     /// Currently just sets up fonts found in the blob.
     fn prepare_request(&self, blob: &[u8], resources: &BlobImageResources) {
         #[cfg(target_os = "windows")]
         fn process_native_font_handle(key: FontKey, handle: &NativeFontHandle) {
-            let system_fc = dwrote::FontCollection::system();
-            let font = system_fc.get_font_from_descriptor(handle).unwrap();
-            let face = font.create_font_face();
+            let file = dwrote::FontFile::new_from_path(&handle.path).unwrap();
+            let face = file.create_face(handle.index, dwrote::DWRITE_FONT_SIMULATIONS_NONE).unwrap();
             unsafe { AddNativeFontHandle(key, face.as_ptr() as *mut c_void, 0) };
         }
 
         #[cfg(target_os = "macos")]
         fn process_native_font_handle(key: FontKey, handle: &NativeFontHandle) {
             unsafe { AddNativeFontHandle(key, handle.0.as_ptr() as *mut c_void, 0) };
         }
 
         #[cfg(not(any(target_os = "macos", target_os = "windows")))]
         fn process_native_font_handle(key: FontKey, handle: &NativeFontHandle) {
-            let cstr = CString::new(handle.pathname.clone()).unwrap();
+            let cstr = CString::new(handle.path.as_os_str().as_bytes()).unwrap();
             unsafe { AddNativeFontHandle(key, cstr.as_ptr() as *mut c_void, handle.index) };
         }
 
         fn process_fonts(
             mut extra_data: BufReader,
             resources: &BlobImageResources,
             unscaled_fonts: &mut Vec<FontKey>,
             scaled_fonts: &mut Vec<FontInstanceKey>,
--- a/gfx/wr/webrender/Cargo.toml
+++ b/gfx/wr/webrender/Cargo.toml
@@ -76,14 +76,14 @@ optional = true
 mozangle = "0.1"
 rand = "0.4"
 
 [target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
 freetype = { version = "0.4", default-features = false }
 libc = "0.2"
 
 [target.'cfg(target_os = "windows")'.dependencies]
-dwrote = "0.7"
+dwrote = "0.8"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.6"
 core-graphics = "0.17.1"
 core-text = { version = "13", default-features = false }
--- a/gfx/wr/webrender/src/platform/unix/font.rs
+++ b/gfx/wr/webrender/src/platform/unix/font.rs
@@ -314,17 +314,18 @@ impl FontContext {
             if let Some(face) = new_ft_face(font_key, self.lib, &file, index) {
                 self.faces.insert(*font_key, FontFace { file, index, face, mm_var: ptr::null_mut() });
             }
         }
     }
 
     pub fn add_native_font(&mut self, font_key: &FontKey, native_font_handle: NativeFontHandle) {
         if !self.faces.contains_key(&font_key) {
-            let file = FontFile::Pathname(CString::new(native_font_handle.pathname).unwrap());
+            let cstr = CString::new(native_font_handle.path.as_os_str().to_str().unwrap()).unwrap();
+            let file = FontFile::Pathname(cstr);
             let index = native_font_handle.index;
             if let Some(face) = new_ft_face(font_key, self.lib, &file, index) {
                 self.faces.insert(*font_key, FontFace { file, index, face, mm_var: ptr::null_mut() });
             }
         }
     }
 
     pub fn delete_font(&mut self, font_key: &FontKey) {
@@ -960,11 +961,12 @@ impl Drop for FontContext {
         }
     }
 }
 
 #[cfg(feature = "pathfinder")]
 impl<'a> Into<pf_freetype::FontDescriptor> for NativeFontHandleWrapper<'a> {
     fn into(self) -> pf_freetype::FontDescriptor {
         let NativeFontHandleWrapper(font_handle) = self;
-        pf_freetype::FontDescriptor::new(font_handle.pathname.clone().into(), font_handle.index)
+        let str = font_handle.path.as_os_str().to_str().unwrap();
+        pf_freetype::FontDescriptor::new(str.into(), font_handle.index)
     }
 }
--- a/gfx/wr/webrender/src/platform/windows/font.rs
+++ b/gfx/wr/webrender/src/platform/windows/font.rs
@@ -1,20 +1,21 @@
 /* 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/. */
 
 use api::{FontInstanceFlags, FontKey, FontRenderMode, FontVariation};
-use api::{ColorU, GlyphDimensions};
+use api::{ColorU, GlyphDimensions, NativeFontHandle};
 use dwrote;
 use gamma_lut::ColorLut;
 use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey};
 use internal_types::{FastHashMap, ResourceCacheError};
 use std::collections::hash_map::Entry;
 use std::sync::Arc;
+
 cfg_if! {
     if #[cfg(feature = "pathfinder")] {
         use pathfinder_font_renderer::{PathfinderComPtr, IDWriteFontFace};
         use glyph_rasterizer::NativeFontHandleWrapper;
     } else if #[cfg(not(feature = "pathfinder"))] {
         use api::FontInstancePlatformOptions;
         use glyph_rasterizer::{GlyphFormat, GlyphRasterError, GlyphRasterResult, RasterizedGlyph};
         use gamma_lut::GammaLut;
@@ -25,18 +26,24 @@ lazy_static! {
     static ref DEFAULT_FONT_DESCRIPTOR: dwrote::FontDescriptor = dwrote::FontDescriptor {
         family_name: "Arial".to_owned(),
         weight: dwrote::FontWeight::Regular,
         stretch: dwrote::FontStretch::Normal,
         style: dwrote::FontStyle::Normal,
     };
 }
 
+struct FontFace {
+    file: dwrote::FontFile,
+    index: u32,
+    face: dwrote::FontFace,
+}
+
 pub struct FontContext {
-    fonts: FastHashMap<FontKey, dwrote::FontFace>,
+    fonts: FastHashMap<FontKey, FontFace>,
     variations: FastHashMap<(FontKey, dwrote::DWRITE_FONT_SIMULATIONS, Vec<FontVariation>), dwrote::FontFace>,
     #[cfg(not(feature = "pathfinder"))]
     gamma_luts: FastHashMap<(u16, u16), GammaLut>,
 }
 
 // DirectWrite is safe to use on multiple threads and non-shareable resources are
 // all hidden inside their font context.
 unsafe impl Send for FontContext {}
@@ -105,78 +112,56 @@ impl FontContext {
             gamma_luts: FastHashMap::default(),
         })
     }
 
     pub fn has_font(&self, font_key: &FontKey) -> bool {
         self.fonts.contains_key(font_key)
     }
 
+    fn add_font_descriptor(&mut self, font_key: &FontKey, desc: &dwrote::FontDescriptor) {
+        let system_fc = dwrote::FontCollection::get_system(false);
+        if let Some(font) = system_fc.get_font_from_descriptor(desc) {
+            let face = font.create_font_face();
+            let file = face.get_files().pop().unwrap();
+            let index = face.get_index();
+            self.fonts.insert(*font_key, FontFace { file, index, face });
+        }
+    }
+
     pub fn add_raw_font(&mut self, font_key: &FontKey, data: Arc<Vec<u8>>, index: u32) {
         if self.fonts.contains_key(font_key) {
             return;
         }
 
-        if let Some(font_file) = dwrote::FontFile::new_from_data(data) {
-            let face = font_file.create_face(index, dwrote::DWRITE_FONT_SIMULATIONS_NONE);
-            self.fonts.insert(*font_key, face);
-        } else {
-            // XXX add_raw_font needs to have a way to return an error
-            debug!("DWrite WR failed to load font from data, using Arial instead");
-            self.add_native_font(font_key, DEFAULT_FONT_DESCRIPTOR.clone());
+        if let Some(file) = dwrote::FontFile::new_from_data(data) {
+            if let Ok(face) = file.create_face(index, dwrote::DWRITE_FONT_SIMULATIONS_NONE) {
+                self.fonts.insert(*font_key, FontFace { file, index, face });
+                return;
+            }
         }
+        // XXX add_raw_font needs to have a way to return an error
+        debug!("DWrite WR failed to load font from data, using Arial instead");
+        self.add_font_descriptor(font_key, &DEFAULT_FONT_DESCRIPTOR);
     }
 
-    pub fn load_system_font(font_handle: &dwrote::FontDescriptor, update: bool) -> Result<dwrote::Font, String> {
-        let system_fc = dwrote::FontCollection::get_system(update);
-        // A version of get_font_from_descriptor() that panics early to help with bug 1455848
-        if let Some(family) = system_fc.get_font_family_by_name(&font_handle.family_name) {
-            let font = family.get_first_matching_font(font_handle.weight, font_handle.stretch, font_handle.style);
-            // Exact matches only here
-            if font.weight() == font_handle.weight &&
-                font.stretch() == font_handle.stretch &&
-                font.style() == font_handle.style
-            {
-                Ok(font)
-            } else {
-                // We can't depend on the family's fonts being in a particular order, so the first match may not
-                // be an exact match, even though it is sufficiently close to be a match. As a slower fallback,
-                // try looking through all of the fonts in the family for an exact match. The caller should have
-                // verified that an exact match exists so that this search shouldn't fail.
-                (0 .. family.get_font_count()).filter_map(|idx| {
-                    let alt = family.get_font(idx);
-                    if alt.weight() == font_handle.weight &&
-                        alt.stretch() == font_handle.stretch &&
-                        alt.style() == font_handle.style
-                    {
-                        Some(alt)
-                    } else {
-                        None
-                    }
-                }).next().ok_or_else(|| {
-                    format!("font mismatch for descriptor {:?} {:?}", font_handle, font.to_descriptor())
-                })
-            }
-        } else {
-            Err(format!("missing font family for descriptor {:?}", font_handle))
-        }
-    }
-
-    pub fn add_native_font(&mut self, font_key: &FontKey, font_handle: dwrote::FontDescriptor) {
+    pub fn add_native_font(&mut self, font_key: &FontKey, font_handle: NativeFontHandle) {
         if self.fonts.contains_key(font_key) {
             return;
         }
-        // First try to load the font without updating the system font collection.
-        // If the font can't be found, try again after updating the system font collection.
-        // If even that fails, panic...
-        let font = Self::load_system_font(&font_handle, false).unwrap_or_else(|_| {
-            Self::load_system_font(&font_handle, true).unwrap()
-        });
-        let face = font.create_font_face();
-        self.fonts.insert(*font_key, face);
+        if let Some(file) = dwrote::FontFile::new_from_path(font_handle.pathname) {
+            let index = font_handle.index;
+            if let Ok(face) = file.create_face(index, dwrote::DWRITE_FONT_SIMULATIONS_NONE) {
+                self.fonts.insert(*font_key, FontFace { file, index, face });
+                return;
+            }
+        }
+        // XXX add_native_font needs to have a way to return an error
+        debug!("DWrite WR failed to load font from path, using Arial instead");
+        self.add_font_descriptor(font_key, &DEFAULT_FONT_DESCRIPTOR);
     }
 
     pub fn delete_font(&mut self, font_key: &FontKey) {
         if let Some(_) = self.fonts.remove(font_key) {
             self.variations.retain(|k, _| k.0 != *font_key);
         }
     }
 
@@ -211,42 +196,45 @@ impl FontContext {
     }
 
     fn get_font_face(
         &mut self,
         font: &FontInstance,
     ) -> &dwrote::FontFace {
         if !font.flags.contains(FontInstanceFlags::SYNTHETIC_BOLD) &&
            font.variations.is_empty() {
-            return self.fonts.get(&font.font_key).unwrap();
+            return &self.fonts.get(&font.font_key).unwrap().face;
         }
         let sims = if font.flags.contains(FontInstanceFlags::SYNTHETIC_BOLD) {
             dwrote::DWRITE_FONT_SIMULATIONS_BOLD
         } else {
             dwrote::DWRITE_FONT_SIMULATIONS_NONE
         };
         match self.variations.entry((font.font_key, sims, font.variations.clone())) {
             Entry::Occupied(entry) => entry.into_mut(),
             Entry::Vacant(entry) => {
                 let normal_face = self.fonts.get(&font.font_key).unwrap();
                 if !font.variations.is_empty() {
-                    if let Some(var_face) = normal_face.create_font_face_with_variations(
+                    if let Some(var_face) = normal_face.face.create_font_face_with_variations(
                         sims,
                         &font.variations.iter().map(|var| {
                             dwrote::DWRITE_FONT_AXIS_VALUE {
                                 // OpenType tags are big-endian, but DWrite wants little-endian.
                                 axisTag: var.tag.swap_bytes(),
                                 value: var.value,
                             }
                         }).collect::<Vec<_>>(),
                     ) {
                         return entry.insert(var_face);
                     }
                 }
-                entry.insert(normal_face.create_font_face_with_simulations(sims))
+                let var_face = normal_face.file
+                    .create_face(normal_face.index, sims)
+                    .unwrap_or_else(|_| normal_face.face.clone());
+                entry.insert(var_face)
             }
         }
     }
 
     fn create_glyph_analysis(
         &mut self,
         font: &FontInstance,
         key: &GlyphKey,
@@ -310,17 +298,17 @@ impl FontContext {
             if bounds2.left != bounds2.right && bounds2.top != bounds2.bottom {
                 return Ok((analysis2, dwrote::DWRITE_TEXTURE_ALIASED_1x1, bounds2));
             }
         }
         Ok((analysis, texture_type, bounds))
     }
 
     pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
-        let face = self.fonts.get(&font_key).unwrap();
+        let face = &self.fonts.get(&font_key).unwrap().face;
         let indices = face.get_glyph_indices(&[ch as u32]);
         indices.first().map(|idx| *idx as u32)
     }
 
     pub fn get_glyph_dimensions(
         &mut self,
         font: &FontInstance,
         key: &GlyphKey,
@@ -542,17 +530,17 @@ impl FontContext {
             bytes: bgra_pixels,
         })
     }
 }
 
 #[cfg(feature = "pathfinder")]
 impl<'a> From<NativeFontHandleWrapper<'a>> for PathfinderComPtr<IDWriteFontFace> {
     fn from(font_handle: NativeFontHandleWrapper<'a>) -> Self {
-        let system_fc = ::dwrote::FontCollection::system();
-        let font = match system_fc.get_font_from_descriptor(&font_handle.0) {
-            Some(font) => font,
-            None => panic!("missing descriptor {:?}", font_handle.0),
-        };
-        let face = font.create_font_face();
-        unsafe { PathfinderComPtr::new(face.as_ptr()) }
+        if let Some(file) = dwrote::FontFile::new_from_path(font_handle.0.pathname) {
+            let index = font_handle.0.index;
+            if let Ok(face) = file.create_face(index, dwrote::DWRITE_FONT_SIMULATIONS_NONE) {
+                return unsafe { PathfinderComPtr::new(face.as_ptr()) };
+            }
+        }
+        panic!("missing font {:?}", font_handle.0)
     }
 }
--- a/gfx/wr/webrender_api/Cargo.toml
+++ b/gfx/wr/webrender_api/Cargo.toml
@@ -25,11 +25,8 @@ serde = { version = "=1.0.80", features 
 serde_derive = { version = "=1.0.80", features = ["deserialize_in_place"] }
 serde_bytes = "0.10"
 time = "0.1"
 wr_malloc_size_of = { version = "0.0.1", path = "../wr_malloc_size_of" }
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.6"
 core-graphics = "0.17.1"
-
-[target.'cfg(target_os = "windows")'.dependencies]
-dwrote = "0.7"
--- a/gfx/wr/webrender_api/src/font.rs
+++ b/gfx/wr/webrender_api/src/font.rs
@@ -2,32 +2,32 @@
  * 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/. */
 
 use app_units::Au;
 #[cfg(target_os = "macos")]
 use core_foundation::string::CFString;
 #[cfg(target_os = "macos")]
 use core_graphics::font::CGFont;
-#[cfg(target_os = "windows")]
-pub use dwrote::FontDescriptor as NativeFontHandle;
 #[cfg(target_os = "macos")]
 use serde::de::{self, Deserialize, Deserializer};
 #[cfg(target_os = "macos")]
 use serde::ser::{Serialize, Serializer};
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
+#[cfg(not(target_os = "macos"))]
+use std::path::PathBuf;
 use std::sync::Arc;
 use {ColorU, IdNamespace, LayoutPoint};
 
 
-#[cfg(not(any(target_os = "macos", target_os = "windows")))]
+#[cfg(not(target_os = "macos"))]
 #[derive(Clone, Debug, Serialize, Deserialize)]
 pub struct NativeFontHandle {
-    pub pathname: String,
+    pub path: PathBuf,
     pub index: u32,
 }
 
 #[cfg(target_os = "macos")]
 #[derive(Clone)]
 pub struct NativeFontHandle(pub CGFont);
 
 #[cfg(target_os = "macos")]
--- a/gfx/wr/webrender_api/src/lib.rs
+++ b/gfx/wr/webrender_api/src/lib.rs
@@ -22,18 +22,16 @@ extern crate byteorder;
 #[cfg(feature = "nightly")]
 extern crate core;
 #[cfg(target_os = "macos")]
 extern crate core_foundation;
 #[cfg(target_os = "macos")]
 extern crate core_graphics;
 #[macro_use]
 extern crate derive_more;
-#[cfg(target_os = "windows")]
-extern crate dwrote;
 pub extern crate euclid;
 #[cfg(feature = "ipc")]
 extern crate ipc_channel;
 #[macro_use]
 extern crate malloc_size_of_derive;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
--- a/gfx/wr/wrench/Cargo.toml
+++ b/gfx/wr/wrench/Cargo.toml
@@ -34,13 +34,13 @@ serde = {version = "1.0", features = ["d
 core-graphics = "0.17.1"
 core-foundation = "0.6"
 
 [features]
 headless = [ "osmesa-sys", "osmesa-src" ]
 pathfinder = [ "webrender/pathfinder" ]
 
 [target.'cfg(target_os = "windows")'.dependencies]
-dwrote = "0.7"
+dwrote = "0.8"
 mozangle = {version = "0.1.5", features = ["egl"]}
 
 [target.'cfg(all(unix, not(target_os = "android")))'.dependencies]
 font-loader = "0.7"
--- a/gfx/wr/wrench/src/wrench.rs
+++ b/gfx/wr/wrench/src/wrench.rs
@@ -386,46 +386,55 @@ impl Wrench {
         let mut txn = Transaction::new();
         txn.add_native_font(key, descriptor.clone());
         self.api.update_resources(txn.resource_updates);
         key
     }
 
     #[cfg(target_os = "windows")]
     pub fn font_key_from_name(&mut self, font_name: &str) -> FontKey {
-        let system_fc = dwrote::FontCollection::system();
-        let family = system_fc.get_font_family_by_name(font_name).unwrap();
-        let font = family.get_first_matching_font(
-            dwrote::FontWeight::Regular,
-            dwrote::FontStretch::Normal,
-            dwrote::FontStyle::Normal,
-        );
-        let descriptor = font.to_descriptor();
-        self.font_key_from_native_handle(&descriptor)
+        self.font_key_from_properties(
+            font_name,
+            dwrote::FontWeight::Regular.to_u32(),
+            dwrote::FontStretch::Normal.to_u32(),
+            dwrote::FontStyle::Normal.to_u32(),
+        )
     }
 
     #[cfg(target_os = "windows")]
     pub fn font_key_from_properties(
         &mut self,
         family: &str,
         weight: u32,
         style: u32,
         stretch: u32,
     ) -> FontKey {
         let weight = dwrote::FontWeight::from_u32(weight);
         let style = dwrote::FontStyle::from_u32(style);
         let stretch = dwrote::FontStretch::from_u32(stretch);
-
         let desc = dwrote::FontDescriptor {
             family_name: family.to_owned(),
             weight,
             style,
             stretch,
         };
-        self.font_key_from_native_handle(&desc)
+        let system_fc = dwrote::FontCollection::system();
+        if let Some(font) = system_fc.get_font_from_descriptor(&desc) {
+            let face = font.create_font_face();
+            let files = face.get_files();
+            if files.len() == 1 {
+                if let Some(path) = files[0].get_font_file_path() {
+                    return self.font_key_from_native_handle(&NativeFontHandle {
+                        path,
+                        index: face.get_index(),
+                    });
+                }
+            }
+        }
+        panic!("failed loading font from properties {:?}", desc)
     }
 
     #[cfg(all(unix, not(target_os = "android")))]
     pub fn font_key_from_properties(
         &mut self,
         family: &str,
         _weight: u32,
         _style: u32,
--- a/gfx/wr/wrench/src/yaml_frame_writer.rs
+++ b/gfx/wr/wrench/src/yaml_frame_writer.rs
@@ -263,29 +263,16 @@ fn write_stacking_context(
                 filters.push(Yaml::String("linear-to-srgb".to_string()))
             }
         }
     }
 
     yaml_node(parent, "filters", Yaml::Array(filters));
 }
 
-#[cfg(target_os = "windows")]
-fn native_font_handle_to_yaml(
-    _rsrc: &mut ResourceGenerator,
-    handle: &NativeFontHandle,
-    parent: &mut yaml_rust::yaml::Hash,
-    _: &mut Option<PathBuf>,
-) {
-    str_node(parent, "family", &handle.family_name);
-    u32_node(parent, "weight", handle.weight.to_u32());
-    u32_node(parent, "style", handle.style.to_u32());
-    u32_node(parent, "stretch", handle.stretch.to_u32());
-}
-
 #[cfg(target_os = "macos")]
 fn native_font_handle_to_yaml(
     rsrc: &mut ResourceGenerator,
     handle: &NativeFontHandle,
     parent: &mut yaml_rust::yaml::Hash,
     path_opt: &mut Option<PathBuf>,
 ) {
     let path = match *path_opt {
@@ -302,24 +289,27 @@ fn native_font_handle_to_yaml(
             *path_opt = Some(path.clone());
             path
         }
     };
 
     path_node(parent, "font", &path);
 }
 
-#[cfg(not(any(target_os = "macos", target_os = "windows")))]
+#[cfg(not(target_os = "macos"))]
 fn native_font_handle_to_yaml(
     _rsrc: &mut ResourceGenerator,
     handle: &NativeFontHandle,
     parent: &mut yaml_rust::yaml::Hash,
     _: &mut Option<PathBuf>,
 ) {
-    str_node(parent, "font", &handle.pathname);
+    str_node(parent, "font", handle.path.as_os_str().to_str().unwrap());
+    if handle.index != 0 {
+        u32_node(parent, "font-index", handle.index);
+    }
 }
 
 fn radial_gradient_to_yaml(
     table: &mut Table,
     gradient: &webrender::api::RadialGradient,
     stops_range: ItemRange<GradientStop>,
     display_list: &BuiltDisplayList
 ) {