Bug 1565158 - Allow forcing DWrite symmetric rendering mode. r=jrmuizel, a=RyanVM
authorLee Salzman <lsalzman@mozilla.com>
Fri, 19 Jul 2019 03:56:50 +0000
changeset 544809 dd328d8b3a0ff4079a5aff7d4996725d96ffe17d
parent 544808 b94ef678a4be6cf724bbe4e2a33c1af8e264e811
child 544810 a5573dc631138b3a3d4415bb3c6b500a9a65eab0
push id2131
push userffxbld-merge
push dateMon, 26 Aug 2019 18:30:20 +0000
treeherdermozilla-release@b19ffb3ca153 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel, RyanVM
bugs1565158
milestone69.0
Bug 1565158 - Allow forcing DWrite symmetric rendering mode. r=jrmuizel, a=RyanVM Differential Revision: https://phabricator.services.mozilla.com/D38569
gfx/2d/2D.h
gfx/2d/Factory.cpp
gfx/2d/ScaledFontDWrite.cpp
gfx/2d/ScaledFontDWrite.h
gfx/skia/skia/include/ports/SkTypeface_win.h
gfx/skia/skia/src/ports/SkFontHost_win.cpp
gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp
gfx/skia/skia/src/ports/SkTypeface_win_dw.h
gfx/thebes/gfxDWriteFonts.cpp
gfx/wr/webrender/src/platform/windows/font.rs
gfx/wr/webrender_api/src/font.rs
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1834,17 +1834,17 @@ class GFX2D_API Factory {
 
   static uint64_t GetD2DVRAMUsageDrawTarget();
   static uint64_t GetD2DVRAMUsageSourceSurface();
   static void D2DCleanup();
 
   static already_AddRefed<ScaledFont> CreateScaledFontForDWriteFont(
       IDWriteFontFace* aFontFace, const gfxFontStyle* aStyle,
       const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
-      bool aUseEmbeddedBitmap, bool aForceGDIMode,
+      bool aUseEmbeddedBitmap, int aRenderingMode,
       IDWriteRenderingParams* aParams, Float aGamma, Float aContrast);
 
   static void SetSystemTextQuality(uint8_t aQuality);
 
  private:
   static StaticRefPtr<ID2D1Device> mD2D1Device;
   static StaticRefPtr<ID3D11Device> mD3D11Device;
   static StaticRefPtr<IDWriteFactory> mDWriteFactory;
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -954,20 +954,21 @@ void Factory::D2DCleanup() {
     mD2D1Device = nullptr;
   }
   DrawTargetD2D1::CleanupD2D();
 }
 
 already_AddRefed<ScaledFont> Factory::CreateScaledFontForDWriteFont(
     IDWriteFontFace* aFontFace, const gfxFontStyle* aStyle,
     const RefPtr<UnscaledFont>& aUnscaledFont, float aSize,
-    bool aUseEmbeddedBitmap, bool aForceGDIMode,
+    bool aUseEmbeddedBitmap, int aRenderingMode,
     IDWriteRenderingParams* aParams, Float aGamma, Float aContrast) {
   return MakeAndAddRef<ScaledFontDWrite>(aFontFace, aUnscaledFont, aSize,
-                                         aUseEmbeddedBitmap, aForceGDIMode,
+                                         aUseEmbeddedBitmap,
+                                         (DWRITE_RENDERING_MODE)aRenderingMode,
                                          aParams, aGamma, aContrast, aStyle);
 }
 
 #endif  // WIN32
 
 #ifdef USE_SKIA
 already_AddRefed<DrawTarget> Factory::CreateDrawTargetWithSkCanvas(
     SkCanvas* aCanvas) {
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -121,24 +121,24 @@ static inline DWRITE_FONT_STRETCH DWrite
     return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
   }
   return DWRITE_FONT_STRETCH_UNDEFINED;
 }
 
 ScaledFontDWrite::ScaledFontDWrite(IDWriteFontFace* aFontFace,
                                    const RefPtr<UnscaledFont>& aUnscaledFont,
                                    Float aSize, bool aUseEmbeddedBitmap,
-                                   bool aForceGDIMode,
+                                   DWRITE_RENDERING_MODE aRenderingMode,
                                    IDWriteRenderingParams* aParams,
                                    Float aGamma, Float aContrast,
                                    const gfxFontStyle* aStyle)
     : ScaledFontBase(aUnscaledFont, aSize),
       mFontFace(aFontFace),
       mUseEmbeddedBitmap(aUseEmbeddedBitmap),
-      mForceGDIMode(aForceGDIMode),
+      mRenderingMode(aRenderingMode),
       mParams(aParams),
       mGamma(aGamma),
       mContrast(aContrast) {
   if (aStyle) {
     mStyle = SkFontStyle(aStyle->weight.ToIntRounded(),
                          DWriteFontStretchFromStretch(aStyle->stretch),
                          // FIXME(jwatt): also use kOblique_Slant
                          aStyle->style == FontSlantStyle::Normal()
@@ -180,17 +180,17 @@ SkTypeface* ScaledFontDWrite::CreateSkTy
 
   Float contrast = mContrast;
   // Skia doesn't support a contrast value outside of 0-1, so default to 1.0
   if (contrast < 0.0f || contrast > 1.0f) {
     contrast = 1.0f;
   }
 
   return SkCreateTypefaceFromDWriteFont(factory, mFontFace, mStyle,
-                                        mForceGDIMode, gamma, contrast);
+                                        mRenderingMode, gamma, contrast);
 }
 #endif
 
 void ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer& aBuffer,
                                            PathBuilder* aBuilder,
                                            const Matrix* aTransformHint) {
   BackendType backendType = aBuilder->GetBackendType();
   if (backendType == BackendType::CAPTURE) {
@@ -412,25 +412,29 @@ bool UnscaledFontDWrite::GetWRFontDescri
       fileName.size() * sizeof(WCHAR), index, aBaton);
   return true;
 }
 
 ScaledFontDWrite::InstanceData::InstanceData(
     const wr::FontInstanceOptions* aOptions,
     const wr::FontInstancePlatformOptions* aPlatformOptions)
     : mUseEmbeddedBitmap(false),
-      mForceGDIMode(false),
+      mRenderingMode(DWRITE_RENDERING_MODE_DEFAULT),
       mGamma(2.2f),
       mContrast(1.0f) {
   if (aOptions) {
     if (aOptions->flags & wr::FontInstanceFlags_EMBEDDED_BITMAPS) {
       mUseEmbeddedBitmap = true;
     }
     if (aOptions->flags & wr::FontInstanceFlags_FORCE_GDI) {
-      mForceGDIMode = true;
+      mRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
+    } else if (aOptions->flags & wr::FontInstanceFlags_FORCE_SYMMETRIC) {
+      mRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
+    } else if (aOptions->flags & wr::FontInstanceFlags_NO_SYMMETRIC) {
+      mRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
     }
   }
   if (aPlatformOptions) {
     mGamma = aPlatformOptions->gamma / 100.0f;
     mContrast = aPlatformOptions->contrast / 100.0f;
   }
 }
 
@@ -501,16 +505,26 @@ bool ScaledFontDWrite::GetWRFontInstance
   if (UseEmbeddedBitmaps()) {
     options.flags |= wr::FontInstanceFlags_EMBEDDED_BITMAPS;
   }
   if (ForceGDIMode()) {
     options.flags |= wr::FontInstanceFlags_FORCE_GDI;
   } else {
     options.flags |= wr::FontInstanceFlags_SUBPIXEL_POSITION;
   }
+  switch (GetRenderingMode()) {
+    case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
+      options.flags |= wr::FontInstanceFlags_FORCE_SYMMETRIC;
+      break;
+    case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
+      options.flags |= wr::FontInstanceFlags_NO_SYMMETRIC;
+      break;
+    default:
+      break;
+  }
   if (Factory::GetBGRSubpixelOrder()) {
     options.flags |= wr::FontInstanceFlags_SUBPIXEL_BGR;
   }
   options.bg_color = wr::ToColorU(Color());
   options.synthetic_italics =
       wr::DegreesToSyntheticItalics(GetSyntheticObliqueAngle());
 
   wr::FontInstancePlatformOptions platformOptions;
@@ -590,17 +604,17 @@ already_AddRefed<ScaledFont> UnscaledFon
       face = ff5;
     } else {
       gfxWarning() << "Failed to create IDWriteFontFace5 with variations.";
     }
   }
 
   RefPtr<ScaledFontBase> scaledFont = new ScaledFontDWrite(
       face, this, aGlyphSize, instanceData.mUseEmbeddedBitmap,
-      instanceData.mForceGDIMode, nullptr, instanceData.mGamma,
+      instanceData.mRenderingMode, nullptr, instanceData.mGamma,
       instanceData.mContrast);
 
   if (mNeedsCairo && !scaledFont->PopulateCairoScaledFont()) {
     gfxWarning() << "Unable to create cairo scaled font DWrite font.";
     return nullptr;
   }
 
   return scaledFont.forget();
--- a/gfx/2d/ScaledFontDWrite.h
+++ b/gfx/2d/ScaledFontDWrite.h
@@ -22,25 +22,27 @@ class UnscaledFontDWrite;
 class ScaledFontDWrite final : public ScaledFontBase {
  public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontDWrite, override)
   ScaledFontDWrite(IDWriteFontFace* aFont,
                    const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize)
       : ScaledFontBase(aUnscaledFont, aSize),
         mFontFace(aFont),
         mUseEmbeddedBitmap(false),
-        mForceGDIMode(false),
+        mRenderingMode(DWRITE_RENDERING_MODE_DEFAULT),
         mGamma(2.2f),
         mContrast(1.0f) {}
 
   ScaledFontDWrite(IDWriteFontFace* aFontFace,
                    const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
-                   bool aUseEmbeddedBitmap, bool aForceGDIMode,
-                   IDWriteRenderingParams* aParams, Float aGamma,
-                   Float aContrast, const gfxFontStyle* aStyle = nullptr);
+                   bool aUseEmbeddedBitmap,
+                   DWRITE_RENDERING_MODE aRenderingMode,
+                   IDWriteRenderingParams* aParams,
+                   Float aGamma, Float aContrast,
+                   const gfxFontStyle* aStyle = nullptr);
 
   FontType GetType() const override { return FontType::DWRITE; }
 
   already_AddRefed<Path> GetPathForGlyphs(const GlyphBuffer& aBuffer,
                                           const DrawTarget* aTarget) override;
   void CopyGlyphsToBuilder(const GlyphBuffer& aBuffer, PathBuilder* aBuilder,
                            const Matrix* aTransformHint) override;
 
@@ -56,27 +58,28 @@ class ScaledFontDWrite final : public Sc
 
   bool GetWRFontInstanceOptions(
       Maybe<wr::FontInstanceOptions>* aOutOptions,
       Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
       std::vector<FontVariation>* aOutVariations) override;
 
   AntialiasMode GetDefaultAAMode() override;
 
-  bool UseEmbeddedBitmaps() { return mUseEmbeddedBitmap; }
-  bool ForceGDIMode() { return mForceGDIMode; }
+  bool UseEmbeddedBitmaps() const { return mUseEmbeddedBitmap; }
+  bool ForceGDIMode() const { return mRenderingMode == DWRITE_RENDERING_MODE_GDI_CLASSIC; }
+  DWRITE_RENDERING_MODE GetRenderingMode() const { return mRenderingMode; }
 
 #ifdef USE_SKIA
   SkTypeface* CreateSkTypeface() override;
   SkFontStyle mStyle;
 #endif
 
   RefPtr<IDWriteFontFace> mFontFace;
   bool mUseEmbeddedBitmap;
-  bool mForceGDIMode;
+  DWRITE_RENDERING_MODE mRenderingMode;
   // DrawTargetD2D1 requires the IDWriteRenderingParams,
   // but we also separately need to store the gamma and contrast
   // since Skia needs to be able to access these without having
   // to use the full set of DWrite parameters (which would be
   // required to recreate an IDWriteRenderingParams) in a
   // DrawTargetRecording playback.
   RefPtr<IDWriteRenderingParams> mParams;
   Float mGamma;
@@ -89,25 +92,25 @@ class ScaledFontDWrite final : public Sc
 
  private:
   friend class NativeFontResourceDWrite;
   friend class UnscaledFontDWrite;
 
   struct InstanceData {
     explicit InstanceData(ScaledFontDWrite* aScaledFont)
         : mUseEmbeddedBitmap(aScaledFont->mUseEmbeddedBitmap),
-          mForceGDIMode(aScaledFont->mForceGDIMode),
+          mRenderingMode(aScaledFont->mRenderingMode),
           mGamma(aScaledFont->mGamma),
           mContrast(aScaledFont->mContrast) {}
 
     InstanceData(const wr::FontInstanceOptions* aOptions,
                  const wr::FontInstancePlatformOptions* aPlatformOptions);
 
     bool mUseEmbeddedBitmap;
-    bool mForceGDIMode;
+    DWRITE_RENDERING_MODE mRenderingMode;
     Float mGamma;
     Float mContrast;
   };
 };
 
 }  // namespace gfx
 }  // namespace mozilla
 
--- a/gfx/skia/skia/include/ports/SkTypeface_win.h
+++ b/gfx/skia/skia/include/ports/SkTypeface_win.h
@@ -48,17 +48,17 @@ struct IDWriteFontFallback;
 /**
  *  Like the other Typeface create methods, this returns a new reference to the
  *  corresponding typeface for the specified dwrite font. The caller is responsible
  *  for calling unref() when it is finished.
  */
 SK_API SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFactory* aFactory,
                                                   IDWriteFontFace* aFontFace,
                                                   SkFontStyle aStyle,
-                                                  bool aForceGDI,
+                                                  DWRITE_RENDERING_MODE aRenderingMode,
                                                   float aGamma,
                                                   float aContrast);
 
 SK_API sk_sp<SkFontMgr> SkFontMgr_New_GDI();
 SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory = NULL,
                                                   IDWriteFontCollection* collection = NULL);
 SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
                                                   IDWriteFontCollection* collection,
--- a/gfx/skia/skia/src/ports/SkFontHost_win.cpp
+++ b/gfx/skia/skia/src/ports/SkFontHost_win.cpp
@@ -346,21 +346,21 @@ SkTypeface* SkCreateTypefaceFromLOGFONT(
 }
 
 /***
  * This guy is public.
  */
 SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFactory* aFactory,
                                            IDWriteFontFace* aFontFace,
                                            SkFontStyle aStyle,
-                                           bool aForceGDI,
+                                           DWRITE_RENDERING_MODE aRenderingMode,
                                            float aGamma,
                                            float aContrast)
 {
-  return DWriteFontTypeface::Create(aFactory, aFontFace, aStyle, aForceGDI, aGamma, aContrast);
+  return DWriteFontTypeface::Create(aFactory, aFontFace, aStyle, aRenderingMode, aGamma, aContrast);
 }
 
 /**
  *  The created SkTypeface takes ownership of fontMemResource.
  */
 sk_sp<SkTypeface> SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
     LOGFONT lf = origLF;
     make_canonical(&lf);
--- a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp
+++ b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp
@@ -330,30 +330,33 @@ SkScalerContext_DW::SkScalerContext_DW(s
         fTextSizeMeasure = gdiTextSize;
         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
 
     // If the font has a gasp table version 1, use it to determine symmetric rendering.
     } else if ((get_gasp_range(typeface, SkScalarRoundToInt(gdiTextSize), &range) &&
                 range.fVersion >= 1) ||
                realTextSize > SkIntToScalar(20) || !is_hinted(this, typeface)) {
         fTextSizeRender = realTextSize;
+        fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
         fTextSizeMeasure = realTextSize;
         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
 
-        IDWriteRenderingParams* params = sk_get_dwrite_default_rendering_params();
         DWriteFontTypeface* typeface = static_cast<DWriteFontTypeface*>(getTypeface());
-        if (params &&
-            !SUCCEEDED(typeface->fDWriteFontFace->GetRecommendedRenderingMode(
-                fTextSizeRender,
-                1.0f,
-                fMeasuringMode,
-                params,
-                &fRenderingMode))) {
-            fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
+        switch (typeface->GetRenderingMode()) {
+        case DWRITE_RENDERING_MODE_NATURAL:
+        case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
+            fRenderingMode = typeface->GetRenderingMode();
+            break;
+        default:
+            if (IDWriteRenderingParams* params = sk_get_dwrite_default_rendering_params()) {
+                typeface->fDWriteFontFace->GetRecommendedRenderingMode(
+                    fTextSizeRender, 1.0f, fMeasuringMode, params, &fRenderingMode);
+            }
+            break;
         }
 
         // We don't support outline mode right now.
         if (fRenderingMode == DWRITE_RENDERING_MODE_OUTLINE) {
             fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
         }
 
     // Fonts with hints, no gasp or gasp version 0, and below 20px get non-symmetric rendering.
--- a/gfx/skia/skia/src/ports/SkTypeface_win_dw.h
+++ b/gfx/skia/skia/src/ports/SkTypeface_win_dw.h
@@ -52,17 +52,17 @@ private:
                        IDWriteFontCollectionLoader* fontCollectionLoader = nullptr)
         : SkTypeface(style, false)
         , fFactory(SkRefComPtr(factory))
         , fDWriteFontCollectionLoader(SkSafeRefComPtr(fontCollectionLoader))
         , fDWriteFontFileLoader(SkSafeRefComPtr(fontFileLoader))
         , fDWriteFontFamily(SkSafeRefComPtr(fontFamily))
         , fDWriteFont(SkSafeRefComPtr(font))
         , fDWriteFontFace(SkRefComPtr(fontFace))
-        , fForceGDI(false)
+        , fRenderingMode(DWRITE_RENDERING_MODE_DEFAULT)
         , fGamma(2.2f)
         , fContrast(1.0f)
     {
         if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace1))) {
             // IUnknown::QueryInterface states that if it fails, punk will be set to nullptr.
             // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx
             SkASSERT_RELEASE(nullptr == fDWriteFontFace1.get());
         }
@@ -100,30 +100,31 @@ public:
         return sk_sp<DWriteFontTypeface>(
             new DWriteFontTypeface(get_style(font), factory, fontFace, font, fontFamily,
                                    fontFileLoader, fontCollectionLoader));
     }
 
     static DWriteFontTypeface* Create(IDWriteFactory* factory,
                                       IDWriteFontFace* fontFace,
                                       SkFontStyle aStyle,
-                                      bool aForceGDI,
+                                      DWRITE_RENDERING_MODE aRenderingMode,
                                       float aGamma,
                                       float aContrast) {
         DWriteFontTypeface* typeface =
                 new DWriteFontTypeface(aStyle, factory, fontFace,
                                        nullptr, nullptr,
                                        nullptr, nullptr);
-        typeface->fForceGDI = aForceGDI;
+        typeface->fRenderingMode = aRenderingMode;
         typeface->fGamma = aGamma;
         typeface->fContrast = aContrast;
         return typeface;
     }
 
-    bool ForceGDI() const { return fForceGDI; }
+    bool ForceGDI() const { return fRenderingMode == DWRITE_RENDERING_MODE_GDI_CLASSIC; }
+    DWRITE_RENDERING_MODE GetRenderingMode() const { return fRenderingMode; }
 
 protected:
     void weak_dispose() const override {
         if (fDWriteFontCollectionLoader.get()) {
             HRV(fFactory->UnregisterFontCollectionLoader(fDWriteFontCollectionLoader.get()));
         }
         if (fDWriteFontFileLoader.get()) {
             HRV(fFactory->UnregisterFontFileLoader(fDWriteFontFileLoader.get()));
@@ -151,14 +152,14 @@ protected:
                                      int coordinateCount) const override;
     int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
                                        int parameterCount) const override;
     int onGetTableTags(SkFontTableTag tags[]) const override;
     size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
 
 private:
     typedef SkTypeface INHERITED;
-    bool fForceGDI;
+    DWRITE_RENDERING_MODE fRenderingMode;
     float fGamma;
     float fContrast;
 };
 
 #endif
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -641,21 +641,24 @@ already_AddRefed<ScaledFont> gfxDWriteFo
 
     IDWriteRenderingParams* params =
         gfxWindowsPlatform::GetPlatform()->GetRenderingParams(
             UsingClearType()
                 ? (forceGDI ? gfxWindowsPlatform::TEXT_RENDERING_GDI_CLASSIC
                             : gfxWindowsPlatform::TEXT_RENDERING_NORMAL)
                 : gfxWindowsPlatform::TEXT_RENDERING_NO_CLEARTYPE);
 
+    DWRITE_RENDERING_MODE renderingMode =
+      forceGDI ? DWRITE_RENDERING_MODE_GDI_CLASSIC : params->GetRenderingMode();
+
     const gfxFontStyle* fontStyle = GetStyle();
     mAzureScaledFont = Factory::CreateScaledFontForDWriteFont(
         mFontFace, fontStyle, GetUnscaledFont(), GetAdjustedSize(),
-        useEmbeddedBitmap, forceGDI, params, params->GetGamma(),
-        params->GetEnhancedContrast());
+        useEmbeddedBitmap, (int)renderingMode,
+        params, params->GetGamma(), params->GetEnhancedContrast());
     if (!mAzureScaledFont) {
       return nullptr;
     }
     InitializeScaledFont();
     mAzureScaledFontUsedClearType = UsingClearType();
   }
 
   if (aTarget->GetBackendType() == BackendType::CAIRO) {
--- a/gfx/wr/webrender/src/platform/windows/font.rs
+++ b/gfx/wr/webrender/src/platform/windows/font.rs
@@ -117,16 +117,20 @@ fn dwrite_render_mode(
     measure_mode: dwrote::DWRITE_MEASURING_MODE,
     bitmaps: bool,
 ) -> dwrote::DWRITE_RENDERING_MODE {
     let dwrite_render_mode = match font.render_mode {
         FontRenderMode::Mono => dwrote::DWRITE_RENDERING_MODE_ALIASED,
         FontRenderMode::Alpha | FontRenderMode::Subpixel => {
             if bitmaps || font.flags.contains(FontInstanceFlags::FORCE_GDI) {
                 dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC
+            } else if font.flags.contains(FontInstanceFlags::FORCE_SYMMETRIC) {
+                dwrote::DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC
+            } else if font.flags.contains(FontInstanceFlags::NO_SYMMETRIC) {
+                dwrote::DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL
             } else {
                 font_face.get_recommended_rendering_mode_default_params(em_size, 1.0, measure_mode)
             }
         }
     };
 
     if dwrite_render_mode == dwrote::DWRITE_RENDERING_MODE_OUTLINE {
         // Outline mode is not supported
--- a/gfx/wr/webrender_api/src/font.rs
+++ b/gfx/wr/webrender_api/src/font.rs
@@ -170,16 +170,18 @@ bitflags! {
         const SUBPIXEL_BGR      = 1 << 3;
         const TRANSPOSE         = 1 << 4;
         const FLIP_X            = 1 << 5;
         const FLIP_Y            = 1 << 6;
         const SUBPIXEL_POSITION = 1 << 7;
 
         // Windows flags
         const FORCE_GDI         = 1 << 16;
+        const FORCE_SYMMETRIC   = 1 << 17;
+        const NO_SYMMETRIC      = 1 << 18;
 
         // Mac flags
         const FONT_SMOOTHING    = 1 << 16;
 
         // FreeType flags
         const FORCE_AUTOHINT    = 1 << 16;
         const NO_AUTOHINT       = 1 << 17;
         const VERTICAL_LAYOUT   = 1 << 18;