Bug 1433060 - Support font variations in Moz2d recording stream on Windows, so printing with variation fonts works properly. r=lsalzman
authorJonathan Kew <jkew@mozilla.com>
Mon, 26 Feb 2018 21:21:01 +0000
changeset 458024 9dbf18bf5e08b28c63e686b90362614812d2fa56
parent 458023 34d3a58cafc25d01d081195d2a396bc77342bf2c
child 458025 07f09cd2e887af248f28b5c11800ba6a7efd759b
push id8799
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 16:46:23 +0000
treeherdermozilla-beta@15334014dc67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsalzman
bugs1433060
milestone60.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 1433060 - Support font variations in Moz2d recording stream on Windows, so printing with variation fonts works properly. r=lsalzman
gfx/2d/ScaledFontDWrite.cpp
gfx/2d/dw-extra.h
gfx/2d/moz.build
gfx/thebes/dw-extra.h
gfx/thebes/gfxDWriteFontList.h
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -6,16 +6,30 @@
 
 #include "ScaledFontDWrite.h"
 #include "UnscaledFontDWrite.h"
 #include "PathD2D.h"
 #include "gfxFont.h"
 #include "Logging.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 
+#include "dwrite_3.h"
+
+// Currently, we build with WINVER=0x601 (Win7), which means newer
+// declarations in dwrite_3.h will not be visible. Also, we don't
+// yet have the Fall Creators Update SDK available on build machines,
+// so even with updated WINVER, some of the interfaces we need would
+// not be present.
+// To work around this, until the build environment is updated,
+// we #include an extra header that contains copies of the relevant
+// classes/interfaces we need.
+#if !defined(__MINGW32__) && WINVER < 0x0A00
+#include "dw-extra.h"
+#endif
+
 using namespace std;
 
 #ifdef USE_SKIA
 #include "PathSkia.h"
 #include "skia/include/core/SkPaint.h"
 #include "skia/include/core/SkPath.h"
 #include "skia/include/ports/SkTypeface_win.h"
 #endif
@@ -373,21 +387,69 @@ UnscaledFontDWrite::GetWRFontDescriptor(
   // 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;
 }
 
+// Helper for ScaledFontDWrite::GetFontInstanceData: if the font has variation
+// axes, get their current values into the aOutput vector.
+static void
+GetVariationsFromFontFace(IDWriteFontFace* aFace,
+                          std::vector<FontVariation>* aOutput)
+{
+  RefPtr<IDWriteFontFace5> ff5;
+  aFace->QueryInterface(__uuidof(IDWriteFontFace5), (void**)getter_AddRefs(ff5));
+  if (!ff5 || !ff5->HasVariations()) {
+    return;
+  }
+
+  uint32_t count = ff5->GetFontAxisValueCount();
+  if (!count) {
+    return;
+  }
+
+  RefPtr<IDWriteFontResource> res;
+  if (FAILED(ff5->GetFontResource(getter_AddRefs(res)))) {
+    return;
+  }
+
+  std::vector<DWRITE_FONT_AXIS_VALUE> values(count);
+  if (FAILED(ff5->GetFontAxisValues(values.data(), count))) {
+    return;
+  }
+
+  aOutput->reserve(count);
+  for (uint32_t i = 0; i < count; i++) {
+    DWRITE_FONT_AXIS_ATTRIBUTES attr = res->GetFontAxisAttributes(i);
+    if (attr & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
+      float v = values[i].value;
+      uint32_t t = TRUETYPE_TAG(uint8_t(values[i].axisTag),
+                                uint8_t(values[i].axisTag >> 8),
+                                uint8_t(values[i].axisTag >> 16),
+                                uint8_t(values[i].axisTag >> 24));
+      aOutput->push_back(FontVariation{uint32_t(t), float(v)});
+    }
+  }
+}
+
 bool
 ScaledFontDWrite::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
 {
   InstanceData instance(this);
-  aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance), nullptr, 0, aBaton);
+
+  // If the font has variations, get the list of axis values.
+  std::vector<FontVariation> variations;
+  GetVariationsFromFontFace(mFontFace, &variations);
+
+  aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance),
+      variations.data(), variations.size(), aBaton);
+
   return true;
 }
 
 bool
 ScaledFontDWrite::GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
                                            Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
                                            std::vector<FontVariation>* aOutVariations)
 {
@@ -404,32 +466,94 @@ ScaledFontDWrite::GetWRFontInstanceOptio
   if (ForceGDIMode()) {
     options.flags |= wr::FontInstanceFlags::FORCE_GDI;
   }
   options.bg_color = wr::ToColorU(Color());
   *aOutOptions = Some(options);
   return true;
 }
 
+// Helper for UnscaledFontDWrite::CreateScaledFont: create a clone of the
+// given IDWriteFontFace, with specified variation-axis values applied.
+// Returns nullptr in case of failure.
+static already_AddRefed<IDWriteFontFace5>
+CreateFaceWithVariations(IDWriteFontFace* aFace,
+                         const FontVariation* aVariations,
+                         uint32_t aNumVariations)
+{
+  auto makeDWriteAxisTag = [](uint32_t aTag) {
+    return DWRITE_MAKE_FONT_AXIS_TAG((aTag >> 24) & 0xff,
+                                     (aTag >> 16) & 0xff,
+                                     (aTag >> 8) & 0xff,
+                                     aTag & 0xff);
+  };
+
+  RefPtr<IDWriteFontFace5> ff5;
+  aFace->QueryInterface(__uuidof(IDWriteFontFace5), (void**)getter_AddRefs(ff5));
+  if (!ff5) {
+    return nullptr;
+  }
+
+  DWRITE_FONT_SIMULATIONS sims = aFace->GetSimulations();
+  RefPtr<IDWriteFontResource> res;
+  if (FAILED(ff5->GetFontResource(getter_AddRefs(res)))) {
+    return nullptr;
+  }
+
+  std::vector<DWRITE_FONT_AXIS_VALUE> fontAxisValues;
+  fontAxisValues.reserve(aNumVariations);
+  for (uint32_t i = 0; i < aNumVariations; i++) {
+    DWRITE_FONT_AXIS_VALUE axisValue = {
+      makeDWriteAxisTag(aVariations[i].mTag),
+      aVariations[i].mValue
+    };
+    fontAxisValues.push_back(axisValue);
+  }
+
+  RefPtr<IDWriteFontFace5> newFace;
+  if (FAILED(res->CreateFontFace(sims,
+                                 fontAxisValues.data(),
+                                 fontAxisValues.size(),
+                                 getter_AddRefs(newFace)))) {
+    return nullptr;
+  }
+
+  return newFace.forget();
+}
+
 already_AddRefed<ScaledFont>
 UnscaledFontDWrite::CreateScaledFont(Float aGlyphSize,
                                      const uint8_t* aInstanceData,
                                      uint32_t aInstanceDataLength,
                                      const FontVariation* aVariations,
                                      uint32_t aNumVariations)
 {
   if (aInstanceDataLength < sizeof(ScaledFontDWrite::InstanceData)) {
     gfxWarning() << "DWrite scaled font instance data is truncated.";
     return nullptr;
   }
 
+  IDWriteFontFace* face = mFontFace;
+
+  // If variations are required, we create a separate IDWriteFontFace5 with
+  // the requested settings applied.
+  RefPtr<IDWriteFontFace5> ff5;
+  if (aNumVariations) {
+    ff5 = CreateFaceWithVariations(mFontFace, aVariations, aNumVariations);
+    if (ff5) {
+      face = ff5;
+    } else {
+      gfxWarning() << "Failed to create IDWriteFontFace5 with variations.";
+    }
+  }
+
   const ScaledFontDWrite::InstanceData *instanceData =
     reinterpret_cast<const ScaledFontDWrite::InstanceData*>(aInstanceData);
   RefPtr<ScaledFontBase> scaledFont =
-    new ScaledFontDWrite(mFontFace, this, aGlyphSize,
+    new ScaledFontDWrite(face, this, aGlyphSize,
                          instanceData->mUseEmbeddedBitmap,
                          instanceData->mForceGDIMode,
                          nullptr,
                          instanceData->mGamma,
                          instanceData->mContrast);
 
   if (mNeedsCairo && !scaledFont->PopulateCairoScaledFont()) {
     gfxWarning() << "Unable to create cairo scaled font DWrite font.";
rename from gfx/thebes/dw-extra.h
rename to gfx/2d/dw-extra.h
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -72,16 +72,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('coc
         'UnscaledFontMac.h',
     ]
     UNIFIED_SOURCES += [
         'NativeFontResourceMac.cpp',
         'ScaledFontMac.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXPORTS.mozilla.gfx += [
+        'dw-extra.h',
         'UnscaledFontDWrite.h',
         'UnscaledFontGDI.h',
     ]
     SOURCES += [
         'DrawTargetD2D1.cpp',
         'ExtendInputEffectD2D1.cpp',
         'FilterNodeD2D1.cpp',
         'JobScheduler_win32.cpp',
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -14,17 +14,17 @@
  // declarations in dwrite_3.h will not be visible. Also, we don't
  // yet have the Fall Creators Update SDK available on build machines,
  // so even with updated WINVER, some of the interfaces we need would
  // not be present.
  // To work around this, until the build environment is updated,
  // we #include an extra header that contains copies of the relevant
  // classes/interfaces we need.
 #if !defined(__MINGW32__) && WINVER < 0x0A00
-#include "dw-extra.h"
+#include "mozilla/gfx/dw-extra.h"
 #endif
 
 #include "gfxFont.h"
 #include "gfxUserFontSet.h"
 #include "cairo-win32.h"
 
 #include "gfxPlatformFontList.h"
 #include "gfxPlatform.h"