Bug 1403198 - support WR font descriptors with DWrite. r=jrmuizel
authorLee Salzman <lsalzman@mozilla.com>
Mon, 06 Nov 2017 20:20:43 -0500
changeset 390418 d619753f890bc744c68bf7948d2e87930bdd9ecc
parent 390417 87fb72d343ed6942483a99813d58f8203bdc56a2
child 390419 8e450204ab2ea252f370020a936c92cc9a90dc7f
push id97040
push userlsalzman@mozilla.com
push dateTue, 07 Nov 2017 01:21:59 +0000
treeherdermozilla-inbound@5a38089c0375 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1403198
milestone58.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 1403198 - support WR font descriptors with DWrite. r=jrmuizel MozReview-Commit-ID: 8u3kYoKYOuC
gfx/2d/NativeFontResourceDWrite.cpp
gfx/2d/ScaledFontDWrite.cpp
gfx/2d/UnscaledFontDWrite.h
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/webrender_bindings/Cargo.toml
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/src/lib.rs
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
--- a/gfx/2d/NativeFontResourceDWrite.cpp
+++ b/gfx/2d/NativeFontResourceDWrite.cpp
@@ -278,16 +278,17 @@ NativeFontResourceDWrite::CreateUnscaled
   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<UnscaledFont> unscaledFont =
     new UnscaledFontDWrite(fontFace,
+                           nullptr,
                            DWRITE_FONT_SIMULATIONS_NONE,
                            mNeedsCairo);
 
   return unscaledFont.forget();
 }
 
 } // gfx
 } // mozilla
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -289,16 +289,94 @@ UnscaledFontDWrite::GetFontFileData(Font
 
   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);
+}
+
+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)) {
+    return false;
+  }
+
+  // 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() - 1) * sizeof(WCHAR),
+      index, aBaton);
+  return true;
+}
+
 bool
 ScaledFontDWrite::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
 {
   InstanceData instance(this);
   aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance), nullptr, 0, aBaton);
   return true;
 }
 
--- a/gfx/2d/UnscaledFontDWrite.h
+++ b/gfx/2d/UnscaledFontDWrite.h
@@ -13,41 +13,46 @@
 
 namespace mozilla {
 namespace gfx {
 
 class UnscaledFontDWrite final : public UnscaledFont
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(UnscaledFontDWrite, override)
-  explicit UnscaledFontDWrite(const RefPtr<IDWriteFontFace>& aFontFace,
-                              DWRITE_FONT_SIMULATIONS aSimulations =
-                                DWRITE_FONT_SIMULATIONS_NONE,
-                              bool aNeedsCairo = false)
+  UnscaledFontDWrite(const RefPtr<IDWriteFontFace>& aFontFace,
+                     const RefPtr<IDWriteFont>& aFont,
+                     DWRITE_FONT_SIMULATIONS aSimulations = DWRITE_FONT_SIMULATIONS_NONE,
+                     bool aNeedsCairo = false)
     : mFontFace(aFontFace)
+    , mFont(aFont)
     , mSimulations(aSimulations)
     , mNeedsCairo(aNeedsCairo)
   {}
 
   FontType GetType() const override { return FontType::DWRITE; }
 
-  const RefPtr<IDWriteFontFace> GetFontFace() const { return mFontFace; }
+  const RefPtr<IDWriteFontFace>& GetFontFace() const { return mFontFace; }
+  const RefPtr<IDWriteFont>& GetFont() const { return mFont; }
   DWRITE_FONT_SIMULATIONS GetSimulations() const { return mSimulations; }
 
   bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) override;
 
   already_AddRefed<ScaledFont>
     CreateScaledFont(Float aGlyphSize,
                      const uint8_t* aInstanceData,
                      uint32_t aInstanceDataLength,
                      const FontVariation* aVariations,
                      uint32_t aNumVariations) override;
 
+  bool GetWRFontDescriptor(WRFontDescriptorOutput aCb, void* aBaton) override;
+
 private:
   RefPtr<IDWriteFontFace> mFontFace;
+  RefPtr<IDWriteFont> mFont;
   DWRITE_FONT_SIMULATIONS mSimulations;
   bool mNeedsCairo;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_UNSCALEDFONTDWRITE_H_ */
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -190,17 +190,17 @@ gfxDWriteFontFamily::FindStyleVariations
         // causes serious problem if web pages wants some elements to be
         // different style from others only with font-style.  For example,
         // <em> and <i> should be rendered as italic in the default style.
         if (fullID.EqualsLiteral("Meiryo Italic") ||
             fullID.EqualsLiteral("Meiryo Bold Italic")) {
             continue;
         }
 
-        gfxDWriteFontEntry *fe = new gfxDWriteFontEntry(fullID, font);
+        gfxDWriteFontEntry *fe = new gfxDWriteFontEntry(fullID, font, mIsSystemFontFamily);
         fe->SetForceGDIClassic(mForceGDIClassic);
         AddFontEntry(fe);
 
         // postscript/fullname if needed
         nsAutoString psname, fullname;
         if (fontInfoShouldHaveFaceNames) {
             aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
             if (!fullname.IsEmpty()) {
@@ -600,17 +600,17 @@ gfxDWriteFontEntry::CreateFontInstance(c
             sims |= DWRITE_FONT_SIMULATIONS_BOLD;
         }
         RefPtr<IDWriteFontFace> fontFace;
         nsresult rv = CreateFontFace(getter_AddRefs(fontFace), sims);
         if (NS_FAILED(rv)) {
             return nullptr;
         }
 
-        unscaledFont = new UnscaledFontDWrite(fontFace, sims);
+        unscaledFont = new UnscaledFontDWrite(fontFace, mIsSystemFont ? mFont : nullptr, sims);
         unscaledFontPtr = unscaledFont;
     }
 
     return new gfxDWriteFont(unscaledFont, this, aFontStyle, aNeedsBold);
 }
 
 nsresult
 gfxDWriteFontEntry::CreateFontFace(IDWriteFontFace **aFontFace,
@@ -1112,17 +1112,17 @@ gfxDWriteFontList::GetFontsFromCollectio
         RefPtr<gfxFontFamily> fam;
 
         if (mFontFamilies.GetWeak(name)) {
             continue;
         }
 
         nsDependentString familyName(enName.Elements());
 
-        fam = new gfxDWriteFontFamily(familyName, family);
+        fam = new gfxDWriteFontFamily(familyName, family, aCollection == mSystemFonts);
         if (!fam) {
             continue;
         }
 
         if (mBadUnderlineFamilyNames.Contains(name)) {
             fam->SetBadUnderlineFamily();
         }
         mFontFamilies.Put(name, fam);
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -35,19 +35,21 @@ class gfxDWriteFontFamily : public gfxFo
 public:
     /**
      * Constructs a new DWriteFont Family.
      *
      * \param aName Name identifying the family
      * \param aFamily IDWriteFontFamily object representing the directwrite
      * family object.
      */
-    gfxDWriteFontFamily(const nsAString& aName, 
-                        IDWriteFontFamily *aFamily)
-      : gfxFontFamily(aName), mDWFamily(aFamily), mForceGDIClassic(false) {}
+    gfxDWriteFontFamily(const nsAString& aName,
+                        IDWriteFontFamily *aFamily,
+                        bool aIsSystemFontFamily = false)
+      : gfxFontFamily(aName), mDWFamily(aFamily),
+        mIsSystemFontFamily(aIsSystemFontFamily), mForceGDIClassic(false) {}
     virtual ~gfxDWriteFontFamily();
     
     void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) final;
 
     void LocalizedName(nsAString& aLocalizedName) final;
 
     void ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
                        bool aNeedFullnamePostscriptNames,
@@ -66,35 +68,37 @@ public:
     }
 
 protected:
     // helper for FilterForFontList
     bool IsSymbolFontFamily() const;
 
     /** This font family's directwrite fontfamily object */
     RefPtr<IDWriteFontFamily> mDWFamily;
+    bool mIsSystemFontFamily;
     bool mForceGDIClassic;
 };
 
 /**
  * \brief Class representing DirectWrite FontEntry (a unique font style/family)
  */
 class gfxDWriteFontEntry : public gfxFontEntry
 {
 public:
     /**
      * Constructs a font entry.
      *
      * \param aFaceName The name of the corresponding font face.
      * \param aFont DirectWrite font object
      */
     gfxDWriteFontEntry(const nsAString& aFaceName,
-                              IDWriteFont *aFont) 
+                       IDWriteFont *aFont,
+                       bool aIsSystemFont = false)
       : gfxFontEntry(aFaceName), mFont(aFont), mFontFile(nullptr),
-        mForceGDIClassic(false)
+        mIsSystemFont(aIsSystemFont), mForceGDIClassic(false)
     {
         DWRITE_FONT_STYLE dwriteStyle = aFont->GetStyle();
         mStyle = (dwriteStyle == DWRITE_FONT_STYLE_ITALIC ?
                   NS_FONT_STYLE_ITALIC :
                   (dwriteStyle == DWRITE_FONT_STYLE_OBLIQUE ?
                    NS_FONT_STYLE_OBLIQUE : NS_FONT_STYLE_NORMAL));
         mStretch = FontStretchFromDWriteStretch(aFont->GetStretch());
         uint16_t weight = NS_ROUNDUP(aFont->GetWeight() - 50, 100);
@@ -118,17 +122,17 @@ public:
      * \param aStyle italic or oblique of font
      */
     gfxDWriteFontEntry(const nsAString& aFaceName,
                               IDWriteFont *aFont,
                               uint16_t aWeight,
                               int16_t aStretch,
                               uint8_t aStyle)
       : gfxFontEntry(aFaceName), mFont(aFont), mFontFile(nullptr),
-        mForceGDIClassic(false)
+        mIsSystemFont(false), mForceGDIClassic(false)
     {
         mWeight = aWeight;
         mStretch = aStretch;
         mStyle = aStyle;
         mIsLocalUserFont = true;
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
@@ -143,18 +147,19 @@ public:
      * \param aStyle italic or oblique of font
      */
     gfxDWriteFontEntry(const nsAString& aFaceName,
                               IDWriteFontFile *aFontFile,
                               IDWriteFontFileStream *aFontFileStream,
                               uint16_t aWeight,
                               int16_t aStretch,
                               uint8_t aStyle)
-      : gfxFontEntry(aFaceName), mFont(nullptr), mFontFile(aFontFile),
-        mFontFileStream(aFontFileStream), mForceGDIClassic(false)
+      : gfxFontEntry(aFaceName), mFont(nullptr),
+        mFontFile(aFontFile), mFontFileStream(aFontFileStream),
+        mIsSystemFont(false), mForceGDIClassic(false)
     {
         mWeight = aWeight;
         mStretch = aStretch;
         mStyle = aStyle;
         mIsDataUserFont = true;
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
@@ -205,16 +210,17 @@ protected:
 
     // font face corresponding to the mFont/mFontFile *without* any DWrite
     // style simulations applied
     RefPtr<IDWriteFontFace> mFontFace;
 
     DWRITE_FONT_FACE_TYPE mFaceType;
 
     int8_t mIsCJK;
+    bool mIsSystemFont;
     bool mForceGDIClassic;
 
     mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontDWrite> mUnscaledFont;
     mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontDWrite> mUnscaledFontBold;
 };
 
 // custom text renderer used to determine the fallback font for a given char
 class DWriteFontFallbackRenderer final : public IDWriteTextRenderer
--- a/gfx/webrender_bindings/Cargo.toml
+++ b/gfx/webrender_bindings/Cargo.toml
@@ -12,8 +12,12 @@ euclid = "0.15"
 app_units = "0.5.6"
 gleam = "0.4"
 log = "0.3"
 
 [dependencies.webrender]
 path = "../webrender"
 version = "0.53.1"
 default-features = false
+
+[target.'cfg(target_os = "windows")'.dependencies]
+dwrote = "0.4"
+
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -13,16 +13,19 @@ use webrender::DebugFlags;
 use webrender::{ApiRecordingReceiver, BinaryRecorder};
 use thread_profiler::register_thread_with_profiler;
 use moz2d_renderer::Moz2dImageRenderer;
 use app_units::Au;
 use rayon;
 use euclid::SideOffsets2D;
 use log::{set_logger, shutdown_logger, LogLevelFilter, Log, LogLevel, LogMetadata, LogRecord};
 
+#[cfg(target_os = "windows")]
+use dwrote::{FontDescriptor, FontWeight, FontStretch, FontStyle};
+
 extern crate webrender_api;
 
 /// cbindgen:field-names=[mNamespace, mHandle]
 type WrExternalImageBufferType = ExternalImageType;
 
 /// cbindgen:field-names=[mHandle]
 /// cbindgen:derive-lt=true
 /// cbindgen:derive-lte=true
@@ -977,16 +980,30 @@ pub extern "C" fn wr_resource_updates_ad
     resources: &mut ResourceUpdates,
     key: WrFontKey,
     bytes: &mut WrVecU8,
     index: u32
 ) {
     resources.add_raw_font(key, bytes.flush_into_vec(), index);
 }
 
+#[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),
+    }
+}
+
 #[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();
     NativeFontHandle {
         pathname: String::from(cstr.to_str().unwrap()),
--- a/gfx/webrender_bindings/src/lib.rs
+++ b/gfx/webrender_bindings/src/lib.rs
@@ -8,11 +8,14 @@ extern crate webrender;
 extern crate webrender_api;
 extern crate euclid;
 extern crate app_units;
 extern crate gleam;
 extern crate rayon;
 extern crate thread_profiler;
 extern crate log;
 
+#[cfg(target_os = "windows")]
+extern crate dwrote;
+
 #[allow(non_snake_case)]
 pub mod bindings;
 pub mod moz2d_renderer;
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -1512,16 +1512,17 @@ dependencies = [
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender_bindings"
 version = "0.1.0"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.53.1",
  "webrender_api 0.53.1",
 ]
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -1524,16 +1524,17 @@ dependencies = [
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender_bindings"
 version = "0.1.0"
 dependencies = [
  "app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.53.1",
  "webrender_api 0.53.1",
 ]