Bug 1436048 part 2 - Store FontWeight as a fixed-point value to support fractional font-weight values. r=jwatt
authorJonathan Kew <jkew@mozilla.com>
Mon, 16 Apr 2018 20:26:08 +0100
changeset 413874 0ceabd10aac2
parent 413873 c95f5a65950c
child 413970 a4abe0e7d569
child 413987 8eaced3b0ff4
push id33852
push usershindli@mozilla.com
push date2018-04-16 21:59 +0000
treeherdermozilla-central@0ceabd10aac2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt
bugs1436048
milestone61.0a1
first release with
nightly linux32
0ceabd10aac2 / 61.0a1 / 20180416220315 / files
nightly linux64
0ceabd10aac2 / 61.0a1 / 20180416220315 / files
nightly mac
0ceabd10aac2 / 61.0a1 / 20180416220315 / files
nightly win32
0ceabd10aac2 / 61.0a1 / 20180416220315 / files
nightly win64
0ceabd10aac2 / 61.0a1 / 20180416220315 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1436048 part 2 - Store FontWeight as a fixed-point value to support fractional font-weight values. r=jwatt
gfx/src/FontPropertyTypes.h
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFontEntry.h
gfx/thebes/gfxGDIFont.cpp
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxGDIFontList.h
gfx/thebes/gfxUserFontSet.cpp
layout/style/FontFaceSet.cpp
--- a/gfx/src/FontPropertyTypes.h
+++ b/gfx/src/FontPropertyTypes.h
@@ -4,130 +4,333 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* font specific types shared by both thebes and layout */
 
 #ifndef GFX_FONT_PROPERTY_TYPES_H
 #define GFX_FONT_PROPERTY_TYPES_H
 
 #include <cstdint>
+#include <cmath>
+#include "mozilla/Assertions.h"
 
 /*
  * This file is separate from gfxFont.h so that layout can include it
  * without bringing in gfxFont.h and everything it includes.
  */
 
 namespace mozilla {
 
 /**
- * A type that will in future encode a value as fixed point.
+ * Generic template for font property type classes that use a fixed-point
+ * internal representation.
+ * Template parameters:
+ *   T - the integer type to use as the internal representation (e.g. uint16_t)
+ *       * NOTE that T must NOT be plain /int/, as that would result in
+ *         ambiguity between constructors from /int/ and /T/, which mean
+ *         different things.
+ *   FractionBits - number of bits to use for the fractional part
+ *   Min, Max - [inclusive] limits to the range of values that may be stored
+ * Values are constructed from and exposed as floating-point, but stored
+ * internally as fixed point, so there will be a quantization effect on
+ * fractional values, depending on the number of fractional bits used.
+ * Using (16-bit) fixed-point types rather than floats for these style
+ * attributes reduces the memory footprint of gfxFontEntry and gfxFontStyle;
+ * it will also tend to reduce the number of distinct font instances that
+ * get created, particularly when styles are animated or set to arbitrary
+ * values (e.g. by sliders in the UI), which should reduce pressure on
+ * graphics resources and improve cache hit rates.
  */
-class FontFixedPointValue
+template<class T,unsigned FractionBits,int Min,int Max>
+class FontPropertyValue
 {
 public:
   // Ugh. We need a default constructor to allow this type to be used in the
-  // union in nsCSSValue.  Furthermore we need the default and copy
+  // union in nsCSSValue. Furthermore we need the default and copy
   // constructors to be "trivial" (i.e. the compiler implemented defaults that
   // do no initialization).
-  // Annoyingly it seems we can't make the default implementations constexpr
-  // (at least in clang).  We'd like to do that to allow Thin() et. al. below
+  // Annoyingly we can't make the default implementations constexpr (at least
+  // in clang). That would be nice to do in order to allow the methods of
+  // subclasses that always return the same value (e.g., FontWeight::Thin())
   // to also be constexpr. :/
-  FontFixedPointValue() = default;
-  FontFixedPointValue(const FontFixedPointValue& aOther) = default;
-
-  // Not currently encoded, but it will be in future
-  explicit FontFixedPointValue(int16_t aValue)
-    : mEncoded(aValue)
-  {}
+  FontPropertyValue() = default;
+  explicit FontPropertyValue(const FontPropertyValue& aOther) = default;
+  FontPropertyValue& operator= (const FontPropertyValue& aOther) = default;
 
-  explicit FontFixedPointValue(int32_t aValue)
-    : mEncoded(aValue)
-  {}
-
-  explicit FontFixedPointValue(float aValue)
-    : mEncoded(int16_t(aValue))
-  {}
-
-  float ToFloat() const {
-    return float(mEncoded);
+  bool operator==(const FontPropertyValue& aOther) const
+  {
+    return mValue == aOther.mValue;
+  }
+  bool operator!=(const FontPropertyValue& aOther) const
+  {
+    return mValue != aOther.mValue;
+  }
+  bool operator<(const FontPropertyValue& aOther) const
+  {
+    return mValue < aOther.mValue;
+  }
+  bool operator>(const FontPropertyValue& aOther) const
+  {
+    return mValue > aOther.mValue;
+  }
+  bool operator<=(const FontPropertyValue& aOther) const
+  {
+    return mValue <= aOther.mValue;
+  }
+  bool operator>=(const FontPropertyValue& aOther) const
+  {
+    return mValue >= aOther.mValue;
   }
 
-  int16_t ToIntRounded() const {
-    return mEncoded;
-  }
-
-  bool operator==(const FontFixedPointValue& aOther) const {
-    return mEncoded == aOther.mEncoded;
-  }
-
-  bool operator!=(const FontFixedPointValue& aOther) const {
-    return mEncoded != aOther.mEncoded;
+  // The difference between two values, returned as a raw floating-point number
+  // (which might not be a valid property value in its own right).
+  float operator-(const FontPropertyValue& aOther) const
+  {
+    return (mValue - aOther.mValue) * kInverseScale;
   }
 
-  bool operator<(const FontFixedPointValue& aOther) const {
-    return mEncoded < aOther.mEncoded;
-  }
-
-  bool operator<=(const FontFixedPointValue& aOther) const {
-    return mEncoded <= aOther.mEncoded;
-  }
-
-  bool operator>=(const FontFixedPointValue& aOther) const {
-    return mEncoded >= aOther.mEncoded;
-  }
-
-  bool operator>(const FontFixedPointValue& aOther) const {
-    return mEncoded > aOther.mEncoded;
-  }
-
-  int16_t ForHash() const {
-    return mEncoded;
+  /// Return the raw internal representation, for purposes of hashing.
+  T ForHash() const
+  {
+    return mValue;
   }
 
 protected:
-  int16_t mEncoded;
+  typedef T internal_type;
+
+  // Construct from a floating-point or integer value, checking that it is
+  // within the allowed range and converting to fixed-point representation.
+  explicit FontPropertyValue(float aValue)
+    : mValue(std::round(aValue * kScale))
+  {
+    MOZ_ASSERT(aValue >= kMin && aValue <= kMax);
+  }
+  explicit FontPropertyValue(int aValue)
+    : mValue(aValue << kFractionBits)
+  {
+    MOZ_ASSERT(aValue >= Min && aValue <= Max);
+  }
+
+  // Construct directly from a fixed-point value of type T, with no check;
+  // note that there may be special "flag" values that are outside the normal
+  // min/max range (e.g. for font-style:italic, distinct from oblique angle).
+  explicit FontPropertyValue(T aValue)
+    : mValue(aValue)
+  {
+  }
+
+  // This is protected as it may not be the most appropriate accessor for a
+  // given instance to expose. It's up to each individual property to provide
+  // public accessors that forward to this as required.
+  float ToFloat() const { return mValue * kInverseScale; }
+  int ToIntRounded() const { return (mValue + kPointFive) >> FractionBits; }
+
+  static constexpr float kScale = float(1u << FractionBits);
+  static constexpr float kInverseScale = 1.0f / kScale;
+  static constexpr float kMin = float(Min);
+  static constexpr float kMax = float(Max);
+  static const unsigned kFractionBits = FractionBits;
+
+  // Constant representing 0.5 in the internal representation (note this
+  // assumes that kFractionBits is greater than zero!)
+  static const T kPointFive = 1u << (kFractionBits - 1);
+
+  T mValue;
 };
 
-class FontWeight : public FontFixedPointValue
+/**
+ * font-weight: range 1..1000, fractional values permitted; keywords
+ * 'normal', 'bold' aliased to 400, 700 respectively; relative keywords
+ * 'lighter', 'bolder' (not currently handled here).
+ *
+ * We use an unsigned 10.6 fixed-point value (range 0.0 - 1023.984375)
+ */
+class FontWeight final : public FontPropertyValue<uint16_t,6,1,1000>
 {
 public:
-  // Ugh, to get union in nsCSSValue compiling
+  // See comment in FontPropertyValue regarding requirement for a trivial
+  // default constructor.
   FontWeight() = default;
-  FontWeight(const FontWeight& aOther) = default;
-
-    // Not currently encoded, but it will be in future
-  explicit FontWeight(int16_t aValue)
-    : FontFixedPointValue(aValue)
-  {}
-
-  explicit FontWeight(int32_t aValue)
-    : FontFixedPointValue(aValue)
-  {}
 
   explicit FontWeight(float aValue)
-    : FontFixedPointValue(int16_t(aValue))
-  {}
+    : FontPropertyValue(aValue)
+  {
+  }
+
+  /**
+   * CSS font weights can have fractional values, but this constructor exists
+   * for convenience when writing constants such as FontWeight(700) in code.
+   */
+  explicit FontWeight(int aValue)
+    : FontPropertyValue(aValue)
+  {
+  }
+
+  static FontWeight Normal()
+  {
+    return FontWeight(kNormal);
+  }
+
+  static FontWeight Thin()
+  {
+    return FontWeight(kThin);
+  }
+
+  static FontWeight Bold()
+  {
+    return FontWeight(kBold);
+  }
+
+  bool IsNormal() const { return mValue == kNormal; }
+  bool IsBold() const { return mValue >= kBoldThreshold; }
+
+  float ToFloat() const { return FontPropertyValue::ToFloat(); }
+  int ToIntRounded() const { return FontPropertyValue::ToIntRounded(); }
 
-  bool operator==(const FontWeight& aOther) const
+private:
+  explicit FontWeight(internal_type aValue)
+    : FontPropertyValue(aValue)
   {
-    return mEncoded == aOther.mEncoded;
+  }
+
+  static const internal_type kNormal        = 400u << kFractionBits;
+  static const internal_type kBold          = 700u << kFractionBits;
+  static const internal_type kBoldThreshold = 600u << kFractionBits;
+  static const internal_type kThin          = 100u << kFractionBits;
+  static const internal_type kExtraBold     = 900u << kFractionBits;
+};
+
+/**
+ * font-stretch is represented as a percentage relative to 'normal'.
+ *
+ * css-fonts says the value must be >= 0%, and normal is 100%. Keywords
+ * from ultra-condensed to ultra-expanded are aliased to percentages
+ * from 50% to 200%; values outside that range are unlikely to be common,
+ * but could occur.
+ *
+ * Like font-weight, we use an unsigned 10.6 fixed-point value (range
+ * 0.0 - 1023.984375).
+ *
+ * We arbitrarily limit here to 1000%. (If that becomes a problem, we
+ * could reduce the number of fractional bits and increase the limit.)
+ */
+class FontStretch final : public FontPropertyValue<uint16_t,6,0,1000>
+{
+public:
+  // See comment in FontPropertyValue regarding requirement for a trivial
+  // default constructor.
+  FontStretch() = default;
+
+  explicit FontStretch(float aPercent)
+    : FontPropertyValue(aPercent)
+  {
   }
 
-  /// The "distance" between two font weights
-  float operator-(const FontWeight& aOther) const {
-    return this->ToFloat() - aOther.ToFloat();
+  static FontStretch Normal()
+  {
+    return FontStretch(kNormal);
+  }
+  static FontStretch UltraCondensed()
+  {
+    return FontStretch(kUltraCondensed);
+  }
+  static FontStretch ExtraCondensed()
+  {
+    return FontStretch(kExtraCondensed);
+  }
+  static FontStretch Condensed()
+  {
+    return FontStretch(kCondensed);
+  }
+  static FontStretch SemiCondensed()
+  {
+    return FontStretch(kSemiCondensed);
+  }
+  static FontStretch SemiExpanded()
+  {
+    return FontStretch(kSemiExpanded);
+  }
+  static FontStretch Expanded()
+  {
+    return FontStretch(kExpanded);
+  }
+  static FontStretch ExtraExpanded()
+  {
+    return FontStretch(kExtraExpanded);
+  }
+  static FontStretch UltraExpanded()
+  {
+    return FontStretch(kUltraExpanded);
   }
 
-  static FontWeight Thin() {
-    return FontWeight{100};
+  bool IsNormal() const { return mValue == kNormal; }
+  float Percentage() const { return ToFloat(); }
+
+private:
+  static const internal_type kUltraCondensed =  50u << kFractionBits;
+  static const internal_type kExtraCondensed = (62u << kFractionBits) + kPointFive;
+  static const internal_type kCondensed      =  75u << kFractionBits;
+  static const internal_type kSemiCondensed  = (87u << kFractionBits) + kPointFive;
+  static const internal_type kNormal         = 100u << kFractionBits;
+  static const internal_type kSemiExpanded  = (112u << kFractionBits) + kPointFive;
+  static const internal_type kExpanded       = 125u << kFractionBits;
+  static const internal_type kExtraExpanded  = 150u << kFractionBits;
+  static const internal_type kUltraExpanded  = 200u << kFractionBits;
+};
+
+/**
+ * font-style: normal | italic | oblique <angle>?
+ * values of <angle> below -90 or above 90 not permitted
+ * - Use a signed 8.8 fixed-point value
+ *   (representable range -128.0 - 127.99609375)
+ * - Define min value (-128.0) as meaning 'normal'
+ * - Define max value (127.99609375) as 'italic'
+ * - Other values represent 'oblique <angle>'
+ * - Note that 'oblique 0deg' is distinct from 'normal' (should it be?)
+ */
+class FontStyle final : public FontPropertyValue<int16_t,8,-90,90>
+{
+public:
+  // See comment in FontPropertyValue regarding requirement for a trivial
+  // default constructor.
+  FontStyle() = default;
+
+  static FontStyle Normal()
+  {
+    return FontStyle(kNormal);
   }
-  static FontWeight Normal() {
-    return FontWeight{400};
+
+  static FontStyle Italic()
+  {
+    return FontStyle(kItalic);
+  }
+
+  static FontStyle Oblique(float aAngle = 14.0f)
+  {
+    return FontStyle(aAngle);
   }
-  static FontWeight Bold() {
-    return FontWeight{700};
+
+  bool IsNormal() const { return mValue == kNormal; }
+  bool IsItalic() const { return mValue == kItalic; }
+  bool IsOblique() const { return mValue != kItalic && mValue != kNormal; }
+
+  float ObliqueAngle() const
+  {
+    // It's not meaningful to get the oblique angle from a style that is
+    // actually 'normal' or 'italic'.
+    MOZ_ASSERT(!IsItalic() && !IsNormal());
+    return ToFloat();
   }
+
+private:
+  explicit FontStyle(float aAngle)
+    : FontPropertyValue(aAngle)
+  {
+  }
+
+  static const int16_t kNormal = INT16_MIN;
+  static const int16_t kItalic = INT16_MAX;
 };
 
 } // namespace mozilla
 
 #endif // GFX_FONT_PROPERTY_TYPES_H
 
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -2,16 +2,17 @@
  * 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 GFX_DWRITEFONTLIST_H
 #define GFX_DWRITEFONTLIST_H
 
 #include "mozilla/FontPropertyTypes.h"
+#include "mozilla/MathAlgorithms.h"
 #include "mozilla/MemoryReporting.h"
 #include "gfxDWriteCommon.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
@@ -113,20 +114,19 @@ public:
         mHasVariations(false), mHasVariationsInitialized(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);
+        int weight = NS_ROUNDUP(aFont->GetWeight() - 50, 100);
 
-        weight = std::max<uint16_t>(100, weight);
-        weight = std::min<uint16_t>(900, weight);
+        weight = mozilla::Clamp(weight, 100, 900);
         mWeight = FontWeight(weight);
 
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
     /**
      * Constructs a font entry using a font. But with custom font values.
      * This is used for creating correct font entries for @font-face with local
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -366,17 +366,17 @@ FTFaceGetWeight(FT_Face aFace)
     } else if (aFace->style_flags & FT_STYLE_FLAG_BOLD) {
         result = 700;
     } else {
         result = 400;
     }
 
     NS_ASSERTION(result >= 100 && result <= 900, "Invalid weight in font!");
 
-    return FontWeight(result);
+    return FontWeight(int(result));
 }
 
 // Used to create the font entry for installed faces on the device,
 // when iterating over the fonts directories.
 // We use the FT_Face to retrieve the details needed for the font entry,
 // but unless we have been passed font data (i.e. for a user font),
 // we do *not* save a reference to it, nor create a cairo face,
 // as we don't want to keep a freetype face for every installed font
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -145,17 +145,17 @@ public:
     uint16_t Stretch() const { return mStretch; }
 
     bool IsUserFont() const { return mIsDataUserFont || mIsLocalUserFont; }
     bool IsLocalUserFont() const { return mIsLocalUserFont; }
     bool IsFixedPitch() const { return mFixedPitch; }
     bool IsItalic() const { return mStyle == NS_FONT_STYLE_ITALIC; }
     bool IsOblique() const { return mStyle == NS_FONT_STYLE_OBLIQUE; }
     bool IsUpright() const { return mStyle == NS_FONT_STYLE_NORMAL; }
-    bool IsBold() const { return mWeight >= FontWeight(600); } // bold == weights 600 and above
+    bool IsBold() const { return mWeight.IsBold(); } // bold == weights 600 and above
     bool IgnoreGDEF() const { return mIgnoreGDEF; }
     bool IgnoreGSUB() const { return mIgnoreGSUB; }
 
     // Return whether the face corresponds to "normal" CSS style properties:
     //    font-style: normal;
     //    font-weight: normal;
     //    font-stretch: normal;
     // If this is false, we might want to fall back to a different face and
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -440,30 +440,32 @@ gfxGDIFont::Initialize()
 #endif
 }
 
 void
 gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize)
 {
     GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry());
 
-    FontWeight weight;
+    // Figure out the lfWeight value to use for GDI font selection,
+    // or zero to use the entry's current LOGFONT value.
+    LONG weight;
     if (fe->IsUserFont()) {
         if (fe->IsLocalUserFont()) {
             // for local user fonts, don't change the original weight
             // in the entry's logfont, because that could alter the
             // choice of actual face used (bug 724231)
-            weight = FontWeight(0);
+            weight = 0;
         } else {
             // avoid GDI synthetic bold which occurs when weight
             // specified is >= font data weight + 200
-            weight = mNeedsBold ? FontWeight(700) : FontWeight(200);
+            weight = mNeedsBold ? 700 : 200;
         }
     } else {
-        weight = mNeedsBold ? FontWeight(700) : fe->Weight();
+        weight = mNeedsBold ? 700 : fe->Weight().ToIntRounded();
     }
 
     fe->FillLogFont(&aLogFont, weight, aSize);
 }
 
 uint32_t
 gfxGDIFont::GetGlyph(uint32_t aUnicode, uint32_t aVarSelector)
 {
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -251,34 +251,34 @@ GDIFontEntry::LookupUnscaledFont(HFONT a
         mUnscaledFont = unscaledFont;
     }
 
     return unscaledFont.forget();
 }
 
 void
 GDIFontEntry::FillLogFont(LOGFONTW *aLogFont,
-                          FontWeight aWeight,
+                          LONG aWeight,
                           gfxFloat aSize)
 {
     memcpy(aLogFont, &mLogFont, sizeof(LOGFONTW));
 
     aLogFont->lfHeight = (LONG)-ROUND(aSize);
 
     if (aLogFont->lfHeight == 0) {
         aLogFont->lfHeight = -1;
     }
 
     // If a non-zero weight is passed in, use this to override the original
     // weight in the entry's logfont. This is used to control synthetic bolding
     // for installed families with no bold face, and for downloaded fonts
     // (but NOT for local user fonts, because it could cause a different,
     // glyph-incompatible face to be used)
-    if (aWeight.ToFloat() != 0.0f) {
-        aLogFont->lfWeight = LONG(aWeight.ToFloat());
+    if (aWeight != 0) {
+        aLogFont->lfWeight = aWeight;
     }
 
     // for non-local() user fonts, we never want to apply italics here;
     // if the face is described as italic, we should use it as-is,
     // and if it's not, but then the element is styled italic, we'll use
     // a cairo transform to create fake italic (oblique)
     if (mIsDataUserFont) {
         aLogFont->lfItalic = 0;
@@ -732,17 +732,17 @@ gfxGDIFontList::LookupLocalFont(const ns
         lookup->mStyle, lookup->mWeight, aStretch, nullptr);
 
     if (!fe)
         return nullptr;
 
     fe->mIsLocalUserFont = true;
 
     // make the new font entry match the userfont entry style characteristics
-    fe->mWeight = (aWeight == FontWeight(0) ? FontWeight(400) : aWeight);
+    fe->mWeight = aWeight;
     fe->mStyle = aStyle;
 
     return fe;
 }
 
 // If aFontData contains only a MS/Symbol cmap subtable, not MS/Unicode,
 // we modify the subtable header to mark it as Unicode instead, because
 // otherwise GDI will refuse to load the font.
@@ -862,21 +862,19 @@ gfxGDIFontList::MakePlatformFont(const n
     // the font is referenced via the name this can be ignored
     if (fontRef && numFonts > 2) {
         RemoveFontMemResourceEx(fontRef);
         return nullptr;
     }
 
     // make a new font entry using the unique name
     WinUserFontData *winUserFontData = new WinUserFontData(fontRef);
-    FontWeight w = (aWeight == FontWeight(0) ? FontWeight(400) : aWeight);
-
     GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(uniqueName,
         gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
-        aStyle, w, aStretch, winUserFontData);
+        aStyle, aWeight, aStretch, winUserFontData);
 
     if (fe) {
       fe->mIsDataUserFont = true;
     }
 
     return fe;
 }
 
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -110,17 +110,17 @@ class GDIFontEntry : public gfxFontEntry
 public:
     typedef mozilla::FontWeight FontWeight;
 
     LPLOGFONTW GetLogFont() { return &mLogFont; }
 
     nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
 
     void FillLogFont(LOGFONTW *aLogFont,
-                     FontWeight aWeight,
+                     LONG aWeight,
                      gfxFloat aSize);
 
     static gfxWindowsFontType DetermineFontType(const NEWTEXTMETRICW& metrics, 
                                                 DWORD fontType)
     {
         gfxWindowsFontType feType;
         if (metrics.ntmFlags & NTM_TYPE1)
             feType = GFX_FONT_TYPE_TYPE1;
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -116,17 +116,17 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUs
     : gfxFontEntry(NS_LITERAL_STRING("userfont")),
       mUserFontLoadState(STATUS_NOT_LOADED),
       mFontDataLoadingState(NOT_LOADING),
       mUnsupportedFormat(false),
       mFontDisplay(aFontDisplay),
       mLoader(nullptr),
       mFontSet(aFontSet)
 {
-    MOZ_ASSERT(aWeight != FontWeight(0),
+    MOZ_ASSERT(aWeight.ToFloat() != 0.0f,
                "aWeight must not be 0; use FontWeight::Normal() instead");
     mIsUserFontContainer = true;
     mSrcList = aFontFaceSrcList;
     mSrcIndex = 0;
     mWeight = aWeight;
     mStretch = aStretch;
     mStyle = aStyle;
     mFeatureSettings.AppendElements(aFeatureSettings);
@@ -1001,17 +1001,17 @@ gfxUserFontSet::FindExistingUserFontEntr
                                uint32_t aStretch,
                                uint8_t aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
-    MOZ_ASSERT(aWeight != FontWeight(0),
+    MOZ_ASSERT(aWeight.ToFloat() != 0.0f,
                "aWeight must not be 0; use FontWeight::Normal() instead");
 
     nsTArray<RefPtr<gfxFontEntry>>& fontList = aFamily->GetFontList();
 
     for (size_t i = 0, count = fontList.Length(); i < count; i++) {
         if (!fontList[i]->mIsUserFontContainer) {
             continue;
         }
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -982,19 +982,16 @@ FontFaceSet::FindOrCreateUserFontEntryFr
   } else if (unit == eCSSUnit_Enumerated) {
     weight = FontWeight(val.GetIntValue());
   } else if (unit == eCSSUnit_Normal) {
     weight = FontWeight::Normal();
   } else {
     MOZ_ASSERT(unit == eCSSUnit_Null, "@font-face weight has unexpected unit");
   }
 
-  if (weight == FontWeight(0)) {
-    weight = FontWeight::Normal();
-  }
   // set up stretch
   aFontFace->GetDesc(eCSSFontDesc_Stretch, val);
   unit = val.GetUnit();
   if (unit == eCSSUnit_Enumerated) {
     stretch = val.GetIntValue();
   } else if (unit == eCSSUnit_Normal) {
     stretch = NS_STYLE_FONT_STRETCH_NORMAL;
   } else {