Bug 1454598 - part 3 - Use WeightRange more extensively in place of FontWeight throughout user-font handling and font-entry creation, and handle Stretch and SlantStyle similarly. r=jwatt
authorJonathan Kew <jkew@mozilla.com>
Wed, 25 Apr 2018 07:18:23 +0100
changeset 469165 ee068c7ae8f44f55c0d0cd004cba77b2c402a2db
parent 469164 3c05b11ca2b837819a60c4a05ac85822f56c608e
child 469166 2e9eda40f4770cc1fd2a2aa2263c1020445ef636
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt
bugs1454598
milestone61.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 1454598 - part 3 - Use WeightRange more extensively in place of FontWeight throughout user-font handling and font-entry creation, and handle Stretch and SlantStyle similarly. r=jwatt
dom/ipc/PContent.ipdl
gfx/src/FontPropertyTypes.h
gfx/src/nsFont.cpp
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxFT2FontBase.cpp
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFT2FontList.h
gfx/thebes/gfxFcPlatformFontList.cpp
gfx/thebes/gfxFcPlatformFontList.h
gfx/thebes/gfxFontEntry.cpp
gfx/thebes/gfxFontEntry.h
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxGDIFontList.h
gfx/thebes/gfxMacFont.cpp
gfx/thebes/gfxMacPlatformFontList.h
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformFontList.h
gfx/thebes/gfxPlatformGtk.cpp
gfx/thebes/gfxPlatformGtk.h
gfx/thebes/gfxUserFontSet.cpp
gfx/thebes/gfxUserFontSet.h
layout/style/FontFace.h
layout/style/FontFaceSet.cpp
layout/style/FontFaceSet.h
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -112,20 +112,19 @@ namespace mozilla {
 namespace dom {
 
 // Used on Android/B2G to pass the list of fonts on the device
 // to the child process
 struct FontListEntry {
     nsString  familyName;
     nsString  faceName;
     nsCString filepath;
-    float     minWeight;
-    float     maxWeight;
-    int16_t   stretch;
-    uint8_t   italic;
+    uint32_t  weightRange;
+    uint32_t  stretchRange;
+    uint32_t  styleRange;
     uint8_t   index;
 };
 
 // Used on Mac OS X to pass the list of font families (not faces)
 // from chrome to content processes.
 // The entryType field distinguishes several types of font family
 // record; see gfxMacPlatformFontList.h for values and meaning.
 struct FontFamilyListEntry {
--- a/gfx/src/FontPropertyTypes.h
+++ b/gfx/src/FontPropertyTypes.h
@@ -8,16 +8,20 @@
 #ifndef GFX_FONT_PROPERTY_TYPES_H
 #define GFX_FONT_PROPERTY_TYPES_H
 
 #include <algorithm>
 #include <cstdint>
 #include <cmath>
 #include <utility>
 
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
 #include "mozilla/Assertions.h"
 #include "nsString.h"
 
 /*
  * This file is separate from gfxFont.h so that layout can include it
  * without bringing in gfxFont.h and everything it includes.
  */
 
@@ -33,17 +37,17 @@ namespace mozilla {
  *         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 gfxFontSlantStyle;
+ * 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.
  */
 template<class InternalType, unsigned FractionBits, int Min, int Max>
 class FontPropertyValue
 {
@@ -53,17 +57,17 @@ public:
   // constructors to be "trivial" (i.e. the compiler implemented defaults that
   // do no initialization).
   // 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. :/
   FontPropertyValue() = default;
   explicit FontPropertyValue(const FontPropertyValue& aOther) = default;
-  FontPropertyValue& operator= (const FontPropertyValue& aOther) = default;
+  FontPropertyValue& operator=(const FontPropertyValue& aOther) = default;
 
   bool operator==(const FontPropertyValue& aOther) const
   {
     return mValue == aOther.mValue;
   }
   bool operator!=(const FontPropertyValue& aOther) const
   {
     return mValue != aOther.mValue;
@@ -88,19 +92,20 @@ public:
   // 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;
   }
 
   /// Return the raw internal representation, for purposes of hashing.
-  InternalType ForHash() const
+  /// (Do not try to interpret the numeric value of this.)
+  uint16_t ForHash() const
   {
-    return mValue;
+    return uint16_t(mValue);
   }
 
   static constexpr const float kMin = float(Min);
   static constexpr const float kMax = float(Max);
 
 protected:
   // Construct from a floating-point or integer value, checking that it is
   // within the allowed range and converting to fixed-point representation.
@@ -184,18 +189,20 @@ public:
   }
 
   bool IsNormal() const { return mValue == kNormal; }
   bool IsBold() const { return mValue >= kBoldThreshold; }
 
   float ToFloat() const { return FontPropertyValue::ToFloat(); }
   int ToIntRounded() const { return FontPropertyValue::ToIntRounded(); }
 
+  typedef uint16_t InternalType;
+
 private:
-  typedef uint16_t InternalType;
+  friend class WeightRange;
 
   explicit FontWeight(InternalType aValue)
     : FontPropertyValue(aValue)
   {
   }
 
   static const InternalType kNormal        = 400u << kFractionBits;
   static const InternalType kBold          = 700u << kFractionBits;
@@ -265,18 +272,20 @@ public:
   static FontStretch UltraExpanded()
   {
     return FontStretch(kUltraExpanded);
   }
 
   bool IsNormal() const { return mValue == kNormal; }
   float Percentage() const { return ToFloat(); }
 
+  typedef uint16_t InternalType;
+
 private:
-  typedef uint16_t InternalType;
+  friend class StretchRange;
 
   explicit FontStretch(InternalType aValue)
     : FontPropertyValue(aValue)
   {
   }
 
   static const InternalType kUltraCondensed =  50u << kFractionBits;
   static const InternalType kExtraCondensed = (62u << kFractionBits) + kPointFive;
@@ -296,17 +305,16 @@ private:
  *   (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 FontSlantStyle final : public FontPropertyValue<int16_t,8,-90,90>
 {
-  typedef int16_t InternalType;
 public:
   const static constexpr float kDefaultAngle = 14.0;
 
   // See comment in FontPropertyValue regarding requirement for a trivial
   // default constructor.
   FontSlantStyle() = default;
 
   static FontSlantStyle Normal()
@@ -319,29 +327,70 @@ public:
     return FontSlantStyle(kItalic);
   }
 
   static FontSlantStyle Oblique(float aAngle = kDefaultAngle)
   {
     return FontSlantStyle(aAngle);
   }
 
+  // Create from a string as generated by ToString. This is for internal use
+  // when serializing/deserializing entries for the startupcache, and is not
+  // intended to parse arbitrary (untrusted) strings.
+  static FontSlantStyle FromString(const char* aString)
+  {
+    if (strcmp(aString, "normal") == 0) {
+      return Normal();
+    } else if (strcmp(aString, "italic") == 0) {
+      return Italic();
+    } else {
+      if (isdigit(aString[0]) && strstr(aString, "deg")) {
+        float angle = strtof(aString, nullptr);
+        return Oblique(angle);
+      }
+      // Not recognized as an oblique angle; maybe it's from a startup-cache
+      // created by an older version. Just treat it as 'normal'.      
+      return Normal();
+    }
+  }
+
   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(IsOblique());
     return ToFloat();
   }
 
+  /**
+   * Write a string representation of the value to aOutString.
+   *
+   * NOTE that this APPENDS to the output string, it does not replace
+   * any existing contents.
+   */
+  void ToString(nsACString& aOutString) const
+  {
+    if (IsNormal()) {
+      aOutString.Append("normal");
+    } else if (IsItalic()) {
+      aOutString.Append("italic");
+    } else {
+      aOutString.AppendPrintf("%gdeg", ObliqueAngle());
+    }
+  }
+
+  typedef int16_t InternalType;
+
 private:
+  friend class SlantStyleRange;
+
   explicit FontSlantStyle(InternalType aConstant)
     : FontPropertyValue(aConstant)
   {
   }
 
   explicit FontSlantStyle(float aAngle)
     : FontPropertyValue(aAngle)
   {
@@ -356,16 +405,20 @@ private:
  * Convenience type to hold a <min, max> pair representing a range of values.
  *
  * The min and max are both inclusive, so when min == max the range represents
  * a single value (not an empty range).
  */
 template<class T>
 class FontPropertyRange
 {
+  // This implementation assumes the underlying property type is a 16-bit value
+  // (see FromScalar and AsScalar below).
+  static_assert(sizeof(T) == 2, "FontPropertyValue should be a 16-bit type!");
+
 public:
   /**
    * Construct a range from given minimum and maximum values (inclusive).
    */
   FontPropertyRange(T aMin, T aMax)
     : mValues(aMin, aMax)
   {
     MOZ_ASSERT(aMin <= aMax);
@@ -374,16 +427,19 @@ public:
   /**
    * Construct a range representing a single value (min==max).
    */
   explicit FontPropertyRange(T aValue)
     : mValues(aValue, aValue)
   {
   }
 
+  explicit FontPropertyRange(const FontPropertyRange& aOther) = default;
+  FontPropertyRange& operator=(const FontPropertyRange& aOther) = default;
+
   T Min() const { return mValues.first; }
   T Max() const { return mValues.second; }
 
   /**
    * Clamp the given value to this range.
    *
    * (We can't use mozilla::Clamp here because it only accepts integral types.)
    */
@@ -404,28 +460,137 @@ public:
   {
     return mValues == aOther.mValues;
   }
   bool operator!=(const FontPropertyRange& aOther) const
   {
     return mValues != aOther.mValues;
   }
 
+  /**
+   * Conversion of the property range to/from a single 32-bit scalar value,
+   * suitable for IPC serialization, hashing, caching.
+   *
+   * No assumptions should be made about the numeric value of the scalar.
+   *
+   * This depends on the underlying property type being a 16-bit value!
+   */
+  typedef uint32_t ScalarType;
+
+  ScalarType AsScalar() const
+  {
+    return (mValues.first.ForHash() << 16) | mValues.second.ForHash();
+  }
+
+  /*
+   * FIXME:
+   * FromScalar is defined in each individual subclass, because I can't
+   * persuade the compiler to accept a definition here in the template. :\
+   *
+  static FontPropertyRange FromScalar(ScalarType aScalar)
+  {
+    return FontPropertyRange(T(typename T::InternalType(aScalar >> 16)),
+                             T(typename T::InternalType(aScalar & 0xffff)));
+  }
+   */
+
+protected:
+  std::pair<T,T> mValues;
+};
+
+class WeightRange : public FontPropertyRange<FontWeight>
+{
+public:
+  WeightRange(FontWeight aMin, FontWeight aMax)
+    : FontPropertyRange(aMin, aMax)
+  {
+  }
+
+  explicit WeightRange(FontWeight aWeight)
+    : FontPropertyRange(aWeight)
+  {
+  }
+
+  WeightRange(const WeightRange& aOther) = default;
+
   void ToString(nsACString& aOutString, const char* aDelim = "..") const
   {
-    aOutString.AppendPrintf("%g", Min().ToFloat());
+    aOutString.AppendFloat(Min().ToFloat());
     if (!IsSingle()) {
-      aOutString.AppendPrintf("%s%g", aDelim, Max().ToFloat());
+      aOutString.Append(aDelim);
+      aOutString.AppendFloat(Max().ToFloat());
     }
   }
 
-private:
-  std::pair<T,T> mValues;
+  static WeightRange FromScalar(ScalarType aScalar)
+  {
+    return WeightRange(FontWeight(FontWeight::InternalType(aScalar >> 16)),
+                       FontWeight(FontWeight::InternalType(aScalar & 0xffff)));
+  }
 };
 
-typedef FontPropertyRange<FontWeight>     WeightRange;
-typedef FontPropertyRange<FontStretch>    StretchRange;
-typedef FontPropertyRange<FontSlantStyle> StyleRange;
+class StretchRange : public FontPropertyRange<FontStretch>
+{
+public:
+  StretchRange(FontStretch aMin, FontStretch aMax)
+    : FontPropertyRange(aMin, aMax)
+  {
+  }
+
+  explicit StretchRange(FontStretch aStretch)
+    : FontPropertyRange(aStretch)
+  {
+  }
+
+  StretchRange(const StretchRange& aOther) = default;
+
+  void ToString(nsACString& aOutString, const char* aDelim = "..") const
+  {
+    aOutString.AppendFloat(Min().Percentage());
+    if (!IsSingle()) {
+      aOutString.Append(aDelim);
+      aOutString.AppendFloat(Max().Percentage());
+    }
+  }
+
+  static StretchRange FromScalar(ScalarType aScalar)
+  {
+    return StretchRange(
+      FontStretch(FontStretch::InternalType(aScalar >> 16)),
+      FontStretch(FontStretch::InternalType(aScalar & 0xffff)));
+  }
+};
+
+class SlantStyleRange : public FontPropertyRange<FontSlantStyle>
+{
+public:
+  SlantStyleRange(FontSlantStyle aMin, FontSlantStyle aMax)
+    : FontPropertyRange(aMin, aMax)
+  {
+  }
+
+  explicit SlantStyleRange(FontSlantStyle aStyle)
+    : FontPropertyRange(aStyle)
+  {
+  }
+
+  SlantStyleRange(const SlantStyleRange& aOther) = default;
+
+  void ToString(nsACString& aOutString, const char* aDelim = "..") const
+  {
+    Min().ToString(aOutString);
+    if (!IsSingle()) {
+      aOutString.Append(aDelim);
+      Max().ToString(aOutString);
+    }
+  }
+
+  static SlantStyleRange FromScalar(ScalarType aScalar)
+  {
+    return SlantStyleRange(
+      FontSlantStyle(FontSlantStyle::InternalType(aScalar >> 16)),
+      FontSlantStyle(FontSlantStyle::InternalType(aScalar & 0xffff)));
+  }
+};
 
 } // namespace mozilla
 
 #endif // GFX_FONT_PROPERTY_TYPES_H
-
--- a/gfx/src/nsFont.cpp
+++ b/gfx/src/nsFont.cpp
@@ -287,19 +287,16 @@ void nsFont::AddFontFeaturesToStyle(gfxF
     aStyle->useGrayscaleAntialiasing = true;
   }
 
   aStyle->fontSmoothingBackgroundColor = fontSmoothingBackgroundColor;
 }
 
 void nsFont::AddFontVariationsToStyle(gfxFontStyle *aStyle) const
 {
-  // TODO: add variation settings from specific CSS properties
-  // such as weight, width, stretch
-
   // If auto optical sizing is enabled, and if there's no 'opsz' axis in
   // fontVariationSettings, then set the automatic value on the style.
   class VariationTagComparator {
   public:
     bool Equals(const gfxFontVariation& aVariation, uint32_t aTag) const {
       return aVariation.mTag == aTag;
     }
   };
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -371,17 +371,21 @@ gfxDWriteFontFamily::AddSizeOfIncludingT
 
 ////////////////////////////////////////////////////////////////////////////////
 // gfxDWriteFontEntry
 
 gfxFontEntry*
 gfxDWriteFontEntry::Clone() const
 {
     MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
-    return new gfxDWriteFontEntry(Name(), mFont);
+    gfxDWriteFontEntry* fe = new gfxDWriteFontEntry(Name(), mFont);
+    fe->mWeightRange = mWeightRange;
+    fe->mStretchRange = mStretchRange;
+    fe->mStyleRange = mStyleRange;
+    return fe;
 }
 
 gfxDWriteFontEntry::~gfxDWriteFontEntry()
 {
 }
 
 static bool
 UsingArabicOrHebrewScriptSystemLocale()
@@ -767,19 +771,17 @@ gfxDWriteFontEntry::CreateFontFace(IDWri
 
     // Do we need to modify DWrite simulations from what mFontFace has?
     bool needSimulations =
         (aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) &&
         !(mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD);
 
     // If the IDWriteFontFace5 interface is available, we can go via
     // IDWriteFontResource to create a new modified face.
-    if (mFontFace5 && ((aFontStyle && !aFontStyle->variationSettings.IsEmpty()) ||
-                       !Weight().IsSingle() ||
-                       needSimulations)) {
+    if (mFontFace5 && (HasVariations() || needSimulations)) {
         RefPtr<IDWriteFontResource> resource;
         HRESULT hr = mFontFace5->GetFontResource(getter_AddRefs(resource));
         MOZ_ASSERT(SUCCEEDED(hr));
         AutoTArray<DWRITE_FONT_AXIS_VALUE, 4> fontAxisValues;
 
         // Get the variation settings needed to instantiate the fontEntry
         // for a particular fontStyle.
         AutoTArray<gfxFontVariation,4> vars;
@@ -952,43 +954,43 @@ gfxDWriteFontList::GetDefaultFontForPlat
         }
     }
 
     return nullptr;
 }
 
 gfxFontEntry *
 gfxDWriteFontList::LookupLocalFont(const nsAString& aFontName,
-                                   FontWeight aWeight,
-                                   FontStretch aStretch,
-                                   FontSlantStyle aStyle)
+                                   WeightRange aWeightForEntry,
+                                   StretchRange aStretchForEntry,
+                                   SlantStyleRange aStyleForEntry)
 {
     gfxFontEntry *lookup;
 
     lookup = LookupInFaceNameLists(aFontName);
     if (!lookup) {
         return nullptr;
     }
 
     gfxDWriteFontEntry* dwriteLookup = static_cast<gfxDWriteFontEntry*>(lookup);
     gfxDWriteFontEntry *fe =
         new gfxDWriteFontEntry(lookup->Name(),
                                dwriteLookup->mFont,
-                               aWeight,
-                               aStretch,
-                               aStyle);
+                               aWeightForEntry,
+                               aStretchForEntry,
+                               aStyleForEntry);
     fe->SetForceGDIClassic(dwriteLookup->GetForceGDIClassic());
     return fe;
 }
 
 gfxFontEntry *
 gfxDWriteFontList::MakePlatformFont(const nsAString& aFontName,
-                                    FontWeight aWeight,
-                                    FontStretch aStretch,
-                                    FontSlantStyle aStyle,
+                                    WeightRange aWeightForEntry,
+                                    StretchRange aStretchForEntry,
+                                    SlantStyleRange aStyleForEntry,
                                     const uint8_t* aFontData,
                                     uint32_t aLength)
 {
     RefPtr<IDWriteFontFileStream> fontFileStream;
     RefPtr<IDWriteFontFile> fontFile;
     HRESULT hr =
       gfxDWriteFontFileLoader::CreateCustomFontFile(aFontData, aLength,
                                                     getter_AddRefs(fontFile),
@@ -1008,19 +1010,19 @@ gfxDWriteFontList::MakePlatformFont(cons
     BOOL isSupported;
     DWRITE_FONT_FILE_TYPE fileType;
     UINT32 numFaces;
 
     gfxDWriteFontEntry *entry = 
         new gfxDWriteFontEntry(uniqueName,
                                fontFile,
                                fontFileStream,
-                               aWeight,
-                               aStretch,
-                               aStyle);
+                               aWeightForEntry,
+                               aStretchForEntry,
+                               aStyleForEntry);
 
     fontFile->Analyze(&isSupported, &fileType, &entry->mFaceType, &numFaces);
     if (!isSupported || numFaces > 1) {
         // We don't know how to deal with 0 faces either.
         delete entry;
         return nullptr;
     }
 
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -110,23 +110,28 @@ public:
     gfxDWriteFontEntry(const nsAString& aFaceName,
                        IDWriteFont *aFont,
                        bool aIsSystemFont = false)
       : gfxFontEntry(aFaceName), mFont(aFont), mFontFile(nullptr),
         mIsSystemFont(aIsSystemFont), mForceGDIClassic(false),
         mHasVariations(false), mHasVariationsInitialized(false)
     {
         DWRITE_FONT_STYLE dwriteStyle = aFont->GetStyle();
-        mStyle = (dwriteStyle == DWRITE_FONT_STYLE_ITALIC ?
-                  FontSlantStyle::Italic() :
-                  (dwriteStyle == DWRITE_FONT_STYLE_OBLIQUE ?
-                   FontSlantStyle::Oblique() : FontSlantStyle::Normal()));
-        mStretch = FontStretchFromDWriteStretch(aFont->GetStretch());
+        FontSlantStyle style =
+            (dwriteStyle == DWRITE_FONT_STYLE_ITALIC
+                ? FontSlantStyle::Italic()
+                : (dwriteStyle == DWRITE_FONT_STYLE_OBLIQUE
+                    ? FontSlantStyle::Oblique()
+                    : FontSlantStyle::Normal()));
+        mStyleRange = SlantStyleRange(style);
+
+        mStretchRange =
+            StretchRange(FontStretchFromDWriteStretch(aFont->GetStretch()));
+
         int weight = NS_ROUNDUP(aFont->GetWeight() - 50, 100);
-
         weight = mozilla::Clamp(weight, 100, 900);
         mWeightRange = WeightRange(FontWeight(weight));
 
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
     /**
      * Constructs a font entry using a font. But with custom font values.
@@ -136,26 +141,26 @@ public:
      * \param aFaceName The name of the corresponding font face.
      * \param aFont DirectWrite font object
      * \param aWeight Weight of the font
      * \param aStretch Stretch of the font
      * \param aStyle italic or oblique of font
      */
     gfxDWriteFontEntry(const nsAString& aFaceName,
                        IDWriteFont *aFont,
-                       FontWeight aWeight,
-                       FontStretch aStretch,
-                       FontSlantStyle aStyle)
+                       WeightRange aWeight,
+                       StretchRange aStretch,
+                       SlantStyleRange aStyle)
       : gfxFontEntry(aFaceName), mFont(aFont), mFontFile(nullptr),
         mIsSystemFont(false), mForceGDIClassic(false),
         mHasVariations(false), mHasVariationsInitialized(false)
     {
-        mWeightRange = WeightRange(aWeight);
-        mStretch = aStretch;
-        mStyle = aStyle;
+        mWeightRange = aWeight;
+        mStretchRange = aStretch;
+        mStyleRange = aStyle;
         mIsLocalUserFont = true;
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
     /**
      * Constructs a font entry using a font file.
      *
      * \param aFaceName The name of the corresponding font face.
@@ -163,27 +168,27 @@ public:
      * \param aFontFileStream DirectWrite fontfile stream object
      * \param aWeight Weight of the font
      * \param aStretch Stretch of the font
      * \param aStyle italic or oblique of font
      */
     gfxDWriteFontEntry(const nsAString& aFaceName,
                               IDWriteFontFile *aFontFile,
                               IDWriteFontFileStream *aFontFileStream,
-                              FontWeight aWeight,
-                              FontStretch aStretch,
-                              FontSlantStyle aStyle)
+                              WeightRange aWeight,
+                              StretchRange aStretch,
+                              SlantStyleRange aStyle)
       : gfxFontEntry(aFaceName), mFont(nullptr),
         mFontFile(aFontFile), mFontFileStream(aFontFileStream),
         mIsSystemFont(false), mForceGDIClassic(false),
         mHasVariations(false), mHasVariationsInitialized(false)
     {
-        mWeightRange = WeightRange(aWeight);
-        mStretch = aStretch;
-        mStyle = aStyle;
+        mWeightRange = aWeight;
+        mStretchRange = aStretch;
+        mStyleRange = aStyle;
         mIsDataUserFont = true;
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
     gfxFontEntry* Clone() const override;
 
     virtual ~gfxDWriteFontEntry();
 
@@ -400,24 +405,24 @@ public:
     }
 
     // initialize font lists
     virtual nsresult InitFontListForPlatform() override;
 
     gfxFontFamily* CreateFontFamily(const nsAString& aName) const override;
 
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          FontWeight aWeight,
-                                          FontStretch aStretch,
-                                          FontSlantStyle aStyle);
+                                          WeightRange aWeightForEntry,
+                                          StretchRange aStretchForEntry,
+                                          SlantStyleRange aStyleForEntry);
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           FontWeight aWeight,
-                                           FontStretch aStretch,
-                                           FontSlantStyle aStyle,
+                                           WeightRange aWeightForEntry,
+                                           StretchRange aStretchForEntry,
+                                           SlantStyleRange aStyleForEntry,
                                            const uint8_t* aFontData,
                                            uint32_t aLength);
     
     bool GetStandardFamilyName(const nsAString& aFontName,
                                  nsAString& aFamilyName);
 
     IDWriteGdiInterop *GetGDIInterop() { return mGDIInterop; }
     bool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -224,20 +224,17 @@ gfxFT2FontBase::InitMetrics()
         mMetrics.underlineOffset = -underlineSize;
         mMetrics.strikeoutOffset = 0.25 * emHeight;
         mMetrics.strikeoutSize = underlineSize;
 
         SanitizeMetrics(&mMetrics, false);
         return;
     }
 
-    if ((!mFontEntry->mVariationSettings.IsEmpty() ||
-         !mStyle.variationSettings.IsEmpty() ||
-         !mFontEntry->Weight().IsSingle()) &&
-         (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
+    if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
         // Resolve variations from entry (descriptor) and style (property)
         AutoTArray<gfxFontVariation,8> settings;
         mFontEntry->GetVariationsForStyle(settings, mStyle);
         SetupVarCoords(face, settings, &mCoords);
         if (!mCoords.IsEmpty()) {
 #if MOZ_TREE_FREETYPE
             FT_Set_Var_Design_Coordinates(face, mCoords.Length(), mCoords.Elements());
 #else
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -220,18 +220,18 @@ FT2FontEntry::~FT2FontEntry()
 gfxFontEntry*
 FT2FontEntry::Clone() const
 {
     MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
     FT2FontEntry* fe = new FT2FontEntry(Name());
     fe->mFilename = mFilename;
     fe->mFTFontIndex = mFTFontIndex;
     fe->mWeightRange = mWeightRange;
-    fe->mStretch = mStretch;
-    fe->mStyle = mStyle;
+    fe->mStretchRange = mStretchRange;
+    fe->mStyleRange = mStyleRange;
     return fe;
 }
 
 gfxFont*
 FT2FontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
 {
     cairo_scaled_font_t *scaledFont = CreateScaledFont(aFontStyle);
     if (!scaledFont) {
@@ -252,19 +252,19 @@ FT2FontEntry::CreateFontInstance(const g
                                    aFontStyle, aNeedsBold);
     cairo_scaled_font_destroy(scaledFont);
     return font;
 }
 
 /* static */
 FT2FontEntry*
 FT2FontEntry::CreateFontEntry(const nsAString& aFontName,
-                              FontWeight aWeight,
-                              FontStretch aStretch,
-                              FontSlantStyle aStyle,
+                              WeightRange aWeight,
+                              StretchRange aStretch,
+                              SlantStyleRange aStyle,
                               const uint8_t* aFontData,
                               uint32_t aLength)
 {
     // Ownership of aFontData is passed in here; the fontEntry must
     // retain it as long as the FT_Face needs it, and ensure it is
     // eventually deleted.
     FT_Face face = Factory::NewFTFaceFromData(nullptr, aFontData, aLength, 0);
     if (!face) {
@@ -277,19 +277,19 @@ FT2FontEntry::CreateFontEntry(const nsAS
         return nullptr;
     }
     // Create our FT2FontEntry, which inherits the name of the userfont entry
     // as it's not guaranteed that the face has valid names (bug 737315)
     FT2FontEntry* fe =
         FT2FontEntry::CreateFontEntry(face, nullptr, 0, aFontName,
                                       aFontData, aLength);
     if (fe) {
-        fe->mStyle = aStyle;
-        fe->mWeightRange = WeightRange(aWeight);
-        fe->mStretch = aStretch;
+        fe->mStyleRange = aStyle;
+        fe->mWeightRange = aWeight;
+        fe->mStretchRange = aStretch;
         fe->mIsDataUserFont = true;
     }
     return fe;
 }
 
 class FTUserFontData {
 public:
     FTUserFontData(FT_Face aFace, const uint8_t* aData, uint32_t aLength)
@@ -323,23 +323,19 @@ FTFontDestroyFunc(void *data)
 
 /* static */
 FT2FontEntry*
 FT2FontEntry::CreateFontEntry(const FontListEntry& aFLE)
 {
     FT2FontEntry *fe = new FT2FontEntry(aFLE.faceName());
     fe->mFilename = aFLE.filepath();
     fe->mFTFontIndex = aFLE.index();
-    // The weight transported across IPC is a float, so we need to explicitly
-    // convert it back to a FontWeight.
-    fe->mWeightRange = WeightRange(FontWeight(aFLE.minWeight()),
-                                   FontWeight(aFLE.maxWeight()));
-    fe->mStretch = FontStretch(float(aFLE.stretch()));
-    fe->mStyle = aFLE.italic()
-      ? FontSlantStyle::Italic() : FontSlantStyle::Normal();
+    fe->mWeightRange = WeightRange::FromScalar(aFLE.weightRange());
+    fe->mStretchRange = StretchRange::FromScalar(aFLE.stretchRange());
+    fe->mStyleRange = SlantStyleRange::FromScalar(aFLE.styleRange());
     return fe;
 }
 
 // Helpers to extract font entry properties from an FT_Face
 static bool
 FTFaceIsItalic(FT_Face aFace)
 {
     return !!(aFace->style_flags & FT_STYLE_FLAG_ITALIC);
@@ -387,18 +383,19 @@ FTFaceGetWeight(FT_Face aFace)
 FT2FontEntry*
 FT2FontEntry::CreateFontEntry(FT_Face aFace,
                               const char* aFilename, uint8_t aIndex,
                               const nsAString& aName,
                               const uint8_t* aFontData,
                               uint32_t aLength)
 {
     FT2FontEntry *fe = new FT2FontEntry(aName);
-    fe->mStyle = (FTFaceIsItalic(aFace) ?
-                  FontSlantStyle::Italic() : FontSlantStyle::Normal());
+    fe->mStyleRange = SlantStyleRange(FTFaceIsItalic(aFace)
+                                      ? FontSlantStyle::Italic()
+                                      : FontSlantStyle::Normal());
     fe->mWeightRange = WeightRange(FTFaceGetWeight(aFace));
     fe->mFilename = aFilename;
     fe->mFTFontIndex = aIndex;
 
     if (aFontData) {
         fe->mFTFace = aFace;
         int flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ?
                     FT_LOAD_DEFAULT :
@@ -456,18 +453,17 @@ FT2FontEntry::CairoFontFace(const gfxFon
                                       userFontData, FTFontDestroyFunc);
         mFTFace = face.forget();
     }
 
     // If variations are present, we will not use our cached mFontFace
     // but always create a new cairo_font_face_t because its FT_Face will
     // have custom variation coordinates applied.
     if ((!mVariationSettings.IsEmpty() ||
-        (aStyle && !aStyle->variationSettings.IsEmpty()) ||
-        !Weight().IsSingle()) &&
+        (aStyle && !aStyle->variationSettings.IsEmpty())) &&
         (mFTFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
         int flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ?
                     FT_LOAD_DEFAULT :
                     (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
         // Resolve variations from entry (descriptor) and style (property)
         AutoTArray<gfxFontVariation,8> settings;
         GetVariationsForStyle(settings, aStyle ? *aStyle : gfxFontStyle());
         AutoTArray<FT_Fixed,8> coords;
@@ -650,27 +646,22 @@ FT2FontFamily::AddFacesToFontList(Infall
 {
     for (int i = 0, n = mAvailableFonts.Length(); i < n; ++i) {
         const FT2FontEntry *fe =
             static_cast<const FT2FontEntry*>(mAvailableFonts[i].get());
         if (!fe) {
             continue;
         }
 
-        // We convert the weight to a float purely for transport across IPC.
-        // Ideally we'd avoid doing that.
         aFontList->AppendElement(FontListEntry(Name(),
                                                fe->Name(),
                                                fe->mFilename,
-                                               fe->Weight().Min().ToFloat(),
-                                               fe->Weight().Max().ToFloat(),
-                                               fe->Stretch().Percentage(),
-                                               fe->mStyle.IsItalic()
-                                                ? NS_FONT_STYLE_ITALIC
-                                                : NS_FONT_STYLE_NORMAL,
+                                               fe->Weight().AsScalar(),
+                                               fe->Stretch().AsScalar(),
+                                               fe->SlantStyle().AsScalar(),
                                                fe->mFTFontIndex));
     }
 }
 
 /*
  * Startup cache support for the font list:
  * We store the list of families and faces, with their style attributes and the
  * corresponding font files, in the startup cache.
@@ -934,52 +925,75 @@ gfxFT2FontList::AppendFacesFromCachedFac
     const nsCString& aFaceList,
     StandardFile aStdFile)
 {
     const char *beginning = aFaceList.get();
     const char *end = strchr(beginning, ',');
     while (end) {
         NS_ConvertUTF8toUTF16 familyName(beginning, end - beginning);
         ToLowerCase(familyName);
+
         beginning = end + 1;
         if (!(end = strchr(beginning, ','))) {
             break;
         }
         NS_ConvertUTF8toUTF16 faceName(beginning, end - beginning);
+
         beginning = end + 1;
         if (!(end = strchr(beginning, ','))) {
             break;
         }
         uint32_t index = strtoul(beginning, nullptr, 10);
+
         beginning = end + 1;
         if (!(end = strchr(beginning, ','))) {
             break;
         }
-        bool italic = (*beginning != '0');
+        nsAutoCString minStyle(beginning, end - beginning);
+        nsAutoCString maxStyle(minStyle);
+        int32_t colon = minStyle.FindChar(':');
+        if (colon > 0) {
+            maxStyle.Assign(minStyle.BeginReading() + colon + 1);
+            minStyle.Truncate(colon - 1);
+        }
+
         beginning = end + 1;
         if (!(end = strchr(beginning, ','))) {
             break;
         }
         char* limit;
         float minWeight = strtof(beginning, &limit);
         float maxWeight;
         if (*limit == ':' && limit + 1 < end) {
             maxWeight = strtof(limit + 1, nullptr);
         } else {
             maxWeight = minWeight;
         }
+
         beginning = end + 1;
         if (!(end = strchr(beginning, ','))) {
             break;
         }
-        uint32_t stretch = strtoul(beginning, nullptr, 10);
+        float minStretch = strtof(beginning, &limit);
+        float maxStretch;
+        if (*limit == ':' && limit + 1 < end) {
+            maxStretch = strtof(limit + 1, nullptr);
+        } else {
+            maxStretch = minStretch;
+        }
 
-        FontListEntry fle(familyName, faceName, aFileName,
-                          minWeight, maxWeight,
-                          stretch, italic, index);
+        FontListEntry fle(
+            familyName, faceName, aFileName,
+            WeightRange(FontWeight(minWeight),
+                        FontWeight(maxWeight)).AsScalar(),
+            StretchRange(FontStretch(minStretch),
+                         FontStretch(maxStretch)).AsScalar(),
+            SlantStyleRange(FontSlantStyle::FromString(minStyle.get()),
+                            FontSlantStyle::FromString(maxStyle.get())).AsScalar(),
+            index);
         AppendFaceFromFontListEntry(fle, aStdFile);
 
         beginning = end + 1;
         end = strchr(beginning, ',');
     }
 }
 
 static void
@@ -993,18 +1007,19 @@ AppendToFaceList(nsCString& aFaceList,
     aFaceList.AppendInt(aFontEntry->mFTFontIndex);
     aFaceList.Append(',');
     aFaceList.Append(aFontEntry->IsItalic() ? '1' : '0');
     aFaceList.Append(',');
     aFaceList.AppendFloat(aFontEntry->Weight().Min().ToFloat());
     aFaceList.Append(':');
     aFaceList.AppendFloat(aFontEntry->Weight().Max().ToFloat());
     aFaceList.Append(',');
-    // FIXME(emilio): Probably the stretch should be converted to float.
-    aFaceList.AppendInt(int32_t(aFontEntry->Stretch().Percentage()));
+    aFaceList.AppendFloat(aFontEntry->Stretch().Min().Percentage());
+    aFaceList.Append(':');
+    aFaceList.AppendFloat(aFontEntry->Stretch().Max().Percentage());
     aFaceList.Append(',');
 }
 
 void
 FT2FontEntry::CheckForBrokenFont(gfxFontFamily *aFamily)
 {
     // note if the family is in the "bad underline" blacklist
     if (aFamily->IsBadUnderlineFamily()) {
@@ -1152,23 +1167,25 @@ gfxFT2FontList::AddFaceToList(const nsCS
         family->AddFontEntry(fe);
 
         fe->CheckForBrokenFont(family);
 
         AppendToFaceList(aFaceList, name, fe);
         if (LOG_ENABLED()) {
             nsAutoCString weightString;
             fe->Weight().ToString(weightString);
+            nsAutoCString stretchString;
+            fe->Stretch().ToString(stretchString);
             LOG(("(fontinit) added (%s) to family (%s)"
-                 " with style: %s weight: %s stretch: %g%%",
+                 " with style: %s weight: %s stretch: %s",
                  NS_ConvertUTF16toUTF8(fe->Name()).get(),
                  NS_ConvertUTF16toUTF8(family->Name()).get(),
                  fe->IsItalic() ? "italic" : "normal",
                  weightString.get(),
-                 fe->Stretch().Percentage()));
+                 stretchString.get()));
         }
     }
 }
 
 void
 gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
                                             const nsCString& aEntryName,
                                             FontNameCache *aCache,
@@ -1468,19 +1485,19 @@ gfxFT2FontList::InitFontListForPlatform(
     return NS_OK;
 }
 
 // called for each family name, based on the assumption that the
 // first part of the full name is the family name
 
 gfxFontEntry*
 gfxFT2FontList::LookupLocalFont(const nsAString& aFontName,
-                                FontWeight aWeight,
-                                FontStretch aStretch,
-                                FontSlantStyle aStyle)
+                                WeightRange aWeightForEntry,
+                                StretchRange aStretchForEntry,
+                                SlantStyleRange aStyleForEntry)
 {
     // walk over list of names
     FT2FontEntry* fontEntry = nullptr;
     nsString fullName(aFontName);
 
     for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
         // Check family name, based on the assumption that the
         // first part of the full name is the family name
@@ -1525,19 +1542,19 @@ searchDone:
     }
 
     FT2FontEntry* fe =
         FT2FontEntry::CreateFontEntry(fontEntry->mFTFace,
                                       fontEntry->mFilename.get(),
                                       fontEntry->mFTFontIndex,
                                       fontEntry->Name(), nullptr);
     if (fe) {
-        fe->mStyle = aStyle;
-        fe->mWeightRange = WeightRange(aWeight);
-        fe->mStretch = aStretch;
+        fe->mStyleRange = aStyleForEntry;
+        fe->mWeightRange = aWeightForEntry;
+        fe->mStretchRange = aStretchForEntry;
         fe->mIsLocalUserFont = true;
     }
 
     return fe;
 }
 
 gfxFontFamily*
 gfxFT2FontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
@@ -1550,27 +1567,30 @@ gfxFT2FontList::GetDefaultFontForPlatfor
     }
 #endif
     /* TODO: what about Qt or other platforms that may use this? */
     return ff;
 }
 
 gfxFontEntry*
 gfxFT2FontList::MakePlatformFont(const nsAString& aFontName,
-                                 FontWeight aWeight,
-                                 FontStretch aStretch,
-                                 FontSlantStyle aStyle,
+                                 WeightRange aWeightForEntry,
+                                 StretchRange aStretchForEntry,
+                                 SlantStyleRange aStyleForEntry,
                                  const uint8_t* aFontData,
                                  uint32_t aLength)
 {
     // The FT2 font needs the font data to persist, so we do NOT free it here
     // but instead pass ownership to the font entry.
     // Deallocation will happen later, when the font face is destroyed.
-    return FT2FontEntry::CreateFontEntry(aFontName, aWeight, aStretch,
-                                         aStyle, aFontData, aLength);
+    return FT2FontEntry::CreateFontEntry(aFontName,
+                                         aWeightForEntry,
+                                         aStretchForEntry,
+                                         aStyleForEntry,
+                                         aFontData, aLength);
 }
 
 void
 gfxFT2FontList::GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily> >& aFamilyArray)
 {
     for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
         RefPtr<gfxFontFamily>& family = iter.Data();
         aFamilyArray.AppendElement(family);
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -38,19 +38,19 @@ public:
 
     const nsString& GetName() const {
         return Name();
     }
 
     // create a font entry for a downloaded font
     static FT2FontEntry* 
     CreateFontEntry(const nsAString& aFontName,
-                    FontWeight aWeight,
-                    FontStretch aStretch,
-                    FontSlantStyle aStyle,
+                    WeightRange aWeight,
+                    StretchRange aStretch,
+                    SlantStyleRange aStyle,
                     const uint8_t* aFontData,
                     uint32_t aLength);
 
     // create a font entry representing an installed font, identified by
     // a FontListEntry; the freetype and cairo faces will not be instantiated
     // until actually needed
     static FT2FontEntry*
     CreateFontEntry(const FontListEntry& aFLE);
@@ -117,24 +117,24 @@ public:
 
 class gfxFT2FontList : public gfxPlatformFontList
 {
 public:
     gfxFT2FontList();
     virtual ~gfxFT2FontList();
 
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          FontWeight aWeight,
-                                          FontStretch aStretch,
-                                          FontSlantStyle aStyle) override;
+                                          WeightRange aWeightForEntry,
+                                          StretchRange aStretchForEntry,
+                                          SlantStyleRange aStyleForEntry) override;
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           FontWeight aWeight,
-                                           FontStretch aStretch,
-                                           FontSlantStyle aStyle,
+                                           WeightRange aWeightForEntry,
+                                           StretchRange aStretchForEntry,
+                                           SlantStyleRange aStyleForEntry,
                                            const uint8_t* aFontData,
                                            uint32_t aLength) override;
 
     void GetSystemFontList(InfallibleTArray<FontListEntry>* retValue);
 
     static gfxFT2FontList* PlatformFontList() {
         return static_cast<gfxFT2FontList*>(gfxPlatformFontList::PlatformFontList());
     }
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -240,34 +240,34 @@ gfxFontconfigFontEntry::gfxFontconfigFon
           mAspect(0.0), mFontData(nullptr), mLength(0)
 {
     // italic
     int slant;
     if (FcPatternGetInteger(aFontPattern, FC_SLANT, 0, &slant) != FcResultMatch) {
         slant = FC_SLANT_ROMAN;
     }
     if (slant == FC_SLANT_OBLIQUE) {
-        mStyle = FontSlantStyle::Oblique();
+        mStyleRange = SlantStyleRange(FontSlantStyle::Oblique());
     } else if (slant > 0) {
-        mStyle = FontSlantStyle::Italic();
+        mStyleRange = SlantStyleRange(FontSlantStyle::Italic());
     }
 
     // weight
     int weight;
     if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, &weight) != FcResultMatch) {
         weight = FC_WEIGHT_REGULAR;
     }
     mWeightRange = WeightRange(MapFcWeight(weight));
 
     // width
     int width;
     if (FcPatternGetInteger(aFontPattern, FC_WIDTH, 0, &width) != FcResultMatch) {
         width = FC_WIDTH_NORMAL;
     }
-    mStretch = MapFcWidth(width);
+    mStretchRange = StretchRange(MapFcWidth(width));
 }
 
 gfxFontEntry*
 gfxFontconfigFontEntry::Clone() const
 {
     MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
     return new gfxFontconfigFontEntry(Name(), mFontPattern, mIgnoreFcCharmap);
 }
@@ -311,51 +311,51 @@ CreateFaceForPattern(FcPattern* aPattern
     int index;
     if (FcPatternGetInteger(aPattern, FC_INDEX, 0, &index) != FcResultMatch) {
         index = 0; // default to 0 if not found in pattern
     }
     return Factory::NewFTFace(nullptr, ToCharPtr(filename), index);
 }
 
 gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
-                                               FontWeight aWeight,
-                                               FontStretch aStretch,
-                                               FontSlantStyle aStyle,
+                                               WeightRange aWeight,
+                                               StretchRange aStretch,
+                                               SlantStyleRange aStyle,
                                                const uint8_t *aData,
                                                uint32_t aLength,
                                                FT_Face aFace)
     : gfxFontEntry(aFaceName),
       mFTFace(aFace), mFTFaceInitialized(true),
       mIgnoreFcCharmap(true),
       mHasVariationsInitialized(false),
       mAspect(0.0), mFontData(aData), mLength(aLength)
 {
-    mWeightRange = WeightRange(aWeight);
-    mStyle = aStyle;
-    mStretch = aStretch;
+    mWeightRange = aWeight;
+    mStyleRange = aStyle;
+    mStretchRange = aStretch;
     mIsDataUserFont = true;
 
     mFontPattern = CreatePatternForFace(mFTFace);
 
     mUserFontData = new FTUserFontData(mFTFace, mFontData);
 }
 
 gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
                                                FcPattern* aFontPattern,
-                                               FontWeight aWeight,
-                                               FontStretch aStretch,
-                                               FontSlantStyle aStyle)
+                                               WeightRange aWeight,
+                                               StretchRange aStretch,
+                                               SlantStyleRange aStyle)
         : gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
           mFTFace(nullptr), mFTFaceInitialized(false),
           mHasVariationsInitialized(false),
           mAspect(0.0), mFontData(nullptr), mLength(0)
 {
-    mWeightRange = WeightRange(aWeight);
-    mStyle = aStyle;
-    mStretch = aStretch;
+    mWeightRange = aWeight;
+    mStyleRange = aStyle;
+    mStretchRange = aStretch;
     mIsLocalUserFont = true;
 
     // The proper setting of mIgnoreFcCharmap is tricky for fonts loaded
     // via src:local()...
     // If the local font happens to come from the application fontset,
     // we want to set it to true so that color/svg fonts will work even
     // if the default glyphs are blank; but if the local font is a non-
     // sfnt face (e.g. legacy type 1) then we need to set it to false
@@ -766,19 +766,17 @@ gfxFontconfigFontEntry::CreateScaledFont
 
     if (needsOblique) {
         // disable embedded bitmaps (mimics behavior in 90-synthetic.conf)
         FcPatternDel(aRenderPattern, FC_EMBEDDED_BITMAP);
         FcPatternAddBool(aRenderPattern, FC_EMBEDDED_BITMAP, FcFalse);
     }
 
     AutoTArray<FT_Fixed,8> coords;
-    if (!aStyle->variationSettings.IsEmpty() ||
-        !mVariationSettings.IsEmpty() ||
-        !Weight().IsSingle()) {
+    if (HasVariations()) {
         FT_Face ftFace = GetFTFace();
         if (ftFace) {
             AutoTArray<gfxFontVariation,8> settings;
             GetVariationsForStyle(settings, *aStyle);
             gfxFT2FontBase::SetupVarCoords(ftFace, settings, &coords);
         }
     }
 
@@ -1216,25 +1214,28 @@ gfxFontconfigFontFamily::FindStyleVariat
 
         if (fontEntry->IsNormalStyle()) {
             numRegularFaces++;
         }
 
         if (LOG_FONTLIST_ENABLED()) {
             nsAutoCString weightString;
             fontEntry->Weight().ToString(weightString);
+            nsAutoCString stretchString;
+            fontEntry->Stretch().ToString(stretchString);
+            nsAutoCString styleString;
+            fontEntry->SlantStyle().ToString(styleString);
             LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
-                 " with style: %s weight: %s stretch: %g%%"
+                 " with style: %s weight: %s stretch: %s"
                  " psname: %s fullname: %s",
                  NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
                  NS_ConvertUTF16toUTF8(Name()).get(),
-                 (fontEntry->IsItalic()) ?
-                  "italic" : (fontEntry->IsOblique() ? "oblique" : "normal"),
+                 styleString.get(),
                  weightString.get(),
-                 fontEntry->Stretch().Percentage(),
+                 stretchString.get(),
                  NS_ConvertUTF16toUTF8(psname).get(),
                  NS_ConvertUTF16toUTF8(fullname).get()));
         }
     }
 
     // somewhat arbitrary, but define a family with two or more regular
     // faces as a family for which intra-family fallback should be used
     if (numRegularFaces > 1) {
@@ -1329,19 +1330,18 @@ gfxFontconfigFontFamily::FindAllFontsFor
             static_cast<gfxFontconfigFontEntry*>(aFontEntryList[i]);
         double dist = SizeDistance(entry, aFontStyle,
                                    mForceScalable || aIgnoreSizeTolerance);
         // If the entry is scalable or has a style that does not match
         // the group of unscalable fonts, then start a new group.
         if (dist < 0.0 ||
             !bestEntry ||
             bestEntry->Stretch() != entry->Stretch() ||
-            bestEntry->Weight().Min() != entry->Weight().Min() ||
-            bestEntry->Weight().Max() != entry->Weight().Max() ||
-            bestEntry->mStyle != entry->mStyle) {
+            bestEntry->Weight() != entry->Weight() ||
+            bestEntry->SlantStyle() != entry->SlantStyle()) {
             // If the best entry in this group is still outside the tolerance,
             // then skip the entire group.
             if (bestDist >= kRejectDistance) {
                 skipped++;
             }
             // Remove any compacted entries from the previous group.
             if (skipped) {
                 i -= skipped;
@@ -1874,54 +1874,59 @@ gfxFcPlatformFontList::GetDefaultFontFor
     if (prefFonts && !prefFonts->IsEmpty()) {
         return (*prefFonts)[0];
     }
     return nullptr;
 }
 
 gfxFontEntry*
 gfxFcPlatformFontList::LookupLocalFont(const nsAString& aFontName,
-                                       FontWeight aWeight,
-                                       FontStretch aStretch,
-                                       FontSlantStyle aStyle)
+                                       WeightRange aWeightForEntry,
+                                       StretchRange aStretchForEntry,
+                                       SlantStyleRange aStyleForEntry)
 {
     nsAutoString keyName(aFontName);
     ToLowerCase(keyName);
 
     // if name is not in the global list, done
     FcPattern* fontPattern = mLocalNames.Get(keyName);
     if (!fontPattern) {
         return nullptr;
     }
 
     return new gfxFontconfigFontEntry(aFontName, fontPattern,
-                                      aWeight, aStretch, aStyle);
+                                      aWeightForEntry,
+                                      aStretchForEntry,
+                                      aStyleForEntry);
 }
 
 gfxFontEntry*
 gfxFcPlatformFontList::MakePlatformFont(const nsAString& aFontName,
-                                        FontWeight aWeight,
-                                        FontStretch aStretch,
-                                        FontSlantStyle aStyle,
+                                        WeightRange aWeightForEntry,
+                                        StretchRange aStretchForEntry,
+                                        SlantStyleRange aStyleForEntry,
                                         const uint8_t* aFontData,
                                         uint32_t aLength)
 {
     FT_Face face = Factory::NewFTFaceFromData(nullptr, aFontData, aLength, 0);
     if (!face) {
         free((void*)aFontData);
         return nullptr;
     }
     if (FT_Err_Ok != FT_Select_Charmap(face, FT_ENCODING_UNICODE)) {
         Factory::ReleaseFTFace(face);
         free((void*)aFontData);
         return nullptr;
     }
 
-    return new gfxFontconfigFontEntry(aFontName, aWeight, aStretch,
-                                      aStyle, aFontData, aLength, face);
+    return new gfxFontconfigFontEntry(aFontName,
+                                      aWeightForEntry,
+                                      aStretchForEntry,
+                                      aStyleForEntry,
+                                      aFontData, aLength, face);
 }
 
 bool
 gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily,
                                           nsTArray<gfxFontFamily*>* aOutput,
                                           FindFamiliesFlags aFlags,
                                           gfxFontStyle* aStyle,
                                           gfxFloat aDevToCssSize)
--- a/gfx/thebes/gfxFcPlatformFontList.h
+++ b/gfx/thebes/gfxFcPlatformFontList.h
@@ -89,29 +89,29 @@ public:
     // used for system fonts with explicit patterns
     explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
                                     FcPattern* aFontPattern,
                                     bool aIgnoreFcCharmap);
 
     // used for data fonts where the fontentry takes ownership
     // of the font data and the FT_Face
     explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
-                                    FontWeight aWeight,
-                                    FontStretch aStretch,
-                                    FontSlantStyle aStyle,
+                                    WeightRange aWeight,
+                                    StretchRange aStretch,
+                                    SlantStyleRange aStyle,
                                     const uint8_t *aData,
                                     uint32_t aLength,
                                     FT_Face aFace);
 
     // used for @font-face local system fonts with explicit patterns
     explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
                                     FcPattern* aFontPattern,
-                                    FontWeight aWeight,
-                                    FontStretch aStretch,
-                                    FontSlantStyle aStyle);
+                                    WeightRange aWeight,
+                                    StretchRange aStretch,
+                                    SlantStyleRange aStyle);
 
     gfxFontEntry* Clone() const override;
 
     FcPattern* GetPattern() { return mFontPattern; }
 
     nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
     bool TestCharacterMap(uint32_t aCh) override;
 
@@ -291,25 +291,25 @@ public:
                      const nsACString& aGenericFamily,
                      nsTArray<nsString>& aListOfFonts) override;
 
     void ReadSystemFontList(
         InfallibleTArray<mozilla::dom::SystemFontListEntry>* retValue);
 
     gfxFontEntry*
     LookupLocalFont(const nsAString& aFontName,
-                    FontWeight aWeight,
-                    FontStretch aStretch,
-                    FontSlantStyle aStyle) override;
+                    WeightRange aWeightForEntry,
+                    StretchRange aStretchForEntry,
+                    SlantStyleRange aStyleForEntry) override;
 
     gfxFontEntry*
     MakePlatformFont(const nsAString& aFontName,
-                     FontWeight aWeight,
-                     FontStretch aStretch,
-                     FontSlantStyle aStyle,
+                     WeightRange aWeightForEntry,
+                     StretchRange aStretchForEntry,
+                     SlantStyleRange aStyleForEntry,
                      const uint8_t* aFontData,
                      uint32_t aLength) override;
 
     bool FindAndAddFamilies(const nsAString& aFamily,
                             nsTArray<gfxFontFamily*>* aOutput,
                             FindFamiliesFlags aFlags,
                             gfxFontStyle* aStyle = nullptr,
                             gfxFloat aDevToCssSize = 1.0) override;
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -76,18 +76,18 @@ gfxFontEntry::gfxFontEntry() :
     mHasGraphiteSpaceContextuals(false),
     mSpaceGlyphIsInvisible(false),
     mSpaceGlyphIsInvisibleInitialized(false),
     mCheckedForGraphiteTables(false),
     mHasCmapTable(false),
     mGrFaceInitialized(false),
     mCheckedForColorGlyph(false),
     mWeightRange(FontWeight(500)),
-    mStretch(FontStretch::Normal()),
-    mStyle(FontSlantStyle::Normal()),
+    mStretchRange(FontStretch::Normal()),
+    mStyleRange(FontSlantStyle::Normal()),
     mUVSOffset(0), mUVSData(nullptr),
     mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
     mCOLR(nullptr),
     mCPAL(nullptr),
     mUnitsPerEm(0),
     mHBFace(nullptr),
     mGrFace(nullptr),
     mGrFaceRefCnt(0),
@@ -115,18 +115,18 @@ gfxFontEntry::gfxFontEntry(const nsAStri
     mHasGraphiteSpaceContextuals(false),
     mSpaceGlyphIsInvisible(false),
     mSpaceGlyphIsInvisibleInitialized(false),
     mCheckedForGraphiteTables(false),
     mHasCmapTable(false),
     mGrFaceInitialized(false),
     mCheckedForColorGlyph(false),
     mWeightRange(FontWeight(500)),
-    mStretch(FontStretch::Normal()),
-    mStyle(FontSlantStyle::Normal()),
+    mStretchRange(FontStretch::Normal()),
+    mStyleRange(FontSlantStyle::Normal()),
     mUVSOffset(0), mUVSData(nullptr),
     mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
     mCOLR(nullptr),
     mCPAL(nullptr),
     mUnitsPerEm(0),
     mHBFace(nullptr),
     mGrFace(nullptr),
     mGrFaceRefCnt(0),
@@ -1044,50 +1044,87 @@ gfxFontEntry::SetupVariationRanges()
         switch (axis.mTag) {
         case HB_TAG('w','g','h','t'):
             // If the axis range looks like it doesn't fit the CSS font-weight
             // scale, we don't hook up the high-level property. Setting 'wght'
             // with font-variation-settings will still work.
             // Strictly speaking, the min value should be checked against 1.0,
             // not 0.0, but we'll allow font makers that amount of leeway, as
             // in practice a number of fonts seem to use 0..1000.
-            if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0 &&
+            if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0f &&
                 // If axis.mMaxValue is less than the default weight we already
                 // set up, assume the axis has a non-standard range (like Skia)
                 // and don't try to map it.
                 Weight().Min() <= FontWeight(axis.mMaxValue)) {
-                mStandardFace = FontWeight(axis.mDefaultValue) == Weight().Min();
+                if (FontWeight(axis.mDefaultValue) != Weight().Min()) {
+                    mStandardFace = false;
+                }
                 mWeightRange =
                     WeightRange(FontWeight(std::max(1.0f, axis.mMinValue)),
                                 FontWeight(axis.mMaxValue));
             }
             break;
-        // XXX todo:
-        // case HB_TAG('w','d','t','h'):
-        // case HB_TAG('s','l','n','t'):
-        // case HB_TAG('i','t','a','l'):
+
+        case HB_TAG('w','d','t','h'):
+            if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0f &&
+                Stretch().Min() <= FontStretch(axis.mMaxValue)) {
+                if (FontStretch(axis.mDefaultValue) != Stretch().Min()) {
+                    mStandardFace = false;
+                }
+                mStretchRange =
+                    StretchRange(FontStretch(axis.mMinValue),
+                                 FontStretch(axis.mMaxValue));
+            }
+            break;
+
+        case HB_TAG('s','l','n','t'):
+            if (axis.mMinValue >= -90.0f && axis.mMaxValue <= 90.0f) {
+                if (FontSlantStyle::Oblique(axis.mDefaultValue) != SlantStyle().Min()) {
+                    mStandardFace = false;
+                }
+                mStyleRange =
+                    SlantStyleRange(FontSlantStyle::Oblique(axis.mMinValue),
+                                    FontSlantStyle::Oblique(axis.mMaxValue));
+            }
+            break;
+
+        // case HB_TAG('i','t','a','l'): // XXX how to handle?
         default:
             continue;
         }
     }
 }
 
 void
 gfxFontEntry::GetVariationsForStyle(nsTArray<gfxFontVariation>& aResult,
                                     const gfxFontStyle& aStyle)
 {
     // Resolve high-level CSS properties from the requested style
     // (font-{style,weight,stretch}) to the appropriate variations.
-    if (!Weight().IsSingle()) {
-        float clampedWeight = Weight().Clamp(aStyle.weight).ToFloat();
-        aResult.AppendElement(gfxFontVariation{HB_TAG('w','g','h','t'),
-                                               clampedWeight});
+    float clampedWeight = Weight().Clamp(aStyle.weight).ToFloat();
+    aResult.AppendElement(gfxFontVariation{HB_TAG('w','g','h','t'),
+                                           clampedWeight});
+
+    float clampedStretch = Stretch().Clamp(aStyle.stretch).Percentage();
+    aResult.AppendElement(gfxFontVariation{HB_TAG('w','d','t','h'),
+                                           clampedStretch});
+
+    if (SlantStyle().Min().IsOblique()) {
+        float clampedSlant =
+          aStyle.style.IsOblique()
+          ? SlantStyle().Clamp(aStyle.style).ObliqueAngle()
+          : aStyle.style.IsItalic()
+            ? SlantStyle().Clamp(FontSlantStyle::Oblique()).ObliqueAngle()
+            : SlantStyle().Clamp(FontSlantStyle::Oblique(0.0f)).ObliqueAngle();
+        aResult.AppendElement(gfxFontVariation{HB_TAG('s','l','n','t'),
+                                               clampedSlant});
     }
 
-    // XXX todo: 'wdth', 'slnt', 'ital'
+    // Although there is a registered tag 'ital', it is normally considered
+    // a binary toggle rather than a variable axis, 
 
     auto replaceOrAppend = [&aResult](const gfxFontVariation& aSetting) {
         struct TagEquals {
             bool Equals(const gfxFontVariation& aIter, uint32_t aTag) const {
                 return aIter.mTag == aTag;
             }
         };
         auto index = aResult.IndexOf(aSetting.mTag, 0, TagEquals());
@@ -1253,84 +1290,125 @@ gfxFontFamily::FindFontForStyle(const gf
     FindAllFontsForStyle(aFontStyle, matched, aNeedsSyntheticBold,
                          aIgnoreSizeTolerance);
     if (!matched.IsEmpty()) {
         return matched[0];
     }
     return nullptr;
 }
 
-#define STYLE_SHIFT 2 // number of bits to contain style distance
-
-// style distance ==> [0,2]
-static inline uint32_t
-StyleDistance(FontSlantStyle aFontStyle, FontSlantStyle aTargetStyle)
+// style distance ==> [0,500]
+static inline double
+StyleDistance(const gfxFontEntry* aFontEntry, FontSlantStyle aTargetStyle)
 {
-    if (aFontStyle == aTargetStyle) {
-        return 0; // styles match exactly ==> 0
+    FontSlantStyle minStyle = aFontEntry->SlantStyle().Min();
+    if (aTargetStyle == minStyle) {
+        return 0.0; // styles match exactly ==> 0
+    }
+
+    // Compare oblique angles to see how closely they match.
+    // The range of angles is [-90.0 .. 90.0], although in practice values
+    // are unlikely to get anywhere near the extremes.
+    // The style 'italic' is treated as having the same angle as the default
+    // for 'oblique', but with a constant added to the distance to reflect
+    // distinction.
+
+    double extraDistance = 0.0;
+    const double kReverseDistance = 100.0;
+
+    double target;
+    if (aTargetStyle.IsNormal()) {
+        target = 0.0;
+        extraDistance = 300.0;
+    } else if (aTargetStyle.IsOblique()) {
+        target = aTargetStyle.ObliqueAngle();
+    } else {
+        target = FontSlantStyle::Oblique().ObliqueAngle();
+        extraDistance = 200.0;
     }
-    if (aFontStyle == FontSlantStyle::Normal() ||
-        aTargetStyle == FontSlantStyle::Normal()) {
-        return 2; // one is normal (but not the other) ==> 2
+
+    FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
+
+    double minAngle, maxAngle;
+    // There can only be a range of styles if it's oblique
+    if (minStyle.IsNormal()) {
+        minAngle = maxAngle = 0.0;
+        extraDistance = 300.0;
+    } else if (minStyle.IsOblique()) {
+        MOZ_ASSERT(maxStyle.IsOblique());
+        minAngle = minStyle.ObliqueAngle();
+        maxAngle = maxStyle.ObliqueAngle();
+    } else {
+        minAngle = maxAngle = FontSlantStyle::Oblique().ObliqueAngle();
+        extraDistance = 200.0;
     }
-    return 1; // neither is normal; must be italic vs oblique ==> 1
+
+    double distance = 0.0;
+    if (target < minAngle || target > maxAngle) {
+        if (target > 0.0) {
+            distance = minAngle - target;
+        } else {
+            distance = target - maxAngle;
+        }
+    }
+    if (distance < 0.0) {
+        distance = kReverseDistance - distance;
+    }
+
+    return distance + extraDistance;
 }
 
-#define REVERSE_STRETCH_DISTANCE 200.0f
+// stretch distance ==> [0,2000]
+static inline double
+StretchDistance(const gfxFontEntry* aFontEntry, FontStretch aTargetStretch)
+{
+    const double kReverseDistance = 1000.0;
+    double distance = 0.0;
 
-// stretch distance ==> [0,350]
-static inline uint32_t
-StretchDistance(FontStretch aFontStretch, FontStretch aTargetStretch)
-{
-    float distance = 0.0f;
-    if (aTargetStretch != aFontStretch) {
-        // stretch values are in the range 50 .. 200
+    FontStretch minStretch = aFontEntry->Stretch().Min();
+    FontStretch maxStretch = aFontEntry->Stretch().Max();
+
+    if (aTargetStretch < minStretch || aTargetStretch > maxStretch) {
+        // stretch values are in the range 0 .. 1000
         // if aTargetStretch is >100, we prefer larger values;
         // if <=100, prefer smaller
         if (aTargetStretch > FontStretch::Normal()) {
-            distance = (aFontStretch - aTargetStretch);
+            distance = (minStretch - aTargetStretch);
         } else {
-            distance = (aTargetStretch - aFontStretch);
+            distance = (aTargetStretch - maxStretch);
         }
         // if the computed "distance" here is negative, it means that
         // aFontEntry lies in the "non-preferred" direction from aTargetStretch,
         // so we treat that as larger than any preferred-direction distance
-        // (max possible is 150) by adding an extra 200 to the absolute value
+        // (max possible is 1000) by adding an extra 1000 to the absolute value
         if (distance < 0.0f) {
-            distance = -distance + REVERSE_STRETCH_DISTANCE;
+            distance = kReverseDistance - distance;
         }
     }
-    return uint32_t(distance);
+    return distance;
 }
 
-// CSS currently limits font weights to multiples of 100 but the weight
-// matching code below does not assume this.
-//
 // Calculate weight distance with values in the range (0..1000). In general,
 // heavier weights match towards even heavier weights while lighter weights
 // match towards even lighter weights. Target weight values in the range
 // [400..500] are special, since they will first match up to 500, then down
 // towards 0, then up again towards 999.
 //
 // Example: with target 600 and font weight 800, distance will be 200. With
 // target 300 and font weight 600, distance will be 900, since heavier
 // weights are farther away than lighter weights. If the target is 5 and the
 // font weight 995, the distance would be 1590 for the same reason.
 
-#define REVERSE_WEIGHT_DISTANCE 600
-#define WEIGHT_SHIFT             11 // number of bits to contain weight distance
-
-// weight distance ==> [0,1598]
-static inline uint32_t
+// weight distance ==> [0,1600]
+static inline double
 WeightDistance(const gfxFontEntry* aFontEntry, FontWeight aTargetWeight)
 {
-    // Compute a measure of the "distance" between the requested
-    // weight and the given fontEntry
+    const double kReverseDistance = 600.0;
 
-    float distance = 0.0f, addedDistance = 0.0f;
+    double distance = 0.0, addedDistance = 0.0;
     FontWeight minWeight = aFontEntry->Weight().Min();
     FontWeight maxWeight = aFontEntry->Weight().Max();
     if (aTargetWeight < minWeight || aTargetWeight > maxWeight) {
         if (aTargetWeight > FontWeight(500)) {
             distance = minWeight - aTargetWeight;
         } else if (aTargetWeight < FontWeight(400)) {
             distance = aTargetWeight - maxWeight;
         } else {
@@ -1344,45 +1422,47 @@ WeightDistance(const gfxFontEntry* aFont
                 } else {
                     distance = minWeight - aTargetWeight;
                 }
             } else {
                 // font weights outside use rule for target weights < 400 with
                 // added distance to separate from font weights in
                 // the [400..500] range
                 distance = aTargetWeight - maxWeight;
-                addedDistance = 100;
+                addedDistance = 100.0;
             }
         }
-        if (distance < 0.0f) {
-            distance = -distance + REVERSE_WEIGHT_DISTANCE;
+        if (distance < 0.0) {
+            distance = kReverseDistance - distance;
         }
         distance += addedDistance;
     }
-    return uint32_t(distance);
+    return distance;
 }
 
-#define MAX_DISTANCE 0xffffffff
+#define MAX_DISTANCE 1.0e20 // >> than any WeightStyleStretchDistance result
 
-static inline uint32_t
+static inline double
 WeightStyleStretchDistance(gfxFontEntry* aFontEntry,
                            const gfxFontStyle& aTargetStyle)
 {
-    // weight/style/stretch priority: stretch >> style >> weight
-    uint32_t stretchDist =
-        StretchDistance(aFontEntry->mStretch, aTargetStyle.stretch);
-    uint32_t styleDist = StyleDistance(aFontEntry->mStyle, aTargetStyle.style);
-    uint32_t weightDist = WeightDistance(aFontEntry, aTargetStyle.weight);
+    double stretchDist = StretchDistance(aFontEntry, aTargetStyle.stretch);
+    double styleDist = StyleDistance(aFontEntry, aTargetStyle.style);
+    double weightDist = WeightDistance(aFontEntry, aTargetStyle.weight);
 
-    NS_ASSERTION(weightDist < (1 << WEIGHT_SHIFT), "weight value out of bounds");
-    NS_ASSERTION(styleDist < (1 << STYLE_SHIFT), "slope value out of bounds");
+    // Sanity-check that the distances are within the expected range
+    // (update if implementation of the distance functions is changed).
+    MOZ_ASSERT(stretchDist >= 0.0 && stretchDist <= 2000.0);
+    MOZ_ASSERT(styleDist >= 0.0 && styleDist <= 500.0);
+    MOZ_ASSERT(weightDist >= 0.0 && weightDist <= 1600.0);
 
-    return (stretchDist << (STYLE_SHIFT + WEIGHT_SHIFT)) |
-           (styleDist << WEIGHT_SHIFT) |
-           weightDist;
+    // weight/style/stretch priority: stretch >> style >> weight
+    // so we multiply the stretch and style values to make them dominate
+    // the result
+    return stretchDist * 1.0e8 + styleDist * 1.0e4 + weightDist;
 }
 
 void
 gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
                                     nsTArray<gfxFontEntry*>& aFontEntryList,
                                     bool& aNeedsSyntheticBold,
                                     bool aIgnoreSizeTolerance)
 {
@@ -1463,24 +1543,24 @@ gfxFontFamily::FindAllFontsForStyle(cons
     // given but the 99% use case is only a single font entry per
     // weight/style/stretch distance value. To optimize this, only add entries
     // to the matched font array when another entry already has the same
     // weight/style/stretch distance and add the last matched font entry. For
     // normal platform fonts with a single font entry for each
     // weight/style/stretch combination, only the last matched font entry will
     // be added.
 
-    uint32_t minDistance = MAX_DISTANCE;
+    double minDistance = MAX_DISTANCE;
     gfxFontEntry* matched = nullptr;
     // iterate in forward order so that faces like 'Bold' are matched before
     // matching style distance faces such as 'Bold Outline' (see bug 1185812)
     for (uint32_t i = 0; i < count; i++) {
         fe = mAvailableFonts[i];
         // weight/style/stretch priority: stretch >> style >> weight
-        uint32_t distance = WeightStyleStretchDistance(fe, aFontStyle);
+        double distance = WeightStyleStretchDistance(fe, aFontStyle);
         if (distance < minDistance) {
             matched = fe;
             if (!aFontEntryList.IsEmpty()) {
                 aFontEntryList.Clear();
             }
             minDistance = distance;
         } else if (distance == minDistance) {
             if (matched) {
@@ -1515,26 +1595,29 @@ gfxFontFamily::CheckForSimpleFamily()
                 // if none then the family is unusable anyway
     }
 
     if (count == 1) {
         mIsSimpleFamily = true;
         return;
     }
 
-    FontStretch firstStretch = mAvailableFonts[0]->Stretch();
+    StretchRange firstStretch = mAvailableFonts[0]->Stretch();
+    if (!firstStretch.IsSingle()) {
+        return; // family with variation fonts is not considered "simple"
+    }
 
     gfxFontEntry *faces[4] = { 0 };
     for (uint8_t i = 0; i < count; ++i) {
         gfxFontEntry *fe = mAvailableFonts[i];
         if (fe->Stretch() != firstStretch || fe->IsOblique()) {
             // simple families don't have varying font-stretch or oblique
             return;
         }
-        if (fe->Weight().Min() != fe->Weight().Max()) {
+        if (!fe->Weight().IsSingle() || !fe->SlantStyle().IsSingle()) {
             return; // family with variation fonts is not considered "simple"
         }
         uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
                             (fe->IsBold() ? kBoldMask : 0);
         if (faces[faceIndex]) {
             return; // two faces resolve to the same slot; family isn't "simple"
         }
         faces[faceIndex] = fe;
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -111,16 +111,18 @@ struct gfxFontFeatureInfo {
 class gfxFontEntry {
 public:
     typedef mozilla::gfx::DrawTarget DrawTarget;
     typedef mozilla::unicode::Script Script;
     typedef mozilla::FontWeight FontWeight;
     typedef mozilla::FontSlantStyle FontSlantStyle;
     typedef mozilla::FontStretch FontStretch;
     typedef mozilla::WeightRange WeightRange;
+    typedef mozilla::SlantStyleRange SlantStyleRange;
+    typedef mozilla::StretchRange StretchRange;
 
     // Used by stylo
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxFontEntry)
 
     explicit gfxFontEntry(const nsAString& aName, bool aIsStandardFace = false);
 
     // Create a new entry that refers to the same font as this, but without
     // additional state that may have been set up (such as family name).
@@ -140,40 +142,42 @@ public:
     // they are intended only for the font-inspection API, not for
     // perf-critical layout/drawing work.
 
     // The "real" name of the face, if available from the font resource;
     // returns Name() if nothing better is available.
     virtual nsString RealFaceName();
 
     WeightRange Weight() const { return mWeightRange; }
-    FontStretch Stretch() const { return mStretch; }
+    StretchRange Stretch() const { return mStretchRange; }
+    SlantStyleRange SlantStyle() const { return mStyleRange; }
 
     bool IsUserFont() const { return mIsDataUserFont || mIsLocalUserFont; }
     bool IsLocalUserFont() const { return mIsLocalUserFont; }
     bool IsFixedPitch() const { return mFixedPitch; }
-    bool IsItalic() const { return mStyle.IsItalic(); }
-    bool IsOblique() const { return mStyle.IsOblique(); }
-    bool IsUpright() const { return mStyle.IsNormal(); }
+    bool IsItalic() const { return SlantStyle().Min().IsItalic(); }
+    bool IsOblique() const { return SlantStyle().Min().IsOblique(); }
+    bool IsUpright() const { return SlantStyle().Min().IsNormal(); }
     bool IsBold() const { return Weight().Max().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
     // possibly apply synthetic styling.
     bool IsNormalStyle() const
     {
         return IsUpright() &&
                Weight().Min() <= FontWeight::Normal() &&
                Weight().Max() >= FontWeight::Normal() &&
-               Stretch().IsNormal();
+               Stretch().Min() <= FontStretch::Normal() &&
+               Stretch().Max() >= FontStretch::Normal();
     }
 
     // whether a feature is supported by the font (limited to a small set
     // of features for which some form of fallback needs to be implemented)
     virtual bool SupportsOpenTypeFeature(Script aScript, uint32_t aFeatureTag);
     bool SupportsGraphiteFeature(uint32_t aFeatureTag);
 
     // returns a set containing all input glyph ids for a given feature
@@ -413,18 +417,18 @@ public:
     bool             mCheckedForColorGlyph : 1;
 
     // bitvector of substitution space features per script, one each
     // for default and non-default features
     uint32_t         mDefaultSubSpaceFeatures[(int(Script::NUM_SCRIPT_CODES) + 31) / 32];
     uint32_t         mNonDefaultSubSpaceFeatures[(int(Script::NUM_SCRIPT_CODES) + 31) / 32];
 
     WeightRange      mWeightRange;
-    FontStretch      mStretch;
-    FontSlantStyle   mStyle;
+    StretchRange     mStretchRange;
+    SlantStyleRange  mStyleRange;
 
     RefPtr<gfxCharacterMap> mCharacterMap;
     uint32_t         mUVSOffset;
     mozilla::UniquePtr<uint8_t[]> mUVSData;
     mozilla::UniquePtr<gfxUserFontData> mUserFontData;
     mozilla::UniquePtr<gfxSVGGlyphs> mSVGGlyphs;
     // list of gfxFonts that are using SVG glyphs
     nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -110,44 +110,42 @@ FontTypeToOutPrecision(uint8_t fontType)
 /***************************************************************
  *
  * GDIFontEntry
  *
  */
 
 GDIFontEntry::GDIFontEntry(const nsAString& aFaceName,
                            gfxWindowsFontType aFontType,
-                           FontSlantStyle aStyle,
-                           FontWeight aWeight,
-                           FontStretch aStretch,
+                           SlantStyleRange aStyle,
+                           WeightRange aWeight,
+                           StretchRange aStretch,
                            gfxUserFontData *aUserFontData)
     : gfxFontEntry(aFaceName),
       mFontType(aFontType),
       mForceGDI(false),
       mUnicodeRanges()
 {
     mUserFontData.reset(aUserFontData);
-    mStyle = aStyle;
-    mWeightRange = WeightRange(aWeight);
-    mStretch = aStretch;
+    mStyleRange = aStyle;
+    mWeightRange = aWeight;
+    mStretchRange = aStretch;
     if (IsType1())
         mForceGDI = true;
     mIsDataUserFont = aUserFontData != nullptr;
 
     InitLogFont(aFaceName, aFontType);
 }
 
 gfxFontEntry*
 GDIFontEntry::Clone() const
 {
     MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
-    // GDI fonts don't support variations, so we don't need to worry about
-    // cloning the weight as a range.
-    return new GDIFontEntry(Name(), mFontType, mStyle, Weight().Min(), mStretch,
-                            nullptr);
+    return new GDIFontEntry(Name(), mFontType, SlantStyle(), Weight(),
+                            Stretch(), nullptr);
 }
 
 nsresult
 GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
 {
     AUTO_PROFILER_LABEL("GDIFontEntry::ReadCMAP", OTHER);
 
     // attempt this once, if errors occur leave a blank cmap
@@ -391,19 +389,19 @@ GDIFontEntry::InitLogFont(const nsAStrin
     int len = std::min<int>(aName.Length(), LF_FACESIZE - 1);
     memcpy(&mLogFont.lfFaceName, aName.BeginReading(), len * sizeof(char16_t));
     mLogFont.lfFaceName[len] = '\0';
 }
 
 GDIFontEntry* 
 GDIFontEntry::CreateFontEntry(const nsAString& aName,
                               gfxWindowsFontType aFontType,
-                              FontSlantStyle aStyle,
-                              FontWeight aWeight,
-                              FontStretch aStretch,
+                              SlantStyleRange aStyle,
+                              WeightRange aWeight,
+                              StretchRange aStretch,
                               gfxUserFontData* aUserFontData)
 {
     // jtdfix - need to set charset, unicode ranges, pitch/family
 
     GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aStyle,
                                         aWeight, aStretch, aUserFontData);
 
     return fe;
@@ -480,19 +478,19 @@ GDIFontFamily::FamilyAddStylesProc(const
     }
 
     // We can't set the hasItalicFace flag correctly here,
     // because we might not have seen the family's italic face(s) yet.
     // So we'll set that flag for all members after loading all the faces.
     auto italicStyle = (logFont.lfItalic == 0xFF ?
                            FontSlantStyle::Italic() : FontSlantStyle::Normal());
     fe = GDIFontEntry::CreateFontEntry(nsDependentString(lpelfe->elfFullName),
-                                       feType, italicStyle,
-                                       FontWeight(int32_t(logFont.lfWeight)),
-                                       FontStretch::Normal(),
+                                       feType, SlantStyleRange(italicStyle),
+                                       WeightRange(FontWeight(int32_t(logFont.lfWeight))),
+                                       StretchRange(FontStretch::Normal()),
                                        nullptr);
     if (!fe)
         return 1;
 
     ff->AddFontEntry(fe);
 
     if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
         nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 &&
@@ -505,25 +503,22 @@ GDIFontFamily::FamilyAddStylesProc(const
             DWORD range = nmetrics->ntmFontSig.fsUsb[i];
             for (uint32_t k = 0; k < 32; ++k) {
                 fe->mUnicodeRanges.set(x++, (range & (1 << k)) != 0);
             }
         }
     }
 
     if (LOG_FONTLIST_ENABLED()) {
-        nsAutoCString stretchString;
         LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
-             " with style: %s weight: %d stretch: %g%%",
+             " with style: %s weight: %d stretch: normal",
              NS_ConvertUTF16toUTF8(fe->Name()).get(),
              NS_ConvertUTF16toUTF8(ff->Name()).get(),
              (logFont.lfItalic == 0xff) ? "italic" : "normal",
-             logFont.lfWeight,
-             fe->Stretch().Percentage(),
-             stretchString.get()));
+             logFont.lfWeight));
     }
     return 1;
 }
 
 void
 GDIFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
 {
     if (mHasStyles)
@@ -711,45 +706,46 @@ gfxGDIFontList::EnumFontFamExProc(ENUMLO
         family->mCharset.set(metrics.tmCharSet);
     }
 
     return 1;
 }
 
 gfxFontEntry* 
 gfxGDIFontList::LookupLocalFont(const nsAString& aFontName,
-                                FontWeight aWeight,
-                                FontStretch aStretch,
-                                FontSlantStyle aStyle)
+                                WeightRange aWeightForEntry,
+                                StretchRange aStretchForEntry,
+                                SlantStyleRange aStyleForEntry)
 {
     gfxFontEntry *lookup;
 
     lookup = LookupInFaceNameLists(aFontName);
     if (!lookup) {
         return nullptr;
     }
 
     bool isCFF = false; // jtdfix -- need to determine this
     
     // use the face name from the lookup font entry, which will be the localized
     // face name which GDI mapping tables use (e.g. with the system locale set to
     // Dutch, a fullname of 'Arial Bold' will find a font entry with the face name
     // 'Arial Vet' which can be used as a key in GDI font lookups).
     GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(lookup->Name(), 
         gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, 
-        lookup->mStyle, lookup->Weight().Min(), aStretch, nullptr);
+        lookup->SlantStyle(), lookup->Weight(), aStretchForEntry, nullptr);
 
     if (!fe)
         return nullptr;
 
     fe->mIsLocalUserFont = true;
 
     // make the new font entry match the userfont entry style characteristics
-    fe->mWeightRange = WeightRange(aWeight);
-    fe->mStyle = aStyle;
+    fe->mWeightRange = aWeightForEntry;
+    fe->mStyleRange = aStyleForEntry;
+    fe->mStretchRange = aStretchForEntry;
 
     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.
 // NOTE that this function does not bounds-check every access to the font data.
@@ -803,19 +799,19 @@ FixupSymbolEncodedFont(uint8_t* aFontDat
             return true;
         }
     }
     return false;
 }
 
 gfxFontEntry*
 gfxGDIFontList::MakePlatformFont(const nsAString& aFontName,
-                                 FontWeight aWeight,
-                                 FontStretch aStretch,
-                                 FontSlantStyle aStyle,
+                                 WeightRange aWeightForEntry,
+                                 StretchRange aStretchForEntry,
+                                 SlantStyleRange aStyleForEntry,
                                  const uint8_t* aFontData,
                                  uint32_t aLength)
 {
     // MakePlatformFont is responsible for deleting the font data with free
     // so we set up a stack object to ensure it is freed even if we take an
     // early exit
     struct FontDataDeleter {
         explicit FontDataDeleter(const uint8_t* aFontData)
@@ -870,17 +866,17 @@ gfxGDIFontList::MakePlatformFont(const n
         RemoveFontMemResourceEx(fontRef);
         return nullptr;
     }
 
     // make a new font entry using the unique name
     WinUserFontData *winUserFontData = new WinUserFontData(fontRef);
     GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(uniqueName,
         gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
-        aStyle, aWeight, aStretch, winUserFontData);
+        aStyleForEntry, aWeightForEntry, aStretchForEntry, winUserFontData);
 
     if (fe) {
       fe->mIsDataUserFont = true;
     }
 
     return fe;
 }
 
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -103,20 +103,16 @@ enum gfxWindowsFontType {
 };
 
 // A single member of a font family (i.e. a single face, such as Times Italic)
 // represented as a LOGFONT that will resolve to the correct face.
 // This replaces FontEntry from gfxWindowsFonts.h/cpp.
 class GDIFontEntry : public gfxFontEntry
 {
 public:
-    typedef mozilla::FontStretch FontStretch;
-    typedef mozilla::FontSlantStyle FontSlantStyle;
-    typedef mozilla::FontWeight FontWeight;
-
     LPLOGFONTW GetLogFont() { return &mLogFont; }
 
     nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
 
     void FillLogFont(LOGFONTW *aLogFont,
                      LONG aWeight,
                      gfxFloat aSize);
 
@@ -165,37 +161,31 @@ public:
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
 
     gfxFontEntry* Clone() const override;
 
     // create a font entry for a font with a given name
     static GDIFontEntry* CreateFontEntry(const nsAString& aName,
                                          gfxWindowsFontType aFontType,
-                                         FontSlantStyle aStyle,
-                                         FontWeight aWeight,
-                                         FontStretch aStretch,
+                                         SlantStyleRange aStyle,
+                                         WeightRange aWeight,
+                                         StretchRange aStretch,
                                          gfxUserFontData* aUserFontData);
 
-    // create a font entry for a font referenced by its fullname
-    static GDIFontEntry* LoadLocalFont(const nsAString& aFontName,
-                                       FontWeight aWeight,
-                                       FontStretch aStretch,
-                                       FontSlantStyle aStyle);
-
     gfxWindowsFontType mFontType;
     bool mForceGDI;
 
     gfxSparseBitSet mUnicodeRanges;
 
 protected:
     friend class gfxGDIFont;
 
     GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
-                 FontSlantStyle aStyle, FontWeight aWeight, FontStretch aStretch,
+                 SlantStyleRange aStyle, WeightRange aWeight, StretchRange aStretch,
                  gfxUserFontData *aUserFontData);
 
     void InitLogFont(const nsAString& aName, gfxWindowsFontType aFontType);
 
     virtual gfxFont* CreateFontInstance(const gfxFontStyle *aFontStyle,
                                         bool aNeedsBold) override;
 
     virtual nsresult CopyFontTable(uint32_t aTableTag,
@@ -317,44 +307,40 @@ protected:
 private:
     static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
                                             const NEWTEXTMETRICEXW *nmetrics,
                                             DWORD fontType, LPARAM data);
 };
 
 class gfxGDIFontList : public gfxPlatformFontList {
 public:
-    typedef mozilla::FontStretch FontStretch;
-    typedef mozilla::FontSlantStyle FontSlantStyle;
-    typedef mozilla::FontWeight FontWeight;
-
     static gfxGDIFontList* PlatformFontList() {
         return static_cast<gfxGDIFontList*>(sPlatformFontList);
     }
 
     // initialize font lists
     virtual nsresult InitFontListForPlatform() override;
 
     gfxFontFamily* CreateFontFamily(const nsAString& aName) const override;
 
     bool FindAndAddFamilies(const nsAString& aFamily,
                             nsTArray<gfxFontFamily*>* aOutput,
                             FindFamiliesFlags aFlags,
                             gfxFontStyle* aStyle = nullptr,
                             gfxFloat aDevToCssSize = 1.0) override;
 
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          FontWeight aWeight,
-                                          FontStretch aStretch,
-                                          FontSlantStyle aStyle);
+                                          WeightRange aWeightForEntry,
+                                          StretchRange aStretchForEntry,
+                                          SlantStyleRange aStyleForEntry);
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           FontWeight aWeight,
-                                           FontStretch aStretch,
-                                           FontSlantStyle aStyle,
+                                           WeightRange aWeightForEntry,
+                                           StretchRange aStretchForEntry,
+                                           SlantStyleRange aStyleForEntry,
                                            const uint8_t* aFontData,
                                            uint32_t aLength);
 
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
     virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
 
--- a/gfx/thebes/gfxMacFont.cpp
+++ b/gfx/thebes/gfxMacFont.cpp
@@ -31,19 +31,17 @@ gfxMacFont::gfxMacFont(const RefPtr<Unsc
       mCGFont(nullptr),
       mCTFont(nullptr),
       mFontFace(nullptr),
       mFontSmoothingBackgroundColor(aFontStyle->fontSmoothingBackgroundColor),
       mVariationFont(aFontEntry->HasVariations())
 {
     mApplySyntheticBold = aNeedsBold;
 
-    if (mVariationFont && (!aFontStyle->variationSettings.IsEmpty() ||
-                           !aFontEntry->mVariationSettings.IsEmpty() ||
-                           !aFontEntry->Weight().IsSingle())) {
+    if (mVariationFont) {
         CGFontRef baseFont = aUnscaledFont->GetFont();
         if (!baseFont) {
             mIsValid = false;
             return;
         }
 
         // Get the variation settings needed to instantiate the fontEntry
         // for a particular fontStyle.
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -26,23 +26,23 @@
 class gfxMacPlatformFontList;
 
 // a single member of a font family (i.e. a single face, such as Times Italic)
 class MacOSFontEntry : public gfxFontEntry
 {
 public:
     friend class gfxMacPlatformFontList;
 
-    MacOSFontEntry(const nsAString& aPostscriptName, FontWeight aWeight,
+    MacOSFontEntry(const nsAString& aPostscriptName, WeightRange aWeight,
                    bool aIsStandardFace = false,
                    double aSizeHint = 0.0);
 
     // for use with data fonts
     MacOSFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef,
-                   FontWeight aWeight, FontStretch aStretch, FontSlantStyle aStyle,
+                   WeightRange aWeight, StretchRange aStretch, SlantStyleRange aStyle,
                    bool aIsDataUserFont, bool aIsLocal);
 
     virtual ~MacOSFontEntry() {
         if (mTrakTable) {
             hb_blob_destroy(mTrakTable);
         }
         ::CGFontRelease(mFontRef);
     }
@@ -126,24 +126,24 @@ public:
 
     gfxFontFamily* CreateFontFamily(const nsAString& aName) const override;
 
     static int32_t AppleWeightToCSSWeight(int32_t aAppleWeight);
 
     bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) override;
 
     gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                  FontWeight aWeight,
-                                  FontStretch aStretch,
-                                  FontSlantStyle aStyle) override;
+                                  WeightRange aWeightForEntry,
+                                  StretchRange aStretchForEntry,
+                                  SlantStyleRange aStyleForEntry) override;
 
     gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                   FontWeight aWeight,
-                                   FontStretch aStretch,
-                                   FontSlantStyle aStyle,
+                                   WeightRange aWeightForEntry,
+                                   StretchRange aStretchForEntry,
+                                   SlantStyleRange aStyleForEntry,
                                    const uint8_t* aFontData,
                                    uint32_t aLength) override;
 
     bool FindAndAddFamilies(const nsAString& aFamily,
                             nsTArray<gfxFontFamily*>* aOutput,
                             FindFamiliesFlags aFlags,
                             gfxFontStyle* aStyle = nullptr,
                             gfxFloat aDevToCssSize = 1.0) override;
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -359,17 +359,17 @@ MacOSFontEntry::IsCFF()
         mIsCFFInitialized = true;
         mIsCFF = HasFontTable(TRUETYPE_TAG('C','F','F',' '));
     }
 
     return mIsCFF;
 }
 
 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
-                               FontWeight aWeight,
+                               WeightRange aWeight,
                                bool aIsStandardFace,
                                double aSizeHint)
     : gfxFontEntry(aPostscriptName, aIsStandardFace),
       mFontRef(NULL),
       mSizeHint(aSizeHint),
       mFontRefInitialized(false),
       mRequiresAAT(false),
       mIsCFF(false),
@@ -378,24 +378,24 @@ MacOSFontEntry::MacOSFontEntry(const nsA
       mHasVariationsInitialized(false),
       mHasAATSmallCaps(false),
       mHasAATSmallCapsInitialized(false),
       mCheckedForTracking(false),
       mTrakTable(nullptr),
       mTrakValues(nullptr),
       mTrakSizeTable(nullptr)
 {
-    mWeightRange = WeightRange(aWeight);
+    mWeightRange = aWeight;
 }
 
 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
                                CGFontRef aFontRef,
-                               FontWeight aWeight,
-                               FontStretch aStretch,
-                               FontSlantStyle aStyle,
+                               WeightRange aWeight,
+                               StretchRange aStretch,
+                               SlantStyleRange aStyle,
                                bool aIsDataUserFont,
                                bool aIsLocalUserFont)
     : gfxFontEntry(aPostscriptName, false),
       mFontRef(NULL),
       mSizeHint(0.0),
       mFontRefInitialized(false),
       mRequiresAAT(false),
       mIsCFF(false),
@@ -408,36 +408,35 @@ MacOSFontEntry::MacOSFontEntry(const nsA
       mTrakTable(nullptr),
       mTrakValues(nullptr),
       mTrakSizeTable(nullptr)
 {
     mFontRef = aFontRef;
     mFontRefInitialized = true;
     ::CFRetain(mFontRef);
 
-    mWeightRange = WeightRange(aWeight);
-    mStretch = aStretch;
+    mWeightRange = aWeight;
+    mStretchRange = aStretch;
     mFixedPitch = false; // xxx - do we need this for downloaded fonts?
-    mStyle = aStyle;
+    mStyleRange = aStyle;
 
     NS_ASSERTION(!(aIsDataUserFont && aIsLocalUserFont),
                  "userfont is either a data font or a local font");
     mIsDataUserFont = aIsDataUserFont;
     mIsLocalUserFont = aIsLocalUserFont;
 }
 
 gfxFontEntry*
 MacOSFontEntry::Clone() const
 {
     MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
     MacOSFontEntry* fe =
-        new MacOSFontEntry(Name(), Weight().Min(), mStandardFace, mSizeHint);
-    fe->mStyle = mStyle;
-    fe->mStretch = mStretch;
-    fe->mWeightRange = mWeightRange;
+        new MacOSFontEntry(Name(), Weight(), mStandardFace, mSizeHint);
+    fe->mStyleRange = mStyleRange;
+    fe->mStretchRange = mStretchRange;
     fe->mFixedPitch = mFixedPitch;
     return fe;
 }
 
 CGFontRef
 MacOSFontEntry::GetFontRef()
 {
     if (!mFontRefInitialized) {
@@ -900,53 +899,56 @@ gfxMacFontFamily::FindStyleVariations(Fo
             [facename isEqualToString:@"Bold Italic"] ||
             [facename isEqualToString:@"Bold Oblique"])
         {
             isStandardFace = true;
         }
 
         // create a font entry
         MacOSFontEntry *fontEntry =
-            new MacOSFontEntry(postscriptFontName, FontWeight(cssWeight),
+            new MacOSFontEntry(postscriptFontName,
+                               WeightRange(FontWeight(cssWeight)),
                                isStandardFace, mSizeHint);
         if (!fontEntry) {
             break;
         }
 
         // set additional properties based on the traits reported by Cocoa
         if (macTraits & (NSCondensedFontMask | NSNarrowFontMask | NSCompressedFontMask)) {
-            fontEntry->mStretch = FontStretch::Condensed();
+            fontEntry->mStretchRange = StretchRange(FontStretch::Condensed());
         } else if (macTraits & NSExpandedFontMask) {
-            fontEntry->mStretch = FontStretch::Expanded();
+            fontEntry->mStretchRange = StretchRange(FontStretch::Expanded());
         }
         // Cocoa fails to set the Italic traits bit for HelveticaLightItalic,
         // at least (see bug 611855), so check for style name endings as well
         if ((macTraits & NSItalicFontMask) ||
             [facename hasSuffix:@"Italic"] ||
             [facename hasSuffix:@"Oblique"])
         {
-            fontEntry->mStyle = FontSlantStyle::Italic();
+            fontEntry->mStyleRange = SlantStyleRange(FontSlantStyle::Italic());
         }
         if (macTraits & NSFixedPitchFontMask) {
             fontEntry->mFixedPitch = true;
         }
 
         fontEntry->SetupVariationRanges();
 
         if (LOG_FONTLIST_ENABLED()) {
             nsAutoCString weightString;
             fontEntry->Weight().ToString(weightString);
+            nsAutoCString stretchString;
+            fontEntry->Stretch().ToString(stretchString);
             LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
-                 " with style: %s weight: %s stretch: %g%%"
+                 " with style: %s weight: %s stretch: %s"
                  " (apple-weight: %d macTraits: %8.8x)",
                  NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
                  NS_ConvertUTF16toUTF8(Name()).get(),
                  fontEntry->IsItalic() ? "italic" : "normal",
                  weightString.get(),
-                 fontEntry->Stretch().Percentage(),
+                 stretchString.get(),
                  appKitWeight, macTraits));
         }
 
         // insert into font entry array of family
         AddFontEntry(fontEntry);
     }
 
     SortAvailableFonts();
@@ -1283,20 +1285,19 @@ gfxMacPlatformFontList::InitSingleFaceLi
 
         // add only if doesn't exist already
         if (!mFontFamilies.GetWeak(key)) {
             RefPtr<gfxFontFamily> familyEntry =
                 new gfxSingleFaceMacFontFamily(familyName);
             // We need a separate font entry, because its family name will
             // differ from the one we found in the main list.
             MacOSFontEntry* fontEntry =
-                new MacOSFontEntry(fe->Name(), fe->Weight().Min(), true,
+                new MacOSFontEntry(fe->Name(), fe->Weight(), true,
                                    static_cast<const MacOSFontEntry*>(fe)->
                                        mSizeHint);
-            fontEntry->mWeightRange = fe->mWeightRange;
             familyEntry->AddFontEntry(fontEntry);
             familyEntry->SetHasStyles(true);
             mFontFamilies.Put(key, familyEntry);
             LOG_FONTLIST(("(fontlist-singleface) added new family: %s, key: %s\n",
                           NS_ConvertUTF16toUTF8(familyName).get(),
                           NS_ConvertUTF16toUTF8(key).get()));
         }
     }
@@ -1535,60 +1536,55 @@ gfxMacPlatformFontList::AppleWeightToCSS
         aAppleWeight = 1;
     else if (aAppleWeight > kAppleMaxWeight)
         aAppleWeight = kAppleMaxWeight;
     return gAppleWeightToCSSWeight[aAppleWeight];
 }
 
 gfxFontEntry*
 gfxMacPlatformFontList::LookupLocalFont(const nsAString& aFontName,
-                                        FontWeight aWeight,
-                                        FontStretch aStretch,
-                                        FontSlantStyle aStyle)
+                                        WeightRange aWeightForEntry,
+                                        StretchRange aStretchForEntry,
+                                        SlantStyleRange aStyleForEntry)
 {
     nsAutoreleasePool localPool;
 
     NSString *faceName = GetNSStringForString(aFontName);
     MacOSFontEntry *newFontEntry;
 
     // lookup face based on postscript or full name
     CGFontRef fontRef = ::CGFontCreateWithFontName(CFStringRef(faceName));
     if (!fontRef) {
         return nullptr;
     }
 
-    MOZ_ASSERT(aWeight >= FontWeight(100) && aWeight <= FontWeight(900),
-               "bogus font weight value!");
-
     newFontEntry =
-        new MacOSFontEntry(aFontName, fontRef, aWeight, aStretch, aStyle,
+        new MacOSFontEntry(aFontName, fontRef, aWeightForEntry,
+                           aStretchForEntry, aStyleForEntry,
                            false, true);
     ::CFRelease(fontRef);
 
     return newFontEntry;
 }
 
 static void ReleaseData(void *info, const void *data, size_t size)
 {
     free((void*)data);
 }
 
 gfxFontEntry*
 gfxMacPlatformFontList::MakePlatformFont(const nsAString& aFontName,
-                                         FontWeight aWeight,
-                                         FontStretch aStretch,
-                                         FontSlantStyle aStyle,
+                                         WeightRange aWeightForEntry,
+                                         StretchRange aStretchForEntry,
+                                         SlantStyleRange aStyleForEntry,
                                          const uint8_t* aFontData,
                                          uint32_t aLength)
 {
     NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
 
-    MOZ_ASSERT(aWeight >= FontWeight(100) && aWeight <= FontWeight(900),
-               "bogus font weight value!");
-
     // create the font entry
     nsAutoString uniqueName;
 
     nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
     if (NS_FAILED(rv)) {
         return nullptr;
     }
 
@@ -1598,18 +1594,19 @@ gfxMacPlatformFontList::MakePlatformFont
     CGFontRef fontRef = ::CGFontCreateWithDataProvider(provider);
     ::CGDataProviderRelease(provider);
 
     if (!fontRef) {
         return nullptr;
     }
 
     auto newFontEntry =
-        MakeUnique<MacOSFontEntry>(uniqueName, fontRef, aWeight, aStretch,
-                                   aStyle, true, false);
+        MakeUnique<MacOSFontEntry>(uniqueName, fontRef, aWeightForEntry,
+                                   aStretchForEntry, aStyleForEntry,
+                                   true, false);
     ::CFRelease(fontRef);
 
     // if succeeded and font cmap is good, return the new font
     if (NS_SUCCEEDED(newFontEntry->ReadCMAP())) {
         return newFontEntry.release();
     }
 
     // if something is funky about this font, delete immediately
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1740,40 +1740,36 @@ gfxPlatform::IsFontFormatSupported(uint3
     }
 
     // no format hint set, need to look at data
     return true;
 }
 
 gfxFontEntry*
 gfxPlatform::LookupLocalFont(const nsAString& aFontName,
-                             FontWeight aWeight,
-                             FontStretch aStretch,
-                             FontSlantStyle aStyle)
+                             WeightRange aWeightForEntry,
+                             StretchRange aStretchForEntry,
+                             SlantStyleRange aStyleForEntry)
 {
-    return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aFontName,
-                                                                    aWeight,
-                                                                    aStretch,
-                                                                    aStyle);
+    return gfxPlatformFontList::PlatformFontList()->
+        LookupLocalFont(aFontName, aWeightForEntry, aStretchForEntry,
+                        aStyleForEntry);
 }
 
 gfxFontEntry*
 gfxPlatform::MakePlatformFont(const nsAString& aFontName,
-                              FontWeight aWeight,
-                              FontStretch aStretch,
-                              FontSlantStyle aStyle,
+                              WeightRange aWeightForEntry,
+                              StretchRange aStretchForEntry,
+                              SlantStyleRange aStyleForEntry,
                               const uint8_t* aFontData,
                               uint32_t aLength)
 {
-    return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aFontName,
-                                                                     aWeight,
-                                                                     aStretch,
-                                                                     aStyle,
-                                                                     aFontData,
-                                                                     aLength);
+    return gfxPlatformFontList::PlatformFontList()->
+        MakePlatformFont(aFontName, aWeightForEntry, aStretchForEntry,
+                         aStyleForEntry, aFontData, aLength);
 }
 
 mozilla::layers::DiagnosticTypes
 gfxPlatform::GetLayerDiagnosticTypes()
 {
   mozilla::layers::DiagnosticTypes type = DiagnosticTypes::NO_DIAGNOSTIC;
   if (gfxPrefs::DrawLayerBorders()) {
     type |= mozilla::layers::DiagnosticTypes::LAYER_BORDERS;
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -154,19 +154,19 @@ struct BackendPrefsData
   uint32_t mContentBitmask = 0;
   mozilla::gfx::BackendType mContentDefault = mozilla::gfx::BackendType::NONE;
 };
 
 class gfxPlatform {
     friend class SRGBOverrideObserver;
 
 public:
-    typedef mozilla::FontStretch FontStretch;
-    typedef mozilla::FontSlantStyle FontSlantStyle;
-    typedef mozilla::FontWeight FontWeight;
+    typedef mozilla::StretchRange StretchRange;
+    typedef mozilla::SlantStyleRange SlantStyleRange;
+    typedef mozilla::WeightRange WeightRange;
     typedef mozilla::gfx::Color Color;
     typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
     typedef mozilla::gfx::DrawTarget DrawTarget;
     typedef mozilla::gfx::IntSize IntSize;
     typedef mozilla::gfx::SourceSurface SourceSurface;
     typedef mozilla::unicode::Script Script;
 
     /**
@@ -389,35 +389,35 @@ public:
                     gfxFloat aDevToCssSize) = 0;
 
     /**
      * Look up a local platform font using the full font face name.
      * (Needed to support @font-face src local().)
      * Ownership of the returned gfxFontEntry is passed to the caller,
      * who must either AddRef() or delete.
      */
-    virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          FontWeight aWeight,
-                                          FontStretch aStretch,
-                                          FontSlantStyle aStyle);
+    gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
+                                  WeightRange aWeightForEntry,
+                                  StretchRange aStretchForEntry,
+                                  SlantStyleRange aStyleForEntry);
 
     /**
      * Activate a platform font.  (Needed to support @font-face src url().)
      * aFontData is a NS_Malloc'ed block that must be freed by this function
      * (or responsibility passed on) when it is no longer needed; the caller
      * will NOT free it.
      * Ownership of the returned gfxFontEntry is passed to the caller,
      * who must either AddRef() or delete.
      */
-    virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           FontWeight aWeight,
-                                           FontStretch aStretch,
-                                           FontSlantStyle aStyle,
-                                           const uint8_t* aFontData,
-                                           uint32_t aLength);
+    gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
+                                   WeightRange aWeightForEntry,
+                                   StretchRange aStretchForEntry,
+                                   SlantStyleRange aStyleForEntry,
+                                   const uint8_t* aFontData,
+                                   uint32_t aLength);
 
     /**
      * Whether to allow downloadable fonts via @font-face rules
      */
     bool DownloadableFontsEnabled();
 
     /**
      * True when hinting should be enabled.  This setting shouldn't
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -93,19 +93,19 @@ struct FontListSizes {
 
 class gfxUserFontSet;
 
 class gfxPlatformFontList : public gfxFontInfoLoader
 {
     friend class InitOtherFamilyNamesRunnable;
 
 public:
-    typedef mozilla::FontStretch FontStretch;
-    typedef mozilla::FontSlantStyle FontSlantStyle;
-    typedef mozilla::FontWeight FontWeight;
+    typedef mozilla::StretchRange StretchRange;
+    typedef mozilla::SlantStyleRange SlantStyleRange;
+    typedef mozilla::WeightRange WeightRange;
     typedef mozilla::unicode::Script Script;
 
     static gfxPlatformFontList* PlatformFontList() {
         return sPlatformFontList;
     }
 
     static nsresult Init() {
         NS_ASSERTION(!sPlatformFontList, "What's this doing here?");
@@ -183,28 +183,43 @@ public:
 
     bool NeedFullnamePostscriptNames() { return mExtraNames != nullptr; }
 
     // pure virtual functions, to be provided by concrete subclasses
 
     // get the system default font family
     gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
 
-    // look up a font by name on the host platform
+    /**
+     * Look up a font by name on the host platform.
+     *
+     * Note that the style attributes (weight, stretch, style) are NOT used in
+     * selecting the platform font, which is looked up by name only; these are
+     * values to be recorded in the new font entry.
+     */
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          FontWeight aWeight,
-                                          FontStretch aStretch,
-                                          FontSlantStyle aStyle) = 0;
+                                          WeightRange aWeightForEntry,
+                                          StretchRange aStretchForEntry,
+                                          SlantStyleRange aStyleForEntry) = 0;
 
-    // create a new platform font from downloaded data (@font-face)
-    // this method is responsible to ensure aFontData is free()'d
+    /**
+     * Create a new platform font from downloaded data (@font-face).
+     *
+     * Note that the style attributes (weight, stretch, style) are NOT related
+     * (necessarily) to any values within the font resource itself; these are
+     * values to be recorded in the new font entry and used for face selection,
+     * in place of whatever inherent style attributes the resource may have.
+     *
+     * This method takes ownership of the data block passed in as aFontData,
+     * and must ensure it is free()'d when no longer required.
+     */
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           FontWeight aWeight,
-                                           FontStretch aStretch,
-                                           FontSlantStyle aStyle,
+                                           WeightRange aWeightForEntry,
+                                           StretchRange aStretchForEntry,
+                                           SlantStyleRange aStyleForEntry,
                                            const uint8_t* aFontData,
                                            uint32_t aLength) = 0;
 
     // get the standard family name on the platform for a given font name
     // (platforms may override, eg Mac)
     virtual bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     // get the default font name which is available on the system from
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -268,40 +268,16 @@ gfxPlatformGtk::CreateFontGroup(const Fo
                                 gfxTextPerfMetrics* aTextPerf,
                                 gfxUserFontSet* aUserFontSet,
                                 gfxFloat aDevToCssSize)
 {
     return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf,
                             aUserFontSet, aDevToCssSize);
 }
 
-gfxFontEntry*
-gfxPlatformGtk::LookupLocalFont(const nsAString& aFontName,
-                                FontWeight aWeight,
-                                FontStretch aStretch,
-                                FontSlantStyle aStyle)
-{
-    gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
-    return pfl->LookupLocalFont(aFontName, aWeight, aStretch,
-                                aStyle);
-}
-
-gfxFontEntry*
-gfxPlatformGtk::MakePlatformFont(const nsAString& aFontName,
-                                 FontWeight aWeight,
-                                 FontStretch aStretch,
-                                 FontSlantStyle aStyle,
-                                 const uint8_t* aFontData,
-                                 uint32_t aLength)
-{
-    gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
-    return pfl->MakePlatformFont(aFontName, aWeight, aStretch,
-                                 aStyle, aFontData, aLength);
-}
-
 FT_Library
 gfxPlatformGtk::GetFTLibrary()
 {
     return gfxFcPlatformFontList::GetFTLibrary();
 }
 
 static int32_t sDPI = 0;
 
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -57,36 +57,16 @@ public:
     gfxFontGroup*
     CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                     const gfxFontStyle *aStyle,
                     gfxTextPerfMetrics* aTextPerf,
                     gfxUserFontSet *aUserFontSet,
                     gfxFloat aDevToCssSize) override;
 
     /**
-     * Look up a local platform font using the full font face name (needed to
-     * support @font-face src local() )
-     */
-    virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          FontWeight aWeight,
-                                          FontStretch aStretch,
-                                          FontSlantStyle aStyle) override;
-
-    /**
-     * Activate a platform font (needed to support @font-face src url() )
-     *
-     */
-    virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           FontWeight aWeight,
-                                           FontStretch aStretch,
-                                           FontSlantStyle aStyle,
-                                           const uint8_t* aFontData,
-                                           uint32_t aLength) override;
-
-    /**
      * Calls XFlush if xrender is enabled.
      */
     virtual void FlushContentDrawing() override;
 
     FT_Library GetFTLibrary() override;
 
     static int32_t GetFontScaleDPI();
     static double  GetFontScaleFactor();
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -100,69 +100,66 @@ private:
     void*        mPtr;
     size_t       mLength;
     const size_t mLimit;
     off_t        mOff;
 };
 
 gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet,
              const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-             FontWeight aWeight,
-             FontStretch aStretch,
-             FontSlantStyle aStyle,
+             WeightRange aWeight,
+             StretchRange aStretch,
+             SlantStyleRange aStyle,
              const nsTArray<gfxFontFeature>& aFeatureSettings,
              const nsTArray<gfxFontVariation>& aVariationSettings,
              uint32_t aLanguageOverride,
              gfxCharacterMap* aUnicodeRanges,
              uint8_t aFontDisplay)
     : gfxFontEntry(NS_LITERAL_STRING("userfont")),
       mUserFontLoadState(STATUS_NOT_LOADED),
       mFontDataLoadingState(NOT_LOADING),
       mUnsupportedFormat(false),
       mFontDisplay(aFontDisplay),
       mLoader(nullptr),
       mFontSet(aFontSet)
 {
-    MOZ_ASSERT(aWeight.ToFloat() != 0.0f,
-               "aWeight must not be 0; use FontWeight::Normal() instead");
     mIsUserFontContainer = true;
     mSrcList = aFontFaceSrcList;
     mSrcIndex = 0;
-    mWeightRange = WeightRange(aWeight);
-    mStretch = aStretch;
-    mStyle = aStyle;
+    mWeightRange = aWeight;
+    mStretchRange = aStretch;
+    mStyleRange = aStyle;
     mFeatureSettings.AppendElements(aFeatureSettings);
     mVariationSettings.AppendElements(aVariationSettings);
     mLanguageOverride = aLanguageOverride;
     mCharacterMap = aUnicodeRanges;
 }
 
 gfxUserFontEntry::~gfxUserFontEntry()
 {
     // Assert that we don't drop any gfxUserFontEntry objects during a Servo
     // traversal, since PostTraversalTask objects can hold raw pointers to
     // gfxUserFontEntry objects.
     MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
 }
 
 bool
 gfxUserFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                          FontWeight aWeight,
-                          FontStretch aStretch,
-                          FontSlantStyle aStyle,
+                          WeightRange aWeight,
+                          StretchRange aStretch,
+                          SlantStyleRange aStyle,
                           const nsTArray<gfxFontFeature>& aFeatureSettings,
                           const nsTArray<gfxFontVariation>& aVariationSettings,
                           uint32_t aLanguageOverride,
                           gfxCharacterMap* aUnicodeRanges,
                           uint8_t aFontDisplay)
 {
-    return Weight().Min() == aWeight &&
-           Weight().Max() == aWeight &&
-           mStretch == aStretch &&
-           mStyle == aStyle &&
+    return Weight() == aWeight &&
+           Stretch() == aStretch &&
+           SlantStyle() == aStyle &&
            mFeatureSettings == aFeatureSettings &&
            mVariationSettings == aVariationSettings &&
            mLanguageOverride == aLanguageOverride &&
            mSrcList == aFontFaceSrcList &&
            mFontDisplay == aFontDisplay &&
            ((!aUnicodeRanges && !mCharacterMap) ||
             (aUnicodeRanges && mCharacterMap && mCharacterMap->Equals(aUnicodeRanges)));
 }
@@ -512,19 +509,19 @@ gfxUserFontEntry::DoLoadNextSrc(bool aFo
         // src local ==> lookup and load immediately
 
         if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_Local) {
             // Don't look up local fonts if the font whitelist is being used.
             gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
             gfxFontEntry* fe = pfl && pfl->IsFontFamilyWhitelistActive() ?
                 nullptr :
                 gfxPlatform::GetPlatform()->LookupLocalFont(currSrc.mLocalName,
-                                                            Weight().Min(),
-                                                            mStretch,
-                                                            mStyle);
+                                                            Weight(),
+                                                            Stretch(),
+                                                            SlantStyle());
             nsTArray<gfxUserFontSet*> fontSets;
             GetUserFontSets(fontSets);
             for (gfxUserFontSet* fontSet : fontSets) {
                 // We need to note on each gfxUserFontSet that contains the user
                 // font entry that we used a local() rule.
                 fontSet->SetLocalRulesUsed();
             }
             if (fe) {
@@ -767,19 +764,19 @@ gfxUserFontEntry::LoadPlatformFont(const
         // don't allow us to retrieve or measure it directly.
         // The *OnAlloc function will also tell DMD about this block, as the
         // OS font code may hold on to it for an extended period.
         computedSize = UserFontMallocSizeOfOnAlloc(saneData);
 
         // Here ownership of saneData is passed to the platform,
         // which will delete it when no longer required
         fe = gfxPlatform::GetPlatform()->MakePlatformFont(mName,
-                                                          Weight().Min(),
-                                                          mStretch,
-                                                          mStyle,
+                                                          Weight(),
+                                                          Stretch(),
+                                                          SlantStyle(),
                                                           saneData,
                                                           saneLen);
         if (!fe) {
             mFontSet->LogMessage(this, "not usable by platform");
         }
     }
 
     if (fe) {
@@ -932,19 +929,19 @@ gfxUserFontSet::~gfxUserFontSet()
         fp->RemoveUserFontSet(this);
     }
 }
 
 already_AddRefed<gfxUserFontEntry>
 gfxUserFontSet::FindOrCreateUserFontEntry(
                                const nsAString& aFamilyName,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                               FontWeight aWeight,
-                               FontStretch aStretch,
-                               FontSlantStyle aStyle,
+                               WeightRange aWeight,
+                               StretchRange aStretch,
+                               SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
     RefPtr<gfxUserFontEntry> entry;
 
@@ -972,19 +969,19 @@ gfxUserFontSet::FindOrCreateUserFontEntr
     }
 
     return entry.forget();
 }
 
 already_AddRefed<gfxUserFontEntry>
 gfxUserFontSet::CreateUserFontEntry(
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                               FontWeight aWeight,
-                               FontStretch aStretch,
-                               FontSlantStyle aStyle,
+                               WeightRange aWeight,
+                               StretchRange aStretch,
+                               SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
 
     RefPtr<gfxUserFontEntry> userFontEntry =
@@ -993,28 +990,25 @@ gfxUserFontSet::CreateUserFontEntry(
                               aLanguageOverride, aUnicodeRanges, aFontDisplay);
     return userFontEntry.forget();
 }
 
 gfxUserFontEntry*
 gfxUserFontSet::FindExistingUserFontEntry(
                                gfxUserFontFamily* aFamily,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                               FontWeight aWeight,
-                               FontStretch aStretch,
-                               FontSlantStyle aStyle,
+                               WeightRange aWeight,
+                               StretchRange aStretch,
+                               SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
-    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;
         }
 
         gfxUserFontEntry* existingUserFontEntry =
@@ -1038,23 +1032,25 @@ gfxUserFontSet::AddUserFontEntry(const n
                                  gfxUserFontEntry* aUserFontEntry)
 {
     gfxUserFontFamily* family = GetFamily(aFamilyName);
     family->AddFontEntry(aUserFontEntry);
 
     if (LOG_ENABLED()) {
         nsAutoCString weightString;
         aUserFontEntry->Weight().ToString(weightString);
+        nsAutoCString stretchString;
+        aUserFontEntry->Stretch().ToString(stretchString);
         LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %s "
-             "stretch: %g%% display: %d",
+             "stretch: %s display: %d",
              this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry,
              (aUserFontEntry->IsItalic() ? "italic" :
               (aUserFontEntry->IsOblique() ? "oblique" : "normal")),
              weightString.get(),
-             aUserFontEntry->Stretch().Percentage(),
+             stretchString.get(),
              aUserFontEntry->GetFontDisplay()));
     }
 }
 
 void
 gfxUserFontSet::IncrementGeneration(bool aIsRebuild)
 {
     // add one, increment again if zero
@@ -1180,19 +1176,19 @@ gfxUserFontSet::UserFontCache::Entry::Ke
             return false;
         }
     }
 
     if (mPrivate != aKey->mPrivate) {
         return false;
     }
 
-    if (mFontEntry->mStyle            != fe->mStyle     ||
+    if (mFontEntry->SlantStyle()      != fe->SlantStyle()     ||
         mFontEntry->Weight()          != fe->Weight()         ||
-        mFontEntry->mStretch          != fe->mStretch         ||
+        mFontEntry->Stretch()         != fe->Stretch()        ||
         mFontEntry->mFeatureSettings  != fe->mFeatureSettings ||
         mFontEntry->mVariationSettings != fe->mVariationSettings ||
         mFontEntry->mLanguageOverride != fe->mLanguageOverride ||
         mFontEntry->mFamilyName       != fe->mFamilyName) {
         return false;
     }
 
     return true;
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -181,18 +181,21 @@ class gfxUserFontEntry;
 class gfxOTSContext;
 
 class gfxUserFontSet {
     friend class gfxUserFontEntry;
     friend class gfxOTSContext;
 
 public:
     typedef mozilla::FontStretch FontStretch;
+    typedef mozilla::StretchRange StretchRange;
     typedef mozilla::FontSlantStyle FontSlantStyle;
+    typedef mozilla::SlantStyleRange SlantStyleRange;
     typedef mozilla::FontWeight FontWeight;
+    typedef mozilla::WeightRange WeightRange;
 
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxUserFontSet)
 
     gfxUserFontSet();
 
     enum {
         // no flags ==> no hint set
         // unknown ==> unknown format hint set
@@ -228,33 +231,33 @@ public:
     // creates a font face without adding it to a particular family
     // weight - [100, 900] (multiples of 100)
     // stretch = [FontStretch::UltraCondensed(), FontStretch::UltraExpanded()]
     // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
     // language override = result of calling nsRuleNode::ParseFontLanguageOverride
     // TODO: support for unicode ranges not yet implemented
     virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
                               const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                              FontWeight aWeight,
-                              FontStretch aStretch,
-                              FontSlantStyle aStyle,
+                              WeightRange aWeight,
+                              StretchRange aStretch,
+                              SlantStyleRange aStyle,
                               const nsTArray<gfxFontFeature>& aFeatureSettings,
                               const nsTArray<gfxFontVariation>& aVariationSettings,
                               uint32_t aLanguageOverride,
                               gfxCharacterMap* aUnicodeRanges,
                               uint8_t aFontDisplay) = 0;
 
     // creates a font face for the specified family, or returns an existing
     // matching entry on the family if there is one
     already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntry(
                                const nsAString& aFamilyName,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                               FontWeight aWeight,
-                               FontStretch aStretch,
-                               FontSlantStyle aStyle,
+                               WeightRange aWeight,
+                               StretchRange aStretch,
+                               SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay);
 
     // add in a font face for which we have the gfxUserFontEntry already
     void AddUserFontEntry(const nsAString& aFamilyName,
@@ -403,21 +406,19 @@ public:
             static PLDHashNumber HashKey(const KeyTypePointer aKey) {
                 PLDHashNumber principalHash =
                     aKey->mPrincipal ? aKey->mPrincipal->Hash() : 0;
                 return mozilla::HashGeneric(principalHash + int(aKey->mPrivate),
                                             aKey->mURI->Hash(),
                                             HashFeatures(aKey->mFontEntry->mFeatureSettings),
                                             HashVariations(aKey->mFontEntry->mVariationSettings),
                                             mozilla::HashString(aKey->mFontEntry->mFamilyName),
-                                            aKey->mFontEntry->Weight().Min().ForHash(),
-                                            aKey->mFontEntry->Weight().Max().ForHash(),
-                                            // XXX Is this right?
-                                            aKey->mFontEntry->mStyle.ForHash(),
-                                            aKey->mFontEntry->mStretch.ForHash(),
+                                            aKey->mFontEntry->Weight().AsScalar(),
+                                            aKey->mFontEntry->SlantStyle().AsScalar(),
+                                            aKey->mFontEntry->Stretch().AsScalar(),
                                             aKey->mFontEntry->mLanguageOverride);
             }
 
             enum { ALLOW_MEMMOVE = false };
 
             gfxFontSrcURI* GetURI() const { return mURI; }
             gfxFontSrcPrincipal* GetPrincipal() const { return mPrincipal; }
             gfxFontEntry* GetFontEntry() const { return mFontEntry; }
@@ -498,19 +499,19 @@ protected:
 
     // helper method for performing the actual userfont set rebuild
     virtual void DoRebuildUserFontSet() = 0;
 
     // helper method for FindOrCreateUserFontEntry
     gfxUserFontEntry* FindExistingUserFontEntry(
                                    gfxUserFontFamily* aFamily,
                                    const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                                   FontWeight aWeight,
-                                   FontStretch aStretch,
-                                   FontSlantStyle aStyle,
+                                   WeightRange aWeight,
+                                   StretchRange aStretch,
+                                   SlantStyleRange aStyle,
                                    const nsTArray<gfxFontFeature>& aFeatureSettings,
                                    const nsTArray<gfxFontVariation>& aVariationSettings,
                                    uint32_t aLanguageOverride,
                                    gfxCharacterMap* aUnicodeRanges,
                                    uint8_t aFontDisplay);
 
     // creates a new gfxUserFontFamily in mFontFamilies, or returns an existing
     // family if there is one
@@ -538,46 +539,42 @@ protected:
 class gfxUserFontEntry : public gfxFontEntry {
     friend class mozilla::PostTraversalTask;
     friend class gfxUserFontSet;
     friend class nsUserFontSet;
     friend class nsFontFaceLoader;
     friend class gfxOTSContext;
 
 public:
-    typedef mozilla::FontStretch FontStretch;
-    typedef mozilla::FontSlantStyle FontSlantStyle;
-    typedef mozilla::FontWeight FontWeight;
-
     enum UserFontLoadState {
         STATUS_NOT_LOADED = 0,
         STATUS_LOAD_PENDING,
         STATUS_LOADING,
         STATUS_LOADED,
         STATUS_FAILED
     };
 
     gfxUserFontEntry(gfxUserFontSet* aFontSet,
                      const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                     FontWeight aWeight,
-                     FontStretch aStretch,
-                     FontSlantStyle aStyle,
+                     WeightRange aWeight,
+                     StretchRange aStretch,
+                     SlantStyleRange aStyle,
                      const nsTArray<gfxFontFeature>& aFeatureSettings,
                      const nsTArray<gfxFontVariation>& aVariationSettings,
                      uint32_t aLanguageOverride,
                      gfxCharacterMap* aUnicodeRanges,
                      uint8_t aFontDisplay);
 
     virtual ~gfxUserFontEntry();
 
     // Return whether the entry matches the given list of attributes
     bool Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                 FontWeight aWeight,
-                 FontStretch aStretch,
-                 FontSlantStyle aStyle,
+                 WeightRange aWeight,
+                 StretchRange aStretch,
+                 SlantStyleRange aStyle,
                  const nsTArray<gfxFontFeature>& aFeatureSettings,
                  const nsTArray<gfxFontVariation>& aVariationSettings,
                  uint32_t aLanguageOverride,
                  gfxCharacterMap* aUnicodeRanges,
                  uint8_t aFontDisplay);
 
     gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle,
                                 bool aNeedsBold) override;
--- a/layout/style/FontFace.h
+++ b/layout/style/FontFace.h
@@ -43,19 +43,19 @@ class FontFace final : public nsISupport
 
 public:
   class Entry final : public gfxUserFontEntry {
     friend class FontFace;
 
   public:
     Entry(gfxUserFontSet* aFontSet,
           const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-          FontWeight aWeight,
-          FontStretch aStretch,
-          FontSlantStyle aStyle,
+          WeightRange aWeight,
+          StretchRange aStretch,
+          SlantStyleRange aStyle,
           const nsTArray<gfxFontFeature>& aFeatureSettings,
           const nsTArray<gfxFontVariation>& aVariationSettings,
           uint32_t aLanguageOverride,
           gfxCharacterMap* aUnicodeRanges,
           uint8_t aFontDisplay)
       : gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch,
                          aStyle, aFeatureSettings, aVariationSettings,
                          aLanguageOverride,
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -984,87 +984,108 @@ GetWeightForDescriptor(const nsCSSValue&
   switch (aVal.GetUnit()) {
     case eCSSUnit_FontWeight:
       return aVal.GetFontWeight();
     case eCSSUnit_Enumerated:
       return FontWeight(aVal.GetIntValue());
     case eCSSUnit_Normal:
     case eCSSUnit_Null:
       return FontWeight::Normal();
-    case eCSSUnit_Pair:
-      // TODO(jfkthame): Handle optional second value of the font descriptor.
-      return GetWeightForDescriptor(aVal.GetPairValue().mXValue);
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown font-weight descriptor value");
       return FontWeight::Normal();
   }
 }
 
+static WeightRange
+GetWeightRangeForDescriptor(const nsCSSValue& aVal)
+{
+  if (aVal.GetUnit() == eCSSUnit_Pair) {
+    return WeightRange(GetWeightForDescriptor(aVal.GetPairValue().mXValue),
+                       GetWeightForDescriptor(aVal.GetPairValue().mYValue));
+  }
+  return WeightRange(GetWeightForDescriptor(aVal));
+}
+
 static FontSlantStyle
 GetStyleForDescriptor(const nsCSSValue& aVal)
 {
   switch (aVal.GetUnit()) {
     case eCSSUnit_Normal:
     case eCSSUnit_Null:
       return FontSlantStyle::Normal();
     case eCSSUnit_Enumerated:
       MOZ_ASSERT(aVal.GetIntValue() == NS_FONT_STYLE_ITALIC);
       return FontSlantStyle::Italic();
     case eCSSUnit_FontSlantStyle:
       return aVal.GetFontSlantStyle();
-    case eCSSUnit_Pair:
-      // TODO(jfkthame): Handle optional second value of the font descriptor.
-      return GetStyleForDescriptor(aVal.GetPairValue().mXValue);
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown font-style descriptor value");
       return FontSlantStyle::Normal();
   }
 }
 
+static SlantStyleRange
+GetStyleRangeForDescriptor(const nsCSSValue& aVal)
+{
+  if (aVal.GetUnit() == eCSSUnit_Pair) {
+    return SlantStyleRange(GetStyleForDescriptor(aVal.GetPairValue().mXValue),
+                           GetStyleForDescriptor(aVal.GetPairValue().mYValue));
+  }
+  return SlantStyleRange(GetStyleForDescriptor(aVal));
+}
+
 static FontStretch
 GetStretchForDescriptor(const nsCSSValue& aVal)
 {
   switch (aVal.GetUnit()) {
     case eCSSUnit_Null:
       return FontStretch::Normal();
     case eCSSUnit_FontStretch:
       return aVal.GetFontStretch();
-    case eCSSUnit_Pair:
-      // TODO(jfkthame): Handle optional second value of the font descriptor.
-      return GetStretchForDescriptor(aVal.GetPairValue().mXValue);
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown font-style descriptor value");
       return FontStretch::Normal();
   }
 }
 
+static StretchRange
+GetStretchRangeForDescriptor(const nsCSSValue& aVal)
+{
+  if (aVal.GetUnit() == eCSSUnit_Pair) {
+    return StretchRange(GetStretchForDescriptor(aVal.GetPairValue().mXValue),
+                       GetStretchForDescriptor(aVal.GetPairValue().mYValue));
+  }
+  return StretchRange(GetStretchForDescriptor(aVal));
+}
+
 /* static */ already_AddRefed<gfxUserFontEntry>
 FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName,
                                                    FontFace* aFontFace,
                                                    SheetType aSheetType)
 {
   FontFaceSet* set = aFontFace->GetPrimaryFontFaceSet();
 
   nsCSSValue val;
   nsCSSUnit unit;
 
   uint32_t languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
   uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
 
   // set up weight
   aFontFace->GetDesc(eCSSFontDesc_Weight, val);
-  FontWeight weight = GetWeightForDescriptor(val);
+  WeightRange weight = GetWeightRangeForDescriptor(val);
 
   // set up stretch
   aFontFace->GetDesc(eCSSFontDesc_Stretch, val);
-  FontStretch stretch = GetStretchForDescriptor(val);
+  StretchRange stretch = GetStretchRangeForDescriptor(val);
 
   // set up font style
   aFontFace->GetDesc(eCSSFontDesc_Style, val);
-  FontSlantStyle italicStyle = GetStyleForDescriptor(val);
+  SlantStyleRange italicStyle = GetStyleRangeForDescriptor(val);
 
   // set up font display
   aFontFace->GetDesc(eCSSFontDesc_Display, val);
   unit = val.GetUnit();
   if (unit == eCSSUnit_Enumerated) {
     fontDisplay = val.GetIntValue();
   } else {
     NS_ASSERTION(unit == eCSSUnit_Null,
@@ -1284,24 +1305,26 @@ FontFaceSet::LogMessage(gfxUserFontEntry
   }
 
   nsAutoCString familyName;
   nsAutoCString fontURI;
   aUserFontEntry->GetFamilyNameAndURIForLogging(familyName, fontURI);
 
   nsAutoCString weightString;
   aUserFontEntry->Weight().ToString(weightString);
+  nsAutoCString stretchString;
+  aUserFontEntry->Stretch().ToString(stretchString);
   nsPrintfCString message
        ("downloadable font: %s "
-        "(font-family: \"%s\" style:%s weight:%s stretch:%g%% src index:%d)",
+        "(font-family: \"%s\" style:%s weight:%s stretch:%s src index:%d)",
         aMessage,
         familyName.get(),
-        aUserFontEntry->IsItalic() ? "italic" : "normal",
+        aUserFontEntry->IsItalic() ? "italic" : "normal", // XXX todo: oblique?
         weightString.get(),
-        aUserFontEntry->Stretch().Percentage(),
+        stretchString.get(),
         aUserFontEntry->GetSrcIndex());
 
   if (NS_FAILED(aStatus)) {
     message.AppendLiteral(": ");
     switch (aStatus) {
     case NS_ERROR_DOM_BAD_URI:
       message.AppendLiteral("bad URI or cross-site access not allowed");
       break;
@@ -1962,19 +1985,19 @@ FontFaceSet::UserFontSet::DoRebuildUserF
     return;
   }
   mFontFaceSet->MarkUserFontSetDirty();
 }
 
 /* virtual */ already_AddRefed<gfxUserFontEntry>
 FontFaceSet::UserFontSet::CreateUserFontEntry(
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                               FontWeight aWeight,
-                               FontStretch aStretch,
-                               FontSlantStyle aStyle,
+                               WeightRange aWeight,
+                               StretchRange aStretch,
+                               SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
   RefPtr<gfxUserFontEntry> entry =
     new FontFace::Entry(this, aFontFaceSrcList, aWeight, aStretch, aStyle,
--- a/layout/style/FontFaceSet.h
+++ b/layout/style/FontFaceSet.h
@@ -93,19 +93,19 @@ public:
                                       uint32_t& aBufferLength) override;
     virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
                                 const char* aMessage,
                                 uint32_t aFlags = nsIScriptError::errorFlag,
                                 nsresult aStatus = NS_OK) override;
     virtual void DoRebuildUserFontSet() override;
     already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
                                    const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                                   FontWeight aWeight,
-                                   FontStretch aStretch,
-                                   FontSlantStyle aStyle,
+                                   WeightRange aWeight,
+                                   StretchRange aStretch,
+                                   SlantStyleRange aStyle,
                                    const nsTArray<gfxFontFeature>& aFeatureSettings,
                                    const nsTArray<gfxFontVariation>& aVariationSettings,
                                    uint32_t aLanguageOverride,
                                    gfxCharacterMap* aUnicodeRanges,
                                    uint8_t aFontDisplay) override;
 
   private:
     RefPtr<FontFaceSet> mFontFaceSet;